Commit 977e4899 authored by David S. Miller's avatar David S. Miller
Browse files

Merge ra.kernel.org:/pub/scm/linux/kernel/git/bpf/bpf



Daniel Borkmann says:

====================
pull-request: bpf 2019-01-08

The following pull-request contains BPF updates for your *net* tree.

The main changes are:

1) Fix BSD'ism in sendmsg(2) to rewrite unspecified IPv6 dst for
   unconnected UDP sockets with [::1] _after_ cgroup BPF invocation,
   from Andrey.

2) Follow-up fix to the speculation fix where we need to reject a
   corner case for sanitation when ptr and scalars are mixed in the
   same alu op. Also, some unrelated minor doc fixes, from Daniel.

3) Fix BPF kselftest's incorrect uses of create_and_get_cgroup()
   by not assuming fd of zero value to be the result of an error
   case, from Stanislav.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 26d92e95 2dc0f02d
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -157,12 +157,11 @@ Q: Does BPF have a stable ABI?
------------------------------
A: YES. BPF instructions, arguments to BPF programs, set of helper
functions and their arguments, recognized return codes are all part
of ABI. However when tracing programs are using bpf_probe_read() helper
to walk kernel internal datastructures and compile with kernel
internal headers these accesses can and will break with newer
kernels. The union bpf_attr -> kern_version is checked at load time
to prevent accidentally loading kprobe-based bpf programs written
for a different kernel. Networking programs don't do kern_version check.
of ABI. However there is one specific exception to tracing programs
which are using helpers like bpf_probe_read() to walk kernel internal
data structures and compile with kernel internal headers. Both of these
kernel internals are subject to change and can break with newer kernels
such that the program needs to be adapted accordingly.

Q: How much stack space a BPF program uses?
-------------------------------------------
+1 −0
Original line number Diff line number Diff line
@@ -172,6 +172,7 @@ struct bpf_verifier_state_list {
#define BPF_ALU_SANITIZE_SRC		1U
#define BPF_ALU_SANITIZE_DST		2U
#define BPF_ALU_NEG_VALUE		(1U << 2)
#define BPF_ALU_NON_POINTER		(1U << 3)
#define BPF_ALU_SANITIZE		(BPF_ALU_SANITIZE_SRC | \
					 BPF_ALU_SANITIZE_DST)

+48 −13
Original line number Diff line number Diff line
@@ -3103,6 +3103,40 @@ static int retrieve_ptr_limit(const struct bpf_reg_state *ptr_reg,
	}
}

static bool can_skip_alu_sanitation(const struct bpf_verifier_env *env,
				    const struct bpf_insn *insn)
{
	return env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K;
}

static int update_alu_sanitation_state(struct bpf_insn_aux_data *aux,
				       u32 alu_state, u32 alu_limit)
{
	/* If we arrived here from different branches with different
	 * state or limits to sanitize, then this won't work.
	 */
	if (aux->alu_state &&
	    (aux->alu_state != alu_state ||
	     aux->alu_limit != alu_limit))
		return -EACCES;

	/* Corresponding fixup done in fixup_bpf_calls(). */
	aux->alu_state = alu_state;
	aux->alu_limit = alu_limit;
	return 0;
}

static int sanitize_val_alu(struct bpf_verifier_env *env,
			    struct bpf_insn *insn)
{
	struct bpf_insn_aux_data *aux = cur_aux(env);

	if (can_skip_alu_sanitation(env, insn))
		return 0;

	return update_alu_sanitation_state(aux, BPF_ALU_NON_POINTER, 0);
}

