[PATCH] blk-iocost: validate weights before narrowing to u32

From: Zhe Liu

Date: Tue Oct 27 2026 - 04:34:48 EST


ioc_weight_write() parses io.weight into a u32 with sscanf("%u")
and range-checks the result afterwards. vsscanf() truncates
out-of-range values modulo 2^32 without reporting an error, so the
check only sees the truncated residue: writing "default 4294967297"
(2^32+1) is accepted as weight 1 instead of being rejected with
-EINVAL, leaving the cgroup with the lowest possible weight. The
per-device override path has the same problem.

Parse into a u64 with %llu in both paths so the range check runs on
the true value. Out-of-range writes now fail with -EINVAL and leave
the configuration untouched; weights that pass the check still fit
in the u32 fields as before.

Fixes: 7caa47151ab2 ("blkcg: implement blk-iocost")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Zhe Liu <liuzhe1@xxxxxxxxxx>
---
block/blk-iocost.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index a81488c755ca..2ae40138e041 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -3170,13 +3170,13 @@ static ssize_t ioc_weight_write(struct kernfs_open_file *of, char *buf,
struct blkg_conf_ctx ctx;
struct ioc_now now;
struct ioc_gq *iocg;
- u32 v;
+ u64 v;
int ret;

if (!strchr(buf, ':')) {
struct blkcg_gq *blkg;

- if (!sscanf(buf, "default %u", &v) && !sscanf(buf, "%u", &v))
+ if (!sscanf(buf, "default %llu", &v) && !sscanf(buf, "%llu", &v))
return -EINVAL;

if (v < CGROUP_WEIGHT_MIN || v > CGROUP_WEIGHT_MAX)
@@ -3216,7 +3216,7 @@ static ssize_t ioc_weight_write(struct kernfs_open_file *of, char *buf,
if (!strncmp(ctx.body, "default", 7)) {
v = 0;
} else {
- if (!sscanf(ctx.body, "%u", &v))
+ if (!sscanf(ctx.body, "%llu", &v))
goto unprep;
if (v < CGROUP_WEIGHT_MIN || v > CGROUP_WEIGHT_MAX)
goto unprep;
--
2.25.1