There were various issues related to the limited size of integers used in the verifier: - `off + size` overflow in __check_map_access() - `off + reg->off` overflow in check_mem_access() - `off + reg->var_off.value` overflow or 32-bit truncation of `reg->var_off.value` in check_mem_access() - 32-bit truncation in check_stack_boundary() Make sure that any integer math cannot overflow by not allowing pointer math with large values. Also reduce the scope of "scalar op scalar" tracking.
Unified · Split
| @@ -15,11 +15,11 @@ · 14 unmodified lines | ||
| 15 | 15 | * In practice this is far bigger than any realistic pointer offset; this limit |
| 16 | 16 | * ensures that umax_value + (int)off + (int)size cannot overflow a u64. |
| 17 | 17 | */ |
| 18 | −#define BPF_MAX_VAR_OFF (1ULL << 31) | |
| 18 | +#define BPF_MAX_VAR_OFF (1 << 29) | |
| 19 | 19 | /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO]. This ensures |
| 20 | 20 | * that converting umax_value to int cannot overflow. |
| 21 | 21 | */ |
| 22 | −#define BPF_MAX_VAR_SIZ INT_MAX | |
| 22 | +#define BPF_MAX_VAR_SIZ (1 << 29) | |
| 23 | 23 | |
| 24 | 24 | /* Liveness marks, used for registers and spilled-regs (in stack slots). |
| 25 | 25 | * Read marks propagate upwards until they find a write mark; they record that |
| @@ -1819,6 +1819,41 @@ static bool signed_sub_overflows(s64 a, s64 b) · 1818 unmodified lines | ||
| 1819 | 1819 | return res > a; |
| 1820 | 1820 | } |
| 1821 | 1821 | |
| 1822 | +static bool check_reg_sane_offset(struct bpf_verifier_env *env, | |
| 1823 | + const struct bpf_reg_state *reg, | |
| 1824 | + enum bpf_reg_type type) | |
| 1825 | +{ | |
| 1826 | + bool known = tnum_is_const(reg->var_off); | |
| 1827 | + s64 val = reg->var_off.value; | |
| 1828 | + s64 smin = reg->smin_value; | |
| 1829 | + | |
| 1830 | + if (known && (val >= BPF_MAX_VAR_OFF || val <= -BPF_MAX_VAR_OFF)) { | |
| 1831 | + verbose(env, "math between %s pointer and %lld is not allowed\n", | |
| 1832 | + reg_type_str[type], val); | |
| 1833 | + return false; | |
| 1834 | + } | |
| 1835 | + | |
| 1836 | + if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) { | |
| 1837 | + verbose(env, "%s pointer offset %d is not allowed\n", | |
| 1838 | + reg_type_str[type], reg->off); | |
| 1839 | + return false; | |
| 1840 | + } | |
| 1841 | + | |
| 1842 | + if (smin == S64_MIN) { | |
| 1843 | + verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n", | |
| 1844 | + reg_type_str[type]); | |
| 1845 | + return false; | |
| 1846 | + } | |
| 1847 | + | |
| 1848 | + if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) { | |
| 1849 | + verbose(env, "value %lld makes %s pointer be out of bounds\n", | |
| 1850 | + smin, reg_type_str[type]); | |
| 1851 | + return false; | |
| 1852 | + } | |
| 1853 | + | |
| 1854 | + return true; | |
| 1855 | +} | |
| 1856 | + | |
| 1822 | 1857 | /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. |
| 1823 | 1858 | * Caller should also handle BPF_MOV case separately. |
| 1824 | 1859 | * If we return -EACCES, caller may want to try again treating pointer as a |
| @@ -1887,6 +1922,10 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 62 unmodified lines | ||
| 1887 | 1922 | dst_reg->type = ptr_reg->type; |
| 1888 | 1923 | dst_reg->id = ptr_reg->id; |
| 1889 | 1924 | |
| 1925 | + if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) || | |
| 1926 | + !check_reg_sane_offset(env, ptr_reg, ptr_reg->type)) | |
| 1927 | + return -EINVAL; | |
| 1928 | + | |
| 1890 | 1929 | switch (opcode) { |
| 1891 | 1930 | case BPF_ADD: |
| 1892 | 1931 | /* We can take a fixed offset as long as it doesn't overflow |
| @@ -2017,6 +2056,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env, · 124 unmodified lines | ||
| 2017 | 2056 | return -EACCES; |
| 2018 | 2057 | } |
| 2019 | 2058 | |
| 2059 | + if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type)) | |
| 2060 | + return -EINVAL; | |
| 2061 | + | |
| 2020 | 2062 | __update_reg_bounds(dst_reg); |
| 2021 | 2063 | __reg_deduce_bounds(dst_reg); |
| 2022 | 2064 | __reg_bound_offset(dst_reg); |
| @@ -2046,6 +2088,12 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env, · 23 unmodified lines | ||
| 2046 | 2088 | src_known = tnum_is_const(src_reg.var_off); |
| 2047 | 2089 | dst_known = tnum_is_const(dst_reg->var_off); |
| 2048 | 2090 | |
| 2091 | + if (!src_known && | |
| 2092 | + opcode != BPF_ADD && opcode != BPF_SUB && opcode != BPF_AND) { | |
| 2093 | + __mark_reg_unknown(dst_reg); | |
| 2094 | + return 0; | |
| 2095 | + } | |
| 2096 | + | |
| 2049 | 2097 | switch (opcode) { |
| 2050 | 2098 | case BPF_ADD: |
| 2051 | 2099 | if (signed_add_overflows(dst_reg->smin_value, smin_val) || |