linux-old/kernel/sys.c
<<
>>
Prefs
   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
  45int overflowuid = DEFAULT_OVERFLOWUID;
  46int 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
  53int fs_overflowuid = DEFAULT_FS_OVERFLOWUID;
  54int fs_overflowgid = DEFAULT_FS_OVERFLOWUID;
  55
  56/*
  57 * this indicates whether you can reboot with ctrl-alt-del: the default is yes
  58 */
  59
  60int C_A_D = 1;
  61int 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
  70static struct notifier_block *reboot_notifier_list;
  71rwlock_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 
  83int 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 
 108int 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 
 141int 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 
 169int 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 
 184int unregister_reboot_notifier(struct notifier_block * nb)
 185{
 186        return notifier_chain_unregister(&reboot_notifier_list, nb);
 187}
 188
 189asmlinkage long sys_ni_syscall(void)
 190{
 191        return -ENOSYS;
 192}
 193
 194static 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
 216asmlinkage 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 */
 258asmlinkage 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 */
 289asmlinkage 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
 353static 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 */
 364void 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 */
 395asmlinkage 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 */
 439asmlinkage 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 */
 495static 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
 512static int set_user(uid_t new_ruid, int dumpclear)
 513{
 514        struct user_struct *new_user;
 515
 516        new_user = alloc_uid(new_ruid);
 517        if (!new_user)
 518                return -EAGAIN;
 519        switch_uid(new_user);
 520
 521        if(dumpclear)
 522        {
 523                current->mm->dumpable = 0;
 524                wmb();
 525        }
 526        current->uid = new_ruid;
 527        return 0;
 528}
 529
 530/*
 531 * Unprivileged users may change the real uid to the effective uid
 532 * or vice versa.  (BSD-style)
 533 *
 534 * If you set the real uid at all, or set the effective uid to a value not
 535 * equal to the real uid, then the saved uid is set to the new effective uid.
 536 *
 537 * This makes it possible for a setuid program to completely drop its
 538 * privileges, which is often a useful assertion to make when you are doing
 539 * a security audit over a program.
 540 *
 541 * The general idea is that a program which uses just setreuid() will be
 542 * 100% compatible with BSD.  A program which uses just setuid() will be
 543 * 100% compatible with POSIX with saved IDs. 
 544 */
 545asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
 546{
 547        int old_ruid, old_euid, old_suid, new_ruid, new_euid;
 548
 549        new_ruid = old_ruid = current->uid;
 550        new_euid = old_euid = current->euid;
 551        old_suid = current->suid;
 552
 553        if (ruid != (uid_t) -1) {
 554                new_ruid = ruid;
 555                if ((old_ruid != ruid) &&
 556                    (current->euid != ruid) &&
 557                    !capable(CAP_SETUID))
 558                        return -EPERM;
 559        }
 560
 561        if (euid != (uid_t) -1) {
 562                new_euid = euid;
 563                if ((old_ruid != euid) &&
 564                    (current->euid != euid) &&
 565                    (current->suid != euid) &&
 566                    !capable(CAP_SETUID))
 567                        return -EPERM;
 568        }
 569
 570        if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
 571                return -EAGAIN;
 572
 573        if (new_euid != old_euid)
 574        {
 575                current->mm->dumpable=0;
 576                wmb();
 577        }
 578        current->fsuid = current->euid = new_euid;
 579        if (ruid != (uid_t) -1 ||
 580            (euid != (uid_t) -1 && euid != old_ruid))
 581                current->suid = current->euid;
 582        current->fsuid = current->euid;
 583
 584        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 585                cap_emulate_setxuid(old_ruid, old_euid, old_suid);
 586        }
 587
 588        return 0;
 589}
 590
 591
 592                
 593/*
 594 * setuid() is implemented like SysV with SAVED_IDS 
 595 * 
 596 * Note that SAVED_ID's is deficient in that a setuid root program
 597 * like sendmail, for example, cannot set its uid to be a normal 
 598 * user and then switch back, because if you're root, setuid() sets
 599 * the saved uid too.  If you don't like this, blame the bright people
 600 * in the POSIX committee and/or USG.  Note that the BSD-style setreuid()
 601 * will allow a root program to temporarily drop privileges and be able to
 602 * regain them by swapping the real and effective uid.  
 603 */
 604asmlinkage long sys_setuid(uid_t uid)
 605{
 606        int old_euid = current->euid;
 607        int old_ruid, old_suid, new_ruid, new_suid;
 608
 609        old_ruid = new_ruid = current->uid;
 610        old_suid = current->suid;
 611        new_suid = old_suid;
 612        
 613        if (capable(CAP_SETUID)) {
 614                if (uid != old_ruid && set_user(uid, old_euid != uid) < 0)
 615                        return -EAGAIN;
 616                new_suid = uid;
 617        } else if ((uid != current->uid) && (uid != new_suid))
 618                return -EPERM;
 619
 620        if (old_euid != uid)
 621        {
 622                current->mm->dumpable = 0;
 623                wmb();
 624        }
 625        current->fsuid = current->euid = uid;
 626        current->suid = new_suid;
 627
 628        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 629                cap_emulate_setxuid(old_ruid, old_euid, old_suid);
 630        }
 631
 632        return 0;
 633}
 634
 635
 636/*
 637 * This function implements a generic ability to update ruid, euid,
 638 * and suid.  This allows you to implement the 4.4 compatible seteuid().
 639 */
 640asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
 641{
 642        int old_ruid = current->uid;
 643        int old_euid = current->euid;
 644        int old_suid = current->suid;
 645
 646        if (!capable(CAP_SETUID)) {
 647                if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
 648                    (ruid != current->euid) && (ruid != current->suid))
 649                        return -EPERM;
 650                if ((euid != (uid_t) -1) && (euid != current->uid) &&
 651                    (euid != current->euid) && (euid != current->suid))
 652                        return -EPERM;
 653                if ((suid != (uid_t) -1) && (suid != current->uid) &&
 654                    (suid != current->euid) && (suid != current->suid))
 655                        return -EPERM;
 656        }
 657        if (ruid != (uid_t) -1) {
 658                if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0)
 659                        return -EAGAIN;
 660        }
 661        if (euid != (uid_t) -1) {
 662                if (euid != current->euid)
 663                {
 664                        current->mm->dumpable = 0;
 665                        wmb();
 666                }
 667                current->euid = euid;
 668        }
 669        current->fsuid = current->euid;
 670        if (suid != (uid_t) -1)
 671                current->suid = suid;
 672
 673        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 674                cap_emulate_setxuid(old_ruid, old_euid, old_suid);
 675        }
 676
 677        return 0;
 678}
 679
 680asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
 681{
 682        int retval;
 683
 684        if (!(retval = put_user(current->uid, ruid)) &&
 685            !(retval = put_user(current->euid, euid)))
 686                retval = put_user(current->suid, suid);
 687
 688        return retval;
 689}
 690
 691/*
 692 * Same as above, but for rgid, egid, sgid.
 693 */
 694asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 695{
 696        if (!capable(CAP_SETGID)) {
 697                if ((rgid != (gid_t) -1) && (rgid != current->gid) &&
 698                    (rgid != current->egid) && (rgid != current->sgid))
 699                        return -EPERM;
 700                if ((egid != (gid_t) -1) && (egid != current->gid) &&
 701                    (egid != current->egid) && (egid != current->sgid))
 702                        return -EPERM;
 703                if ((sgid != (gid_t) -1) && (sgid != current->gid) &&
 704                    (sgid != current->egid) && (sgid != current->sgid))
 705                        return -EPERM;
 706        }
 707        if (egid != (gid_t) -1) {
 708                if (egid != current->egid)
 709                {
 710                        current->mm->dumpable = 0;
 711                        wmb();
 712                }
 713                current->egid = egid;
 714        }
 715        current->fsgid = current->egid;
 716        if (rgid != (gid_t) -1)
 717                current->gid = rgid;
 718        if (sgid != (gid_t) -1)
 719                current->sgid = sgid;
 720        return 0;
 721}
 722
 723asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 724{
 725        int retval;
 726
 727        if (!(retval = put_user(current->gid, rgid)) &&
 728            !(retval = put_user(current->egid, egid)))
 729                retval = put_user(current->sgid, sgid);
 730
 731        return retval;
 732}
 733
 734
 735/*
 736 * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This
 737 * is used for "access()" and for the NFS daemon (letting nfsd stay at
 738 * whatever uid it wants to). It normally shadows "euid", except when
 739 * explicitly set by setfsuid() or for access..
 740 */
 741asmlinkage long sys_setfsuid(uid_t uid)
 742{
 743        int old_fsuid;
 744
 745        old_fsuid = current->fsuid;
 746        if (uid == current->uid || uid == current->euid ||
 747            uid == current->suid || uid == current->fsuid || 
 748            capable(CAP_SETUID))
 749        {
 750                if (uid != old_fsuid)
 751                {
 752                        current->mm->dumpable = 0;
 753                        wmb();
 754                }
 755                current->fsuid = uid;
 756        }
 757
 758        /* We emulate fsuid by essentially doing a scaled-down version
 759         * of what we did in setresuid and friends. However, we only
 760         * operate on the fs-specific bits of the process' effective
 761         * capabilities 
 762         *
 763         * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
 764         *          if not, we might be a bit too harsh here.
 765         */
 766        
 767        if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 768                if (old_fsuid == 0 && current->fsuid != 0) {
 769                        cap_t(current->cap_effective) &= ~CAP_FS_MASK;
 770                }
 771                if (old_fsuid != 0 && current->fsuid == 0) {
 772                        cap_t(current->cap_effective) |=
 773                                (cap_t(current->cap_permitted) & CAP_FS_MASK);
 774                }
 775        }
 776
 777        return old_fsuid;
 778}
 779
 780/*
 781 * Samma på svenska..
 782 */
 783asmlinkage long sys_setfsgid(gid_t gid)
 784{
 785        int old_fsgid;
 786
 787        old_fsgid = current->fsgid;
 788        if (gid == current->gid || gid == current->egid ||
 789            gid == current->sgid || gid == current->fsgid || 
 790            capable(CAP_SETGID))
 791        {
 792                if (gid != old_fsgid)
 793                {
 794                        current->mm->dumpable = 0;
 795                        wmb();
 796                }
 797                current->fsgid = gid;
 798        }
 799        return old_fsgid;
 800}
 801
 802asmlinkage long sys_times(struct tms * tbuf)
 803{
 804        /*
 805         *      In the SMP world we might just be unlucky and have one of
 806         *      the times increment as we use it. Since the value is an
 807         *      atomically safe type this is just fine. Conceptually its
 808         *      as if the syscall took an instant longer to occur.
 809         */
 810        if (tbuf)
 811                if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
 812                        return -EFAULT;
 813        return jiffies;
 814}
 815
 816/*
 817 * This needs some heavy checking ...
 818 * I just haven't the stomach for it. I also don't fully
 819 * understand sessions/pgrp etc. Let somebody who does explain it.
 820 *
 821 * OK, I think I have the protection semantics right.... this is really
 822 * only important on a multi-user system anyway, to make sure one user
 823 * can't send a signal to a process owned by another.  -TYT, 12/12/91
 824 *
 825 * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
 826 * LBT 04.03.94
 827 */
 828
 829asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
 830{
 831        struct task_struct * p;
 832        int err = -EINVAL;
 833
 834        if (!pid)
 835                pid = current->pid;
 836        if (!pgid)
 837                pgid = pid;
 838        if (pgid < 0)
 839                return -EINVAL;
 840
 841        /* From this point forward we keep holding onto the tasklist lock
 842         * so that our parent does not change from under us. -DaveM
 843         */
 844        read_lock(&tasklist_lock);
 845
 846        err = -ESRCH;
 847        p = find_task_by_pid(pid);
 848        if (!p)
 849                goto out;
 850
 851        if (p->p_pptr == current || p->p_opptr == current) {
 852                err = -EPERM;
 853                if (p->session != current->session)
 854                        goto out;
 855                err = -EACCES;
 856                if (p->did_exec)
 857                        goto out;
 858        } else if (p != current)
 859                goto out;
 860        err = -EPERM;
 861        if (p->leader)
 862                goto out;
 863        if (pgid != pid) {
 864                struct task_struct * tmp;
 865                for_each_task (tmp) {
 866                        if (tmp->pgrp == pgid &&
 867                            tmp->session == current->session)
 868                                goto ok_pgid;
 869                }
 870                goto out;
 871        }
 872
 873ok_pgid:
 874        p->pgrp = pgid;
 875        err = 0;
 876out:
 877        /* All paths lead to here, thus we are safe. -DaveM */
 878        read_unlock(&tasklist_lock);
 879        return err;
 880}
 881
 882asmlinkage long sys_getpgid(pid_t pid)
 883{
 884        if (!pid) {
 885                return current->pgrp;
 886        } else {
 887                int retval;
 888                struct task_struct *p;
 889
 890                read_lock(&tasklist_lock);
 891                p = find_task_by_pid(pid);
 892
 893                retval = -ESRCH;
 894                if (p)
 895                        retval = p->pgrp;
 896                read_unlock(&tasklist_lock);
 897                return retval;
 898        }
 899}
 900
 901asmlinkage long sys_getpgrp(void)
 902{
 903        /* SMP - assuming writes are word atomic this is fine */
 904        return current->pgrp;
 905}
 906
 907asmlinkage long sys_getsid(pid_t pid)
 908{
 909        if (!pid) {
 910                return current->session;
 911        } else {
 912                int retval;
 913                struct task_struct *p;
 914
 915                read_lock(&tasklist_lock);
 916                p = find_task_by_pid(pid);
 917
 918                retval = -ESRCH;
 919                if(p)
 920                        retval = p->session;
 921                read_unlock(&tasklist_lock);
 922                return retval;
 923        }
 924}
 925
 926asmlinkage long sys_setsid(void)
 927{
 928        struct task_struct * p;
 929        int err = -EPERM;
 930
 931        read_lock(&tasklist_lock);
 932        for_each_task(p) {
 933                if (p->pgrp == current->pid)
 934                        goto out;
 935        }
 936
 937        current->leader = 1;
 938        current->session = current->pgrp = current->pid;
 939        current->tty = NULL;
 940        current->tty_old_pgrp = 0;
 941        err = current->pgrp;
 942out:
 943        read_unlock(&tasklist_lock);
 944        return err;
 945}
 946
 947/*
 948 * Supplementary group IDs
 949 */
 950asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist)
 951{
 952        int i;
 953        
 954        /*
 955         *      SMP: Nobody else can change our grouplist. Thus we are
 956         *      safe.
 957         */
 958
 959        if (gidsetsize < 0)
 960                return -EINVAL;
 961        i = current->ngroups;
 962        if (gidsetsize) {
 963                if (i > gidsetsize)
 964                        return -EINVAL;
 965                if (copy_to_user(grouplist, current->groups, sizeof(gid_t)*i))
 966                        return -EFAULT;
 967        }
 968        return i;
 969}
 970
 971/*
 972 *      SMP: Our groups are not shared. We can copy to/from them safely
 973 *      without another task interfering.
 974 */
 975 
 976asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist)
 977{
 978        if (!capable(CAP_SETGID))
 979                return -EPERM;
 980        if ((unsigned) gidsetsize > NGROUPS)
 981                return -EINVAL;
 982        if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
 983                return -EFAULT;
 984        current->ngroups = gidsetsize;
 985        return 0;
 986}
 987
 988static int supplemental_group_member(gid_t grp)
 989{
 990        int i = current->ngroups;
 991
 992        if (i) {
 993                gid_t *groups = current->groups;
 994                do {
 995                        if (*groups == grp)
 996                                return 1;
 997                        groups++;
 998                        i--;
 999                } while (i);
1000        }
1001        return 0;
1002}
1003
1004/*
1005 * Check whether we're fsgid/egid or in the supplemental group..
1006 */
1007int in_group_p(gid_t grp)
1008{
1009        int retval = 1;
1010        if (grp != current->fsgid)
1011                retval = supplemental_group_member(grp);
1012        return retval;
1013}
1014
1015int in_egroup_p(gid_t grp)
1016{
1017        int retval = 1;
1018        if (grp != current->egid)
1019                retval = supplemental_group_member(grp);
1020        return retval;
1021}
1022
1023DECLARE_RWSEM(uts_sem);
1024
1025asmlinkage long sys_newuname(struct new_utsname * name)
1026{
1027        int errno = 0;
1028
1029        down_read(&uts_sem);
1030        if (copy_to_user(name,&system_utsname,sizeof *name))
1031                errno = -EFAULT;
1032        up_read(&uts_sem);
1033        return errno;
1034}
1035
1036asmlinkage long sys_sethostname(char *name, int len)
1037{
1038        int errno;
1039        char tmp[__NEW_UTS_LEN];
1040
1041        if (!capable(CAP_SYS_ADMIN))
1042                return -EPERM;
1043        if (len < 0 || len > __NEW_UTS_LEN)
1044                return -EINVAL;
1045        down_write(&uts_sem);
1046        errno = -EFAULT;
1047        if (!copy_from_user(tmp, name, len)) {
1048                memcpy(system_utsname.nodename, tmp, len);
1049                system_utsname.nodename[len] = 0;
1050                errno = 0;
1051        }
1052        up_write(&uts_sem);
1053        return errno;
1054}
1055
1056asmlinkage long sys_gethostname(char *name, int len)
1057{
1058        int i, errno;
1059
1060        if (len < 0)
1061                return -EINVAL;
1062        down_read(&uts_sem);
1063        i = 1 + strlen(system_utsname.nodename);
1064        if (i > len)
1065                i = len;
1066        errno = 0;
1067        if (copy_to_user(name, system_utsname.nodename, i))
1068                errno = -EFAULT;
1069        up_read(&uts_sem);
1070        return errno;
1071}
1072
1073/*
1074 * Only setdomainname; getdomainname can be implemented by calling
1075 * uname()
1076 */
1077asmlinkage long sys_setdomainname(char *name, int len)
1078{
1079        int errno;
1080        char tmp[__NEW_UTS_LEN];
1081
1082        if (!capable(CAP_SYS_ADMIN))
1083                return -EPERM;
1084        if (len < 0 || len > __NEW_UTS_LEN)
1085                return -EINVAL;
1086
1087        down_write(&uts_sem);
1088        errno = -EFAULT;
1089        if (!copy_from_user(tmp, name, len)) {
1090                memcpy(system_utsname.domainname, tmp, len);
1091                system_utsname.domainname[len] = 0;
1092                errno = 0;
1093        }
1094        up_write(&uts_sem);
1095        return errno;
1096}
1097
1098asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim)
1099{
1100        if (resource >= RLIM_NLIMITS)
1101                return -EINVAL;
1102        else
1103                return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
1104                        ? -EFAULT : 0;
1105}
1106
1107#if !defined(__ia64__) 
1108
1109/*
1110 *      Back compatibility for getrlimit. Needed for some apps.
1111 */
1112 
1113asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim)
1114{
1115        struct rlimit x;
1116        if (resource >= RLIM_NLIMITS)
1117                return -EINVAL;
1118
1119        memcpy(&x, current->rlim + resource, sizeof(*rlim));
1120        if(x.rlim_cur > 0x7FFFFFFF)
1121                x.rlim_cur = 0x7FFFFFFF;
1122        if(x.rlim_max > 0x7FFFFFFF)
1123                x.rlim_max = 0x7FFFFFFF;
1124        return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
1125}
1126
1127#endif
1128
1129asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim)
1130{
1131        struct rlimit new_rlim, *old_rlim;
1132
1133        if (resource >= RLIM_NLIMITS)
1134                return -EINVAL;
1135        if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
1136                return -EFAULT;
1137       if (new_rlim.rlim_cur > new_rlim.rlim_max)
1138               return -EINVAL;
1139        old_rlim = current->rlim + resource;
1140        if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
1141             (new_rlim.rlim_max > old_rlim->rlim_max)) &&
1142            !capable(CAP_SYS_RESOURCE))
1143                return -EPERM;
1144        if (resource == RLIMIT_NOFILE) {
1145                if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
1146                        return -EPERM;
1147        }
1148        *old_rlim = new_rlim;
1149        return 0;
1150}
1151
1152/*
1153 * It would make sense to put struct rusage in the task_struct,
1154 * except that would make the task_struct be *really big*.  After
1155 * task_struct gets moved into malloc'ed memory, it would
1156 * make sense to do this.  It will make moving the rest of the information
1157 * a lot simpler!  (Which we're not doing right now because we're not
1158 * measuring them yet).
1159 *
1160 * This is SMP safe.  Either we are called from sys_getrusage on ourselves
1161 * below (we know we aren't going to exit/disappear and only we change our
1162 * rusage counters), or we are called from wait4() on a process which is
1163 * either stopped or zombied.  In the zombied case the task won't get
1164 * reaped till shortly after the call to getrusage(), in both cases the
1165 * task being examined is in a frozen state so the counters won't change.
1166 *
1167 * FIXME! Get the fault counts properly!
1168 */
1169int getrusage(struct task_struct *p, int who, struct rusage *ru)
1170{
1171        struct rusage r;
1172
1173        memset((char *) &r, 0, sizeof(r));
1174        switch (who) {
1175                case RUSAGE_SELF:
1176                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime);
1177                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime);
1178                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime);
1179                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime);
1180                        r.ru_minflt = p->min_flt;
1181                        r.ru_majflt = p->maj_flt;
1182                        r.ru_nswap = p->nswap;
1183                        break;
1184                case RUSAGE_CHILDREN:
1185                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_cutime);
1186                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_cutime);
1187                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_cstime);
1188                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_cstime);
1189                        r.ru_minflt = p->cmin_flt;
1190                        r.ru_majflt = p->cmaj_flt;
1191                        r.ru_nswap = p->cnswap;
1192                        break;
1193                default:
1194                        r.ru_utime.tv_sec = CT_TO_SECS(p->times.tms_utime + p->times.tms_cutime);
1195                        r.ru_utime.tv_usec = CT_TO_USECS(p->times.tms_utime + p->times.tms_cutime);
1196                        r.ru_stime.tv_sec = CT_TO_SECS(p->times.tms_stime + p->times.tms_cstime);
1197                        r.ru_stime.tv_usec = CT_TO_USECS(p->times.tms_stime + p->times.tms_cstime);
1198                        r.ru_minflt = p->min_flt + p->cmin_flt;
1199                        r.ru_majflt = p->maj_flt + p->cmaj_flt;
1200                        r.ru_nswap = p->nswap + p->cnswap;
1201                        break;
1202        }
1203        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
1204}
1205
1206asmlinkage long sys_getrusage(int who, struct rusage *ru)
1207{
1208        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
1209                return -EINVAL;
1210        return getrusage(current, who, ru);
1211}
1212
1213asmlinkage long sys_umask(int mask)
1214{
1215        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
1216        return mask;
1217}
1218    
1219asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
1220                          unsigned long arg4, unsigned long arg5)
1221{
1222        int error = 0;
1223        int sig;
1224
1225        switch (option) {
1226                case PR_SET_PDEATHSIG:
1227                        sig = arg2;
1228                        if (sig < 0 || sig > _NSIG) {
1229                                error = -EINVAL;
1230                                break;
1231                        }
1232                        current->pdeath_signal = sig;
1233                        break;
1234                case PR_GET_PDEATHSIG:
1235                        error = put_user(current->pdeath_signal, (int *)arg2);
1236                        break;
1237                case PR_GET_DUMPABLE:
1238                        if (is_dumpable(current))
1239                                error = 1;
1240                        break;
1241                case PR_SET_DUMPABLE:
1242                        if (arg2 != 0 && arg2 != 1) {
1243                                error = -EINVAL;
1244                                break;
1245                        }
1246                        current->mm->dumpable = arg2;
1247                        break;
1248
1249                case PR_SET_UNALIGN:
1250                        error = SET_UNALIGN_CTL(current, arg2);
1251                        break;
1252                case PR_GET_UNALIGN:
1253                        error = GET_UNALIGN_CTL(current, arg2);
1254                        break;
1255                case PR_SET_FPEMU:
1256                        error = SET_FPEMU_CTL(current, arg2);
1257                        break;
1258                case PR_GET_FPEMU:
1259                        error = GET_FPEMU_CTL(current, arg2);
1260                        break;
1261                case PR_SET_FPEXC:
1262                        error = SET_FPEXC_CTL(current, arg2);
1263                        break;
1264                case PR_GET_FPEXC:
1265                        error = GET_FPEXC_CTL(current, arg2);
1266                        break;
1267
1268                case PR_GET_KEEPCAPS:
1269                        if (current->keep_capabilities)
1270                                error = 1;
1271                        break;
1272                case PR_SET_KEEPCAPS:
1273                        if (arg2 != 0 && arg2 != 1) {
1274                                error = -EINVAL;
1275                                break;
1276                        }
1277                        current->keep_capabilities = arg2;
1278                        break;
1279                default:
1280                        error = -EINVAL;
1281                        break;
1282        }
1283        return error;
1284}
1285
1286EXPORT_SYMBOL(notifier_chain_register);
1287EXPORT_SYMBOL(notifier_chain_unregister);
1288EXPORT_SYMBOL(notifier_call_chain);
1289EXPORT_SYMBOL(register_reboot_notifier);
1290EXPORT_SYMBOL(unregister_reboot_notifier);
1291EXPORT_SYMBOL(in_group_p);
1292EXPORT_SYMBOL(in_egroup_p);
1293
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.