Skip to content

Commit

Permalink
LSM/SELinux: Interfaces to allow FS to control mount options
Browse files Browse the repository at this point in the history
Introduce new LSM interfaces to allow an FS to deal with their own mount
options.  This includes a new string parsing function exported from the
LSM that an FS can use to get a security data blob and a new security
data blob.  This is particularly useful for an FS which uses binary
mount data, like NFS, which does not pass strings into the vfs to be
handled by the loaded LSM.  Also fix a BUG() in both SELinux and SMACK
when dealing with binary mount data.  If the binary mount data is less
than one page the copy_page() in security_sb_copy_data() can cause an
illegal page fault and boom.  Remove all NFSisms from the SELinux code
since they were broken by past NFS changes.

Signed-off-by: Eric Paris <eparis@redhat.com>
Acked-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: James Morris <jmorris@namei.org>
  • Loading branch information
Eric Paris authored and James Morris committed Mar 5, 2008
1 parent 29e8c3c commit e000752
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 134 deletions.
4 changes: 2 additions & 2 deletions fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,12 +870,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
if (!mnt)
goto out;

if (data) {
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
secdata = alloc_secdata();
if (!secdata)
goto out_mnt;

error = security_sb_copy_data(type, data, secdata);
error = security_sb_copy_data(data, secdata);
if (error)
goto out_free_secdata;
}
Expand Down
99 changes: 74 additions & 25 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@
#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

extern unsigned securebits;

struct ctl_table;
Expand Down Expand Up @@ -114,6 +108,32 @@ struct request_sock;

#ifdef CONFIG_SECURITY

struct security_mnt_opts {
char **mnt_opts;
int *mnt_opts_flags;
int num_mnt_opts;
};

static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
{
opts->mnt_opts = NULL;
opts->mnt_opts_flags = NULL;
opts->num_mnt_opts = 0;
}

static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
{
int i;
if (opts->mnt_opts)
for(i = 0; i < opts->num_mnt_opts; i++)
kfree(opts->mnt_opts[i]);
kfree(opts->mnt_opts);
opts->mnt_opts = NULL;
kfree(opts->mnt_opts_flags);
opts->mnt_opts_flags = NULL;
opts->num_mnt_opts = 0;
}

/**
* struct security_operations - main security structure
*
Expand Down Expand Up @@ -262,19 +282,19 @@ struct request_sock;
* @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
* @opts binary data structure containing all lsm mount data
* @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
* @opts binary data structure containing all lsm mount data
* @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
* @sb_parse_opts_str:
* Parse a string of security data filling in the opts structure
* @options string containing all mount options known by the LSM
* @opts binary data structure usable by the LSM
*
* Security hooks for inode operations.
*
Expand Down Expand Up @@ -1238,8 +1258,7 @@ struct security_operations {

int (*sb_alloc_security) (struct super_block * sb);
void (*sb_free_security) (struct super_block * sb);
int (*sb_copy_data)(struct file_system_type *type,
void *orig, void *copy);
int (*sb_copy_data)(char *orig, char *copy);
int (*sb_kern_mount) (struct super_block *sb, void *data);
int (*sb_statfs) (struct dentry *dentry);
int (*sb_mount) (char *dev_name, struct nameidata * nd,
Expand All @@ -1257,12 +1276,12 @@ struct security_operations {
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);
struct security_mnt_opts *opts);
int (*sb_set_mnt_opts) (struct super_block *sb,
struct security_mnt_opts *opts);
void (*sb_clone_mnt_opts) (const struct super_block *oldsb,
struct super_block *newsb);
int (*sb_parse_opts_str) (char *options, struct security_mnt_opts *opts);

int (*inode_alloc_security) (struct inode *inode);
void (*inode_free_security) (struct inode *inode);
Expand Down Expand Up @@ -1507,7 +1526,7 @@ int security_bprm_check(struct linux_binprm *bprm);
int security_bprm_secureexec(struct linux_binprm *bprm);
int security_sb_alloc(struct super_block *sb);
void security_sb_free(struct super_block *sb);
int security_sb_copy_data(struct file_system_type *type, void *orig, void *copy);
int security_sb_copy_data(char *orig, char *copy);
int security_sb_kern_mount(struct super_block *sb, void *data);
int security_sb_statfs(struct dentry *dentry);
int security_sb_mount(char *dev_name, struct nameidata *nd,
Expand All @@ -1520,12 +1539,12 @@ void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *d
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);
int security_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts);
int security_sb_set_mnt_opts(struct super_block *sb, struct security_mnt_opts *opts);
void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts);

int security_inode_alloc(struct inode *inode);
void security_inode_free(struct inode *inode);
Expand Down Expand Up @@ -1635,6 +1654,16 @@ int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);

#else /* CONFIG_SECURITY */
struct security_mnt_opts {
};

