flow_dissector: implements flow dissector BPF hook
Adds a hook for programs of type BPF_PROG_TYPE_FLOW_DISSECTOR and attach type BPF_FLOW_DISSECTOR that is executed in the flow dissector path. The BPF program is per-network namespace. Signed-off-by: Petar Penkov <ppenkov@google.com> Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:

committed by
Alexei Starovoitov

parent
1edb6e035e
commit
d58e468b11
@@ -1615,6 +1615,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
|
||||
case BPF_LIRC_MODE2:
|
||||
ptype = BPF_PROG_TYPE_LIRC_MODE2;
|
||||
break;
|
||||
case BPF_FLOW_DISSECTOR:
|
||||
ptype = BPF_PROG_TYPE_FLOW_DISSECTOR;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1636,6 +1639,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
|
||||
case BPF_PROG_TYPE_LIRC_MODE2:
|
||||
ret = lirc_prog_attach(attr, prog);
|
||||
break;
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
ret = skb_flow_dissector_bpf_prog_attach(attr, prog);
|
||||
break;
|
||||
default:
|
||||
ret = cgroup_bpf_prog_attach(attr, ptype, prog);
|
||||
}
|
||||
@@ -1688,6 +1694,8 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
||||
return sockmap_get_from_fd(attr, BPF_PROG_TYPE_SK_SKB, NULL);
|
||||
case BPF_LIRC_MODE2:
|
||||
return lirc_prog_detach(attr);
|
||||
case BPF_FLOW_DISSECTOR:
|
||||
return skb_flow_dissector_bpf_prog_detach(attr);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@@ -261,6 +261,7 @@ static const char * const reg_type_str[] = {
|
||||
[PTR_TO_PACKET] = "pkt",
|
||||
[PTR_TO_PACKET_META] = "pkt_meta",
|
||||
[PTR_TO_PACKET_END] = "pkt_end",
|
||||
[PTR_TO_FLOW_KEYS] = "flow_keys",
|
||||
};
|
||||
|
||||
static char slot_type_char[] = {
|
||||
@@ -965,6 +966,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
|
||||
case PTR_TO_PACKET:
|
||||
case PTR_TO_PACKET_META:
|
||||
case PTR_TO_PACKET_END:
|
||||
case PTR_TO_FLOW_KEYS:
|
||||
case CONST_PTR_TO_MAP:
|
||||
return true;
|
||||
default:
|
||||
@@ -1238,6 +1240,7 @@ static bool may_access_direct_pkt_data(struct bpf_verifier_env *env,
|
||||
case BPF_PROG_TYPE_LWT_XMIT:
|
||||
case BPF_PROG_TYPE_SK_SKB:
|
||||
case BPF_PROG_TYPE_SK_MSG:
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
if (meta)
|
||||
return meta->pkt_access;
|
||||
|
||||
@@ -1321,6 +1324,18 @@ static int check_ctx_access(struct bpf_verifier_env *env, int insn_idx, int off,
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
static int check_flow_keys_access(struct bpf_verifier_env *env, int off,
|
||||
int size)
|
||||
{
|
||||
if (size < 0 || off < 0 ||
|
||||
(u64)off + size > sizeof(struct bpf_flow_keys)) {
|
||||
verbose(env, "invalid access to flow keys off=%d size=%d\n",
|
||||
off, size);
|
||||
return -EACCES;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool __is_pointer_value(bool allow_ptr_leaks,
|
||||
const struct bpf_reg_state *reg)
|
||||
{
|
||||
@@ -1422,6 +1437,9 @@ static int check_ptr_alignment(struct bpf_verifier_env *env,
|
||||
* right in front, treat it the very same way.
|
||||
*/
|
||||
return check_pkt_ptr_alignment(env, reg, off, size, strict);
|
||||
case PTR_TO_FLOW_KEYS:
|
||||
pointer_desc = "flow keys ";
|
||||
break;
|
||||
case PTR_TO_MAP_VALUE:
|
||||
pointer_desc = "value ";
|
||||
break;
|
||||
@@ -1692,6 +1710,17 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
|
||||
err = check_packet_access(env, regno, off, size, false);
|
||||
if (!err && t == BPF_READ && value_regno >= 0)
|
||||
mark_reg_unknown(env, regs, value_regno);
|
||||
} else if (reg->type == PTR_TO_FLOW_KEYS) {
|
||||
if (t == BPF_WRITE && value_regno >= 0 &&
|
||||
is_pointer_value(env, value_regno)) {
|
||||
verbose(env, "R%d leaks addr into flow keys\n",
|
||||
value_regno);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
err = check_flow_keys_access(env, off, size);
|
||||
if (!err && t == BPF_READ && value_regno >= 0)
|
||||
mark_reg_unknown(env, regs, value_regno);
|
||||
} else {
|
||||
verbose(env, "R%d invalid mem access '%s'\n", regno,
|
||||
reg_type_str[reg->type]);
|
||||
@@ -1839,6 +1868,8 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
|
||||
case PTR_TO_PACKET_META:
|
||||
return check_packet_access(env, regno, reg->off, access_size,
|
||||
zero_size_allowed);
|
||||
case PTR_TO_FLOW_KEYS:
|
||||
return check_flow_keys_access(env, reg->off, access_size);
|
||||
case PTR_TO_MAP_VALUE:
|
||||
return check_map_access(env, regno, reg->off, access_size,
|
||||
zero_size_allowed);
|
||||
@@ -4366,6 +4397,7 @@ static bool regsafe(struct bpf_reg_state *rold, struct bpf_reg_state *rcur,
|
||||
case PTR_TO_CTX:
|
||||
case CONST_PTR_TO_MAP:
|
||||
case PTR_TO_PACKET_END:
|
||||
case PTR_TO_FLOW_KEYS:
|
||||
/* Only valid matches are exact, which memcmp() above
|
||||
* would have accepted
|
||||
*/
|
||||
|
Reference in New Issue
Block a user