aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorZhi Li <lizhi1215@gmail.com>2011-08-11 01:27:50 -0400
committerJames Morris <jmorris@namei.org>2011-08-12 01:06:57 -0400
commit4d49f6710bfbd2271feab074f8c1053387e5d9fe (patch)
tree87a508aa2a51d2d855c3b67961a711bd636d842c /security
parentf995e74087402c482c55c29bf11da8bcf631245a (diff)
capabilities: do not grant full privs for setuid w/ file caps + no effective caps
A task (when !SECURE_NOROOT) which executes a setuid-root binary will obtain root privileges while executing that binary. If the binary also has effective capabilities set, then only those capabilities will be granted. The rationale is that the same binary can carry both setuid-root and the minimal file capability set, so that on a filesystem not supporting file caps the binary can still be executed with privilege, while on a filesystem supporting file caps it will run with minimal privilege. This special case currently does NOT happen if there are file capabilities but no effective capabilities. Since capability-aware programs can very well start with empty pE but populated pP and move those caps to pE when needed. In other words, if the file has file capabilities but NOT effective capabilities, then we should do the same thing as if there were file capabilities, and not grant full root privileges. This patchset does that. (Changelog by Serge Hallyn). Signed-off-by: Zhi Li <lizhi1215@gmail.com> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
-rw-r--r--security/commoncap.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index a93b3b73307..0f620c564fa 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -332,7 +332,8 @@ int cap_inode_killpriv(struct dentry *dentry)
332 */ 332 */
333static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, 333static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
334 struct linux_binprm *bprm, 334 struct linux_binprm *bprm,
335 bool *effective) 335 bool *effective,
336 bool *has_cap)
336{ 337{
337 struct cred *new = bprm->cred; 338 struct cred *new = bprm->cred;
338 unsigned i; 339 unsigned i;
@@ -341,6 +342,9 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
341 if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE) 342 if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
342 *effective = true; 343 *effective = true;
343 344
345 if (caps->magic_etc & VFS_CAP_REVISION_MASK)
346 *has_cap = true;
347
344 CAP_FOR_EACH_U32(i) { 348 CAP_FOR_EACH_U32(i) {
345 __u32 permitted = caps->permitted.cap[i]; 349 __u32 permitted = caps->permitted.cap[i];
346 __u32 inheritable = caps->inheritable.cap[i]; 350 __u32 inheritable = caps->inheritable.cap[i];
@@ -424,7 +428,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
424 * its xattrs and, if present, apply them to the proposed credentials being 428 * its xattrs and, if present, apply them to the proposed credentials being
425 * constructed by execve(). 429 * constructed by execve().
426 */ 430 */
427static int get_file_caps(struct linux_binprm *bprm, bool *effective) 431static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap)
428{ 432{
429 struct dentry *dentry; 433 struct dentry *dentry;
430 int rc = 0; 434 int rc = 0;
@@ -450,7 +454,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
450 goto out; 454 goto out;
451 } 455 }
452 456
453 rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective); 457 rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap);
454 if (rc == -EINVAL) 458 if (rc == -EINVAL)
455 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", 459 printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
456 __func__, rc, bprm->filename); 460 __func__, rc, bprm->filename);
@@ -475,11 +479,11 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
475{ 479{
476 const struct cred *old = current_cred(); 480 const struct cred *old = current_cred();
477 struct cred *new = bprm->cred; 481 struct cred *new = bprm->cred;
478 bool effective; 482 bool effective, has_cap;
479 int ret; 483 int ret;
480 484
481 effective = false; 485 effective = false;
482 ret = get_file_caps(bprm, &effective); 486 ret = get_file_caps(bprm, &effective, &has_cap);
483 if (ret < 0) 487 if (ret < 0)
484 return ret; 488 return ret;
485 489
@@ -489,7 +493,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
489 * for a setuid root binary run by a non-root user. Do set it 493 * for a setuid root binary run by a non-root user. Do set it
490 * for a root user just to cause least surprise to an admin. 494 * for a root user just to cause least surprise to an admin.
491 */ 495 */
492 if (effective && new->uid != 0 && new->euid == 0) { 496 if (has_cap && new->uid != 0 && new->euid == 0) {
493 warn_setuid_and_fcaps_mixed(bprm->filename); 497 warn_setuid_and_fcaps_mixed(bprm->filename);
494 goto skip; 498 goto skip;
495 } 499 }