[patch 2/2] VFS: allow filesystem to override mknod capability checks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Miklos Szeredi <[email protected]>

Add a new super block flag, that results in the VFS not checking if
the current process has enough privileges to do an mknod().

If this flag is set, all mounts for this super block will have the
"nodev" flag implied.

This is needed on filesystems, where an unprivileged user may be able
to create a device node, without causing security problems.

One such example is "mountlo" a loopback mount utility implemented
with fuse and UML, which runs as an unprivileged userspace process.
In this case the user does in fact have the right to create device
nodes within the filesystem image, as long as the user has write
access to the image.  Since the filesystem is mounted with "nodev",
adding device nodes is not a security concern.

Signed-off-by: Miklos Szeredi <[email protected]>
---

Index: linux/fs/namei.c
===================================================================
--- linux.orig/fs/namei.c	2007-09-24 13:52:17.000000000 +0200
+++ linux/fs/namei.c	2007-09-24 13:54:57.000000000 +0200
@@ -1617,7 +1617,7 @@ int may_open(struct nameidata *nd, int a
 	if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
 	    	flag &= ~O_TRUNC;
 	} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-		if (nd->mnt->mnt_flags & MNT_NODEV)
+		if (IS_MNT_NODEV(nd->mnt))
 			return -EACCES;
 
 		flag &= ~O_TRUNC;
@@ -1920,7 +1920,8 @@ int vfs_mknod(struct inode *dir, struct 
 	if (error)
 		return error;
 
-	if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
+	if (!(dir->i_sb->s_flags & MS_MKNOD_NOCAP) &&
+	    (S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
 		return -EPERM;
 
 	if (!dir->i_op || !dir->i_op->mknod)
Index: linux/include/linux/fs.h
===================================================================
--- linux.orig/include/linux/fs.h	2007-09-24 13:52:17.000000000 +0200
+++ linux/include/linux/fs.h	2007-09-24 13:54:57.000000000 +0200
@@ -130,6 +130,8 @@ extern int dir_notify_enable;
 #define MS_SETUSER	(1<<23) /* set mnt_uid to current user */
 #define MS_NOMNT	(1<<24) /* don't allow unprivileged submounts */
 #define MS_KERNMOUNT	(1<<25) /* this is a kern_mount call */
+#define MS_MKNOD_NOCAP	(1<<26) /* no capability check in mknod,
+				   implies "nodev" */
 #define MS_ACTIVE	(1<<30)
 #define MS_NOUSER	(1<<31)
 
@@ -190,6 +192,10 @@ extern int dir_notify_enable;
 #define IS_SWAPFILE(inode)	((inode)->i_flags & S_SWAPFILE)
 #define IS_PRIVATE(inode)	((inode)->i_flags & S_PRIVATE)
 
+#define IS_MNT_NODEV(mnt)	(((mnt)->mnt_flags & MNT_NODEV) || \
+				    ((mnt)->mnt_sb->s_flags & MS_MKNOD_NOCAP))
+
+
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
 
Index: linux/drivers/mtd/mtdsuper.c
===================================================================
--- linux.orig/drivers/mtd/mtdsuper.c	2007-09-24 13:52:17.000000000 +0200
+++ linux/drivers/mtd/mtdsuper.c	2007-09-24 13:54:57.000000000 +0200
@@ -194,7 +194,7 @@ int get_sb_mtd(struct file_system_type *
 	if (!S_ISBLK(nd.dentry->d_inode->i_mode))
 		goto out;
 
-	if (nd.mnt->mnt_flags & MNT_NODEV) {
+	if (IS_MNT_NODEV(nd.mnt)) {
 		ret = -EACCES;
 		goto out;
 	}
Index: linux/fs/block_dev.c
===================================================================
--- linux.orig/fs/block_dev.c	2007-09-24 13:52:17.000000000 +0200
+++ linux/fs/block_dev.c	2007-09-24 13:54:57.000000000 +0200
@@ -1408,7 +1408,7 @@ struct block_device *lookup_bdev(const c
 	if (!S_ISBLK(inode->i_mode))
 		goto fail;
 	error = -EACCES;
-	if (nd.mnt->mnt_flags & MNT_NODEV)
+	if (IS_MNT_NODEV(nd.mnt))
 		goto fail;
 	error = -ENOMEM;
 	bdev = bd_acquire(inode);
Index: linux/fs/namespace.c
===================================================================
--- linux.orig/fs/namespace.c	2007-09-24 13:52:17.000000000 +0200
+++ linux/fs/namespace.c	2007-09-24 13:54:57.000000000 +0200
@@ -431,7 +431,6 @@ static int show_vfsmnt(struct seq_file *
 	};
 	static struct proc_fs_info mnt_info[] = {
 		{ MNT_NOSUID, ",nosuid" },
-		{ MNT_NODEV, ",nodev" },
 		{ MNT_NOEXEC, ",noexec" },
 		{ MNT_NOATIME, ",noatime" },
 		{ MNT_NODIRATIME, ",nodiratime" },
@@ -459,6 +458,8 @@ static int show_vfsmnt(struct seq_file *
 		if (mnt->mnt_flags & fs_infop->flag)
 			seq_puts(m, fs_infop->str);
 	}
+	if (IS_MNT_NODEV(mnt))
+		seq_puts(m, ",nodev");
 	if (mnt->mnt_flags & MNT_USER)
 		seq_printf(m, ",user=%i", mnt->mnt_uid);
 	if (mnt->mnt_sb->s_op->show_options)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux