netlib.narod.ru< Назад | Оглавление | Далее >

kernel/sys.c

29140 /*
29141  *  linux/kernel/sys.c
29142  *
29143  *  Copyright (C) 1991, 1992  Linus Torvalds
29144  */
29145 
29146 #include <linux/mm.h>
29147 #include <linux/utsname.h>
29148 #include <linux/mman.h>
29149 #include <linux/smp_lock.h>
29150 #include <linux/notifier.h>
29151 #include <linux/reboot.h>
29152 #include <linux/prctl.h>
29153 
29154 #include <asm/uaccess.h>
29155 #include <asm/io.h>
29156 
29157 /* this indicates whether you can reboot with
29158  * ctrl-alt-del: the default is yes */
29159 
29160 int C_A_D = 1;
29161 
29162 
29163 /* Notifier list for kernel code which wants to be called
29164  * at shutdown. This is used to stop any idling DMA
29165  * operations and the like.  */
29166 
29167 struct notifier_block *reboot_notifier_list = NULL;
29168 
29169 int register_reboot_notifier(struct notifier_block * nb)
29170 {
29171   return notifier_chain_register(&reboot_notifier_list,
29172                                  nb);
29173 }
29174 
29175 int unregister_reboot_notifier(struct notifier_block *nb)
29176 {
29177   return notifier_chain_unregister(&reboot_notifier_list,
29178                                    nb);
29179 }
29180 
29181 
29182 
29183 extern void adjust_clock(void);
29184 
 Комментарий
29185 asmlinkage int sys_ni_syscall(void)
29186 {
29187   return -ENOSYS;
29188 }
29189 
29190 static int proc_sel(struct task_struct *p, int which,
29191                     int who)
29192 {
29193   if(p->pid)
29194   {
29195     switch (which) {
29196       case PRIO_PROCESS:
29197         if (!who && p == current)
29198           return 1;
29199         return(p->pid == who);
29200       case PRIO_PGRP:
29201         if (!who)
29202           who = current->pgrp;
29203         return(p->pgrp == who);
29204       case PRIO_USER:
29205         if (!who)
29206           who = current->uid;
29207         return(p->uid == who);
29208     }
29209   }
29210   return 0;
29211 }
29212 
 Комментарий
29213 asmlinkage int sys_setpriority(int which, int who,
29214                                int niceval)
29215 {
29216   struct task_struct *p;
29217   unsigned int priority;
29218   int error;
29219 
29220   if (which > 2 || which < 0)
29221     return -EINVAL;
29222 
29223   /* normalize: avoid signed division
29224    * (rounding problems) */
29225   error = ESRCH;
29226   priority = niceval;
29227   if (niceval < 0)
29228     priority = -niceval;
29229   if (priority > 20)
29230     priority = 20;
29231   priority = (priority * DEF_PRIORITY + 10) / 20 +
29232              DEF_PRIORITY;
29233 
29234   if (niceval >= 0) {
29235     priority = 2*DEF_PRIORITY - priority;
29236     if (!priority)
29237       priority = 1;
29238   }
29239 
29240   read_lock(&tasklist_lock);
 Комментарий
29241   for_each_task(p) {
29242     if (!proc_sel(p, which, who))
29243       continue;
29244     if (p->uid != current->euid &&
29245       p->uid != current->uid && !capable(CAP_SYS_NICE)) {
29246       error = EPERM;
29247       continue;
29248     }
29249     if (error == ESRCH)
29250       error = 0;
29251     if (priority > p->priority && !capable(CAP_SYS_NICE))
29252       error = EACCES;
29253     else
29254       p->priority = priority;
29255   }
29256   read_unlock(&tasklist_lock);
29257 
29258   return -error;
29259 }
29260 
29261 /* Ugh. To avoid negative return values, "getpriority()"
29262  * will not return the normal nice-value, but a value
29263  * that has been offset by 20 (ie it returns 0..40
29264  * instead of -20..20) */
29265 asmlinkage int sys_getpriority(int which, int who)
29266 {
29267   struct task_struct *p;
29268   long max_prio = -ESRCH;
29269 
29270   if (which > 2 || which < 0)
29271     return -EINVAL;
29272 
29273   read_lock(&tasklist_lock);
29274   for_each_task (p) {
29275     if (!proc_sel(p, which, who))
29276       continue;
29277     if (p->priority > max_prio)
29278       max_prio = p->priority;
29279   }
29280   read_unlock(&tasklist_lock);
29281 
29282   /* scale the priority from timeslice to 0..40 */
29283   if (max_prio > 0)
29284     max_prio = (max_prio * 20 + DEF_PRIORITY/2) /
29285                DEF_PRIORITY;
29286   return max_prio;
29287 }
29288 
29289 
29290 /* Reboot system call: for obvious reasons only root may
29291  * call it, and even root needs to set up some magic
29292  * numbers in the registers so that some mistake won't
29293  * make this reboot the whole machine.  You can also set
29294  * the meaning of the ctrl-alt-del-key here.
29295  *
29296  * reboot doesn't sync: do that yourself before calling
29297  * this.  */
 Комментарий
