| From 9e8e819f8f272c4e5dcd0bd6c7450e36481ed139 Mon Sep 17 00:00:00 2001 |
| From: Baokun Li <libaokun1@huawei.com> |
| Date: Tue, 19 Mar 2024 19:33:17 +0800 |
| Subject: ext4: avoid overflow when setting values via sysfs |
| |
| From: Baokun Li <libaokun1@huawei.com> |
| |
| commit 9e8e819f8f272c4e5dcd0bd6c7450e36481ed139 upstream. |
| |
| When setting values of type unsigned int through sysfs, we use kstrtoul() |
| to parse it and then truncate part of it as the final set value, when the |
| set value is greater than UINT_MAX, the set value will not match what we |
| see because of the truncation. As follows: |
| |
| $ echo 4294967296 > /sys/fs/ext4/sda/mb_max_linear_groups |
| $ cat /sys/fs/ext4/sda/mb_max_linear_groups |
| 0 |
| |
| So we use kstrtouint() to parse the attr_pointer_ui type to avoid the |
| inconsistency described above. In addition, a judgment is added to avoid |
| setting s_resv_clusters less than 0. |
| |
| Signed-off-by: Baokun Li <libaokun1@huawei.com> |
| Reviewed-by: Jan Kara <jack@suse.cz> |
| Link: https://lore.kernel.org/r/20240319113325.3110393-2-libaokun1@huawei.com |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/ext4/sysfs.c | 11 ++++++----- |
| 1 file changed, 6 insertions(+), 5 deletions(-) |
| |
| --- a/fs/ext4/sysfs.c |
| +++ b/fs/ext4/sysfs.c |
| @@ -104,7 +104,7 @@ static ssize_t reserved_clusters_store(s |
| int ret; |
| |
| ret = kstrtoull(skip_spaces(buf), 0, &val); |
| - if (ret || val >= clusters) |
| + if (ret || val >= clusters || (s64)val < 0) |
| return -EINVAL; |
| |
| atomic64_set(&sbi->s_resv_clusters, val); |
| @@ -451,7 +451,8 @@ static ssize_t ext4_attr_store(struct ko |
| s_kobj); |
| struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); |
| void *ptr = calc_ptr(a, sbi); |
| - unsigned long t; |
| + unsigned int t; |
| + unsigned long lt; |
| int ret; |
| |
| switch (a->attr_id) { |
| @@ -460,7 +461,7 @@ static ssize_t ext4_attr_store(struct ko |
| case attr_pointer_ui: |
| if (!ptr) |
| return 0; |
| - ret = kstrtoul(skip_spaces(buf), 0, &t); |
| + ret = kstrtouint(skip_spaces(buf), 0, &t); |
| if (ret) |
| return ret; |
| if (a->attr_ptr == ptr_ext4_super_block_offset) |
| @@ -471,10 +472,10 @@ static ssize_t ext4_attr_store(struct ko |
| case attr_pointer_ul: |
| if (!ptr) |
| return 0; |
| - ret = kstrtoul(skip_spaces(buf), 0, &t); |
| + ret = kstrtoul(skip_spaces(buf), 0, <); |
| if (ret) |
| return ret; |
| - *((unsigned long *) ptr) = t; |
| + *((unsigned long *) ptr) = lt; |
| return len; |
| case attr_inode_readahead: |
| return inode_readahead_blks_store(sbi, buf, len); |