aboutsummaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAlexei Starovoitov <[email protected]>2019-03-13 12:04:35 -0700
committerAlexei Starovoitov <[email protected]>2019-03-13 12:04:36 -0700
commitf48a920504e516bded420255946f8e1cb8a0944a (patch)
tree31578584bffd05a9c77b22211ec37e648f113a40 /include/linux
parent6bf21b54a596d60905cfc7e8af8e2fe16d9fe7e9 (diff)
parent7681e7b2fbe2a78806423810c0d84dd230b96f94 (diff)
Merge branch 'fix-fullsock-access-after-bpf_sk_release'
Martin KaFai Lau says: ==================== This set addresses issue about accessing invalid ptr returned from bpf_tcp_sock() and bpf_sk_fullsock() after bpf_sk_release(). v4: - Tried the one "id" approach. It does not work well and the reason is in the Patch 1 commit message. - Rename refcount_id to ref_obj_id. - With ref_obj_id, resetting reg->id to 0 is fine in mark_ptr_or_null_reg() because ref_obj_id is passed to release_reference() instead of reg->id. - Also reset reg->ref_obj_id in mark_ptr_or_null_reg() when is_null == true - sk_to_full_sk() is removed from bpf_sk_fullsock() and bpf_tcp_sock(). - bpf_get_listener_sock() is added to do sk_to_full_sk() in Patch 2. - If tp is from bpf_tcp_sock(sk) and sk is a refcounted ptr, bpf_sk_release(tp) is also allowed. v3: - reset reg->refcount_id for the is_null case in mark_ptr_or_null_reg() v2: - Remove refcount_id arg from release_reference() because id == refcount_id - Add a WARN_ON_ONCE to mark_ptr_or_null_regs() to catch an internal verifier bug. ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/bpf.h1
-rw-r--r--include/linux/bpf_verifier.h40
2 files changed, 40 insertions, 1 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index a2132e09dc1c..f02367faa58d 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -193,7 +193,6 @@ enum bpf_arg_type {
ARG_PTR_TO_CTX, /* pointer to context */
ARG_ANYTHING, /* any (initialized) argument is ok */
- ARG_PTR_TO_SOCKET, /* pointer to bpf_sock */
ARG_PTR_TO_SPIN_LOCK, /* pointer to bpf_spin_lock */
ARG_PTR_TO_SOCK_COMMON, /* pointer to sock_common */
};
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 69f7a3449eda..7d8228d1c898 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -66,6 +66,46 @@ struct bpf_reg_state {
* same reference to the socket, to determine proper reference freeing.
*/
u32 id;
+ /* PTR_TO_SOCKET and PTR_TO_TCP_SOCK could be a ptr returned
+ * from a pointer-cast helper, bpf_sk_fullsock() and
+ * bpf_tcp_sock().
+ *
+ * Consider the following where "sk" is a reference counted
+ * pointer returned from "sk = bpf_sk_lookup_tcp();":
+ *
+ * 1: sk = bpf_sk_lookup_tcp();
+ * 2: if (!sk) { return 0; }
+ * 3: fullsock = bpf_sk_fullsock(sk);
+ * 4: if (!fullsock) { bpf_sk_release(sk); return 0; }
+ * 5: tp = bpf_tcp_sock(fullsock);
+ * 6: if (!tp) { bpf_sk_release(sk); return 0; }
+ * 7: bpf_sk_release(sk);
+ * 8: snd_cwnd = tp->snd_cwnd; // verifier will complain
+ *
+ * After bpf_sk_release(sk) at line 7, both "fullsock" ptr and
+ * "tp" ptr should be invalidated also. In order to do that,
+ * the reg holding "fullsock" and "sk" need to remember
+ * the original refcounted ptr id (i.e. sk_reg->id) in ref_obj_id
+ * such that the verifier can reset all regs which have
+ * ref_obj_id matching the sk_reg->id.
+ *
+ * sk_reg->ref_obj_id is set to sk_reg->id at line 1.
+ * sk_reg->id will stay as NULL-marking purpose only.
+ * After NULL-marking is done, sk_reg->id can be reset to 0.
+ *
+ * After "fullsock = bpf_sk_fullsock(sk);" at line 3,
+ * fullsock_reg->ref_obj_id is set to sk_reg->ref_obj_id.
+ *
+ * After "tp = bpf_tcp_sock(fullsock);" at line 5,
+ * tp_reg->ref_obj_id is set to fullsock_reg->ref_obj_id
+ * which is the same as sk_reg->ref_obj_id.
+ *
+ * From the verifier perspective, if sk, fullsock and tp
+ * are not NULL, they are the same ptr with different
+ * reg->type. In particular, bpf_sk_release(tp) is also
+ * allowed and has the same effect as bpf_sk_release(sk).
+ */
+ u32 ref_obj_id;
/* For scalar types (SCALAR_VALUE), this represents our knowledge of
* the actual value.
* For pointer types, this represents the variable part of the offset