aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2017-10-03 01:50:23 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-04 19:05:05 -0400
commit390ee7e29fc8e6e90d3065b00afb047c4ee552f9 (patch)
tree9a5d9870bb4cf67905cb638cbe1b3063251a100f
parent468e2f64d220fe2dc11caa2bcb9b3a1e50fc7321 (diff)
bpf: enforce return code for cgroup-bpf programs
with addition of tnum logic the verifier got smart enough and we can enforce return codes at program load time. For now do so for cgroup-bpf program types. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--kernel/bpf/verifier.c40
-rw-r--r--tools/testing/selftests/bpf/test_verifier.c72
2 files changed, 112 insertions, 0 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 4cf9b72c59a0..52b022310f6a 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3073,6 +3073,43 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
3073 return 0; 3073 return 0;
3074} 3074}
3075 3075
3076static int check_return_code(struct bpf_verifier_env *env)
3077{
3078 struct bpf_reg_state *reg;
3079 struct tnum range = tnum_range(0, 1);
3080
3081 switch (env->prog->type) {
3082 case BPF_PROG_TYPE_CGROUP_SKB:
3083 case BPF_PROG_TYPE_CGROUP_SOCK:
3084 case BPF_PROG_TYPE_SOCK_OPS:
3085 break;
3086 default:
3087 return 0;
3088 }
3089
3090 reg = &env->cur_state.regs[BPF_REG_0];
3091 if (reg->type != SCALAR_VALUE) {
3092 verbose("At program exit the register R0 is not a known value (%s)\n",
3093 reg_type_str[reg->type]);
3094 return -EINVAL;
3095 }
3096
3097 if (!tnum_in(range, reg->var_off)) {
3098 verbose("At program exit the register R0 ");
3099 if (!tnum_is_unknown(reg->var_off)) {
3100 char tn_buf[48];
3101
3102 tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
3103 verbose("has value %s", tn_buf);
3104 } else {
3105 verbose("has unknown scalar value");
3106 }
3107 verbose(" should have been 0 or 1\n");
3108 return -EINVAL;
3109 }
3110 return 0;
3111}
3112
3076/* non-recursive DFS pseudo code 3113/* non-recursive DFS pseudo code
3077 * 1 procedure DFS-iterative(G,v): 3114 * 1 procedure DFS-iterative(G,v):
3078 * 2 label v as discovered 3115 * 2 label v as discovered
@@ -3863,6 +3900,9 @@ static int do_check(struct bpf_verifier_env *env)
3863 return -EACCES; 3900 return -EACCES;
3864 } 3901 }
3865 3902
3903 err = check_return_code(env);
3904 if (err)
3905 return err;
3866process_bpf_exit: 3906process_bpf_exit:
3867 insn_idx = pop_stack(env, &prev_insn_idx); 3907 insn_idx = pop_stack(env, &prev_insn_idx);
3868 if (insn_idx < 0) { 3908 if (insn_idx < 0) {
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 290d5056c165..cc91d0159f43 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -6892,6 +6892,78 @@ static struct bpf_test tests[] = {
6892 .result = ACCEPT, 6892 .result = ACCEPT,
6893 .prog_type = BPF_PROG_TYPE_XDP, 6893 .prog_type = BPF_PROG_TYPE_XDP,
6894 }, 6894 },
6895 {
6896 "bpf_exit with invalid return code. test1",
6897 .insns = {
6898 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
6899 BPF_EXIT_INSN(),
6900 },
6901 .errstr = "R0 has value (0x0; 0xffffffff)",
6902 .result = REJECT,
6903 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6904 },
6905 {
6906 "bpf_exit with invalid return code. test2",
6907 .insns = {
6908 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
6909 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 1),
6910 BPF_EXIT_INSN(),
6911 },
6912 .result = ACCEPT,
6913 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6914 },
6915 {
6916 "bpf_exit with invalid return code. test3",
6917 .insns = {
6918 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
6919 BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 3),
6920 BPF_EXIT_INSN(),
6921 },
6922 .errstr = "R0 has value (0x0; 0x3)",
6923 .result = REJECT,
6924 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6925 },
6926 {
6927 "bpf_exit with invalid return code. test4",
6928 .insns = {
6929 BPF_MOV64_IMM(BPF_REG_0, 1),
6930 BPF_EXIT_INSN(),
6931 },
6932 .result = ACCEPT,
6933 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6934 },
6935 {
6936 "bpf_exit with invalid return code. test5",
6937 .insns = {
6938 BPF_MOV64_IMM(BPF_REG_0, 2),
6939 BPF_EXIT_INSN(),
6940 },
6941 .errstr = "R0 has value (0x2; 0x0)",
6942 .result = REJECT,
6943 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6944 },
6945 {
6946 "bpf_exit with invalid return code. test6",
6947 .insns = {
6948 BPF_MOV64_REG(BPF_REG_0, BPF_REG_1),
6949 BPF_EXIT_INSN(),
6950 },
6951 .errstr = "R0 is not a known value (ctx)",
6952 .result = REJECT,
6953 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6954 },
6955 {
6956 "bpf_exit with invalid return code. test7",
6957 .insns = {
6958 BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
6959 BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 4),
6960 BPF_ALU64_REG(BPF_MUL, BPF_REG_0, BPF_REG_2),
6961 BPF_EXIT_INSN(),
6962 },
6963 .errstr = "R0 has unknown scalar value",
6964 .result = REJECT,
6965 .prog_type = BPF_PROG_TYPE_CGROUP_SOCK,
6966 },
6895}; 6967};
6896 6968
6897static int probe_filter_length(const struct bpf_insn *fp) 6969static int probe_filter_length(const struct bpf_insn *fp)