public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs: get rid of memparse() for sysfs operations
@ 2023-12-07  3:36 Qu Wenruo
  2023-12-07 14:09 ` David Sterba
  0 siblings, 1 reply; 3+ messages in thread
From: Qu Wenruo @ 2023-12-07  3:36 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Disseldorp

[CONFUSION]
Btrfs is using memparse() for the following sysfs interfaces:

- /sys/fs/btrfs/<uuid>/devinfo/<devid>/scrub_speed_max
- /sys/fs/btrfs/<uuid>/allocation/<type>/chunk_size

Thus we can echo some seemingly valid values into them (using
scrub_speed_max as an example):

 # echo 25e > scrub_speed_max
 # cat scrub_speed_max
 10376293541461622784

This can cause several confusion:

- The end user may just want to type "0x25e"
- Even if it's treated as decimal "25" and E (exabyte), the result is
  not correct
  25 exabyte should be 28147497671065600, as 25 with 2 ** 10 would lead
  to something ends with "00" in decimal (25 * 4 = 100).

[CAUSE]
Above "25e" is valid because memparse() handles the extra suffix and do
proper base conversion.

"25e" has no "0x" or "0" prefix, thus it's treated as decimal, and only
"25" is the valid part. Then it goes with number detection, but the
final "e" is treated as invalid since the base is 10.

Then we do the extra left shift based on the suffix.

There are several problem in memparse itself:

- No overflow check
  The usage of simple_strtoull() lacks the overflow check, thus it's
  already discouraged to use.

- The suffix "E" (exabyte) can be easily confused with 0xe.

[FIX]
For btrfs sysfs interface, we don't accept extra suffix, except the
mentioned two entries.

Furthermore since we don't do pretty size output, and considering the
sysfs interfaces are mostly for script or other tools, there is no need
to accept extra suffix either.

So here we can just replace the memparse() to kstrou64() instead, and
reject the above "25e" example.

Reported-by: David Disseldorp <ddiss@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/sysfs.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c
index e6b51fb3ddc1..051642177982 100644
--- a/fs/btrfs/sysfs.c
+++ b/fs/btrfs/sysfs.c
@@ -760,8 +760,8 @@ static ssize_t btrfs_chunk_size_store(struct kobject *kobj,
 {
 	struct btrfs_space_info *space_info = to_space_info(kobj);
 	struct btrfs_fs_info *fs_info = to_fs_info(get_btrfs_kobj(kobj));
-	char *retptr;
 	u64 val;
+	int ret;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -776,11 +776,9 @@ static ssize_t btrfs_chunk_size_store(struct kobject *kobj,
 	if (space_info->flags & BTRFS_BLOCK_GROUP_SYSTEM)
 		return -EPERM;
 
-	val = memparse(buf, &retptr);
-	/* There could be trailing '\n', also catch any typos after the value */
-	retptr = skip_spaces(retptr);
-	if (*retptr != 0 || val == 0)
-		return -EINVAL;
+	ret = kstrtou64(buf, 0, &val);
+	if (ret < 0)
+		return ret;
 
 	val = min(val, BTRFS_MAX_DATA_CHUNK_SIZE);
 
@@ -1779,10 +1777,12 @@ static ssize_t btrfs_devinfo_scrub_speed_max_store(struct kobject *kobj,
 {
 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
 						   devid_kobj);
-	char *endptr;
-	unsigned long long limit;
+	u64 limit;
+	int ret;
 
-	limit = memparse(buf, &endptr);
+	ret = kstrtou64(buf, 0, &limit);
+	if (ret < 0)
+		return ret;
 	WRITE_ONCE(device->scrub_speed_max, limit);
 	return len;
 }
-- 
2.43.0


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

end of thread, other threads:[~2023-12-07 20:11 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-07  3:36 [PATCH] btrfs: get rid of memparse() for sysfs operations Qu Wenruo
2023-12-07 14:09 ` David Sterba
2023-12-07 20:11   ` Qu Wenruo

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