Skip to content

Commit 2e2b96c

Browse files
committed
Merge tag 'v5.4.116' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into odroid-5.4.y
This is the 5.4.116 stable release Change-Id: I7b3d02ef2b9bbfa4abffaeac6e931d00d09585ff
2 parents 70491c2 + 370636f commit 2e2b96c

File tree

6 files changed

+174
-103
lines changed

6 files changed

+174
-103
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
VERSION = 5
33
PATCHLEVEL = 4
4-
SUBLEVEL = 115
4+
SUBLEVEL = 116
55
EXTRAVERSION =
66
NAME = Kleptomaniac Octopus
77

kernel/bpf/verifier.c

Lines changed: 159 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,40 +4263,51 @@ static struct bpf_insn_aux_data *cur_aux(struct bpf_verifier_env *env)
42634263
return &env->insn_aux_data[env->insn_idx];
42644264
}
42654265

4266+
enum {
4267+
REASON_BOUNDS = -1,
4268+
REASON_TYPE = -2,
4269+
REASON_PATHS = -3,
4270+
REASON_LIMIT = -4,
4271+
REASON_STACK = -5,
4272+
};
4273+
42664274
static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
4267-
u32 *ptr_limit, u8 opcode, bool off_is_neg)
4275+
const struct bpf_reg_state *off_reg,
4276+
u32 *alu_limit, u8 opcode)
42684277
{
4278+
bool off_is_neg = off_reg->smin_value < 0;
42694279
bool mask_to_left = (opcode == BPF_ADD && off_is_neg) ||
42704280
(opcode == BPF_SUB && !off_is_neg);
4271-
u32 off, max;
4281+
u32 max = 0, ptr_limit = 0;
4282+
4283+
if (!tnum_is_const(off_reg->var_off) &&
4284+
(off_reg->smin_value < 0) != (off_reg->smax_value < 0))
4285+
return REASON_BOUNDS;
42724286

42734287
switch (ptr_reg->type) {
42744288
case PTR_TO_STACK:
42754289
/* Offset 0 is out-of-bounds, but acceptable start for the
4276-
* left direction, see BPF_REG_FP.
4290+
* left direction, see BPF_REG_FP. Also, unknown scalar
4291+
* offset where we would need to deal with min/max bounds is
4292+
* currently prohibited for unprivileged.
42774293
*/
42784294
max = MAX_BPF_STACK + mask_to_left;
4279-
/* Indirect variable offset stack access is prohibited in
4280-
* unprivileged mode so it's not handled here.
4281-
*/
4282-
off = ptr_reg->off + ptr_reg->var_off.value;
4283-
if (mask_to_left)
4284-
*ptr_limit = MAX_BPF_STACK + off;
4285-
else
4286-
*ptr_limit = -off - 1;
4287-
return *ptr_limit >= max ? -ERANGE : 0;
4295+
ptr_limit = -(ptr_reg->var_off.value + ptr_reg->off);
4296+
break;
42884297
case PTR_TO_MAP_VALUE:
42894298
max = ptr_reg->map_ptr->value_size;
4290-
if (mask_to_left) {
4291-
*ptr_limit = ptr_reg->umax_value + ptr_reg->off;
4292-
} else {
4293-
off = ptr_reg->smin_value + ptr_reg->off;
4294-
*ptr_limit = ptr_reg->map_ptr->value_size - off - 1;
4295-
}
4296-
return *ptr_limit >= max ? -ERANGE : 0;
4299+
ptr_limit = (mask_to_left ?
4300+
ptr_reg->smin_value :
4301+
ptr_reg->umax_value) + ptr_reg->off;
4302+
break;
42974303
default:
4298-
return -EINVAL;
4304+
return REASON_TYPE;
42994305
}
4306+
4307+
if (ptr_limit >= max)
4308+
return REASON_LIMIT;
4309+
*alu_limit = ptr_limit;
4310+
return 0;
43004311
}
43014312

43024313
static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env,
@@ -4314,7 +4325,7 @@ static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
43144325
if (aux->alu_state &&
43154326
(aux->alu_state != alu_state ||
43164327
aux->alu_limit != alu_limit))
4317-
return -EACCES;
4328+
return REASON_PATHS;
43184329

43194330
/* Corresponding fixup done in fixup_bpf_calls(). */
43204331
aux->alu_state = alu_state;
@@ -4333,14 +4344,22 @@ static int sanitize_val_alu(struct bpf_verifier_env *env,
43334344
return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0);
43344345
}
43354346

4347+
static bool sanitize_needed(u8 opcode)
4348+
{
4349+
return opcode == BPF_ADD || opcode == BPF_SUB;
4350+
}
4351+
43364352
static int sanitize_ptr_alu(struct bpf_verifier_env *env,
43374353
struct bpf_insn *insn,
43384354
const struct bpf_reg_state *ptr_reg,
4355+
const struct bpf_reg_state *off_reg,
43394356
struct bpf_reg_state *dst_reg,
4340-
bool off_is_neg)
4357+
struct bpf_insn_aux_data *tmp_aux,
4358+
const bool commit_window)
43414359
{
4360+
struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : tmp_aux;
43424361
struct bpf_verifier_state *vstate = env->cur_state;
4343-
struct bpf_insn_aux_data *aux = cur_aux(env);
4362+
bool off_is_neg = off_reg->smin_value < 0;
43444363
bool ptr_is_dst_reg = ptr_reg == dst_reg;
43454364
u8 opcode = BPF_OP(insn->code);
43464365
u32 alu_state, alu_limit;
@@ -4358,18 +4377,33 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
43584377
if (vstate->speculative)
43594378
goto do_sim;
43604379

4361-
alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
4362-
alu_state |= ptr_is_dst_reg ?
4363-
BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
4364-
4365-
err = retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg);
4380+
err = retrieve_ptr_limit(ptr_reg, off_reg, &alu_limit, opcode);
43664381
if (err < 0)
43674382
return err;
43684383

