Here is a small patch relative to my previous capabilities patch that moves the capability-specific hacks from the set*uid calls to a new post_setuid hook. -- Stephen D. Smalley, NAI Labs ssmalleyat_private Index: include/linux/security.h =================================================================== RCS file: /cvs/lsm/lsm-new/include/linux/security.h,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- include/linux/security.h 2001/06/19 20:31:46 1.12 +++ include/linux/security.h 2001/06/19 20:37:17 1.13 @@ -108,6 +108,7 @@ #define LSM_SETID_RES 4 /* setresuid or setresgid, id0 == real, id1 == eff, uid2 == saved */ #define LSM_SETID_FS 8 /* setfsuid or setfsgid, id0 == fsuid or fsgid */ int (* setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); + int (* post_setuid) (uid_t old_ruid /* or fsuid */, uid_t old_euid, uid_t old_suid, int flags); int (* setgid) (gid_t id0, gid_t id1, gid_t id2, int flags); int (* setgroups) (int gidsetsize, gid_t *grouplist); int (* setnice) (struct task_struct *p, int nice); Index: kernel/capability_plug.c =================================================================== RCS file: /cvs/lsm/lsm-new/kernel/capability_plug.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- kernel/capability_plug.c 2001/06/19 20:35:03 1.2 +++ kernel/capability_plug.c 2001/06/19 20:37:17 1.3 @@ -189,6 +189,94 @@ static int cap_task_alloc_security (struct task_struct *p) {return 0;} static void cap_task_free_security (struct task_struct *p) {return;} static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; } + +/* Copied from kernel/sys.c. */ +/* + * cap_emulate_setxuid() fixes the effective / permitted capabilities of + * a process after a call to setuid, setreuid, or setresuid. + * + * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of + * {r,e,s}uid != 0, the permitted and effective capabilities are + * cleared. + * + * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective + * capabilities of the process are cleared. + * + * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective + * capabilities are set to the permitted capabilities. + * + * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should + * never happen. + * + * -astor + * + * cevans - New behaviour, Oct '99 + * A process may, via prctl(), elect to keep its capabilities when it + * calls setuid() and switches away from uid==0. Both permitted and + * effective sets will be retained. + * Without this change, it was impossible for a daemon to drop only some + * of its privilege. The call to setuid(!=0) would drop all privileges! + * Keeping uid 0 is not an option because uid 0 owns too many vital + * files.. + * Thanks to Olaf Kirch and Peter Benie for spotting this. + */ +extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, + int old_suid) +{ + if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && + (current->uid != 0 && current->euid != 0 && current->suid != 0) && + !current->keep_capabilities) { + cap_clear(current->cap_permitted); + cap_clear(current->cap_effective); + } + if (old_euid == 0 && current->euid != 0) { + cap_clear(current->cap_effective); + } + if (old_euid != 0 && current->euid == 0) { + current->cap_effective = current->cap_permitted; + } +} + +static int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags) +{ + switch (flags) { + case LSM_SETID_RE: + case LSM_SETID_ID: + case LSM_SETID_RES: + /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */ + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + cap_emulate_setxuid(old_ruid, old_euid, old_suid); + } + break; + case LSM_SETID_FS: + { + uid_t old_fsuid = old_ruid; + + /* Copied from kernel/sys.c:setfsuid. */ + + /* + * FIXME - is fsuser used for all CAP_FS_MASK capabilities? + * if not, we might be a bit too harsh here. + */ + + if (!issecure(SECURE_NO_SETUID_FIXUP)) { + if (old_fsuid == 0 && current->fsuid != 0) { + cap_t(current->cap_effective) &= ~CAP_FS_MASK; + } + if (old_fsuid != 0 && current->fsuid == 0) { + cap_t(current->cap_effective) |= + (cap_t(current->cap_permitted) & CAP_FS_MASK); + } + } + break; + } + default: + return -EINVAL; + } + + return 0; +} + static int cap_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) { return 0; } static int cap_task_setgroups(int gidsetsize, gid_t *grouplist) { return 0; } static int cap_task_setnice(struct task_struct *p, int nice) { return 0; } @@ -298,6 +386,7 @@ alloc_security: cap_task_alloc_security, free_security: cap_task_free_security, setuid: cap_task_setuid, + post_setuid: cap_task_post_setuid, setgid: cap_task_setgid, setgroups: cap_task_setgroups, setnice: cap_task_setnice, Index: kernel/security.c =================================================================== RCS file: /cvs/lsm/lsm-new/kernel/security.c,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- kernel/security.c 2001/06/19 20:31:46 1.12 +++ kernel/security.c 2001/06/19 20:37:17 1.13 @@ -117,6 +117,7 @@ static int dummy_task_alloc_security (struct task_struct *p) {return 0;} static void dummy_task_free_security (struct task_struct *p) {return;} static int dummy_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; } +static int dummy_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; } static int dummy_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) { return 0; } static int dummy_task_setgroups(int gidsetsize, gid_t *grouplist) { return 0; } static int dummy_task_setnice(struct task_struct *p, int nice) { return 0; } @@ -221,6 +222,7 @@ alloc_security: dummy_task_alloc_security, free_security: dummy_task_free_security, setuid: dummy_task_setuid, + post_setuid: dummy_task_post_setuid, setgid: dummy_task_setgid, setgroups: dummy_task_setgroups, setnice: dummy_task_setnice, Index: kernel/sys.c =================================================================== RCS file: /cvs/lsm/lsm-new/kernel/sys.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- kernel/sys.c 2001/06/18 17:22:05 1.4 +++ kernel/sys.c 2001/06/19 20:37:17 1.5 @@ -466,52 +466,6 @@ return 0; } -/* - * cap_emulate_setxuid() fixes the effective / permitted capabilities of - * a process after a call to setuid, setreuid, or setresuid. - * - * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of - * {r,e,s}uid != 0, the permitted and effective capabilities are - * cleared. - * - * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective - * capabilities of the process are cleared. - * - * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective - * capabilities are set to the permitted capabilities. - * - * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should - * never happen. - * - * -astor - * - * cevans - New behaviour, Oct '99 - * A process may, via prctl(), elect to keep its capabilities when it - * calls setuid() and switches away from uid==0. Both permitted and - * effective sets will be retained. - * Without this change, it was impossible for a daemon to drop only some - * of its privilege. The call to setuid(!=0) would drop all privileges! - * Keeping uid 0 is not an option because uid 0 owns too many vital - * files.. - * Thanks to Olaf Kirch and Peter Benie for spotting this. - */ -extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, - int old_suid) -{ - if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) && - (current->uid != 0 && current->euid != 0 && current->suid != 0) && - !current->keep_capabilities) { - cap_clear(current->cap_permitted); - cap_clear(current->cap_effective); - } - if (old_euid == 0 && current->euid != 0) { - cap_clear(current->cap_effective); - } - if (old_euid != 0 && current->euid == 0) { - current->cap_effective = current->cap_permitted; - } -} - static int set_user(uid_t new_ruid, int dumpclear) { struct user_struct *new_user, *old_user; @@ -597,12 +551,8 @@ (euid != (uid_t) -1 && euid != old_ruid)) current->suid = current->euid; current->fsuid = current->euid; - - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - cap_emulate_setxuid(old_ruid, old_euid, old_suid); - } - return 0; + return security_ops->task_ops->post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); } @@ -646,12 +596,8 @@ } current->fsuid = current->euid = uid; current->suid = new_suid; - - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - cap_emulate_setxuid(old_ruid, old_euid, old_suid); - } - return 0; + return security_ops->task_ops->post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); } @@ -697,11 +643,7 @@ if (suid != (uid_t) -1) current->suid = suid; - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - cap_emulate_setxuid(old_ruid, old_euid, old_suid); - } - - return 0; + return security_ops->task_ops->post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); } asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) @@ -793,24 +735,9 @@ current->fsuid = uid; } - /* We emulate fsuid by essentially doing a scaled-down version - * of what we did in setresuid and friends. However, we only - * operate on the fs-specific bits of the process' effective - * capabilities - * - * FIXME - is fsuser used for all CAP_FS_MASK capabilities? - * if not, we might be a bit too harsh here. - */ - - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - if (old_fsuid == 0 && current->fsuid != 0) { - cap_t(current->cap_effective) &= ~CAP_FS_MASK; - } - if (old_fsuid != 0 && current->fsuid == 0) { - cap_t(current->cap_effective) |= - (cap_t(current->cap_permitted) & CAP_FS_MASK); - } - } + retval = security_ops->task_ops->post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); + if (retval) + return retval; return old_fsuid; } _______________________________________________ linux-security-module mailing list linux-security-moduleat_private http://mail.wirex.com/mailman/listinfo/linux-security-module
This archive was generated by hypermail 2b30 : Tue Jun 19 2001 - 13:50:26 PDT