The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kernel/capability.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * linux/kernel/capability.c
    3  *
    4  * Copyright (C) 1997  Andrew Main <zefram@fysh.org>
    5  * Integrated into 2.1.97+,  Andrew G. Morgan <morgan@transmeta.com>
    6  */ 
    7 
    8 #include <linux/mm.h>
    9 #include <asm/uaccess.h>
   10 
   11 kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
   12 
   13 /* Note: never hold tasklist_lock while spinning for this one */
   14 spinlock_t task_capability_lock = SPIN_LOCK_UNLOCKED;
   15 
   16 /*
   17  * For sys_getproccap() and sys_setproccap(), any of the three
   18  * capability set pointers may be NULL -- indicating that that set is
   19  * uninteresting and/or not to be changed.
   20  */
   21 
   22 asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
   23 {
   24      int error, pid;
   25      __u32 version;
   26      struct task_struct *target;
   27      struct __user_cap_data_struct data;
   28 
   29      if (get_user(version, &header->version))
   30              return -EFAULT;
   31              
   32      error = -EINVAL; 
   33      if (version != _LINUX_CAPABILITY_VERSION) {
   34              version = _LINUX_CAPABILITY_VERSION;
   35              if (put_user(version, &header->version))
   36                      error = -EFAULT; 
   37              return error;
   38      }
   39 
   40      if (get_user(pid, &header->pid))
   41              return -EFAULT; 
   42 
   43      if (pid < 0) 
   44              return -EINVAL;
   45 
   46      error = 0;
   47 
   48      spin_lock(&task_capability_lock);
   49 
   50      if (pid && pid != current->pid) {
   51              read_lock(&tasklist_lock); 
   52              target = find_task_by_pid(pid);  /* identify target of query */
   53              if (!target) 
   54                      error = -ESRCH;
   55      } else {
   56              target = current;
   57      }
   58 
   59      if (!error) { 
   60              data.permitted = cap_t(target->cap_permitted);
   61              data.inheritable = cap_t(target->cap_inheritable); 
   62              data.effective = cap_t(target->cap_effective);
   63      }
   64 
   65      if (target != current)
   66              read_unlock(&tasklist_lock); 
   67      spin_unlock(&task_capability_lock);
   68 
   69      if (!error) {
   70              if (copy_to_user(dataptr, &data, sizeof data))
   71                      return -EFAULT; 
   72      }
   73 
   74      return error;
   75 }
   76 
   77 /* set capabilities for all processes in a given process group */
   78 
   79 static void cap_set_pg(int pgrp,
   80                     kernel_cap_t *effective,
   81                     kernel_cap_t *inheritable,
   82                     kernel_cap_t *permitted)
   83 {
   84      struct task_struct *target;
   85 
   86      /* FIXME: do we need to have a write lock here..? */
   87      read_lock(&tasklist_lock);
   88      for_each_task(target) {
   89              if (target->pgrp != pgrp)
   90                      continue;
   91              target->cap_effective   = *effective;
   92              target->cap_inheritable = *inheritable;
   93              target->cap_permitted   = *permitted;
   94      }
   95      read_unlock(&tasklist_lock);
   96 }
   97 
   98 /* set capabilities for all processes other than 1 and self */
   99 
  100 static void cap_set_all(kernel_cap_t *effective,
  101                      kernel_cap_t *inheritable,
  102                      kernel_cap_t *permitted)
  103 {
  104      struct task_struct *target;
  105 
  106      /* FIXME: do we need to have a write lock here..? */
  107      read_lock(&tasklist_lock);
  108      /* ALL means everyone other than self or 'init' */
  109      for_each_task(target) {
  110              if (target == current || target->pid == 1)
  111                      continue;
  112              target->cap_effective   = *effective;
  113              target->cap_inheritable = *inheritable;
  114              target->cap_permitted   = *permitted;
  115      }
  116      read_unlock(&tasklist_lock);
  117 }
  118 
  119 /*
  120  * The restrictions on setting capabilities are specified as:
  121  *
  122  * [pid is for the 'target' task.  'current' is the calling task.]
  123  *
  124  * I: any raised capabilities must be a subset of the (old current) Permitted
  125  * P: any raised capabilities must be a subset of the (old current) permitted
  126  * E: must be set to a subset of (new target) Permitted
  127  */
  128 
  129 asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
  130 {
  131      kernel_cap_t inheritable, permitted, effective;
  132      __u32 version;
  133      struct task_struct *target;
  134      int error, pid;
  135 
  136      if (get_user(version, &header->version))
  137              return -EFAULT; 
  138 
  139      if (version != _LINUX_CAPABILITY_VERSION) {
  140              version = _LINUX_CAPABILITY_VERSION;
  141              if (put_user(version, &header->version))
  142                      return -EFAULT; 
  143              return -EINVAL;
  144      }
  145 
  146      if (get_user(pid, &header->pid))
  147              return -EFAULT; 
  148 
  149      if (pid && !capable(CAP_SETPCAP))
  150              return -EPERM;
  151 
  152      if (copy_from_user(&effective, &data->effective, sizeof(effective)) ||
  153          copy_from_user(&inheritable, &data->inheritable, sizeof(inheritable)) ||
  154          copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
  155              return -EFAULT; 
  156 
  157      error = -EPERM;
  158      spin_lock(&task_capability_lock);
  159 
  160      if (pid > 0 && pid != current->pid) {
  161              read_lock(&tasklist_lock);
  162              target = find_task_by_pid(pid);  /* identify target of query */
  163              if (!target) {
  164                      error = -ESRCH;
  165                      goto out;
  166              }
  167      } else {
  168              target = current;
  169      }
  170 
  171 
  172      /* verify restrictions on target's new Inheritable set */
  173      if (!cap_issubset(inheritable,
  174                        cap_combine(target->cap_inheritable,
  175                                    current->cap_permitted))) {
  176              goto out;
  177      }
  178 
  179      /* verify restrictions on target's new Permitted set */
  180      if (!cap_issubset(permitted,
  181                        cap_combine(target->cap_permitted,
  182                                    current->cap_permitted))) {
  183              goto out;
  184      }
  185 
  186      /* verify the _new_Effective_ is a subset of the _new_Permitted_ */
  187      if (!cap_issubset(effective, permitted)) {
  188              goto out;
  189      }
  190 
  191      /* having verified that the proposed changes are legal,
  192            we now put them into effect. */
  193      error = 0;
  194 
  195      if (pid < 0) {
  196              if (pid == -1)  /* all procs other than current and init */
  197                      cap_set_all(&effective, &inheritable, &permitted);
  198 
  199              else            /* all procs in process group */
  200                      cap_set_pg(-pid, &effective, &inheritable, &permitted);
  201              goto spin_out;
  202      } else {
  203              /* FIXME: do we need to have a write lock here..? */
  204              target->cap_effective   = effective;
  205              target->cap_inheritable = inheritable;
  206              target->cap_permitted   = permitted;
  207      }
  208 
  209 out:
  210      if (target != current) {
  211              read_unlock(&tasklist_lock);
  212      }
  213 spin_out:
  214      spin_unlock(&task_capability_lock);
  215      return error;
  216 }

Cache object: 29eb239ce284cbd61f0c72ffe738c073


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.