mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] f2fs: fix user.fadvise xattr input validation
@ 2026-05-20 14:19 Wenjie Qi
  2026-05-21  8:33 ` Chao Yu
  0 siblings, 1 reply; 2+ messages in thread
From: Wenjie Qi @ 2026-05-20 14:19 UTC (permalink / raw)
  To: jaegeuk, chao; +Cc: linux-f2fs-devel, linux-kernel, qiwenjie, qwjhust

The user.fadvise xattr handler reads an unsigned int directly from value,
but it is also reached by xattr removal and does not validate the supplied
value length.

removexattr("user.fadvise") calls the xattr set callback with value == NULL
and size == 0, which can dereference NULL.  A normal setxattr() call with a
short value, including size == 0, can also make the handler read past the
provided value buffer.

Treat a NULL value as clearing the large-folio inode registration.  Reject
non-NULL user.fadvise values whose length is not exactly
sizeof(unsigned int) before reading the value.

Fixes: 39774f27deaf ("f2fs: another way to set large folio by remembering inode number")
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
---
 fs/f2fs/xattr.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 84273936f2a..4e11d774a2c 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -80,10 +80,19 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
 			     buffer, size, NULL);
 }
 
-static int f2fs_xattr_fadvise_set(struct inode *inode, const void *value)
+static int f2fs_xattr_fadvise_set(struct inode *inode, const void *value,
+				  size_t size)
 {
 	unsigned int new_fadvise;
 
+	if (!value) {
+		f2fs_remove_ino_entry(F2FS_I_SB(inode),
+				      inode->i_ino, LARGE_FOLIO_INO);
+		return 0;
+	}
+	if (size != sizeof(new_fadvise))
+		return -EINVAL;
+
 	new_fadvise = *(unsigned int *)value;
 
 	if (new_fadvise & BIT(F2FS_XATTR_FADV_LARGEFOLIO))
@@ -116,7 +125,7 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
 	}
 	if (handler->flags == F2FS_XATTR_INDEX_USER &&
 	    !strcmp(name, "fadvise"))
-		return f2fs_xattr_fadvise_set(inode, value);
+		return f2fs_xattr_fadvise_set(inode, value, size);
 
 	return f2fs_setxattr(inode, handler->flags, name,
 					value, size, NULL, flags);
-- 
2.43.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] f2fs: fix user.fadvise xattr input validation
  2026-05-20 14:19 [PATCH] f2fs: fix user.fadvise xattr input validation Wenjie Qi
@ 2026-05-21  8:33 ` Chao Yu
  0 siblings, 0 replies; 2+ messages in thread
From: Chao Yu @ 2026-05-21  8:33 UTC (permalink / raw)
  To: Wenjie Qi, jaegeuk; +Cc: chao, linux-f2fs-devel, linux-kernel, qiwenjie

On 5/20/26 22:19, Wenjie Qi wrote:
> The user.fadvise xattr handler reads an unsigned int directly from value,
> but it is also reached by xattr removal and does not validate the supplied
> value length.
> 
> removexattr("user.fadvise") calls the xattr set callback with value == NULL
> and size == 0, which can dereference NULL.  A normal setxattr() call with a
> short value, including size == 0, can also make the handler read past the
> provided value buffer.
> 
> Treat a NULL value as clearing the large-folio inode registration.  Reject
> non-NULL user.fadvise values whose length is not exactly
> sizeof(unsigned int) before reading the value.
> 

Cc: stable@kernel.org

> Fixes: 39774f27deaf ("f2fs: another way to set large folio by remembering inode number")
> Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
> ---
>   fs/f2fs/xattr.c | 13 +++++++++++--
>   1 file changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
> index 84273936f2a..4e11d774a2c 100644
> --- a/fs/f2fs/xattr.c
> +++ b/fs/f2fs/xattr.c
> @@ -80,10 +80,19 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
>   			     buffer, size, NULL);
>   }
>   
> -static int f2fs_xattr_fadvise_set(struct inode *inode, const void *value)
> +static int f2fs_xattr_fadvise_set(struct inode *inode, const void *value,
> +				  size_t size)
>   {
>   	unsigned int new_fadvise;
>   

Better to add a comment here to describe it's from removexattr("user.fadvise") path?

Thanks,

> +	if (!value) {
> +		f2fs_remove_ino_entry(F2FS_I_SB(inode),
> +				      inode->i_ino, LARGE_FOLIO_INO);
> +		return 0;
> +	}
> +	if (size != sizeof(new_fadvise))
> +		return -EINVAL;
> +
>   	new_fadvise = *(unsigned int *)value;
>   
>   	if (new_fadvise & BIT(F2FS_XATTR_FADV_LARGEFOLIO))
> @@ -116,7 +125,7 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
>   	}
>   	if (handler->flags == F2FS_XATTR_INDEX_USER &&
>   	    !strcmp(name, "fadvise"))
> -		return f2fs_xattr_fadvise_set(inode, value);
> +		return f2fs_xattr_fadvise_set(inode, value, size);
>   
>   	return f2fs_setxattr(inode, handler->flags, name,
>   					value, size, NULL, flags);


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-05-21  8:33 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-20 14:19 [PATCH] f2fs: fix user.fadvise xattr input validation Wenjie Qi
2026-05-21  8:33 ` Chao Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®