Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da71aeb6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* '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
parents 9af6b056 f9c3a380
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 */

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

struct nfs_string;

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

	struct security_mnt_opts lsm_opts;
};

/* client.c */
+62 −2
Original line number Diff line number Diff line
@@ -684,8 +684,9 @@ 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");
@@ -693,6 +694,20 @@ static int nfs_parse_mount_options(char *raw,
	}
	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;
@@ -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;
@@ -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;
@@ -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)
@@ -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;
@@ -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);
@@ -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;

@@ -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)
@@ -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:
+2 −2
Original line number Diff line number Diff line
@@ -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;
	}
+74 −25
Original line number Diff line number Diff line
@@ -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;
@@ -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
 *
@@ -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.
 *
@@ -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,
@@ -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);
@@ -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,
@@ -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);
@@ -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
@@ -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;
}
@@ -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)
{
+13 −10
Original line number Diff line number Diff line
@@ -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;
}
@@ -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;
}
@@ -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;
@@ -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);
Loading