sys.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:30k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/kernel/sys.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6. #include <linux/module.h>
  7. #include <linux/mm.h>
  8. #include <linux/utsname.h>
  9. #include <linux/mman.h>
  10. #include <linux/smp_lock.h>
  11. #include <linux/notifier.h>
  12. #include <linux/reboot.h>
  13. #include <linux/prctl.h>
  14. #include <linux/init.h>
  15. #include <linux/highuid.h>
  16. #include <asm/uaccess.h>
  17. #include <asm/io.h>
  18. /*
  19.  * this is where the system-wide overflow UID and GID are defined, for
  20.  * architectures that now have 32-bit UID/GID but didn't in the past
  21.  */
  22. int overflowuid = DEFAULT_OVERFLOWUID;
  23. int overflowgid = DEFAULT_OVERFLOWGID;
  24. /*
  25.  * the same as above, but for filesystems which can only store a 16-bit
  26.  * UID and GID. as such, this is needed on all architectures
  27.  */
  28. int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
  29. int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;
  30. /*
  31.  * this indicates whether you can reboot with ctrl-alt-del: the default is yes
  32.  */
  33. int C_A_D = 1;
  34. int cad_pid = 1;
  35. /*
  36.  * Notifier list for kernel code which wants to be called
  37.  * at shutdown. This is used to stop any idling DMA operations
  38.  * and the like. 
  39.  */
  40. static struct notifier_block *reboot_notifier_list;
  41. rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
  42. /**
  43.  * notifier_chain_register - Add notifier to a notifier chain
  44.  * @list: Pointer to root list pointer
  45.  * @n: New entry in notifier chain
  46.  *
  47.  * Adds a notifier to a notifier chain.
  48.  *
  49.  * Currently always returns zero.
  50.  */
  51.  
  52. int notifier_chain_register(struct notifier_block **list, struct notifier_block *n)
  53. {
  54. write_lock(&notifier_lock);
  55. while(*list)
  56. {
  57. if(n->priority > (*list)->priority)
  58. break;
  59. list= &((*list)->next);
  60. }
  61. n->next = *list;
  62. *list=n;
  63. write_unlock(&notifier_lock);
  64. return 0;
  65. }
  66. /**
  67.  * notifier_chain_unregister - Remove notifier from a notifier chain
  68.  * @nl: Pointer to root list pointer
  69.  * @n: New entry in notifier chain
  70.  *
  71.  * Removes a notifier from a notifier chain.
  72.  *
  73.  * Returns zero on success, or %-ENOENT on failure.
  74.  */
  75.  
  76. int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n)
  77. {
  78. write_lock(&notifier_lock);
  79. while((*nl)!=NULL)
  80. {
  81. if((*nl)==n)
  82. {
  83. *nl=n->next;
  84. write_unlock(&notifier_lock);
  85. return 0;
  86. }
  87. nl=&((*nl)->next);
  88. }
  89. write_unlock(&notifier_lock);
  90. return -ENOENT;
  91. }
  92. /**
  93.  * notifier_call_chain - Call functions in a notifier chain
  94.  * @n: Pointer to root pointer of notifier chain
  95.  * @val: Value passed unmodified to notifier function
  96.  * @v: Pointer passed unmodified to notifier function
  97.  *
  98.  * Calls each function in a notifier chain in turn.
  99.  *
  100.  * If the return value of the notifier can be and'd
  101.  * with %NOTIFY_STOP_MASK, then notifier_call_chain
  102.  * will return immediately, with the return value of
  103.  * the notifier function which halted execution.
  104.  * Otherwise, the return value is the return value
  105.  * of the last notifier function called.
  106.  */
  107.  
  108. int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
  109. {
  110. int ret=NOTIFY_DONE;
  111. struct notifier_block *nb = *n;
  112. while(nb)
  113. {
  114. ret=nb->notifier_call(nb,val,v);
  115. if(ret&NOTIFY_STOP_MASK)
  116. {
  117. return ret;
  118. }
  119. nb=nb->next;
  120. }
  121. return ret;
  122. }
  123. /**
  124.  * register_reboot_notifier - Register function to be called at reboot time
  125.  * @nb: Info about notifier function to be called
  126.  *
  127.  * Registers a function with the list of functions
  128.  * to be called at reboot time.
  129.  *
  130.  * Currently always returns zero, as notifier_chain_register
  131.  * always returns zero.
  132.  */
  133.  
  134. int register_reboot_notifier(struct notifier_block * nb)
  135. {
  136. return notifier_chain_register(&reboot_notifier_list, nb);
  137. }
  138. /**
  139.  * unregister_reboot_notifier - Unregister previously registered reboot notifier
  140.  * @nb: Hook to be unregistered
  141.  *
  142.  * Unregisters a previously registered reboot
  143.  * notifier function.
  144.  *
  145.  * Returns zero on success, or %-ENOENT on failure.
  146.  */
  147.  
  148. int unregister_reboot_notifier(struct notifier_block * nb)
  149. {
  150. return notifier_chain_unregister(&reboot_notifier_list, nb);
  151. }
  152. asmlinkage long sys_ni_syscall(void)
  153. {
  154. return -ENOSYS;
  155. }
  156. static int proc_sel(struct task_struct *p, int which, int who)
  157. {
  158. if(p->pid)
  159. {
  160. switch (which) {
  161. case PRIO_PROCESS:
  162. if (!who && p == current)
  163. return 1;
  164. return(p->pid == who);
  165. case PRIO_PGRP:
  166. if (!who)
  167. who = current->pgrp;
  168. return(p->pgrp == who);
  169. case PRIO_USER:
  170. if (!who)
  171. who = current->uid;
  172. return(p->uid == who);
  173. }
  174. }
  175. return 0;
  176. }
  177. asmlinkage long sys_setpriority(int which, int who, int niceval)
  178. {
  179. struct task_struct *p;
  180. int error;
  181. if (which > 2 || which < 0)
  182. return -EINVAL;
  183. /* normalize: avoid signed division (rounding problems) */
  184. error = -ESRCH;
  185. if (niceval < -20)
  186. niceval = -20;
  187. if (niceval > 19)
  188. niceval = 19;
  189. read_lock(&tasklist_lock);
  190. for_each_task(p) {
  191. if (!proc_sel(p, which, who))
  192. continue;
  193. if (p->uid != current->euid &&
  194. p->uid != current->uid && !capable(CAP_SYS_NICE)) {
  195. error = -EPERM;
  196. continue;
  197. }
  198. if (error == -ESRCH)
  199. error = 0;
  200. if (niceval < p->nice && !capable(CAP_SYS_NICE))
  201. error = -EACCES;
  202. else
  203. p->nice = niceval;
  204. }
  205. read_unlock(&tasklist_lock);
  206. return error;
  207. }
  208. /*
  209.  * Ugh. To avoid negative return values, "getpriority()" will
  210.  * not return the normal nice-value, but a negated value that
  211.  * has been offset by 20 (ie it returns 40..1 instead of -20..19)
  212.  * to stay compatible.
  213.  */
  214. asmlinkage long sys_getpriority(int which, int who)
  215. {
  216. struct task_struct *p;
  217. long retval = -ESRCH;
  218. if (which > 2 || which < 0)
  219. return -EINVAL;
  220. read_lock(&tasklist_lock);
  221. for_each_task (p) {
  222. long niceval;
  223. if (!proc_sel(p, which, who))
  224. continue;
  225. niceval = 20 - p->nice;
  226. if (niceval > retval)
  227. retval = niceval;
  228. }
  229. read_unlock(&tasklist_lock);
  230. return retval;
  231. }
  232. /*
  233.  * Reboot system call: for obvious reasons only root may call it,
  234.  * and even root needs to set up some magic numbers in the registers
  235.  * so that some mistake won't make this reboot the whole machine.
  236.  * You can also set the meaning of the ctrl-alt-del-key here.
  237.  *
  238.  * reboot doesn't sync: do that yourself before calling this.
  239.  */
  240. asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg)
  241. {
  242. char buffer[256];
  243. /* We only trust the superuser with rebooting the system. */
  244. if (!capable(CAP_SYS_BOOT))
  245. return -EPERM;
  246. /* For safety, we require "magic" arguments. */
  247. if (magic1 != LINUX_REBOOT_MAGIC1 ||
  248.     (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A &&
  249. magic2 != LINUX_REBOOT_MAGIC2B))
  250. return -EINVAL;
  251. lock_kernel();
  252. switch (cmd) {
  253. case LINUX_REBOOT_CMD_RESTART:
  254. notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
  255. printk(KERN_EMERG "Restarting system.n");
  256. machine_restart(NULL);
  257. break;
  258. case LINUX_REBOOT_CMD_CAD_ON:
  259. C_A_D = 1;
  260. break;
  261. case LINUX_REBOOT_CMD_CAD_OFF:
  262. C_A_D = 0;
  263. break;
  264. case LINUX_REBOOT_CMD_HALT:
  265. notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
  266. printk(KERN_EMERG "System halted.n");
  267. machine_halt();
  268. do_exit(0);
  269. break;
  270. case LINUX_REBOOT_CMD_POWER_OFF:
  271. notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
  272. printk(KERN_EMERG "Power down.n");
  273. machine_power_off();
  274. do_exit(0);
  275. break;
  276. case LINUX_REBOOT_CMD_RESTART2:
  277. if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
  278. unlock_kernel();
  279. return -EFAULT;
  280. }
  281. buffer[sizeof(buffer) - 1] = '';
  282. notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
  283. printk(KERN_EMERG "Restarting system with command '%s'.n", buffer);
  284. machine_restart(buffer);
  285. break;
  286. default:
  287. unlock_kernel();
  288. return -EINVAL;
  289. }
  290. unlock_kernel();
  291. return 0;
  292. }
  293. static void deferred_cad(void *dummy)
  294. {
  295. notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
  296. machine_restart(NULL);
  297. }
  298. /*
  299.  * This function gets called by ctrl-alt-del - ie the keyboard interrupt.
  300.  * As it's called within an interrupt, it may NOT sync: the only choice
  301.  * is whether to reboot at once, or just ignore the ctrl-alt-del.
  302.  */
  303. void ctrl_alt_del(void)
  304. {
  305. static struct tq_struct cad_tq = {
  306. routine: deferred_cad,
  307. };
  308. if (C_A_D)
  309. schedule_task(&cad_tq);
  310. else
  311. kill_proc(cad_pid, SIGINT, 1);
  312. }
  313. /*
  314.  * Unprivileged users may change the real gid to the effective gid
  315.  * or vice versa.  (BSD-style)
  316.  *
  317.  * If you set the real gid at all, or set the effective gid to a value not
  318.  * equal to the real gid, then the saved gid is set to the new effective gid.
  319.  *
  320.  * This makes it possible for a setgid program to completely drop its
  321.  * privileges, which is often a useful assertion to make when you are doing
  322.  * a security audit over a program.
  323.  *
  324.  * The general idea is that a program which uses just setregid() will be
  325.  * 100% compatible with BSD.  A program which uses just setgid() will be
  326.  * 100% compatible with POSIX with saved IDs. 
  327.  *
  328.  * SMP: There are not races, the GIDs are checked only by filesystem
  329.  *      operations (as far as semantic preservation is concerned).
  330.  */
  331. asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
  332. {
  333. int old_rgid = current->gid;
  334. int old_egid = current->egid;
  335. int new_rgid = old_rgid;
  336. int new_egid = old_egid;
  337. if (rgid != (gid_t) -1) {
  338. if ((old_rgid == rgid) ||
  339.     (current->egid==rgid) ||
  340.     capable(CAP_SETGID))
  341. new_rgid = rgid;
  342. else
  343. return -EPERM;
  344. }
  345. if (egid != (gid_t) -1) {
  346. if ((old_rgid == egid) ||
  347.     (current->egid == egid) ||
  348.     (current->sgid == egid) ||
  349.     capable(CAP_SETGID))
  350. new_egid = egid;
  351. else {
  352. return -EPERM;
  353. }
  354. }
  355. if (new_egid != old_egid)
  356. {
  357. current->mm->dumpable = 0;
  358. wmb();
  359. }
  360. if (rgid != (gid_t) -1 ||
  361.     (egid != (gid_t) -1 && egid != old_rgid))
  362. current->sgid = new_egid;
  363. current->fsgid = new_egid;
  364. current->egid = new_egid;
  365. current->gid = new_rgid;
  366. return 0;
  367. }
  368. /*
  369.  * setgid() is implemented like SysV w/ SAVED_IDS 
  370.  *
  371.  * SMP: Same implicit races as above.
  372.  */
  373. asmlinkage long sys_setgid(gid_t gid)
  374. {
  375. int old_egid = current->egid;
  376. if (capable(CAP_SETGID))
  377. {
  378. if(old_egid != gid)
  379. {
  380. current->mm->dumpable=0;
  381. wmb();
  382. }
  383. current->gid = current->egid = current->sgid = current->fsgid = gid;
  384. }
  385. else if ((gid == current->gid) || (gid == current->sgid))
  386. {
  387. if(old_egid != gid)
  388. {
  389. current->mm->dumpable=0;
  390. wmb();
  391. }
  392. current->egid = current->fsgid = gid;
  393. }
  394. else
  395. return -EPERM;
  396. return 0;
  397. }
  398.   
  399. /* 
  400.  * cap_emulate_setxuid() fixes the effective / permitted capabilities of
  401.  * a process after a call to setuid, setreuid, or setresuid.
  402.  *
  403.  *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
  404.  *  {r,e,s}uid != 0, the permitted and effective capabilities are
  405.  *  cleared.
  406.  *
  407.  *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
  408.  *  capabilities of the process are cleared.
  409.  *
  410.  *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
  411.  *  capabilities are set to the permitted capabilities.
  412.  *
  413.  *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
  414.  *  never happen.
  415.  *
  416.  *  -astor 
  417.  *
  418.  * cevans - New behaviour, Oct '99
  419.  * A process may, via prctl(), elect to keep its capabilities when it
  420.  * calls setuid() and switches away from uid==0. Both permitted and
  421.  * effective sets will be retained.
  422.  * Without this change, it was impossible for a daemon to drop only some
  423.  * of its privilege. The call to setuid(!=0) would drop all privileges!
  424.  * Keeping uid 0 is not an option because uid 0 owns too many vital
  425.  * files..
  426.  * Thanks to Olaf Kirch and Peter Benie for spotting this.
  427.  */
  428. static inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
  429.        int old_suid)
  430. {
  431. if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
  432.     (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
  433.     !current->keep_capabilities) {
  434. cap_clear(current->cap_permitted);
  435. cap_clear(current->cap_effective);
  436. }
  437. if (old_euid == 0 && current->euid != 0) {
  438. cap_clear(current->cap_effective);
  439. }
  440. if (old_euid != 0 && current->euid == 0) {
  441. current->cap_effective = current->cap_permitted;
  442. }
  443. }
  444. static int set_user(uid_t new_ruid, int dumpclear)
  445. {
  446. struct user_struct *new_user, *old_user;
  447. /* What if a process setreuid()'s and this brings the
  448.  * new uid over his NPROC rlimit?  We can check this now
  449.  * cheaply with the new uid cache, so if it matters
  450.  * we should be checking for it.  -DaveM
  451.  */
  452. new_user = alloc_uid(new_ruid);
  453. if (!new_user)
  454. return -EAGAIN;
  455. old_user = current->user;
  456. atomic_dec(&old_user->processes);
  457. atomic_inc(&new_user->processes);
  458. if(dumpclear)
  459. {
  460. current->mm->dumpable = 0;
  461. wmb();
  462. }
  463. current->uid = new_ruid;
  464. current->user = new_user;
  465. free_uid(old_user);
  466. return 0;
  467. }
  468. /*
  469.  * Unprivileged users may change the real uid to the effective uid
  470.  * or vice versa.  (BSD-style)
  471.  *
  472.  * If you set the real uid at all, or set the effective uid to a value not
  473.  * equal to the real uid, then the saved uid is set to the new effective uid.
  474.  *
  475.  * This makes it possible for a setuid program to completely drop its
  476.  * privileges, which is often a useful assertion to make when you are doing
  477.  * a security audit over a program.
  478.  *
  479.  * The general idea is that a program which uses just setreuid() will be
  480.  * 100% compatible with BSD.  A program which uses just setuid() will be
  481.  * 100% compatible with POSIX with saved IDs. 
  482.  */
  483. asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
  484. {
  485. int old_ruid, old_euid, old_suid, new_ruid, new_euid;
  486. new_ruid = old_ruid = current->uid;
  487. new_euid = old_euid = current->euid;
  488. old_suid = current->suid;
  489. if (ruid != (uid_t) -1) {
  490. new_ruid = ruid;
  491. if ((old_ruid != ruid) &&
  492.     (current->euid != ruid) &&
  493.     !capable(CAP_SETUID))
  494. return -EPERM;
  495. }
  496. if (euid != (uid_t) -1) {
  497. new_euid = euid;
  498. if ((old_ruid != euid) &&
  499.     (current->euid != euid) &&
  500.     (current->suid != euid) &&
  501.     !capable(CAP_SETUID))
  502. return -EPERM;
  503. }
  504. if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
  505. return -EAGAIN;
  506. if (new_euid != old_euid)
  507. {
  508. current->mm->dumpable=0;
  509. wmb();
  510. }
  511. current->fsuid = current->euid = new_euid;
  512. if (ruid != (uid_t) -1 ||
  513.     (euid != (uid_t) -1 && euid != old_ruid))
  514. current->suid = current->euid;
  515. current->fsuid = current->euid;
  516. if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  517. cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  518. }
  519. return 0;
  520. }
  521. /*
  522.  * setuid() is implemented like SysV with SAVED_IDS 
  523.  * 
  524.  * Note that SAVED_ID's is deficient in that a setuid root program
  525.  * like sendmail, for example, cannot set its uid to be a normal 
  526.  * user and then switch back, because if you're root, setuid() sets
  527.  * the saved uid too.  If you don't like this, blame the bright people
  528.  * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
  529.  * will allow a root program to temporarily drop privileges and be able to
  530.  * regain them by swapping the real and effective uid.  
  531.  */
  532. asmlinkage long sys_setuid(uid_t uid)
  533. {
  534. int old_euid = current->euid;
  535. int old_ruid, old_suid, new_ruid, new_suid;
  536. old_ruid = new_ruid = current->uid;
  537. old_suid = current->suid;
  538. new_suid = old_suid;
  539. if (capable(CAP_SETUID)) {
  540. if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
  541. return -EAGAIN;
  542. new_suid = uid;
  543. } else if ((uid != current->uid) && (uid != new_suid))
  544. return -EPERM;
  545. if (old_euid != uid)
  546. {
  547. current->mm->dumpable = 0;
  548. wmb();
  549. }
  550. current->fsuid = current->euid = uid;
  551. current->suid = new_suid;
  552. if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  553. cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  554. }
  555. return 0;
  556. }
  557. /*
  558.  * This function implements a generic ability to update ruid, euid,
  559.  * and suid.  This allows you to implement the 4.4 compatible seteuid().
  560.  */
  561. asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
  562. {
  563. int old_ruid = current->uid;
  564. int old_euid = current->euid;
  565. int old_suid = current->suid;
  566. if (!capable(CAP_SETUID)) {
  567. if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
  568.     (ruid != current->euid) && (ruid != current->suid))
  569. return -EPERM;
  570. if ((euid != (uid_t) -1) && (euid != current->uid) &&
  571.     (euid != current->euid) && (euid != current->suid))
  572. return -EPERM;
  573. if ((suid != (uid_t) -1) && (suid != current->uid) &&
  574.     (suid != current->euid) && (suid != current->suid))
  575. return -EPERM;
  576. }
  577. if (ruid != (uid_t) -1) {
  578. if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
  579. return -EAGAIN;
  580. }
  581. if (euid != (uid_t) -1) {
  582. if (euid != current->euid)
  583. {
  584. current->mm->dumpable = 0;
  585. wmb();
  586. }
  587. current->euid = euid;
  588. current->fsuid = euid;
  589. }
  590. if (suid != (uid_t) -1)
  591. current->suid = suid;
  592. if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  593. cap_emulate_setxuid(old_ruid, old_euid, old_suid);
  594. }
  595. return 0;
  596. }
  597. asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
  598. {
  599. int retval;
  600. if (!(retval = put_user(current->uid, ruid)) &&
  601.     !(retval = put_user(current->euid, euid)))
  602. retval = put_user(current->suid, suid);
  603. return retval;
  604. }
  605. /*
  606.  * Same as above, but for rgid, egid, sgid.
  607.  */
  608. asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
  609. {
  610. if (!capable(CAP_SETGID)) {
  611. if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
  612.     (rgid != current->egid) && (rgid != current->sgid))
  613. return -EPERM;
  614. if ((egid != (gid_t) -1) && (egid != current->gid) &&
  615.     (egid != current->egid) && (egid != current->sgid))
  616. return -EPERM;
  617. if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
  618.     (sgid != current->egid) && (sgid != current->sgid))
  619. return -EPERM;
  620. }
  621. if (egid != (gid_t) -1) {
  622. if (egid != current->egid)
  623. {
  624. current->mm->dumpable = 0;
  625. wmb();
  626. }
  627. current->egid = egid;
  628. current->fsgid = egid;
  629. }
  630. if (rgid != (gid_t) -1)
  631. current->gid = rgid;
  632. if (sgid != (gid_t) -1)
  633. current->sgid = sgid;
  634. return 0;
  635. }
  636. asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
  637. {
  638. int retval;
  639. if (!(retval = put_user(current->gid, rgid)) &&
  640.     !(retval = put_user(current->egid, egid)))
  641. retval = put_user(current->sgid, sgid);
  642. return retval;
  643. }
  644. /*
  645.  * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
  646.  * is used for "access()" and for the NFS daemon (letting nfsd stay at
  647.  * whatever uid it wants to). It normally shadows "euid", except when
  648.  * explicitly set by setfsuid() or for access..
  649.  */
  650. asmlinkage long sys_setfsuid(uid_t uid)
  651. {
  652. int old_fsuid;
  653. old_fsuid = current->fsuid;
  654. if (uid == current->uid || uid == current->euid ||
  655.     uid == current->suid || uid == current->fsuid || 
  656.     capable(CAP_SETUID))
  657. {
  658. if (uid != old_fsuid)
  659. {
  660. current->mm->dumpable = 0;
  661. wmb();
  662. }
  663. current->fsuid = uid;
  664. }
  665. /* We emulate fsuid by essentially doing a scaled-down version
  666.  * of what we did in setresuid and friends. However, we only
  667.  * operate on the fs-specific bits of the process' effective
  668.  * capabilities 
  669.  *
  670.  * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
  671.  *          if not, we might be a bit too harsh here.
  672.  */
  673. if (!issecure(SECURE_NO_SETUID_FIXUP)) {
  674. if (old_fsuid == 0 && current->fsuid != 0) {
  675. cap_t(current->cap_effective) &= ~CAP_FS_MASK;
  676. }
  677. if (old_fsuid != 0 && current->fsuid == 0) {
  678. cap_t(current->cap_effective) |=
  679. (cap_t(current->cap_permitted) & CAP_FS_MASK);
  680. }
  681. }
  682. return old_fsuid;
  683. }
  684. /*
  685.  * Samma p