source: mainline/kernel/generic/src/security/perm.c@ 07d4271

Last change on this file since 07d4271 was 07d4271, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 17 months ago

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.

  • Property mode set to 100644
File size: 5.8 KB
RevLine 
[1077d91]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Jermar
[1077d91]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[174156fd]29/** @addtogroup kernel_generic
[b45c443]30 * @{
31 */
32
[cf26ba9]33/**
[719a208]34 * @file perm.c
35 * @brief Task permissions control.
[cf26ba9]36 *
[719a208]37 * @see perm.h
[cf26ba9]38 */
[da1bafb]39
[719a208]40#include <security/perm.h>
[1077d91]41#include <proc/task.h>
42#include <synch/spinlock.h>
[2bb8648]43#include <syscall/copy.h>
[1077d91]44#include <arch.h>
[2bb8648]45#include <errno.h>
[1077d91]46
[719a208]47/** Set permissions.
[1077d91]48 *
[719a208]49 * @param task Task whose permissions are to be changed.
50 * @param perms New set of permissions.
[da1bafb]51 *
[1077d91]52 */
[719a208]53void perm_set(task_t *task, perm_t perms)
[1077d91]54{
[da1bafb]55 irq_spinlock_lock(&task->lock, true);
[719a208]56 task->perms = perms;
[da1bafb]57 irq_spinlock_unlock(&task->lock, true);
[1077d91]58}
59
[719a208]60/** Get permissions.
[1077d91]61 *
[719a208]62 * @param task Task whose permissions are to be returned.
[da1bafb]63 *
[719a208]64 * @return Task's permissions.
[da1bafb]65 *
[1077d91]66 */
[719a208]67perm_t perm_get(task_t *task)
[1077d91]68{
[da1bafb]69 irq_spinlock_lock(&task->lock, true);
[719a208]70 perm_t perms = task->perms;
[da1bafb]71 irq_spinlock_unlock(&task->lock, true);
[a35b458]72
[719a208]73 return perms;
[1077d91]74}
[2bb8648]75
[719a208]76/** Grant permissions to a task.
[2bb8648]77 *
[719a208]78 * The calling task must have the PERM_PERM permission.
[2bb8648]79 *
[6b10dab]80 * @param taskid Destination task ID.
[719a208]81 * @param perms Permissions to grant.
[2bb8648]82 *
83 * @return Zero on success or an error code from @ref errno.h.
[da1bafb]84 *
[2bb8648]85 */
[b7fd2a0]86static errno_t perm_grant(task_id_t taskid, perm_t perms)
[2bb8648]87{
[719a208]88 if (!(perm_get(TASK) & PERM_PERM))
[7f11dc6]89 return EPERM;
[a35b458]90
[6b10dab]91 task_t *task = task_find_by_id(taskid);
[07d4271]92 if (!task)
[7f11dc6]93 return ENOENT;
[a35b458]94
[07d4271]95 errno_t rc = ENOENT;
[a35b458]96
[07d4271]97 irq_spinlock_lock(&task->lock, true);
98 if (container_check(CONTAINER, task->container)) {
99 task->perms |= perms;
100 rc = EOK;
101 }
102 irq_spinlock_unlock(&task->lock, true);
103
104 task_release(task);
105 return rc;
[2bb8648]106}
107
[719a208]108/** Revoke permissions from a task.
[2bb8648]109 *
[719a208]110 * The calling task must have the PERM_PERM permission or the caller must
111 * attempt to revoke permissions from itself.
[2bb8648]112 *
[6b10dab]113 * @param taskid Destination task ID.
[719a208]114 * @param perms Permissions to revoke.
[2bb8648]115 *
116 * @return Zero on success or an error code from @ref errno.h.
[da1bafb]117 *
[2bb8648]118 */
[b7fd2a0]119static errno_t perm_revoke(task_id_t taskid, perm_t perms)
[2bb8648]120{
[6b10dab]121 task_t *task = task_find_by_id(taskid);
[07d4271]122 if (!task)
[7f11dc6]123 return ENOENT;
[a35b458]124
[2bb8648]125 /*
[719a208]126 * Revoking permissions is different from granting them in that
127 * a task can revoke permissions from itself even if it
128 * doesn't have PERM_PERM.
[2bb8648]129 */
[07d4271]130 if (task != TASK && !(perm_get(TASK) & PERM_PERM)) {
131 task_release(task);
[7f11dc6]132 return EPERM;
[2bb8648]133 }
[a35b458]134
[07d4271]135 errno_t rc = ENOENT;
136
137 irq_spinlock_lock(&task->lock, true);
138 if (container_check(CONTAINER, task->container)) {
139 task->perms &= ~perms;
140 rc = EOK;
141 }
142 irq_spinlock_unlock(&task->lock, true);
[a35b458]143
[07d4271]144 task_release(task);
145 return rc;
[2bb8648]146}
[b45c443]147
[6b10dab]148#ifdef __32_BITS__
149
[719a208]150/** Grant permissions to a task (32 bits)
[6b10dab]151 *
[719a208]152 * The calling task must have the PERM_PERM permission.
[6b10dab]153 *
154 * @param uspace_taskid User-space pointer to destination task ID.
[719a208]155 * @param perms Permissions to grant.
[6b10dab]156 *
157 * @return Zero on success or an error code from @ref errno.h.
158 *
159 */
[5a5269d]160sys_errno_t sys_perm_grant(uspace_ptr_sysarg64_t uspace_taskid, perm_t perms)
[6b10dab]161{
162 sysarg64_t taskid;
[b7fd2a0]163 errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t));
[a53ed3a]164 if (rc != EOK)
[b7fd2a0]165 return (sys_errno_t) rc;
[a35b458]166
[719a208]167 return perm_grant((task_id_t) taskid, perms);
[6b10dab]168}
169
[719a208]170/** Revoke permissions from a task (32 bits)
[6b10dab]171 *
[719a208]172 * The calling task must have the PERM_PERM permission or the caller must
173 * attempt to revoke permissions from itself.
[6b10dab]174 *
175 * @param uspace_taskid User-space pointer to destination task ID.
[719a208]176 * @param perms Perms to revoke.
[6b10dab]177 *
178 * @return Zero on success or an error code from @ref errno.h.
179 *
180 */
[5a5269d]181sys_errno_t sys_perm_revoke(uspace_ptr_sysarg64_t uspace_taskid, perm_t perms)
[6b10dab]182{
183 sysarg64_t taskid;
[b7fd2a0]184 errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t));
[a53ed3a]185 if (rc != EOK)
[b7fd2a0]186 return (sys_errno_t) rc;
[a35b458]187
[719a208]188 return perm_revoke((task_id_t) taskid, perms);
[6b10dab]189}
190
191#endif /* __32_BITS__ */
192
193#ifdef __64_BITS__
194
[719a208]195/** Grant permissions to a task (64 bits)
[6b10dab]196 *
[719a208]197 * The calling task must have the PERM_PERM permission.
[6b10dab]198 *
199 * @param taskid Destination task ID.
[719a208]200 * @param perms Permissions to grant.
[6b10dab]201 *
202 * @return Zero on success or an error code from @ref errno.h.
203 *
204 */
[b7fd2a0]205sys_errno_t sys_perm_grant(sysarg_t taskid, perm_t perms)
[6b10dab]206{
[719a208]207 return perm_grant((task_id_t) taskid, perms);
[6b10dab]208}
209
[719a208]210/** Revoke permissions from a task (64 bits)
[6b10dab]211 *
[719a208]212 * The calling task must have the PERM_PERM permission or the caller must
213 * attempt to revoke permissions from itself.
[6b10dab]214 *
215 * @param taskid Destination task ID.
[719a208]216 * @param perms Permissions to revoke.
[6b10dab]217 *
218 * @return Zero on success or an error code from @ref errno.h.
219 *
220 */
[b7fd2a0]221sys_errno_t sys_perm_revoke(sysarg_t taskid, perm_t perms)
[6b10dab]222{
[719a208]223 return perm_revoke((task_id_t) taskid, perms);
[6b10dab]224}
225
226#endif /* __64_BITS__ */
227
[06e1e95]228/** @}
[b45c443]229 */
Note: See TracBrowser for help on using the repository browser.