linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
To: hch@infradead.org, viro@zeniv.linux.org.uk, adilger@sun.com,
	corbet@lwn.net, neilb@suse.de, npiggin@kernel.dk,
	hooanon05@yahoo.co.jp, bfields@fieldses.org, miklos@szeredi.hu
Cc: linux-fsdevel@vger.kernel.org, sfrench@us.ibm.com,
	philippe.deniel@CEA.FR, linux-kernel@vger.kernel.org,
	"Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Subject: [PATCH -V26 12/16] vfs: Add O_PATH open flag
Date: Sun, 30 Jan 2011 00:38:15 +0530	[thread overview]
Message-ID: <1296328099-23263-13-git-send-email-aneesh.kumar@linux.vnet.ibm.com> (raw)
In-Reply-To: <1296328099-23263-1-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

This flag can be used to get a descriptor that is used only
for fetching file attributes. We can get a O_PATH descriptor for even symlink.
A attempt to do any file system operation like read/write/lseek/ioctl will all
fail with EBADF

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
---
 fs/fcntl.c                  |    4 +-
 fs/file_table.c             |   60 +++++++++++++++++++++++++++++++++++++++++++
 fs/namei.c                  |   38 +++++++++++++++++++++++----
 fs/open.c                   |   16 +++++++++--
 include/asm-generic/fcntl.h |    4 +++
 include/linux/file.h        |    2 +
 6 files changed, 113 insertions(+), 11 deletions(-)

diff --git a/fs/fcntl.c b/fs/fcntl.c
index ecc8b39..ba4b564 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -808,14 +808,14 @@ static int __init fcntl_init(void)
 	 * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
 	 * is defined as O_NONBLOCK on some platforms and not on others.
 	 */
-	BUILD_BUG_ON(18 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
+	BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
 		O_RDONLY	| O_WRONLY	| O_RDWR	|
 		O_CREAT		| O_EXCL	| O_NOCTTY	|
 		O_TRUNC		| O_APPEND	| /* O_NONBLOCK	| */
 		__O_SYNC	| O_DSYNC	| FASYNC	|
 		O_DIRECT	| O_LARGEFILE	| O_DIRECTORY	|
 		O_NOFOLLOW	| O_NOATIME	| O_CLOEXEC	|
-		FMODE_EXEC
+		FMODE_EXEC	| O_PATH
 		));
 
 	fasync_cache = kmem_cache_create("fasync_cache",
diff --git a/fs/file_table.c b/fs/file_table.c
index c3e89ad..67b2668 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -284,11 +284,39 @@ struct file *fget(unsigned int fd)
 	}
 	rcu_read_unlock();
 
+	if (file && (file->f_flags & O_PATH)) {
+		/*
+		 * O_PATH descriptor need to use
+		 * fget_light_lenient() variant
+		 */
+		fput(file);
+		file = NULL;
+	}
 	return file;
 }
 
 EXPORT_SYMBOL(fget);
 
+struct file *fget_lenient(unsigned int fd)
+{
+	struct file *file;
+	struct files_struct *files = current->files;
+
+	rcu_read_lock();
+	file = fcheck_files(files, fd);
+	if (file) {
+		if (!atomic_long_inc_not_zero(&file->f_count)) {
+			/* File object ref couldn't be taken */
+			rcu_read_unlock();
+			return NULL;
+		}
+	}
+	rcu_read_unlock();
+
+	return file;
+}
+EXPORT_SYMBOL(fget_lenient);
+
 /*
  * Lightweight file lookup - no refcnt increment if fd table isn't shared.
  *
@@ -326,6 +354,38 @@ struct file *fget_light(unsigned int fd, int *fput_needed)
 		rcu_read_unlock();
 	}
 
+	if (file && (file->f_flags & O_PATH)) {
+		/*
+		 * O_PATH descriptor need to use
+		 * fget_light_lenient() variant
+		 */
+		if (*fput_needed)
+			fput(file);
+		file = NULL;
+	}
+	return file;
+}
+
+struct file *fget_light_lenient(unsigned int fd, int *fput_needed)
+{
+	struct file *file;
+	struct files_struct *files = current->files;
+
+	*fput_needed = 0;
+	if (atomic_read(&files->count) == 1) {
+		file = fcheck_files(files, fd);
+	} else {
+		rcu_read_lock();
+		file = fcheck_files(files, fd);
+		if (file) {
+			if (atomic_long_inc_not_zero(&file->f_count))
+				*fput_needed = 1;
+			else
+				/* Didn't get the reference, someone's freed */
+				file = NULL;
+		}
+		rcu_read_unlock();
+	}
 	return file;
 }
 
