| From 0c93ac69407d63a85be0129aa55ffaec27ffebd3 Mon Sep 17 00:00:00 2001 |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| Date: Sat, 17 Apr 2021 09:27:04 -0700 |
| Subject: readdir: make sure to verify directory entry for legacy interfaces too |
| |
| From: Linus Torvalds <torvalds@linux-foundation.org> |
| |
| commit 0c93ac69407d63a85be0129aa55ffaec27ffebd3 upstream. |
| |
| This does the directory entry name verification for the legacy |
| "fillonedir" (and compat) interface that goes all the way back to the |
| dark ages before we had a proper dirent, and the readdir() system call |
| returned just a single entry at a time. |
| |
| Nobody should use this interface unless you still have binaries from |
| 1991, but let's do it right. |
| |
| This came up during discussions about unsafe_copy_to_user() and proper |
| checking of all the inputs to it, as the networking layer is looking to |
| use it in a few new places. So let's make sure the _old_ users do it |
| all right and proper, before we add new ones. |
| |
| See also commit 8a23eb804ca4 ("Make filldir[64]() verify the directory |
| entry filename is valid") which did the proper modern interfaces that |
| people actually use. It had a note: |
| |
| Note that I didn't bother adding the checks to any legacy interfaces |
| that nobody uses. |
| |
| which this now corrects. Note that we really don't care about POSIX and |
| the presense of '/' in a directory entry, but verify_dirent_name() also |
| ends up doing the proper name length verification which is what the |
| input checking discussion was about. |
| |
| [ Another option would be to remove the support for this particular very |
| old interface: any binaries that use it are likely a.out binaries, and |
| they will no longer run anyway since we removed a.out binftm support |
| in commit eac616557050 ("x86: Deprecate a.out support"). |
| |
| But I'm not sure which came first: getdents() or ELF support, so let's |
| pretend somebody might still have a working binary that uses the |
| legacy readdir() case.. ] |
| |
| Link: https://lore.kernel.org/lkml/CAHk-=wjbvzCAhAtvG0d81W5o0-KT5PPTHhfJ5ieDFq+bGtgOYg@mail.gmail.com/ |
| Acked-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/readdir.c | 6 ++++++ |
| 1 file changed, 6 insertions(+) |
| |
| --- a/fs/readdir.c |
| +++ b/fs/readdir.c |
| @@ -150,6 +150,9 @@ static int fillonedir(struct dir_context |
| |
| if (buf->result) |
| return -EINVAL; |
| + buf->result = verify_dirent_name(name, namlen); |
| + if (buf->result < 0) |
| + return buf->result; |
| d_ino = ino; |
| if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { |
| buf->result = -EOVERFLOW; |
| @@ -405,6 +408,9 @@ static int compat_fillonedir(struct dir_ |
| |
| if (buf->result) |
| return -EINVAL; |
| + buf->result = verify_dirent_name(name, namlen); |
| + if (buf->result < 0) |
| + return buf->result; |
| d_ino = ino; |
| if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { |
| buf->result = -EOVERFLOW; |