Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/jmorris/selinux-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6:
  NFS: use new LSM interfaces to explicitly set mount options
  LSM/SELinux: Interfaces to allow FS to control mount options
  • Loading branch information
Linus Torvalds committed Mar 6, 2008
2 parents 9af6b05 + f9c3a38 commit da71aeb
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 136 deletions.
3 changes: 3 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

#include <linux/mount.h>
#include <linux/security.h>

struct nfs_string;

Expand Down Expand Up @@ -57,6 +58,8 @@ struct nfs_parsed_mount_data {
char *export_path;
int protocol;
} nfs_server;

struct security_mnt_opts lsm_opts;
};

/* client.c */
Expand Down
64 changes: 62 additions & 2 deletions fs/nfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,15 +684,30 @@ static void nfs_parse_server_address(char *value,
static int nfs_parse_mount_options(char *raw,
struct nfs_parsed_mount_data *mnt)
{
char *p, *string;
char *p, *string, *secdata;
unsigned short port = 0;
int rc;

if (!raw) {
dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
return 1;
}
dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);

secdata = alloc_secdata();
if (!secdata)
goto out_nomem;

rc = security_sb_copy_data(raw, secdata);
if (rc)
goto out_security_failure;

rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
if (rc)
goto out_security_failure;

free_secdata(secdata);

while ((p = strsep(&raw, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int option, token;
Expand Down Expand Up @@ -1042,7 +1057,10 @@ static int nfs_parse_mount_options(char *raw,
out_nomem:
printk(KERN_INFO "NFS: not enough memory to parse option\n");
return 0;

out_security_failure:
free_secdata(secdata);
printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
return 0;
out_unrec_vers:
printk(KERN_INFO "NFS: unrecognized NFS version number\n");
return 0;
Expand Down Expand Up @@ -1214,6 +1232,33 @@ static int nfs_validate_mount_data(void *options,
args->namlen = data->namlen;
args->bsize = data->bsize;
args->auth_flavors[0] = data->pseudoflavor;

/*
* The legacy version 6 binary mount data from userspace has a
* field used only to transport selinux information into the
* the kernel. To continue to support that functionality we
* have a touch of selinux knowledge here in the NFS code. The
* userspace code converted context=blah to just blah so we are
* converting back to the full string selinux understands.
*/
if (data->context[0]){
#ifdef CONFIG_SECURITY_SELINUX
int rc;
char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
if (!opts_str)
return -ENOMEM;
strcpy(opts_str, "context=");
data->context[NFS_MAX_CONTEXT_LEN] = '\0';
strcat(opts_str, &data->context[0]);
rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts);
kfree(opts_str);
if (rc)
return rc;
#else
return -EINVAL;
#endif
}

break;
default: {
unsigned int len;
Expand Down Expand Up @@ -1476,6 +1521,8 @@ static int nfs_get_sb(struct file_system_type *fs_type,
};
int error;

security_init_mnt_opts(&data.lsm_opts);

/* Validate the mount data */
error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name);
if (error < 0)
Expand Down Expand Up @@ -1515,6 +1562,10 @@ static int nfs_get_sb(struct file_system_type *fs_type,
goto error_splat_super;
}

error = security_sb_set_mnt_opts(s, &data.lsm_opts);
if (error)
goto error_splat_root;

s->s_flags |= MS_ACTIVE;
mnt->mnt_sb = s;
mnt->mnt_root = mntroot;
Expand All @@ -1523,12 +1574,15 @@ static int nfs_get_sb(struct file_system_type *fs_type,
out:
kfree(data.nfs_server.hostname);
kfree(data.mount_server.hostname);
security_free_mnt_opts(&data.lsm_opts);
return error;

out_err_nosb:
nfs_free_server(server);
goto out;

error_splat_root:
dput(mntroot);
error_splat_super:
up_write(&s->s_umount);
deactivate_super(s);
Expand Down Expand Up @@ -1608,6 +1662,9 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
mnt->mnt_sb = s;
mnt->mnt_root = mntroot;

/* clone any lsm security options from the parent to the new sb */
security_sb_clone_mnt_opts(data->sb, s);

dprintk("<-- nfs_xdev_get_sb() = 0\n");
return 0;

Expand Down Expand Up @@ -1850,6 +1907,8 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
};
int error;

security_init_mnt_opts(&data.lsm_opts);

/* Validate the mount data */
error = nfs4_validate_mount_data(raw_data, &data, dev_name);
if (error < 0)
Expand Down Expand Up @@ -1898,6 +1957,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
kfree(data.client_address);
kfree(data.nfs_server.export_path);
kfree(data.nfs_server.hostname);
security_free_mnt_opts(&data.lsm_opts);
return error;

out_free:
Expand Down
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
Loading

0 comments on commit da71aeb

Please sign in to comment.