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


Ignore:
Timestamp:
2024-01-25T16:22:55Z (16 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/ipc/kbox.c

    r1a1e124 r07d4271  
    200200/** Connect phone to a task kernel-box specified by id.
    201201 *
    202  * Note that this is not completely atomic. For optimisation reasons, the task
    203  * might start cleaning up kbox after the phone has been connected and before
    204  * a kbox thread has been created. This must be taken into account in the
    205  * cleanup code.
    206  *
    207202 * @param[out] out_phone  Phone capability handle on success.
    208203 * @return Error code.
     
    211206errno_t ipc_connect_kbox(task_id_t taskid, cap_phone_handle_t *out_phone)
    212207{
    213         irq_spinlock_lock(&tasks_lock, true);
    214 
    215208        task_t *task = task_find_by_id(taskid);
    216         if (task == NULL) {
    217                 irq_spinlock_unlock(&tasks_lock, true);
     209        if (!task)
    218210                return ENOENT;
    219         }
    220 
    221         atomic_inc(&task->refcount);
    222 
    223         irq_spinlock_unlock(&tasks_lock, true);
    224211
    225212        mutex_lock(&task->kb.cleanup_lock);
    226 
    227         if (atomic_predec(&task->refcount) == 0) {
    228                 mutex_unlock(&task->kb.cleanup_lock);
    229                 task_destroy(task);
    230                 return ENOENT;
    231         }
    232213
    233214        if (task->kb.finished) {
    234215                mutex_unlock(&task->kb.cleanup_lock);
     216                task_release(task);
    235217                return EINVAL;
    236218        }
     
    243225                if (!kb_thread) {
    244226                        mutex_unlock(&task->kb.cleanup_lock);
     227                        task_release(task);
    245228                        return ENOMEM;
    246229                }
     
    255238        if (rc != EOK) {
    256239                mutex_unlock(&task->kb.cleanup_lock);
     240                task_release(task);
    257241                return rc;
    258242        }
     
    265249
    266250        mutex_unlock(&task->kb.cleanup_lock);
     251        task_release(task);
    267252        *out_phone = phone_handle;
    268253        return EOK;
Note: See TracChangeset for help on using the changeset viewer.