diff options
| author | Christophe Leroy (CS GROUP) <chleroy@kernel.org> | 2026-03-24 14:41:15 +0300 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-03-24 16:44:02 +0300 |
| commit | 4bf798e027d35e4fd9a31b32e6bc2d33a73c0041 (patch) | |
| tree | 82e511d4b1d07ecf206dbc96b91d609aea0471e4 | |
| parent | f30186b0c7829841744a40f7345e6cc9865f8a67 (diff) | |
| download | linux-4bf798e027d35e4fd9a31b32e6bc2d33a73c0041.tar.xz | |
readdir: Introduce dirent_size()
In several places in readdir.c there are calculations of the total size
of a dirent, which contains a few fixed fields plus a name field with
variable size. To add fun every dirent is of a slightly different type:
- struct old_linux_dirent
- struct linux_dirent
- struct linux_dirent64
- struct compat_old_linux_dirent
- struct compat_linux_dirent
Replace ugly size calculation by a macro called dirent_size() which
calculates the size of the structure based on the pointed type and
the name field len.
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Link: https://patch.msgid.link/c20d2f8f6817a39401155cfc80f0dff88df116e0.1774350128.git.chleroy@kernel.org
Reviewed-by: David Laight <david.laight.linux@gmail.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
| -rw-r--r-- | fs/readdir.c | 19 |
1 files changed, 7 insertions, 12 deletions
diff --git a/fs/readdir.c b/fs/readdir.c index 73707b6816e9..fb910dc2f52b 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -22,6 +22,8 @@ #include <linux/compat.h> #include <linux/uaccess.h> +#define dirent_size(dirent, len) offsetof(typeof(*(dirent)), d_name[len]) + /* * Some filesystems were never converted to '->iterate_shared()' * and their directory iterators want the inode lock held for @@ -198,9 +200,7 @@ static bool fillonedir(struct dir_context *ctx, const char *name, int namlen, } buf->result++; dirent = buf->dirent; - if (!user_write_access_begin(dirent, - (unsigned long)(dirent->d_name + namlen + 1) - - (unsigned long)dirent)) + if (!user_write_access_begin(dirent, dirent_size(dirent, namlen + 1))) goto efault; unsafe_put_user(d_ino, &dirent->d_ino, efault_end); unsafe_put_user(offset, &dirent->d_offset, efault_end); @@ -263,8 +263,7 @@ static bool filldir(struct dir_context *ctx, const char *name, int namlen, struct getdents_callback *buf = container_of(ctx, struct getdents_callback, ctx); unsigned long d_ino; - int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, - sizeof(long)); + int reclen = ALIGN(dirent_size(dirent, namlen + 2), sizeof(long)); int prev_reclen; unsigned int flags = d_type; @@ -352,8 +351,7 @@ static bool filldir64(struct dir_context *ctx, const char *name, int namlen, struct linux_dirent64 __user *dirent, *prev; struct getdents_callback64 *buf = container_of(ctx, struct getdents_callback64, ctx); - int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, - sizeof(u64)); + int reclen = ALIGN(dirent_size(dirent, namlen + 1), sizeof(u64)); int prev_reclen; unsigned int flags = d_type; @@ -460,9 +458,7 @@ static bool compat_fillonedir(struct dir_context *ctx, const char *name, } buf->result++; dirent = buf->dirent; - if (!user_write_access_begin(dirent, - (unsigned long)(dirent->d_name + namlen + 1) - - (unsigned long)dirent)) + if (!user_write_access_begin(dirent, dirent_size(dirent, namlen + 1))) goto efault; unsafe_put_user(d_ino, &dirent->d_ino, efault_end); unsafe_put_user(offset, &dirent->d_offset, efault_end); @@ -519,8 +515,7 @@ static bool compat_filldir(struct dir_context *ctx, const char *name, int namlen struct compat_getdents_callback *buf = container_of(ctx, struct compat_getdents_callback, ctx); compat_ulong_t d_ino; - int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) + - namlen + 2, sizeof(compat_long_t)); + int reclen = ALIGN(dirent_size(dirent, namlen + 2), sizeof(compat_long_t)); int prev_reclen; unsigned int flags = d_type; |