diff --git a/fs/namei.c b/fs/namei.c
index a8346fa..b9a500c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2115,6 +2115,9 @@ int may_open(struct path *path, int acc_mode, int flag)
 	if (!inode)
 		return -ENOENT;
 
+	if (!(acc_mode & MAY_OPEN))
+		return 0;
+
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFLNK:
 		return -ELOOP;
@@ -2404,8 +2407,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
 	if (!path->dentry->d_inode)
 		goto exit_dput;
 
-	if (path->dentry->d_inode->i_op->follow_link)
-		return NULL;
+	/* We allow open on symlinks with O_PATH flag */
+	if ((open_flag & (O_PATH | O_NOFOLLOW)) != (O_PATH | O_NOFOLLOW))
+		if (path->dentry->d_inode->i_op->follow_link)
+			return NULL;
 
 	path_to_nameidata(path, nd);
 	nd->inode = path->dentry->d_inode;
@@ -2444,6 +2449,14 @@ struct file *do_filp_open(int dfd, const char *pathname,
 	int flag = open_to_namei_flags(open_flag);
 	int flags;
 
+	/*
+	 * If we have O_PATH in the open flag. Then we
+	 * cannot have anything other than the below set of flags
+	 */
+	if ((open_flag & O_PATH) &&
+	    (open_flag & ~(O_DIRECTORY|O_NOFOLLOW|O_PATH)))
+		return ERR_PTR(-EINVAL);
+
 	if (!(open_flag & O_CREAT))
 		mode = 0;
 
@@ -2459,7 +2472,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
 	if (open_flag & __O_SYNC)
 		open_flag |= O_DSYNC;
 
-	if (!acc_mode)
+	if (!acc_mode && !(open_flag & O_PATH))
 		acc_mode = MAY_OPEN | ACC_MODE(open_flag);
 
 	/* O_TRUNC implies we need access checks for write permissions */
@@ -2499,7 +2512,10 @@ struct file *do_filp_open(int dfd, const char *pathname,
 	if (unlikely(error))
 		goto out_filp;
 	error = -ELOOP;
-	if (!(nd.flags & LOOKUP_FOLLOW)) {
+	/*
+	 * With allow open on symlinks with O_PATH flag.
+	 */
+	if (!(nd.flags & LOOKUP_FOLLOW) && !(open_flag & O_PATH)) {
 		if (nd.inode->i_op->follow_link)
 			goto out_path;
 	}
@@ -2708,10 +2724,19 @@ long do_handle_open(int mountdirfd,
 		    struct file_handle __user *ufh, int open_flag)
 {
 	long retval = 0;
-	int fd, acc_mode;
+	int fd, acc_mode = 0;
 	struct path path;
 	struct file *filp;
 
+	/*
+	 * If we have O_PATH in the open flag. Then we
+	 * cannot have anything other than the below set of flags
+	 */
+	if ((open_flag & O_PATH) &&
+	    (open_flag & ~(O_DIRECTORY|O_PATH))) {
+		retval = -EINVAL;
+		goto out_err;
+	}
 	/* can't use O_CREATE with open_by_handle */
 	if (open_flag & O_CREAT) {
 		retval = -EINVAL;
@@ -2739,7 +2764,8 @@ long do_handle_open(int mountdirfd,
 	if (open_flag & __O_SYNC)
 		open_flag |= O_DSYNC;
 
-	acc_mode = MAY_OPEN | ACC_MODE(open_flag);
+	if (!(open_flag & O_PATH))
+		acc_mode = MAY_OPEN | ACC_MODE(open_flag);
 
 	/* O_TRUNC implies we need access checks for write permissions */
 	if (open_flag & O_TRUNC)
diff --git a/fs/open.c b/fs/open.c
index 1ec2623..7dbde0f 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -657,6 +657,9 @@ static inline int __get_file_write_access(struct inode *inode,
 	return error;
 }
 
+/* empty file_operations to be used for O_PATH descriptor */
+static const struct file_operations o_path_file_operations = {};
+
 struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 			   struct file *f,
 			   int (*open)(struct inode *, struct file *),
@@ -665,8 +668,9 @@ struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 	struct inode *inode;
 	int error;
 
-	f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
-				FMODE_PREAD | FMODE_PWRITE;
+	if (!(f->f_flags & O_PATH))
+		f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
+			    FMODE_PREAD | FMODE_PWRITE;
 	inode = dentry->d_inode;
 	if (f->f_mode & FMODE_WRITE) {
 		error = __get_file_write_access(inode, mnt);
@@ -680,8 +684,14 @@ struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 	f->f_path.dentry = dentry;
 	f->f_path.mnt = mnt;
 	f->f_pos = 0;
-	f->f_op = fops_get(inode->i_fop);
 	file_sb_list_add(f, inode->i_sb);
+	/* For O_PATH open we just return without opening the file */
+	if (f->f_flags & O_PATH) {
+		f->f_op = &o_path_file_operations;
+		return f;
+	}
+	f->f_op = fops_get(inode->i_fop);
+
 
 	error = security_dentry_open(f, cred);
 	if (error)
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index 0fc16e3..84793c7 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -80,6 +80,10 @@
 #define O_SYNC		(__O_SYNC|O_DSYNC)
 #endif
 
+#ifndef O_PATH
+#define O_PATH		010000000
+#endif
+
 #ifndef O_NDELAY
 #define O_NDELAY	O_NONBLOCK
 #endif
diff --git a/include/linux/file.h b/include/linux/file.h
index e85baeb..e21b733 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -29,6 +29,8 @@ static inline void fput_light(struct file *file, int fput_needed)
 
 extern struct file *fget(unsigned int fd);
 extern struct file *fget_light(unsigned int fd, int *fput_needed);
+extern struct file *fget_lenient(unsigned int fd);
+extern struct file *fget_light_lenient(unsigned int fd, int *fput_needed);
 extern void set_close_on_exec(unsigned int fd, int flag);
 extern void put_filp(struct file *);
 extern int alloc_fd(unsigned start, unsigned flags);
-- 
1.7.1

  parent reply	other threads:[~2011-01-29 19:08 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-29 19:08 [PATCH -V26 00/16] Generic name to handle and open by handle syscalls Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 01/16] exportfs: Return the minimum required handle size Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 02/16] vfs: Add name to file handle conversion support Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 03/16] vfs: Add open by file handle support Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 04/16] fs: Don't allow to create hardlink for deleted file Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 05/16] fs: Remove i_nlink check from file system link callback Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 06/16] x86: Add new syscalls for x86_32 Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 07/16] x86: Add new syscalls for x86_64 Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 08/16] unistd.h: Add new syscalls numbers to asm-generic Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 09/16] vfs: Export file system uuid via /proc/<pid>/mountinfo Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 10/16] ext3: Copy fs UUID to superblock Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 11/16] ext4: " Aneesh Kumar K.V
2011-01-29 19:08 ` Aneesh Kumar K.V [this message]
2011-01-29 19:08 ` [PATCH -V26 13/16] fs: Support "" relative pathnames Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 14/16] fs: limit linkat syscall with null relative name to CAP_DAC_READ_SEARCH Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 15/16] vfs: enable O_PATH descriptor for few syscalls Aneesh Kumar K.V
2011-01-29 19:08 ` [PATCH -V26 16/16] vfs: enable "" pathname in openat syscall Aneesh Kumar K.V

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1296328099-23263-13-git-send-email-aneesh.kumar@linux.vnet.ibm.com \
    --to=aneesh.kumar@linux.vnet.ibm.com \
    --cc=adilger@sun.com \
    --cc=bfields@fieldses.org \
    --cc=corbet@lwn.net \
    --cc=hch@infradead.org \
    --cc=hooanon05@yahoo.co.jp \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=neilb@suse.de \
    --cc=npiggin@kernel.dk \
    --cc=philippe.deniel@CEA.FR \
    --cc=sfrench@us.ibm.com \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).