X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=security%2Fselinux%2Fhooks.c;h=2e8b4dfcbc743d4b2394085043f35793780ef1dc;hb=7b69a4c360e8787877ebf5e42609b8bab13afa6a;hp=51bec4c88f19fd020b9fd7f3f1a0556069c907d3;hpb=3e8d6ad9bf1f02fdb9fd119c3c266d4b73b7175d;p=pandora-kernel.git diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 51bec4c88f19..2e8b4dfcbc74 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -18,7 +18,6 @@ * as published by the Free Software Foundation. */ -#include #include #include #include @@ -247,6 +246,7 @@ static int superblock_alloc_security(struct super_block *sb) sbsec->sb = sb; sbsec->sid = SECINITSID_UNLABELED; sbsec->def_sid = SECINITSID_FILE; + sbsec->mntpoint_sid = SECINITSID_UNLABELED; sb->s_security = sbsec; return 0; @@ -320,19 +320,53 @@ enum { Opt_context = 1, Opt_fscontext = 2, Opt_defcontext = 4, + Opt_rootcontext = 8, }; static match_table_t tokens = { {Opt_context, "context=%s"}, {Opt_fscontext, "fscontext=%s"}, {Opt_defcontext, "defcontext=%s"}, + {Opt_rootcontext, "rootcontext=%s"}, }; #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" +static int may_context_mount_sb_relabel(u32 sid, + struct superblock_security_struct *sbsec, + struct task_security_struct *tsec) +{ + int rc; + + rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + FILESYSTEM__RELABELFROM, NULL); + if (rc) + return rc; + + rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, + FILESYSTEM__RELABELTO, NULL); + return rc; +} + +static int may_context_mount_inode_relabel(u32 sid, + struct superblock_security_struct *sbsec, + struct task_security_struct *tsec) +{ + int rc; + rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, + FILESYSTEM__RELABELFROM, NULL); + if (rc) + return rc; + + rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, + FILESYSTEM__ASSOCIATE, NULL); + return rc; +} + static int try_context_mount(struct super_block *sb, void *data) { char *context = NULL, *defcontext = NULL; + char *fscontext = NULL, *rootcontext = NULL; const char *name; u32 sid; int alloc = 0, rc = 0, seen = 0; @@ -375,7 +409,7 @@ static int try_context_mount(struct super_block *sb, void *data) switch (token) { case Opt_context: - if (seen) { + if (seen & (Opt_context|Opt_defcontext)) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; @@ -391,13 +425,13 @@ static int try_context_mount(struct super_block *sb, void *data) break; case Opt_fscontext: - if (seen & (Opt_context|Opt_fscontext)) { + if (seen & Opt_fscontext) { rc = -EINVAL; printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); goto out_free; } - context = match_strdup(&args[0]); - if (!context) { + fscontext = match_strdup(&args[0]); + if (!fscontext) { rc = -ENOMEM; goto out_free; } @@ -406,6 +440,22 @@ static int try_context_mount(struct super_block *sb, void *data) seen |= Opt_fscontext; break; + case Opt_rootcontext: + if (seen & Opt_rootcontext) { + rc = -EINVAL; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_free; + } + rootcontext = match_strdup(&args[0]); + if (!rootcontext) { + rc = -ENOMEM; + goto out_free; + } + if (!alloc) + alloc = 1; + seen |= Opt_rootcontext; + break; + case Opt_defcontext: if (sbsec->behavior != SECURITY_FS_USE_XATTR) { rc = -EINVAL; @@ -442,6 +492,28 @@ static int try_context_mount(struct super_block *sb, void *data) if (!seen) goto out; + /* sets the context of the superblock for the fs being mounted. */ + if (fscontext) { + rc = security_context_to_sid(fscontext, strlen(fscontext), &sid); + if (rc) { + printk(KERN_WARNING "SELinux: security_context_to_sid" + "(%s) failed for (dev %s, type %s) errno=%d\n", + fscontext, sb->s_id, name, rc); + goto out_free; + } + + rc = may_context_mount_sb_relabel(sid, sbsec, tsec); + if (rc) + goto out_free; + + sbsec->sid = sid; + } + + /* + * Switch to using mount point labeling behavior. + * sets the label used on all file below the mountpoint, and will set + * the superblock context if not already set. + */ if (context) { rc = security_context_to_sid(context, strlen(context), &sid); if (rc) { @@ -451,20 +523,34 @@ static int try_context_mount(struct super_block *sb, void *data) goto out_free; } - rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, - FILESYSTEM__RELABELFROM, NULL); + rc = may_context_mount_sb_relabel(sid, sbsec, tsec); if (rc) goto out_free; - rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, - FILESYSTEM__RELABELTO, NULL); - if (rc) + if (!fscontext) + sbsec->sid = sid; + sbsec->mntpoint_sid = sid; + + sbsec->behavior = SECURITY_FS_USE_MNTPOINT; + } + + if (rootcontext) { + struct inode *inode = sb->s_root->d_inode; + struct inode_security_struct *isec = inode->i_security; + rc = security_context_to_sid(rootcontext, strlen(rootcontext), &sid); + if (rc) { + printk(KERN_WARNING "SELinux: security_context_to_sid" + "(%s) failed for (dev %s, type %s) errno=%d\n", + rootcontext, sb->s_id, name, rc); goto out_free; + } - sbsec->sid = sid; + rc = may_context_mount_inode_relabel(sid, sbsec, tsec); + if (rc) + goto out_free; - if (seen & Opt_context) - sbsec->behavior = SECURITY_FS_USE_MNTPOINT; + isec->sid = sid; + isec->initialized = 1; } if (defcontext) { @@ -479,13 +565,7 @@ static int try_context_mount(struct super_block *sb, void *data) if (sid == sbsec->def_sid) goto out_free; - rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, - FILESYSTEM__RELABELFROM, NULL); - if (rc) - goto out_free; - - rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, - FILESYSTEM__ASSOCIATE, NULL); + rc = may_context_mount_inode_relabel(sid, sbsec, tsec); if (rc) goto out_free; @@ -496,6 +576,8 @@ out_free: if (alloc) { kfree(context); kfree(defcontext); + kfree(fscontext); + kfree(rootcontext); } out: return rc; @@ -877,8 +959,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent goto out; isec->sid = sid; break; + case SECURITY_FS_USE_MNTPOINT: + isec->sid = sbsec->mntpoint_sid; + break; default: - /* Default to the fs SID. */ + /* Default to the fs superblock SID. */ isec->sid = sbsec->sid; if (sbsec->proc) { @@ -1844,7 +1929,8 @@ static inline int selinux_option(char *option, int len) { return (match_prefix("context=", sizeof("context=")-1, option, len) || match_prefix("fscontext=", sizeof("fscontext=")-1, option, len) || - match_prefix("defcontext=", sizeof("defcontext=")-1, option, len)); + match_prefix("defcontext=", sizeof("defcontext=")-1, option, len) || + match_prefix("rootcontext=", sizeof("rootcontext=")-1, option, len)); } static inline void take_option(char **to, char *from, int *first, int len)