aboutsummaryrefslogtreecommitdiffstats
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:23 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:23 -0500
commitd84f4f992cbd76e8f39c488cf0c5d123843923b1 (patch)
treefc4a0349c42995715b93d0f7a3c78e9ea9b3f36e /security/commoncap.c
parent745ca2475a6ac596e3d8d37c2759c0fbe2586227 (diff)
CRED: Inaugurate COW credentials
Inaugurate copy-on-write credentials management. This uses RCU to manage the credentials pointer in the task_struct with respect to accesses by other tasks. A process may only modify its own credentials, and so does not need locking to access or modify its own credentials. A mutex (cred_replace_mutex) is added to the task_struct to control the effect of PTRACE_ATTACHED on credential calculations, particularly with respect to execve(). With this patch, the contents of an active credentials struct may not be changed directly; rather a new set of credentials must be prepared, modified and committed using something like the following sequence of events: struct cred *new = prepare_creds(); int ret = blah(new); if (ret < 0) { abort_creds(new); return ret; } return commit_creds(new); There are some exceptions to this rule: the keyrings pointed to by the active credentials may be instantiated - keyrings violate the COW rule as managing COW keyrings is tricky, given that it is possible for a task to directly alter the keys in a keyring in use by another task. To help enforce this, various pointers to sets of credentials, such as those in the task_struct, are declared const. The purpose of this is compile-time discouragement of altering credentials through those pointers. Once a set of credentials has been made public through one of these pointers, it may not be modified, except under special circumstances: (1) Its reference count may incremented and decremented. (2) The keyrings to which it points may be modified, but not replaced. The only safe way to modify anything else is to create a replacement and commit using the functions described in Documentation/credentials.txt (which will be added by a later patch). This patch and the preceding patches have been tested with the LTP SELinux testsuite. This patch makes several logical sets of alteration: (1) execve(). This now prepares and commits credentials in various places in the security code rather than altering the current creds directly. (2) Temporary credential overrides. do_coredump() and sys_faccessat() now prepare their own credentials and temporarily override the ones currently on the acting thread, whilst preventing interference from other threads by holding cred_replace_mutex on the thread being dumped. This will be replaced in a future patch by something that hands down the credentials directly to the functions being called, rather than altering the task's objective credentials. (3) LSM interface. A number of functions have been changed, added or removed: (*) security_capset_check(), ->capset_check() (*) security_capset_set(), ->capset_set() Removed in favour of security_capset(). (*) security_capset(), ->capset() New. This is passed a pointer to the new creds, a pointer to the old creds and the proposed capability sets. It should fill in the new creds or return an error. All pointers, barring the pointer to the new creds, are now const. (*) security_bprm_apply_creds(), ->bprm_apply_creds() Changed; now returns a value, which will cause the process to be killed if it's an error. (*) security_task_alloc(), ->task_alloc_security() Removed in favour of security_prepare_creds(). (*) security_cred_free(), ->cred_free() New. Free security data attached to cred->security. (*) security_prepare_creds(), ->cred_prepare() New. Duplicate any security data attached to cred->security. (*) security_commit_creds(), ->cred_commit() New. Apply any security effects for the upcoming installation of new security by commit_creds(). (*) security_task_post_setuid(), ->task_post_setuid() Removed in favour of security_task_fix_setuid(). (*) security_task_fix_setuid(), ->task_fix_setuid() Fix up the proposed new credentials for setuid(). This is used by cap_set_fix_setuid() to implicitly adjust capabilities in line with setuid() changes. Changes are made to the new credentials, rather than the task itself as in security_task_post_setuid(). (*) security_task_reparent_to_init(), ->task_reparent_to_init() Removed. Instead the task being reparented to init is referred directly to init's credentials. NOTE! This results in the loss of some state: SELinux's osid no longer records the sid of the thread that forked it. (*) security_key_alloc(), ->key_alloc() (*) security_key_permission(), ->key_permission() Changed. These now take cred pointers rather than task pointers to refer to the security context. (4) sys_capset(). This has been simplified and uses less locking. The LSM functions it calls have been merged. (5) reparent_to_kthreadd(). This gives the current thread the same credentials as init by simply using commit_thread() to point that way. (6) __sigqueue_alloc() and switch_uid() __sigqueue_alloc() can't stop the target task from changing its creds beneath it, so this function gets a reference to the currently applicable user_struct which it then passes into the sigqueue struct it returns if successful. switch_uid() is now called from commit_creds(), and possibly should be folded into that. commit_creds() should take care of protecting __sigqueue_alloc(). (7) [sg]et[ug]id() and co and [sg]et_current_groups. The set functions now all use prepare_creds(), commit_creds() and abort_creds() to build and check a new set of credentials before applying it. security_task_set[ug]id() is called inside the prepared section. This guarantees that nothing else will affect the creds until we've finished. The calling of set_dumpable() has been moved into commit_creds(). Much of the functionality of set_user() has been moved into commit_creds(). The get functions all simply access the data directly. (8) security_task_prctl() and cap_task_prctl(). security_task_prctl() has been modified to return -ENOSYS if it doesn't want to handle a function, or otherwise return the return value directly rather than through an argument. Additionally, cap_task_prctl() now prepares a new set of credentials, even if it doesn't end up using it. (9) Keyrings. A number of changes have been made to the keyrings code: (a) switch_uid_keyring(), copy_keys(), exit_keys() and suid_keys() have all been dropped and built in to the credentials functions directly. They may want separating out again later. (b) key_alloc() and search_process_keyrings() now take a cred pointer rather than a task pointer to specify the security context. (c) copy_creds() gives a new thread within the same thread group a new thread keyring if its parent had one, otherwise it discards the thread keyring. (d) The authorisation key now points directly to the credentials to extend the search into rather pointing to the task that carries them. (e) Installing thread, process or session keyrings causes a new set of credentials to be created, even though it's not strictly necessary for process or session keyrings (they're shared). (10) Usermode helper. The usermode helper code now carries a cred struct pointer in its subprocess_info struct instead of a new session keyring pointer. This set of credentials is derived from init_cred and installed on the new process after it has been cloned. call_usermodehelper_setup() allocates the new credentials and call_usermodehelper_freeinfo() discards them if they haven't been used. A special cred function (prepare_usermodeinfo_creds()) is provided specifically for call_usermodehelper_setup() to call. call_usermodehelper_setkeys() adjusts the credentials to sport the supplied keyring as the new session keyring. (11) SELinux. SELinux has a number of changes, in addition to those to support the LSM interface changes mentioned above: (a) selinux_setprocattr() no longer does its check for whether the current ptracer can access processes with the new SID inside the lock that covers getting the ptracer's SID. Whilst this lock ensures that the check is done with the ptracer pinned, the result is only valid until the lock is released, so there's no point doing it inside the lock. (12) is_single_threaded(). This function has been extracted from selinux_setprocattr() and put into a file of its own in the lib/ directory as join_session_keyring() now wants to use it too. The code in SELinux just checked to see whether a task shared mm_structs with other tasks (CLONE_VM), but that isn't good enough. We really want to know if they're part of the same thread group (CLONE_THREAD). (13) nfsd. The NFS server daemon now has to use the COW credentials to set the credentials it is going to use. It really needs to pass the credentials down to the functions it calls, but it can't do that until other patches in this series have been applied. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c265
1 files changed, 125 insertions, 140 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 0384bf95db68..b5419273f92d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -72,8 +72,8 @@ int cap_ptrace_may_access(struct task_struct *child, unsigned int mode)
72 int ret = 0; 72 int ret = 0;
73 73
74 rcu_read_lock(); 74 rcu_read_lock();
75 if (!cap_issubset(child->cred->cap_permitted, 75 if (!cap_issubset(__task_cred(child)->cap_permitted,
76 current->cred->cap_permitted) && 76 current_cred()->cap_permitted) &&
77 !capable(CAP_SYS_PTRACE)) 77 !capable(CAP_SYS_PTRACE))
78 ret = -EPERM; 78 ret = -EPERM;
79 rcu_read_unlock(); 79 rcu_read_unlock();
@@ -85,8 +85,8 @@ int cap_ptrace_traceme(struct task_struct *parent)
85 int ret = 0; 85 int ret = 0;
86 86
87 rcu_read_lock(); 87 rcu_read_lock();
88 if (!cap_issubset(current->cred->cap_permitted, 88 if (!cap_issubset(current_cred()->cap_permitted,
89 parent->cred->cap_permitted) && 89 __task_cred(parent)->cap_permitted) &&
90 !has_capability(parent, CAP_SYS_PTRACE)) 90 !has_capability(parent, CAP_SYS_PTRACE))
91 ret = -EPERM; 91 ret = -EPERM;
92 rcu_read_unlock(); 92 rcu_read_unlock();
@@ -117,7 +117,7 @@ static inline int cap_inh_is_capped(void)
117 * to the old permitted set. That is, if the current task 117 * to the old permitted set. That is, if the current task
118 * does *not* possess the CAP_SETPCAP capability. 118 * does *not* possess the CAP_SETPCAP capability.
119 */ 119 */
120 return (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0); 120 return cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0;
121} 121}
122 122
123static inline int cap_limit_ptraced_target(void) { return 1; } 123static inline int cap_limit_ptraced_target(void) { return 1; }
@@ -132,52 +132,39 @@ static inline int cap_limit_ptraced_target(void)
132 132
133#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ 133#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
134 134
135int cap_capset_check(const kernel_cap_t *effective, 135int cap_capset(struct cred *new,
136 const kernel_cap_t *inheritable, 136 const struct cred *old,
137 const kernel_cap_t *permitted) 137 const kernel_cap_t *effective,
138 const kernel_cap_t *inheritable,
139 const kernel_cap_t *permitted)
138{ 140{
139 const struct cred *cred = current->cred; 141 if (cap_inh_is_capped() &&
140 142 !cap_issubset(*inheritable,
141 if (cap_inh_is_capped() 143 cap_combine(old->cap_inheritable,
142 && !cap_issubset(*inheritable, 144 old->cap_permitted)))
143 cap_combine(cred->cap_inheritable,
144 cred->cap_permitted))) {
145 /* incapable of using this inheritable set */ 145 /* incapable of using this inheritable set */
146 return -EPERM; 146 return -EPERM;
147 } 147
148 if (!cap_issubset(*inheritable, 148 if (!cap_issubset(*inheritable,
149 cap_combine(cred->cap_inheritable, 149 cap_combine(old->cap_inheritable,
150 cred->cap_bset))) { 150 old->cap_bset)))
151 /* no new pI capabilities outside bounding set */ 151 /* no new pI capabilities outside bounding set */
152 return -EPERM; 152 return -EPERM;
153 }
154 153
155 /* verify restrictions on target's new Permitted set */ 154 /* verify restrictions on target's new Permitted set */
156 if (!cap_issubset (*permitted, 155 if (!cap_issubset(*permitted, old->cap_permitted))
157 cap_combine (cred->cap_permitted,
158 cred->cap_permitted))) {
159 return -EPERM; 156 return -EPERM;
160 }
161 157
162 /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ 158 /* verify the _new_Effective_ is a subset of the _new_Permitted_ */
163 if (!cap_issubset (*effective, *permitted)) { 159 if (!cap_issubset(*effective, *permitted))
164 return -EPERM; 160 return -EPERM;
165 }
166 161
162 new->cap_effective = *effective;
163 new->cap_inheritable = *inheritable;
164 new->cap_permitted = *permitted;
167 return 0; 165 return 0;
168} 166}
169 167
170void cap_capset_set(const kernel_cap_t *effective,
171 const kernel_cap_t *inheritable,
172 const kernel_cap_t *permitted)
173{
174 struct cred *cred = current->cred;
175
176 cred->cap_effective = *effective;
177 cred->cap_inheritable = *inheritable;
178 cred->cap_permitted = *permitted;
179}
180
181static inline void bprm_clear_caps(struct linux_binprm *bprm) 168static inline void bprm_clear_caps(struct linux_binprm *bprm)
182{ 169{
183 cap_clear(bprm->cap_post_exec_permitted); 170 cap_clear(bprm->cap_post_exec_permitted);
@@ -382,41 +369,46 @@ int cap_bprm_set_security (struct linux_binprm *bprm)
382 return ret; 369 return ret;
383} 370}
384 371
385void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) 372int cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
386{ 373{
387 struct cred *cred = current->cred; 374 const struct cred *old = current_cred();
375 struct cred *new;
376
377 new = prepare_creds();
378 if (!new)
379 return -ENOMEM;
388 380
389 if (bprm->e_uid != cred->uid || bprm->e_gid != cred->gid || 381 if (bprm->e_uid != old->uid || bprm->e_gid != old->gid ||
390 !cap_issubset(bprm->cap_post_exec_permitted, 382 !cap_issubset(bprm->cap_post_exec_permitted,
391 cred->cap_permitted)) { 383 old->cap_permitted)) {
392 set_dumpable(current->mm, suid_dumpable); 384 set_dumpable(current->mm, suid_dumpable);
393 current->pdeath_signal = 0; 385 current->pdeath_signal = 0;
394 386
395 if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { 387 if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
396 if (!capable(CAP_SETUID)) { 388 if (!capable(CAP_SETUID)) {
397 bprm->e_uid = cred->uid; 389 bprm->e_uid = old->uid;
398 bprm->e_gid = cred->gid; 390 bprm->e_gid = old->gid;
399 } 391 }
400 if (cap_limit_ptraced_target()) { 392 if (cap_limit_ptraced_target()) {
401 bprm->cap_post_exec_permitted = cap_intersect( 393 bprm->cap_post_exec_permitted = cap_intersect(
402 bprm->cap_post_exec_permitted, 394 bprm->cap_post_exec_permitted,
403 cred->cap_permitted); 395 new->cap_permitted);
404 } 396 }
405 } 397 }
406 } 398 }
407 399
408 cred->suid = cred->euid = cred->fsuid = bprm->e_uid; 400 new->suid = new->euid = new->fsuid = bprm->e_uid;
409 cred->sgid = cred->egid = cred->fsgid = bprm->e_gid; 401 new->sgid = new->egid = new->fsgid = bprm->e_gid;
410 402
411 /* For init, we want to retain the capabilities set 403 /* For init, we want to retain the capabilities set
412 * in the init_task struct. Thus we skip the usual 404 * in the init_task struct. Thus we skip the usual
413 * capability rules */ 405 * capability rules */
414 if (!is_global_init(current)) { 406 if (!is_global_init(current)) {
415 cred->cap_permitted = bprm->cap_post_exec_permitted; 407 new->cap_permitted = bprm->cap_post_exec_permitted;
416 if (bprm->cap_effective) 408 if (bprm->cap_effective)
417 cred->cap_effective = bprm->cap_post_exec_permitted; 409 new->cap_effective = bprm->cap_post_exec_permitted;
418 else 410 else
419 cap_clear(cred->cap_effective); 411 cap_clear(new->cap_effective);
420 } 412 }
421 413
422 /* 414 /*
@@ -431,15 +423,15 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
431 * Number 1 above might fail if you don't have a full bset, but I think 423 * Number 1 above might fail if you don't have a full bset, but I think
432 * that is interesting information to audit. 424 * that is interesting information to audit.
433 */ 425 */
434 if (!cap_isclear(cred->cap_effective)) { 426 if (!cap_isclear(new->cap_effective)) {
435 if (!cap_issubset(CAP_FULL_SET, cred->cap_effective) || 427 if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
436 (bprm->e_uid != 0) || (cred->uid != 0) || 428 bprm->e_uid != 0 || new->uid != 0 ||
437 issecure(SECURE_NOROOT)) 429 issecure(SECURE_NOROOT))
438 audit_log_bprm_fcaps(bprm, &cred->cap_permitted, 430 audit_log_bprm_fcaps(bprm, new, old);
439 &cred->cap_effective);
440 } 431 }
441 432
442 cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); 433 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
434 return commit_creds(new);
443} 435}
444 436
445int cap_bprm_secureexec (struct linux_binprm *bprm) 437int cap_bprm_secureexec (struct linux_binprm *bprm)
@@ -514,65 +506,49 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
514 * files.. 506 * files..
515 * Thanks to Olaf Kirch and Peter Benie for spotting this. 507 * Thanks to Olaf Kirch and Peter Benie for spotting this.
516 */ 508 */
517static inline void cap_emulate_setxuid (int old_ruid, int old_euid, 509static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
518 int old_suid)
519{ 510{
520 struct cred *cred = current->cred; 511 if ((old->uid == 0 || old->euid == 0 || old->suid == 0) &&
521 512 (new->uid != 0 && new->euid != 0 && new->suid != 0) &&
522 if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
523 (cred->uid != 0 && cred->euid != 0 && cred->suid != 0) &&
524 !issecure(SECURE_KEEP_CAPS)) { 513 !issecure(SECURE_KEEP_CAPS)) {
525 cap_clear(cred->cap_permitted); 514 cap_clear(new->cap_permitted);
526 cap_clear(cred->cap_effective); 515 cap_clear(new->cap_effective);
527 }
528 if (old_euid == 0 && cred->euid != 0) {
529 cap_clear(cred->cap_effective);
530 }
531 if (old_euid != 0 && cred->euid == 0) {
532 cred->cap_effective = cred->cap_permitted;
533 } 516 }
517 if (old->euid == 0 && new->euid != 0)
518 cap_clear(new->cap_effective);
519 if (old->euid != 0 && new->euid == 0)
520 new->cap_effective = new->cap_permitted;
534} 521}
535 522
536int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, 523int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
537 int flags)
538{ 524{
539 struct cred *cred = current->cred;
540
541 switch (flags) { 525 switch (flags) {
542 case LSM_SETID_RE: 526 case LSM_SETID_RE:
543 case LSM_SETID_ID: 527 case LSM_SETID_ID:
544 case LSM_SETID_RES: 528 case LSM_SETID_RES:
545 /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */ 529 /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
546 if (!issecure (SECURE_NO_SETUID_FIXUP)) { 530 if (!issecure(SECURE_NO_SETUID_FIXUP))
547 cap_emulate_setxuid (old_ruid, old_euid, old_suid); 531 cap_emulate_setxuid(new, old);
548 }
549 break; 532 break;
550 case LSM_SETID_FS: 533 case LSM_SETID_FS:
551 { 534 /* Copied from kernel/sys.c:setfsuid. */
552 uid_t old_fsuid = old_ruid;
553
554 /* Copied from kernel/sys.c:setfsuid. */
555 535
556 /* 536 /*
557 * FIXME - is fsuser used for all CAP_FS_MASK capabilities? 537 * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
558 * if not, we might be a bit too harsh here. 538 * if not, we might be a bit too harsh here.
559 */ 539 */
560 540 if (!issecure(SECURE_NO_SETUID_FIXUP)) {
561 if (!issecure (SECURE_NO_SETUID_FIXUP)) { 541 if (old->fsuid == 0 && new->fsuid != 0) {
562 if (old_fsuid == 0 && cred->fsuid != 0) { 542 new->cap_effective =
563 cred->cap_effective = 543 cap_drop_fs_set(new->cap_effective);
564 cap_drop_fs_set( 544 }
565 cred->cap_effective); 545 if (old->fsuid != 0 && new->fsuid == 0) {
566 } 546 new->cap_effective =
567 if (old_fsuid != 0 && cred->fsuid == 0) { 547 cap_raise_fs_set(new->cap_effective,
568 cred->cap_effective = 548 new->cap_permitted);
569 cap_raise_fs_set(
570 cred->cap_effective,
571 cred->cap_permitted);
572 }
573 } 549 }
574 break;
575 } 550 }
551 break;
576 default: 552 default:
577 return -EINVAL; 553 return -EINVAL;
578 } 554 }
@@ -628,13 +604,14 @@ int cap_task_setnice (struct task_struct *p, int nice)
628 * this task could get inconsistent info. There can be no 604 * this task could get inconsistent info. There can be no
629 * racing writer bc a task can only change its own caps. 605 * racing writer bc a task can only change its own caps.
630 */ 606 */
631static long cap_prctl_drop(unsigned long cap) 607static long cap_prctl_drop(struct cred *new, unsigned long cap)
632{ 608{
633 if (!capable(CAP_SETPCAP)) 609 if (!capable(CAP_SETPCAP))
634 return -EPERM; 610 return -EPERM;
635 if (!cap_valid(cap)) 611 if (!cap_valid(cap))
636 return -EINVAL; 612 return -EINVAL;
637 cap_lower(current->cred->cap_bset, cap); 613
614 cap_lower(new->cap_bset, cap);
638 return 0; 615 return 0;
639} 616}
640 617
@@ -655,22 +632,29 @@ int cap_task_setnice (struct task_struct *p, int nice)
655#endif 632#endif
656 633
657int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, 634int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
658 unsigned long arg4, unsigned long arg5, long *rc_p) 635 unsigned long arg4, unsigned long arg5)
659{ 636{
660 struct cred *cred = current_cred(); 637 struct cred *new;
661 long error = 0; 638 long error = 0;
662 639
640 new = prepare_creds();
641 if (!new)
642 return -ENOMEM;
643
663 switch (option) { 644 switch (option) {
664 case PR_CAPBSET_READ: 645 case PR_CAPBSET_READ:
646 error = -EINVAL;
665 if (!cap_valid(arg2)) 647 if (!cap_valid(arg2))
666 error = -EINVAL; 648 goto error;
667 else 649 error = !!cap_raised(new->cap_bset, arg2);
668 error = !!cap_raised(cred->cap_bset, arg2); 650 goto no_change;
669 break; 651
670#ifdef CONFIG_SECURITY_FILE_CAPABILITIES 652#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
671 case PR_CAPBSET_DROP: 653 case PR_CAPBSET_DROP:
672 error = cap_prctl_drop(arg2); 654 error = cap_prctl_drop(new, arg2);
673 break; 655 if (error < 0)
656 goto error;
657 goto changed;
674 658
675 /* 659 /*
676 * The next four prctl's remain to assist with transitioning a 660 * The next four prctl's remain to assist with transitioning a
@@ -692,12 +676,12 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
692 * capability-based-privilege environment. 676 * capability-based-privilege environment.
693 */ 677 */
694 case PR_SET_SECUREBITS: 678 case PR_SET_SECUREBITS:
695 if ((((cred->securebits & SECURE_ALL_LOCKS) >> 1) 679 error = -EPERM;
696 & (cred->securebits ^ arg2)) /*[1]*/ 680 if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
697 || ((cred->securebits & SECURE_ALL_LOCKS 681 & (new->securebits ^ arg2)) /*[1]*/
698 & ~arg2)) /*[2]*/ 682 || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
699 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ 683 || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
700 || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0)) { /*[4]*/ 684 || (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/
701 /* 685 /*
702 * [1] no changing of bits that are locked 686 * [1] no changing of bits that are locked
703 * [2] no unlocking of locks 687 * [2] no unlocking of locks
@@ -705,50 +689,51 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
705 * [4] doing anything requires privilege (go read about 689 * [4] doing anything requires privilege (go read about
706 * the "sendmail capabilities bug") 690 * the "sendmail capabilities bug")
707 */ 691 */
708 error = -EPERM; /* cannot change a locked bit */ 692 )
709 } else { 693 /* cannot change a locked bit */
710 cred->securebits = arg2; 694 goto error;
711 } 695 new->securebits = arg2;
712 break; 696 goto changed;
697
713 case PR_GET_SECUREBITS: 698 case PR_GET_SECUREBITS:
714 error = cred->securebits; 699 error = new->securebits;
715 break; 700 goto no_change;
716 701
717#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */ 702#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
718 703
719 case PR_GET_KEEPCAPS: 704 case PR_GET_KEEPCAPS:
720 if (issecure(SECURE_KEEP_CAPS)) 705 if (issecure(SECURE_KEEP_CAPS))
721 error = 1; 706 error = 1;
722 break; 707 goto no_change;
708
723 case PR_SET_KEEPCAPS: 709 case PR_SET_KEEPCAPS:
710 error = -EINVAL;
724 if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ 711 if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
725 error = -EINVAL; 712 goto error;
726 else if (issecure(SECURE_KEEP_CAPS_LOCKED)) 713 error = -EPERM;
727 error = -EPERM; 714 if (issecure(SECURE_KEEP_CAPS_LOCKED))
728 else if (arg2) 715 goto error;
729 cred->securebits |= issecure_mask(SECURE_KEEP_CAPS); 716 if (arg2)
717 new->securebits |= issecure_mask(SECURE_KEEP_CAPS);
730 else 718 else
731 cred->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); 719 new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
732 break; 720 goto changed;
733 721
734 default: 722 default:
735 /* No functionality available - continue with default */ 723 /* No functionality available - continue with default */
736 return 0; 724 error = -ENOSYS;
725 goto error;
737 } 726 }
738 727
739 /* Functionality provided */ 728 /* Functionality provided */
740 *rc_p = error; 729changed:
741 return 1; 730 return commit_creds(new);
742} 731
743 732no_change:
744void cap_task_reparent_to_init (struct task_struct *p) 733 error = 0;
745{ 734error:
746 struct cred *cred = p->cred; 735 abort_creds(new);
747 736 return error;
748 cap_set_init_eff(cred->cap_effective);
749 cap_clear(cred->cap_inheritable);
750 cap_set_full(cred->cap_permitted);
751 p->cred->securebits = SECUREBITS_DEFAULT;
752} 737}
753 738
754int cap_syslog (int type) 739int cap_syslog (int type)