Since __counted_by(handle_bytes) was added to struct file_handle, we need to explicitly set it in the one place it wasn't yet happening prior to accessing the flex array "f_handle". For robustness also check for a negative value for handle_bytes, which is possible for an "int", but nothing appears to set. Fixes: 1b43c4629756 ("fs: Annotate struct file_handle with __counted_by() and use struct_size()") Signed-off-by: Kees Cook <keescook@xxxxxxxxxxxx> --- Cc: Jan Kara <jack@xxxxxxx> Cc: Chuck Lever <chuck.lever@xxxxxxxxxx> Cc: Gustavo A. R. Silva <gustavoars@xxxxxxxxxx> Cc: Christian Brauner <brauner@xxxxxxxxxx> Cc: Alexander Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Jeff Layton <jlayton@xxxxxxxxxx> Cc: Amir Goldstein <amir73il@xxxxxxxxx> Cc: linux-fsdevel@xxxxxxxxxxxxxxx Cc: linux-nfs@xxxxxxxxxxxxxxx Cc: linux-hardening@xxxxxxxxxxxxxxx v2: more bounds checking, add comments, dropped reviews since logic changed v1: https://lore.kernel.org/all/20240403215358.work.365-kees@xxxxxxxxxx/ --- fs/fhandle.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs/fhandle.c b/fs/fhandle.c index 8a7f86c2139a..854f866eaad2 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c @@ -40,6 +40,11 @@ static long do_sys_name_to_handle(const struct path *path, GFP_KERNEL); if (!handle) return -ENOMEM; + /* + * Since handle->f_handle is about to be written, make sure the + * associated __counted_by(handle_bytes) variable is correct. + */ + handle->handle_bytes = f_handle.handle_bytes; /* convert handle size to multiple of sizeof(u32) */ handle_dwords = f_handle.handle_bytes >> 2; @@ -51,8 +56,8 @@ static long do_sys_name_to_handle(const struct path *path, handle->handle_type = retval; /* convert handle size to bytes */ handle_bytes = handle_dwords * sizeof(u32); - handle->handle_bytes = handle_bytes; - if ((handle->handle_bytes > f_handle.handle_bytes) || + /* check if handle_bytes would have exceeded the allocation */ + if ((handle_bytes < 0) || (handle_bytes > f_handle.handle_bytes) || (retval == FILEID_INVALID) || (retval < 0)) { /* As per old exportfs_encode_fh documentation * we could return ENOSPC to indicate overflow @@ -68,6 +73,8 @@ static long do_sys_name_to_handle(const struct path *path, handle_bytes = 0; } else retval = 0; + /* the "valid" number of bytes may fewer than originally allocated */ + handle->handle_bytes = handle_bytes; /* copy the mount id */ if (put_user(real_mount(path->mnt)->mnt_id, mnt_id) || copy_to_user(ufh, handle, -- 2.34.1