29298 asmlinkage int sys_reboot(int magic1, int magic2,
29299                           int cmd, void * arg)
29300 {
29301   char buffer[256];
29302 
29303   /* We only trust the superuser with rebooting the
29304    * system. */
29305   if (!capable(CAP_SYS_BOOT))
29306     return -EPERM;
29307 
29308   /* For safety, we require "magic" arguments. */
29309   if (magic1 != LINUX_REBOOT_MAGIC1 ||
29310       (magic2 != LINUX_REBOOT_MAGIC2 &&
29311        magic2 != LINUX_REBOOT_MAGIC2A &&
29312        magic2 != LINUX_REBOOT_MAGIC2B))
29313     return -EINVAL;
29314 
 Комментарий
29315   lock_kernel();
29316   switch (cmd) {
29317   case LINUX_REBOOT_CMD_RESTART:
29318     notifier_call_chain(&reboot_notifier_list,
29319                         SYS_RESTART, NULL);
29320     printk(KERN_EMERG "Restarting system.\n");
29321     machine_restart(NULL);
29322     break;
29323 
29324   case LINUX_REBOOT_CMD_CAD_ON:
29325     C_A_D = 1;
29326     break;
29327 
29328   case LINUX_REBOOT_CMD_CAD_OFF:
29329     C_A_D = 0;
29330     break;
29331 
29332   case LINUX_REBOOT_CMD_HALT:
29333     notifier_call_chain(&reboot_notifier_list,
29334                         SYS_HALT, NULL);
29335     printk(KERN_EMERG "System halted.\n");
29336     machine_halt();
29337     do_exit(0);
29338     break;
29339 
29340   case LINUX_REBOOT_CMD_POWER_OFF:
29341     notifier_call_chain(&reboot_notifier_list,
29342                         SYS_POWER_OFF, NULL);
29343     printk(KERN_EMERG "Power down.\n");
29344     machine_power_off();
29345     do_exit(0);
29346     break;
29347 
29348   case LINUX_REBOOT_CMD_RESTART2:
29349     if (strncpy_from_user(&buffer[0], (char *)arg,
29350                           sizeof(buffer) - 1) < 0) {
29351       unlock_kernel();
29352       return -EFAULT;
29353     }
29354     buffer[sizeof(buffer) - 1] = '\0';
29355 
29356     notifier_call_chain(&reboot_notifier_list,
29357                         SYS_RESTART, buffer);
29358     printk(KERN_EMERG
29359            "Restarting system with command '%s'.\n",
29360            buffer);
29361     machine_restart(buffer);
29362     break;
29363 
29364   default:
29365     unlock_kernel();
29366     return -EINVAL;
29367     break;
29368   };
29369   unlock_kernel();
29370   return 0;
29371 }
29372 
29373 /* This function gets called by ctrl-alt-del - ie the
29374  * keyboard interrupt.  As it's called within an
29375  * interrupt, it may NOT sync: the only choice is whether
29376  * to reboot at once, or just ignore the ctrl-alt-del.
29377  */
29378 void ctrl_alt_del(void)
29379 {
29380   if (C_A_D) {
29381     notifier_call_chain(&reboot_notifier_list,
29382                         SYS_RESTART, NULL);
29383     machine_restart(NULL);
29384   } else
29385     kill_proc(1, SIGINT, 1);
29386 }
29387 
29388 
29389 /* Unprivileged users may change the real gid to the
29390  * effective gid or vice versa.  (BSD-style)
29391  *
29392  * If you set the real gid at all, or set the effective
29393  * gid to a value not equal to the real gid, then the
29394  * saved gid is set to the new effective gid.
29395  *
29396  * This makes it possible for a setgid program to
29397  * completely drop its privileges, which is often a
29398  * useful assertion to make when you are doing a security
29399  * audit over a program.
29400  *
29401  * The general idea is that a program which uses just
29402  * setregid() will be 100% compatible with BSD.  A
29403  * program which uses just setgid() will be 100%
29404  * compatible with POSIX with saved IDs.
29405  *
29406  * SMP: There are not races, the GIDs are checked only by
29407  * filesystem operations (as far as semantic preservation
29408  * is concerned).  */
29409 asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
29410 {
29411   int old_rgid = current->gid;
29412   int old_egid = current->egid;
29413 
29414   if (rgid != (gid_t) -1) {
29415     if ((old_rgid == rgid) ||
29416         (current->egid==rgid) ||
29417         capable(CAP_SETGID))
29418       current->gid = rgid;
29419     else
29420       return -EPERM;
29421   }
29422   if (egid != (gid_t) -1) {
29423     if ((old_rgid == egid) ||
29424         (current->egid == egid) ||
29425         (current->sgid == egid) ||
29426         capable(CAP_SETGID))
29427       current->fsgid = current->egid = egid;
29428     else {
29429       current->gid = old_rgid;
29430       return -EPERM;
29431     }
29432   }
29433   if (rgid != (gid_t) -1 ||
29434       (egid != (gid_t) -1 && egid != old_rgid))
29435     current->sgid = current->egid;
29436   current->fsgid = current->egid;
29437   if (current->egid != old_egid)
29438     current->dumpable = 0;
29439   return 0;
29440 }
29441 
29442 /* setgid() is implemented like SysV w/ SAVED_IDS
29443  *
29444  * SMP: Same implicit races as above.  */
29445 asmlinkage int sys_setgid(gid_t gid)
29446 {
29447   int old_egid = current->egid;
29448 
29449   if (capable(CAP_SETGID))
29450     current->gid = current->egid = current->sgid =
29451       current->fsgid = gid;
29452   else if ((gid == current->gid) ||
29453            (gid == current->sgid))
29454     current->egid = current->fsgid = gid;
29455   else
29456     return -EPERM;
29457 
29458   if (current->egid != old_egid)
29459     current->dumpable = 0;
29460   return 0;
29461 }
29462 
29463 /* cap_emulate_setxuid() fixes the effective / permitted
29464  * capabilities of a process after a call to setuid,
29465  * setreuid, or setresuid.
29466  *
29467  *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_
29468  *  all of {r,e,s}uid != 0, the permitted and effective
29469  *  capabilities are cleared.
29470  *
29471  *  2) When set*uiding _from_ euid == 0 _to_ euid != 0,
29472  *  the effective capabilities of the process are
29473  *  cleared.
29474  *
29475  *  3) When set*uiding _from_ euid != 0 _to_ euid == 0,
29476  *  the effective capabilities are set to the permitted
29477  *  capabilities.
29478  *
29479  *  fsuid is handled elsewhere. fsuid == 0 and
29480  *  {r,e,s}uid!= 0 should never happen.
29481  *
29482  *  -astor */
29483 extern inline void cap_emulate_setxuid(int old_ruid,
29484                                        int old_euid,
29485                                        int old_suid)
29486 {
29487   if ((old_ruid == 0 || old_euid == 0 || old_suid == 0)
29488       && (current->uid != 0 && current->euid != 0 &&
29489           current->suid != 0)) {
29490     cap_clear(current->cap_permitted);
29491     cap_clear(current->cap_effective);
29492   }
29493   if (old_euid == 0 && current->euid != 0) {
29494     cap_clear(current->cap_effective);
29495   }
29496   if (old_euid != 0 && current->euid == 0) {
29497     current->cap_effective = current->cap_permitted;
29498   }
29499 }
29500 
29501 /* Unprivileged users may change the real uid to the
29502  * effective uid or vice versa.  (BSD-style)
29503  *
29504  * If you set the real uid at all, or set the effective
29505  * uid to a value not equal to the real uid, then the
29506  * saved uid is set to the new effective uid.
29507  *
29508  * This makes it possible for a setuid program to
29509  * completely drop its privileges, which is often a
29510  * useful assertion to make when you are doing a security
29511  * audit over a program.
29512  *
29513  * The general idea is that a program which uses just
29514  * setreuid() will be 100% compatible with BSD.  A
29515  * program which uses just setuid() will be 100%
29516  * compatible with POSIX with saved IDs.  */
29517 asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
29518 {
29519   int old_ruid, old_euid, old_suid, new_ruid;
29520 
29521   new_ruid = old_ruid = current->uid;
29522   old_euid = current->euid;
29523   old_suid = current->suid;
29524   if (ruid != (uid_t) -1) {
29525     if ((old_ruid == ruid) ||
29526         (current->euid==ruid) ||
29527         capable(CAP_SETUID))
29528       new_ruid = ruid;
29529     else
29530       return -EPERM;
29531   }
29532   if (euid != (uid_t) -1) {
29533     if ((old_ruid == euid) ||
29534         (current->euid == euid) ||
29535         (current->suid == euid) ||
29536         capable(CAP_SETUID))
29537       current->fsuid = current->euid = euid;
29538     else
29539       return -EPERM;
29540   }
29541   if (ruid != (uid_t) -1 ||
29542       (euid != (uid_t) -1 && euid != old_ruid))
29543     current->suid = current->euid;
29544   current->fsuid = current->euid;
29545   if (current->euid != old_euid)
29546     current->dumpable = 0;
29547 
29548   if(new_ruid != old_ruid) {
29549     /* What if a process setreuid()'s and this brings the
29550      * new uid over his NPROC rlimit?  We can check this
29551      * now cheaply with the new uid cache, so if it
29552      * matters we should be checking for it.  -DaveM */
29553     free_uid(current);
29554     current->uid = new_ruid;
29555     alloc_uid(current);
29556   }
29557 
29558   if (!issecure(SECURE_NO_SETUID_FIXUP)) {
29559     cap_emulate_setxuid(old_ruid, old_euid, old_suid);
29560   }
29561 
29562   return 0;
29563 }
29564 
29565 
29566 
29567 /* setuid() is implemented like SysV with SAVED_IDS
29568  *
29569  * Note that SAVED_ID's is deficient in that a setuid
29570  * root program like sendmail, for example, cannot set
29571  * its uid to be a normal user and then switch back,
29572  * because if you're root, setuid() sets the saved uid
29573  * too.  If you don't like this, blame the bright people
29574  * in the POSIX committee and/or USG.  Note that the
29575  * BSD-style setreuid() will allow a root program to
29576  * temporarily drop privileges and be able to regain them
29577  * by swapping the real and effective uid.  */
29578 asmlinkage int sys_setuid(uid_t uid)
29579 {
29580   int old_euid = current->euid;
29581   int old_ruid, old_suid, new_ruid;
29582 
29583   old_ruid = new_ruid = current->uid;
29584   old_suid = current->suid;
29585   if (capable(CAP_SETUID))
29586     new_ruid = current->euid = current->suid =
29587       current->fsuid = uid;
29588   else if ((uid == current->uid) ||
29589            (uid == current->suid))
29590     current->fsuid = current->euid = uid;
29591   else
29592     return -EPERM;
29593 
29594   if (current->euid != old_euid)
29595     current->dumpable = 0;
29596 
29597   if (new_ruid != old_ruid) {
29598     /* See comment above about NPROC rlimit issues... */
29599     free_uid(current);
29600     current->uid = new_ruid;
29601     alloc_uid(current);
29602   }
29603 
29604   if (!issecure(SECURE_NO_SETUID_FIXUP)) {
29605     cap_emulate_setxuid(old_ruid, old_euid, old_suid);
29606   }
29607 
29608   return 0;
29609 }
29610 
29611 
29612 /* This function implements a generic ability to update
29613  * ruid, euid, and suid.  This allows you to implement
29614  * the 4.4 compatible seteuid().  */
29615 asmlinkage int sys_setresuid(uid_t ruid, uid_t euid,
29616                              uid_t suid)
29617 {
29618   int old_ruid = current->uid;
29619   int old_euid = current->euid;
29620   int old_suid = current->suid;
29621 
29622   if (!capable(CAP_SETUID)) {
29623     if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
29624         (ruid != current->euid) &&
29625         (ruid != current->suid))
29626       return -EPERM;
29627     if ((euid != (uid_t) -1) && (euid != current->uid) &&
29628         (euid != current->euid) &&
29629         (euid != current->suid))
29630       return -EPERM;
29631     if ((suid != (uid_t) -1) && (suid != current->uid) &&
29632         (suid != current->euid) &&
29633         (suid != current->suid))
29634       return -EPERM;
29635   }
29636   if (ruid != (uid_t) -1) {
29637     /* See above commentary about NPROC rlimit issues
29638      * here. */
29639     free_uid(current);
29640     current->uid = ruid;
29641     alloc_uid(current);
29642   }
29643   if (euid != (uid_t) -1) {
29644     if (euid != current->euid)
29645       current->dumpable = 0;
29646     current->euid = euid;
29647     current->fsuid = euid;
29648   }
29649   if (suid != (uid_t) -1)
29650     current->suid = suid;
29651 
29652   if (!issecure(SECURE_NO_SETUID_FIXUP)) {
29653     cap_emulate_setxuid(old_ruid, old_euid, old_suid);
29654   }
29655 
29656   return 0;
29657 }
29658 
29659 asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid,
29660                              uid_t *suid)
29661 {
29662   int retval;
29663 
29664   if (!(retval = put_user(current->uid, ruid)) &&
29665       !(retval = put_user(current->euid, euid)))
29666     retval = put_user(current->suid, suid);
29667 
29668   return retval;
29669 }
29670 
29671 /* Same as above, but for rgid, egid, sgid. */
29672 asmlinkage int sys_setresgid(gid_t rgid, gid_t egid,
29673                              gid_t sgid)
29674 {
29675   if (!capable(CAP_SETGID)) {
29676     if ((rgid != (gid_t) -1)    &&
29677         (rgid != current->gid)  &&
29678         (rgid != current->egid) &&
29679         (rgid != current->sgid))
29680       return -EPERM;
29681     if ((egid != (gid_t) -1)    &&
29682         (egid != current->gid)  &&
29683         (egid != current->egid) &&
29684         (egid != current->sgid))
29685       return -EPERM;
29686     if ((sgid != (gid_t) -1)    &&
29687         (sgid != current->gid)  &&
29688         (sgid != current->egid) &&
29689         (sgid != current->sgid))
29690       return -EPERM;
29691   }
29692   if (rgid != (gid_t) -1)
29693     current->gid = rgid;
29694   if (egid != (gid_t) -1) {
29695     if (egid != current->egid)
29696       current->dumpable = 0;
29697     current->egid = egid;
29698     current->fsgid = egid;
29699   }
29700   if (sgid != (gid_t) -1)
29701     current->sgid = sgid;
29702   return 0;
29703 }
29704 
29705 asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid,
29706                              gid_t *sgid)
29707 {
29708   int retval;
29709 
29710   if (!(retval = put_user(current->gid, rgid)) &&
29711       !(retval = put_user(current->egid, egid)))
29712     retval = put_user(current->sgid, sgid);
29713 
29714   return retval;
29715 }
29716 
29717 
29718 /* "setfsuid()" sets the fsuid - the uid used for
29719  * filesystem checks. This is used for "access()" and for
29720  * the NFS daemon (letting nfsd stay at whatever uid it
29721  * wants to). It normally shadows "euid", except when
29722  * explicitly set by setfsuid() or for access..  */
29723 asmlinkage int sys_setfsuid(uid_t uid)
29724 {
29725   int old_fsuid;
29726 
29727   old_fsuid = current->fsuid;
29728   if (uid == current->uid || uid == current->euid ||
29729       uid == current->suid || uid == current->fsuid ||
29730       capable(CAP_SETUID))
29731     current->fsuid = uid;
29732   if (current->fsuid != old_fsuid)
29733     current->dumpable = 0;
29734 
29735   /* We emulate fsuid by essentially doing a scaled-down
29736    * version of what we did in setresuid and
29737    * friends. However, we only operate on the fs-specific
29738    * bits of the process' effective capabilities
29739    *
29740    * FIXME - is fsuser used for all CAP_FS_MASK
29741    * capabilities?  if not, we might be a bit too harsh
29742    * here.  */
29743   if (!issecure(SECURE_NO_SETUID_FIXUP)) {
29744     if (old_fsuid == 0 && current->fsuid != 0) {
29745       cap_t(current->cap_effective) &= ~CAP_FS_MASK;
29746     }
29747     if (old_fsuid != 0 && current->fsuid == 0) {
29748       cap_t(current->cap_effective) |=
29749         (cap_t(current->cap_permitted) & CAP_FS_MASK);
29750     }
29751   }
29752 
29753   return old_fsuid;
29754 }
29755 
29756 /* Samma pе svenska. */
29757 asmlinkage int sys_setfsgid(gid_t gid)
29758 {
29759   int old_fsgid;
29760 
29761   old_fsgid = current->fsgid;
29762   if (gid == current->gid || gid == current->egid ||
29763       gid == current->sgid || gid == current->fsgid ||
29764       capable(CAP_SETGID))
29765     current->fsgid = gid;
29766   if (current->fsgid != old_fsgid)
29767     current->dumpable = 0;
29768 
29769   return old_fsgid;
29770 }
29771 
29772 asmlinkage long sys_times(struct tms * tbuf)
29773 {
29774   /* In the SMP world we might just be unlucky and have
29775    * one of the times increment as we use it. Since the
29776    * value is an atomically safe type this is just
29777    * fine. Conceptually it's as if the syscall took an
29778    * instant longer to occur.  */
29779   if (tbuf)
29780     if (copy_to_user(tbuf, &current->times,
29781                      sizeof(struct tms)))
29782       return -EFAULT;
29783   return jiffies;
29784 }
29785 
29786 /* This needs some heavy checking ...  I just haven't the
29787  * stomach for it. I also don't fully understand
29788  * sessions/pgrp etc. Let somebody who does explain it.
29789  *
29790  * OK, I think I have the protection semantics
29791  * right.... this is really only important on a
29792  * multi-user system anyway, to make sure one user can't
29793  * send a signal to a process owned by another.  -TYT,
29794  * 12/12/91
29795  *
29796  * Auch. Had to add the 'did_exec' flag to conform
29797  * completely to POSIX.  LBT 04.03.94 */
29798 asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
29799 {
29800   struct task_struct * p;
29801   int err = -EINVAL;
29802 
29803   if (!pid)
29804     pid = current->pid;
29805   if (!pgid)
29806     pgid = pid;
29807   if (pgid < 0)
29808     return -EINVAL;
29809 
29810   /* From this point forward we keep holding onto the
29811    * tasklist lock so that our parent does not change
29812    * from under us. -DaveM */
29813   read_lock(&tasklist_lock);
29814 
29815   err = -ESRCH;
29816   p = find_task_by_pid(pid);
29817   if (!p)
29818     goto out;
29819 
29820   if (p->p_pptr == current || p->p_opptr == current) {
29821     err = -EPERM;
29822     if (p->session != current->session)
29823       goto out;
29824     err = -EACCES;
29825     if (p->did_exec)
29826       goto out;
29827   } else if (p != current)
29828     goto out;
29829   err = -EPERM;
29830   if (p->leader)
29831     goto out;
29832   if (pgid != pid) {
29833     struct task_struct * tmp;
29834     for_each_task (tmp) {
29835       if (tmp->pgrp == pgid &&
29836           tmp->session == current->session)
29837         goto ok_pgid;
29838     }
29839     goto out;
29840   }
29841 
29842 ok_pgid:
29843   p->pgrp = pgid;
29844   err = 0;
29845 out:
29846   /* All paths lead to here, thus we are safe. -DaveM */
29847   read_unlock(&tasklist_lock);
29848   return err;
29849 }
29850 
29851 asmlinkage int sys_getpgid(pid_t pid)
29852 {
29853   if (!pid) {
29854     return current->pgrp;
29855   } else {
29856     int retval;
29857     struct task_struct *p;
29858 
29859     read_lock(&tasklist_lock);
29860     p = find_task_by_pid(pid);
29861 
29862     retval = -ESRCH;
29863     if (p)
29864       retval = p->pgrp;
29865     read_unlock(&tasklist_lock);
29866     return retval;
29867   }
29868 }
29869 
29870 asmlinkage int sys_getpgrp(void)
29871 {
29872   /* SMP: assuming writes are word atomic this is fine */
29873   return current->pgrp;
29874 }
29875 
29876 asmlinkage int sys_getsid(pid_t pid)
29877 {
29878   if (!pid) {
29879     return current->session;
29880   } else {
29881     int retval;
29882     struct task_struct *p;
29883 
29884     read_lock(&tasklist_lock);
29885     p = find_task_by_pid(pid);
29886 
29887     retval = -ESRCH;
29888     if(p)
29889       retval = p->session;
29890     read_unlock(&tasklist_lock);
29891     return retval;
29892   }
29893 }
29894 
29895 asmlinkage int sys_setsid(void)
29896 {
29897   struct task_struct * p;
29898   int err = -EPERM;
29899 
29900   read_lock(&tasklist_lock);
29901   for_each_task(p) {
29902     if (p->pgrp == current->pid)
29903       goto out;
29904   }
29905 
29906   current->leader = 1;
29907   current->session = current->pgrp = current->pid;
29908   current->tty = NULL;
29909   current->tty_old_pgrp = 0;
29910   err = current->pgrp;
29911 out:
29912   read_unlock(&tasklist_lock);
29913   return err;
29914 }
29915 
29916 /* Supplementary group IDs */
29917 asmlinkage int sys_getgroups(int gidsetsize,
29918                              gid_t *grouplist)
29919 {
29920   int i;
29921 
29922   /* SMP: Nobody else can change our grouplist. Thus we
29923    * are safe.  */
29924   if (gidsetsize < 0)
29925     return -EINVAL;
29926   i = current->ngroups;
29927   if (gidsetsize) {
29928     if (i > gidsetsize)
29929       return -EINVAL;
29930     if (copy_to_user(grouplist, current->groups,
29931                      sizeof(gid_t)*i))
29932       return -EFAULT;
29933   }
29934   return i;
29935 }
29936 
29937 /* SMP: Our groups are not shared. We can copy to/from
29938  * them safely without another task interfering.  */
29939 asmlinkage int sys_setgroups(int gidsetsize,
29940                              gid_t *grouplist)
29941 {
29942   if (!capable(CAP_SETGID))
29943     return -EPERM;
29944   if ((unsigned) gidsetsize > NGROUPS)
29945     return -EINVAL;
29946   if (copy_from_user(current->groups, grouplist,
29947                      gidsetsize * sizeof(gid_t)))
29948     return -EFAULT;
29949   current->ngroups = gidsetsize;
29950   return 0;
29951 }
29952 
29953 int in_group_p(gid_t grp)
29954 {
29955   if (grp != current->fsgid) {
29956     int i = current->ngroups;
29957     if (i) {
29958       gid_t *groups = current->groups;
29959       do {
29960         if (*groups == grp)
29961           goto out;
29962         groups++;
29963         i--;
29964       } while (i);
29965     }
29966     return 0;
29967   }
29968 out:
29969   return 1;
29970 }
29971 
29972 /* This should really be a blocking read-write lock
29973  * rather than a semaphore. Anybody want to implement
29974  * one?  */
29975 struct semaphore uts_sem = MUTEX;
29976 
29977 asmlinkage int sys_newuname(struct new_utsname * name)
29978 {
29979   int errno = 0;
29980 
29981   down(&uts_sem);
29982   if (copy_to_user(name,&system_utsname,sizeof *name))
29983     errno = -EFAULT;
29984   up(&uts_sem);
29985   return errno;
29986 }
29987 
29988 asmlinkage int sys_sethostname(char *name, int len)
29989 {
29990   int errno;
29991 
29992   if (!capable(CAP_SYS_ADMIN))
29993     return -EPERM;
29994   if (len < 0 || len > __NEW_UTS_LEN)
29995     return -EINVAL;
29996   down(&uts_sem);
29997   errno = -EFAULT;
29998   if (!copy_from_user(system_utsname.nodename, name,
29999                       len)) {
30000     system_utsname.nodename[len] = 0;
30001     errno = 0;
30002   }
30003   up(&uts_sem);
30004   return errno;
30005 }
30006 
30007 asmlinkage int sys_gethostname(char *name, int len)
30008 {
30009   int i, errno;
30010 
30011   if (len < 0)
30012     return -EINVAL;
30013   down(&uts_sem);
30014   i = 1 + strlen(system_utsname.nodename);
30015   if (i > len)
30016     i = len;
30017   errno = 0;
30018   if (copy_to_user(name, system_utsname.nodename, i))
30019     errno = -EFAULT;
30020   up(&uts_sem);
30021   return errno;
30022 }
30023 
30024 /* Only setdomainname; getdomainname can be implemented
30025  * by calling uname() */
30026 asmlinkage int sys_setdomainname(char *name, int len)
30027 {
30028   int errno;
30029 
30030   if (!capable(CAP_SYS_ADMIN))
30031     return -EPERM;
30032   if (len < 0 || len > __NEW_UTS_LEN)
30033     return -EINVAL;
30034 
30035   down(&uts_sem);
30036   errno = -EFAULT;
30037   if (!copy_from_user(system_utsname.domainname, name,
30038                       len)) {
30039     errno = 0;
30040     system_utsname.domainname[len] = 0;
30041   }
30042   up(&uts_sem);
30043   return errno;
30044 }
30045 
30046 asmlinkage int sys_getrlimit(unsigned int resource,
30047                              struct rlimit *rlim)
30048 {
30049   if (resource >= RLIM_NLIMITS)
30050     return -EINVAL;
30051   else
30052     return copy_to_user(rlim, current->rlim + resource,
30053                         sizeof(*rlim))
30054       ? -EFAULT : 0;
30055 }
30056 
30057 asmlinkage int sys_setrlimit(unsigned int resource,
30058                              struct rlimit *rlim)
30059 {
30060   struct rlimit new_rlim, *old_rlim;
30061 
30062   if (resource >= RLIM_NLIMITS)
30063     return -EINVAL;
30064   if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
30065     return -EFAULT;
30066   old_rlim = current->rlim + resource;
30067   if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
30068        (new_rlim.rlim_max > old_rlim->rlim_max)) &&
30069       !capable(CAP_SYS_RESOURCE))
30070     return -EPERM;
30071   if (resource == RLIMIT_NOFILE) {
30072     if (new_rlim.rlim_cur > NR_OPEN ||
30073         new_rlim.rlim_max > NR_OPEN)
30074       return -EPERM;
30075   }
30076   *old_rlim = new_rlim;
30077   return 0;
30078 }
30079 
30080 /* It would make sense to put struct rusage in the
30081  * task_struct, except that would make the task_struct be
30082  * *really big*.  After task_struct gets moved into
30083  * malloc'ed memory, it would make sense to do this.  It
30084  * will make moving the rest of the information a lot
30085  * simpler!  (Which we're not doing right now because
30086  * we're not measuring them yet).
30087  *
30088  * This is SMP safe.  Either we are called from
30089  * sys_getrusage on ourselves below (we know we aren't
30090  * going to exit/disappear and only we change our rusage
30091  * counters), or we are called from wait4() on a process
30092  * which is either stopped or zombied.  In the zombied
30093  * case the task won't get reaped till shortly after the
30094  * call to getrusage(), in both cases the task being
30095  * examined is in a frozen state so the counters won't
30096  * change.  */
30097 int getrusage(struct task_struct *p, int who,
30098               struct rusage *ru)
30099 {
30100   struct rusage r;
30101 
30102   memset((char *) &r, 0, sizeof(r));
30103   switch (who) {
30104     case RUSAGE_SELF:
30105       r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
30106       r.ru_utime.tv_usec=CT_TO_USECS(p->times.tms_utime);
30107       r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
30108       r.ru_stime.tv_usec=CT_TO_USECS(p->times.tms_stime);
30109       r.ru_minflt = p->min_flt;
30110       r.ru_majflt = p->maj_flt;
30111       r.ru_nswap = p->nswap;
30112       break;
30113     case RUSAGE_CHILDREN:
30114       r.ru_utime.tv_sec =
30115         CT_TO_SECS(p->times.tms_cutime);
30116       r.ru_utime.tv_usec =
30117         CT_TO_USECS(p->times.tms_cutime);
30118       r.ru_stime.tv_sec =
30119         CT_TO_SECS(p->times.tms_cstime);
30120       r.ru_stime.tv_usec =
30121         CT_TO_USECS(p->times.tms_cstime);
30122       r.ru_minflt = p->cmin_flt;
30123       r.ru_majflt = p->cmaj_flt;
30124       r.ru_nswap = p->cnswap;
30125       break;
30126     default:
30127       r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime
30128                                   + p->times.tms_cutime);
30129       r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime
30130                                   + p->times.tms_cutime);
30131       r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime
30132                                   + p->times.tms_cstime);
30133       r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime
30134                                   + p->times.tms_cstime);
30135       r.ru_minflt = p->min_flt + p->cmin_flt;
30136       r.ru_majflt = p->maj_flt + p->cmaj_flt;
30137       r.ru_nswap = p->nswap + p->cnswap;
30138       break;
30139   }
30140   return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
30141 }
30142 
30143 asmlinkage int sys_getrusage(int who, struct rusage *ru)
30144 {
30145   if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
30146     return -EINVAL;
30147   return getrusage(current, who, ru);
30148 }
30149 
30150 asmlinkage int sys_umask(int mask)
30151 {
30152   mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
30153   return mask;
30154 }
30155 
30156 asmlinkage int sys_prctl(int option, unsigned long arg2,
30157   unsigned long arg3, unsigned long arg4,
30158   unsigned long arg5)
30159 {
30160   int error = 0;
30161   int sig;
30162 
30163   switch (option) {
30164     case PR_SET_PDEATHSIG:
30165       sig = arg2;
30166       if (sig > _NSIG) {
30167         error = -EINVAL;
30168         break;
30169       }
30170       current->pdeath_signal = sig;
30171       break;
30172     default:
30173       error = -EINVAL;
30174       break;
30175   }
30176   return error;
30177 }
30178 

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz