Post History
You could try and convince Linux kernel maintainers, but they are reticent to that. I wonder what they'll do after POSIX.1-202x (Issue 8) possibly will forbid those. Maybe you could patch your ke...
#3: Post edited
- You could try and convince Linux kernel maintainers, but they are reticent to that. I wonder what they'll do after POSIX.1-202x (Issue 8) possibly will forbid those.
- Maybe you could patch your kernel. It would be an interesting thing to do, even if just for fun. I've never done such a thing, so maybe I'm a bit off, but after a quick inspection of the Linux kernel v6.4 code, I think I found a place where you could hack this thing.
- Here's how I found the place:
- I started inspecting open(2), which is the first thing that comes to my mind for creating file names.
- ```c
$ grepc -tfsd open- ./fs/open.c:1376:
- SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- if (force_o_largefile())
- flags |= O_LARGEFILE;
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ./fs/open.c:1421:
- COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ```
- Okay, let's see do_sys_open().
- ```c
- $ grepc do_sys_open
- ./include/linux/fs.h:2340:
- extern long do_sys_open(int dfd, const char __user *filename, int flags,
- umode_t mode);
- ./fs/open.c:1369:
- long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
- {
- struct open_how how = build_open_how(flags, mode);
- return do_sys_openat2(dfd, filename, &how);
- }
- ```
- The filename is only passed to do_sys_openat2(); let's see that one.
- ```c
- $ grepc do_sys_openat2
- ./fs/open.c:1340:
- static long do_sys_openat2(int dfd, const char __user *filename,
- struct open_how *how)
- {
- struct open_flags op;
- int fd = build_open_flags(how, &op);
- struct filename *tmp;
- if (fd)
- return fd;
- tmp = getname(filename);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
- fd = get_unused_fd_flags(how->flags);
- if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, &op);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = PTR_ERR(f);
- } else {
- fsnotify_open(f);
- fd_install(fd, f);
- }
- }
- putname(tmp);
- return fd;
- }
- ```
- There, the file name seems to be read in getname().
- ```c
- $ grepc getname
- ./include/linux/fs.h:2365:
- extern struct filename *getname(const char __user *);
- ./fs/namei.c:216:
- struct filename *
- getname(const char __user * filename)
- {
- return getname_flags(filename, 0, NULL);
- }
- ```
- And getname_flags() seems to be the function that is checking the file name.
- ```c
- $ grepc getname_flags
- ./include/linux/fs.h:2363:
- extern struct filename *getname_flags(const char __user *, int, int *);
- ./fs/namei.c:129:
- struct filename *
- getname_flags(const char __user *filename, int flags, int *empty)
- {
- struct filename *result;
- char *kname;
- int len;
- result = audit_reusename(filename);
- if (result)
- return result;
- result = __getname();
- if (unlikely(!result))
- return ERR_PTR(-ENOMEM);
- /*
- * First, try to embed the struct filename inside the names_cache
- * allocation
- */
- kname = (char *)result->iname;
- result->name = kname;
- len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
- if (unlikely(len < 0)) {
- __putname(result);
- return ERR_PTR(len);
- }
- /*
- * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
- * separate struct filename so we can dedicate the entire
- * names_cache allocation for the pathname, and re-do the copy from
- * userland.
- */
- if (unlikely(len == EMBEDDED_NAME_MAX)) {
- const size_t size = offsetof(struct filename, iname[1]);
- kname = (char *)result;
- /*
- * 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);
- return ERR_PTR(-ENOMEM);
- }
- result->name = kname;
- len = strncpy_from_user(kname, filename, PATH_MAX);
- if (unlikely(len < 0)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(len);
- }
- if (unlikely(len == PATH_MAX)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(-ENAMETOOLONG);
- }
- }
- result->refcnt = 1;
- /* The empty path is special. */
- if (unlikely(!len)) {
- if (empty)
- *empty = 1;
- if (!(flags & LOOKUP_EMPTY)) {
- putname(result);
- return ERR_PTR(-ENOENT);
- }
- }
- result->uptr = filename;
- result->aname = NULL;
- audit_getname(result);
- return result;
- }
- ```
- You could add something there to check if you see any `\n` (or could check for anything in the range [1, 31]) and `return ERR_PTR(-EINVAL);`.
- (If you try it and it works, I'd be curious to know your results.)
- You could try and convince Linux kernel maintainers, but they are reticent to that. I wonder what they'll do after POSIX.1-202x (Issue 8) possibly will forbid those.
- Maybe you could patch your kernel. It would be an interesting thing to do, even if just for fun. I've never done such a thing, so maybe I'm a bit off, but after a quick inspection of the Linux kernel v6.4 code, I think I found a place where you could hack this thing.
- Here's how I found the place:
- I started inspecting open(2), which is the first thing that comes to my mind for creating file names.
- ```c
- alx@debian:~/src/linux/linux/6.4$ grepc -tfsd open
- ./fs/open.c:1376:
- SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- if (force_o_largefile())
- flags |= O_LARGEFILE;
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ./fs/open.c:1421:
- COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ```
- Okay, let's see do_sys_open().
- ```c
- $ grepc do_sys_open
- ./include/linux/fs.h:2340:
- extern long do_sys_open(int dfd, const char __user *filename, int flags,
- umode_t mode);
- ./fs/open.c:1369:
- long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
- {
- struct open_how how = build_open_how(flags, mode);
- return do_sys_openat2(dfd, filename, &how);
- }
- ```
- The filename is only passed to do_sys_openat2(); let's see that one.
- ```c
- $ grepc do_sys_openat2
- ./fs/open.c:1340:
- static long do_sys_openat2(int dfd, const char __user *filename,
- struct open_how *how)
- {
- struct open_flags op;
- int fd = build_open_flags(how, &op);
- struct filename *tmp;
- if (fd)
- return fd;
- tmp = getname(filename);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
- fd = get_unused_fd_flags(how->flags);
- if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, &op);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = PTR_ERR(f);
- } else {
- fsnotify_open(f);
- fd_install(fd, f);
- }
- }
- putname(tmp);
- return fd;
- }
- ```
- There, the file name seems to be read in getname().
- ```c
- $ grepc getname
- ./include/linux/fs.h:2365:
- extern struct filename *getname(const char __user *);
- ./fs/namei.c:216:
- struct filename *
- getname(const char __user * filename)
- {
- return getname_flags(filename, 0, NULL);
- }
- ```
- And getname_flags() seems to be the function that is checking the file name.
- ```c
- $ grepc getname_flags
- ./include/linux/fs.h:2363:
- extern struct filename *getname_flags(const char __user *, int, int *);
- ./fs/namei.c:129:
- struct filename *
- getname_flags(const char __user *filename, int flags, int *empty)
- {
- struct filename *result;
- char *kname;
- int len;
- result = audit_reusename(filename);
- if (result)
- return result;
- result = __getname();
- if (unlikely(!result))
- return ERR_PTR(-ENOMEM);
- /*
- * First, try to embed the struct filename inside the names_cache
- * allocation
- */
- kname = (char *)result->iname;
- result->name = kname;
- len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
- if (unlikely(len < 0)) {
- __putname(result);
- return ERR_PTR(len);
- }
- /*
- * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
- * separate struct filename so we can dedicate the entire
- * names_cache allocation for the pathname, and re-do the copy from
- * userland.
- */
- if (unlikely(len == EMBEDDED_NAME_MAX)) {
- const size_t size = offsetof(struct filename, iname[1]);
- kname = (char *)result;
- /*
- * 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);
- return ERR_PTR(-ENOMEM);
- }
- result->name = kname;
- len = strncpy_from_user(kname, filename, PATH_MAX);
- if (unlikely(len < 0)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(len);
- }
- if (unlikely(len == PATH_MAX)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(-ENAMETOOLONG);
- }
- }
- result->refcnt = 1;
- /* The empty path is special. */
- if (unlikely(!len)) {
- if (empty)
- *empty = 1;
- if (!(flags & LOOKUP_EMPTY)) {
- putname(result);
- return ERR_PTR(-ENOENT);
- }
- }
- result->uptr = filename;
- result->aname = NULL;
- audit_getname(result);
- return result;
- }
- ```
- You could add something there to check if you see any `\n` (or could check for anything in the range [1, 31]) and `return ERR_PTR(-EINVAL);`.
- (If you try it and it works, I'd be curious to know your results.)
#2: Post edited
- You could try and convince Linux kernel maintainers, but they are reticent to that. I wonder what they'll do after POSIX.1-202x (Issue 8) possibly will forbid those.
- Maybe you could patch your kernel. It would be an interesting thing to do, even if just for fun. I've never done such a thing, so maybe I'm a bit off, but after a quick inspection of the Linux kernel v6.4 code, I think I found a place where you could hack this thing.
- Here's how I found the place:
- I started inspecting open(2), which is the first thing that comes to my mind for creating file names.- ```c
- $ grepc -tfsd open
- ./fs/open.c:1376:
- SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- if (force_o_largefile())
- flags |= O_LARGEFILE;
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ./fs/open.c:1421:
- COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ```
- Okay, let's see do_sys_open().
- ```c
- $ grepc do_sys_open
- ./include/linux/fs.h:2340:
- extern long do_sys_open(int dfd, const char __user *filename, int flags,
- umode_t mode);
- ./fs/open.c:1369:
- long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
- {
- struct open_how how = build_open_how(flags, mode);
- return do_sys_openat2(dfd, filename, &how);
- }
- ```
- The filename is only passed to do_sys_openat2(); let's see that one.
- ```c
- $ grepc do_sys_openat2
- ./fs/open.c:1340:
- static long do_sys_openat2(int dfd, const char __user *filename,
- struct open_how *how)
- {
- struct open_flags op;
- int fd = build_open_flags(how, &op);
- struct filename *tmp;
- if (fd)
- return fd;
- tmp = getname(filename);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
- fd = get_unused_fd_flags(how->flags);
- if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, &op);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = PTR_ERR(f);
- } else {
- fsnotify_open(f);
- fd_install(fd, f);
- }
- }
- putname(tmp);
- return fd;
- }
- ```
- There, the file name seems to be read in getname().
- ```c
- $ grepc getname
- ./include/linux/fs.h:2365:
- extern struct filename *getname(const char __user *);
- ./fs/namei.c:216:
- struct filename *
- getname(const char __user * filename)
- {
- return getname_flags(filename, 0, NULL);
- }
- ```
- And getname_flags() seems to be the function that is checking the file name.
- ```c
- $ grepc getname_flags
- ./include/linux/fs.h:2363:
- extern struct filename *getname_flags(const char __user *, int, int *);
- ./fs/namei.c:129:
- struct filename *
- getname_flags(const char __user *filename, int flags, int *empty)
- {
- struct filename *result;
- char *kname;
- int len;
- result = audit_reusename(filename);
- if (result)
- return result;
- result = __getname();
- if (unlikely(!result))
- return ERR_PTR(-ENOMEM);
- /*
- * First, try to embed the struct filename inside the names_cache
- * allocation
- */
- kname = (char *)result->iname;
- result->name = kname;
- len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
- if (unlikely(len < 0)) {
- __putname(result);
- return ERR_PTR(len);
- }
- /*
- * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
- * separate struct filename so we can dedicate the entire
- * names_cache allocation for the pathname, and re-do the copy from
- * userland.
- */
- if (unlikely(len == EMBEDDED_NAME_MAX)) {
- const size_t size = offsetof(struct filename, iname[1]);
- kname = (char *)result;
- /*
- * 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);
- return ERR_PTR(-ENOMEM);
- }
- result->name = kname;
- len = strncpy_from_user(kname, filename, PATH_MAX);
- if (unlikely(len < 0)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(len);
- }
- if (unlikely(len == PATH_MAX)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(-ENAMETOOLONG);
- }
- }
- result->refcnt = 1;
- /* The empty path is special. */
- if (unlikely(!len)) {
- if (empty)
- *empty = 1;
- if (!(flags & LOOKUP_EMPTY)) {
- putname(result);
- return ERR_PTR(-ENOENT);
- }
- }
- result->uptr = filename;
- result->aname = NULL;
- audit_getname(result);
- return result;
- }
- ```
- You could add something there to check if you see any `\n` (or could check for anything in the range [1, 31]) and `return ERR_PTR(-EINVAL);`.
- (If you try it and it works, I'd be curious to know your results.)
- You could try and convince Linux kernel maintainers, but they are reticent to that. I wonder what they'll do after POSIX.1-202x (Issue 8) possibly will forbid those.
- Maybe you could patch your kernel. It would be an interesting thing to do, even if just for fun. I've never done such a thing, so maybe I'm a bit off, but after a quick inspection of the Linux kernel v6.4 code, I think I found a place where you could hack this thing.
- Here's how I found the place:
- I started inspecting open(2), which is the first thing that comes to my mind for creating file names.
- ```c
- $ grepc -tfsd open
- ./fs/open.c:1376:
- SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- if (force_o_largefile())
- flags |= O_LARGEFILE;
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ./fs/open.c:1421:
- COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
- {
- return do_sys_open(AT_FDCWD, filename, flags, mode);
- }
- ```
- Okay, let's see do_sys_open().
- ```c
- $ grepc do_sys_open
- ./include/linux/fs.h:2340:
- extern long do_sys_open(int dfd, const char __user *filename, int flags,
- umode_t mode);
- ./fs/open.c:1369:
- long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
- {
- struct open_how how = build_open_how(flags, mode);
- return do_sys_openat2(dfd, filename, &how);
- }
- ```
- The filename is only passed to do_sys_openat2(); let's see that one.
- ```c
- $ grepc do_sys_openat2
- ./fs/open.c:1340:
- static long do_sys_openat2(int dfd, const char __user *filename,
- struct open_how *how)
- {
- struct open_flags op;
- int fd = build_open_flags(how, &op);
- struct filename *tmp;
- if (fd)
- return fd;
- tmp = getname(filename);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
- fd = get_unused_fd_flags(how->flags);
- if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, &op);
- if (IS_ERR(f)) {
- put_unused_fd(fd);
- fd = PTR_ERR(f);
- } else {
- fsnotify_open(f);
- fd_install(fd, f);
- }
- }
- putname(tmp);
- return fd;
- }
- ```
- There, the file name seems to be read in getname().
- ```c
- $ grepc getname
- ./include/linux/fs.h:2365:
- extern struct filename *getname(const char __user *);
- ./fs/namei.c:216:
- struct filename *
- getname(const char __user * filename)
- {
- return getname_flags(filename, 0, NULL);
- }
- ```
- And getname_flags() seems to be the function that is checking the file name.
- ```c
- $ grepc getname_flags
- ./include/linux/fs.h:2363:
- extern struct filename *getname_flags(const char __user *, int, int *);
- ./fs/namei.c:129:
- struct filename *
- getname_flags(const char __user *filename, int flags, int *empty)
- {
- struct filename *result;
- char *kname;
- int len;
- result = audit_reusename(filename);
- if (result)
- return result;
- result = __getname();
- if (unlikely(!result))
- return ERR_PTR(-ENOMEM);
- /*
- * First, try to embed the struct filename inside the names_cache
- * allocation
- */
- kname = (char *)result->iname;
- result->name = kname;
- len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
- if (unlikely(len < 0)) {
- __putname(result);
- return ERR_PTR(len);
- }
- /*
- * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
- * separate struct filename so we can dedicate the entire
- * names_cache allocation for the pathname, and re-do the copy from
- * userland.
- */
- if (unlikely(len == EMBEDDED_NAME_MAX)) {
- const size_t size = offsetof(struct filename, iname[1]);
- kname = (char *)result;
- /*
- * 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);
- return ERR_PTR(-ENOMEM);
- }
- result->name = kname;
- len = strncpy_from_user(kname, filename, PATH_MAX);
- if (unlikely(len < 0)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(len);
- }
- if (unlikely(len == PATH_MAX)) {
- __putname(kname);
- kfree(result);
- return ERR_PTR(-ENAMETOOLONG);
- }
- }
- result->refcnt = 1;
- /* The empty path is special. */
- if (unlikely(!len)) {
- if (empty)
- *empty = 1;
- if (!(flags & LOOKUP_EMPTY)) {
- putname(result);
- return ERR_PTR(-ENOENT);
- }
- }
- result->uptr = filename;
- result->aname = NULL;
- audit_getname(result);
- return result;
- }
- ```
- You could add something there to check if you see any `\n` (or could check for anything in the range [1, 31]) and `return ERR_PTR(-EINVAL);`.
- (If you try it and it works, I'd be curious to know your results.)
#1: Initial revision
You could try and convince Linux kernel maintainers, but they are reticent to that. I wonder what they'll do after POSIX.1-202x (Issue 8) possibly will forbid those.
Maybe you could patch your kernel. It would be an interesting thing to do, even if just for fun. I've never done such a thing, so maybe I'm a bit off, but after a quick inspection of the Linux kernel v6.4 code, I think I found a place where you could hack this thing.
Here's how I found the place:
- I started inspecting open(2), which is the first thing that comes to my mind for creating file names.
```c
$ grepc -tfsd open
./fs/open.c:1376:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
./fs/open.c:1421:
COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
```
Okay, let's see do_sys_open().
```c
$ grepc do_sys_open
./include/linux/fs.h:2340:
extern long do_sys_open(int dfd, const char __user *filename, int flags,
umode_t mode);
./fs/open.c:1369:
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_how how = build_open_how(flags, mode);
return do_sys_openat2(dfd, filename, &how);
}
```
The filename is only passed to do_sys_openat2(); let's see that one.
```c
$ grepc do_sys_openat2
./fs/open.c:1340:
static long do_sys_openat2(int dfd, const char __user *filename,
struct open_how *how)
{
struct open_flags op;
int fd = build_open_flags(how, &op);
struct filename *tmp;
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
fd = get_unused_fd_flags(how->flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
}
putname(tmp);
return fd;
}
```
There, the file name seems to be read in getname().
```c
$ grepc getname
./include/linux/fs.h:2365:
extern struct filename *getname(const char __user *);
./fs/namei.c:216:
struct filename *
getname(const char __user * filename)
{
return getname_flags(filename, 0, NULL);
}
```
And getname_flags() seems to be the function that is checking the file name.
```c
$ grepc getname_flags
./include/linux/fs.h:2363:
extern struct filename *getname_flags(const char __user *, int, int *);
./fs/namei.c:129:
struct filename *
getname_flags(const char __user *filename, int flags, int *empty)
{
struct filename *result;
char *kname;
int len;
result = audit_reusename(filename);
if (result)
return result;
result = __getname();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
/*
* First, try to embed the struct filename inside the names_cache
* allocation
*/
kname = (char *)result->iname;
result->name = kname;
len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
if (unlikely(len < 0)) {
__putname(result);
return ERR_PTR(len);
}
/*
* Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
* separate struct filename so we can dedicate the entire
* names_cache allocation for the pathname, and re-do the copy from
* userland.
*/
if (unlikely(len == EMBEDDED_NAME_MAX)) {
const size_t size = offsetof(struct filename, iname[1]);
kname = (char *)result;
/*
* 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);
return ERR_PTR(-ENOMEM);
}
result->name = kname;
len = strncpy_from_user(kname, filename, PATH_MAX);
if (unlikely(len < 0)) {
__putname(kname);
kfree(result);
return ERR_PTR(len);
}
if (unlikely(len == PATH_MAX)) {
__putname(kname);
kfree(result);
return ERR_PTR(-ENAMETOOLONG);
}
}
result->refcnt = 1;
/* The empty path is special. */
if (unlikely(!len)) {
if (empty)
*empty = 1;
if (!(flags & LOOKUP_EMPTY)) {
putname(result);
return ERR_PTR(-ENOENT);
}
}
result->uptr = filename;
result->aname = NULL;
audit_getname(result);
return result;
}
```
You could add something there to check if you see any `\n` (or could check for anything in the range [1, 31]) and `return ERR_PTR(-EINVAL);`.
(If you try it and it works, I'd be curious to know your results.)
