Skip to content

Commit 10303a7

Browse files
committed
[core] fix potential use-after-free after li_job_reset
* need `job->ref->job = NULL;` when detaching ref from job * li_job_reset is just li_job_stop + reset of generation * move optimization of keeping jobref with refcount==1 to li_job_stop Change-Id: Ia2e4db186582ebfea92a64aa9aeaf9a67bb722bf
1 parent e966bbb commit 10303a7

File tree

2 files changed

+9
-17
lines changed

2 files changed

+9
-17
lines changed

include/lighttpd/jobqueue.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typedef void (*liJobCB)(liJob *job);
1414
/* All data here is private; use the functions to interact with the job-queue */
1515

1616
struct liJob {
17+
/* prevent running callback in a loop (delay if job generation == queue generation) */
1718
guint generation;
1819
GList link;
1920
liJobCB callback;
@@ -43,7 +44,8 @@ LI_API void li_job_queue_clear(liJobQueue *jq); /* runs until all jobs are done
4344

4445
LI_API void li_job_init(liJob *job, liJobCB callback);
4546
LI_API void li_job_reset(liJob *job);
46-
LI_API void li_job_stop(liJob *job); /* remove job from queue if active and detach references */
47+
/* remove job from queue if active and detach existing references, but doesn't reset loop detection */
48+
LI_API void li_job_stop(liJob *job);
4749
LI_API void li_job_clear(liJob *job);
4850

4951
/* marks the job for later execution */

src/common/jobqueue.c

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,38 +100,28 @@ void li_job_init(liJob *job, liJobCB callback) {
100100
}
101101

102102
void li_job_reset(liJob *job) {
103+
li_job_stop(job);
104+
job->generation = 0;
105+
}
106+
107+
void li_job_stop(liJob *job) {
103108
if (NULL != job->link.data) {
104109
liJobQueue *jq = job->link.data;
105110

106111
g_queue_unlink(&jq->queue, &job->link);
107112
job->link.data = NULL;
108113
}
109114

110-
job->generation = 0;
111115
if (NULL != job->ref) {
112116
/* keep it if refcount == 1, as we are the only reference then */
113117
if (1 < g_atomic_int_get(&job->ref->refcount)) {
118+
job->ref->job = NULL;
114119
li_job_ref_release(job->ref);
115120
job->ref = NULL;
116121
}
117122
}
118123
}
119124

120-
void li_job_stop(liJob *job) {
121-
if (NULL != job->link.data) {
122-
liJobQueue *jq = job->link.data;
123-
124-
g_queue_unlink(&jq->queue, &job->link);
125-
job->link.data = NULL;
126-
}
127-
128-
if (NULL != job->ref) {
129-
job->ref->job = NULL;
130-
li_job_ref_release(job->ref);
131-
job->ref = NULL;
132-
}
133-
}
134-
135125
void li_job_clear(liJob *job) {
136126
if (NULL != job->link.data) {
137127
liJobQueue *jq = job->link.data;

0 commit comments

Comments
 (0)