From: Christophe Leroy (CS GROUP) Date: Tue, 24 Mar 2026 11:41:15 +0000 (+0100) Subject: readdir: Introduce dirent_size() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4bf798e027d35e4fd9a31b32e6bc2d33a73c0041;p=thirdparty%2Fkernel%2Flinux.git 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 Signed-off-by: Christophe Leroy (CS GROUP) Link: https://patch.msgid.link/c20d2f8f6817a39401155cfc80f0dff88df116e0.1774350128.git.chleroy@kernel.org Reviewed-by: David Laight Signed-off-by: Christian Brauner --- diff --git a/fs/readdir.c b/fs/readdir.c index 73707b6816e9a..fb910dc2f52b5 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -22,6 +22,8 @@ #include #include +#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;