public inbox for [email protected]
 help / color / mirror / Atom feed
From: Al Viro <[email protected]>
To: [email protected]
Cc: "Christian Brauner" <[email protected]>,
	[email protected],
	"Christian Göttsche" <[email protected]>
Subject: [PATCH v2 02/13] getname_maybe_null() - the third variant of pathname copy-in
Date: Sat,  2 Nov 2024 07:31:38 +0000	[thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>

Semantics used by statx(2) (and later *xattrat(2)): without AT_EMPTY_PATH
it's standard getname() (i.e. ERR_PTR(-ENOENT) on empty string,
ERR_PTR(-EFAULT) on NULL), with AT_EMPTY_PATH both empty string and
NULL are accepted.

Calling conventions: getname_maybe_null(user_pointer, flags) returns
	* pointer to struct filename when non-empty string had been
successfully read
	* ERR_PTR(...) on error
	* NULL if an empty string or NULL pointer had been given
with AT_EMPTY_PATH in the flags argument.

It tries to avoid allocation in the last case; it's not always
able to do so, in which case the temporary struct filename instance
is freed and NULL returned anyway.

Fast path is inlined.

Signed-off-by: Al Viro <[email protected]>
---
 fs/namei.c         | 30 +++++++++++++++++++++++-------
 fs/stat.c          | 28 ++++------------------------
 include/linux/fs.h | 10 ++++++++++
 3 files changed, 37 insertions(+), 31 deletions(-)

diff --git a/fs/namei.c b/fs/namei.c
index aaf3cd6c802f..2bfe476c3bd0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -211,22 +211,38 @@ getname_flags(const char __user *filename, int flags)
 	return result;
 }
 
-struct filename *
-getname_uflags(const char __user *filename, int uflags)
+struct filename *getname_uflags(const char __user *filename, int uflags)
 {
 	int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0;
 
 	return getname_flags(filename, flags);
 }
 
-struct filename *
-getname(const char __user * filename)
+struct filename *getname(const char __user * filename)
 {
 	return getname_flags(filename, 0);
 }
 
