On Tue, Jun 9, 2026 at 8:26 AM Samuel Moelius
<[email protected]> wrote:
>
> invalidate_cblocks parses the cache block number into an unsigned long
> long, but then stores it in a narrower cblock_t.  Values that do not fit
> in the target type are silently truncated before the cache block is
> invalidated.
>
> That can make a request for one cache block invalidate a different
> block.  It also makes the userspace-visible control file accept input
> that cannot be represented by the mapping it is about to update.
>
> Reject cache block numbers that do not round-trip through cblock_t
> before using them.
>
> Assisted-by: Codex:gpt-5.5-cyber-preview
> Signed-off-by: Samuel Moelius <[email protected]>
> ---
>  drivers/md/dm-cache-target.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
> index 097315a9bf0f..5f1a019a9a8d 100644
> --- a/drivers/md/dm-cache-target.c
> +++ b/drivers/md/dm-cache-target.c
> @@ -3330,6 +3330,9 @@ static int parse_cblock_range(struct cache *cache, 
> const char *str,
>         r = sscanf(str, "%llu-%llu%c", &b, &e, &dummy);
>
>         if (r == 2) {
> +               if (b > U32_MAX || e > U32_MAX)
> +                       return -EINVAL;
> +
>                 result->begin = to_cblock(b);
>                 result->end = to_cblock(e);
>                 return 0;
> @@ -3341,8 +3344,11 @@ static int parse_cblock_range(struct cache *cache, 
> const char *str,
>         r = sscanf(str, "%llu%c", &b, &dummy);
>
>         if (r == 1) {
> +               if (b > U32_MAX || b == U32_MAX)
> +                       return -EINVAL;
> +
>                 result->begin = to_cblock(b);
> -               result->end = to_cblock(from_cblock(result->begin) + 1u);
> +               result->end = to_cblock(b + 1);
>                 return 0;
>         }
>
> --
> 2.43.0
>
>

This patch is a half-measure. sscanf() silently wraps on overflow, so
values beyond U64_MAX still get wrapped to a u64 value, bypass the
range check, and invalidate a different block than specified.

Also, in the single-value path, the b == U32_MAX check is redundant.
With the original end calculation, end wraps to 0 via uint32_t
overflow, and validate_cblock_range() already rejects it since begin
>= end. Neither the extra check nor the new end calculation is needed
here.

To properly fix truncation, a rework using kstrtoull() is needed.


Reply via email to