diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2016-06-09 16:34:02 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2016-06-23 16:41:57 -0400 |
commit | a2982cc922c3068783eb9a1f77a5626a1ec36a1f (patch) | |
tree | 61ccc6ad01f8804d5290ae4565ba8d4238bf648a | |
parent | 3ee690143c3c99f6c0e83f08ff17556890bc6027 (diff) |
vfs: Generalize filesystem nodev handling.
Introduce a function may_open_dev that tests MNT_NODEV and a new
superblock flab SB_I_NODEV. Use this new function in all of the
places where MNT_NODEV was previously tested.
Add the new SB_I_NODEV s_iflag to proc, sysfs, and mqueuefs as those
filesystems should never support device nodes, and a simple superblock
flags makes that very hard to get wrong. With SB_I_NODEV set if any
device nodes somehow manage to show up on on a filesystem those
device nodes will be unopenable.
Acked-by: Seth Forshee <seth.forshee@canonical.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | fs/block_dev.c | 2 | ||||
-rw-r--r-- | fs/kernfs/mount.c | 4 | ||||
-rw-r--r-- | fs/namei.c | 8 | ||||
-rw-r--r-- | fs/proc/inode.c | 4 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | ipc/mqueue.c | 2 |
6 files changed, 15 insertions, 7 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 71ccab1d22c6..30b8d568203a 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1857,7 +1857,7 @@ struct block_device *lookup_bdev(const char *pathname) | |||
1857 | if (!S_ISBLK(inode->i_mode)) | 1857 | if (!S_ISBLK(inode->i_mode)) |
1858 | goto fail; | 1858 | goto fail; |
1859 | error = -EACCES; | 1859 | error = -EACCES; |
1860 | if (path.mnt->mnt_flags & MNT_NODEV) | 1860 | if (!may_open_dev(&path)) |
1861 | goto fail; | 1861 | goto fail; |
1862 | error = -ENOMEM; | 1862 | error = -ENOMEM; |
1863 | bdev = bd_acquire(inode); | 1863 | bdev = bd_acquire(inode); |
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 1443df670260..b3d73ad52b22 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c | |||
@@ -152,8 +152,8 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic) | |||
152 | struct dentry *root; | 152 | struct dentry *root; |
153 | 153 | ||
154 | info->sb = sb; | 154 | info->sb = sb; |
155 | /* Userspace would break if executables appear on sysfs */ | 155 | /* Userspace would break if executables or devices appear on sysfs */ |
156 | sb->s_iflags |= SB_I_NOEXEC; | 156 | sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; |
157 | sb->s_blocksize = PAGE_SIZE; | 157 | sb->s_blocksize = PAGE_SIZE; |
158 | sb->s_blocksize_bits = PAGE_SHIFT; | 158 | sb->s_blocksize_bits = PAGE_SHIFT; |
159 | sb->s_magic = magic; | 159 | sb->s_magic = magic; |
diff --git a/fs/namei.c b/fs/namei.c index 6a82fb7e2127..757a32725d92 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2881,6 +2881,12 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
2881 | } | 2881 | } |
2882 | EXPORT_SYMBOL(vfs_create); | 2882 | EXPORT_SYMBOL(vfs_create); |
2883 | 2883 | ||
2884 | bool may_open_dev(const struct path *path) | ||
2885 | { | ||
2886 | return !(path->mnt->mnt_flags & MNT_NODEV) && | ||
2887 | !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV); | ||
2888 | } | ||
2889 | |||
2884 | static int may_open(struct path *path, int acc_mode, int flag) | 2890 | static int may_open(struct path *path, int acc_mode, int flag) |
2885 | { | 2891 | { |
2886 | struct dentry *dentry = path->dentry; | 2892 | struct dentry *dentry = path->dentry; |
@@ -2899,7 +2905,7 @@ static int may_open(struct path *path, int acc_mode, int flag) | |||
2899 | break; | 2905 | break; |
2900 | case S_IFBLK: | 2906 | case S_IFBLK: |
2901 | case S_IFCHR: | 2907 | case S_IFCHR: |
2902 | if (path->mnt->mnt_flags & MNT_NODEV) | 2908 | if (!may_open_dev(path)) |
2903 | return -EACCES; | 2909 | return -EACCES; |
2904 | /*FALLTHRU*/ | 2910 | /*FALLTHRU*/ |
2905 | case S_IFIFO: | 2911 | case S_IFIFO: |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index f4817efb25a6..a5b2c33745b7 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -466,8 +466,8 @@ int proc_fill_super(struct super_block *s, void *data, int silent) | |||
466 | if (!proc_parse_options(data, ns)) | 466 | if (!proc_parse_options(data, ns)) |
467 | return -EINVAL; | 467 | return -EINVAL; |
468 | 468 | ||
469 | /* User space would break if executables appear on proc */ | 469 | /* User space would break if executables or devices appear on proc */ |
470 | s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC; | 470 | s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV; |
471 | s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; | 471 | s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; |
472 | s->s_blocksize = 1024; | 472 | s->s_blocksize = 1024; |
473 | s->s_blocksize_bits = 10; | 473 | s->s_blocksize_bits = 10; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 9eef64f23a75..e05983170d23 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1327,6 +1327,7 @@ struct mm_struct; | |||
1327 | /* sb->s_iflags */ | 1327 | /* sb->s_iflags */ |
1328 | #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ | 1328 | #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ |
1329 | #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ | 1329 | #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ |
1330 | #define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */ | ||
1330 | 1331 | ||
1331 | /* sb->s_iflags to limit user namespace mounts */ | 1332 | /* sb->s_iflags to limit user namespace mounts */ |
1332 | #define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ | 1333 | #define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ |
@@ -1602,6 +1603,7 @@ extern int vfs_whiteout(struct inode *, struct dentry *); | |||
1602 | */ | 1603 | */ |
1603 | extern void inode_init_owner(struct inode *inode, const struct inode *dir, | 1604 | extern void inode_init_owner(struct inode *inode, const struct inode *dir, |
1604 | umode_t mode); | 1605 | umode_t mode); |
1606 | extern bool may_open_dev(const struct path *path); | ||
1605 | /* | 1607 | /* |
1606 | * VFS FS_IOC_FIEMAP helper definitions. | 1608 | * VFS FS_IOC_FIEMAP helper definitions. |
1607 | */ | 1609 | */ |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 5bdd50de7d05..0b13ace266f2 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
@@ -307,7 +307,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) | |||
307 | struct inode *inode; | 307 | struct inode *inode; |
308 | struct ipc_namespace *ns = sb->s_fs_info; | 308 | struct ipc_namespace *ns = sb->s_fs_info; |
309 | 309 | ||
310 | sb->s_iflags |= SB_I_NOEXEC; | 310 | sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; |
311 | sb->s_blocksize = PAGE_SIZE; | 311 | sb->s_blocksize = PAGE_SIZE; |
312 | sb->s_blocksize_bits = PAGE_SHIFT; | 312 | sb->s_blocksize_bits = PAGE_SHIFT; |
313 | sb->s_magic = MQUEUE_MAGIC; | 313 | sb->s_magic = MQUEUE_MAGIC; |