Skip to content

Commit dbcfe5f

Browse files
gianlucaborellodavem330
authored andcommitted
bpf: split check_mem_access logic for map values
Move the logic to check memory accesses to a PTR_TO_MAP_VALUE_ADJ from check_mem_access() to a separate helper check_map_access_adj(). This enables to use those checks in other parts of the verifier as well, where boundaries on PTR_TO_MAP_VALUE_ADJ might need to be checked, for example when checking helper function arguments. The same thing is already happening for other types such as PTR_TO_PACKET and its check_packet_access() helper. The code has been copied verbatim, with the only difference of removing the "off += reg->max_value" statement and moving the sum into the call statement to check_map_access(), as that was only needed due to the earlier common check_map_access() call. Signed-off-by: Gianluca Borello <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f3a3e24 commit dbcfe5f

File tree

1 file changed

+49
-39
lines changed

1 file changed

+49
-39
lines changed

kernel/bpf/verifier.c

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,51 @@ static int check_map_access(struct bpf_verifier_env *env, u32 regno, int off,
635635
return 0;
636636
}
637637

638+
/* check read/write into an adjusted map element */
639+
static int check_map_access_adj(struct bpf_verifier_env *env, u32 regno,
640+
int off, int size)
641+
{
642+
struct bpf_verifier_state *state = &env->cur_state;
643+
struct bpf_reg_state *reg = &state->regs[regno];
644+
int err;
645+
646+
/* We adjusted the register to this map value, so we
647+
* need to change off and size to min_value and max_value
648+
* respectively to make sure our theoretical access will be
649+
* safe.
650+
*/
651+
if (log_level)
652+
print_verifier_state(state);
653+
env->varlen_map_value_access = true;
654+
/* The minimum value is only important with signed
655+
* comparisons where we can't assume the floor of a
656+
* value is 0. If we are using signed variables for our
657+
* index'es we need to make sure that whatever we use
658+
* will have a set floor within our range.
659+
*/
660+
if (reg->min_value < 0) {
661+
verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
662+
regno);
663+
return -EACCES;
664+
}
665+
err = check_map_access(env, regno, reg->min_value + off, size);
666+
if (err) {
667+
verbose("R%d min value is outside of the array range\n",
668+
regno);
669+
return err;
670+
}
671+
672+
/* If we haven't set a max value then we need to bail
673+
* since we can't be sure we won't do bad things.
674+
*/
675+
if (reg->max_value == BPF_REGISTER_MAX_RANGE) {
676+
verbose("R%d unbounded memory access, make sure to bounds check any array access into a map\n",
677+
regno);
678+
return -EACCES;
679+
}
680+
return check_map_access(env, regno, reg->max_value + off, size);
681+
}
682+
638683
#define MAX_PACKET_OFF 0xffff
639684

640685
static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
@@ -775,45 +820,10 @@ static int check_mem_access(struct bpf_verifier_env *env, u32 regno, int off,
775820
return -EACCES;
776821
}
777822

778-
/* If we adjusted the register to this map value at all then we
779-
* need to change off and size to min_value and max_value
780-
* respectively to make sure our theoretical access will be
781-
* safe.
782-
*/
783-
if (reg->type == PTR_TO_MAP_VALUE_ADJ) {
784-
if (log_level)
785-
print_verifier_state(state);
786-
env->varlen_map_value_access = true;
787-
/* The minimum value is only important with signed
788-
* comparisons where we can't assume the floor of a
789-
* value is 0. If we are using signed variables for our
790-
* index'es we need to make sure that whatever we use
791-
* will have a set floor within our range.
792-
*/
793-
if (reg->min_value < 0) {
794-
verbose("R%d min value is negative, either use unsigned index or do a if (index >=0) check.\n",
795-
regno);
796-
return -EACCES;
797-
}
798-
err = check_map_access(env, regno, reg->min_value + off,
799-
size);
800-
if (err) {
801-
verbose("R%d min value is outside of the array range\n",
802-
regno);
803-
return err;
804-
}
805-
806-
/* If we haven't set a max value then we need to bail
807-
* since we can't be sure we won't do bad things.
808-
*/
809-
if (reg->max_value == BPF_REGISTER_MAX_RANGE) {
810-
verbose("R%d unbounded memory access, make sure to bounds check any array access into a map\n",
811-
regno);
812-
return -EACCES;
813-
}
814-
off += reg->max_value;
815-
}
816-
err = check_map_access(env, regno, off, size);
823+
if (reg->type == PTR_TO_MAP_VALUE_ADJ)
824+
err = check_map_access_adj(env, regno, off, size);
825+
else
826+
err = check_map_access(env, regno, off, size);
817827
if (!err && t == BPF_READ && value_regno >= 0)
818828
mark_reg_unknown_value(state->regs, value_regno);
819829

0 commit comments

Comments
 (0)