diff options
Diffstat (limited to 'kernel/sys.c')
| -rw-r--r-- | kernel/sys.c | 588 | 
1 files changed, 333 insertions, 255 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 31deba8f7d16..d356d79e84ac 100644 --- a/kernel/sys.c +++ b/kernel/sys.c  | |||
| @@ -112,12 +112,17 @@ EXPORT_SYMBOL(cad_pid); | |||
| 112 | 112 | ||
| 113 | void (*pm_power_off_prepare)(void); | 113 | void (*pm_power_off_prepare)(void); | 
| 114 | 114 | ||
| 115 | /* | ||
| 116 | * set the priority of a task | ||
| 117 | * - the caller must hold the RCU read lock | ||
| 118 | */ | ||
| 115 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 119 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 
| 116 | { | 120 | { | 
| 121 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); | ||
| 117 | int no_nice; | 122 | int no_nice; | 
| 118 | 123 | ||
| 119 | if (p->uid != current->euid && | 124 | if (pcred->uid != cred->euid && | 
| 120 | p->euid != current->euid && !capable(CAP_SYS_NICE)) { | 125 | pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) { | 
| 121 | error = -EPERM; | 126 | error = -EPERM; | 
| 122 | goto out; | 127 | goto out; | 
| 123 | } | 128 | } | 
| @@ -141,6 +146,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
| 141 | { | 146 | { | 
| 142 | struct task_struct *g, *p; | 147 | struct task_struct *g, *p; | 
| 143 | struct user_struct *user; | 148 | struct user_struct *user; | 
| 149 | const struct cred *cred = current_cred(); | ||
| 144 | int error = -EINVAL; | 150 | int error = -EINVAL; | 
| 145 | struct pid *pgrp; | 151 | struct pid *pgrp; | 
| 146 | 152 | ||
| @@ -174,18 +180,18 @@ asmlinkage long sys_setpriority(int which, int who, int niceval) | |||
| 174 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 180 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 
| 175 | break; | 181 | break; | 
| 176 | case PRIO_USER: | 182 | case PRIO_USER: | 
| 177 | user = current->user; | 183 | user = (struct user_struct *) cred->user; | 
| 178 | if (!who) | 184 | if (!who) | 
| 179 | who = current->uid; | 185 | who = cred->uid; | 
| 180 | else | 186 | else if ((who != cred->uid) && | 
| 181 | if ((who != current->uid) && !(user = find_user(who))) | 187 | !(user = find_user(who))) | 
| 182 | goto out_unlock; /* No processes for this user */ | 188 | goto out_unlock; /* No processes for this user */ | 
| 183 | 189 | ||
| 184 | do_each_thread(g, p) | 190 | do_each_thread(g, p) | 
| 185 | if (p->uid == who) | 191 | if (__task_cred(p)->uid == who) | 
| 186 | error = set_one_prio(p, niceval, error); | 192 | error = set_one_prio(p, niceval, error); | 
| 187 | while_each_thread(g, p); | 193 | while_each_thread(g, p); | 
| 188 | if (who != current->uid) | 194 | if (who != cred->uid) | 
| 189 | free_uid(user); /* For find_user() */ | 195 | free_uid(user); /* For find_user() */ | 
| 190 | break; | 196 | break; | 
| 191 | } | 197 | } | 
| @@ -205,6 +211,7 @@ asmlinkage long sys_getpriority(int which, int who) | |||
| 205 | { | 211 | { | 
| 206 | struct task_struct *g, *p; | 212 | struct task_struct *g, *p; | 
| 207 | struct user_struct *user; | 213 | struct user_struct *user; | 
| 214 | const struct cred *cred = current_cred(); | ||
| 208 | long niceval, retval = -ESRCH; | 215 | long niceval, retval = -ESRCH; | 
| 209 | struct pid *pgrp; | 216 | struct pid *pgrp; | 
| 210 | 217 | ||
| @@ -236,21 +243,21 @@ asmlinkage long sys_getpriority(int which, int who) | |||
| 236 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 243 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); | 
| 237 | break; | 244 | break; | 
| 238 | case PRIO_USER: | 245 | case PRIO_USER: | 
| 239 | user = current->user; | 246 | user = (struct user_struct *) cred->user; | 
| 240 | if (!who) | 247 | if (!who) | 
| 241 | who = current->uid; | 248 | who = cred->uid; | 
| 242 | else | 249 | else if ((who != cred->uid) && | 
| 243 | if ((who != current->uid) && !(user = find_user(who))) | 250 | !(user = find_user(who))) | 
| 244 | goto out_unlock; /* No processes for this user */ | 251 | goto out_unlock; /* No processes for this user */ | 
| 245 | 252 | ||
| 246 | do_each_thread(g, p) | 253 | do_each_thread(g, p) | 
| 247 | if (p->uid == who) { | 254 | if (__task_cred(p)->uid == who) { | 
| 248 | niceval = 20 - task_nice(p); | 255 | niceval = 20 - task_nice(p); | 
| 249 | if (niceval > retval) | 256 | if (niceval > retval) | 
| 250 | retval = niceval; | 257 | retval = niceval; | 
| 251 | } | 258 | } | 
| 252 | while_each_thread(g, p); | 259 | while_each_thread(g, p); | 
| 253 | if (who != current->uid) | 260 | if (who != cred->uid) | 
| 254 | free_uid(user); /* for find_user() */ | 261 | free_uid(user); /* for find_user() */ | 
| 255 | break; | 262 | break; | 
| 256 | } | 263 | } | 
| @@ -472,46 +479,48 @@ void ctrl_alt_del(void) | |||
| 472 | */ | 479 | */ | 
| 473 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | 480 | asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | 
| 474 | { | 481 | { | 
| 475 | int old_rgid = current->gid; | 482 | const struct cred *old; | 
| 476 | int old_egid = current->egid; | 483 | struct cred *new; | 
| 477 | int new_rgid = old_rgid; | ||
| 478 | int new_egid = old_egid; | ||
| 479 | int retval; | 484 | int retval; | 
| 480 | 485 | ||
| 486 | new = prepare_creds(); | ||
| 487 | if (!new) | ||
| 488 | return -ENOMEM; | ||
| 489 | old = current_cred(); | ||
| 490 | |||
| 481 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | 491 | retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); | 
| 482 | if (retval) | 492 | if (retval) | 
| 483 | return retval; | 493 | goto error; | 
| 484 | 494 | ||
| 495 | retval = -EPERM; | ||
| 485 | if (rgid != (gid_t) -1) { | 496 | if (rgid != (gid_t) -1) { | 
| 486 | if ((old_rgid == rgid) || | 497 | if (old->gid == rgid || | 
| 487 | (current->egid==rgid) || | 498 | old->egid == rgid || | 
| 488 | capable(CAP_SETGID)) | 499 | capable(CAP_SETGID)) | 
| 489 | new_rgid = rgid; | 500 | new->gid = rgid; | 
| 490 | else | 501 | else | 
| 491 | return -EPERM; | 502 | goto error; | 
| 492 | } | 503 | } | 
| 493 | if (egid != (gid_t) -1) { | 504 | if (egid != (gid_t) -1) { | 
| 494 | if ((old_rgid == egid) || | 505 | if (old->gid == egid || | 
| 495 | (current->egid == egid) || | 506 | old->egid == egid || | 
| 496 | (current->sgid == egid) || | 507 | old->sgid == egid || | 
| 497 | capable(CAP_SETGID)) | 508 | capable(CAP_SETGID)) | 
| 498 | new_egid = egid; | 509 | new->egid = egid; | 
| 499 | else | 510 | else | 
| 500 | return -EPERM; | 511 | goto error; | 
| 501 | } | ||
| 502 | if (new_egid != old_egid) { | ||
| 503 | set_dumpable(current->mm, suid_dumpable); | ||
| 504 | smp_wmb(); | ||
| 505 | } | 512 | } | 
| 513 | |||
| 506 | if (rgid != (gid_t) -1 || | 514 | if (rgid != (gid_t) -1 || | 
| 507 | (egid != (gid_t) -1 && egid != old_rgid)) | 515 | (egid != (gid_t) -1 && egid != old->gid)) | 
| 508 | current->sgid = new_egid; | 516 | new->sgid = new->egid; | 
| 509 | current->fsgid = new_egid; | 517 | new->fsgid = new->egid; | 
| 510 | current->egid = new_egid; | 518 | |
| 511 | current->gid = new_rgid; | 519 | return commit_creds(new); | 
| 512 | key_fsgid_changed(current); | 520 | |
| 513 | proc_id_connector(current, PROC_EVENT_GID); | 521 | error: | 
| 514 | return 0; | 522 | abort_creds(new); | 
| 523 | return retval; | ||
| 515 | } | 524 | } | 
| 516 | 525 | ||
| 517 | /* | 526 | /* | 
| @@ -521,56 +530,54 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) | |||
| 521 | */ | 530 | */ | 
| 522 | asmlinkage long sys_setgid(gid_t gid) | 531 | asmlinkage long sys_setgid(gid_t gid) | 
| 523 | { | 532 | { | 
| 524 | int old_egid = current->egid; | 533 | const struct cred *old; | 
| 534 | struct cred *new; | ||
| 525 | int retval; | 535 | int retval; | 
| 526 | 536 | ||
| 537 | new = prepare_creds(); | ||
| 538 | if (!new) | ||
| 539 | return -ENOMEM; | ||
| 540 | old = current_cred(); | ||
| 541 | |||
| 527 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | 542 | retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); | 
| 528 | if (retval) | 543 | if (retval) | 
| 529 | return retval; | 544 | goto error; | 
| 530 | 545 | ||
| 531 | if (capable(CAP_SETGID)) { | 546 | retval = -EPERM; | 
| 532 | if (old_egid != gid) { | 547 | if (capable(CAP_SETGID)) | 
| 533 | set_dumpable(current->mm, suid_dumpable); | 548 | new->gid = new->egid = new->sgid = new->fsgid = gid; | 
| 534 | smp_wmb(); | 549 | else if (gid == old->gid || gid == old->sgid) | 
| 535 | } | 550 | new->egid = new->fsgid = gid; | 
| 536 | current->gid = current->egid = current->sgid = current->fsgid = gid; | ||
| 537 | } else if ((gid == current->gid) || (gid == current->sgid)) { | ||
| 538 | if (old_egid != gid) { | ||
| 539 | set_dumpable(current->mm, suid_dumpable); | ||
| 540 | smp_wmb(); | ||
| 541 | } | ||
| 542 | current->egid = current->fsgid = gid; | ||
| 543 | } | ||
| 544 | else | 551 | else | 
| 545 | return -EPERM; | 552 | goto error; | 
| 546 | 553 | ||
| 547 | key_fsgid_changed(current); | 554 | return commit_creds(new); | 
| 548 | proc_id_connector(current, PROC_EVENT_GID); | 555 | |
| 549 | return 0; | 556 | error: | 
| 557 | abort_creds(new); | ||
| 558 | return retval; | ||
| 550 | } | 559 | } | 
| 551 | 560 | ||
| 552 | static int set_user(uid_t new_ruid, int dumpclear) | 561 | /* | 
| 562 | * change the user struct in a credentials set to match the new UID | ||
| 563 | */ | ||
| 564 | static int set_user(struct cred *new) | ||
| 553 | { | 565 | { | 
| 554 | struct user_struct *new_user; | 566 | struct user_struct *new_user; | 
| 555 | 567 | ||
| 556 | new_user = alloc_uid(current->nsproxy->user_ns, new_ruid); | 568 | new_user = alloc_uid(current_user_ns(), new->uid); | 
| 557 | if (!new_user) | 569 | if (!new_user) | 
| 558 | return -EAGAIN; | 570 | return -EAGAIN; | 
| 559 | 571 | ||
| 560 | if (atomic_read(&new_user->processes) >= | 572 | if (atomic_read(&new_user->processes) >= | 
| 561 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && | 573 | current->signal->rlim[RLIMIT_NPROC].rlim_cur && | 
| 562 | new_user != current->nsproxy->user_ns->root_user) { | 574 | new_user != INIT_USER) { | 
| 563 | free_uid(new_user); | 575 | free_uid(new_user); | 
| 564 | return -EAGAIN; | 576 | return -EAGAIN; | 
| 565 | } | 577 | } | 
| 566 | 578 | ||
| 567 | switch_uid(new_user); | 579 | free_uid(new->user); | 
| 568 | 580 | new->user = new_user; | |
| 569 | if (dumpclear) { | ||
| 570 | set_dumpable(current->mm, suid_dumpable); | ||
| 571 | smp_wmb(); | ||
| 572 | } | ||
| 573 | current->uid = new_ruid; | ||
| 574 | return 0; | 581 | return 0; | 
| 575 | } | 582 | } | 
| 576 | 583 | ||
| @@ -591,54 +598,56 @@ static int set_user(uid_t new_ruid, int dumpclear) | |||
| 591 | */ | 598 | */ | 
| 592 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | 599 | asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | 
| 593 | { | 600 | { | 
| 594 | int old_ruid, old_euid, old_suid, new_ruid, new_euid; | 601 | const struct cred *old; | 
| 602 | struct cred *new; | ||
| 595 | int retval; | 603 | int retval; | 
| 596 | 604 | ||
| 605 | new = prepare_creds(); | ||
| 606 | if (!new) | ||
| 607 | return -ENOMEM; | ||
| 608 | old = current_cred(); | ||
| 609 | |||
| 597 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | 610 | retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); | 
| 598 | if (retval) | 611 | if (retval) | 
| 599 | return retval; | 612 | goto error; | 
| 600 | |||
| 601 | new_ruid = old_ruid = current->uid; | ||
| 602 | new_euid = old_euid = current->euid; | ||
| 603 | old_suid = current->suid; | ||
| 604 | 613 | ||
| 614 | retval = -EPERM; | ||
| 605 | if (ruid != (uid_t) -1) { | 615 | if (ruid != (uid_t) -1) { | 
| 606 | new_ruid = ruid; | 616 | new->uid = ruid; | 
| 607 | if ((old_ruid != ruid) && | 617 | if (old->uid != ruid && | 
| 608 | (current->euid != ruid) && | 618 | old->euid != ruid && | 
| 609 | !capable(CAP_SETUID)) | 619 | !capable(CAP_SETUID)) | 
| 610 | return -EPERM; | 620 | goto error; | 
| 611 | } | 621 | } | 
| 612 | 622 | ||
| 613 | if (euid != (uid_t) -1) { | 623 | if (euid != (uid_t) -1) { | 
| 614 | new_euid = euid; | 624 | new->euid = euid; | 
| 615 | if ((old_ruid != euid) && | 625 | if (old->uid != euid && | 
| 616 | (current->euid != euid) && | 626 | old->euid != euid && | 
| 617 | (current->suid != euid) && | 627 | old->suid != euid && | 
| 618 | !capable(CAP_SETUID)) | 628 | !capable(CAP_SETUID)) | 
| 619 | return -EPERM; | 629 | goto error; | 
| 620 | } | 630 | } | 
| 621 | 631 | ||
| 622 | if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) | 632 | retval = -EAGAIN; | 
| 623 | return -EAGAIN; | 633 | if (new->uid != old->uid && set_user(new) < 0) | 
| 634 | goto error; | ||
| 624 | 635 | ||
| 625 | if (new_euid != old_euid) { | ||
| 626 | set_dumpable(current->mm, suid_dumpable); | ||
| 627 | smp_wmb(); | ||
| 628 | } | ||
| 629 | current->fsuid = current->euid = new_euid; | ||
| 630 | if (ruid != (uid_t) -1 || | 636 | if (ruid != (uid_t) -1 || | 
| 631 | (euid != (uid_t) -1 && euid != old_ruid)) | 637 | (euid != (uid_t) -1 && euid != old->uid)) | 
| 632 | current->suid = current->euid; | 638 | new->suid = new->euid; | 
| 633 | current->fsuid = current->euid; | 639 | new->fsuid = new->euid; | 
| 634 | 640 | ||
| 635 | key_fsuid_changed(current); | 641 | retval = security_task_fix_setuid(new, old, LSM_SETID_RE); | 
| 636 | proc_id_connector(current, PROC_EVENT_UID); | 642 | if (retval < 0) | 
| 637 | 643 | goto error; | |
| 638 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); | ||
| 639 | } | ||
| 640 | 644 | ||
| 645 | return commit_creds(new); | ||
| 641 | 646 | ||
| 647 | error: | ||
| 648 | abort_creds(new); | ||
| 649 | return retval; | ||
| 650 | } | ||
| 642 | 651 | ||
| 643 | /* | 652 | /* | 
| 644 | * setuid() is implemented like SysV with SAVED_IDS | 653 | * setuid() is implemented like SysV with SAVED_IDS | 
| @@ -653,36 +662,41 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) | |||
| 653 | */ | 662 | */ | 
| 654 | asmlinkage long sys_setuid(uid_t uid) | 663 | asmlinkage long sys_setuid(uid_t uid) | 
| 655 | { | 664 | { | 
| 656 | int old_euid = current->euid; | 665 | const struct cred *old; | 
| 657 | int old_ruid, old_suid, new_suid; | 666 | struct cred *new; | 
| 658 | int retval; | 667 | int retval; | 
| 659 | 668 | ||
| 669 | new = prepare_creds(); | ||
| 670 | if (!new) | ||
| 671 | return -ENOMEM; | ||
| 672 | old = current_cred(); | ||
| 673 | |||
| 660 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | 674 | retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); | 
| 661 | if (retval) | 675 | if (retval) | 
| 662 | return retval; | 676 | goto error; | 
| 663 | 677 | ||
| 664 | old_ruid = current->uid; | 678 | retval = -EPERM; | 
| 665 | old_suid = current->suid; | ||
| 666 | new_suid = old_suid; | ||
| 667 | |||
| 668 | if (capable(CAP_SETUID)) { | 679 | if (capable(CAP_SETUID)) { | 
| 669 | if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) | 680 | new->suid = new->uid = uid; | 
| 670 | return -EAGAIN; | 681 | if (uid != old->uid && set_user(new) < 0) { | 
| 671 | new_suid = uid; | 682 | retval = -EAGAIN; | 
| 672 | } else if ((uid != current->uid) && (uid != new_suid)) | 683 | goto error; | 
| 673 | return -EPERM; | 684 | } | 
| 674 | 685 | } else if (uid != old->uid && uid != new->suid) { | |
| 675 | if (old_euid != uid) { | 686 | goto error; | 
| 676 | set_dumpable(current->mm, suid_dumpable); | ||
| 677 | smp_wmb(); | ||
| 678 | } | 687 | } | 
| 679 | current->fsuid = current->euid = uid; | ||
| 680 | current->suid = new_suid; | ||
| 681 | 688 | ||
| 682 | key_fsuid_changed(current); | 689 | new->fsuid = new->euid = uid; | 
| 683 | proc_id_connector(current, PROC_EVENT_UID); | 690 | |
| 691 | retval = security_task_fix_setuid(new, old, LSM_SETID_ID); | ||
| 692 | if (retval < 0) | ||
| 693 | goto error; | ||
| 684 | 694 | ||
| 685 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); | 695 | return commit_creds(new); | 
| 696 | |||
| 697 | error: | ||
| 698 | abort_creds(new); | ||
| 699 | return retval; | ||
| 686 | } | 700 | } | 
| 687 | 701 | ||
| 688 | 702 | ||
| @@ -692,54 +706,63 @@ asmlinkage long sys_setuid(uid_t uid) | |||
| 692 | */ | 706 | */ | 
| 693 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | 707 | asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) | 
| 694 | { | 708 | { | 
| 695 | int old_ruid = current->uid; | 709 | const struct cred *old; | 
| 696 | int old_euid = current->euid; | 710 | struct cred *new; | 
| 697 | int old_suid = current->suid; | ||
| 698 | int retval; | 711 | int retval; | 
| 699 | 712 | ||
| 713 | new = prepare_creds(); | ||
| 714 | if (!new) | ||
| 715 | return -ENOMEM; | ||
| 716 | |||
| 700 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | 717 | retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); | 
| 701 | if (retval) | 718 | if (retval) | 
| 702 | return retval; | 719 | goto error; | 
| 720 | old = current_cred(); | ||
| 703 | 721 | ||
| 722 | retval = -EPERM; | ||
| 704 | if (!capable(CAP_SETUID)) { | 723 | if (!capable(CAP_SETUID)) { | 
| 705 | if ((ruid != (uid_t) -1) && (ruid != current->uid) && | 724 | if (ruid != (uid_t) -1 && ruid != old->uid && | 
| 706 | (ruid != current->euid) && (ruid != current->suid)) | 725 | ruid != old->euid && ruid != old->suid) | 
| 707 | return -EPERM; | 726 | goto error; | 
| 708 | if ((euid != (uid_t) -1) && (euid != current->uid) && | 727 | if (euid != (uid_t) -1 && euid != old->uid && | 
| 709 | (euid != current->euid) && (euid != current->suid)) | 728 | euid != old->euid && euid != old->suid) | 
| 710 | return -EPERM; | 729 | goto error; | 
| 711 | if ((suid != (uid_t) -1) && (suid != current->uid) && | 730 | if (suid != (uid_t) -1 && suid != old->uid && | 
| 712 | (suid != current->euid) && (suid != current->suid)) | 731 | suid != old->euid && suid != old->suid) | 
| 713 | return -EPERM; | 732 | goto error; | 
| 714 | } | 733 | } | 
| 734 | |||
| 735 | retval = -EAGAIN; | ||
| 715 | if (ruid != (uid_t) -1) { | 736 | if (ruid != (uid_t) -1) { | 
| 716 | if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) | 737 | new->uid = ruid; | 
| 717 | return -EAGAIN; | 738 | if (ruid != old->uid && set_user(new) < 0) | 
| 739 | goto error; | ||
| 718 | } | 740 | } | 
| 719 | if (euid != (uid_t) -1) { | 741 | if (euid != (uid_t) -1) | 
| 720 | if (euid != current->euid) { | 742 | new->euid = euid; | 
| 721 | set_dumpable(current->mm, suid_dumpable); | ||
| 722 | smp_wmb(); | ||
| 723 | } | ||
| 724 | current->euid = euid; | ||
| 725 | } | ||
| 726 | current->fsuid = current->euid; | ||
| 727 | if (suid != (uid_t) -1) | 743 | if (suid != (uid_t) -1) | 
| 728 | current->suid = suid; | 744 | new->suid = suid; | 
| 745 | new->fsuid = new->euid; | ||
| 746 | |||
| 747 | retval = security_task_fix_setuid(new, old, LSM_SETID_RES); | ||
| 748 | if (retval < 0) | ||
| 749 | goto error; | ||
| 729 | 750 | ||
| 730 | key_fsuid_changed(current); | 751 | return commit_creds(new); | 
| 731 | proc_id_connector(current, PROC_EVENT_UID); | ||
| 732 | 752 | ||
| 733 | return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); | 753 | error: | 
| 754 | abort_creds(new); | ||
| 755 | return retval; | ||
| 734 | } | 756 | } | 
| 735 | 757 | ||
| 736 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) | 758 | asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid) | 
| 737 | { | 759 | { | 
| 760 | const struct cred *cred = current_cred(); | ||
| 738 | int retval; | 761 | int retval; | 
| 739 | 762 | ||
| 740 | if (!(retval = put_user(current->uid, ruid)) && | 763 | if (!(retval = put_user(cred->uid, ruid)) && | 
| 741 | !(retval = put_user(current->euid, euid))) | 764 | !(retval = put_user(cred->euid, euid))) | 
| 742 | retval = put_user(current->suid, suid); | 765 | retval = put_user(cred->suid, suid); | 
| 743 | 766 | ||
| 744 | return retval; | 767 | return retval; | 
| 745 | } | 768 | } | 
| @@ -749,48 +772,55 @@ asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __us | |||
| 749 | */ | 772 | */ | 
| 750 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) | 773 | asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) | 
| 751 | { | 774 | { | 
| 775 | const struct cred *old; | ||
| 776 | struct cred *new; | ||
| 752 | int retval; | 777 | int retval; | 
| 753 | 778 | ||
| 779 | new = prepare_creds(); | ||
| 780 | if (!new) | ||
| 781 | return -ENOMEM; | ||
| 782 | old = current_cred(); | ||
| 783 | |||
| 754 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | 784 | retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); | 
| 755 | if (retval) | 785 | if (retval) | 
| 756 | return retval; | 786 | goto error; | 
| 757 | 787 | ||
| 788 | retval = -EPERM; | ||
| 758 | if (!capable(CAP_SETGID)) { | 789 | if (!capable(CAP_SETGID)) { | 
| 759 | if ((rgid != (gid_t) -1) && (rgid != current->gid) && | 790 | if (rgid != (gid_t) -1 && rgid != old->gid && | 
| 760 | (rgid != current->egid) && (rgid != current->sgid)) | 791 | rgid != old->egid && rgid != old->sgid) | 
| 761 | return -EPERM; | 792 | goto error; | 
| 762 | if ((egid != (gid_t) -1) && (egid != current->gid) && | 793 | if (egid != (gid_t) -1 && egid != old->gid && | 
| 763 | (egid != current->egid) && (egid != current->sgid)) | 794 | egid != old->egid && egid != old->sgid) | 
| 764 | return -EPERM; | 795 | goto error; | 
| 765 | if ((sgid != (gid_t) -1) && (sgid != current->gid) && | 796 | if (sgid != (gid_t) -1 && sgid != old->gid && | 
| 766 | (sgid != current->egid) && (sgid != current->sgid)) | 797 | sgid != old->egid && sgid != old->sgid) | 
| 767 | return -EPERM; | 798 | goto error; | 
| 768 | } | ||
| 769 | if (egid != (gid_t) -1) { | ||
| 770 | if (egid != current->egid) { | ||
| 771 | set_dumpable(current->mm, suid_dumpable); | ||
| 772 | smp_wmb(); | ||
| 773 | } | ||
| 774 | current->egid = egid; | ||
| 775 | } | 799 | } | 
| 776 | current->fsgid = current->egid; | 800 | |
| 777 | if (rgid != (gid_t) -1) | 801 | if (rgid != (gid_t) -1) | 
| 778 | current->gid = rgid; | 802 | new->gid = rgid; | 
| 803 | if (egid != (gid_t) -1) | ||
| 804 | new->egid = egid; | ||
| 779 | if (sgid != (gid_t) -1) | 805 | if (sgid != (gid_t) -1) | 
| 780 | current->sgid = sgid; | 806 | new->sgid = sgid; | 
| 807 | new->fsgid = new->egid; | ||
| 781 | 808 | ||
| 782 | key_fsgid_changed(current); | 809 | return commit_creds(new); | 
| 783 | proc_id_connector(current, PROC_EVENT_GID); | 810 | |
| 784 | return 0; | 811 | error: | 
| 812 | abort_creds(new); | ||
| 813 | return retval; | ||
| 785 | } | 814 | } | 
| 786 | 815 | ||
| 787 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) | 816 | asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid) | 
| 788 | { | 817 | { | 
| 818 | const struct cred *cred = current_cred(); | ||
| 789 | int retval; | 819 | int retval; | 
| 790 | 820 | ||
| 791 | if (!(retval = put_user(current->gid, rgid)) && | 821 | if (!(retval = put_user(cred->gid, rgid)) && | 
| 792 | !(retval = put_user(current->egid, egid))) | 822 | !(retval = put_user(cred->egid, egid))) | 
| 793 | retval = put_user(current->sgid, sgid); | 823 | retval = put_user(cred->sgid, sgid); | 
| 794 | 824 | ||
| 795 | return retval; | 825 | return retval; | 
| 796 | } | 826 | } | 
| @@ -804,27 +834,35 @@ asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __us | |||
| 804 | */ | 834 | */ | 
| 805 | asmlinkage long sys_setfsuid(uid_t uid) | 835 | asmlinkage long sys_setfsuid(uid_t uid) | 
| 806 | { | 836 | { | 
| 807 | int old_fsuid; | 837 | const struct cred *old; | 
| 838 | struct cred *new; | ||
| 839 | uid_t old_fsuid; | ||
| 840 | |||
| 841 | new = prepare_creds(); | ||
| 842 | if (!new) | ||
| 843 | return current_fsuid(); | ||
| 844 | old = current_cred(); | ||
| 845 | old_fsuid = old->fsuid; | ||
| 808 | 846 | ||
| 809 | old_fsuid = current->fsuid; | 847 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS) < 0) | 
| 810 | if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) | 848 | goto error; | 
| 811 | return old_fsuid; | ||
| 812 | 849 | ||
| 813 | if (uid == current->uid || uid == current->euid || | 850 | if (uid == old->uid || uid == old->euid || | 
| 814 | uid == current->suid || uid == current->fsuid || | 851 | uid == old->suid || uid == old->fsuid || | 
| 815 | capable(CAP_SETUID)) { | 852 | capable(CAP_SETUID)) { | 
| 816 | if (uid != old_fsuid) { | 853 | if (uid != old_fsuid) { | 
| 817 | set_dumpable(current->mm, suid_dumpable); | 854 | new->fsuid = uid; | 
| 818 | smp_wmb(); | 855 | if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) | 
| 856 | goto change_okay; | ||
| 819 | } | 857 | } | 
| 820 | current->fsuid = uid; | ||
| 821 | } | 858 | } | 
| 822 | 859 | ||
| 823 | key_fsuid_changed(current); | 860 | error: | 
| 824 | proc_id_connector(current, PROC_EVENT_UID); | 861 | abort_creds(new); | 
| 825 | 862 | return old_fsuid; | |
| 826 | security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); | ||
| 827 | 863 | ||
| 864 | change_okay: | ||
| 865 | commit_creds(new); | ||
| 828 | return old_fsuid; | 866 | return old_fsuid; | 
| 829 | } | 867 | } | 
| 830 | 868 | ||
| @@ -833,23 +871,34 @@ asmlinkage long sys_setfsuid(uid_t uid) | |||
| 833 | */ | 871 | */ | 
| 834 | asmlinkage long sys_setfsgid(gid_t gid) | 872 | asmlinkage long sys_setfsgid(gid_t gid) | 
| 835 | { | 873 | { | 
| 836 | int old_fsgid; | 874 | const struct cred *old; | 
| 875 | struct cred *new; | ||
| 876 | gid_t old_fsgid; | ||
| 877 | |||
| 878 | new = prepare_creds(); | ||
| 879 | if (!new) | ||
| 880 | return current_fsgid(); | ||
| 881 | old = current_cred(); | ||
| 882 | old_fsgid = old->fsgid; | ||
| 837 | 883 | ||
| 838 | old_fsgid = current->fsgid; | ||
| 839 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | 884 | if (security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS)) | 
| 840 | return old_fsgid; | 885 | goto error; | 
| 841 | 886 | ||
| 842 | if (gid == current->gid || gid == current->egid || | 887 | if (gid == old->gid || gid == old->egid || | 
| 843 | gid == current->sgid || gid == current->fsgid || | 888 | gid == old->sgid || gid == old->fsgid || | 
| 844 | capable(CAP_SETGID)) { | 889 | capable(CAP_SETGID)) { | 
| 845 | if (gid != old_fsgid) { | 890 | if (gid != old_fsgid) { | 
| 846 | set_dumpable(current->mm, suid_dumpable); | 891 | new->fsgid = gid; | 
| 847 | smp_wmb(); | 892 | goto change_okay; | 
| 848 | } | 893 | } | 
| 849 | current->fsgid = gid; | ||
| 850 | key_fsgid_changed(current); | ||
| 851 | proc_id_connector(current, PROC_EVENT_GID); | ||
| 852 | } | 894 | } | 
| 895 | |||
| 896 | error: | ||
| 897 | abort_creds(new); | ||
| 898 | return old_fsgid; | ||
| 899 | |||
| 900 | change_okay: | ||
| 901 | commit_creds(new); | ||
| 853 | return old_fsgid; | 902 | return old_fsgid; | 
| 854 | } | 903 | } | 
| 855 | 904 | ||
| @@ -858,8 +907,8 @@ void do_sys_times(struct tms *tms) | |||
| 858 | struct task_cputime cputime; | 907 | struct task_cputime cputime; | 
| 859 | cputime_t cutime, cstime; | 908 | cputime_t cutime, cstime; | 
| 860 | 909 | ||
| 861 | spin_lock_irq(¤t->sighand->siglock); | ||
| 862 | thread_group_cputime(current, &cputime); | 910 | thread_group_cputime(current, &cputime); | 
| 911 | spin_lock_irq(¤t->sighand->siglock); | ||
| 863 | cutime = current->signal->cutime; | 912 | cutime = current->signal->cutime; | 
| 864 | cstime = current->signal->cstime; | 913 | cstime = current->signal->cstime; | 
| 865 | spin_unlock_irq(¤t->sighand->siglock); | 914 | spin_unlock_irq(¤t->sighand->siglock); | 
| @@ -1118,7 +1167,7 @@ EXPORT_SYMBOL(groups_free); | |||
| 1118 | 1167 | ||
| 1119 | /* export the group_info to a user-space array */ | 1168 | /* export the group_info to a user-space array */ | 
| 1120 | static int groups_to_user(gid_t __user *grouplist, | 1169 | static int groups_to_user(gid_t __user *grouplist, | 
| 1121 | struct group_info *group_info) | 1170 | const struct group_info *group_info) | 
| 1122 | { | 1171 | { | 
| 1123 | int i; | 1172 | int i; | 
| 1124 | unsigned int count = group_info->ngroups; | 1173 | unsigned int count = group_info->ngroups; | 
| @@ -1186,7 +1235,7 @@ static void groups_sort(struct group_info *group_info) | |||
| 1186 | } | 1235 | } | 
| 1187 | 1236 | ||
| 1188 | /* a simple bsearch */ | 1237 | /* a simple bsearch */ | 
| 1189 | int groups_search(struct group_info *group_info, gid_t grp) | 1238 | int groups_search(const struct group_info *group_info, gid_t grp) | 
| 1190 | { | 1239 | { | 
| 1191 | unsigned int left, right; | 1240 | unsigned int left, right; | 
| 1192 | 1241 | ||
| @@ -1208,51 +1257,74 @@ int groups_search(struct group_info *group_info, gid_t grp) | |||
| 1208 | return 0; | 1257 | return 0; | 
| 1209 | } | 1258 | } | 
| 1210 | 1259 | ||
| 1211 | /* validate and set current->group_info */ | 1260 | /** | 
| 1212 | int set_current_groups(struct group_info *group_info) | 1261 | * set_groups - Change a group subscription in a set of credentials | 
| 1262 | * @new: The newly prepared set of credentials to alter | ||
| 1263 | * @group_info: The group list to install | ||
| 1264 | * | ||
| 1265 | * Validate a group subscription and, if valid, insert it into a set | ||
| 1266 | * of credentials. | ||
| 1267 | */ | ||
| 1268 | int set_groups(struct cred *new, struct group_info *group_info) | ||
| 1213 | { | 1269 | { | 
| 1214 | int retval; | 1270 | int retval; | 
| 1215 | struct group_info *old_info; | ||
| 1216 | 1271 | ||
| 1217 | retval = security_task_setgroups(group_info); | 1272 | retval = security_task_setgroups(group_info); | 
| 1218 | if (retval) | 1273 | if (retval) | 
| 1219 | return retval; | 1274 | return retval; | 
| 1220 | 1275 | ||
| 1276 | put_group_info(new->group_info); | ||
| 1221 | groups_sort(group_info); | 1277 | groups_sort(group_info); | 
| 1222 | get_group_info(group_info); | 1278 | get_group_info(group_info); | 
| 1279 | new->group_info = group_info; | ||
| 1280 | return 0; | ||
| 1281 | } | ||
| 1223 | 1282 | ||
| 1224 | task_lock(current); | 1283 | EXPORT_SYMBOL(set_groups); | 
| 1225 | old_info = current->group_info; | ||
| 1226 | current->group_info = group_info; | ||
| 1227 | task_unlock(current); | ||
| 1228 | 1284 | ||
| 1229 | put_group_info(old_info); | 1285 | /** | 
| 1286 | * set_current_groups - Change current's group subscription | ||
| 1287 | * @group_info: The group list to impose | ||
| 1288 | * | ||
| 1289 | * Validate a group subscription and, if valid, impose it upon current's task | ||
| 1290 | * security record. | ||
| 1291 | */ | ||
| 1292 | int set_current_groups(struct group_info *group_info) | ||
| 1293 | { | ||
| 1294 | struct cred *new; | ||
| 1295 | int ret; | ||
| 1230 | 1296 | ||
| 1231 | return 0; | 1297 | new = prepare_creds(); | 
| 1298 | if (!new) | ||
| 1299 | return -ENOMEM; | ||
| 1300 | |||
| 1301 | ret = set_groups(new, group_info); | ||
| 1302 | if (ret < 0) { | ||
| 1303 | abort_creds(new); | ||
| 1304 | return ret; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | return commit_creds(new); | ||
| 1232 | } | 1308 | } | 
| 1233 | 1309 | ||
| 1234 | EXPORT_SYMBOL(set_current_groups); | 1310 | EXPORT_SYMBOL(set_current_groups); | 
| 1235 | 1311 | ||
| 1236 | asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) | 1312 | asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) | 
| 1237 | { | 1313 | { | 
| 1238 | int i = 0; | 1314 | const struct cred *cred = current_cred(); | 
| 1239 | 1315 | int i; | |
| 1240 | /* | ||
| 1241 | * SMP: Nobody else can change our grouplist. Thus we are | ||
| 1242 | * safe. | ||
| 1243 | */ | ||
| 1244 | 1316 | ||
| 1245 | if (gidsetsize < 0) | 1317 | if (gidsetsize < 0) | 
| 1246 | return -EINVAL; | 1318 | return -EINVAL; | 
| 1247 | 1319 | ||
| 1248 | /* no need to grab task_lock here; it cannot change */ | 1320 | /* no need to grab task_lock here; it cannot change */ | 
| 1249 | i = current->group_info->ngroups; | 1321 | i = cred->group_info->ngroups; | 
| 1250 | if (gidsetsize) { | 1322 | if (gidsetsize) { | 
| 1251 | if (i > gidsetsize) { | 1323 | if (i > gidsetsize) { | 
| 1252 | i = -EINVAL; | 1324 | i = -EINVAL; | 
| 1253 | goto out; | 1325 | goto out; | 
| 1254 | } | 1326 | } | 
| 1255 | if (groups_to_user(grouplist, current->group_info)) { | 1327 | if (groups_to_user(grouplist, cred->group_info)) { | 
| 1256 | i = -EFAULT; | 1328 | i = -EFAULT; | 
| 1257 | goto out; | 1329 | goto out; | 
| 1258 | } | 1330 | } | 
| @@ -1296,9 +1368,11 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist) | |||
| 1296 | */ | 1368 | */ | 
| 1297 | int in_group_p(gid_t grp) | 1369 | int in_group_p(gid_t grp) | 
| 1298 | { | 1370 | { | 
| 1371 | const struct cred *cred = current_cred(); | ||
| 1299 | int retval = 1; | 1372 | int retval = 1; | 
| 1300 | if (grp != current->fsgid) | 1373 | |
| 1301 | retval = groups_search(current->group_info, grp); | 1374 | if (grp != cred->fsgid) | 
| 1375 | retval = groups_search(cred->group_info, grp); | ||
| 1302 | return retval; | 1376 | return retval; | 
| 1303 | } | 1377 | } | 
| 1304 | 1378 | ||
| @@ -1306,9 +1380,11 @@ EXPORT_SYMBOL(in_group_p); | |||
| 1306 | 1380 | ||
| 1307 | int in_egroup_p(gid_t grp) | 1381 | int in_egroup_p(gid_t grp) | 
| 1308 | { | 1382 | { | 
| 1383 | const struct cred *cred = current_cred(); | ||
| 1309 | int retval = 1; | 1384 | int retval = 1; | 
| 1310 | if (grp != current->egid) | 1385 | |
| 1311 | retval = groups_search(current->group_info, grp); | 1386 | if (grp != cred->egid) | 
| 1387 | retval = groups_search(cred->group_info, grp); | ||
| 1312 | return retval; | 1388 | return retval; | 
| 1313 | } | 1389 | } | 
| 1314 | 1390 | ||
| @@ -1624,50 +1700,56 @@ asmlinkage long sys_umask(int mask) | |||
| 1624 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | 1700 | asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | 
| 1625 | unsigned long arg4, unsigned long arg5) | 1701 | unsigned long arg4, unsigned long arg5) | 
| 1626 | { | 1702 | { | 
| 1627 | long error = 0; | 1703 | struct task_struct *me = current; | 
| 1704 | unsigned char comm[sizeof(me->comm)]; | ||
| 1705 | long error; | ||
| 1628 | 1706 | ||
| 1629 | if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) | 1707 | error = security_task_prctl(option, arg2, arg3, arg4, arg5); | 
| 1708 | if (error != -ENOSYS) | ||
| 1630 | return error; | 1709 | return error; | 
| 1631 | 1710 | ||
| 1711 | error = 0; | ||
| 1632 | switch (option) { | 1712 | switch (option) { | 
| 1633 | case PR_SET_PDEATHSIG: | 1713 | case PR_SET_PDEATHSIG: | 
| 1634 | if (!valid_signal(arg2)) { | 1714 | if (!valid_signal(arg2)) { | 
| 1635 | error = -EINVAL; | 1715 | error = -EINVAL; | 
| 1636 | break; | 1716 | break; | 
| 1637 | } | 1717 | } | 
| 1638 | current->pdeath_signal = arg2; | 1718 | me->pdeath_signal = arg2; | 
| 1719 | error = 0; | ||
| 1639 | break; | 1720 | break; | 
| 1640 | case PR_GET_PDEATHSIG: | 1721 | case PR_GET_PDEATHSIG: | 
| 1641 | error = put_user(current->pdeath_signal, (int __user *)arg2); | 1722 | error = put_user(me->pdeath_signal, (int __user *)arg2); | 
| 1642 | break; | 1723 | break; | 
| 1643 | case PR_GET_DUMPABLE: | 1724 | case PR_GET_DUMPABLE: | 
| 1644 | error = get_dumpable(current->mm); | 1725 | error = get_dumpable(me->mm); | 
| 1645 | break; | 1726 | break; | 
| 1646 | case PR_SET_DUMPABLE: | 1727 | case PR_SET_DUMPABLE: | 
| 1647 | if (arg2 < 0 || arg2 > 1) { | 1728 | if (arg2 < 0 || arg2 > 1) { | 
| 1648 | error = -EINVAL; | 1729 | error = -EINVAL; | 
| 1649 | break; | 1730 | break; | 
| 1650 | } | 1731 | } | 
| 1651 | set_dumpable(current->mm, arg2); | 1732 | set_dumpable(me->mm, arg2); | 
| 1733 | error = 0; | ||
| 1652 | break; | 1734 | break; | 
| 1653 | 1735 | ||
| 1654 | case PR_SET_UNALIGN: | 1736 | case PR_SET_UNALIGN: | 
| 1655 | error = SET_UNALIGN_CTL(current, arg2); | 1737 | error = SET_UNALIGN_CTL(me, arg2); | 
| 1656 | break; | 1738 | break; | 
| 1657 | case PR_GET_UNALIGN: | 1739 | case PR_GET_UNALIGN: | 
| 1658 | error = GET_UNALIGN_CTL(current, arg2); | 1740 | error = GET_UNALIGN_CTL(me, arg2); | 
| 1659 | break; | 1741 | break; | 
| 1660 | case PR_SET_FPEMU: | 1742 | case PR_SET_FPEMU: | 
| 1661 | error = SET_FPEMU_CTL(current, arg2); | 1743 | error = SET_FPEMU_CTL(me, arg2); | 
| 1662 | break; | 1744 | break; | 
| 1663 | case PR_GET_FPEMU: | 1745 | case PR_GET_FPEMU: | 
| 1664 | error = GET_FPEMU_CTL(current, arg2); | 1746 | error = GET_FPEMU_CTL(me, arg2); | 
| 1665 | break; | 1747 | break; | 
| 1666 | case PR_SET_FPEXC: | 1748 | case PR_SET_FPEXC: | 
| 1667 | error = SET_FPEXC_CTL(current, arg2); | 1749 | error = SET_FPEXC_CTL(me, arg2); | 
| 1668 | break; | 1750 | break; | 
| 1669 | case PR_GET_FPEXC: | 1751 | case PR_GET_FPEXC: | 
| 1670 | error = GET_FPEXC_CTL(current, arg2); | 1752 | error = GET_FPEXC_CTL(me, arg2); | 
| 1671 | break; | 1753 | break; | 
| 1672 | case PR_GET_TIMING: | 1754 | case PR_GET_TIMING: | 
| 1673 | error = PR_TIMING_STATISTICAL; | 1755 | error = PR_TIMING_STATISTICAL; | 
| @@ -1675,33 +1757,28 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 1675 | case PR_SET_TIMING: | 1757 | case PR_SET_TIMING: | 
| 1676 | if (arg2 != PR_TIMING_STATISTICAL) | 1758 | if (arg2 != PR_TIMING_STATISTICAL) | 
| 1677 | error = -EINVAL; | 1759 | error = -EINVAL; | 
| 1760 | else | ||
| 1761 | error = 0; | ||
| 1678 | break; | 1762 | break; | 
| 1679 | 1763 | ||
| 1680 | case PR_SET_NAME: { | 1764 | case PR_SET_NAME: | 
| 1681 | struct task_struct *me = current; | 1765 | comm[sizeof(me->comm)-1] = 0; | 
| 1682 | unsigned char ncomm[sizeof(me->comm)]; | 1766 | if (strncpy_from_user(comm, (char __user *)arg2, | 
| 1683 | 1767 | sizeof(me->comm) - 1) < 0) | |
| 1684 | ncomm[sizeof(me->comm)-1] = 0; | ||
| 1685 | if (strncpy_from_user(ncomm, (char __user *)arg2, | ||
| 1686 | sizeof(me->comm)-1) < 0) | ||
| 1687 | return -EFAULT; | 1768 | return -EFAULT; | 
| 1688 | set_task_comm(me, ncomm); | 1769 | set_task_comm(me, comm); | 
| 1689 | return 0; | 1770 | return 0; | 
| 1690 | } | 1771 | case PR_GET_NAME: | 
| 1691 | case PR_GET_NAME: { | 1772 | get_task_comm(comm, me); | 
| 1692 | struct task_struct *me = current; | 1773 | if (copy_to_user((char __user *)arg2, comm, | 
| 1693 | unsigned char tcomm[sizeof(me->comm)]; | 1774 | sizeof(comm))) | 
| 1694 | |||
| 1695 | get_task_comm(tcomm, me); | ||
| 1696 | if (copy_to_user((char __user *)arg2, tcomm, sizeof(tcomm))) | ||
| 1697 | return -EFAULT; | 1775 | return -EFAULT; | 
| 1698 | return 0; | 1776 | return 0; | 
| 1699 | } | ||
| 1700 | case PR_GET_ENDIAN: | 1777 | case PR_GET_ENDIAN: | 
| 1701 | error = GET_ENDIAN(current, arg2); | 1778 | error = GET_ENDIAN(me, arg2); | 
| 1702 | break; | 1779 | break; | 
| 1703 | case PR_SET_ENDIAN: | 1780 | case PR_SET_ENDIAN: | 
| 1704 | error = SET_ENDIAN(current, arg2); | 1781 | error = SET_ENDIAN(me, arg2); | 
| 1705 | break; | 1782 | break; | 
| 1706 | 1783 | ||
| 1707 | case PR_GET_SECCOMP: | 1784 | case PR_GET_SECCOMP: | 
| @@ -1725,6 +1802,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 1725 | current->default_timer_slack_ns; | 1802 | current->default_timer_slack_ns; | 
| 1726 | else | 1803 | else | 
| 1727 | current->timer_slack_ns = arg2; | 1804 | current->timer_slack_ns = arg2; | 
| 1805 | error = 0; | ||
| 1728 | break; | 1806 | break; | 
| 1729 | default: | 1807 | default: | 
| 1730 | error = -EINVAL; | 1808 | error = -EINVAL; | 
