diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2014-11-18 23:38:21 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-10 21:32:15 -0500 |
| commit | bd9b51e79cb0b8bc00a7e0076a4a8963ca4a797c (patch) | |
| tree | bee3cc60bfbe1d7f837826bf495c0cf92747404b | |
| parent | 1f55a6ec940fb45e3edaa52b6e9fc40cf8e18dcb (diff) | |
make default ->i_fop have ->open() fail with ENXIO
As it is, default ->i_fop has NULL ->open() (along with all other methods).
The only case where it matters is reopening (via procfs symlink) a file that
didn't get its ->f_op from ->i_fop - anything else will have ->i_fop assigned
to something sane (default would fail on read/write/ioctl/etc.).
Unfortunately, such case exists - alloc_file() users, especially
anon_get_file() ones. There we have tons of opened files of very different
kinds sharing the same inode. As the result, attempt to reopen those via
procfs succeeds and you get a descriptor you can't do anything with.
Moreover, in case of sockets we set ->i_fop that will only be used
on such reopen attempts - and put a failing ->open() into it to make sure
those do not succeed.
It would be simpler to put such ->open() into default ->i_fop and leave
it unchanged both for anon inode (as we do anyway) and for socket ones. Result:
* everything going through do_dentry_open() works as it used to
* sock_no_open() kludge is gone
* attempts to reopen anon-inode files fail as they really ought to
* ditto for aio_private_file()
* ditto for perfmon - this one actually tried to imitate sock_no_open()
trick, but failed to set ->i_fop, so in the current tree reopens succeed and
yield completely useless descriptor. Intent clearly had been to fail with
-ENXIO on such reopens; now it actually does.
* everything else that used alloc_file() keeps working - it has ->i_fop
set for its inodes anyway
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | arch/ia64/kernel/perfmon.c | 10 | ||||
| -rw-r--r-- | fs/inode.c | 11 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 | ||||
| -rw-r--r-- | net/Makefile | 2 | ||||
| -rw-r--r-- | net/nonet.c | 26 | ||||
| -rw-r--r-- | net/socket.c | 19 |
6 files changed, 8 insertions, 61 deletions
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 5845ffea67c3..ac4528f5acd1 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c | |||
| @@ -2145,22 +2145,12 @@ doit: | |||
| 2145 | return 0; | 2145 | return 0; |
| 2146 | } | 2146 | } |
| 2147 | 2147 | ||
| 2148 | static int | ||
| 2149 | pfm_no_open(struct inode *irrelevant, struct file *dontcare) | ||
| 2150 | { | ||
| 2151 | DPRINT(("pfm_no_open called\n")); | ||
| 2152 | return -ENXIO; | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | |||
| 2156 | |||
| 2157 | static const struct file_operations pfm_file_ops = { | 2148 | static const struct file_operations pfm_file_ops = { |
| 2158 | .llseek = no_llseek, | 2149 | .llseek = no_llseek, |
| 2159 | .read = pfm_read, | 2150 | .read = pfm_read, |
| 2160 | .write = pfm_write, | 2151 | .write = pfm_write, |
| 2161 | .poll = pfm_poll, | 2152 | .poll = pfm_poll, |
| 2162 | .unlocked_ioctl = pfm_ioctl, | 2153 | .unlocked_ioctl = pfm_ioctl, |
| 2163 | .open = pfm_no_open, /* special open code to disallow open via /proc */ | ||
| 2164 | .fasync = pfm_fasync, | 2154 | .fasync = pfm_fasync, |
| 2165 | .release = pfm_close, | 2155 | .release = pfm_close, |
| 2166 | .flush = pfm_flush | 2156 | .flush = pfm_flush |
diff --git a/fs/inode.c b/fs/inode.c index 26753ba7b6d6..5b83ef7fc8d5 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -114,6 +114,11 @@ int proc_nr_inodes(struct ctl_table *table, int write, | |||
| 114 | } | 114 | } |
| 115 | #endif | 115 | #endif |
| 116 | 116 | ||
| 117 | static int no_open(struct inode *inode, struct file *file) | ||
| 118 | { | ||
| 119 | return -ENXIO; | ||
| 120 | } | ||
| 121 | |||
| 117 | /** | 122 | /** |
| 118 | * inode_init_always - perform inode structure intialisation | 123 | * inode_init_always - perform inode structure intialisation |
| 119 | * @sb: superblock inode belongs to | 124 | * @sb: superblock inode belongs to |
| @@ -125,7 +130,7 @@ int proc_nr_inodes(struct ctl_table *table, int write, | |||
| 125 | int inode_init_always(struct super_block *sb, struct inode *inode) | 130 | int inode_init_always(struct super_block *sb, struct inode *inode) |
| 126 | { | 131 | { |
| 127 | static const struct inode_operations empty_iops; | 132 | static const struct inode_operations empty_iops; |
| 128 | static const struct file_operations empty_fops; | 133 | static const struct file_operations no_open_fops = {.open = no_open}; |
| 129 | struct address_space *const mapping = &inode->i_data; | 134 | struct address_space *const mapping = &inode->i_data; |
| 130 | 135 | ||
| 131 | inode->i_sb = sb; | 136 | inode->i_sb = sb; |
| @@ -133,7 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
| 133 | inode->i_flags = 0; | 138 | inode->i_flags = 0; |
| 134 | atomic_set(&inode->i_count, 1); | 139 | atomic_set(&inode->i_count, 1); |
| 135 | inode->i_op = &empty_iops; | 140 | inode->i_op = &empty_iops; |
| 136 | inode->i_fop = &empty_fops; | 141 | inode->i_fop = &no_open_fops; |
| 137 | inode->__i_nlink = 1; | 142 | inode->__i_nlink = 1; |
| 138 | inode->i_opflags = 0; | 143 | inode->i_opflags = 0; |
| 139 | i_uid_write(inode, 0); | 144 | i_uid_write(inode, 0); |
| @@ -1801,7 +1806,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) | |||
| 1801 | } else if (S_ISFIFO(mode)) | 1806 | } else if (S_ISFIFO(mode)) |
| 1802 | inode->i_fop = &pipefifo_fops; | 1807 | inode->i_fop = &pipefifo_fops; |
| 1803 | else if (S_ISSOCK(mode)) | 1808 | else if (S_ISSOCK(mode)) |
| 1804 | inode->i_fop = &bad_sock_fops; | 1809 | ; /* leave it no_open_fops */ |
| 1805 | else | 1810 | else |
| 1806 | printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" | 1811 | printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" |
| 1807 | " inode %s:%lu\n", mode, inode->i_sb->s_id, | 1812 | " inode %s:%lu\n", mode, inode->i_sb->s_id, |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 2beddc284bc2..b37beaf7a3a5 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -2151,7 +2151,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb) | |||
| 2151 | extern int sync_filesystem(struct super_block *); | 2151 | extern int sync_filesystem(struct super_block *); |
| 2152 | extern const struct file_operations def_blk_fops; | 2152 | extern const struct file_operations def_blk_fops; |
| 2153 | extern const struct file_operations def_chr_fops; | 2153 | extern const struct file_operations def_chr_fops; |
| 2154 | extern const struct file_operations bad_sock_fops; | ||
| 2155 | #ifdef CONFIG_BLOCK | 2154 | #ifdef CONFIG_BLOCK |
| 2156 | extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); | 2155 | extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); |
| 2157 | extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); | 2156 | extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); |
diff --git a/net/Makefile b/net/Makefile index 7ed1970074b0..1f6c3e4b36d5 100644 --- a/net/Makefile +++ b/net/Makefile | |||
| @@ -5,8 +5,6 @@ | |||
| 5 | # Rewritten to use lists instead of if-statements. | 5 | # Rewritten to use lists instead of if-statements. |
| 6 | # | 6 | # |
| 7 | 7 | ||
| 8 | obj-y := nonet.o | ||
| 9 | |||
| 10 | obj-$(CONFIG_NET) := socket.o core/ | 8 | obj-$(CONFIG_NET) := socket.o core/ |
| 11 | 9 | ||
| 12 | tmp-$(CONFIG_COMPAT) := compat.o | 10 | tmp-$(CONFIG_COMPAT) := compat.o |
diff --git a/net/nonet.c b/net/nonet.c deleted file mode 100644 index b1a73fda9c12..000000000000 --- a/net/nonet.c +++ /dev/null | |||
| @@ -1,26 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * net/nonet.c | ||
| 3 | * | ||
| 4 | * Dummy functions to allow us to configure network support entirely | ||
| 5 | * out of the kernel. | ||
| 6 | * | ||
| 7 | * Distributed under the terms of the GNU GPL version 2. | ||
| 8 | * Copyright (c) Matthew Wilcox 2003 | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/fs.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | |||
| 17 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare) | ||
| 18 | { | ||
| 19 | return -ENXIO; | ||
| 20 | } | ||
| 21 | |||
| 22 | const struct file_operations bad_sock_fops = { | ||
| 23 | .owner = THIS_MODULE, | ||
| 24 | .open = sock_no_open, | ||
| 25 | .llseek = noop_llseek, | ||
| 26 | }; | ||
diff --git a/net/socket.c b/net/socket.c index fe20c319a0bb..850f6c383342 100644 --- a/net/socket.c +++ b/net/socket.c | |||
| @@ -113,7 +113,6 @@ unsigned int sysctl_net_busy_read __read_mostly; | |||
| 113 | unsigned int sysctl_net_busy_poll __read_mostly; | 113 | unsigned int sysctl_net_busy_poll __read_mostly; |
| 114 | #endif | 114 | #endif |
| 115 | 115 | ||
| 116 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare); | ||
| 117 | static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, | 116 | static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, |
| 118 | unsigned long nr_segs, loff_t pos); | 117 | unsigned long nr_segs, loff_t pos); |
| 119 | static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, | 118 | static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, |
| @@ -151,7 +150,6 @@ static const struct file_operations socket_file_ops = { | |||
| 151 | .compat_ioctl = compat_sock_ioctl, | 150 | .compat_ioctl = compat_sock_ioctl, |
| 152 | #endif | 151 | #endif |
| 153 | .mmap = sock_mmap, | 152 | .mmap = sock_mmap, |
| 154 | .open = sock_no_open, /* special open code to disallow open via /proc */ | ||
| 155 | .release = sock_close, | 153 | .release = sock_close, |
| 156 | .fasync = sock_fasync, | 154 | .fasync = sock_fasync, |
| 157 | .sendpage = sock_sendpage, | 155 | .sendpage = sock_sendpage, |
| @@ -559,23 +557,6 @@ static struct socket *sock_alloc(void) | |||
| 559 | return sock; | 557 | return sock; |
| 560 | } | 558 | } |
| 561 | 559 | ||
| 562 | /* | ||
| 563 | * In theory you can't get an open on this inode, but /proc provides | ||
| 564 | * a back door. Remember to keep it shut otherwise you'll let the | ||
| 565 | * creepy crawlies in. | ||
| 566 | */ | ||
| 567 | |||
| 568 | static int sock_no_open(struct inode *irrelevant, struct file *dontcare) | ||
| 569 | { | ||
| 570 | return -ENXIO; | ||
| 571 | } | ||
| 572 | |||
| 573 | const struct file_operations bad_sock_fops = { | ||
| 574 | .owner = THIS_MODULE, | ||
| 575 | .open = sock_no_open, | ||
| 576 | .llseek = noop_llseek, | ||
| 577 | }; | ||
| 578 | |||
| 579 | /** | 560 | /** |
| 580 | * sock_release - close a socket | 561 | * sock_release - close a socket |
| 581 | * @sock: socket to close | 562 | * @sock: socket to close |
