/* * Copyright (c) 2006 Jakub Jermar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup kernel_generic * @{ */ /** * @file perm.c * @brief Task permissions control. * * @see perm.h */ #include <security/perm.h> #include <proc/task.h> #include <synch/spinlock.h> #include <syscall/copy.h> #include <arch.h> #include <errno.h> /** Set permissions. * * @param task Task whose permissions are to be changed. * @param perms New set of permissions. * */ void perm_set(task_t *task, perm_t perms) { irq_spinlock_lock(&task->lock, true); task->perms = perms; irq_spinlock_unlock(&task->lock, true); } /** Get permissions. * * @param task Task whose permissions are to be returned. * * @return Task's permissions. * */ perm_t perm_get(task_t *task) { irq_spinlock_lock(&task->lock, true); perm_t perms = task->perms; irq_spinlock_unlock(&task->lock, true); return perms; } /** Grant permissions to a task. * * The calling task must have the PERM_PERM permission. * * @param taskid Destination task ID. * @param perms Permissions to grant. * * @return Zero on success or an error code from @ref errno.h. * */ static errno_t perm_grant(task_id_t taskid, perm_t perms) { if (!(perm_get(TASK) & PERM_PERM)) return EPERM; task_t *task = task_find_by_id(taskid); if (!task) return ENOENT; errno_t rc = ENOENT; irq_spinlock_lock(&task->lock, true); if (container_check(CONTAINER, task->container)) { task->perms |= perms; rc = EOK; } irq_spinlock_unlock(&task->lock, true); task_release(task); return rc; } /** Revoke permissions from a task. * * The calling task must have the PERM_PERM permission or the caller must * attempt to revoke permissions from itself. * * @param taskid Destination task ID. * @param perms Permissions to revoke. * * @return Zero on success or an error code from @ref errno.h. * */ static errno_t perm_revoke(task_id_t taskid, perm_t perms) { task_t *task = task_find_by_id(taskid); if (!task) return ENOENT; /* * Revoking permissions is different from granting them in that * a task can revoke permissions from itself even if it * doesn't have PERM_PERM. */ if (task != TASK && !(perm_get(TASK) & PERM_PERM)) { task_release(task); return EPERM; } errno_t rc = ENOENT; irq_spinlock_lock(&task->lock, true); if (container_check(CONTAINER, task->container)) { task->perms &= ~perms; rc = EOK; } irq_spinlock_unlock(&task->lock, true); task_release(task); return rc; } #ifdef __32_BITS__ /** Grant permissions to a task (32 bits) * * The calling task must have the PERM_PERM permission. * * @param uspace_taskid User-space pointer to destination task ID. * @param perms Permissions to grant. * * @return Zero on success or an error code from @ref errno.h. * */ sys_errno_t sys_perm_grant(uspace_ptr_sysarg64_t uspace_taskid, perm_t perms) { sysarg64_t taskid; errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t)); if (rc != EOK) return (sys_errno_t) rc; return perm_grant((task_id_t) taskid, perms); } /** Revoke permissions from a task (32 bits) * * The calling task must have the PERM_PERM permission or the caller must * attempt to revoke permissions from itself. * * @param uspace_taskid User-space pointer to destination task ID. * @param perms Perms to revoke. * * @return Zero on success or an error code from @ref errno.h. * */ sys_errno_t sys_perm_revoke(uspace_ptr_sysarg64_t uspace_taskid, perm_t perms) { sysarg64_t taskid; errno_t rc = copy_from_uspace(&taskid, uspace_taskid, sizeof(sysarg64_t)); if (rc != EOK) return (sys_errno_t) rc; return perm_revoke((task_id_t) taskid, perms); } #endif /* __32_BITS__ */ #ifdef __64_BITS__ /** Grant permissions to a task (64 bits) * * The calling task must have the PERM_PERM permission. * * @param taskid Destination task ID. * @param perms Permissions to grant. * * @return Zero on success or an error code from @ref errno.h. * */ sys_errno_t sys_perm_grant(sysarg_t taskid, perm_t perms) { return perm_grant((task_id_t) taskid, perms); } /** Revoke permissions from a task (64 bits) * * The calling task must have the PERM_PERM permission or the caller must * attempt to revoke permissions from itself. * * @param taskid Destination task ID. * @param perms Permissions to revoke. * * @return Zero on success or an error code from @ref errno.h. * */ sys_errno_t sys_perm_revoke(sysarg_t taskid, perm_t perms) { return perm_revoke((task_id_t) taskid, perms); } #endif /* __64_BITS__ */ /** @} */