Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Daniel Borkmann says: ==================== pull-request: bpf 2018-11-01 The following pull-request contains BPF updates for your *net* tree. The main changes are: 1) Fix tcp_bpf_recvmsg() to return -EAGAIN instead of 0 in non-blocking case when no data is available yet, from John. 2) Fix a compilation error in libbpf_attach_type_by_name() when compiled with clang 3.8, from Andrey. 3) Fix a partial copy of map pointer on scalar alu and remove id generation for RET_PTR_TO_MAP_VALUE return types, from Daniel. 4) Add unlimited memlock limit for kernel selftest's flow_dissector_load program, from Yonghong. 5) Fix ping for some BPF shell based kselftests where distro does not ship "ping -6" anymore, from Li. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Коммит
df975da4e5
|
@ -51,6 +51,9 @@ struct bpf_reg_state {
|
||||||
* PTR_TO_MAP_VALUE_OR_NULL
|
* PTR_TO_MAP_VALUE_OR_NULL
|
||||||
*/
|
*/
|
||||||
struct bpf_map *map_ptr;
|
struct bpf_map *map_ptr;
|
||||||
|
|
||||||
|
/* Max size from any of the above. */
|
||||||
|
unsigned long raw;
|
||||||
};
|
};
|
||||||
/* Fixed part of pointer offset, pointer types only */
|
/* Fixed part of pointer offset, pointer types only */
|
||||||
s32 off;
|
s32 off;
|
||||||
|
|
|
@ -2852,10 +2852,6 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
|
||||||
regs[BPF_REG_0].type = NOT_INIT;
|
regs[BPF_REG_0].type = NOT_INIT;
|
||||||
} else if (fn->ret_type == RET_PTR_TO_MAP_VALUE_OR_NULL ||
|
} else if (fn->ret_type == RET_PTR_TO_MAP_VALUE_OR_NULL ||
|
||||||
fn->ret_type == RET_PTR_TO_MAP_VALUE) {
|
fn->ret_type == RET_PTR_TO_MAP_VALUE) {
|
||||||
if (fn->ret_type == RET_PTR_TO_MAP_VALUE)
|
|
||||||
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE;
|
|
||||||
else
|
|
||||||
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
|
|
||||||
/* There is no offset yet applied, variable or fixed */
|
/* There is no offset yet applied, variable or fixed */
|
||||||
mark_reg_known_zero(env, regs, BPF_REG_0);
|
mark_reg_known_zero(env, regs, BPF_REG_0);
|
||||||
/* remember map_ptr, so that check_map_access()
|
/* remember map_ptr, so that check_map_access()
|
||||||
|
@ -2868,7 +2864,12 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
regs[BPF_REG_0].map_ptr = meta.map_ptr;
|
regs[BPF_REG_0].map_ptr = meta.map_ptr;
|
||||||
regs[BPF_REG_0].id = ++env->id_gen;
|
if (fn->ret_type == RET_PTR_TO_MAP_VALUE) {
|
||||||
|
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE;
|
||||||
|
} else {
|
||||||
|
regs[BPF_REG_0].type = PTR_TO_MAP_VALUE_OR_NULL;
|
||||||
|
regs[BPF_REG_0].id = ++env->id_gen;
|
||||||
|
}
|
||||||
} else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) {
|
} else if (fn->ret_type == RET_PTR_TO_SOCKET_OR_NULL) {
|
||||||
int id = acquire_reference_state(env, insn_idx);
|
int id = acquire_reference_state(env, insn_idx);
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
|
@ -3046,7 +3047,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||||
dst_reg->umax_value = umax_ptr;
|
dst_reg->umax_value = umax_ptr;
|
||||||
dst_reg->var_off = ptr_reg->var_off;
|
dst_reg->var_off = ptr_reg->var_off;
|
||||||
dst_reg->off = ptr_reg->off + smin_val;
|
dst_reg->off = ptr_reg->off + smin_val;
|
||||||
dst_reg->range = ptr_reg->range;
|
dst_reg->raw = ptr_reg->raw;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* A new variable offset is created. Note that off_reg->off
|
/* A new variable offset is created. Note that off_reg->off
|
||||||
|
@ -3076,10 +3077,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||||
}
|
}
|
||||||
dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
|
dst_reg->var_off = tnum_add(ptr_reg->var_off, off_reg->var_off);
|
||||||
dst_reg->off = ptr_reg->off;
|
dst_reg->off = ptr_reg->off;
|
||||||
|
dst_reg->raw = ptr_reg->raw;
|
||||||
if (reg_is_pkt_pointer(ptr_reg)) {
|
if (reg_is_pkt_pointer(ptr_reg)) {
|
||||||
dst_reg->id = ++env->id_gen;
|
dst_reg->id = ++env->id_gen;
|
||||||
/* something was added to pkt_ptr, set range to zero */
|
/* something was added to pkt_ptr, set range to zero */
|
||||||
dst_reg->range = 0;
|
dst_reg->raw = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BPF_SUB:
|
case BPF_SUB:
|
||||||
|
@ -3108,7 +3110,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||||
dst_reg->var_off = ptr_reg->var_off;
|
dst_reg->var_off = ptr_reg->var_off;
|
||||||
dst_reg->id = ptr_reg->id;
|
dst_reg->id = ptr_reg->id;
|
||||||
dst_reg->off = ptr_reg->off - smin_val;
|
dst_reg->off = ptr_reg->off - smin_val;
|
||||||
dst_reg->range = ptr_reg->range;
|
dst_reg->raw = ptr_reg->raw;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* A new variable offset is created. If the subtrahend is known
|
/* A new variable offset is created. If the subtrahend is known
|
||||||
|
@ -3134,11 +3136,12 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
|
||||||
}
|
}
|
||||||
dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
|
dst_reg->var_off = tnum_sub(ptr_reg->var_off, off_reg->var_off);
|
||||||
dst_reg->off = ptr_reg->off;
|
dst_reg->off = ptr_reg->off;
|
||||||
|
dst_reg->raw = ptr_reg->raw;
|
||||||
if (reg_is_pkt_pointer(ptr_reg)) {
|
if (reg_is_pkt_pointer(ptr_reg)) {
|
||||||
dst_reg->id = ++env->id_gen;
|
dst_reg->id = ++env->id_gen;
|
||||||
/* something was added to pkt_ptr, set range to zero */
|
/* something was added to pkt_ptr, set range to zero */
|
||||||
if (smin_val < 0)
|
if (smin_val < 0)
|
||||||
dst_reg->range = 0;
|
dst_reg->raw = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BPF_AND:
|
case BPF_AND:
|
||||||
|
|
|
@ -145,6 +145,7 @@ msg_bytes_ready:
|
||||||
ret = err;
|
ret = err;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
copied = -EAGAIN;
|
||||||
}
|
}
|
||||||
ret = copied;
|
ret = copied;
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -2084,19 +2084,19 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||||
prog->expected_attach_type = type;
|
prog->expected_attach_type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \
|
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, atype) \
|
||||||
{ string, sizeof(string) - 1, ptype, eatype, atype }
|
{ string, sizeof(string) - 1, ptype, eatype, is_attachable, atype }
|
||||||
|
|
||||||
/* Programs that can NOT be attached. */
|
/* Programs that can NOT be attached. */
|
||||||
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL)
|
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0)
|
||||||
|
|
||||||
/* Programs that can be attached. */
|
/* Programs that can be attached. */
|
||||||
#define BPF_APROG_SEC(string, ptype, atype) \
|
#define BPF_APROG_SEC(string, ptype, atype) \
|
||||||
BPF_PROG_SEC_IMPL(string, ptype, 0, atype)
|
BPF_PROG_SEC_IMPL(string, ptype, 0, 1, atype)
|
||||||
|
|
||||||
/* Programs that must specify expected attach type at load time. */
|
/* Programs that must specify expected attach type at load time. */
|
||||||
#define BPF_EAPROG_SEC(string, ptype, eatype) \
|
#define BPF_EAPROG_SEC(string, ptype, eatype) \
|
||||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype)
|
BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, eatype)
|
||||||
|
|
||||||
/* Programs that can be attached but attach type can't be identified by section
|
/* Programs that can be attached but attach type can't be identified by section
|
||||||
* name. Kept for backward compatibility.
|
* name. Kept for backward compatibility.
|
||||||
|
@ -2108,6 +2108,7 @@ static const struct {
|
||||||
size_t len;
|
size_t len;
|
||||||
enum bpf_prog_type prog_type;
|
enum bpf_prog_type prog_type;
|
||||||
enum bpf_attach_type expected_attach_type;
|
enum bpf_attach_type expected_attach_type;
|
||||||
|
int is_attachable;
|
||||||
enum bpf_attach_type attach_type;
|
enum bpf_attach_type attach_type;
|
||||||
} section_names[] = {
|
} section_names[] = {
|
||||||
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
|
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
|
||||||
|
@ -2198,7 +2199,7 @@ int libbpf_attach_type_by_name(const char *name,
|
||||||
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
|
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
|
||||||
if (strncmp(name, section_names[i].sec, section_names[i].len))
|
if (strncmp(name, section_names[i].sec, section_names[i].len))
|
||||||
continue;
|
continue;
|
||||||
if (section_names[i].attach_type == -EINVAL)
|
if (!section_names[i].is_attachable)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
*attach_type = section_names[i].attach_type;
|
*attach_type = section_names[i].attach_type;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <bpf/bpf.h>
|
#include <bpf/bpf.h>
|
||||||
#include <bpf/libbpf.h>
|
#include <bpf/libbpf.h>
|
||||||
|
|
||||||
|
#include "bpf_rlimit.h"
|
||||||
|
|
||||||
const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector";
|
const char *cfg_pin_path = "/sys/fs/bpf/flow_dissector";
|
||||||
const char *cfg_map_name = "jmp_table";
|
const char *cfg_map_name = "jmp_table";
|
||||||
bool cfg_attach = true;
|
bool cfg_attach = true;
|
||||||
|
|
|
@ -10,7 +10,7 @@ wait_for_ip()
|
||||||
echo -n "Wait for testing link-local IP to become available "
|
echo -n "Wait for testing link-local IP to become available "
|
||||||
for _i in $(seq ${MAX_PING_TRIES}); do
|
for _i in $(seq ${MAX_PING_TRIES}); do
|
||||||
echo -n "."
|
echo -n "."
|
||||||
if ping -6 -q -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
|
if $PING6 -c 1 -W 1 ff02::1%${TEST_IF} >/dev/null 2>&1; then
|
||||||
echo " OK"
|
echo " OK"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
@ -58,5 +58,6 @@ BPF_PROG_OBJ="${DIR}/test_skb_cgroup_id_kern.o"
|
||||||
BPF_PROG_SECTION="cgroup_id_logger"
|
BPF_PROG_SECTION="cgroup_id_logger"
|
||||||
BPF_PROG_ID=0
|
BPF_PROG_ID=0
|
||||||
PROG="${DIR}/test_skb_cgroup_id_user"
|
PROG="${DIR}/test_skb_cgroup_id_user"
|
||||||
|
type ping6 >/dev/null 2>&1 && PING6="ping6" || PING6="ping -6"
|
||||||
|
|
||||||
main
|
main
|
||||||
|
|
|
@ -4,7 +4,8 @@ set -eu
|
||||||
|
|
||||||
ping_once()
|
ping_once()
|
||||||
{
|
{
|
||||||
ping -${1} -q -c 1 -W 1 ${2%%/*} >/dev/null 2>&1
|
type ping${1} >/dev/null 2>&1 && PING="ping${1}" || PING="ping -${1}"
|
||||||
|
$PING -q -c 1 -W 1 ${2%%/*} >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_ip()
|
wait_for_ip()
|
||||||
|
|
|
@ -76,7 +76,7 @@ struct bpf_test {
|
||||||
int fixup_percpu_cgroup_storage[MAX_FIXUPS];
|
int fixup_percpu_cgroup_storage[MAX_FIXUPS];
|
||||||
const char *errstr;
|
const char *errstr;
|
||||||
const char *errstr_unpriv;
|
const char *errstr_unpriv;
|
||||||
uint32_t retval;
|
uint32_t retval, retval_unpriv;
|
||||||
enum {
|
enum {
|
||||||
UNDEF,
|
UNDEF,
|
||||||
ACCEPT,
|
ACCEPT,
|
||||||
|
@ -3084,6 +3084,8 @@ static struct bpf_test tests[] = {
|
||||||
.fixup_prog1 = { 2 },
|
.fixup_prog1 = { 2 },
|
||||||
.result = ACCEPT,
|
.result = ACCEPT,
|
||||||
.retval = 42,
|
.retval = 42,
|
||||||
|
/* Verifier rewrite for unpriv skips tail call here. */
|
||||||
|
.retval_unpriv = 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"stack pointer arithmetic",
|
"stack pointer arithmetic",
|
||||||
|
@ -6454,6 +6456,256 @@ static struct bpf_test tests[] = {
|
||||||
.errstr = "R1 min value is negative",
|
.errstr = "R1 min value is negative",
|
||||||
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
.prog_type = BPF_PROG_TYPE_TRACEPOINT,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"map access: known scalar += value_ptr",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_1, 4),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.retval = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr += known scalar",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_1, 4),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.retval = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: unknown scalar += value_ptr",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_0),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.retval = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr += unknown scalar",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.retval = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr += value_ptr",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_0),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = REJECT,
|
||||||
|
.errstr = "R0 pointer += pointer prohibited",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: known scalar -= value_ptr",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_1, 4),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = REJECT,
|
||||||
|
.errstr = "R1 tried to subtract pointer from scalar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr -= known scalar",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_1, 4),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = REJECT,
|
||||||
|
.errstr = "R0 min value is outside of the array range",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr -= known scalar, 2",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_1, 6),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_2, 4),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_2),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.retval = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: unknown scalar -= value_ptr",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_1, BPF_REG_0),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = REJECT,
|
||||||
|
.errstr = "R1 tried to subtract pointer from scalar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr -= unknown scalar",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = REJECT,
|
||||||
|
.errstr = "R0 min value is negative",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr -= unknown scalar, 2",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 8),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0xf),
|
||||||
|
BPF_ALU64_IMM(BPF_OR, BPF_REG_1, 0x7),
|
||||||
|
BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_ALU64_IMM(BPF_AND, BPF_REG_1, 0x7),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = ACCEPT,
|
||||||
|
.retval = 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"map access: value_ptr -= value_ptr",
|
||||||
|
.insns = {
|
||||||
|
BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
|
||||||
|
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
|
||||||
|
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
|
||||||
|
BPF_LD_MAP_FD(BPF_REG_1, 0),
|
||||||
|
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
|
||||||
|
BPF_FUNC_map_lookup_elem),
|
||||||
|
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
|
||||||
|
BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_0),
|
||||||
|
BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_0, 0),
|
||||||
|
BPF_MOV64_IMM(BPF_REG_0, 1),
|
||||||
|
BPF_EXIT_INSN(),
|
||||||
|
},
|
||||||
|
.fixup_map_array_48b = { 3 },
|
||||||
|
.result = REJECT,
|
||||||
|
.errstr = "R0 invalid mem access 'inv'",
|
||||||
|
.errstr_unpriv = "R0 pointer -= pointer prohibited",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"map lookup helper access to map",
|
"map lookup helper access to map",
|
||||||
.insns = {
|
.insns = {
|
||||||
|
@ -13899,6 +14151,33 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_map_type prog_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int set_admin(bool admin)
|
||||||
|
{
|
||||||
|
cap_t caps;
|
||||||
|
const cap_value_t cap_val = CAP_SYS_ADMIN;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
caps = cap_get_proc();
|
||||||
|
if (!caps) {
|
||||||
|
perror("cap_get_proc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_val,
|
||||||
|
admin ? CAP_SET : CAP_CLEAR)) {
|
||||||
|
perror("cap_set_flag");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (cap_set_proc(caps)) {
|
||||||
|
perror("cap_set_proc");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
if (cap_free(caps))
|
||||||
|
perror("cap_free");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_test_single(struct bpf_test *test, bool unpriv,
|
static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||||
int *passes, int *errors)
|
int *passes, int *errors)
|
||||||
{
|
{
|
||||||
|
@ -13907,6 +14186,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||||
struct bpf_insn *prog = test->insns;
|
struct bpf_insn *prog = test->insns;
|
||||||
int map_fds[MAX_NR_MAPS];
|
int map_fds[MAX_NR_MAPS];
|
||||||
const char *expected_err;
|
const char *expected_err;
|
||||||
|
uint32_t expected_val;
|
||||||
uint32_t retval;
|
uint32_t retval;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
|
@ -13926,6 +14206,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||||
test->result_unpriv : test->result;
|
test->result_unpriv : test->result;
|
||||||
expected_err = unpriv && test->errstr_unpriv ?
|
expected_err = unpriv && test->errstr_unpriv ?
|
||||||
test->errstr_unpriv : test->errstr;
|
test->errstr_unpriv : test->errstr;
|
||||||
|
expected_val = unpriv && test->retval_unpriv ?
|
||||||
|
test->retval_unpriv : test->retval;
|
||||||
|
|
||||||
reject_from_alignment = fd_prog < 0 &&
|
reject_from_alignment = fd_prog < 0 &&
|
||||||
(test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) &&
|
(test->flags & F_NEEDS_EFFICIENT_UNALIGNED_ACCESS) &&
|
||||||
|
@ -13959,16 +14241,20 @@ static void do_test_single(struct bpf_test *test, bool unpriv,
|
||||||
__u8 tmp[TEST_DATA_LEN << 2];
|
__u8 tmp[TEST_DATA_LEN << 2];
|
||||||
__u32 size_tmp = sizeof(tmp);
|
__u32 size_tmp = sizeof(tmp);
|
||||||
|
|
||||||
|
if (unpriv)
|
||||||
|
set_admin(true);
|
||||||
err = bpf_prog_test_run(fd_prog, 1, test->data,
|
err = bpf_prog_test_run(fd_prog, 1, test->data,
|
||||||
sizeof(test->data), tmp, &size_tmp,
|
sizeof(test->data), tmp, &size_tmp,
|
||||||
&retval, NULL);
|
&retval, NULL);
|
||||||
|
if (unpriv)
|
||||||
|
set_admin(false);
|
||||||
if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
|
if (err && errno != 524/*ENOTSUPP*/ && errno != EPERM) {
|
||||||
printf("Unexpected bpf_prog_test_run error\n");
|
printf("Unexpected bpf_prog_test_run error\n");
|
||||||
goto fail_log;
|
goto fail_log;
|
||||||
}
|
}
|
||||||
if (!err && retval != test->retval &&
|
if (!err && retval != expected_val &&
|
||||||
test->retval != POINTER_VALUE) {
|
expected_val != POINTER_VALUE) {
|
||||||
printf("FAIL retval %d != %d\n", retval, test->retval);
|
printf("FAIL retval %d != %d\n", retval, expected_val);
|
||||||
goto fail_log;
|
goto fail_log;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14011,33 +14297,6 @@ static bool is_admin(void)
|
||||||
return (sysadmin == CAP_SET);
|
return (sysadmin == CAP_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_admin(bool admin)
|
|
||||||
{
|
|
||||||
cap_t caps;
|
|
||||||
const cap_value_t cap_val = CAP_SYS_ADMIN;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
caps = cap_get_proc();
|
|
||||||
if (!caps) {
|
|
||||||
perror("cap_get_proc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap_val,
|
|
||||||
admin ? CAP_SET : CAP_CLEAR)) {
|
|
||||||
perror("cap_set_flag");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (cap_set_proc(caps)) {
|
|
||||||
perror("cap_set_proc");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
out:
|
|
||||||
if (cap_free(caps))
|
|
||||||
perror("cap_free");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void get_unpriv_disabled()
|
static void get_unpriv_disabled()
|
||||||
{
|
{
|
||||||
char buf[2];
|
char buf[2];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче