forked from mirrors/linux
		
	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>
This commit is contained in:
		
							parent
							
								
									1f55a6ec94
								
							
						
					
					
						commit
						bd9b51e79c
					
				
					 6 changed files with 8 additions and 61 deletions
				
			
		| 
						 | 
					@ -2145,22 +2145,12 @@ pfm_close(struct inode *inode, struct file *filp)
 | 
				
			||||||
	return 0;
 | 
						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 = {
 | 
					static const struct file_operations pfm_file_ops = {
 | 
				
			||||||
	.llseek		= no_llseek,
 | 
						.llseek		= no_llseek,
 | 
				
			||||||
	.read		= pfm_read,
 | 
						.read		= pfm_read,
 | 
				
			||||||
	.write		= pfm_write,
 | 
						.write		= pfm_write,
 | 
				
			||||||
	.poll		= pfm_poll,
 | 
						.poll		= pfm_poll,
 | 
				
			||||||
	.unlocked_ioctl = pfm_ioctl,
 | 
						.unlocked_ioctl = pfm_ioctl,
 | 
				
			||||||
	.open		= pfm_no_open,	/* special open code to disallow open via /proc */
 | 
					 | 
				
			||||||
	.fasync		= pfm_fasync,
 | 
						.fasync		= pfm_fasync,
 | 
				
			||||||
	.release	= pfm_close,
 | 
						.release	= pfm_close,
 | 
				
			||||||
	.flush		= pfm_flush
 | 
						.flush		= pfm_flush
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								fs/inode.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								fs/inode.c
									
									
									
									
									
								
							| 
						 | 
					@ -114,6 +114,11 @@ int proc_nr_inodes(struct ctl_table *table, int write,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int no_open(struct inode *inode, struct file *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return -ENXIO;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * inode_init_always - perform inode structure intialisation
 | 
					 * inode_init_always - perform inode structure intialisation
 | 
				
			||||||
 * @sb: superblock inode belongs to
 | 
					 * @sb: superblock inode belongs to
 | 
				
			||||||
| 
						 | 
					@ -125,7 +130,7 @@ int proc_nr_inodes(struct ctl_table *table, int write,
 | 
				
			||||||
int inode_init_always(struct super_block *sb, struct inode *inode)
 | 
					int inode_init_always(struct super_block *sb, struct inode *inode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static const struct inode_operations empty_iops;
 | 
						static const struct inode_operations empty_iops;
 | 
				
			||||||
	static const struct file_operations empty_fops;
 | 
						static const struct file_operations no_open_fops = {.open = no_open};
 | 
				
			||||||
	struct address_space *const mapping = &inode->i_data;
 | 
						struct address_space *const mapping = &inode->i_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inode->i_sb = sb;
 | 
						inode->i_sb = sb;
 | 
				
			||||||
| 
						 | 
					@ -133,7 +138,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
 | 
				
			||||||
	inode->i_flags = 0;
 | 
						inode->i_flags = 0;
 | 
				
			||||||
	atomic_set(&inode->i_count, 1);
 | 
						atomic_set(&inode->i_count, 1);
 | 
				
			||||||
	inode->i_op = &empty_iops;
 | 
						inode->i_op = &empty_iops;
 | 
				
			||||||
	inode->i_fop = &empty_fops;
 | 
						inode->i_fop = &no_open_fops;
 | 
				
			||||||
	inode->__i_nlink = 1;
 | 
						inode->__i_nlink = 1;
 | 
				
			||||||
	inode->i_opflags = 0;
 | 
						inode->i_opflags = 0;
 | 
				
			||||||
	i_uid_write(inode, 0);
 | 
						i_uid_write(inode, 0);
 | 
				
			||||||
| 
						 | 
					@ -1801,7 +1806,7 @@ void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
 | 
				
			||||||
	} else if (S_ISFIFO(mode))
 | 
						} else if (S_ISFIFO(mode))
 | 
				
			||||||
		inode->i_fop = &pipefifo_fops;
 | 
							inode->i_fop = &pipefifo_fops;
 | 
				
			||||||
	else if (S_ISSOCK(mode))
 | 
						else if (S_ISSOCK(mode))
 | 
				
			||||||
		inode->i_fop = &bad_sock_fops;
 | 
							;	/* leave it no_open_fops */
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
 | 
							printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
 | 
				
			||||||
				  " inode %s:%lu\n", mode, inode->i_sb->s_id,
 | 
									  " inode %s:%lu\n", mode, inode->i_sb->s_id,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2151,7 +2151,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
 | 
				
			||||||
extern int sync_filesystem(struct super_block *);
 | 
					extern int sync_filesystem(struct super_block *);
 | 
				
			||||||
extern const struct file_operations def_blk_fops;
 | 
					extern const struct file_operations def_blk_fops;
 | 
				
			||||||
extern const struct file_operations def_chr_fops;
 | 
					extern const struct file_operations def_chr_fops;
 | 
				
			||||||
extern const struct file_operations bad_sock_fops;
 | 
					 | 
				
			||||||
#ifdef CONFIG_BLOCK
 | 
					#ifdef CONFIG_BLOCK
 | 
				
			||||||
extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
 | 
					extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
 | 
				
			||||||
extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
 | 
					extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,6 @@
 | 
				
			||||||
# Rewritten to use lists instead of if-statements.
 | 
					# Rewritten to use lists instead of if-statements.
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-y	:= nonet.o
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
obj-$(CONFIG_NET)		:= socket.o core/
 | 
					obj-$(CONFIG_NET)		:= socket.o core/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tmp-$(CONFIG_COMPAT) 		:= compat.o
 | 
					tmp-$(CONFIG_COMPAT) 		:= compat.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								net/nonet.c
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								net/nonet.c
									
									
									
									
									
								
							| 
						 | 
					@ -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,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										19
									
								
								net/socket.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								net/socket.c
									
									
									
									
									
								
							| 
						 | 
					@ -113,7 +113,6 @@ unsigned int sysctl_net_busy_read __read_mostly;
 | 
				
			||||||
unsigned int sysctl_net_busy_poll __read_mostly;
 | 
					unsigned int sysctl_net_busy_poll __read_mostly;
 | 
				
			||||||
#endif
 | 
					#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,
 | 
					static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
 | 
				
			||||||
			 unsigned long nr_segs, loff_t pos);
 | 
								 unsigned long nr_segs, loff_t pos);
 | 
				
			||||||
static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
 | 
					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,
 | 
						.compat_ioctl = compat_sock_ioctl,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	.mmap =		sock_mmap,
 | 
						.mmap =		sock_mmap,
 | 
				
			||||||
	.open =		sock_no_open,	/* special open code to disallow open via /proc */
 | 
					 | 
				
			||||||
	.release =	sock_close,
 | 
						.release =	sock_close,
 | 
				
			||||||
	.fasync =	sock_fasync,
 | 
						.fasync =	sock_fasync,
 | 
				
			||||||
	.sendpage =	sock_sendpage,
 | 
						.sendpage =	sock_sendpage,
 | 
				
			||||||
| 
						 | 
					@ -559,23 +557,6 @@ static struct socket *sock_alloc(void)
 | 
				
			||||||
	return sock;
 | 
						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_release	-	close a socket
 | 
				
			||||||
 *	@sock: socket to close
 | 
					 *	@sock: socket to close
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue