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 | * In practice this is far bigger than any realistic pointer offset; this limit | 15 | * In practice this is far bigger than any realistic pointer offset; this limit |
| 16 | * ensures that umax_value + (int)off + (int)size cannot overflow a u64. | 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 | /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO]. This ensures | 19 | /* Maximum variable size permitted for ARG_CONST_SIZE[_OR_ZERO]. This ensures |
| 20 | * that converting umax_value to int cannot overflow. | 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 | /* Liveness marks, used for registers and spilled-regs (in stack slots). | 24 | /* Liveness marks, used for registers and spilled-regs (in stack slots). |
| 25 | * Read marks propagate upwards until they find a write mark; they record that | 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 | return res > a; | 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 | /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. | 1857 | /* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off. |
| 1823 | * Caller should also handle BPF_MOV case separately. | 1858 | * Caller should also handle BPF_MOV case separately. |
| 1824 | * If we return -EACCES, caller may want to try again treating pointer as a | 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 | dst_reg->type = ptr_reg->type; | 1922 | dst_reg->type = ptr_reg->type; |
| 1888 | dst_reg->id = ptr_reg->id; | 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 | switch (opcode) { | 1929 | switch (opcode) { |
| 1891 | case BPF_ADD: | 1930 | case BPF_ADD: |
| 1892 | /* We can take a fixed offset as long as it doesn't overflow | 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 | return -EACCES; | 2056 | return -EACCES; |
| 2018 | } | 2057 | } |
| 2019 | 2058 | ||
| 2059 | if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type)) | ||
| 2060 | return -EINVAL; | ||
| 2061 | |||
| 2020 | __update_reg_bounds(dst_reg); | 2062 | __update_reg_bounds(dst_reg); |
| 2021 | __reg_deduce_bounds(dst_reg); | 2063 | __reg_deduce_bounds(dst_reg); |
| 2022 | __reg_bound_offset(dst_reg); | 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 | src_known = tnum_is_const(src_reg.var_off); | 2088 | src_known = tnum_is_const(src_reg.var_off); |
| 2047 | dst_known = tnum_is_const(dst_reg->var_off); | 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 | switch (opcode) { | 2097 | switch (opcode) { |
| 2050 | case BPF_ADD: | 2098 | case BPF_ADD: |
| 2051 | if (signed_add_overflows(dst_reg->smin_value, smin_val) || | 2099 | if (signed_add_overflows(dst_reg->smin_value, smin_val) || |