aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-11-18 23:38:21 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-12-10 21:32:15 -0500
commitbd9b51e79cb0b8bc00a7e0076a4a8963ca4a797c (patch)
treebee3cc60bfbe1d7f837826bf495c0cf92747404b
parent1f55a6ec940fb45e3edaa52b6e9fc40cf8e18dcb (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.c10
-rw-r--r--fs/inode.c11
-rw-r--r--include/linux/fs.h1
-rw-r--r--net/Makefile2
-rw-r--r--net/nonet.c26
-rw-r--r--net/socket.c19
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
2148static int
2149pfm_no_open(struct inode *irrelevant, struct file *dontcare)
2150{
2151 DPRINT(("pfm_no_open called\n"));
2152 return -ENXIO;
2153}
2154
2155
2156
2157static const struct file_operations pfm_file_ops = { 2148static 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
117static 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,
125int inode_init_always(struct super_block *sb, struct inode *inode) 130int 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)
2151extern int sync_filesystem(struct super_block *); 2151extern int sync_filesystem(struct super_block *);
2152extern const struct file_operations def_blk_fops; 2152extern const struct file_operations def_blk_fops;
2153extern const struct file_operations def_chr_fops; 2153extern const struct file_operations def_chr_fops;
2154extern const struct file_operations bad_sock_fops;
2155#ifdef CONFIG_BLOCK 2154#ifdef CONFIG_BLOCK
2156extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); 2155extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
2157extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); 2156extern 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
8obj-y := nonet.o
9
10obj-$(CONFIG_NET) := socket.o core/ 8obj-$(CONFIG_NET) := socket.o core/
11 9
12tmp-$(CONFIG_COMPAT) := compat.o 10tmp-$(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
17static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
18{
19 return -ENXIO;
20}
21
22const 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;
113unsigned int sysctl_net_busy_poll __read_mostly; 113unsigned int sysctl_net_busy_poll __read_mostly;
114#endif 114#endif
115 115
116static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
117static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 116static 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);
119static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 118static 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
568static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
569{
570 return -ENXIO;
571}
572
573const 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