--- sys.c Fri Aug 30 18:42:20 2002 +++ /tmp/sys.c Wed Sep 4 20:12:51 2002 @@ -450,7 +450,7 @@ * * 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. + * cleared with the exception case related to fsuid. See below. * * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective * capabilities of the process are cleared. @@ -472,6 +472,15 @@ * 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. + * + * Change: + * Invariant fsuid =0 iff one of the {r,e,s}uid == 0 is no more valid. + * So rule 1 should be modified as + * 4) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of + * {r,e,s}uid != 0, the file system permitted and effective + * capabilities are cleared based on the value of fsuid != 0, + * and other effective and permitted capabilties will be cleared + * regardless of the value of fsuid. */ static inline void cap_emulate_setxuid(int old_ruid, int old_euid, int old_suid) @@ -479,8 +488,14 @@ 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 (current->fsuid != 0) { + cap_clear(current->cap_permitted); + cap_clear(current->cap_effective); + } + else { + cap_t(current->cap_effective) &= CAP_FS_MASK; + cap_t(current->cap_permitted) &= CAP_FS_MASK; + } } if (old_euid == 0 && current->euid != 0) { cap_clear(current->cap_effective);