lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Sun, 30 Jan 2011 00:38:16 +0530
From:	"Aneesh Kumar K.V" <aneesh.kumar@...ux.vnet.ibm.com>
To:	hch@...radead.org, viro@...iv.linux.org.uk, adilger@....com,
	corbet@....net, neilb@...e.de, npiggin@...nel.dk,
	hooanon05@...oo.co.jp, bfields@...ldses.org, miklos@...redi.hu
Cc:	linux-fsdevel@...r.kernel.org, sfrench@...ibm.com,
	philippe.deniel@....FR, linux-kernel@...r.kernel.org,
	"Aneesh Kumar K.V" <aneesh.kumar@...ux.vnet.ibm.com>
Subject: [PATCH -V26 13/16] fs: Support "" relative pathnames

Support "" relative pathnames relative to file descriptor opened
with O_PATH flag. This is needed so that we can make *_at variant
syscall operate on the dirfd passed.

Primary motivation is to enable readlinkat and linkat syscall
to work on symlink file descriptor. This also enables us to
do path lookup in userspace which can be useful for implementing
file servers in userspace.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@...ux.vnet.ibm.com>
---
 fs/namei.c         |  104 +++++++++++++++++++++++++++++++++++++++-------------
 include/linux/fs.h |   10 ++++-
 2 files changed, 87 insertions(+), 27 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index b9a500c..990b155 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -115,7 +115,8 @@
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-static int do_getname(const char __user *filename, char *page)
+static int __do_getname(const char __user *filename,
+			char *page, int allow_null_name)
 {
 	int retval;
 	unsigned long len = PATH_MAX;
@@ -132,19 +133,20 @@ static int do_getname(const char __user *filename, char *page)
 		if (retval < len)
 			return 0;
 		return -ENAMETOOLONG;
-	} else if (!retval)
+	} else if (!retval && !allow_null_name)
 		retval = -ENOENT;
+
 	return retval;
 }
 
-char * getname(const char __user * filename)
+char *do_getname(const char __user *filename, int allow_null_name)
 {
 	char *tmp, *result;
 
 	result = ERR_PTR(-ENOMEM);
 	tmp = __getname();
 	if (tmp)  {
-		int retval = do_getname(filename, tmp);
+		int retval = __do_getname(filename, tmp, allow_null_name);
 
 		result = tmp;
 		if (retval < 0) {
@@ -155,6 +157,7 @@ char * getname(const char __user * filename)
 	audit_getname(result);
 	return result;
 }
+EXPORT_SYMBOL(do_getname);
 
 #ifdef CONFIG_AUDITSYSCALL
 void putname(const char *name)
@@ -1605,6 +1608,14 @@ static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct n
 		struct fs_struct *fs = current->fs;
 		unsigned seq;
 
+		/*
+		 * If relative name is "" the descriptor should
+		 * be O_PATH descriptor.
+		 */
+		if (*name == 0) {
+			retval = -ENOENT;
+			goto out_fail;
+		}
 		br_read_lock(vfsmount_lock);
 		rcu_read_lock();
 
@@ -1617,21 +1628,38 @@ static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct n
 	} else {
 		struct dentry *dentry;
 
-		file = fget_light(dfd, &fput_needed);
+		file = fget_light_lenient(dfd, &fput_needed);
 		retval = -EBADF;
 		if (!file)
 			goto out_fail;
 
 		dentry = file->f_path.dentry;
-
-		retval = -ENOTDIR;
-		if (!S_ISDIR(dentry->d_inode->i_mode))
-			goto fput_fail;
-
-		retval = file_permission(file, MAY_EXEC);
-		if (retval)
-			goto fput_fail;
-
+		/*
+		 * We allow O_PATH fd to be used relative
+		 * to "" name. This indicate operate on
+		 * dfd itself.
+		 */
+		if (!S_ISDIR(dentry->d_inode->i_mode)) {
+			if (!(file->f_flags & O_PATH) || (*name != 0)) {
+				retval = -ENOTDIR;
+				goto fput_fail;
+			}
+		} else {
+			/*
+			 * if directory and relative name is not ""
+			 * then we need to check for EXEC permission.
+			 * If relative name is "" the descriptor should
+			 * be O_PATH descriptor.
+			 */
+			if (*name != 0) {
+				retval = file_permission(file, MAY_EXEC);
+				if (retval)
+					goto fput_fail;
+			} else if (!(file->f_flags & O_PATH)) {
+				retval = -ENOENT;
+				goto fput_fail;
+			}
+		}
 		nd->path = file->f_path;
 		if (fput_needed)
 			nd->file = file;
@@ -1665,25 +1693,50 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
 		nd->path = nd->root;
 		path_get(&nd->root);
 	} else if (dfd == AT_FDCWD) {
+		/*
+		 * If relative name is "" the descriptor should
+		 * be O_PATH descriptor.
+		 */
+		if (*name == 0) {
+			retval = -ENOENT;
+			goto out_fail;
+		}
 		get_fs_pwd(current->fs, &nd->path);
 	} else {
 		struct dentry *dentry;
 
-		file = fget_light(dfd, &fput_needed);
+		file = fget_light_lenient(dfd, &fput_needed);
 		retval = -EBADF;
 		if (!file)
 			goto out_fail;
 
 		dentry = file->f_path.dentry;
-
-		retval = -ENOTDIR;
-		if (!S_ISDIR(dentry->d_inode->i_mode))
-			goto fput_fail;
-
-		retval = file_permission(file, MAY_EXEC);
-		if (retval)
-			goto fput_fail;
-
+		/*
+		 * We allow O_PATH fd to be used relative
+		 * to "" name. This indicate operate on
+		 * dfd itself.
+		 */
+		if (!S_ISDIR(dentry->d_inode->i_mode)) {
+			if (!(file->f_flags & O_PATH) || (*name != 0)) {
+				retval = -ENOTDIR;
+				goto fput_fail;
+			}
+		} else {
+			/*
+			 * if directory and relative name is not ""
+			 * then we need to check for EXEC permission.
+			 * If relative name is "" the descriptor should
+			 * be O_PATH descriptor.
+			 */
+			if (*name != 0) {
+				retval = file_permission(file, MAY_EXEC);
+				if (retval)
+					goto fput_fail;
+			} else if (!(file->f_flags & O_PATH)) {
+				retval = -ENOENT;
+				goto fput_fail;
+			}
+		}
 		nd->path = file->f_path;
 		path_get(&file->f_path);
 
@@ -1926,7 +1979,7 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
 		 struct path *path)
 {
 	struct nameidata nd;
-	char *tmp = getname(name);
+	char *tmp = getname_null(name);
 	int err = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
 
@@ -3806,7 +3859,6 @@ EXPORT_SYMBOL(follow_down_one);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
-EXPORT_SYMBOL(getname);
 EXPORT_SYMBOL(lock_rename);
 EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link_light);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index ac6e899..3f1e7fc 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2004,7 +2004,15 @@ struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
 				 const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
-extern char * getname(const char __user *);
+extern char *do_getname(const char __user *, int allow_null_name);
+static inline char *getname(const char __user *name)
+{
+	return do_getname(name, 0);
+}
+static inline char *getname_null(const char __user *name)
+{
+	return do_getname(name, 1);
+}
 
 /* fs/ioctl.c */
 
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