4384+
if (commit_window) {
4385+
/* In commit phase we narrow the masking window based on
4386+
* the observed pointer move after the simulated operation.
4387+
*/
4388+
alu_state = tmp_aux->alu_state;
4389+
alu_limit = abs(tmp_aux->alu_limit - alu_limit);
4390+
} else {
4391+
alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0;
4392+
alu_state |= ptr_is_dst_reg ?
4393+
BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST;
4394+
}
4395+
43694396
err = update_alu_sanitation_state(aux, alu_state, alu_limit);
43704397
if (err < 0)
43714398
return err;
43724399
do_sim:
4400+
/* If we're in commit phase, we're done here given we already
4401+
* pushed the truncated dst_reg into the speculative verification
4402+
* stack.
4403+
*/
4404+
if (commit_window)
4405+
return 0;
4406+
43734407
/* Simulate and find potential out-of-bounds access under
43744408
* speculative execution from truncation as a result of
43754409
* masking when off was not within expected range. If off
@@ -4386,7 +4420,81 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
43864420
ret = push_stack(env, env->insn_idx + 1, env->insn_idx, true);
43874421
if (!ptr_is_dst_reg && ret)
43884422
*dst_reg = tmp;
4389-
return !ret ? -EFAULT : 0;
4423+
return !ret ? REASON_STACK : 0;
4424+
}
4425+
4426+
static int sanitize_err(struct bpf_verifier_env *env,
4427+
const struct bpf_insn *insn, int reason,
4428+
const struct bpf_reg_state *off_reg,
4429+
const struct bpf_reg_state *dst_reg)
4430+
{
4431+
static const char *err = "pointer arithmetic with it prohibited for !root";
4432+
const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub";
4433+
u32 dst = insn->dst_reg, src = insn->src_reg;
4434+
4435+
switch (reason) {
4436+
case REASON_BOUNDS:
4437+
verbose(env, "R%d has unknown scalar with mixed signed bounds, %s\n",
4438+
off_reg == dst_reg ? dst : src, err);
4439+
break;
4440+
case REASON_TYPE:
4441+
verbose(env, "R%d has pointer with unsupported alu operation, %s\n",
4442+
off_reg == dst_reg ? src : dst, err);
4443+
break;
4444+
case REASON_PATHS:
4445+
verbose(env, "R%d tried to %s from different maps, paths or scalars, %s\n",
4446+
dst, op, err);
4447+
break;
4448+
case REASON_LIMIT:
4449+
verbose(env, "R%d tried to %s beyond pointer bounds, %s\n",
4450+
dst, op, err);
4451+
break;
4452+
case REASON_STACK:
4453+
verbose(env, "R%d could not be pushed for speculative verification, %s\n",
4454+
dst, err);
4455+
break;
4456+
default:
4457+
verbose(env, "verifier internal error: unknown reason (%d)\n",
4458+
reason);
4459+
break;
4460+
}
4461+
4462+
return -EACCES;
4463+
}
4464+
4465+
static int sanitize_check_bounds(struct bpf_verifier_env *env,
4466+
const struct bpf_insn *insn,
4467+
const struct bpf_reg_state *dst_reg)
4468+
{
4469+
u32 dst = insn->dst_reg;
4470+
4471+
/* For unprivileged we require that resulting offset must be in bounds
4472+
* in order to be able to sanitize access later on.
4473+
*/
4474+
if (env->allow_ptr_leaks)
4475+
return 0;
4476+
4477+
switch (dst_reg->type) {
4478+
case PTR_TO_STACK:
4479+
if (check_stack_access(env, dst_reg, dst_reg->off +
4480+
dst_reg->var_off.value, 1)) {
4481+
verbose(env, "R%d stack pointer arithmetic goes out of range, "
4482+
"prohibited for !root\n", dst);
4483+
return -EACCES;
4484+
}
4485+
break;
4486+
case PTR_TO_MAP_VALUE:
4487+
if (check_map_access(env, dst, dst_reg->off, 1, false)) {
4488+
verbose(env, "R%d pointer arithmetic of map value goes out of range, "
4489+
"prohibited for !root\n", dst);
4490+
return -EACCES;
4491+
}
4492+
break;
4493+
default:
4494+
break;
4495+
}
4496+
4497+
return 0;
43904498
}
43914499

43924500
/* Handles arithmetic on a pointer and a scalar: computes new min/max and var_off.
@@ -4407,8 +4515,9 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
44074515
smin_ptr = ptr_reg->smin_value, smax_ptr = ptr_reg->smax_value;
44084516
u64 umin_val = off_reg->umin_value, umax_val = off_reg->umax_value,
44094517
umin_ptr = ptr_reg->umin_value, umax_ptr = ptr_reg->umax_value;
4410-
u32 dst = insn->dst_reg, src = insn->src_reg;
4518+
struct bpf_insn_aux_data tmp_aux = {};
44114519
u8 opcode = BPF_OP(insn->code);
4520+
u32 dst = insn->dst_reg;
44124521
int ret;
44134522

44144523
dst_reg = &regs[dst];
@@ -4451,13 +4560,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
44514560
verbose(env, "R%d pointer arithmetic on %s prohibited\n",
44524561
dst, reg_type_str[ptr_reg->type]);
44534562
return -EACCES;
4454-
case PTR_TO_MAP_VALUE:
4455-
if (!env->allow_ptr_leaks && !known && (smin_val < 0) != (smax_val < 0)) {
4456-
verbose(env, "R%d has unknown scalar with mixed signed bounds, pointer arithmetic with it prohibited for !root\n",
4457-
off_reg == dst_reg ? dst : src);
4458-
return -EACCES;
4459-
}
4460-
/* fall-through */
44614563
default:
44624564
break;
44634565
}
@@ -4472,13 +4574,15 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
44724574
!check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
44734575
return -EINVAL;
44744576

