SELinux: Add get, set, and cloning of superblock security information
Subsystems (2)
PATCH 1/1 SELinux: Add get, set, and cloning of superblock security information
Adds security_get_sb_mnt_opts, security_set_sb_mnt_opts, and security_clont_sb_mnt_opts to the LSM and to SELinux. This will allow filesystems to directly own and control all of their mount options if they so choose.
---
include/linux/security.h | 36 ++ security/dummy.c | 26 ++ security/security.c | 20 + security/selinux/hooks.c | 749 ++++++++++++++++++++++++------------- security/selinux/include/objsec.h | 1 + 5 files changed, 578 insertions(+), 254 deletions(-)
include/linux/security.h +36 -0
@@ -34,6 +34,12 @@#include <linux/xfrm.h> #include <net/flow.h> +/* only a char in selinux superblock security struct flags */ +#define FSCONTEXT_MNT 0x01 +#define CONTEXT_MNT 0x02 +#define ROOTCONTEXT_MNT 0x04 +#define DEFCONTEXT_MNT 0x08 +/* * Bounding set */
@@ -261,6 +267,22 @@ struct request_sock;* Update module state after a successful pivot. * @old_nd contains the nameidata structure for the old root. * @new_nd contains the nameidata structure for the new root. +* @sb_get_mnt_opts: +* Get the security relevant mount options used for a superblock +* @sb the superblock to get security mount options from +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_set_mnt_opts: +* Set the security relevant mount options used for a superblock +* @sb the superblock to set security mount options for +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_clone_mnt_opts: +* Copy all security options from a given superblock to another +* @oldsb old superblock which contain information to clone +* @newsb new superblock which needs filled in * * Security hooks for inode operations. *
@@ -1242,6 +1264,13 @@ struct security_operations { struct nameidata * new_nd);void (*sb_post_pivotroot) (struct nameidata * old_nd,struct nameidata * new_nd); +int (*sb_get_mnt_opts) (const struct super_block *sb, +char ***mount_options,int **flags, +int *num_opts); +int (*sb_set_mnt_opts) (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void (*sb_clone_mnt_opts) (const struct super_block *oldsb, +struct super_block *newsb);int (*inode_alloc_security) (struct inode *inode);void (*inode_free_security) (struct inode *inode);
@@ -1499,6 +1528,13 @@ void security_sb_post_mountroot(void);void security_sb_post_addmount (struct vfsmount *mnt,struct nameidata *mountpoint_nd);int security_sb_pivotroot (struct nameidata *old_nd,struct nameidata *new_nd);void security_sb_post_pivotroot (struct nameidata *old_nd,struct nameidata *new_nd); +int security_sb_get_mnt_opts (const struct super_block *sb,char ***mount_options, +int **flags,int *num_opts); +int security_sb_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb); +int security_inode_alloc (struct inode *inode);void security_inode_free (struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir,
security/dummy.c +26 -0
@@ -245,6 +245,29 @@ static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidatareturn ; } +static int dummy_sb_get_mnt_opts (const struct super_block *sb,char ***mount_options, +int **flags,int *num_opts) +{ + *mount_options =NULL ; + *flags =NULL ; + *num_opts =0 ; +return 0 ; +} + +static int dummy_sb_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts) +{ +if (unlikely (num_opts)) +return -EOPNOTSUPP ; +return 0 ; +} + +static void dummy_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ +return ; +} +static int dummy_inode_alloc_security (struct inode *inode) {return 0 ;
@@ -998,6 +1021,9 @@ void security_fixup_ops (struct security_operations *ops)set_to_dummy_if_null (ops, sb_post_addmount);set_to_dummy_if_null (ops, sb_pivotroot);set_to_dummy_if_null (ops, sb_post_pivotroot); +set_to_dummy_if_null (ops, sb_get_mnt_opts); +set_to_dummy_if_null (ops, sb_set_mnt_opts); +set_to_dummy_if_null (ops, sb_clone_mnt_opts);set_to_dummy_if_null (ops, inode_alloc_security);set_to_dummy_if_null (ops, inode_free_security);set_to_dummy_if_null (ops, inode_init_security);
security/security.c +20 -0
@@ -308,6 +308,26 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_ security_ops->sb_post_pivotroot (old_nd, new_nd); } +int security_sb_get_mnt_opts (const struct super_block *sb, +char ***mount_options, +int **flags,int *num_opts) +{ +return security_ops->sb_get_mnt_opts (sb, mount_options, flags, num_opts); +} + +int security_sb_set_mnt_opts (struct super_block *sb, +char **mount_options, +int *flags,int num_opts) +{ +return security_ops->sb_set_mnt_opts (sb, mount_options, flags, num_opts); +} + +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ + security_ops->sb_clone_mnt_opts (oldsb, newsb); +} +int security_inode_alloc (struct inode *inode) { inode->i_security =NULL ;
security/selinux/hooks.c +495 -254
847 lines not on this page · raw message
security/selinux/include/objsec.h +1 -0
@@ -65,6 +65,7 @@ struct superblock_security_struct {u32 mntpoint_sid;/* SECURITY_FS_USE_MNTPOINT context for files */ unsigned int behavior;/* labeling behavior */ unsigned char initialized;/* initialization flag */ +unsigned char flags;/* which mount options were specified */ unsigned char proc;/* proc fs */ struct mutex lock;struct list_head isec_head;
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 6 lines · Eric Paris
Adds
security_get_sb_mnt_opts,security_set_sb_mnt_opts, andsecurity_clont_sb_mnt_optsto the LSM and to SELinux. This will allow filesystems to directly own and control all of their mount options if they so choose.Signed-off-by Eric Paris <[email protected]>
Quoted 1,028 lines
---
include/linux/security.h | 36 ++ security/dummy.c | 26 ++ security/security.c | 20 + security/selinux/hooks.c | 749 ++++++++++++++++++++++++------------- security/selinux/include/objsec.h | 1 + 5 files changed, 578 insertions(+), 254 deletions(-)include/linux/security.h +36
-0@@ -34,6 +34,12 @@#include <linux/xfrm.h> #include <net/flow.h> +/* only a char in selinux superblock security struct flags */ +#define FSCONTEXT_MNT 0x01 +#define CONTEXT_MNT 0x02 +#define ROOTCONTEXT_MNT 0x04 +#define DEFCONTEXT_MNT 0x08 +/* * Bounding set */ @@ -261,6 +267,22 @@ struct request_sock;* Update module state after a successful pivot. * @old_nd contains the nameidata structure for the old root. * @new_nd contains the nameidata structure for the new root. +* @sb_get_mnt_opts: +* Get the security relevant mount options used for a superblock +* @sb the superblock to get security mount options from +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_set_mnt_opts: +* Set the security relevant mount options used for a superblock +* @sb the superblock to set security mount options for +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_clone_mnt_opts: +* Copy all security options from a given superblock to another +* @oldsb old superblock which contain information to clone +* @newsb new superblock which needs filled in * * Security hooks for inode operations. * @@ -1242,6 +1264,13 @@ struct security_operations { struct nameidata * new_nd);void (*sb_post_pivotroot) (struct nameidata * old_nd,struct nameidata * new_nd); +int (*sb_get_mnt_opts) (const struct super_block *sb, +char ***mount_options,int **flags, +int *num_opts); +int (*sb_set_mnt_opts) (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void (*sb_clone_mnt_opts) (const struct super_block *oldsb, +struct super_block *newsb);int (*inode_alloc_security) (struct inode *inode);void (*inode_free_security) (struct inode *inode);@@ -1499,6 +1528,13 @@ void security_sb_post_mountroot(void);void security_sb_post_addmount (struct vfsmount *mnt,struct nameidata *mountpoint_nd);int security_sb_pivotroot (struct nameidata *old_nd,struct nameidata *new_nd);void security_sb_post_pivotroot (struct nameidata *old_nd,struct nameidata *new_nd); +int security_sb_get_mnt_opts (const struct super_block *sb,char ***mount_options, +int **flags,int *num_opts); +int security_sb_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb); +int security_inode_alloc (struct inode *inode);void security_inode_free (struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir,security/dummy.c +26
-0@@ -245,6 +245,29 @@ static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidatareturn ; } +static int dummy_sb_get_mnt_opts (const struct super_block *sb,char ***mount_options, +int **flags,int *num_opts) +{ + *mount_options =NULL ; + *flags =NULL ; + *num_opts =0 ; +return 0 ; +} + +static int dummy_sb_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts) +{ +if (unlikely (num_opts)) +return -EOPNOTSUPP ; +return 0 ; +} + +static void dummy_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ +return ; +} +static int dummy_inode_alloc_security (struct inode *inode) {return 0 ;@@ -998,6 +1021,9 @@ void security_fixup_ops (struct security_operations *ops)set_to_dummy_if_null (ops, sb_post_addmount);set_to_dummy_if_null (ops, sb_pivotroot);set_to_dummy_if_null (ops, sb_post_pivotroot); +set_to_dummy_if_null (ops, sb_get_mnt_opts); +set_to_dummy_if_null (ops, sb_set_mnt_opts); +set_to_dummy_if_null (ops, sb_clone_mnt_opts);set_to_dummy_if_null (ops, inode_alloc_security);set_to_dummy_if_null (ops, inode_free_security);set_to_dummy_if_null (ops, inode_init_security);security/security.c +20
-0@@ -308,6 +308,26 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_ security_ops->sb_post_pivotroot (old_nd, new_nd); } +int security_sb_get_mnt_opts (const struct super_block *sb, +char ***mount_options, +int **flags,int *num_opts) +{ +return security_ops->sb_get_mnt_opts (sb, mount_options, flags, num_opts); +} + +int security_sb_set_mnt_opts (struct super_block *sb, +char **mount_options, +int *flags,int num_opts) +{ +return security_ops->sb_set_mnt_opts (sb, mount_options, flags, num_opts); +} + +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ + security_ops->sb_clone_mnt_opts (oldsb, newsb); +} +int security_inode_alloc (struct inode *inode) { inode->i_security =NULL ;security/selinux/hooks.c +495
-254@@ -82,6 +82,8 @@#define XATTR_SELINUX_SUFFIX "selinux"#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX +#define NUM_SEL_MNT_OPTS 4 +extern unsigned int policydb_loaded_version;extern int selinux_nlmsg_lookup (u16 sclass,u16 nlmsg_type,u32 *perm);extern int selinux_compat_net;@@ -321,8 +323,8 @@ enum { Opt_error =-1 , Opt_context =1 , Opt_fscontext =2 , - Opt_defcontext =4 , - Opt_rootcontext = 8, + Opt_defcontext =3 , + Opt_rootcontext = 4, }; static match_table_t tokens = {@@ -366,150 +368,318 @@ static int may_context_mount_inode_relabel(u32 sid,return rc; } -static int try_context_mount (struct super_block *sb,void *data) +static int sb_finish_set_opts (struct super_block *sb) { -char *context =NULL , *defcontext =NULL ; -char *fscontext =NULL , *rootcontext =NULL ; -const char *name; -u32 sid; -int alloc =0 , rc =0 , seen =0 ; -struct task_security_struct *tsec = current->security;struct superblock_security_struct *sbsec = sb->s_security; +struct dentry *root = sb->s_root; +struct inode *root_inode = root->d_inode; +int rc =0 ; -if (!data) - goto out; +if (sbsec->behavior ==SECURITY_FS_USE_XATTR ) { +/* Make sure that the xattr handler exists and that no +error other than -ENODATA is returned by getxattr on +the root directory. -ENODATA is ok, as this may be +the first boot of the SELinux kernel before we have +assigned xattr values to the filesystem. */ +if (!root_inode->i_op->getxattr) { +printk (KERN_WARNING "SELinux: (dev %s, type %s) has no " +"xattr support\n" , sb->s_id, sb->s_type->name); + rc = -EOPNOTSUPP ; + goto out; + } + rc = root_inode->i_op->getxattr (root,XATTR_NAME_SELINUX ,NULL ,0 ); +if (rc <0 && rc != -ENODATA ) { +if (rc == -EOPNOTSUPP ) +printk (KERN_WARNING "SELinux: (dev %s, type " +"%s) has no security xattr handler\n" , + sb->s_id, sb->s_type->name); +else +printk (KERN_WARNING "SELinux: (dev %s, type " +"%s) getxattr errno %d\n" , sb->s_id, + sb->s_type->name, -rc); + goto out; + } + } - name = sb->s_type->name; + sbsec->initialized =1 ; -if (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) { +if (sbsec->behavior >ARRAY_SIZE (labeling_behaviors)) { +printk (KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n" , + sb->s_id, sb->s_type->name); + } +else { +printk (KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n" , + sb->s_id, sb->s_type->name, + labeling_behaviors[sbsec->behavior-1 ]); + } -/* NFS we understand. */ -if (!strcmp (name,"nfs" )) { -struct nfs_mount_data *d = data; +/* Initialize the root inode. */ + rc =inode_doinit_with_dentry (root_inode, root); -if (d->version <NFS_MOUNT_VERSION ) - goto out; +/* Initialize any other inodes associated with the superblock, e.g. +inodes created prior to initial policy load or inodes created +during get_sb by a pseudo filesystem that directly +populates itself. */ +spin_lock (&sbsec->isec_lock); +next_inode: +if (!list_empty (&sbsec->isec_head)) { +struct inode_security_struct *isec = +list_entry (sbsec->isec_head.next, + struct inode_security_struct, list); +struct inode *inode = isec->inode; +spin_unlock (&sbsec->isec_lock); + inode =igrab (inode); +if (inode) { +if (!IS_PRIVATE (inode)) +inode_doinit (inode); +iput (inode); + } +spin_lock (&sbsec->isec_lock); +list_del_init (&isec->list); + goto next_inode; + } +spin_unlock (&sbsec->isec_lock); +out: +return rc; +} -if (d->context[0 ]) { - context = d->context; - seen |= Opt_context; - } - }else - goto out; +/* +* This function should allow an FS to ask what it's mount security +* options were so it can use those later for submounts, displaying +* mount options, or whatever. +*/ +static int selinux_get_mnt_opts (const struct super_block *sb, +char ***mount_options,int **mnt_opts_flags, +int *num_opts) +{ +int rc =0 , i; +struct superblock_security_struct *sbsec = sb->s_security; +char *context =NULL ; +u32 len; +char tmp; - }else { -/* Standard string-based options. */ -char *p, *options = data; + *num_opts =0 ; + *mount_options =NULL ; + *mnt_opts_flags =NULL ; -while ((p =strsep (&options,"|" )) !=NULL ) { -int token; -substring_t args[MAX_OPT_ARGS ]; +if (!sbsec->initialized) +return -EINVAL ; -if (!*p) -continue ; +if (!ss_initialized) +return -EINVAL ; - token =match_token (p, tokens, args); +/* +* if we ever use sbsec flags for anything other than tracking mount +* settings this is going to need a mask +*/ + tmp = sbsec->flags; +/* count the number of mount options for this sb */ +for (i =0 ; i <8 ; i++) { +if (tmp &0x01 ) + (*num_opts)++; + tmp >>=1 ; + } -switch (token) { -case Opt_context: -if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - context =match_strdup (&args[0 ]); -if (!context) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_context; -break ; + *mount_options =kcalloc (*num_opts,sizeof (char *),GFP_ATOMIC ); +if (!*mount_options) { + rc = -ENOMEM ; + goto out_free; + } -case Opt_fscontext: -if (seen & Opt_fscontext) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - fscontext =match_strdup (&args[0 ]); -if (!fscontext) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_fscontext; -break ; + *mnt_opts_flags =kcalloc (*num_opts,sizeof (int ),GFP_ATOMIC ); +if (!*mnt_opts_flags) { + rc = -ENOMEM ; + goto out_free; + } -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 ; + i =0 ; +if (sbsec->flags &FSCONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =FSCONTEXT_MNT ; + } +if (sbsec->flags &CONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->mntpoint_sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =CONTEXT_MNT ; + } +if (sbsec->flags &DEFCONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->def_sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =DEFCONTEXT_MNT ; + } +if (sbsec->flags &ROOTCONTEXT_MNT ) { +struct inode *root = sbsec->sb->s_root->d_inode; +struct inode_security_struct *isec = root->i_security; -case Opt_defcontext: -if (sbsec->behavior !=SECURITY_FS_USE_XATTR ) { - rc = -EINVAL ; -printk (KERN_WARNING "SELinux: " -"defcontext option is invalid " -"for this filesystem type\n" ); - goto out_free; - } -if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - defcontext =match_strdup (&args[0 ]); -if (!defcontext) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_defcontext; -break ; + rc =security_sid_to_context (isec->sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =ROOTCONTEXT_MNT ; + } -default : - rc = -EINVAL ; -printk (KERN_WARNING "SELinux: unknown mount " -"option\n" ); - goto out_free; +BUG_ON (i != *num_opts); - } - } - } +return 0 ; + +out_free: +/* don't leak context string if security_sid_to_context had an error */ +if (*mount_options && i) +for (; i >0 ; i--) +kfree ((*mount_options)[i-1 ]); +kfree (*mount_options); + *mount_options =NULL ; +kfree (*mnt_opts_flags); + *mnt_opts_flags =NULL ; + *num_opts =0 ; +return rc; +} + +static int bad_option (struct superblock_security_struct *sbsec,char flag, +u32 old_sid,u32 new_sid) +{ +/* check if the old mount command had the same options */ +if (sbsec->initialized) +if (!(sbsec->flags & flag) || + (old_sid != new_sid)) +return 1 ; + +/* check if we were passed the same options twice, +* aka someone passed context=a,context=b +*/ +if (!sbsec->initialized) +if (sbsec->flags & flag) +return 1 ; +return 0 ; +} +/* +* Allow filesystems with binary mount data to explicitly set mount point labeling. +*/ +int selinux_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts) +{ +int rc =0 , i; +struct task_security_struct *tsec = current->security; +struct superblock_security_struct *sbsec = sb->s_security; +const char *name = sb->s_type->name; +struct inode *inode = sbsec->sb->s_root->d_inode; +struct inode_security_struct *root_isec = inode->i_security; +u32 fscontext_sid =0 , context_sid =0 , rootcontext_sid =0 ; +u32 defcontext_sid =0 ; + +mutex_lock (&sbsec->lock); -if (!seen) +if (!ss_initialized) { +if (!num_opts) { +/* Defer initialization until selinux_complete_init, +after the initial policy is loaded and the security +server is ready to handle calls. */ +spin_lock (&sb_security_lock); +if (list_empty (&sbsec->list)) +list_add (&sbsec->list, &superblock_security_head); +spin_unlock (&sb_security_lock); + goto out; + } + rc = -EINVAL ; +printk (KERN_WARNING "Unable to set superblock options before " +"the security server is initialized\n" ); goto out; + } -/* sets the context of the superblock for the fs being mounted. */ -if (fscontext) { - rc =security_context_to_sid (fscontext,strlen (fscontext), &sid); +/* +* parse the mount options, check if they are valid sids. +* also check if someone is trying to mount the same sb more +* than once with different security options. +*/ +for (i =0 ; i < num_opts; i++) { +u32 sid; + rc =security_context_to_sid (mount_options[i], +strlen (mount_options[i]), &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; + mount_options[i], sb->s_id, name, rc); + goto out; } +switch (flags[i]) { +case FSCONTEXT_MNT : + fscontext_sid = sid; + +if (bad_option (sbsec,FSCONTEXT_MNT , sbsec->sid, + fscontext_sid)) + goto out_double_mount; + + sbsec->flags |=FSCONTEXT_MNT ; +break ; +case CONTEXT_MNT : + context_sid = sid; + +if (bad_option (sbsec,CONTEXT_MNT , sbsec->mntpoint_sid, + context_sid)) + goto out_double_mount; + + sbsec->flags |=CONTEXT_MNT ; +break ; +case ROOTCONTEXT_MNT : + rootcontext_sid = sid; + +if (bad_option (sbsec,ROOTCONTEXT_MNT , root_isec->sid, + rootcontext_sid)) + goto out_double_mount; + + sbsec->flags |=ROOTCONTEXT_MNT ; + +break ; +case DEFCONTEXT_MNT : + defcontext_sid = sid; + +if (bad_option (sbsec,DEFCONTEXT_MNT , sbsec->def_sid, + defcontext_sid)) + goto out_double_mount; - rc =may_context_mount_sb_relabel (sid, sbsec, tsec); + sbsec->flags |=DEFCONTEXT_MNT ; + +break ; +default : + rc = -EINVAL ; + goto out; + } + } + +if (sbsec->initialized) { +/* previously mounted with options, but not on this attempt? */ +if (sbsec->flags && !num_opts) + goto out_double_mount; + rc =0 ; + goto out; + } + +if (strcmp (sb->s_type->name,"proc" ) ==0 ) + sbsec->proc =1 ; + +/* Determine the labeling behavior to use for this filesystem type. */ + rc =security_fs_use (sb->s_type->name, &sbsec->behavior, &sbsec->sid); +if (rc) { +printk (KERN_WARNING "%s: security_fs_use(%s) returned %d\n" , + __FUNCTION__, sb->s_type->name, rc); + goto out; + } + +/* sets the context of the superblock for the fs being mounted. */ +if (fscontext_sid) { + + rc =may_context_mount_sb_relabel (fscontext_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; - sbsec->sid = sid; + sbsec->sid = fscontext_sid; }/* @@ -517,182 +687,250 @@ static int try_context_mount(struct super_block *sb, void *data)* 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) { -printk (KERN_WARNING "SELinux: security_context_to_sid" -"(%s) failed for (dev %s, type %s) errno=%d\n" , - context, sb->s_id, name, rc); - goto out_free; - } - -if (!fscontext) { - rc =may_context_mount_sb_relabel (sid, sbsec, tsec); +if (context_sid) { +if (!fscontext_sid) { + rc =may_context_mount_sb_relabel (context_sid, sbsec, tsec);if (rc) - goto out_free; - sbsec->sid = sid; + goto out; + sbsec->sid = context_sid; }else { - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); + rc =may_context_mount_inode_relabel (context_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; } - sbsec->mntpoint_sid = sid; +if (!rootcontext_sid) + rootcontext_sid = context_sid; + sbsec->mntpoint_sid = context_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; - } - - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); +if (rootcontext_sid) { + rc =may_context_mount_inode_relabel (rootcontext_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; - isec->sid = sid; - isec->initialized =1 ; + root_isec->sid = rootcontext_sid; + root_isec->initialized =1 ; } -if (defcontext) { - rc =security_context_to_sid (defcontext,strlen (defcontext), &sid); -if (rc) { -printk (KERN_WARNING "SELinux: security_context_to_sid" -"(%s) failed for (dev %s, type %s) errno=%d\n" , - defcontext, sb->s_id, name, rc); - goto out_free; +if (defcontext_sid) { +if (sbsec->behavior !=SECURITY_FS_USE_XATTR ) { + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: defcontext option is " +"invalid for this filesystem type\n" ); + goto out; } -if (sid == sbsec->def_sid) - goto out_free; - - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); -if (rc) - goto out_free; +if (defcontext_sid != sbsec->def_sid) { + rc =may_context_mount_inode_relabel (defcontext_sid, + sbsec, tsec); +if (rc) + goto out; + } - sbsec->def_sid = sid; + sbsec->def_sid = defcontext_sid; } -out_free: -if (alloc) { -kfree (context); -kfree (defcontext); -kfree (fscontext); -kfree (rootcontext); - } + rc =sb_finish_set_opts (sb); out: +mutex_unlock (&sbsec->lock);return rc; +out_double_mount: + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: mount invalid. Same superblock, different " +"security settings for (dev %s, type %s)\n" , sb->s_id, name); + goto out; } -static int superblock_doinit (struct super_block *sb,void *data) +static void selinux_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) { -struct superblock_security_struct *sbsec = sb->s_security; -struct dentry *root = sb->s_root; -struct inode *inode = root->d_inode; -int rc =0 ; +const struct superblock_security_struct *oldsbsec = oldsb->s_security; +struct superblock_security_struct *newsbsec = newsb->s_security; -mutex_lock (&sbsec->lock); -if (sbsec->initialized) - goto out; +int set_fscontext = (oldsbsec->flags &FSCONTEXT_MNT ); +int set_context = (oldsbsec->flags &CONTEXT_MNT ); +int set_rootcontext = (oldsbsec->flags &ROOTCONTEXT_MNT ); -if (!ss_initialized) { -/* Defer initialization until selinux_complete_init, -after the initial policy is loaded and the security -server is ready to handle calls. */ -spin_lock (&sb_security_lock); -if (list_empty (&sbsec->list)) -list_add (&sbsec->list, &superblock_security_head); -spin_unlock (&sb_security_lock); - goto out; +/* we can't error, we can't save the info, this shouldn't get called +* this early in the boot process. */ +BUG_ON (!ss_initialized); + +/* this might go away sometime down the line if there is a new user +* of clone, but for now, nfs better not get here... */ +BUG_ON (newsbsec->initialized); + +/* how can we clone if the old one wasn't set up?? */ +BUG_ON (!oldsbsec->initialized); + +mutex_lock (&newsbsec->lock); + + newsbsec->flags = oldsbsec->flags; + + newsbsec->sid = oldsbsec->sid; + newsbsec->def_sid = oldsbsec->def_sid; + newsbsec->behavior = oldsbsec->behavior; + +if (set_context) { +u32 sid = oldsbsec->mntpoint_sid; + +if (!set_fscontext) + newsbsec->sid = sid; +if (!set_rootcontext) { +struct inode *newinode = newsb->s_root->d_inode; +struct inode_security_struct *newisec = newinode->i_security; + newisec->sid = sid; + } + newsbsec->mntpoint_sid = sid; } +if (set_rootcontext) { +const struct inode *oldinode = oldsb->s_root->d_inode; +const struct inode_security_struct *oldisec = oldinode->i_security; +struct inode *newinode = newsb->s_root->d_inode; +struct inode_security_struct *newisec = newinode->i_security; -/* Determine the labeling behavior to use for this filesystem type. */ - rc =security_fs_use (sb->s_type->name, &sbsec->behavior, &sbsec->sid); -if (rc) { -printk (KERN_WARNING "%s: security_fs_use(%s) returned %d\n" , - __FUNCTION__, sb->s_type->name, rc); - goto out; + newisec->sid = oldisec->sid; } - rc =try_context_mount (sb, data); -if (rc) +sb_finish_set_opts (newsb); +mutex_unlock (&newsbsec->lock); +} + +/* +* string mount options parsing and call set the sbsec +*/ +static int superblock_doinit (struct super_block *sb,void *data) +{ +char *context =NULL , *defcontext =NULL ; +char *fscontext =NULL , *rootcontext =NULL ; +int rc =0 ; +char *p, *options = data; +/* selinux only know about a fixed number of mount options */ +char *mnt_opts[NUM_SEL_MNT_OPTS ]; +int mnt_opts_flags[NUM_SEL_MNT_OPTS ], num_mnt_opts =0 ; + +if (!data) goto out; -if (sbsec->behavior ==SECURITY_FS_USE_XATTR ) { -/* Make sure that the xattr handler exists and that no -error other than -ENODATA is returned by getxattr on -the root directory. -ENODATA is ok, as this may be -the first boot of the SELinux kernel before we have -assigned xattr values to the filesystem. */ -if (!inode->i_op->getxattr) { -printk (KERN_WARNING "SELinux: (dev %s, type %s) has no " -"xattr support\n" , sb->s_id, sb->s_type->name); - rc = -EOPNOTSUPP ; - goto out; - } - rc = inode->i_op->getxattr (root,XATTR_NAME_SELINUX ,NULL ,0 ); -if (rc <0 && rc != -ENODATA ) { -if (rc == -EOPNOTSUPP ) -printk (KERN_WARNING "SELinux: (dev %s, type " -"%s) has no security xattr handler\n" , - sb->s_id, sb->s_type->name); -else -printk (KERN_WARNING "SELinux: (dev %s, type " -"%s) getxattr errno %d\n" , sb->s_id, - sb->s_type->name, -rc); +/* with the nfs patch this will become a goto out; */ +if (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) { +const char *name = sb->s_type->name; +/* NFS we understand. */ +if (!strcmp (name,"nfs" )) { +struct nfs_mount_data *d = data; + +if (d->version !=NFS_MOUNT_VERSION ) + goto out; + +if (d->context[0 ]) { + context =kstrdup (d->context,GFP_KERNEL ); +if (!context) { + rc = -ENOMEM ; + goto out; + } + } + goto build_flags; + }else goto out; - } } -if (strcmp (sb->s_type->name,"proc" ) ==0 ) - sbsec->proc =1 ; +/* Standard string-based options. */ +while ((p =strsep (&options,"|" )) !=NULL ) { +int token; +substring_t args[MAX_OPT_ARGS ]; - sbsec->initialized =1 ; +if (!*p) +continue ; -if (sbsec->behavior >ARRAY_SIZE (labeling_behaviors)) { -printk (KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n" , - sb->s_id, sb->s_type->name); - } -else { -printk (KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n" , - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1 ]); - } + token =match_token (p, tokens, args); -/* Initialize the root inode. */ - rc =inode_doinit_with_dentry (sb->s_root->d_inode, sb->s_root); +switch (token) { +case Opt_context: +if (context || defcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + context =match_strdup (&args[0 ]); +if (!context) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_fscontext: +if (fscontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + fscontext =match_strdup (&args[0 ]); +if (!fscontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_rootcontext: +if (rootcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + rootcontext =match_strdup (&args[0 ]); +if (!rootcontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_defcontext: +if (context || defcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + defcontext =match_strdup (&args[0 ]); +if (!defcontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +default : + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: unknown mount option\n" ); + goto out_err; -/* Initialize any other inodes associated with the superblock, e.g. -inodes created prior to initial policy load or inodes created -during get_sb by a pseudo filesystem that directly -populates itself. */ -spin_lock (&sbsec->isec_lock); -next_inode: -if (!list_empty (&sbsec->isec_head)) { -struct inode_security_struct *isec = -list_entry (sbsec->isec_head.next, - struct inode_security_struct, list); -struct inode *inode = isec->inode; -spin_unlock (&sbsec->isec_lock); - inode =igrab (inode); -if (inode) { -if (!IS_PRIVATE (inode)) -inode_doinit (inode); -iput (inode); } -spin_lock (&sbsec->isec_lock); -list_del_init (&isec->list); - goto next_inode; } -spin_unlock (&sbsec->isec_lock); + +build_flags: +if (fscontext) { + mnt_opts[num_mnt_opts] = fscontext; + mnt_opts_flags[num_mnt_opts++] =FSCONTEXT_MNT ; + } +if (context) { + mnt_opts[num_mnt_opts] = context; + mnt_opts_flags[num_mnt_opts++] =CONTEXT_MNT ; + } +if (rootcontext) { + mnt_opts[num_mnt_opts] = rootcontext; + mnt_opts_flags[num_mnt_opts++] =ROOTCONTEXT_MNT ; + } +if (defcontext) { + mnt_opts[num_mnt_opts] = defcontext; + mnt_opts_flags[num_mnt_opts++] =DEFCONTEXT_MNT ; + } + out: -mutex_unlock (&sbsec->lock); + rc =selinux_set_mnt_opts (sb, mnt_opts, mnt_opts_flags, num_mnt_opts); +out_err: +kfree (context); +kfree (defcontext); +kfree (fscontext); +kfree (rootcontext);return rc; }@@ -4800,6 +5038,9 @@ static struct security_operations selinux_ops = { .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, + .sb_get_mnt_opts = selinux_get_mnt_opts, + .sb_set_mnt_opts = selinux_set_mnt_opts, + .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, .inode_alloc_security = selinux_inode_alloc_security, .inode_free_security = selinux_inode_free_security,security/selinux/include/objsec.h +1
-1@@ -65,6 +65,7 @@ struct superblock_security_struct {u32 mntpoint_sid;/* SECURITY_FS_USE_MNTPOINT context for files */ unsigned int behavior;/* labeling behavior */ unsigned char initialized;/* initialization flag */ +unsigned char flags;/* which mount options were specified */ unsigned char proc;/* proc fs */ struct mutex lock;struct list_head isec_head; --This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 9 lines · --- Stephen Smalley
Quoted 6 lines · Eric Paris
Adds
security_get_sb_mnt_opts,security_set_sb_mnt_opts, andsecurity_clont_sb_mnt_optsto the LSM and to SELinux. This will allow filesystems to directly own and control all of their mount options if they so choose.Signed-off-by Eric Paris <[email protected]>
Shouldn't this get cross posted to the LSM list?
Quoted 1,040 lines
Quoted 7 lines
---
include/linux/security.h | 36 ++ security/dummy.c | 26 ++ security/security.c | 20 + security/selinux/hooks.c | 749++++++++++++++++++++++++-------------
Quoted 58 lines
security/selinux/include/objsec.h | 1 + 5 files changed, 578 insertions(+), 254 deletions(-)include/linux/security.h +29
-0@@ -34,6 +34,12 @@#include <linux/xfrm.h> #include <net/flow.h> +/* only a char in selinux superblock security struct flags */ +#define FSCONTEXT_MNT 0x01 +#define CONTEXT_MNT 0x02 +#define ROOTCONTEXT_MNT 0x04 +#define DEFCONTEXT_MNT 0x08 +/* * Bounding set */ @@ -261,6 +267,22 @@ struct request_sock;* Update module state after a successful pivot. * @old_nd contains the nameidata structure for the old root. * @new_nd contains the nameidata structure for the new root. +* @sb_get_mnt_opts: +* Get the security relevant mount options used for a superblock +* @sb the superblock to get security mount options from +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_set_mnt_opts: +* Set the security relevant mount options used for a superblock +* @sb the superblock to set security mount options for +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_clone_mnt_opts: +* Copy all security options from a given superblock to another +* @oldsb old superblock which contain information to clone +* @newsb new superblock which needs filled in * * Security hooks for inode operations. * @@ -1242,6 +1264,13 @@ struct security_operations { struct nameidata * new_nd);void (*sb_post_pivotroot) (struct nameidata * old_nd,struct nameidata * new_nd); +int (*sb_get_mnt_opts) (const struct super_block *sb, +char ***mount_options,int **flags, +int *num_opts); +int (*sb_set_mnt_opts) (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void (*sb_clone_mnt_opts) (const struct super_block *oldsb, +struct super_block *newsb);int (*inode_alloc_security) (struct inode *inode);void (*inode_free_security) (struct inode *inode);include/linux/security.h void security_sb_post_mountroot(void); · line 1528
Quoted 1 line
include/linux/security.h +0
-0@@ -1499,6 +1528,13 @@ void security_sb_post_mountroot(void); void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata
*mountpoint_nd);include/linux/security.h void security_sb_post_mountroot(void); · line 1529
Quoted 1 line
include/linux/security.h +0
-0int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata
*new_nd);include/linux/security.h void security_sb_post_mountroot(void); · line 1530
Quoted 1 line
include/linux/security.h +0
-0void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata
*new_nd);include/linux/security.h void security_sb_post_mountroot(void); · line 1531
Quoted 1 line
include/linux/security.h +1
-0+int security_sb_get_mnt_opts(const struct super_block *sb, char***mount_options,
security/dummy.c static void dummy_sb_post_pivotroot (struct nameidata
Quoted 14 lines
include/linux/security.h +6
-0+ int **flags, int *num_opts); +int security_sb_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb); +int security_inode_alloc (struct inode *inode);void security_inode_free (struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir,security/dummy.c +0
-0@@ -245,6 +245,29 @@ static void dummy_sb_post_pivotroot (struct nameidata
*old_nd, struct nameidatasecurity/dummy.c static void dummy_sb_post_pivotroot (struct nameidata · line 248
Quoted 4 lines
security/dummy.c +1
-0return ; } +static int dummy_sb_get_mnt_opts(const struct super_block *sb, char***mount_options,
security/dummy.c static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata
Quoted 9 lines
security/dummy.c +9
-0+ int **flags, int *num_opts) +{ + *mount_options =NULL ; + *flags =NULL ; + *num_opts =0 ; +return 0 ; +} + +static int dummy_sb_set_mnt_opts(struct super_block *sb, char**mount_options,
security/dummy.c void security_fixup_ops (struct security_operations
Quoted 17 lines
security/dummy.c +13
-0+ int *flags, int num_opts) +{ + if (unlikely(num_opts)) + return -EOPNOTSUPP; +return 0 ; +} + +static void dummy_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ +return ; +} +static int dummy_inode_alloc_security (struct inode *inode) {return 0 ;@@ -998,6 +1021,9 @@ void security_fixup_ops (struct security_operations*ops)
security/security.c void security_sb_post_pivotroot(struct nameidata
Quoted 14 lines
security/dummy.c +3
-0set_to_dummy_if_null (ops, sb_post_addmount);set_to_dummy_if_null (ops, sb_pivotroot);set_to_dummy_if_null (ops, sb_post_pivotroot); +set_to_dummy_if_null (ops, sb_get_mnt_opts); +set_to_dummy_if_null (ops, sb_set_mnt_opts); +set_to_dummy_if_null (ops, sb_clone_mnt_opts);set_to_dummy_if_null (ops, inode_alloc_security);set_to_dummy_if_null (ops, inode_free_security);set_to_dummy_if_null (ops, inode_init_security);security/security.c +0
-0@@ -308,6 +308,26 @@ void security_sb_post_pivotroot(struct nameidata
*old_nd, struct nameidata*new_Quoted 92 lines
security/security.c +20
-0security_ops->sb_post_pivotroot (old_nd, new_nd); } +int security_sb_get_mnt_opts (const struct super_block *sb, +char ***mount_options, +int **flags,int *num_opts) +{ +return security_ops->sb_get_mnt_opts (sb, mount_options, flags, num_opts); +} + +int security_sb_set_mnt_opts (struct super_block *sb, +char **mount_options, +int *flags,int num_opts) +{ +return security_ops->sb_set_mnt_opts (sb, mount_options, flags, num_opts); +} + +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ + security_ops->sb_clone_mnt_opts (oldsb, newsb); +} +int security_inode_alloc (struct inode *inode) { inode->i_security =NULL ;security/selinux/hooks.c +30
-11@@ -82,6 +82,8 @@#define XATTR_SELINUX_SUFFIX "selinux"#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX +#define NUM_SEL_MNT_OPTS 4 +extern unsigned int policydb_loaded_version;extern int selinux_nlmsg_lookup (u16 sclass,u16 nlmsg_type,u32 *perm);extern int selinux_compat_net;@@ -321,8 +323,8 @@ enum { Opt_error =-1 , Opt_context =1 , Opt_fscontext =2 , - Opt_defcontext =4 , - Opt_rootcontext = 8, + Opt_defcontext =3 , + Opt_rootcontext = 4, }; static match_table_t tokens = {@@ -366,150 +368,318 @@ static int may_context_mount_inode_relabel(u32 sid,return rc; } -static int try_context_mount (struct super_block *sb,void *data) +static int sb_finish_set_opts (struct super_block *sb) { -char *context =NULL , *defcontext =NULL ; -char *fscontext =NULL , *rootcontext =NULL ; -const char *name; -u32 sid; -int alloc =0 , rc =0 , seen =0 ; -struct task_security_struct *tsec = current->security;struct superblock_security_struct *sbsec = sb->s_security; +struct dentry *root = sb->s_root; +struct inode *root_inode = root->d_inode; +int rc =0 ; -if (!data) - goto out; +if (sbsec->behavior ==SECURITY_FS_USE_XATTR ) { +/* Make sure that the xattr handler exists and that no +error other than -ENODATA is returned by getxattr on +the root directory. -ENODATA is ok, as this may be +the first boot of the SELinux kernel before we have +assigned xattr values to the filesystem. */ +if (!root_inode->i_op->getxattr) { +printk (KERN_WARNING "SELinux: (dev %s, type %s) has no " +"xattr support\n" , sb->s_id, sb->s_type->name); + rc = -EOPNOTSUPP ; + goto out; + } + rc = root_inode->i_op->getxattr (root,XATTR_NAME_SELINUX ,NULL ,0 ); +if (rc <0 && rc != -ENODATA ) { +if (rc == -EOPNOTSUPP ) +printk (KERN_WARNING "SELinux: (dev %s, type " +"%s) has no security xattr handler\n" , + sb->s_id, sb->s_type->name); +else +printk (KERN_WARNING "SELinux: (dev %s, type " +"%s) getxattr errno %d\n" , sb->s_id, + sb->s_type->name, -rc);security/selinux/hooks.c static int may_context_mount_inode_relabel(u32 sid, · line 407
Quoted 10 lines
security/selinux/hooks.c +6
-2+ goto out; + } + } - name = sb->s_type->name; + sbsec->initialized =1 ; -if (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) { + if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { + printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknownbehavior\n",
Quoted 242 lines
security/selinux/hooks.c +133
-96+ sb->s_id, sb->s_type->name); + } +else { +printk (KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n" , + sb->s_id, sb->s_type->name, + labeling_behaviors[sbsec->behavior-1 ]); + } -/* NFS we understand. */ -if (!strcmp (name,"nfs" )) { -struct nfs_mount_data *d = data; +/* Initialize the root inode. */ + rc =inode_doinit_with_dentry (root_inode, root); -if (d->version <NFS_MOUNT_VERSION ) - goto out; +/* Initialize any other inodes associated with the superblock, e.g. +inodes created prior to initial policy load or inodes created +during get_sb by a pseudo filesystem that directly +populates itself. */ +spin_lock (&sbsec->isec_lock); +next_inode: +if (!list_empty (&sbsec->isec_head)) { +struct inode_security_struct *isec = +list_entry (sbsec->isec_head.next, + struct inode_security_struct, list); +struct inode *inode = isec->inode; +spin_unlock (&sbsec->isec_lock); + inode =igrab (inode); +if (inode) { +if (!IS_PRIVATE (inode)) +inode_doinit (inode); +iput (inode); + } +spin_lock (&sbsec->isec_lock); +list_del_init (&isec->list); + goto next_inode; + } +spin_unlock (&sbsec->isec_lock); +out: +return rc; +} -if (d->context[0 ]) { - context = d->context; - seen |= Opt_context; - } - }else - goto out; +/* +* This function should allow an FS to ask what it's mount security +* options were so it can use those later for submounts, displaying +* mount options, or whatever. +*/ +static int selinux_get_mnt_opts (const struct super_block *sb, +char ***mount_options,int **mnt_opts_flags, +int *num_opts) +{ +int rc =0 , i; +struct superblock_security_struct *sbsec = sb->s_security; +char *context =NULL ; +u32 len; +char tmp; - }else { -/* Standard string-based options. */ -char *p, *options = data; + *num_opts =0 ; + *mount_options =NULL ; + *mnt_opts_flags =NULL ; -while ((p =strsep (&options,"|" )) !=NULL ) { -int token; -substring_t args[MAX_OPT_ARGS ]; +if (!sbsec->initialized) +return -EINVAL ; -if (!*p) -continue ; +if (!ss_initialized) +return -EINVAL ; - token =match_token (p, tokens, args); +/* +* if we ever use sbsec flags for anything other than tracking mount +* settings this is going to need a mask +*/ + tmp = sbsec->flags; +/* count the number of mount options for this sb */ +for (i =0 ; i <8 ; i++) { +if (tmp &0x01 ) + (*num_opts)++; + tmp >>=1 ; + } -switch (token) { -case Opt_context: -if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - context =match_strdup (&args[0 ]); -if (!context) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_context; -break ; + *mount_options =kcalloc (*num_opts,sizeof (char *),GFP_ATOMIC ); +if (!*mount_options) { + rc = -ENOMEM ; + goto out_free; + } -case Opt_fscontext: -if (seen & Opt_fscontext) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - fscontext =match_strdup (&args[0 ]); -if (!fscontext) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_fscontext; -break ; + *mnt_opts_flags =kcalloc (*num_opts,sizeof (int ),GFP_ATOMIC ); +if (!*mnt_opts_flags) { + rc = -ENOMEM ; + goto out_free; + } -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 ; + i =0 ; +if (sbsec->flags &FSCONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =FSCONTEXT_MNT ; + } +if (sbsec->flags &CONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->mntpoint_sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =CONTEXT_MNT ; + } +if (sbsec->flags &DEFCONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->def_sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =DEFCONTEXT_MNT ; + } +if (sbsec->flags &ROOTCONTEXT_MNT ) { +struct inode *root = sbsec->sb->s_root->d_inode; +struct inode_security_struct *isec = root->i_security; -case Opt_defcontext: -if (sbsec->behavior !=SECURITY_FS_USE_XATTR ) { - rc = -EINVAL ; -printk (KERN_WARNING "SELinux: " -"defcontext option is invalid " -"for this filesystem type\n" ); - goto out_free; - } -if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - defcontext =match_strdup (&args[0 ]); -if (!defcontext) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_defcontext; -break ; + rc =security_sid_to_context (isec->sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =ROOTCONTEXT_MNT ; + } -default : - rc = -EINVAL ; -printk (KERN_WARNING "SELinux: unknown mount " -"option\n" ); - goto out_free; +BUG_ON (i != *num_opts); - } - } - } +return 0 ; + +out_free: +/* don't leak context string if security_sid_to_context had an error */ +if (*mount_options && i) +for (; i >0 ; i--) +kfree ((*mount_options)[i-1 ]); +kfree (*mount_options); + *mount_options =NULL ; +kfree (*mnt_opts_flags); + *mnt_opts_flags =NULL ; + *num_opts =0 ; +return rc; +} + +static int bad_option (struct superblock_security_struct *sbsec,char flag, +u32 old_sid,u32 new_sid) +{ +/* check if the old mount command had the same options */ +if (sbsec->initialized) +if (!(sbsec->flags & flag) || + (old_sid != new_sid)) +return 1 ; +security/selinux/hooks.c static int may_context_mount_inode_relabel(u32 sid,
Quoted 10 lines
security/selinux/hooks.c +10
-0+/* check if we were passed the same options twice, +* aka someone passed context=a,context=b +*/ +if (!sbsec->initialized) +if (sbsec->flags & flag) +return 1 ; +return 0 ; +} +/* +* Allow filesystems with binary mount data to explicitly set mount point labeling.
security/selinux/hooks.c static int try_context_mount(struct super_block
Quoted 132 lines
security/selinux/hooks.c +109
-9+*/ +int selinux_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts) +{ +int rc =0 , i; +struct task_security_struct *tsec = current->security; +struct superblock_security_struct *sbsec = sb->s_security; +const char *name = sb->s_type->name; +struct inode *inode = sbsec->sb->s_root->d_inode; +struct inode_security_struct *root_isec = inode->i_security; +u32 fscontext_sid =0 , context_sid =0 , rootcontext_sid =0 ; +u32 defcontext_sid =0 ; + +mutex_lock (&sbsec->lock); -if (!seen) +if (!ss_initialized) { +if (!num_opts) { +/* Defer initialization until selinux_complete_init, +after the initial policy is loaded and the security +server is ready to handle calls. */ +spin_lock (&sb_security_lock); +if (list_empty (&sbsec->list)) +list_add (&sbsec->list, &superblock_security_head); +spin_unlock (&sb_security_lock); + goto out; + } + rc = -EINVAL ; +printk (KERN_WARNING "Unable to set superblock options before " +"the security server is initialized\n" ); goto out; + } -/* sets the context of the superblock for the fs being mounted. */ -if (fscontext) { - rc =security_context_to_sid (fscontext,strlen (fscontext), &sid); +/* +* parse the mount options, check if they are valid sids. +* also check if someone is trying to mount the same sb more +* than once with different security options. +*/ +for (i =0 ; i < num_opts; i++) { +u32 sid; + rc =security_context_to_sid (mount_options[i], +strlen (mount_options[i]), &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; + mount_options[i], sb->s_id, name, rc); + goto out; } +switch (flags[i]) { +case FSCONTEXT_MNT : + fscontext_sid = sid; + +if (bad_option (sbsec,FSCONTEXT_MNT , sbsec->sid, + fscontext_sid)) + goto out_double_mount; + + sbsec->flags |=FSCONTEXT_MNT ; +break ; +case CONTEXT_MNT : + context_sid = sid; + +if (bad_option (sbsec,CONTEXT_MNT , sbsec->mntpoint_sid, + context_sid)) + goto out_double_mount; + + sbsec->flags |=CONTEXT_MNT ; +break ; +case ROOTCONTEXT_MNT : + rootcontext_sid = sid; + +if (bad_option (sbsec,ROOTCONTEXT_MNT , root_isec->sid, + rootcontext_sid)) + goto out_double_mount; + + sbsec->flags |=ROOTCONTEXT_MNT ; + +break ; +case DEFCONTEXT_MNT : + defcontext_sid = sid; + +if (bad_option (sbsec,DEFCONTEXT_MNT , sbsec->def_sid, + defcontext_sid)) + goto out_double_mount; - rc =may_context_mount_sb_relabel (sid, sbsec, tsec); + sbsec->flags |=DEFCONTEXT_MNT ; + +break ; +default : + rc = -EINVAL ; + goto out; + } + } + +if (sbsec->initialized) { +/* previously mounted with options, but not on this attempt? */ +if (sbsec->flags && !num_opts) + goto out_double_mount; + rc =0 ; + goto out; + } + +if (strcmp (sb->s_type->name,"proc" ) ==0 ) + sbsec->proc =1 ; + +/* Determine the labeling behavior to use for this filesystem type. */ + rc =security_fs_use (sb->s_type->name, &sbsec->behavior, &sbsec->sid); +if (rc) { +printk (KERN_WARNING "%s: security_fs_use(%s) returned %d\n" , + __FUNCTION__, sb->s_type->name, rc); + goto out; + } + +/* sets the context of the superblock for the fs being mounted. */ +if (fscontext_sid) { + + rc =may_context_mount_sb_relabel (fscontext_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; - sbsec->sid = sid; + sbsec->sid = fscontext_sid; }/* @@ -517,182 +687,250 @@ static int try_context_mount(struct super_block*sb, void *data)
Quoted 97 lines
security/selinux/hooks.c +28
-49* 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) { -printk (KERN_WARNING "SELinux: security_context_to_sid" -"(%s) failed for (dev %s, type %s) errno=%d\n" , - context, sb->s_id, name, rc); - goto out_free; - } - -if (!fscontext) { - rc =may_context_mount_sb_relabel (sid, sbsec, tsec); +if (context_sid) { +if (!fscontext_sid) { + rc =may_context_mount_sb_relabel (context_sid, sbsec, tsec);if (rc) - goto out_free; - sbsec->sid = sid; + goto out; + sbsec->sid = context_sid; }else { - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); + rc =may_context_mount_inode_relabel (context_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; } - sbsec->mntpoint_sid = sid; +if (!rootcontext_sid) + rootcontext_sid = context_sid; + sbsec->mntpoint_sid = context_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; - } - - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); +if (rootcontext_sid) { + rc =may_context_mount_inode_relabel (rootcontext_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; - isec->sid = sid; - isec->initialized =1 ; + root_isec->sid = rootcontext_sid; + root_isec->initialized =1 ; } -if (defcontext) { - rc =security_context_to_sid (defcontext,strlen (defcontext), &sid); -if (rc) { -printk (KERN_WARNING "SELinux: security_context_to_sid" -"(%s) failed for (dev %s, type %s) errno=%d\n" , - defcontext, sb->s_id, name, rc); - goto out_free; +if (defcontext_sid) { +if (sbsec->behavior !=SECURITY_FS_USE_XATTR ) { + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: defcontext option is " +"invalid for this filesystem type\n" ); + goto out; } -if (sid == sbsec->def_sid) - goto out_free; - - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); -if (rc) - goto out_free; +if (defcontext_sid != sbsec->def_sid) { + rc =may_context_mount_inode_relabel (defcontext_sid, + sbsec, tsec); +if (rc) + goto out; + } - sbsec->def_sid = sid; + sbsec->def_sid = defcontext_sid; } -out_free: -if (alloc) { -kfree (context); -kfree (defcontext);security/selinux/hooks.c static int try_context_mount(struct super_block *sb, void *data)
Quoted 10 lines
security/selinux/hooks.c +5
-3-kfree (fscontext); -kfree (rootcontext); - } + rc =sb_finish_set_opts (sb); out: +mutex_unlock (&sbsec->lock);return rc; +out_double_mount: + rc = -EINVAL ; + printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different"
Quoted 147 lines
security/selinux/hooks.c +83
-50+ "security settings for (dev %s, type %s)\n", sb->s_id, name); + goto out; } -static int superblock_doinit (struct super_block *sb,void *data) +static void selinux_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) { -struct superblock_security_struct *sbsec = sb->s_security; -struct dentry *root = sb->s_root; -struct inode *inode = root->d_inode; -int rc =0 ; +const struct superblock_security_struct *oldsbsec = oldsb->s_security; +struct superblock_security_struct *newsbsec = newsb->s_security; -mutex_lock (&sbsec->lock); -if (sbsec->initialized) - goto out; +int set_fscontext = (oldsbsec->flags &FSCONTEXT_MNT ); +int set_context = (oldsbsec->flags &CONTEXT_MNT ); +int set_rootcontext = (oldsbsec->flags &ROOTCONTEXT_MNT ); -if (!ss_initialized) { -/* Defer initialization until selinux_complete_init, -after the initial policy is loaded and the security -server is ready to handle calls. */ -spin_lock (&sb_security_lock); -if (list_empty (&sbsec->list)) -list_add (&sbsec->list, &superblock_security_head); -spin_unlock (&sb_security_lock); - goto out; +/* we can't error, we can't save the info, this shouldn't get called +* this early in the boot process. */ +BUG_ON (!ss_initialized); + +/* this might go away sometime down the line if there is a new user +* of clone, but for now, nfs better not get here... */ +BUG_ON (newsbsec->initialized); + +/* how can we clone if the old one wasn't set up?? */ +BUG_ON (!oldsbsec->initialized); + +mutex_lock (&newsbsec->lock); + + newsbsec->flags = oldsbsec->flags; + + newsbsec->sid = oldsbsec->sid; + newsbsec->def_sid = oldsbsec->def_sid; + newsbsec->behavior = oldsbsec->behavior; + +if (set_context) { +u32 sid = oldsbsec->mntpoint_sid; + +if (!set_fscontext) + newsbsec->sid = sid; +if (!set_rootcontext) { +struct inode *newinode = newsb->s_root->d_inode; +struct inode_security_struct *newisec = newinode->i_security; + newisec->sid = sid; + } + newsbsec->mntpoint_sid = sid; } +if (set_rootcontext) { +const struct inode *oldinode = oldsb->s_root->d_inode; +const struct inode_security_struct *oldisec = oldinode->i_security; +struct inode *newinode = newsb->s_root->d_inode; +struct inode_security_struct *newisec = newinode->i_security; -/* Determine the labeling behavior to use for this filesystem type. */ - rc =security_fs_use (sb->s_type->name, &sbsec->behavior, &sbsec->sid); -if (rc) { -printk (KERN_WARNING "%s: security_fs_use(%s) returned %d\n" , - __FUNCTION__, sb->s_type->name, rc); - goto out; + newisec->sid = oldisec->sid; } - rc =try_context_mount (sb, data); -if (rc) +sb_finish_set_opts (newsb); +mutex_unlock (&newsbsec->lock); +} + +/* +* string mount options parsing and call set the sbsec +*/ +static int superblock_doinit (struct super_block *sb,void *data) +{ +char *context =NULL , *defcontext =NULL ; +char *fscontext =NULL , *rootcontext =NULL ; +int rc =0 ; +char *p, *options = data; +/* selinux only know about a fixed number of mount options */ +char *mnt_opts[NUM_SEL_MNT_OPTS ]; +int mnt_opts_flags[NUM_SEL_MNT_OPTS ], num_mnt_opts =0 ; + +if (!data) goto out; -if (sbsec->behavior ==SECURITY_FS_USE_XATTR ) { -/* Make sure that the xattr handler exists and that no -error other than -ENODATA is returned by getxattr on -the root directory. -ENODATA is ok, as this may be -the first boot of the SELinux kernel before we have -assigned xattr values to the filesystem. */ -if (!inode->i_op->getxattr) { -printk (KERN_WARNING "SELinux: (dev %s, type %s) has no " -"xattr support\n" , sb->s_id, sb->s_type->name); - rc = -EOPNOTSUPP ; - goto out; - } - rc = inode->i_op->getxattr (root,XATTR_NAME_SELINUX ,NULL ,0 ); -if (rc <0 && rc != -ENODATA ) { -if (rc == -EOPNOTSUPP ) -printk (KERN_WARNING "SELinux: (dev %s, type " -"%s) has no security xattr handler\n" , - sb->s_id, sb->s_type->name); -else -printk (KERN_WARNING "SELinux: (dev %s, type " -"%s) getxattr errno %d\n" , sb->s_id, - sb->s_type->name, -rc); +/* with the nfs patch this will become a goto out; */ +if (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) { +const char *name = sb->s_type->name; +/* NFS we understand. */ +if (!strcmp (name,"nfs" )) { +struct nfs_mount_data *d = data; + +if (d->version !=NFS_MOUNT_VERSION ) + goto out; + +if (d->context[0 ]) { + context =kstrdup (d->context,GFP_KERNEL ); +if (!context) { + rc = -ENOMEM ; + goto out; + } + } + goto build_flags; + }else goto out; - } } -if (strcmp (sb->s_type->name,"proc" ) ==0 ) - sbsec->proc =1 ; +/* Standard string-based options. */ security/selinux/hooks.c static int try_context_mount(struct super_block *sb, void *data)
Quoted 10 lines
security/selinux/hooks.c +5
-3+while ((p =strsep (&options,"|" )) !=NULL ) { +int token; +substring_t args[MAX_OPT_ARGS ]; - sbsec->initialized =1 ; +if (!*p) +continue ; - if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { - printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknownbehavior\n",
Review
Quoted 133 lines
security/selinux/hooks.c +86
-31- sb->s_id, sb->s_type->name); - } -else { -printk (KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n" , - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1 ]); - } + token =match_token (p, tokens, args); -/* Initialize the root inode. */ - rc =inode_doinit_with_dentry (sb->s_root->d_inode, sb->s_root); +switch (token) { +case Opt_context: +if (context || defcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + context =match_strdup (&args[0 ]); +if (!context) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_fscontext: +if (fscontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + fscontext =match_strdup (&args[0 ]); +if (!fscontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_rootcontext: +if (rootcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + rootcontext =match_strdup (&args[0 ]); +if (!rootcontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_defcontext: +if (context || defcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + defcontext =match_strdup (&args[0 ]); +if (!defcontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +default : + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: unknown mount option\n" ); + goto out_err; -/* Initialize any other inodes associated with the superblock, e.g. -inodes created prior to initial policy load or inodes created -during get_sb by a pseudo filesystem that directly -populates itself. */ -spin_lock (&sbsec->isec_lock); -next_inode: -if (!list_empty (&sbsec->isec_head)) { -struct inode_security_struct *isec = -list_entry (sbsec->isec_head.next, - struct inode_security_struct, list); -struct inode *inode = isec->inode; -spin_unlock (&sbsec->isec_lock); - inode =igrab (inode); -if (inode) { -if (!IS_PRIVATE (inode)) -inode_doinit (inode); -iput (inode); } -spin_lock (&sbsec->isec_lock); -list_del_init (&isec->list); - goto next_inode; } -spin_unlock (&sbsec->isec_lock); + +build_flags: +if (fscontext) { + mnt_opts[num_mnt_opts] = fscontext; + mnt_opts_flags[num_mnt_opts++] =FSCONTEXT_MNT ; + } +if (context) { + mnt_opts[num_mnt_opts] = context; + mnt_opts_flags[num_mnt_opts++] =CONTEXT_MNT ; + } +if (rootcontext) { + mnt_opts[num_mnt_opts] = rootcontext; + mnt_opts_flags[num_mnt_opts++] =ROOTCONTEXT_MNT ; + } +if (defcontext) { + mnt_opts[num_mnt_opts] = defcontext; + mnt_opts_flags[num_mnt_opts++] =DEFCONTEXT_MNT ; + } + out: -mutex_unlock (&sbsec->lock); + rc =selinux_set_mnt_opts (sb, mnt_opts, mnt_opts_flags, num_mnt_opts); +out_err: +kfree (context); +kfree (defcontext); +kfree (fscontext); +kfree (rootcontext);return rc; }@@ -4800,6 +5038,9 @@ static struct security_operations selinux_ops = { .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, + .sb_get_mnt_opts = selinux_get_mnt_opts, + .sb_set_mnt_opts = selinux_set_mnt_opts, + .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, .inode_alloc_security = selinux_inode_alloc_security, .inode_free_security = selinux_inode_free_security,(quoted diff) +0
-0
b/security/selinux/include/objsec.hQuoted 14 lines
index 642a9fd..4138a80 100644
security/selinux/include/objsec.h +1
-0@@ -65,6 +65,7 @@ struct superblock_security_struct {u32 mntpoint_sid;/* SECURITY_FS_USE_MNTPOINT context for files */ unsigned int behavior;/* labeling behavior */ unsigned char initialized;/* initialization flag */ +unsigned char flags;/* which mount options were specified */ unsigned char proc;/* proc fs */ struct mutex lock;struct list_head isec_head;
Quoted 17 lines
Quoted 3 lines
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected]with
Quoted 1 line
the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Casey Schaufler
[email protected]
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 8 lines · Casey Schaufler
Quoted 6 lines · --- Stephen Smalley
Quoted 5 lines · Eric Paris
Adds
security_get_sb_mnt_opts,security_set_sb_mnt_opts, andsecurity_clont_sb_mnt_optsto the LSM and to SELinux. This will allow filesystems to directly own and control all of their mount options if they so choose.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Signed-off-by Eric Paris <[email protected]>Shouldn't this get cross posted to the LSM list?
Yes, I was reminded of that yesterday and will do so today.
Quoted 1,060 lines
Quoted 1,041 lines
Quoted 8 lines
---
include/linux/security.h | 36 ++ security/dummy.c | 26 ++ security/security.c | 20 + security/selinux/hooks.c | 749++++++++++++++++++++++++-------------
Quoted 58 lines
security/selinux/include/objsec.h | 1 + 5 files changed, 578 insertions(+), 254 deletions(-)include/linux/security.h +29
-0@@ -34,6 +34,12 @@#include <linux/xfrm.h> #include <net/flow.h> +/* only a char in selinux superblock security struct flags */ +#define FSCONTEXT_MNT 0x01 +#define CONTEXT_MNT 0x02 +#define ROOTCONTEXT_MNT 0x04 +#define DEFCONTEXT_MNT 0x08 +/* * Bounding set */ @@ -261,6 +267,22 @@ struct request_sock;* Update module state after a successful pivot. * @old_nd contains the nameidata structure for the old root. * @new_nd contains the nameidata structure for the new root. +* @sb_get_mnt_opts: +* Get the security relevant mount options used for a superblock +* @sb the superblock to get security mount options from +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_set_mnt_opts: +* Set the security relevant mount options used for a superblock +* @sb the superblock to set security mount options for +* @mount_options array for pointers to mount options +* @mount_flags array of ints specifying what each mount options is +* @num_opts number of options in the arrays +* @sb_clone_mnt_opts: +* Copy all security options from a given superblock to another +* @oldsb old superblock which contain information to clone +* @newsb new superblock which needs filled in * * Security hooks for inode operations. * @@ -1242,6 +1264,13 @@ struct security_operations { struct nameidata * new_nd);void (*sb_post_pivotroot) (struct nameidata * old_nd,struct nameidata * new_nd); +int (*sb_get_mnt_opts) (const struct super_block *sb, +char ***mount_options,int **flags, +int *num_opts); +int (*sb_set_mnt_opts) (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void (*sb_clone_mnt_opts) (const struct super_block *oldsb, +struct super_block *newsb);int (*inode_alloc_security) (struct inode *inode);void (*inode_free_security) (struct inode *inode);include/linux/security.h void security_sb_post_mountroot(void); · line 1528
Quoted 1 line
include/linux/security.h +0
-0@@ -1499,6 +1528,13 @@ void security_sb_post_mountroot(void); void security_sb_post_addmount(struct vfsmount *mnt, struct nameidata
*mountpoint_nd);include/linux/security.h void security_sb_post_mountroot(void); · line 1529
Quoted 1 line
include/linux/security.h +0
-0int security_sb_pivotroot(struct nameidata *old_nd, struct nameidata
*new_nd);include/linux/security.h void security_sb_post_mountroot(void); · line 1530
Quoted 1 line
include/linux/security.h +0
-0void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata
*new_nd);include/linux/security.h void security_sb_post_mountroot(void); · line 1531
Quoted 1 line
include/linux/security.h +1
-0+int security_sb_get_mnt_opts(const struct super_block *sb, char***mount_options,
security/dummy.c static void dummy_sb_post_pivotroot (struct nameidata
Quoted 14 lines
include/linux/security.h +6
-0+ int **flags, int *num_opts); +int security_sb_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts); +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb); +int security_inode_alloc (struct inode *inode);void security_inode_free (struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir,security/dummy.c +0
-0@@ -245,6 +245,29 @@ static void dummy_sb_post_pivotroot (struct nameidata
*old_nd, struct nameidatasecurity/dummy.c static void dummy_sb_post_pivotroot (struct nameidata · line 248
Quoted 4 lines
security/dummy.c +1
-0return ; } +static int dummy_sb_get_mnt_opts(const struct super_block *sb, char***mount_options,
security/dummy.c static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata
Quoted 9 lines
security/dummy.c +9
-0+ int **flags, int *num_opts) +{ + *mount_options =NULL ; + *flags =NULL ; + *num_opts =0 ; +return 0 ; +} + +static int dummy_sb_set_mnt_opts(struct super_block *sb, char**mount_options,
security/dummy.c void security_fixup_ops (struct security_operations
Quoted 17 lines
security/dummy.c +13
-0+ int *flags, int num_opts) +{ + if (unlikely(num_opts)) + return -EOPNOTSUPP; +return 0 ; +} + +static void dummy_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ +return ; +} +static int dummy_inode_alloc_security (struct inode *inode) {return 0 ;@@ -998,6 +1021,9 @@ void security_fixup_ops (struct security_operations*ops)
security/security.c void security_sb_post_pivotroot(struct nameidata
Quoted 14 lines
security/dummy.c +3
-0set_to_dummy_if_null (ops, sb_post_addmount);set_to_dummy_if_null (ops, sb_pivotroot);set_to_dummy_if_null (ops, sb_post_pivotroot); +set_to_dummy_if_null (ops, sb_get_mnt_opts); +set_to_dummy_if_null (ops, sb_set_mnt_opts); +set_to_dummy_if_null (ops, sb_clone_mnt_opts);set_to_dummy_if_null (ops, inode_alloc_security);set_to_dummy_if_null (ops, inode_free_security);set_to_dummy_if_null (ops, inode_init_security);security/security.c +0
-0@@ -308,6 +308,26 @@ void security_sb_post_pivotroot(struct nameidata
*old_nd, struct nameidata*new_Quoted 92 lines
security/security.c +20
-0security_ops->sb_post_pivotroot (old_nd, new_nd); } +int security_sb_get_mnt_opts (const struct super_block *sb, +char ***mount_options, +int **flags,int *num_opts) +{ +return security_ops->sb_get_mnt_opts (sb, mount_options, flags, num_opts); +} + +int security_sb_set_mnt_opts (struct super_block *sb, +char **mount_options, +int *flags,int num_opts) +{ +return security_ops->sb_set_mnt_opts (sb, mount_options, flags, num_opts); +} + +void security_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) +{ + security_ops->sb_clone_mnt_opts (oldsb, newsb); +} +int security_inode_alloc (struct inode *inode) { inode->i_security =NULL ;security/selinux/hooks.c +30
-11@@ -82,6 +82,8 @@#define XATTR_SELINUX_SUFFIX "selinux"#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX +#define NUM_SEL_MNT_OPTS 4 +extern unsigned int policydb_loaded_version;extern int selinux_nlmsg_lookup (u16 sclass,u16 nlmsg_type,u32 *perm);extern int selinux_compat_net;@@ -321,8 +323,8 @@ enum { Opt_error =-1 , Opt_context =1 , Opt_fscontext =2 , - Opt_defcontext =4 , - Opt_rootcontext = 8, + Opt_defcontext =3 , + Opt_rootcontext = 4, }; static match_table_t tokens = {@@ -366,150 +368,318 @@ static int may_context_mount_inode_relabel(u32 sid,return rc; } -static int try_context_mount (struct super_block *sb,void *data) +static int sb_finish_set_opts (struct super_block *sb) { -char *context =NULL , *defcontext =NULL ; -char *fscontext =NULL , *rootcontext =NULL ; -const char *name; -u32 sid; -int alloc =0 , rc =0 , seen =0 ; -struct task_security_struct *tsec = current->security;struct superblock_security_struct *sbsec = sb->s_security; +struct dentry *root = sb->s_root; +struct inode *root_inode = root->d_inode; +int rc =0 ; -if (!data) - goto out; +if (sbsec->behavior ==SECURITY_FS_USE_XATTR ) { +/* Make sure that the xattr handler exists and that no +error other than -ENODATA is returned by getxattr on +the root directory. -ENODATA is ok, as this may be +the first boot of the SELinux kernel before we have +assigned xattr values to the filesystem. */ +if (!root_inode->i_op->getxattr) { +printk (KERN_WARNING "SELinux: (dev %s, type %s) has no " +"xattr support\n" , sb->s_id, sb->s_type->name); + rc = -EOPNOTSUPP ; + goto out; + } + rc = root_inode->i_op->getxattr (root,XATTR_NAME_SELINUX ,NULL ,0 ); +if (rc <0 && rc != -ENODATA ) { +if (rc == -EOPNOTSUPP ) +printk (KERN_WARNING "SELinux: (dev %s, type " +"%s) has no security xattr handler\n" , + sb->s_id, sb->s_type->name); +else +printk (KERN_WARNING "SELinux: (dev %s, type " +"%s) getxattr errno %d\n" , sb->s_id, + sb->s_type->name, -rc);security/selinux/hooks.c static int may_context_mount_inode_relabel(u32 sid, · line 407
Quoted 10 lines
security/selinux/hooks.c +6
-2+ goto out; + } + } - name = sb->s_type->name; + sbsec->initialized =1 ; -if (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) { + if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { + printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknownbehavior\n",
Quoted 242 lines
security/selinux/hooks.c +133
-96+ sb->s_id, sb->s_type->name); + } +else { +printk (KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n" , + sb->s_id, sb->s_type->name, + labeling_behaviors[sbsec->behavior-1 ]); + } -/* NFS we understand. */ -if (!strcmp (name,"nfs" )) { -struct nfs_mount_data *d = data; +/* Initialize the root inode. */ + rc =inode_doinit_with_dentry (root_inode, root); -if (d->version <NFS_MOUNT_VERSION ) - goto out; +/* Initialize any other inodes associated with the superblock, e.g. +inodes created prior to initial policy load or inodes created +during get_sb by a pseudo filesystem that directly +populates itself. */ +spin_lock (&sbsec->isec_lock); +next_inode: +if (!list_empty (&sbsec->isec_head)) { +struct inode_security_struct *isec = +list_entry (sbsec->isec_head.next, + struct inode_security_struct, list); +struct inode *inode = isec->inode; +spin_unlock (&sbsec->isec_lock); + inode =igrab (inode); +if (inode) { +if (!IS_PRIVATE (inode)) +inode_doinit (inode); +iput (inode); + } +spin_lock (&sbsec->isec_lock); +list_del_init (&isec->list); + goto next_inode; + } +spin_unlock (&sbsec->isec_lock); +out: +return rc; +} -if (d->context[0 ]) { - context = d->context; - seen |= Opt_context; - } - }else - goto out; +/* +* This function should allow an FS to ask what it's mount security +* options were so it can use those later for submounts, displaying +* mount options, or whatever. +*/ +static int selinux_get_mnt_opts (const struct super_block *sb, +char ***mount_options,int **mnt_opts_flags, +int *num_opts) +{ +int rc =0 , i; +struct superblock_security_struct *sbsec = sb->s_security; +char *context =NULL ; +u32 len; +char tmp; - }else { -/* Standard string-based options. */ -char *p, *options = data; + *num_opts =0 ; + *mount_options =NULL ; + *mnt_opts_flags =NULL ; -while ((p =strsep (&options,"|" )) !=NULL ) { -int token; -substring_t args[MAX_OPT_ARGS ]; +if (!sbsec->initialized) +return -EINVAL ; -if (!*p) -continue ; +if (!ss_initialized) +return -EINVAL ; - token =match_token (p, tokens, args); +/* +* if we ever use sbsec flags for anything other than tracking mount +* settings this is going to need a mask +*/ + tmp = sbsec->flags; +/* count the number of mount options for this sb */ +for (i =0 ; i <8 ; i++) { +if (tmp &0x01 ) + (*num_opts)++; + tmp >>=1 ; + } -switch (token) { -case Opt_context: -if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - context =match_strdup (&args[0 ]); -if (!context) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_context; -break ; + *mount_options =kcalloc (*num_opts,sizeof (char *),GFP_ATOMIC ); +if (!*mount_options) { + rc = -ENOMEM ; + goto out_free; + } -case Opt_fscontext: -if (seen & Opt_fscontext) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - fscontext =match_strdup (&args[0 ]); -if (!fscontext) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_fscontext; -break ; + *mnt_opts_flags =kcalloc (*num_opts,sizeof (int ),GFP_ATOMIC ); +if (!*mnt_opts_flags) { + rc = -ENOMEM ; + goto out_free; + } -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 ; + i =0 ; +if (sbsec->flags &FSCONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =FSCONTEXT_MNT ; + } +if (sbsec->flags &CONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->mntpoint_sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =CONTEXT_MNT ; + } +if (sbsec->flags &DEFCONTEXT_MNT ) { + rc =security_sid_to_context (sbsec->def_sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =DEFCONTEXT_MNT ; + } +if (sbsec->flags &ROOTCONTEXT_MNT ) { +struct inode *root = sbsec->sb->s_root->d_inode; +struct inode_security_struct *isec = root->i_security; -case Opt_defcontext: -if (sbsec->behavior !=SECURITY_FS_USE_XATTR ) { - rc = -EINVAL ; -printk (KERN_WARNING "SELinux: " -"defcontext option is invalid " -"for this filesystem type\n" ); - goto out_free; - } -if (seen & (Opt_context|Opt_defcontext)) { - rc = -EINVAL ; - printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); - goto out_free; - } - defcontext =match_strdup (&args[0 ]); -if (!defcontext) { - rc = -ENOMEM ; - goto out_free; - } -if (!alloc) - alloc =1 ; - seen |= Opt_defcontext; -break ; + rc =security_sid_to_context (isec->sid, &context, &len); +if (rc) + goto out_free; + (*mount_options)[i] = context; + (*mnt_opts_flags)[i++] =ROOTCONTEXT_MNT ; + } -default : - rc = -EINVAL ; -printk (KERN_WARNING "SELinux: unknown mount " -"option\n" ); - goto out_free; +BUG_ON (i != *num_opts); - } - } - } +return 0 ; + +out_free: +/* don't leak context string if security_sid_to_context had an error */ +if (*mount_options && i) +for (; i >0 ; i--) +kfree ((*mount_options)[i-1 ]); +kfree (*mount_options); + *mount_options =NULL ; +kfree (*mnt_opts_flags); + *mnt_opts_flags =NULL ; + *num_opts =0 ; +return rc; +} + +static int bad_option (struct superblock_security_struct *sbsec,char flag, +u32 old_sid,u32 new_sid) +{ +/* check if the old mount command had the same options */ +if (sbsec->initialized) +if (!(sbsec->flags & flag) || + (old_sid != new_sid)) +return 1 ; +security/selinux/hooks.c static int may_context_mount_inode_relabel(u32 sid,
Quoted 10 lines
security/selinux/hooks.c +10
-0+/* check if we were passed the same options twice, +* aka someone passed context=a,context=b +*/ +if (!sbsec->initialized) +if (sbsec->flags & flag) +return 1 ; +return 0 ; +} +/* +* Allow filesystems with binary mount data to explicitly set mount point labeling.
security/selinux/hooks.c static int try_context_mount(struct super_block
Quoted 132 lines
security/selinux/hooks.c +109
-9+*/ +int selinux_set_mnt_opts (struct super_block *sb,char **mount_options, +int *flags,int num_opts) +{ +int rc =0 , i; +struct task_security_struct *tsec = current->security; +struct superblock_security_struct *sbsec = sb->s_security; +const char *name = sb->s_type->name; +struct inode *inode = sbsec->sb->s_root->d_inode; +struct inode_security_struct *root_isec = inode->i_security; +u32 fscontext_sid =0 , context_sid =0 , rootcontext_sid =0 ; +u32 defcontext_sid =0 ; + +mutex_lock (&sbsec->lock); -if (!seen) +if (!ss_initialized) { +if (!num_opts) { +/* Defer initialization until selinux_complete_init, +after the initial policy is loaded and the security +server is ready to handle calls. */ +spin_lock (&sb_security_lock); +if (list_empty (&sbsec->list)) +list_add (&sbsec->list, &superblock_security_head); +spin_unlock (&sb_security_lock); + goto out; + } + rc = -EINVAL ; +printk (KERN_WARNING "Unable to set superblock options before " +"the security server is initialized\n" ); goto out; + } -/* sets the context of the superblock for the fs being mounted. */ -if (fscontext) { - rc =security_context_to_sid (fscontext,strlen (fscontext), &sid); +/* +* parse the mount options, check if they are valid sids. +* also check if someone is trying to mount the same sb more +* than once with different security options. +*/ +for (i =0 ; i < num_opts; i++) { +u32 sid; + rc =security_context_to_sid (mount_options[i], +strlen (mount_options[i]), &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; + mount_options[i], sb->s_id, name, rc); + goto out; } +switch (flags[i]) { +case FSCONTEXT_MNT : + fscontext_sid = sid; + +if (bad_option (sbsec,FSCONTEXT_MNT , sbsec->sid, + fscontext_sid)) + goto out_double_mount; + + sbsec->flags |=FSCONTEXT_MNT ; +break ; +case CONTEXT_MNT : + context_sid = sid; + +if (bad_option (sbsec,CONTEXT_MNT , sbsec->mntpoint_sid, + context_sid)) + goto out_double_mount; + + sbsec->flags |=CONTEXT_MNT ; +break ; +case ROOTCONTEXT_MNT : + rootcontext_sid = sid; + +if (bad_option (sbsec,ROOTCONTEXT_MNT , root_isec->sid, + rootcontext_sid)) + goto out_double_mount; + + sbsec->flags |=ROOTCONTEXT_MNT ; + +break ; +case DEFCONTEXT_MNT : + defcontext_sid = sid; + +if (bad_option (sbsec,DEFCONTEXT_MNT , sbsec->def_sid, + defcontext_sid)) + goto out_double_mount; - rc =may_context_mount_sb_relabel (sid, sbsec, tsec); + sbsec->flags |=DEFCONTEXT_MNT ; + +break ; +default : + rc = -EINVAL ; + goto out; + } + } + +if (sbsec->initialized) { +/* previously mounted with options, but not on this attempt? */ +if (sbsec->flags && !num_opts) + goto out_double_mount; + rc =0 ; + goto out; + } + +if (strcmp (sb->s_type->name,"proc" ) ==0 ) + sbsec->proc =1 ; + +/* Determine the labeling behavior to use for this filesystem type. */ + rc =security_fs_use (sb->s_type->name, &sbsec->behavior, &sbsec->sid); +if (rc) { +printk (KERN_WARNING "%s: security_fs_use(%s) returned %d\n" , + __FUNCTION__, sb->s_type->name, rc); + goto out; + } + +/* sets the context of the superblock for the fs being mounted. */ +if (fscontext_sid) { + + rc =may_context_mount_sb_relabel (fscontext_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; - sbsec->sid = sid; + sbsec->sid = fscontext_sid; }/* @@ -517,182 +687,250 @@ static int try_context_mount(struct super_block*sb, void *data)
Quoted 97 lines
security/selinux/hooks.c +28
-49* 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) { -printk (KERN_WARNING "SELinux: security_context_to_sid" -"(%s) failed for (dev %s, type %s) errno=%d\n" , - context, sb->s_id, name, rc); - goto out_free; - } - -if (!fscontext) { - rc =may_context_mount_sb_relabel (sid, sbsec, tsec); +if (context_sid) { +if (!fscontext_sid) { + rc =may_context_mount_sb_relabel (context_sid, sbsec, tsec);if (rc) - goto out_free; - sbsec->sid = sid; + goto out; + sbsec->sid = context_sid; }else { - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); + rc =may_context_mount_inode_relabel (context_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; } - sbsec->mntpoint_sid = sid; +if (!rootcontext_sid) + rootcontext_sid = context_sid; + sbsec->mntpoint_sid = context_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; - } - - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); +if (rootcontext_sid) { + rc =may_context_mount_inode_relabel (rootcontext_sid, sbsec, tsec);if (rc) - goto out_free; + goto out; - isec->sid = sid; - isec->initialized =1 ; + root_isec->sid = rootcontext_sid; + root_isec->initialized =1 ; } -if (defcontext) { - rc =security_context_to_sid (defcontext,strlen (defcontext), &sid); -if (rc) { -printk (KERN_WARNING "SELinux: security_context_to_sid" -"(%s) failed for (dev %s, type %s) errno=%d\n" , - defcontext, sb->s_id, name, rc); - goto out_free; +if (defcontext_sid) { +if (sbsec->behavior !=SECURITY_FS_USE_XATTR ) { + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: defcontext option is " +"invalid for this filesystem type\n" ); + goto out; } -if (sid == sbsec->def_sid) - goto out_free; - - rc =may_context_mount_inode_relabel (sid, sbsec, tsec); -if (rc) - goto out_free; +if (defcontext_sid != sbsec->def_sid) { + rc =may_context_mount_inode_relabel (defcontext_sid, + sbsec, tsec); +if (rc) + goto out; + } - sbsec->def_sid = sid; + sbsec->def_sid = defcontext_sid; } -out_free: -if (alloc) { -kfree (context); -kfree (defcontext);security/selinux/hooks.c static int try_context_mount(struct super_block *sb, void *data)
Quoted 10 lines
security/selinux/hooks.c +5
-3-kfree (fscontext); -kfree (rootcontext); - } + rc =sb_finish_set_opts (sb); out: +mutex_unlock (&sbsec->lock);return rc; +out_double_mount: + rc = -EINVAL ; + printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different"
Quoted 147 lines
security/selinux/hooks.c +83
-50+ "security settings for (dev %s, type %s)\n", sb->s_id, name); + goto out; } -static int superblock_doinit (struct super_block *sb,void *data) +static void selinux_sb_clone_mnt_opts (const struct super_block *oldsb, +struct super_block *newsb) { -struct superblock_security_struct *sbsec = sb->s_security; -struct dentry *root = sb->s_root; -struct inode *inode = root->d_inode; -int rc =0 ; +const struct superblock_security_struct *oldsbsec = oldsb->s_security; +struct superblock_security_struct *newsbsec = newsb->s_security; -mutex_lock (&sbsec->lock); -if (sbsec->initialized) - goto out; +int set_fscontext = (oldsbsec->flags &FSCONTEXT_MNT ); +int set_context = (oldsbsec->flags &CONTEXT_MNT ); +int set_rootcontext = (oldsbsec->flags &ROOTCONTEXT_MNT ); -if (!ss_initialized) { -/* Defer initialization until selinux_complete_init, -after the initial policy is loaded and the security -server is ready to handle calls. */ -spin_lock (&sb_security_lock); -if (list_empty (&sbsec->list)) -list_add (&sbsec->list, &superblock_security_head); -spin_unlock (&sb_security_lock); - goto out; +/* we can't error, we can't save the info, this shouldn't get called +* this early in the boot process. */ +BUG_ON (!ss_initialized); + +/* this might go away sometime down the line if there is a new user +* of clone, but for now, nfs better not get here... */ +BUG_ON (newsbsec->initialized); + +/* how can we clone if the old one wasn't set up?? */ +BUG_ON (!oldsbsec->initialized); + +mutex_lock (&newsbsec->lock); + + newsbsec->flags = oldsbsec->flags; + + newsbsec->sid = oldsbsec->sid; + newsbsec->def_sid = oldsbsec->def_sid; + newsbsec->behavior = oldsbsec->behavior; + +if (set_context) { +u32 sid = oldsbsec->mntpoint_sid; + +if (!set_fscontext) + newsbsec->sid = sid; +if (!set_rootcontext) { +struct inode *newinode = newsb->s_root->d_inode; +struct inode_security_struct *newisec = newinode->i_security; + newisec->sid = sid; + } + newsbsec->mntpoint_sid = sid; } +if (set_rootcontext) { +const struct inode *oldinode = oldsb->s_root->d_inode; +const struct inode_security_struct *oldisec = oldinode->i_security; +struct inode *newinode = newsb->s_root->d_inode; +struct inode_security_struct *newisec = newinode->i_security; -/* Determine the labeling behavior to use for this filesystem type. */ - rc =security_fs_use (sb->s_type->name, &sbsec->behavior, &sbsec->sid); -if (rc) { -printk (KERN_WARNING "%s: security_fs_use(%s) returned %d\n" , - __FUNCTION__, sb->s_type->name, rc); - goto out; + newisec->sid = oldisec->sid; } - rc =try_context_mount (sb, data); -if (rc) +sb_finish_set_opts (newsb); +mutex_unlock (&newsbsec->lock); +} + +/* +* string mount options parsing and call set the sbsec +*/ +static int superblock_doinit (struct super_block *sb,void *data) +{ +char *context =NULL , *defcontext =NULL ; +char *fscontext =NULL , *rootcontext =NULL ; +int rc =0 ; +char *p, *options = data; +/* selinux only know about a fixed number of mount options */ +char *mnt_opts[NUM_SEL_MNT_OPTS ]; +int mnt_opts_flags[NUM_SEL_MNT_OPTS ], num_mnt_opts =0 ; + +if (!data) goto out; -if (sbsec->behavior ==SECURITY_FS_USE_XATTR ) { -/* Make sure that the xattr handler exists and that no -error other than -ENODATA is returned by getxattr on -the root directory. -ENODATA is ok, as this may be -the first boot of the SELinux kernel before we have -assigned xattr values to the filesystem. */ -if (!inode->i_op->getxattr) { -printk (KERN_WARNING "SELinux: (dev %s, type %s) has no " -"xattr support\n" , sb->s_id, sb->s_type->name); - rc = -EOPNOTSUPP ; - goto out; - } - rc = inode->i_op->getxattr (root,XATTR_NAME_SELINUX ,NULL ,0 ); -if (rc <0 && rc != -ENODATA ) { -if (rc == -EOPNOTSUPP ) -printk (KERN_WARNING "SELinux: (dev %s, type " -"%s) has no security xattr handler\n" , - sb->s_id, sb->s_type->name); -else -printk (KERN_WARNING "SELinux: (dev %s, type " -"%s) getxattr errno %d\n" , sb->s_id, - sb->s_type->name, -rc); +/* with the nfs patch this will become a goto out; */ +if (sb->s_type->fs_flags &FS_BINARY_MOUNTDATA ) { +const char *name = sb->s_type->name; +/* NFS we understand. */ +if (!strcmp (name,"nfs" )) { +struct nfs_mount_data *d = data; + +if (d->version !=NFS_MOUNT_VERSION ) + goto out; + +if (d->context[0 ]) { + context =kstrdup (d->context,GFP_KERNEL ); +if (!context) { + rc = -ENOMEM ; + goto out; + } + } + goto build_flags; + }else goto out; - } } -if (strcmp (sb->s_type->name,"proc" ) ==0 ) - sbsec->proc =1 ; +/* Standard string-based options. */ security/selinux/hooks.c static int try_context_mount(struct super_block *sb, void *data)
Quoted 10 lines
security/selinux/hooks.c +5
-3+while ((p =strsep (&options,"|" )) !=NULL ) { +int token; +substring_t args[MAX_OPT_ARGS ]; - sbsec->initialized =1 ; +if (!*p) +continue ; - if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) { - printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknownbehavior\n",
Review
Quoted 133 lines
security/selinux/hooks.c +86
-31- sb->s_id, sb->s_type->name); - } -else { -printk (KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n" , - sb->s_id, sb->s_type->name, - labeling_behaviors[sbsec->behavior-1 ]); - } + token =match_token (p, tokens, args); -/* Initialize the root inode. */ - rc =inode_doinit_with_dentry (sb->s_root->d_inode, sb->s_root); +switch (token) { +case Opt_context: +if (context || defcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + context =match_strdup (&args[0 ]); +if (!context) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_fscontext: +if (fscontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + fscontext =match_strdup (&args[0 ]); +if (!fscontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_rootcontext: +if (rootcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + rootcontext =match_strdup (&args[0 ]); +if (!rootcontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +case Opt_defcontext: +if (context || defcontext) { + rc = -EINVAL ; + printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); + goto out_err; + } + defcontext =match_strdup (&args[0 ]); +if (!defcontext) { + rc = -ENOMEM ; + goto out_err; + } +break ; + +default : + rc = -EINVAL ; +printk (KERN_WARNING "SELinux: unknown mount option\n" ); + goto out_err; -/* Initialize any other inodes associated with the superblock, e.g. -inodes created prior to initial policy load or inodes created -during get_sb by a pseudo filesystem that directly -populates itself. */ -spin_lock (&sbsec->isec_lock); -next_inode: -if (!list_empty (&sbsec->isec_head)) { -struct inode_security_struct *isec = -list_entry (sbsec->isec_head.next, - struct inode_security_struct, list); -struct inode *inode = isec->inode; -spin_unlock (&sbsec->isec_lock); - inode =igrab (inode); -if (inode) { -if (!IS_PRIVATE (inode)) -inode_doinit (inode); -iput (inode); } -spin_lock (&sbsec->isec_lock); -list_del_init (&isec->list); - goto next_inode; } -spin_unlock (&sbsec->isec_lock); + +build_flags: +if (fscontext) { + mnt_opts[num_mnt_opts] = fscontext; + mnt_opts_flags[num_mnt_opts++] =FSCONTEXT_MNT ; + } +if (context) { + mnt_opts[num_mnt_opts] = context; + mnt_opts_flags[num_mnt_opts++] =CONTEXT_MNT ; + } +if (rootcontext) { + mnt_opts[num_mnt_opts] = rootcontext; + mnt_opts_flags[num_mnt_opts++] =ROOTCONTEXT_MNT ; + } +if (defcontext) { + mnt_opts[num_mnt_opts] = defcontext; + mnt_opts_flags[num_mnt_opts++] =DEFCONTEXT_MNT ; + } + out: -mutex_unlock (&sbsec->lock); + rc =selinux_set_mnt_opts (sb, mnt_opts, mnt_opts_flags, num_mnt_opts); +out_err: +kfree (context); +kfree (defcontext); +kfree (fscontext); +kfree (rootcontext);return rc; }@@ -4800,6 +5038,9 @@ static struct security_operations selinux_ops = { .sb_statfs = selinux_sb_statfs, .sb_mount = selinux_mount, .sb_umount = selinux_umount, + .sb_get_mnt_opts = selinux_get_mnt_opts, + .sb_set_mnt_opts = selinux_set_mnt_opts, + .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, .inode_alloc_security = selinux_inode_alloc_security, .inode_free_security = selinux_inode_free_security,(quoted diff) +0
-0
b/security/selinux/include/objsec.hQuoted 14 lines
index 642a9fd..4138a80 100644
security/selinux/include/objsec.h +1
-0@@ -65,6 +65,7 @@ struct superblock_security_struct {u32 mntpoint_sid;/* SECURITY_FS_USE_MNTPOINT context for files */ unsigned int behavior;/* labeling behavior */ unsigned char initialized;/* initialization flag */ +unsigned char flags;/* which mount options were specified */ unsigned char proc;/* proc fs */ struct mutex lock;struct list_head isec_head;Quoted 17 lines
Quoted 3 lines
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected]with
Quoted 1 line
the words "unsubscribe selinux" without quotes as the message.
Signature · 8 lines
Stephen Smalley National Security Agency -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.
Quoted 2 lines
Casey Schaufler
[email protected]
--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.