static int sanitize_ptr_alu(struct bpf_verifier_env *env,
			    struct bpf_insn *insn,
			    const struct bpf_reg_state *ptr_reg,
@@ -3117,7 +3151,7 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,
	struct bpf_reg_state tmp;
	bool ret;

	if (env->allow_ptr_leaks || BPF_SRC(insn->code) == BPF_K)
	if (can_skip_alu_sanitation(env, insn))
		return 0;

	/* We already marked aux for masking from non-speculative
@@ -3133,19 +3167,8 @@ static int sanitize_ptr_alu(struct bpf_verifier_env *env,

	if (retrieve_ptr_limit(ptr_reg, &alu_limit, opcode, off_is_neg))
		return 0;

	/* If we arrived here from different branches with different
	 * limits to sanitize, then this won't work.
	 */
	if (aux->alu_state &&
	    (aux->alu_state != alu_state ||
	     aux->alu_limit != alu_limit))
	if (update_alu_sanitation_state(aux, alu_state, alu_limit))
		return -EACCES;

	/* Corresponding fixup done in fixup_bpf_calls(). */
	aux->alu_state = alu_state;
	aux->alu_limit = alu_limit;

do_sim:
	/* Simulate and find potential out-of-bounds access under
	 * speculative execution from truncation as a result of
@@ -3418,6 +3441,8 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
	s64 smin_val, smax_val;
	u64 umin_val, umax_val;
	u64 insn_bitness = (BPF_CLASS(insn->code) == BPF_ALU64) ? 64 : 32;
	u32 dst = insn->dst_reg;
	int ret;

	if (insn_bitness == 32) {
		/* Relevant for 32-bit RSH: Information can propagate towards
@@ -3452,6 +3477,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,

	switch (opcode) {
	case BPF_ADD:
		ret = sanitize_val_alu(env, insn);
		if (ret < 0) {
			verbose(env, "R%d tried to add from different pointers or scalars\n", dst);
			return ret;
		}
		if (signed_add_overflows(dst_reg->smin_value, smin_val) ||
		    signed_add_overflows(dst_reg->smax_value, smax_val)) {
			dst_reg->smin_value = S64_MIN;
@@ -3471,6 +3501,11 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
		dst_reg->var_off = tnum_add(dst_reg->var_off, src_reg.var_off);
		break;
	case BPF_SUB:
		ret = sanitize_val_alu(env, insn);
		if (ret < 0) {
			verbose(env, "R%d tried to sub from different pointers or scalars\n", dst);
			return ret;
		}
		if (signed_sub_overflows(dst_reg->smin_value, smax_val) ||
		    signed_sub_overflows(dst_reg->smax_value, smin_val)) {
			/* Overflow possible, we know nothing */
+4 −4
Original line number Diff line number Diff line
@@ -1390,10 +1390,7 @@ do_udp_sendmsg:
	ipc6.opt = opt;

	fl6.flowi6_proto = sk->sk_protocol;
	if (!ipv6_addr_any(daddr))
	fl6.daddr = *daddr;
	else
		fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
	if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
		fl6.saddr = np->saddr;
	fl6.fl6_sport = inet->inet_sport;
@@ -1421,6 +1418,9 @@ do_udp_sendmsg:
		}
	}

	if (ipv6_addr_any(&fl6.daddr))
		fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */

	final_p = fl6_update_dst(&fl6, opt, &final);
	if (final_p)
		connected = false;
+7 −7
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ static int test_foo_bar(void)

	/* Create cgroup /foo, get fd, and join it */
	foo = create_and_get_cgroup(FOO);
	if (!foo)
	if (foo < 0)
		goto err;

	if (join_cgroup(FOO))
@@ -94,7 +94,7 @@ static int test_foo_bar(void)

	/* Create cgroup /foo/bar, get fd, and join it */
	bar = create_and_get_cgroup(BAR);
	if (!bar)
	if (bar < 0)
		goto err;

	if (join_cgroup(BAR))
@@ -298,19 +298,19 @@ static int test_multiprog(void)
		goto err;

	cg1 = create_and_get_cgroup("/cg1");
	if (!cg1)
	if (cg1 < 0)
		goto err;
	cg2 = create_and_get_cgroup("/cg1/cg2");
	if (!cg2)
	if (cg2 < 0)
		goto err;
	cg3 = create_and_get_cgroup("/cg1/cg2/cg3");
	if (!cg3)
	if (cg3 < 0)
		goto err;
	cg4 = create_and_get_cgroup("/cg1/cg2/cg3/cg4");
	if (!cg4)
	if (cg4 < 0)
		goto err;
	cg5 = create_and_get_cgroup("/cg1/cg2/cg3/cg4/cg5");
	if (!cg5)
	if (cg5 < 0)
		goto err;

	if (join_cgroup("/cg1/cg2/cg3/cg4/cg5"))
Loading