static inline void security_init_mnt_opts(struct security_mnt_opts *opts)
{
}

static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
{
}

/*
* This is the default capabilities functionality. Most of these functions
Expand Down Expand Up @@ -1762,8 +1791,7 @@ static inline int security_sb_alloc (struct super_block *sb)
static inline void security_sb_free (struct super_block *sb)
{ }

static inline int security_sb_copy_data (struct file_system_type *type,
void *orig, void *copy)
static inline int security_sb_copy_data (char *orig, char *copy)
{
return 0;
}
Expand Down Expand Up @@ -1819,6 +1847,27 @@ static inline int security_sb_pivotroot (struct nameidata *old_nd,
static inline void security_sb_post_pivotroot (struct nameidata *old_nd,
struct nameidata *new_nd)
{ }
static inline int security_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts)
{
security_init_mnt_opts(opts);
return 0;
}

static inline int security_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
return 0;
}

static inline void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{ }

static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
return 0;
}

static inline int security_inode_alloc (struct inode *inode)
{
Expand Down
23 changes: 13 additions & 10 deletions security/dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,7 @@ static void dummy_sb_free_security (struct super_block *sb)
return;
}

static int dummy_sb_copy_data (struct file_system_type *type,
void *orig, void *copy)
static int dummy_sb_copy_data (char *orig, char *copy)
{
return 0;
}
Expand Down Expand Up @@ -245,19 +244,17 @@ static void dummy_sb_post_pivotroot (struct nameidata *old_nd, struct nameidata
return;
}

static int dummy_sb_get_mnt_opts(const struct super_block *sb, char ***mount_options,
int **flags, int *num_opts)
static int dummy_sb_get_mnt_opts(const struct super_block *sb,
struct security_mnt_opts *opts)
{
*mount_options = NULL;
*flags = NULL;
*num_opts = 0;
security_init_mnt_opts(opts);
return 0;
}

static int dummy_sb_set_mnt_opts(struct super_block *sb, char **mount_options,
int *flags, int num_opts)
static int dummy_sb_set_mnt_opts(struct super_block *sb,
struct security_mnt_opts *opts)
{
if (unlikely(num_opts))
if (unlikely(opts->num_mnt_opts))
return -EOPNOTSUPP;
return 0;
}
Expand All @@ -268,6 +265,11 @@ static void dummy_sb_clone_mnt_opts(const struct super_block *oldsb,
return;
}

static int dummy_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
return 0;
}

static int dummy_inode_alloc_security (struct inode *inode)
{
return 0;
Expand Down Expand Up @@ -1028,6 +1030,7 @@ void security_fixup_ops (struct security_operations *ops)
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, sb_parse_opts_str);
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);
Expand Down
23 changes: 15 additions & 8 deletions security/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,11 @@ void security_sb_free(struct super_block *sb)
security_ops->sb_free_security(sb);
}

int security_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
int security_sb_copy_data(char *orig, char *copy)
{
return security_ops->sb_copy_data(type, orig, copy);
return security_ops->sb_copy_data(orig, copy);
}
EXPORT_SYMBOL(security_sb_copy_data);

int security_sb_kern_mount(struct super_block *sb, void *data)
{
Expand Down Expand Up @@ -306,24 +307,30 @@ void security_sb_post_pivotroot(struct nameidata *old_nd, struct nameidata *new_
}

int security_sb_get_mnt_opts(const struct super_block *sb,
char ***mount_options,
int **flags, int *num_opts)
struct security_mnt_opts *opts)
{
return security_ops->sb_get_mnt_opts(sb, mount_options, flags, num_opts);
return security_ops->sb_get_mnt_opts(sb, opts);
}

int security_sb_set_mnt_opts(struct super_block *sb,
char **mount_options,
int *flags, int num_opts)
struct security_mnt_opts *opts)
{
return security_ops->sb_set_mnt_opts(sb, mount_options, flags, num_opts);
return security_ops->sb_set_mnt_opts(sb, opts);
}
EXPORT_SYMBOL(security_sb_set_mnt_opts);

void security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
security_ops->sb_clone_mnt_opts(oldsb, newsb);
}
EXPORT_SYMBOL(security_sb_clone_mnt_opts);

int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
return security_ops->sb_parse_opts_str(options, opts);
}
EXPORT_SYMBOL(security_sb_parse_opts_str);

int security_inode_alloc(struct inode *inode)
{
Expand Down
Loading

0 comments on commit e000752

Please sign in to comment.