History

bpf: Hooks for sys_connect

== The problem == See description of the problem in the initial patch of this patch set. == The solution == The patch provides much more reliable in-kernel solution for the 2nd part of the problem: making outgoing connecttion from desired IP. It adds new attach types `BPF_CGROUP_INET4_CONNECT` and `BPF_CGROUP_INET6_CONNECT` for program type `BPF_PROG_TYPE_CGROUP_SOCK_ADDR` that can be used to override both source and destination of a connection at connect(2) time. Local end of connection can be bound to desired IP using newly introduced BPF-helper `bpf_bind()`. It allows to bind to only IP though, and doesn't support binding to port, i.e. leverages `IP_BIND_ADDRESS_NO_PORT` socket option. There are two reasons for this: * looking for a free port is expensive and can affect performance significantly; * there is no use-case for port. As for remote end (`struct sockaddr *` passed by user), both parts of it can be overridden, remote IP and remote port. It's useful if an application inside cgroup wants to connect to another application inside same cgroup or to itself, but knows nothing about IP assigned to the cgroup. Support is added for IPv4 and IPv6, for TCP and UDP. IPv4 and IPv6 have separate attach types for same reason as sys_bind hooks, i.e. to prevent reading from / writing to e.g. user_ip6 fields when user passes sockaddr_in since it'd be out-of-bound. == Implementation notes == The patch introduces new field in `struct proto`: `pre_connect` that is a pointer to a function with same signature as `connect` but is called before it. The reason is in some cases BPF hooks should be called way before control is passed to `sk->sk_prot->connect`. Specifically `inet_dgram_connect` autobinds socket before calling `sk->sk_prot->connect` and there is no way to call `bpf_bind()` from hooks from e.g. `ip4_datagram_connect` or `ip6_datagram_connect` since it'd cause double-bind. On the other hand `proto.pre_connect` provides a flexible way to add BPF hooks for connect only for necessary `proto` and call them at desired time before `connect`. Since `bpf_bind()` is allowed to bind only to IP and autobind in `inet_dgram_connect` binds only port there is no chance of double-bind. bpf_bind() sets `force_bind_address_no_port` to bind to only IP despite of value of `bind_address_no_port` socket field. bpf_bind() sets `with_lock` to `false` when calling to __inet_bind() and __inet6_bind() since all call-sites, where bpf_bind() is called, already hold socket lock.

Andrey Ignatov committed 8 years ago

Commit d74bad41 parent 3679d5813 files · +202 −1Browse files

Showing the changes to include/uapi/linux (1 of 13 files). Show all

Unified · Split

include/uapi/linux/bpf.h+11−1
@@ -150,6 +150,8 @@ enum bpf_attach_type { · 149 unmodified lines
150150 BPF_SK_MSG_VERDICT,
151151 BPF_CGROUP_INET4_BIND,
152152 BPF_CGROUP_INET6_BIND,
153+ BPF_CGROUP_INET4_CONNECT,
154+ BPF_CGROUP_INET6_CONNECT,
153155 __MAX_BPF_ATTACH_TYPE
154156 };
155157
@@ -744,6 +746,13 @@ union bpf_attr { · 588 unmodified lines
744746 * @flags: reserved for future use
745747 * Return: SK_PASS
746748 *
749+ * int bpf_bind(ctx, addr, addr_len)
750+ * Bind socket to address. Only binding to IP is supported, no port can be
751+ * set in addr.
752+ * @ctx: pointer to context of type bpf_sock_addr
753+ * @addr: pointer to struct sockaddr to bind socket to
754+ * @addr_len: length of sockaddr structure
755+ * Return: 0 on success or negative error code
747756 */
748757 #define __BPF_FUNC_MAPPER(FN) \
749758 FN(unspec), \
@@ -809,7 +818,8 @@ union bpf_attr { · 59 unmodified lines
809818 FN(msg_redirect_map), \
810819 FN(msg_apply_bytes), \
811820 FN(msg_cork_bytes), \
812− FN(msg_pull_data),
821+ FN(msg_pull_data), \
822+ FN(bind),
813823
814824 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
815825 * function eBPF program intends to call

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t