4577+
if (sanitize_needed(opcode)) {
4578+
ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
4579+
&tmp_aux, false);
4580+
if (ret < 0)
4581+
return sanitize_err(env, insn, ret, off_reg, dst_reg);
4582+
}
4583+
44754584
switch (opcode) {
44764585
case BPF_ADD:
4477-
ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
4478-
if (ret < 0) {
4479-
verbose(env, "R%d tried to add from different maps, paths, or prohibited types\n", dst);
4480-
return ret;
4481-
}
44824586
/* We can take a fixed offset as long as it doesn't overflow
44834587
* the s32 'off' field
44844588
*/
@@ -4529,11 +4633,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
45294633
}
45304634
break;
45314635
case BPF_SUB:
4532-
ret = sanitize_ptr_alu(env, insn, ptr_reg, dst_reg, smin_val < 0);
4533-
if (ret < 0) {
4534-
verbose(env, "R%d tried to sub from different maps, paths, or prohibited types\n", dst);
4535-
return ret;
4536-
}
45374636
if (dst_reg == off_reg) {
45384637
/* scalar -= pointer. Creates an unknown scalar */
45394638
verbose(env, "R%d tried to subtract pointer from scalar\n",
@@ -4614,22 +4713,13 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
46144713
__reg_deduce_bounds(dst_reg);
46154714
__reg_bound_offset(dst_reg);
46164715

4617-
/* For unprivileged we require that resulting offset must be in bounds
4618-
* in order to be able to sanitize access later on.
4619-
*/
4620-
if (!env->allow_ptr_leaks) {
4621-
if (dst_reg->type == PTR_TO_MAP_VALUE &&
4622-
check_map_access(env, dst, dst_reg->off, 1, false)) {
4623-
verbose(env, "R%d pointer arithmetic of map value goes out of range, "
4624-
"prohibited for !root\n", dst);
4625-
return -EACCES;
4626-
} else if (dst_reg->type == PTR_TO_STACK &&
4627-
check_stack_access(env, dst_reg, dst_reg->off +
4628-
dst_reg->var_off.value, 1)) {
4629-
verbose(env, "R%d stack pointer arithmetic goes out of range, "
4630-
"prohibited for !root\n", dst);
4631-
return -EACCES;
4632-
}
4716+
if (sanitize_check_bounds(env, insn, dst_reg) < 0)
4717+
return -EACCES;
4718+
if (sanitize_needed(opcode)) {
4719+
ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg,
4720+
&tmp_aux, true);
4721+
if (ret < 0)
4722+
return sanitize_err(env, insn, ret, off_reg, dst_reg);
46334723
}
46344724

46354725
return 0;
@@ -4650,7 +4740,6 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
46504740
s64 smin_val, smax_val;
46514741
u64 umin_val, umax_val;
46524742
u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
4653-
u32 dst = insn->dst_reg;
46544743
int ret;
46554744

46564745
if (insn_bitness == 32) {
@@ -4684,13 +4773,14 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
46844773
return 0;
46854774
}
46864775

4776+
if (sanitize_needed(opcode)) {
4777+
ret = sanitize_val_alu(env, insn);
4778+
if (ret < 0)
4779+
return sanitize_err(env, insn, ret, NULL, NULL);
4780+
}
4781+
46874782
switch (opcode) {
46884783
case BPF_ADD:
4689-
ret = sanitize_val_alu(env, insn);
4690-
if (ret < 0) {
4691-
verbose(env, "R%d tried to add from different pointers or scalars\n", dst);
4692-
return ret;
4693-
}
46944784
if (signed_add_overflows(dst_reg->smin_value, smin_val) ||
46954785
signed_add_overflows(dst_reg->smax_value, smax_val)) {
46964786
dst_reg->smin_value = S64_MIN;
@@ -4710,11 +4800,6 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
47104800
dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
47114801
break;
47124802
case BPF_SUB:
4713-
ret = sanitize_val_alu(env, insn);
4714-
if (ret < 0) {
4715-
verbose(env, "R%d tried to sub from different pointers or scalars\n", dst);
4716-
return ret;
4717-
}
47184803
if (signed_sub_overflows(dst_reg->smin_value, smax_val) ||
47194804
signed_sub_overflows(dst_reg->smax_value, smin_val)) {
47204805
/* Overflow possible, we know nothing */

0 commit comments

Comments
 (0)