[Devel] [PATCH RHEL7 COMMIT] ms/make default ->i_fop have ->open() fail with ENXIO

Konstantin Khorenko khorenko at virtuozzo.com
Thu Oct 15 04:04:20 PDT 2015


The commit is pushed to "branch-rh7-3.10.0-229.7.2.vz7.8.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-229.7.2.vz7.8.6
------>
commit ab6784bb6f5bca77caef0e23d07e0b86dd178557
Author: Andrew Vagin <avagin at openvz.org>
Date:   Thu Oct 15 15:04:20 2015 +0400

    ms/make default ->i_fop have ->open() fail with ENXIO
    
    The patch is required for CRIU.
    
    https://jira.sw.ru/browse/PSBM-39834
    
    ML: bd9b51e79cb0b8bc00a7e0076a4a8963ca4a797c
    
    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 at zeniv.linux.org.uk>
    Signed-off-by: Andrew Vagin <avagin at openvz.org>
---
 arch/ia64/kernel/perfmon.c | 10 ----------
 fs/inode.c                 | 12 +++++++++---
 include/linux/fs.h         |  1 -
 net/Makefile               |  2 --
 net/nonet.c                | 26 --------------------------
 net/socket.c               | 19 -------------------
 6 files changed, 9 insertions(+), 61 deletions(-)

diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 9ea25fc..4334a96 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2145,22 +2145,12 @@ doit:
 	return 0;
 }
 
-static int
-pfm_no_open(struct inode *irrelevant, struct file *dontcare)
-{
-	DPRINT(("pfm_no_open called\n"));
-	return -ENXIO;
-}
-
-
-
 static const struct file_operations pfm_file_ops = {
 	.llseek		= no_llseek,
 	.read		= pfm_read,
 	.write		= pfm_write,
 	.poll		= pfm_poll,
 	.unlocked_ioctl = pfm_ioctl,
-	.open		= pfm_no_open,	/* special open code to disallow open via /proc */
 	.fasync		= pfm_fasync,
 	.release	= pfm_close,
 	.flush		= pfm_flush
diff --git a/fs/inode.c b/fs/inode.c
index 960cd15..6c27178 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -121,6 +121,11 @@ int proc_nr_inodes(ctl_table *table, int write,
 }
 #endif
 
+static int no_open(struct inode *inode, struct file *file)
+{
+	return -ENXIO;
+}
+
 /**
  * inode_init_always - perform inode structure intialisation
  * @sb: superblock inode belongs to
@@ -131,7 +136,8 @@ int proc_nr_inodes(ctl_table *table, int write,
  */
 int inode_init_always(struct super_block *sb, struct inode *inode)
 {
-	static const struct file_operations empty_fops;
+	static const struct inode_operations empty_iops;
+	static const struct file_operations no_open_fops = {.open = no_open};
 	struct address_space *const mapping = &inode->i_data;
 
 	inode->i_sb = sb;
@@ -139,7 +145,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
 	inode->i_flags = 0;
 	atomic_set(&inode->i_count, 1);
 	inode->i_op = &empty_iops;
-	inode->i_fop = &empty_fops;
+	inode->i_fop = &no_open_fops;
 	inode->__i_nlink = 1;
 	inode->i_opflags = 0;
 	i_uid_write(inode, 0);
@@ -1900,7 +1906,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
 	} else if (S_ISFIFO(mode))
 		inode->i_fop = &pipefifo_fops;
 	else if (S_ISSOCK(mode))
-		inode->i_fop = &bad_sock_fops;
+		;	/* leave it no_open_fops */
 	else
 		printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
 				  " inode %s:%lu\n", mode, inode->i_sb->s_id,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f410c54..507e720 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2437,7 +2437,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
 extern int sync_filesystem(struct super_block *);
 extern const struct file_operations def_blk_fops;
 extern const struct file_operations def_chr_fops;
-extern const struct file_operations bad_sock_fops;
 #ifdef CONFIG_BLOCK
 extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
 extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
diff --git a/net/Makefile b/net/Makefile
index 9492e8c..2c98197 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -5,8 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-obj-y	:= nonet.o
-
 obj-$(CONFIG_NET)		:= socket.o core/
 
 tmp-$(CONFIG_COMPAT) 		:= compat.o
diff --git a/net/nonet.c b/net/nonet.c
deleted file mode 100644
index b1a73fd..0000000
--- a/net/nonet.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * net/nonet.c
- *
- * Dummy functions to allow us to configure network support entirely
- * out of the kernel.
- *
- * Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) Matthew Wilcox 2003
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
-{
-	return -ENXIO;
-}
-
-const struct file_operations bad_sock_fops = {
-	.owner = THIS_MODULE,
-	.open = sock_no_open,
-	.llseek = noop_llseek,
-};
diff --git a/net/socket.c b/net/socket.c
index df73b9d..59b0780 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -113,7 +113,6 @@ unsigned int sysctl_net_busy_read __read_mostly;
 unsigned int sysctl_net_busy_poll __read_mostly;
 #endif
 
-static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
 static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
 			 unsigned long nr_segs, loff_t pos);
 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 = {
 	.compat_ioctl = compat_sock_ioctl,
 #endif
 	.mmap =		sock_mmap,
-	.open =		sock_no_open,	/* special open code to disallow open via /proc */
 	.release =	sock_close,
 	.fasync =	sock_fasync,
 	.sendpage =	sock_sendpage,
@@ -559,23 +557,6 @@ static struct socket *sock_alloc(void)
 	return sock;
 }
 
-/*
- *	In theory you can't get an open on this inode, but /proc provides
- *	a back door. Remember to keep it shut otherwise you'll let the
- *	creepy crawlies in.
- */
-
-static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
-{
-	return -ENXIO;
-}
-
-const struct file_operations bad_sock_fops = {
-	.owner = THIS_MODULE,
-	.open = sock_no_open,
-	.llseek = noop_llseek,
-};
-
 /**
  *	sock_release	-	close a socket
  *	@sock: socket to close



More information about the Devel mailing list