---
id: CVE-2022-49658
title: 'bpf: Fix insufficient bounds propagation from adjust_scalar_min_max_vals'
summary: |-
  In the Linux kernel, the following vulnerability has been resolved:

  bpf: Fix insufficient bounds propagation from adjust_scalar_min_max_vals

  Kuee reported a corner case where the tnum becomes constant after the call
  to __reg_bound_offs…
severity: none
vendor: Linux
product: Linux
affected:
  - >-
    Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 <
    e917be1f83ea14a68b3cf64d3da9968eaf991dae
  - >-
    Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 <
    a7de8d436db92bab8b1f44624297c2554a6ac36b
  - >-
    Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 <
    b2a28bb36664c94375926cbbb91976242847699d
  - >-
    Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 <
    3844d153a41adea718202c10ae91dc96b37453b5
  - Linux 4.14
ssvc:
  exploitation: none
  automatable: 'no'
  technicalImpact: partial
  timestamp: '2026-11-05T19:46:39.344320Z'
published: '2025-02-26'
updated: '2026-11-05'
sourceUpdated: '2026-11-05T19:49:41.689Z'
source: CVEORG
sourceUrl: 'https://www.cve.org/CVERecord?id=CVE-2022-49658'
references:
  - url: 'https://git.kernel.org/stable/c/e917be1f83ea14a68b3cf64d3da9968eaf991dae'
  - url: 'https://git.kernel.org/stable/c/a7de8d436db92bab8b1f44624297c2554a6ac36b'
  - url: 'https://git.kernel.org/stable/c/b2a28bb36664c94375926cbbb91976242847699d'
  - url: 'https://git.kernel.org/stable/c/3844d153a41adea718202c10ae91dc96b37453b5'
tags:
  - cve.org
epss: 0.00281
epssPercentile: 0.20699
ingestedAt: '2026-11-05T22:38:31.583Z'
---

## Overview

In the Linux kernel, the following vulnerability has been resolved:

bpf: Fix insufficient bounds propagation from adjust_scalar_min_max_vals

Kuee reported a corner case where the tnum becomes constant after the call
to __reg_bound_offset(), but the register's bounds are not, that is, its
min bounds are still not equal to the register's max bounds.

This in turn allows to leak pointers through turning a pointer register as
is into an unknown scalar via adjust_ptr_min_max_vals().

Before:

  func#0 @0
  0: R1=ctx(off=0,imm=0,umax=0,var_off=(0x0; 0x0)) R10=fp(off=0,imm=0,umax=0,var_off=(0x0; 0x0))
  0: (b7) r0 = 1                        ; R0_w=scalar(imm=1,umin=1,umax=1,var_off=(0x1; 0x0))
  1: (b7) r3 = 0                        ; R3_w=scalar(imm=0,umax=0,var_off=(0x0; 0x0))
  2: (87) r3 = -r3                      ; R3_w=scalar()
  3: (87) r3 = -r3                      ; R3_w=scalar()
  4: (47) r3 |= 32767                   ; R3_w=scalar(smin=-9223372036854743041,umin=32767,var_off=(0x7fff; 0xffffffffffff8000),s32_min=-2147450881)
  5: (75) if r3 s>= 0x0 goto pc+1       ; R3_w=scalar(umin=9223372036854808575,var_off=(0x8000000000007fff; 0x7fffffffffff8000),s32_min=-2147450881,u32_min=32767)
  6: (95) exit

  from 5 to 7: R0=scalar(imm=1,umin=1,umax=1,var_off=(0x1; 0x0)) R1=ctx(off=0,imm=0,umax=0,var_off=(0x0; 0x0)) R3=scalar(umin=32767,umax=9223372036854775807,var_off=(0x7fff; 0x7fffffffffff8000),s32_min=-2147450881) R10=fp(off=0,imm=0,umax=0,var_off=(0x0; 0x0))
  7: (d5) if r3 s<= 0x8000 goto pc+1    ; R3=scalar(umin=32769,umax=9223372036854775807,var_off=(0x7fff; 0x7fffffffffff8000),s32_min=-2147450881,u32_min=32767)
  8: (95) exit

  from 7 to 9: R0=scalar(imm=1,umin=1,umax=1,var_off=(0x1; 0x0)) R1=ctx(off=0,imm=0,umax=0,var_off=(0x0; 0x0)) R3=scalar(umin=32767,umax=32768,var_off=(0x7fff; 0x8000)) R10=fp(off=0,imm=0,umax=0,var_off=(0x0; 0x0))
  9: (07) r3 += -32767                  ; R3_w=scalar(imm=0,umax=1,var_off=(0x0; 0x0))  <--- [*]
  10: (95) exit

