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) --- fs/readdir.c | 19 +++++++------------ 1 file 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 #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; -- 2.49.0