Skip to content

Commit 1c23876

Browse files
committed
Merge branch 'bpf-improvements'
Alexei Starovoitov says: ==================== bpf improvements Two bpf improvements: 1. allow bpf helpers like bpf_map_lookup_elem() access packet data directly for XDP programs 2. enable bpf_get_prandom_u32() for tracing programs ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 03ff497 + 8937bd8 commit 1c23876

File tree

3 files changed

+155
-22
lines changed

3 files changed

+155
-22
lines changed

kernel/bpf/verifier.c

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -930,14 +930,14 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
930930
enum bpf_arg_type arg_type,
931931
struct bpf_call_arg_meta *meta)
932932
{
933-
struct reg_state *reg = env->cur_state.regs + regno;
934-
enum bpf_reg_type expected_type;
933+
struct reg_state *regs = env->cur_state.regs, *reg = &regs[regno];
934+
enum bpf_reg_type expected_type, type = reg->type;
935935
int err = 0;
936936

937937
if (arg_type == ARG_DONTCARE)
938938
return 0;
939939

940-
if (reg->type == NOT_INIT) {
940+
if (type == NOT_INIT) {
941941
verbose("R%d !read_ok\n", regno);
942942
return -EACCES;
943943
}
@@ -950,37 +950,46 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
950950
return 0;
951951
}
952952

953+
if (type == PTR_TO_PACKET && !may_write_pkt_data(env->prog->type)) {
954+
verbose("helper access to the packet is not allowed for clsact\n");
955+
return -EACCES;
956+
}
957+
953958
if (arg_type == ARG_PTR_TO_MAP_KEY ||
954959
arg_type == ARG_PTR_TO_MAP_VALUE) {
955960
expected_type = PTR_TO_STACK;
961+
if (type != PTR_TO_PACKET && type != expected_type)
962+
goto err_type;
956963
} else if (arg_type == ARG_CONST_STACK_SIZE ||
957964
arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
958965
expected_type = CONST_IMM;
966+
if (type != expected_type)
967+
goto err_type;
959968
} else if (arg_type == ARG_CONST_MAP_PTR) {
960969
expected_type = CONST_PTR_TO_MAP;
970+
if (type != expected_type)
971+
goto err_type;
961972
} else if (arg_type == ARG_PTR_TO_CTX) {
962973
expected_type = PTR_TO_CTX;
974+
if (type != expected_type)
975+
goto err_type;
963976
} else if (arg_type == ARG_PTR_TO_STACK ||
964977
arg_type == ARG_PTR_TO_RAW_STACK) {
965978
expected_type = PTR_TO_STACK;
966979
/* One exception here. In case function allows for NULL to be
967980
* passed in as argument, it's a CONST_IMM type. Final test
968981
* happens during stack boundary checking.
969982
*/
970-
if (reg->type == CONST_IMM && reg->imm == 0)
971-
expected_type = CONST_IMM;
983+
if (type == CONST_IMM && reg->imm == 0)
984+
/* final test in check_stack_boundary() */;
985+
else if (type != PTR_TO_PACKET && type != expected_type)
986+
goto err_type;
972987
meta->raw_mode = arg_type == ARG_PTR_TO_RAW_STACK;
973988
} else {
974989
verbose("unsupported arg_type %d\n", arg_type);
975990
return -EFAULT;
976991
}
977992

978-
if (reg->type != expected_type) {
979-
verbose("R%d type=%s expected=%s\n", regno,
980-
reg_type_str[reg->type], reg_type_str[expected_type]);
981-
return -EACCES;
982-
}
983-
984993
if (arg_type == ARG_CONST_MAP_PTR) {
985994
/* bpf_map_xxx(map_ptr) call: remember that map_ptr */
986995
meta->map_ptr = reg->map_ptr;
@@ -998,8 +1007,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
9981007
verbose("invalid map_ptr to access map->key\n");
9991008
return -EACCES;
10001009
}
1001-
err = check_stack_boundary(env, regno, meta->map_ptr->key_size,
1002-
false, NULL);
1010+
if (type == PTR_TO_PACKET)
1011+
err = check_packet_access(env, regno, 0,
1012+
meta->map_ptr->key_size);
1013+
else
1014+
err = check_stack_boundary(env, regno,
1015+
meta->map_ptr->key_size,
1016+
false, NULL);
10031017
} else if (arg_type == ARG_PTR_TO_MAP_VALUE) {
10041018
/* bpf_map_xxx(..., map_ptr, ..., value) call:
10051019
* check [value, value + map->value_size) validity
@@ -1009,9 +1023,13 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
10091023
verbose("invalid map_ptr to access map->value\n");
10101024
return -EACCES;
10111025
}
1012-
err = check_stack_boundary(env, regno,
1013-
meta->map_ptr->value_size,
1014-
false, NULL);
1026+
if (type == PTR_TO_PACKET)
1027+
err = check_packet_access(env, regno, 0,
1028+
meta->map_ptr->value_size);
1029+
else
1030+
err = check_stack_boundary(env, regno,
1031+
meta->map_ptr->value_size,
1032+
false, NULL);
10151033
} else if (arg_type == ARG_CONST_STACK_SIZE ||
10161034
arg_type == ARG_CONST_STACK_SIZE_OR_ZERO) {
10171035
bool zero_size_allowed = (arg_type == ARG_CONST_STACK_SIZE_OR_ZERO);
@@ -1025,11 +1043,18 @@ static int check_func_arg(struct verifier_env *env, u32 regno,
10251043
verbose("ARG_CONST_STACK_SIZE cannot be first argument\n");
10261044
return -EACCES;
10271045
}
1028-
err = check_stack_boundary(env, regno - 1, reg->imm,
1029-
zero_size_allowed, meta);
1046+
if (regs[regno - 1].type == PTR_TO_PACKET)
1047+
err = check_packet_access(env, regno - 1, 0, reg->imm);
1048+
else
1049+
err = check_stack_boundary(env, regno - 1, reg->imm,
1050+
zero_size_allowed, meta);
10301051
}
10311052

10321053
return err;
1054+
err_type:
1055+
verbose("R%d type=%s expected=%s\n", regno,
1056+
reg_type_str[type], reg_type_str[expected_type]);
1057+
return -EACCES;
10331058
}
10341059

10351060
static int check_map_func_compatibility(struct bpf_map *map, int func_id)

kernel/trace/bpf_trace.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,8 @@ static const struct bpf_func_proto *tracing_func_proto(enum bpf_func_id func_id)
437437
return bpf_get_probe_write_proto();
438438
case BPF_FUNC_current_task_under_cgroup:
439439
return &bpf_current_task_under_cgroup_proto;
440+
case BPF_FUNC_get_prandom_u32:
441+
return &bpf_get_prandom_u32_proto;
440442
default:
441443
return NULL;
442444
}

samples/bpf/test_verifier.c

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,7 +1449,7 @@ static struct bpf_test tests[] = {
14491449
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
14501450
},
14511451
{
1452-
"pkt: test1",
1452+
"direct packet access: test1",
14531453
.insns = {
14541454
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
14551455
offsetof(struct __sk_buff, data)),
@@ -1466,7 +1466,7 @@ static struct bpf_test tests[] = {
14661466
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
14671467
},
14681468
{
1469-
"pkt: test2",
1469+
"direct packet access: test2",
14701470
.insns = {
14711471
BPF_MOV64_IMM(BPF_REG_0, 1),
14721472
BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1,
@@ -1499,7 +1499,7 @@ static struct bpf_test tests[] = {
14991499
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
15001500
},
15011501
{
1502-
"pkt: test3",
1502+
"direct packet access: test3",
15031503
.insns = {
15041504
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
15051505
offsetof(struct __sk_buff, data)),
@@ -1511,7 +1511,7 @@ static struct bpf_test tests[] = {
15111511
.prog_type = BPF_PROG_TYPE_SOCKET_FILTER,
15121512
},
15131513
{
1514-
"pkt: test4",
1514+
"direct packet access: test4",
15151515
.insns = {
15161516
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
15171517
offsetof(struct __sk_buff, data)),
@@ -1528,6 +1528,112 @@ static struct bpf_test tests[] = {
15281528
.result = REJECT,
15291529
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
15301530
},
1531+
{
1532+
"helper access to packet: test1, valid packet_ptr range",
1533+
.insns = {
1534+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
1535+
offsetof(struct xdp_md, data)),
1536+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
1537+
offsetof(struct xdp_md, data_end)),
1538+
BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
1539+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
1540+
BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 5),
1541+
BPF_LD_MAP_FD(BPF_REG_1, 0),
1542+
BPF_MOV64_REG(BPF_REG_3, BPF_REG_2),
1543+
BPF_MOV64_IMM(BPF_REG_4, 0),
1544+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem),
1545+
BPF_MOV64_IMM(BPF_REG_0, 0),
1546+
BPF_EXIT_INSN(),
1547+
},
1548+
.fixup = {5},
1549+
.result_unpriv = ACCEPT,
1550+
.result = ACCEPT,
1551+
.prog_type = BPF_PROG_TYPE_XDP,
1552+
},
1553+
{
1554+
"helper access to packet: test2, unchecked packet_ptr",
1555+
.insns = {
1556+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
1557+
offsetof(struct xdp_md, data)),
1558+
BPF_LD_MAP_FD(BPF_REG_1, 0),
1559+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1560+
BPF_MOV64_IMM(BPF_REG_0, 0),
1561+
BPF_EXIT_INSN(),
1562+
},
1563+
.fixup = {1},
1564+
.result = REJECT,
1565+
.errstr = "invalid access to packet",
1566+
.prog_type = BPF_PROG_TYPE_XDP,
1567+
},
1568+
{
1569+
"helper access to packet: test3, variable add",
1570+
.insns = {
1571+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
1572+
offsetof(struct xdp_md, data)),
1573+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
1574+
offsetof(struct xdp_md, data_end)),
1575+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
1576+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8),
1577+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 10),
1578+
BPF_LDX_MEM(BPF_B, BPF_REG_5, BPF_REG_2, 0),
1579+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
1580+
BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_5),
1581+
BPF_MOV64_REG(BPF_REG_5, BPF_REG_4),
1582+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 8),
1583+
BPF_JMP_REG(BPF_JGT, BPF_REG_5, BPF_REG_3, 4),
1584+
BPF_LD_MAP_FD(BPF_REG_1, 0),
1585+
BPF_MOV64_REG(BPF_REG_2, BPF_REG_4),
1586+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1587+
BPF_MOV64_IMM(BPF_REG_0, 0),
1588+
BPF_EXIT_INSN(),
1589+
},
1590+
.fixup = {11},
1591+
.result = ACCEPT,
1592+
.prog_type = BPF_PROG_TYPE_XDP,
1593+
},
1594+
{
1595+
"helper access to packet: test4, packet_ptr with bad range",
1596+
.insns = {
1597+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
1598+
offsetof(struct xdp_md, data)),
1599+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
1600+
offsetof(struct xdp_md, data_end)),
1601+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
1602+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
1603+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 2),
1604+
BPF_MOV64_IMM(BPF_REG_0, 0),
1605+
BPF_EXIT_INSN(),
1606+
BPF_LD_MAP_FD(BPF_REG_1, 0),
1607+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1608+
BPF_MOV64_IMM(BPF_REG_0, 0),
1609+
BPF_EXIT_INSN(),
1610+
},
1611+
.fixup = {7},
1612+
.result = REJECT,
1613+
.errstr = "invalid access to packet",
1614+
.prog_type = BPF_PROG_TYPE_XDP,
1615+
},
1616+
{
1617+
"helper access to packet: test5, packet_ptr with too short range",
1618+
.insns = {
1619+
BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
1620+
offsetof(struct xdp_md, data)),
1621+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
1622+
offsetof(struct xdp_md, data_end)),
1623+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1),
1624+
BPF_MOV64_REG(BPF_REG_4, BPF_REG_2),
1625+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 7),
1626+
BPF_JMP_REG(BPF_JGT, BPF_REG_4, BPF_REG_3, 3),
1627+
BPF_LD_MAP_FD(BPF_REG_1, 0),
1628+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
1629+
BPF_MOV64_IMM(BPF_REG_0, 0),
1630+
BPF_EXIT_INSN(),
1631+
},
1632+
.fixup = {6},
1633+
.result = REJECT,
1634+
.errstr = "invalid access to packet",
1635+
.prog_type = BPF_PROG_TYPE_XDP,
1636+
},
15311637
};
15321638

15331639
static int probe_filter_length(struct bpf_insn *fp)

0 commit comments

Comments
 (0)