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/sys.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/sys.c
    3  *
    4  *  Copyright (C) 1991, 1992  Linus Torvalds
    5  */
    6 
    7 #include <linux/module.h>
    8 #include <linux/mm.h>
    9 #include <linux/utsname.h>
   10 #include <linux/mman.h>
   11 #include <linux/smp_lock.h>
   12 #include <linux/notifier.h>
   13 #include <linux/reboot.h>
   14 #include <linux/prctl.h>
   15 #include <linux/init.h>
   16 #include <linux/highuid.h>
   17 
   18 #include <asm/uaccess.h>
   19 #include <asm/io.h>
   20 
   21 #ifndef SET_UNALIGN_CTL
   22 # define SET_UNALIGN_CTL(a,b)   (-EINVAL)
   23 #endif
   24 #ifndef GET_UNALIGN_CTL
   25 # define GET_UNALIGN_CTL(a,b)   (-EINVAL)
   26 #endif
   27 #ifndef SET_FPEMU_CTL
   28 # define SET_FPEMU_CTL(a,b)     (-EINVAL)
   29 #endif
   30 #ifndef GET_FPEMU_CTL
   31 # define GET_FPEMU_CTL(a,b)     (-EINVAL)
   32 #endif
   33 #ifndef SET_FPEXC_CTL
   34 # define SET_FPEXC_CTL(a,b)     (-EINVAL)
   35 #endif
   36 #ifndef GET_FPEXC_CTL
   37 # define GET_FPEXC_CTL(a,b)     (-EINVAL)
   38 #endif
   39 
   40 /*
   41  * this is where the system-wide overflow UID and GID are defined, for
   42  * architectures that now have 32-bit UID/GID but didn't in the past
   43  */
   44 
   45 int overflowuid = DEFAULT_OVERFLOWUID;
   46 int overflowgid = DEFAULT_OVERFLOWGID;
   47 
   48 /*
   49  * the same as above, but for filesystems which can only store a 16-bit
   50  * UID and GID. as such, this is needed on all architectures
   51  */
   52 
   53 int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
   54 int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;
   55 
   56 /*
   57  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
   58  */
   59 
   60 int C_A_D = 1;
   61 int cad_pid = 1;
   62 
   63 
   64 /*
   65  *      Notifier list for kernel code which wants to be called
   66  *      at shutdown. This is used to stop any idling DMA operations
   67  *      and the like. 
   68  */
   69 
   70 static struct notifier_block *reboot_notifier_list;
   71 rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
   72 
   73 /**
   74  *      notifier_chain_register - Add notifier to a notifier chain
   75  *      @list: Pointer to root list pointer
   76  *      @n: New entry in notifier chain
   77  *
   78  *      Adds a notifier to a notifier chain.
   79  *
   80  *      Currently always returns zero.
   81  */
   82  
   83 int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
   84 {
   85         write_lock(&notifier_lock);
   86         while(*list)
   87         {
   88                 if(n->priority > (*list)->priority)
   89                         break;
   90                 list= &((*list)->next);
   91         }
   92         n->next = *list;
   93         *list=n;
   94         write_unlock(&notifier_lock);
   95         return 0;
   96 }
   97 
   98 /**
   99  *      notifier_chain_unregister - Remove notifier from a notifier chain
  100  *      @nl: Pointer to root list pointer
  101  *      @n: New entry in notifier chain
  102  *
  103  *      Removes a notifier from a notifier chain.
  104  *
  105  *      Returns zero on success, or %-ENOENT on failure.
  106  */
  107  
  108 int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
  109 {
  110         write_lock(&notifier_lock);
  111         while((*nl)!=NULL)
  112         {
  113                 if((*nl)==n)
  114                 {
  115                         *nl=n->next;
  116                         write_unlock(&notifier_lock);
  117                         return 0;
  118                 }
  119                 nl=&((*nl)->next);
  120         }
  121         write_unlock(&notifier_lock);
  122         return -ENOENT;
  123 }
  124 
  125 /**
  126  *      notifier_call_chain - Call functions in a notifier chain
  127  *      @n: Pointer to root pointer of notifier chain
  128  *      @val: Value passed unmodified to notifier function
  129  *      @v: Pointer passed unmodified to notifier function
  130  *
  131  *      Calls each function in a notifier chain in turn.
  132  *
  133  *      If the return value of the notifier can be and'd
  134  *      with %NOTIFY_STOP_MASK, then notifier_call_chain
  135  *      will return immediately, with the return value of
  136  *      the notifier function which halted execution.
  137  *      Otherwise, the return value is the return value
  138  *      of the last notifier function called.
  139  */
  140  
  141 int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
  142 {
  143         int ret=NOTIFY_DONE;
  144         struct notifier_block *nb = *n;
  145 
  146         while(nb)
  147         {
  148                 ret=nb->notifier_call(nb,val,v);
  149                 if(ret&NOTIFY_STOP_MASK)
  150                 {
  151                         return ret;
  152                 }
  153                 nb=nb->next;
  154         }
  155         return ret;
  156 }
  157 
  158 /**
  159  *      register_reboot_notifier - Register function to be called at reboot time
  160  *      @nb: Info about notifier function to be called
  161  *
  162  *      Registers a function with the list of functions
  163  *      to be called at reboot time.
  164  *
  165  *      Currently always returns zero, as notifier_chain_register
  166  *      always returns zero.
  167  */
  168  
  169 int register_reboot_notifier(struct notifier_block * nb)
  170 {
  171         return notifier_chain_register(&reboot_notifier_list, nb);
  172 }
  173 
  174 /**
  175  *      unregister_reboot_notifier - Unregister previously registered reboot notifier
  176  *      @nb: Hook to be unregistered
  177  *
  178  *      Unregisters a previously registered reboot
  179  *      notifier function.
  180  *
  181  *      Returns zero on success, or %-ENOENT on failure.
  182  */
  183  
  184 int unregister_reboot_notifier(struct notifier_block * nb)
  185 {
  186         return notifier_chain_unregister(&reboot_notifier_list, nb);
  187 }
  188 
  189 asmlinkage long sys_ni_syscall(void)
  190 {
  191         return -ENOSYS;
  192 }
  193 
  194 static int proc_sel(struct task_struct *p, int which, int who)
  195 {
  196         if(p->pid)
  197         {
  198                 switch (which) {
  199                         case PRIO_PROCESS:
  200                                 if (!who && p == current)
  201                                         return 1;
  202                                 return(p->pid == who);
  203                         case PRIO_PGRP:
  204                                 if (!who)
  205                                         who = current->pgrp;
  206                                 return(p->pgrp == who);
  207                         case PRIO_USER:
  208                                 if (!who)
  209                                         who = current->uid;
  210                                 return(p->uid == who);
  211                 }
  212         }
  213         return 0;
  214 }
  215 
  216 asmlinkage long sys_setpriority(int which, int who, int niceval)
  217 {
  218         struct task_struct *p;
  219         int error;
  220 
  221         if (which > 2 || which < 0)
  222                 return -EINVAL;
  223 
  224         /* normalize: avoid signed division (rounding problems) */
  225         error = -ESRCH;
  226         if (niceval < -20)
  227                 niceval = -20;
  228         if (niceval > 19)
  229                 niceval = 19;
  230 
  231         read_lock(&tasklist_lock);
  232         for_each_task(p) {
  233                 if (!proc_sel(p, which, who))
  234                         continue;
  235                 if (p->uid != current->euid &&
  236                         p->uid != current->uid && !capable(CAP_SYS_NICE)) {
  237                         error = -EPERM;
  238                         continue;
  239                 }
  240                 if (error == -ESRCH)
  241                         error = 0;
  242                 if (niceval < p->nice && !capable(CAP_SYS_NICE))
  243                         error = -EACCES;
  244                 else
  245                         p->nice = niceval;
  246         }
  247         read_unlock(&tasklist_lock);
  248 
  249         return error;
  250 }
  251 
  252 /*
  253  * Ugh. To avoid negative return values, "getpriority()" will
  254  * not return the normal nice-value, but a negated value that
  255  * has been offset by 20 (ie it returns 40..1 instead of -20..19)
  256  * to stay compatible.
  257  */
  258 asmlinkage long sys_getpriority(int which, int who)
  259 {
  260         struct task_struct *p;
  261         long retval = -ESRCH;
  262 
  263         if (which > 2 || which < 0)
  264                 return -EINVAL;
  265 
  266         read_lock(&tasklist_lock);
  267         for_each_task (p) {
  268                 long niceval;
  269                 if (!proc_sel(p, which, who))
  270                         continue;
  271                 niceval = 20 - p->nice;
  272                 if (niceval > retval)
  273                         retval = niceval;
  274         }
  275         read_unlock(&tasklist_lock);
  276 
  277         return retval;
  278 }
  279 
  280 
  281 /*
  282  * Reboot system call: for obvious reasons only root may call it,
  283  * and even root needs to set up some magic numbers in the registers
  284  * so that some mistake won't make this reboot the whole machine.
  285  * You can also set the meaning of the ctrl-alt-del-key here.
  286  *
  287  * reboot doesn't sync: do that yourself before calling this.
  288  */
  289 asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg)
  290 {
  291         char buffer[256];
  292 
  293         /* We only trust the superuser with rebooting the system. */
  294         if (!capable(CAP_SYS_BOOT))
  295                 return -EPERM;
  296 
  297         /* For safety, we require "magic" arguments. */
  298         if (magic1 != LINUX_REBOOT_MAGIC1 ||
  299             (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
  300                         magic2 != LINUX_REBOOT_MAGIC2B))
  301                 return -EINVAL;
  302 
  303         lock_kernel();
  304         switch (cmd) {
  305         case LINUX_REBOOT_CMD_RESTART:
  306                 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
  307                 printk(KERN_EMERG "Restarting system.\n");
  308                 machine_restart(NULL);
  309                 break;
  310 
  311         case LINUX_REBOOT_CMD_CAD_ON:
  312                 C_A_D = 1;
  313                 break;
  314 
  315         case LINUX_REBOOT_CMD_CAD_OFF:
  316                 C_A_D = 0;
  317                 break;
  318 
  319         case LINUX_REBOOT_CMD_HALT:
  320                 notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
  321                 printk(KERN_EMERG "System halted.\n");
  322                 machine_halt();
  323                 do_exit(0);
  324                 break;
  325 
  326         case LINUX_REBOOT_CMD_POWER_OFF:
  327                 notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
  328                 printk(KERN_EMERG "Power down.\n");
  329                 machine_power_off();
  330                 do_exit(0);
  331                 break;
  332 
  333         case LINUX_REBOOT_CMD_RESTART2:
  334                 if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
  335                         unlock_kernel();
  336                         return -EFAULT;
  337                 }
  338                 buffer[sizeof(buffer) - 1] = '\0';
  339 
  340                 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
  341                 printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
  342                 machine_restart(buffer);
  343                 break;
  344 
  345         default:
  346                 unlock_kernel();
  347                 return -EINVAL;
  348         }
  349         unlock_kernel();
  350         return 0;
  351 }
  352 
  353 static void deferred_cad(void *dummy)
  354 {
  355         notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
  356         machine_restart(NULL);
  357 }
  358 
  359 /*
  360  * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
  361  * As it's called within an interrupt, it may NOT sync: the only choice
  362  * is whether to reboot at once, or just ignore the ctrl-alt-del.
  363  */
  364 void ctrl_alt_del(void)
  365 {
  366         static struct tq_struct cad_tq = {
  367                 routine: deferred_cad,
  368         };
  369 
  370         if (C_A_D)
  371                 schedule_task(&cad_tq);
  372         else
  373                 kill_proc(cad_pid, SIGINT, 1);
  374 }
  375         
  376 
  377 /*
  378  * Unprivileged users may change the real gid to the effective gid
  379  * or vice versa.  (BSD-style)
  380  *
  381  * If you set the real gid at all, or set the effective gid to a value not
  382  * equal to the real gid, then the saved gid is set to the new effective gid.
  383  *
  384  * This makes it possible for a setgid program to completely drop its
  385  * privileges, which is often a useful assertion to make when you are doing
  386  * a security audit over a program.
  387  *
  388  * The general idea is that a program which uses just setregid() will be
  389  * 100% compatible with BSD.  A program which uses just setgid() will be
  390  * 100% compatible with POSIX with saved IDs. 
  391  *
  392  * SMP: There are not races, the GIDs are checked only by filesystem
  393  *      operations (as far as semantic preservation is concerned).
  394  */
  395 asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
  396 {
  397         int old_rgid = current->gid;
  398         int old_egid = current->egid;
  399         int new_rgid = old_rgid;
  400         int new_egid = old_egid;
  401 
  402         if (rgid != (gid_t) -1) {
  403                 if ((old_rgid == rgid) ||
  404                     (current->egid==rgid) ||
  405                     capable(CAP_SETGID))
  406                         new_rgid = rgid;
  407                 else
  408                         return -EPERM;
  409         }
  410         if (egid != (gid_t) -1) {
  411                 if ((old_rgid == egid) ||
  412                     (current->egid == egid) ||
  413                     (current->sgid == egid) ||
  414                     capable(CAP_SETGID))
  415                         new_egid = egid;
  416                 else {
  417                         return -EPERM;
  418                 }
  419         }
  420         if (new_egid != old_egid)
  421         {
  422                 current->mm->dumpable = 0;
  423                 wmb();
  424         }
  425         if (rgid != (gid_t) -1 ||
  426             (egid != (gid_t) -1 && egid != old_rgid))
  427                 current->sgid = new_egid;
  428         current->fsgid = new_egid;
  429         current->egid = new_egid;
  430         current->gid = new_rgid;
  431         return 0;
  432 }
  433 
  434 /*
  435  * setgid() is implemented like SysV w/ SAVED_IDS 
  436  *
  437  * SMP: Same implicit races as above.
  438  */
  439 asmlinkage long sys_setgid(gid_t gid)
  440 {
  441         int old_egid = current->egid;
  442 
  443         if (capable(CAP_SETGID))
  444         {
  445                 if(old_egid != gid)
  446                 {
  447                         current->mm->dumpable=0;
  448                         wmb();
  449                 }
  450                 current->gid = current->egid = current->sgid = current->fsgid = gid;
  451         }
  452         else if ((gid == current->gid) || (gid == current->sgid))
  453         {
  454                 if(old_egid != gid)
  455                 {
  456                         current->mm->dumpable=0;
  457                         wmb();
  458                 }
  459                 current->egid = current->fsgid = gid;
  460         }
  461         else
  462                 return -EPERM;
  463         return 0;
  464 }
  465   
  466 /* 
  467  * cap_emulate_setxuid() fixes the effective / permitted capabilities of
  468  * a process after a call to setuid, setreuid, or setresuid.
  469  *
  470  *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
  471  *  {r,e,s}uid != 0, the permitted and effective capabilities are
  472  *  cleared.
  473  *
  474  *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
  475  *  capabilities of the process are cleared.
  476  *
  477  *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
  478  *  capabilities are set to the permitted capabilities.
  479  *
  480  *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
  481  *  never happen.
  482  *
  483  *  -astor 
  484  *
  485  * cevans - New behaviour, Oct '99
  486  * A process may, via prctl(), elect to keep its capabilities when it
  487  * calls setuid() and switches away from uid==0. Both permitted and
  488  * effective sets will be retained.
  489  * Without this change, it was impossible for a daemon to drop only some
  490  * of its privilege. The call to setuid(!=0) would drop all privileges!
  491  * Keeping uid 0 is not an option because uid 0 owns too many vital
  492  * files..
  493  * Thanks to Olaf Kirch and Peter Benie for spotting this.
  494  */
  495 static inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
  496                                        int old_suid)
  497 {
  498         if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
  499             (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
  500             !current->keep_capabilities) {
  501                 cap_clear(current->cap_permitted);
  502                 cap_clear(current->cap_effective);
  503         }
  504         if (old_euid == 0 && current->euid != 0) {
  505                 cap_clear(current->cap_effective);
  506         }
  507         if (old_euid != 0 && current->euid == 0) {
  508                 current->cap_effective = current->cap_permitted;
  509         }
  510 }
  511 
  512 static int set_user(uid_t new_ruid, int dumpclear)
  513 {
  514         struct user_struct *new_user, *old_user;
  515 
  516         /* What if a process setreuid()'s and this brings the
  517          * new uid over his NPROC rlimit?  We can check this now
  518          * cheaply with the new uid cache, so if it matters
  519          * we should be checking for it.  -DaveM
  520          */
  521         new_user = alloc_uid(new_ruid);
  522         if (!new_user)
  523                 return -EAGAIN;
  524         old_user = current->user;
  525         atomic_dec(&old_user->processes);
  526         atomic_inc(&new_user->processes);
  527 
  528         if(dumpclear)
  529         {
  530                 current->mm->dumpable = 0;
  531                 wmb();
  532         }
  533         current->uid = new_ruid;
  534         current->user = new_user;
  535         free_uid(old_user);
  536         return 0;
  537 }
  538 
  539 /*
  540  * Unprivileged users may change the real uid to the effective uid
  541  * or vice versa.  (BSD-style)
  542  *
  543  * If you set the real uid at all, or set the effective uid to a value not
  544  * equal to the real uid, then the saved uid is set to the new effective uid.
  545  *
  546  * This makes it possible for a setuid program to completely drop its
  547  * privileges, which is often a useful assertion to make when you are doing
  548  * a security audit over a program.
  549  *
  550  * The general idea is that a program which uses just setreuid() will be
  551  * 100% compatible with BSD.  A program which uses just setuid() will be
  552  * 100% compatible with POSIX with saved IDs. 
  553  */
  554 asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
  555 {
  556         int old_ruid, old_euid, old_suid, new_ruid, new_euid;
  557 
  558         new_ruid = old_ruid = current->uid;
  559         new_euid = old_euid = current->euid;
  560         old_suid = current->suid;
  561 
  562         if (ruid != (uid_t) -1) {
  563                 new_ruid = ruid;
  564                 if ((old_ruid != ruid) &&
  565                     (current->euid != ruid) &&
  566                     !capable(CAP_SETUID))
  567                         return -EPERM;
  568         }
  569 
  570         if (euid != (uid_t) -1) {
  571                 new_euid = euid;
  572                 if ((old_ruid != euid) &&
  573                     (current->euid != euid) &&
  574                     (current->suid != euid) &&
  575                     !capable(CAP_SETUID))
  576                         return -EPERM;
  577         }
  578 
  579         if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
  580                 return -EAGAIN;
  581 
  582         if (new_euid != old_euid)
  583         {
  584                 current->mm->dumpable=0;
  585                 wmb();
  586         }
  587         current->fsuid = current->euid = new_euid;
  588         if (ruid != (uid_t) -1 ||
  589             (euid != (uid_t) -1 && euid != old_ruid))
  590                 current->suid = current->euid;
  591         current->fsuid = current->euid;
  592 
  593         if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  594                 cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  595         }
  596 
  597         return 0;
  598 }
  599 
  600 
  601                 
  602 /*
  603  * setuid() is implemented like SysV with SAVED_IDS 
  604  * 
  605  * Note that SAVED_ID's is deficient in that a setuid root program
  606  * like sendmail, for example, cannot set its uid to be a normal 
  607  * user and then switch back, because if you're root, setuid() sets
  608  * the saved uid too.  If you don't like this, blame the bright people
  609  * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
  610  * will allow a root program to temporarily drop privileges and be able to
  611  * regain them by swapping the real and effective uid.  
  612  */
  613 asmlinkage long sys_setuid(uid_t uid)
  614 {
  615         int old_euid = current->euid;
  616         int old_ruid, old_suid, new_ruid, new_suid;
  617 
  618         old_ruid = new_ruid = current->uid;
  619         old_suid = current->suid;
  620         new_suid = old_suid;
  621         
  622         if (capable(CAP_SETUID)) {
  623                 if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
  624                         return -EAGAIN;
  625                 new_suid = uid;
  626         } else if ((uid != current->uid) && (uid != new_suid))
  627                 return -EPERM;
  628 
  629         if (old_euid != uid)
  630         {
  631                 current->mm->dumpable = 0;
  632                 wmb();
  633         }
  634         current->fsuid = current->euid = uid;
  635         current->suid = new_suid;
  636 
  637         if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  638                 cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  639         }
  640 
  641         return 0;
  642 }
  643 
  644 
  645 /*
  646  * This function implements a generic ability to update ruid, euid,
  647  * and suid.  This allows you to implement the 4.4 compatible seteuid().
  648  */
  649 asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
  650 {
  651         int old_ruid = current->uid;
  652         int old_euid = current->euid;
  653         int old_suid = current->suid;
  654 
  655         if (!capable(CAP_SETUID)) {
  656                 if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
  657                     (ruid != current->euid) && (ruid != current->suid))
  658                         return -EPERM;
  659                 if ((euid != (uid_t) -1) && (euid != current->uid) &&
  660                     (euid != current->euid) && (euid != current->suid))
  661                         return -EPERM;
  662                 if ((suid != (uid_t) -1) && (suid != current->uid) &&
  663                     (suid != current->euid) && (suid != current->suid))
  664                         return -EPERM;
  665         }
  666         if (ruid != (uid_t) -1) {
  667                 if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
  668                         return -EAGAIN;
  669         }
  670         if (euid != (uid_t) -1) {
  671                 if (euid != current->euid)
  672                 {
  673                         current->mm->dumpable = 0;
  674                         wmb();
  675                 }
  676                 current->euid = euid;
  677         }
  678         current->fsuid = current->euid;
  679         if (suid != (uid_t) -1)
  680                 current->suid = suid;
  681 
  682         if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  683                 cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  684         }
  685 
  686         return 0;
  687 }
  688 
  689 asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
  690 {
  691         int retval;
  692 
  693         if (!(retval = put_user(current->uid, ruid)) &&
  694             !(retval = put_user(current->euid, euid)))
  695                 retval = put_user(current->suid, suid);
  696 
  697         return retval;
  698 }
  699 
  700 /*
  701  * Same as above, but for rgid, egid, sgid.
  702  */
  703 asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
  704 {
  705         if (!capable(CAP_SETGID)) {
  706                 if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
  707                     (rgid != current->egid) && (rgid != current->sgid))
  708                         return -EPERM;
  709                 if ((egid != (gid_t) -1) && (egid != current->gid) &&
  710                     (egid != current->egid) && (egid != current->sgid))
  711                         return -EPERM;
  712                 if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
  713                     (sgid != current->egid) && (sgid != current->sgid))
  714                         return -EPERM;
  715         }
  716         if (egid != (gid_t) -1) {
  717                 if (egid != current->egid)
  718                 {
  719                         current->mm->dumpable = 0;
  720                         wmb();
  721                 }
  722                 current->egid = egid;
  723         }
  724         current->fsgid = current->egid;
  725         if (rgid != (gid_t) -1)
  726                 current->gid = rgid;
  727         if (sgid != (gid_t) -1)
  728                 current->sgid = sgid;
  729         return 0;
  730 }
  731 
  732 asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
  733 {
  734         int retval;
  735 
  736         if (!(retval = put_user(current->gid, rgid)) &&
  737             !(retval = put_user(current->egid, egid)))
  738                 retval = put_user(current->sgid, sgid);
  739 
  740         return retval;
  741 }
  742 
  743 
  744 /*
  745  * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
  746  * is used for "access()" and for the NFS daemon (letting nfsd stay at
  747  * whatever uid it wants to). It normally shadows "euid", except when
  748  * explicitly set by setfsuid() or for access..
  749  */
  750 asmlinkage long sys_setfsuid(uid_t uid)
  751 {
  752         int old_fsuid;
  753 
  754         old_fsuid = current->fsuid;
  755         if (uid == current->uid || uid == current->euid ||
  756             uid == current->suid || uid == current->fsuid || 
  757             capable(CAP_SETUID))
  758         {
  759                 if (uid != old_fsuid)
  760                 {
  761                         current->mm->dumpable = 0;
  762                         wmb();
  763                 }
  764                 current->fsuid = uid;
  765         }
  766 
  767         /* We emulate fsuid by essentially doing a scaled-down version
  768          * of what we did in setresuid and friends. However, we only
  769          * operate on the fs-specific bits of the process' effective
  770          * capabilities 
  771          *
  772          * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
  773          *          if not, we might be a bit too harsh here.
  774          */
  775         
  776         if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  777                 if (old_fsuid == 0 && current->fsuid != 0) {
  778                         cap_t(current->cap_effective) &= ~CAP_FS_MASK;
  779                 }
  780                 if (old_fsuid != 0 && current->fsuid == 0) {
  781                         cap_t(current->cap_effective) |=
  782                                 (cap_t(current->cap_permitted) & CAP_FS_MASK);
  783                 }
  784         }
  785 
  786         return old_fsuid;
  787 }
  788 
  789 /*
  790  * Samma på svenska..
  791  */
  792 asmlinkage long sys_setfsgid(gid_t gid)
  793 {
  794         int old_fsgid;
  795 
  796         old_fsgid = current->fsgid;
  797         if (gid == current->gid || gid == current->egid ||
  798             gid == current->sgid || gid == current->fsgid || 
  799             capable(CAP_SETGID))
  800         {
  801                 if (gid != old_fsgid)
  802                 {
  803                         current->mm->dumpable = 0;
  804                         wmb();
  805                 }
  806                 current->fsgid = gid;
  807         }
  808         return old_fsgid;
  809 }
  810 
  811 asmlinkage long sys_times(struct tms * tbuf)
  812 {
  813         /*
  814          *      In the SMP world we might just be unlucky and have one of
  815          *      the times increment as we use it. Since the value is an
  816          *      atomically safe type this is just fine. Conceptually its
  817          *      as if the syscall took an instant longer to occur.
  818          */
  819         if (tbuf)
  820                 if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
  821                         return -EFAULT;
  822         return jiffies;
  823 }
  824 
  825 /*
  826  * This needs some heavy checking ...
  827  * I just haven't the stomach for it. I also don't fully
  828  * understand sessions/pgrp etc. Let somebody who does explain it.
  829  *
  830  * OK, I think I have the protection semantics right.... this is really
  831  * only important on a multi-user system anyway, to make sure one user
  832  * can't send a signal to a process owned by another.  -TYT, 12/12/91
  833  *
  834  * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
  835  * LBT 04.03.94
  836  */
  837 
  838 asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
  839 {
  840         struct task_struct * p;
  841         int err = -EINVAL;
  842 
  843         if (!pid)
  844                 pid = current->pid;
  845         if (!pgid)
  846                 pgid = pid;
  847         if (pgid < 0)
  848                 return -EINVAL;
  849 
  850         /* From this point forward we keep holding onto the tasklist lock
  851          * so that our parent does not change from under us. -DaveM
  852          */
  853         read_lock(&tasklist_lock);
  854 
  855         err = -ESRCH;
  856         p = find_task_by_pid(pid);
  857         if (!p)
  858                 goto out;
  859 
  860         if (p->p_pptr == current || p->p_opptr == current) {
  861                 err = -EPERM;
  862                 if (p->session != current->session)
  863                         goto out;
  864                 err = -EACCES;
  865                 if (p->did_exec)
  866                         goto out;
  867         } else if (p != current)
  868                 goto out;
  869         err = -EPERM;
  870         if (p->leader)
  871                 goto out;
  872         if (pgid != pid) {
  873                 struct task_struct * tmp;
  874                 for_each_task (tmp) {
  875                         if (tmp->pgrp == pgid &&
  876                             tmp->session == current->session)
  877                                 goto ok_pgid;
  878                 }
  879                 goto out;
  880         }
  881 
  882 ok_pgid:
  883         p->pgrp = pgid;
  884         err = 0;
  885 out:
  886         /* All paths lead to here, thus we are safe. -DaveM */
  887         read_unlock(&tasklist_lock);
  888         return err;
  889 }
  890 
  891 asmlinkage long sys_getpgid(pid_t pid)
  892 {
  893         if (!pid) {
  894                 return current->pgrp;
  895         } else {
  896                 int retval;
  897                 struct task_struct *p;
  898 
  899                 read_lock(&tasklist_lock);
  900                 p = find_task_by_pid(pid);
  901 
  902                 retval = -ESRCH;
  903                 if (p)
  904                         retval = p->pgrp;
  905                 read_unlock(&tasklist_lock);
  906                 return retval;
  907         }
  908 }
  909 
  910 asmlinkage long sys_getpgrp(void)
  911 {
  912         /* SMP - assuming writes are word atomic this is fine */
  913         return current->pgrp;
  914 }
  915 
  916 asmlinkage long sys_getsid(pid_t pid)
  917 {
  918         if (!pid) {
  919                 return current->session;
  920         } else {
  921                 int retval;
  922                 struct task_struct *p;
  923 
  924                 read_lock(&tasklist_lock);
  925                 p = find_task_by_pid(pid);
  926 
  927                 retval = -ESRCH;
  928                 if(p)
  929                         retval = p->session;
  930                 read_unlock(&tasklist_lock);
  931                 return retval;
  932         }
  933 }
  934 
  935 asmlinkage long sys_setsid(void)
  936 {
  937         struct task_struct * p;
  938         int err = -EPERM;
  939 
  940         read_lock(&tasklist_lock);
  941         for_each_task(p) {
  942                 if (p->pgrp == current->pid)
  943                         goto out;
  944         }
  945 
  946         current->leader = 1;
  947         current->session = current->pgrp = current->pid;
  948         current->tty = NULL;
  949         current->tty_old_pgrp = 0;
  950         err = current->pgrp;
  951 out:
  952         read_unlock(&tasklist_lock);
  953         return err;
  954 }
  955 
  956 /*
  957  * Supplementary group IDs
  958  */
  959 asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist)
  960 {
  961         int i;
  962         
  963         /*
  964          *      SMP: Nobody else can change our grouplist. Thus we are
  965          *      safe.
  966          */
  967 
  968         if (gidsetsize < 0)
  969                 return -EINVAL;
  970         i = current->ngroups;
  971         if (gidsetsize) {
  972                 if (i > gidsetsize)
  973                         return -EINVAL;
  974                 if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
  975                         return -EFAULT;
  976         }
  977         return i;
  978 }
  979 
  980 /*
  981  *      SMP: Our groups are not shared. We can copy to/from them safely
  982  *      without another task interfering.
  983  */
  984  
  985 asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist)
  986 {
  987         if (!capable(CAP_SETGID))
  988                 return -EPERM;
  989         if ((unsigned) gidsetsize > NGROUPS)
  990                 return -EINVAL;
  991         if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
  992                 return -EFAULT;
  993         current->ngroups = gidsetsize;
  994         return 0;
  995 }
  996 
  997 static int supplemental_group_member(gid_t grp)
  998 {
  999         int i = current->ngroups;
 1000 
 1001         if (i) {
 1002                 gid_t *groups = current->groups;
 1003                 do {
 1004                         if (*groups == grp)
 1005                                 return 1;
 1006                         groups++;
 1007                         i--;
 1008                 } while (i);
 1009         }
 1010         return 0;
 1011 }
 1012 
 1013 /*
 1014  * Check whether we're fsgid/egid or in the supplemental group..
 1015  */
 1016 int in_group_p(gid_t grp)
 1017 {
 1018         int retval = 1;
 1019         if (grp != current->fsgid)
 1020                 retval = supplemental_group_member(grp);
 1021         return retval;
 1022 }
 1023 
 1024 int in_egroup_p(gid_t grp)
 1025 {
 1026         int retval = 1;
 1027         if (grp != current->egid)
 1028                 retval = supplemental_group_member(grp);
 1029         return retval;
 1030 }
 1031 
 1032 DECLARE_RWSEM(uts_sem);
 1033 
 1034 asmlinkage long sys_newuname(struct new_utsname * name)
 1035 {
 1036         int errno = 0;
 1037 
 1038         down_read(&uts_sem);
 1039         if (copy_to_user(name,&system_utsname,sizeof *name))
 1040                 errno = -EFAULT;
 1041         up_read(&uts_sem);
 1042         return errno;
 1043 }
 1044 
 1045 asmlinkage long sys_sethostname(char *name, int len)
 1046 {
 1047         int errno;
 1048         char tmp[__NEW_UTS_LEN];
 1049 
 1050         if (!capable(CAP_SYS_ADMIN))
 1051                 return -EPERM;
 1052         if (len < 0 || len > __NEW_UTS_LEN)
 1053                 return -EINVAL;
 1054         down_write(&uts_sem);
 1055         errno = -EFAULT;
 1056         if (!copy_from_user(tmp, name, len)) {
 1057                 memcpy(system_utsname.nodename, tmp, len);
 1058                 system_utsname.nodename[len] = 0;
 1059                 errno = 0;
 1060         }
 1061         up_write(&uts_sem);
 1062         return errno;
 1063 }
 1064 
 1065 asmlinkage long sys_gethostname(char *name, int len)
 1066 {
 1067         int i, errno;
 1068 
 1069         if (len < 0)
 1070                 return -EINVAL;
 1071         down_read(&uts_sem);
 1072         i = 1 + strlen(system_utsname.nodename);
 1073         if (i > len)
 1074                 i = len;
 1075         errno = 0;
 1076         if (copy_to_user(name, system_utsname.nodename, i))
 1077                 errno = -EFAULT;
 1078         up_read(&uts_sem);
 1079         return errno;
 1080 }
 1081 
 1082 /*
 1083  * Only setdomainname; getdomainname can be implemented by calling
 1084  * uname()
 1085  */
 1086 asmlinkage long sys_setdomainname(char *name, int len)
 1087 {
 1088         int errno;
 1089         char tmp[__NEW_UTS_LEN];
 1090 
 1091         if (!capable(CAP_SYS_ADMIN))
 1092                 return -EPERM;
 1093         if (len < 0 || len > __NEW_UTS_LEN)
 1094                 return -EINVAL;
 1095 
 1096         down_write(&uts_sem);
 1097         errno = -EFAULT;
 1098         if (!copy_from_user(tmp, name, len)) {
 1099                 memcpy(system_utsname.domainname, tmp, len);
 1100                 system_utsname.domainname[len] = 0;
 1101                 errno = 0;
 1102         }
 1103         up_write(&uts_sem);
 1104         return errno;
 1105 }
 1106 
 1107 asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim)
 1108 {
 1109         if (resource >= RLIM_NLIMITS)
 1110                 return -EINVAL;
 1111         else
 1112                 return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
 1113                         ? -EFAULT : 0;
 1114 }
 1115 
 1116 #if !defined(__ia64__) 
 1117 
 1118 /*
 1119  *      Back compatibility for getrlimit. Needed for some apps.
 1120  */
 1121  
 1122 asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim)
 1123 {
 1124         struct rlimit x;
 1125         if (resource >= RLIM_NLIMITS)
 1126                 return -EINVAL;
 1127 
 1128         memcpy(&x, current->rlim + resource, sizeof(*rlim));
 1129         if(x.rlim_cur > 0x7FFFFFFF)
 1130                 x.rlim_cur = 0x7FFFFFFF;
 1131         if(x.rlim_max > 0x7FFFFFFF)
 1132                 x.rlim_max = 0x7FFFFFFF;
 1133         return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
 1134 }
 1135 
 1136 #endif
 1137 
 1138 asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim)
 1139 {
 1140         struct rlimit new_rlim, *old_rlim;
 1141 
 1142         if (resource >= RLIM_NLIMITS)
 1143                 return -EINVAL;
 1144         if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
 1145                 return -EFAULT;
 1146        if (new_rlim.rlim_cur > new_rlim.rlim_max)
 1147                return -EINVAL;
 1148         old_rlim = current->rlim + resource;
 1149         if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
 1150              (new_rlim.rlim_max > old_rlim->rlim_max)) &&
 1151             !capable(CAP_SYS_RESOURCE))
 1152                 return -EPERM;
 1153         if (resource == RLIMIT_NOFILE) {
 1154                 if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
 1155                         return -EPERM;
 1156         }
 1157         *old_rlim = new_rlim;
 1158         return 0;
 1159 }
 1160 
 1161 /*
 1162  * It would make sense to put struct rusage in the task_struct,
 1163  * except that would make the task_struct be *really big*.  After
 1164  * task_struct gets moved into malloc'ed memory, it would
 1165  * make sense to do this.  It will make moving the rest of the information
 1166  * a lot simpler!  (Which we're not doing right now because we're not
 1167  * measuring them yet).
 1168  *
 1169  * This is SMP safe.  Either we are called from sys_getrusage on ourselves
 1170  * below (we know we aren't going to exit/disappear and only we change our
 1171  * rusage counters), or we are called from wait4() on a process which is
 1172  * either stopped or zombied.  In the zombied case the task won't get
 1173  * reaped till shortly after the call to getrusage(), in both cases the
 1174  * task being examined is in a frozen state so the counters won't change.
 1175  *
 1176  * FIXME! Get the fault counts properly!
 1177  */
 1178 int getrusage(struct task_struct *p, int who, struct rusage *ru)
 1179 {
 1180         struct rusage r;
 1181 
 1182         memset((char *) &r, 0, sizeof(r));
 1183         switch (who) {
 1184                 case RUSAGE_SELF:
 1185                         r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
 1186                         r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
 1187                         r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
 1188                         r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
 1189                         r.ru_minflt = p->min_flt;
 1190                         r.ru_majflt = p->maj_flt;
 1191                         r.ru_nswap = p->nswap;
 1192                         break;
 1193                 case RUSAGE_CHILDREN:
 1194                         r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
 1195                         r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
 1196                         r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
 1197                         r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
 1198                         r.ru_minflt = p->cmin_flt;
 1199                         r.ru_majflt = p->cmaj_flt;
 1200                         r.ru_nswap = p->cnswap;
 1201                         break;
 1202                 default:
 1203                         r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
 1204                         r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
 1205                         r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
 1206                         r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
 1207                         r.ru_minflt = p->min_flt + p->cmin_flt;
 1208                         r.ru_majflt = p->maj_flt + p->cmaj_flt;
 1209                         r.ru_nswap = p->nswap + p->cnswap;
 1210                         break;
 1211         }
 1212         return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 1213 }
 1214 
 1215 asmlinkage long sys_getrusage(int who, struct rusage *ru)
 1216 {
 1217         if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
 1218                 return -EINVAL;
 1219         return getrusage(current, who, ru);
 1220 }
 1221 
 1222 asmlinkage long sys_umask(int mask)
 1223 {
 1224         mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
 1225         return mask;
 1226 }
 1227     
 1228 asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
 1229                           unsigned long arg4, unsigned long arg5)
 1230 {
 1231         int error = 0;
 1232         int sig;
 1233 
 1234         switch (option) {
 1235                 case PR_SET_PDEATHSIG:
 1236                         sig = arg2;
 1237                         if (sig < 0 || sig > _NSIG) {
 1238                                 error = -EINVAL;
 1239                                 break;
 1240                         }
 1241                         current->pdeath_signal = sig;
 1242                         break;
 1243                 case PR_GET_PDEATHSIG:
 1244                         error = put_user(current->pdeath_signal, (int *)arg2);
 1245                         break;
 1246                 case PR_GET_DUMPABLE:
 1247                         if (is_dumpable(current))
 1248                                 error = 1;
 1249                         break;
 1250                 case PR_SET_DUMPABLE:
 1251                         if (arg2 != 0 && arg2 != 1) {
 1252                                 error = -EINVAL;
 1253                                 break;
 1254                         }
 1255                         current->mm->dumpable = arg2;
 1256                         break;
 1257 
 1258                 case PR_SET_UNALIGN:
 1259                         error = SET_UNALIGN_CTL(current, arg2);
 1260                         break;
 1261                 case PR_GET_UNALIGN:
 1262                         error = GET_UNALIGN_CTL(current, arg2);
 1263                         break;
 1264                 case PR_SET_FPEMU:
 1265                         error = SET_FPEMU_CTL(current, arg2);
 1266                         break;
 1267                 case PR_GET_FPEMU:
 1268                         error = GET_FPEMU_CTL(current, arg2);
 1269                         break;
 1270                 case PR_SET_FPEXC:
 1271                         error = SET_FPEXC_CTL(current, arg2);
 1272                         break;
 1273                 case PR_GET_FPEXC:
 1274                         error = GET_FPEXC_CTL(current, arg2);
 1275                         break;
 1276 
 1277                 case PR_GET_KEEPCAPS:
 1278                         if (current->keep_capabilities)
 1279                                 error = 1;
 1280                         break;
 1281                 case PR_SET_KEEPCAPS:
 1282                         if (arg2 != 0 && arg2 != 1) {
 1283                                 error = -EINVAL;
 1284                                 break;
 1285                         }
 1286                         current->keep_capabilities = arg2;
 1287                         break;
 1288                 default:
 1289                         error = -EINVAL;
 1290                         break;
 1291         }
 1292         return error;
 1293 }
 1294 
 1295 EXPORT_SYMBOL(notifier_chain_register);
 1296 EXPORT_SYMBOL(notifier_chain_unregister);
 1297 EXPORT_SYMBOL(notifier_call_chain);
 1298 EXPORT_SYMBOL(register_reboot_notifier);
 1299 EXPORT_SYMBOL(unregister_reboot_notifier);
 1300 EXPORT_SYMBOL(in_group_p);
 1301 EXPORT_SYMBOL(in_egroup_p);

Cache object: 2f6d585d17e56f9445bbfbba28cbab41


[ 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.