Changeset 07d4271 in mainline for kernel/generic/src/ddi/ddi.c


Ignore:
Timestamp:
2024-01-25T16:22:55Z (17 months ago)
Author:
Jiří Zárevúcky <zarevucky.jiri@…>
Branches:
master
Children:
f8b69a1e
Parents:
1a1e124
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2024-01-25 15:56:31)
git-committer:
Jiří Zárevúcky <zarevucky.jiri@…> (2024-01-25 16:22:55)
Message:

Fix some unsound task reference manipulation and locking

In some operations that take task ID as an argument,
there's a possibility of the task being destroyed mid-operation
and a subsequent use-after-free situation.
As a general solution, task_find_by_id() is reimplemented to
check for this situation and always return a valid strong reference.
The callers then only need to handle the reference itself, and
don't need to concern themselves with tasks_lock.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/ddi/ddi.c

    r1a1e124 r07d4271  
    336336                return EPERM;
    337337
    338         irq_spinlock_lock(&tasks_lock, true);
    339 
    340338        task_t *task = task_find_by_id(id);
    341339
    342         if ((!task) || (!container_check(CONTAINER, task->container))) {
    343                 /*
    344                  * There is no task with the specified ID
    345                  * or the task belongs to a different security
    346                  * context.
    347                  */
    348                 irq_spinlock_unlock(&tasks_lock, true);
     340        if (!task)
    349341                return ENOENT;
    350         }
    351 
    352         /* Lock the task and release the lock protecting tasks dictionary. */
    353         irq_spinlock_exchange(&tasks_lock, &task->lock);
    354         errno_t rc = ddi_iospace_enable_arch(task, ioaddr, size);
     342
     343        errno_t rc = ENOENT;
     344
     345        irq_spinlock_lock(&task->lock, true);
     346
     347        /* Check that the task belongs to the correct security context. */
     348        if (container_check(CONTAINER, task->container))
     349                rc = ddi_iospace_enable_arch(task, ioaddr, size);
     350
    355351        irq_spinlock_unlock(&task->lock, true);
    356 
     352        task_release(task);
    357353        return rc;
    358354}
     
    377373                return EPERM;
    378374
    379         irq_spinlock_lock(&tasks_lock, true);
    380 
    381375        task_t *task = task_find_by_id(id);
    382376
    383         if ((!task) || (!container_check(CONTAINER, task->container))) {
    384                 /*
    385                  * There is no task with the specified ID
    386                  * or the task belongs to a different security
    387                  * context.
    388                  */
    389                 irq_spinlock_unlock(&tasks_lock, true);
     377        if (!task)
    390378                return ENOENT;
    391         }
    392 
    393         /* Lock the task and release the lock protecting tasks dictionary. */
    394         irq_spinlock_exchange(&tasks_lock, &task->lock);
    395         errno_t rc = ddi_iospace_disable_arch(task, ioaddr, size);
     379
     380        errno_t rc = ENOENT;
     381
     382        irq_spinlock_lock(&task->lock, true);
     383
     384        /* Check that the task belongs to the correct security context. */
     385        if (container_check(CONTAINER, task->container))
     386                rc = ddi_iospace_disable_arch(task, ioaddr, size);
     387
    396388        irq_spinlock_unlock(&task->lock, true);
    397 
     389        task_release(task);
    398390        return rc;
    399391}
Note: See TracChangeset for help on using the changeset viewer.