What can be seen here is that R3=scalar(umin=32767,umax=32768,var_off=(0x7fff;
0x8000)) after the operation R3 += -32767 results in a 'malformed' constant, that
is, R3_w=scalar(imm=0,umax=1,var_off=(0x0; 0x0)). Intersecting with var_off has
not been done at that point via __update_reg_bounds(), which would have improved
the umax to be equal to umin.

Refactor the tnum <> min/max bounds information flow into a reg_bounds_sync()
helper and use it consistently everywhere. After the fix, bounds have been
corrected to R3_w=scalar(imm=0,umax=0,var_off=(0x0; 0x0)) and thus the register
is regarded as a 'proper' constant scalar of 0.

After:

  func#0 @0
  0: R1=ctx(off=0,imm=0,umax=0,var_off=(0x0; 0x0)) R10=fp(off=0,imm=0,umax=0,var_off=(0x0; 0x0))
  0: (b7) r0 = 1                        ; R0_w=scalar(imm=1,umin=1,umax=1,var_off=(0x1; 0x0))
  1: (b7) r3 = 0                        ; R3_w=scalar(imm=0,umax=0,var_off=(0x0; 0x0))
  2: (87) r3 = -r3                      ; R3_w=scalar()
  3: (87) r3 = -r3                      ; R3_w=scalar()
  4: (47) r3 |= 32767                   ; R3_w=scalar(smin=-9223372036854743041,umin=32767,var_off=(0x7fff; 0xffffffffffff8000),s32_min=-2147450881)
  5: (75) if r3 s>= 0x0 goto pc+1       ; R3_w=scalar(umin=9223372036854808575,var_off=(0x8000000000007fff; 0x7fffffffffff8000),s32_min=-2147450881,u32_min=32767)
  6: (95) exit

  from 5 to 7: R0=scalar(imm=1,umin=1,umax=1,var_off=(0x1; 0x0)) R1=ctx(off=0,imm=0,umax=0,var_off=(0x0; 0x0)) R3=scalar(umin=32767,umax=9223372036854775807,var_off=(0x7fff; 0x7fffffffffff8000),s32_min=-2147450881) R10=fp(off=0,imm=0,umax=0,var_off=(0x0; 0x0))
  7: (d5) if r3 s<= 0x8000 goto pc+1    ; R3=scalar(umin=32769,umax=9223372036854775807,var_off=(0x7fff; 0x7fffffffffff8000),s32_min=-2147450881,u32_min=32767)
  8: (95) exit

  from 7 to 9: R0=scalar(imm=1,umin=1,umax=1,var_off=(0x1; 0x0)) R1=ctx(off=0,imm=0,umax=0,var_off=(0x0; 0x0)) R3=scalar(umin=32767,umax=32768,var_off=(0x7fff; 0x8000)) R10=fp(off=0
---truncated---

## Affected

- `Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 < e917be1f83ea14a68b3cf64d3da9968eaf991dae`
- `Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 < a7de8d436db92bab8b1f44624297c2554a6ac36b`
- `Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 < b2a28bb36664c94375926cbbb91976242847699d`
- `Linux >= b03c9f9fdc37dab81ea04d5dacdc5995d4c224c2 < 3844d153a41adea718202c10ae91dc96b37453b5`
- `Linux 4.14`

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.
