summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2025-11-19 17:15:23 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2026-01-13 15:16:44 -0500
commit8ba29c85e2ef24764a05b557ebeca32f9bfafada (patch)
tree44ad4d04078dba77013e5dfc0f052a589d811ac8
parentca2a04e84af79596e5cd9cfe697d5122ec39c8ce (diff)
getname_flags() massage, part 1
In case of long name don't reread what we'd already copied. memmove() it instead. That avoids the possibility of ending up with empty name there and the need to look at the flags on the slow path. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c33
1 files changed, 16 insertions, 17 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 3ba712032f55..72ee663a9b6b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -174,36 +174,35 @@ getname_flags(const char __user *filename, int flags)
*/
if (unlikely(len == EMBEDDED_NAME_MAX)) {
const size_t size = offsetof(struct filename, iname[1]);
- kname = (char *)result;
+ struct filename *p;
/*
* size is chosen that way we to guarantee that
* result->iname[0] is within the same object and that
* kname can't be equal to result->iname, no matter what.
*/
- result = kzalloc(size, GFP_KERNEL);
- if (unlikely(!result)) {
- __putname(kname);
+ p = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!p)) {
+ __putname(result);
return ERR_PTR(-ENOMEM);
}
- result->name = kname;
- len = strncpy_from_user(kname, filename, PATH_MAX);
+ memmove(result, &result->iname, EMBEDDED_NAME_MAX);
+ kname = (char *)result;
+ p->name = kname;
+ len = strncpy_from_user(kname + EMBEDDED_NAME_MAX,
+ filename + EMBEDDED_NAME_MAX,
+ PATH_MAX - EMBEDDED_NAME_MAX);
if (unlikely(len < 0)) {
- __putname(kname);
- kfree(result);
+ kfree(p);
+ __putname(result);
return ERR_PTR(len);
}
- /* The empty path is special. */
- if (unlikely(!len) && !(flags & LOOKUP_EMPTY)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(-ENOENT);
- }
- if (unlikely(len == PATH_MAX)) {
- __putname(kname);
- kfree(result);
+ if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX)) {
+ kfree(p);
+ __putname(result);
return ERR_PTR(-ENAMETOOLONG);
}
+ result = p;
}
initname(result);
audit_getname(result);