-struct filename *
-getname_kernel(const char * filename)
+struct filename *__getname_maybe_null(const char __user *pathname)
+{
+	struct filename *name;
+	char c;
+
+	/* try to save on allocations; loss on um, though */
+	if (get_user(c, pathname))
+		return ERR_PTR(-EFAULT);
+	if (!c)
+		return NULL;
+
+	name = getname_flags(pathname, LOOKUP_EMPTY);
+	if (!IS_ERR(name) && !(name->name[0])) {
+		putname(name);
+		name = NULL;
+	}
+	return name;
+}
+
+struct filename *getname_kernel(const char * filename)
 {
 	struct filename *result;
 	int len = strlen(filename) + 1;
@@ -264,7 +280,7 @@ EXPORT_SYMBOL(getname_kernel);
 
 void putname(struct filename *name)
 {
-	if (IS_ERR(name))
+	if (IS_ERR_OR_NULL(name))
 		return;
 
 	if (WARN_ON_ONCE(!atomic_read(&name->refcnt)))
diff --git a/fs/stat.c b/fs/stat.c
index 41e598376d7e..b74831dc7ae6 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -326,18 +326,11 @@ int vfs_fstatat(int dfd, const char __user *filename,
 {
 	int ret;
 	int statx_flags = flags | AT_NO_AUTOMOUNT;
-	struct filename *name;
+	struct filename *name = getname_maybe_null(filename, flags);
 
-	/*
-	 * Work around glibc turning fstat() into fstatat(AT_EMPTY_PATH)
-	 *
-	 * If AT_EMPTY_PATH is set, we expect the common case to be that
-	 * empty path, and avoid doing all the extra pathname work.
-	 */
-	if (flags == AT_EMPTY_PATH && vfs_empty_path(dfd, filename))
+	if (!name && dfd >= 0)
 		return vfs_fstat(dfd, stat);
 
-	name = getname_flags(filename, getname_statx_lookup_flags(statx_flags));
 	ret = vfs_statx(dfd, name, statx_flags, stat, STATX_BASIC_STATS);
 	putname(name);
 
@@ -774,24 +767,11 @@ SYSCALL_DEFINE5(statx,
 		struct statx __user *, buffer)
 {
 	int ret;
-	unsigned lflags;
-	struct filename *name;
+	struct filename *name = getname_maybe_null(filename, flags);
 
-	/*
-	 * Short-circuit handling of NULL and "" paths.
-	 *
-	 * For a NULL path we require and accept only the AT_EMPTY_PATH flag
-	 * (possibly |'d with AT_STATX flags).
-	 *
-	 * However, glibc on 32-bit architectures implements fstatat as statx
-	 * with the "" pathname and AT_NO_AUTOMOUNT | AT_EMPTY_PATH flags.
-	 * Supporting this results in the uglification below.
-	 */
-	lflags = flags & ~(AT_NO_AUTOMOUNT | AT_STATX_SYNC_TYPE);
-	if (lflags == AT_EMPTY_PATH && vfs_empty_path(dfd, filename))
+	if (!name && dfd >= 0)
 		return do_statx_fd(dfd, flags & ~AT_NO_AUTOMOUNT, mask, buffer);
 
-	name = getname_flags(filename, getname_statx_lookup_flags(flags));
 	ret = do_statx(dfd, name, flags, mask, buffer);
 	putname(name);
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e3c603d01337..403258ac2ea2 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2766,6 +2766,16 @@ extern struct filename *getname_flags(const char __user *, int);
 extern struct filename *getname_uflags(const char __user *, int);
 extern struct filename *getname(const char __user *);
 extern struct filename *getname_kernel(const char *);
+extern struct filename *__getname_maybe_null(const char __user *);
+static inline struct filename *getname_maybe_null(const char __user *name, int flags)
+{
+	if (!(flags & AT_EMPTY_PATH))
+		return getname(name);
+
+	if (!name)
+		return NULL;
+	return __getname_maybe_null(name);
+}
 extern void putname(struct filename *name);
 
 extern int finish_open(struct file *file, struct dentry *dentry,
-- 
2.39.5


  reply	other threads:[~2024-11-02  7:31 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-02  1:10 [RFC][PATCHES] xattr stuff and interactions with io_uring Al Viro
2024-10-02  1:22 ` [PATCH 1/9] xattr: switch to CLASS(fd) Al Viro
2024-10-02  1:22   ` [PATCH 2/9] fs: rename struct xattr_ctx to kernel_xattr_ctx Al Viro
2024-10-02  5:56     ` Christian Brauner
2024-10-02  1:22   ` [PATCH 3/9] io_[gs]etxattr_prep(): just use getname() Al Viro
2024-10-02  5:57     ` Christian Brauner
2024-10-02  1:22   ` [PATCH 4/9] new helper: import_xattr_name() Al Viro
2024-10-02  5:57     ` Christian Brauner
2024-10-02  1:22   ` [PATCH 5/9] replace do_setxattr() with saner helpers Al Viro
2024-10-02  1:34     ` Jens Axboe
2024-10-02  2:08       ` Al Viro
2024-10-02 18:00         ` Jens Axboe
2024-10-02 21:19           ` Al Viro
2024-10-02 22:55             ` Jens Axboe
2024-10-06  5:28               ` Al Viro
2024-10-07 18:09                 ` Jens Axboe
2024-10-07 18:20                   ` Jens Axboe
2024-10-07 21:20                     ` Al Viro
2024-10-07 22:29                       ` Jens Axboe
2024-10-07 23:58                         ` Al Viro
2024-10-08  1:58                           ` Jens Axboe
2024-10-08  4:08                             ` Al Viro
2024-10-02  1:22   ` [PATCH 6/9] replace do_getxattr() " Al Viro
2024-10-02  5:59     ` Christian Brauner
2024-10-02  1:22   ` [PATCH 7/9] new helpers: file_listxattr(), filename_listxattr() Al Viro
2024-10-02  6:00     ` Christian Brauner
2024-10-02  1:22   ` [PATCH 8/9] new helpers: file_removexattr(), filename_removexattr() Al Viro
2024-10-02  6:01     ` Christian Brauner
2024-10-02  1:22   ` [PATCH 9/9] fs/xattr: add *at family syscalls Al Viro
2024-10-02  6:03     ` Christian Brauner
2024-10-02  5:56   ` [PATCH 1/9] xattr: switch to CLASS(fd) Christian Brauner
2024-11-02  7:28 ` [RFC][PATCHES v2] xattr stuff and interactions with io_uring Al Viro
2024-11-02  7:31   ` [PATCH v2 01/13] teach filename_lookup() to treat NULL filename as "" Al Viro
2024-11-02  7:31     ` Al Viro [this message]
2024-11-02  7:31     ` [PATCH v2 03/13] io_uring: IORING_OP_F[GS]ETXATTR is fine with REQ_F_FIXED_FILE Al Viro
2024-11-02  7:31     ` [PATCH v2 04/13] io_[gs]etxattr_prep(): just use getname() Al Viro
2024-11-02  7:31     ` [PATCH v2 05/13] xattr: switch to CLASS(fd) Al Viro
2024-11-02  7:31     ` [PATCH v2 06/13] fs: rename struct xattr_ctx to kernel_xattr_ctx Al Viro
2024-11-02  7:31     ` [PATCH v2 07/13] new helper: import_xattr_name() Al Viro
2024-11-02  7:31     ` [PATCH v2 08/13] replace do_setxattr() with saner helpers Al Viro
2024-11-02  7:31     ` [PATCH v2 09/13] replace do_getxattr() " Al Viro
2024-11-02  7:31     ` [PATCH v2 10/13] new helpers: file_listxattr(), filename_listxattr() Al Viro
2024-11-02  7:31     ` [PATCH v2 11/13] new helpers: file_removexattr(), filename_removexattr() Al Viro
2024-11-02  7:31     ` [PATCH v2 12/13] fs/xattr: add *at family syscalls Al Viro
2024-11-02  7:31     ` [PATCH v2 13/13] xattr: remove redundant check on variable err Al Viro

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 \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    /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