Skip to content

Commit

Permalink
[core] fix potential use-after-free after li_job_reset
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
stbuehler committed Jan 6, 2025
1 parent e966bbb commit 10303a7
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 17 deletions.
4 changes: 3 additions & 1 deletion include/lighttpd/jobqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef void (*liJobCB)(liJob *job);
/* All data here is private; use the functions to interact with the job-queue */

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

LI_API void li_job_init(liJob *job, liJobCB callback);
LI_API void li_job_reset(liJob *job);
LI_API void li_job_stop(liJob *job); /* remove job from queue if active and detach references */
/* remove job from queue if active and detach existing references, but doesn't reset loop detection */
LI_API void li_job_stop(liJob *job);
LI_API void li_job_clear(liJob *job);

/* marks the job for later execution */
Expand Down
22 changes: 6 additions & 16 deletions src/common/jobqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,38 +100,28 @@ void li_job_init(liJob *job, liJobCB callback) {
}

void li_job_reset(liJob *job) {
li_job_stop(job);
job->generation = 0;
}

void li_job_stop(liJob *job) {
if (NULL != job->link.data) {
liJobQueue *jq = job->link.data;

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

job->generation = 0;
if (NULL != job->ref) {
/* keep it if refcount == 1, as we are the only reference then */
if (1 < g_atomic_int_get(&job->ref->refcount)) {
job->ref->job = NULL;
li_job_ref_release(job->ref);
job->ref = NULL;
}
}
}

void li_job_stop(liJob *job) {
if (NULL != job->link.data) {
liJobQueue *jq = job->link.data;

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

if (NULL != job->ref) {
job->ref->job = NULL;
li_job_ref_release(job->ref);
job->ref = NULL;
}
}

void li_job_clear(liJob *job) {
if (NULL != job->link.data) {
liJobQueue *jq = job->link.data;
Expand Down

0 comments on commit 10303a7

Please sign in to comment.