net: core: Two Helper function about socket information
Subsystems (5)
v7 cover net: core: Two Helper function about socket information
From: Chenbo Feng <[email protected]>
Introduce two eBpf helper function to get the socket cookie and socket uid for each packet. The helper function is useful when the *sk field inside sk_buff is not empty. These helper functions can be used on socket and uid based traffic monitoring programs.
Change since V6:
* change the user namespace of uid helper function back to init_user_ns since in some situation, for example, pinned bpf object, the current user namespace is not always applicable.
Change since V5:
* Delete unnecessary blank lines in sample program.
* Refine the variable orders in get_uid helper function.
Change since V4:
* Using current user namespace to get uid instead of using init_ns.
* Add compiling setup of example program in to Makefile.
* Change the name style of the example program binaries.
Change since V3:
* Fixed some typos and incorrect comments in sample program
* replaced raw insns with BPF_STX_XADD and add it to libbpf.h
* Use a temp dir as mount point instead and added a check for the user input string.
* Make the get uid helper function returns the user namespace uid instead of kuid.
* Return a overflowuid instead of 0 when no uid information is found.
Change since V2:
* Add a sample program to demostrate the usage of the helper function.
* Moved the helper function proto invoking place.
* Add function header into tools/include
* Apply sk_to_full_sk() before getting uid.
Change since V1:
* Removed the unnecessary declarations and export command
* resolved conflict with master branch.
* Examine if the socket is a full socket before getting the uid.
Chenbo Feng (3):
Add a helper function to get socket cookie in eBPF Add a eBPF helper function to retrieve socket uid
A Sample of using socket cookie and uid for traffic monitoring
include/linux/sock_diag.h | 1 + include/uapi/linux/bpf.h | 16 +- net/core/filter.c | 39 +++++ net/core/sock_diag.c | 2 +- samples/bpf/Makefile | 3 + samples/bpf/cookie_uid_helper_example.c | 217 +++++++++++++++++++++++++++ samples/bpf/libbpf.h | 10 ++ samples/bpf/run_cookie_uid_helper_example.sh | 14 ++ tools/include/uapi/linux/bpf.h | 4 +- 9 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 samples/bpf/cookie_uid_helper_example.c create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh
Signature · 1 line
2.7.4
PATCH v7 1/3 Add a helper function to get socket cookie in eBPF
From: Chenbo Feng <[email protected]>
Retrieve the socket cookie generated by sock_gen_cookie() from a sk_buff with a known socket. Generates a new cookie if one was not yet set.If the socket pointer inside sk_buff is NULL, 0 is returned. The helper function coud be useful in monitoring per socket networking traffic statistics and provide a unique socket identifier per namespace.
--- include/linux/sock_diag.h | 1 + include/uapi/linux/bpf.h | 9 ++++++++- net/core/filter.c | 17 +++++++++++++++++ net/core/sock_diag.c | 2 +- tools/include/uapi/linux/bpf.h | 3 ++- 5 files changed, 29 insertions(+), 3 deletions(-)
include/linux/sock_diag.h +1 -0
@@ -24,6 +24,7 @@ void sock_diag_unregister(const struct sock_diag_handler *h);void sock_diag_register_inet_compat (int (*fn)(struct sk_buff *skb,struct nlmsghdr *nlh));void sock_diag_unregister_inet_compat (int (*fn)(struct sk_buff *skb,struct nlmsghdr *nlh)); +u64 sock_gen_cookie (struct sock *sk);int sock_diag_check_cookie (struct sock *sk,const __u32 *cookie);void sock_diag_save_cookie (struct sock *sk,__u32 *cookie);
include/uapi/linux/bpf.h +8 -1
@@ -456,6 +456,12 @@ union bpf_attr {* Return: * > 0 length of the string including the trailing NUL on success * < 0 error +* +* u64 bpf_bpf_get_socket_cookie(skb) +* Get the cookie for the socket stored inside sk_buff. +* @skb: pointer to skb +* Return: 8 Bytes non-decreasing number on success or 0 if the socket +* field is missing inside sk_buff */ #define __BPF_FUNC_MAPPER (FN ) \ FN(unspec), \
@@ -503,7 +509,8 @@ union bpf_attr {FN (get_numa_node_id), \FN (skb_change_head), \FN (xdp_adjust_head), \ -FN (probe_read_str), +FN (probe_read_str), \ +FN (get_socket_cookie),/* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call
net/core/filter.c +17 -0
@@ -26,6 +26,7 @@#include <linux/mm.h> #include <linux/fcntl.h> #include <linux/socket.h> +#include <linux/sock_diag.h> #include <linux/in.h> #include <linux/inet.h> #include <linux/netdevice.h>
@@ -2599,6 +2600,18 @@ static const struct bpf_func_proto bpf_xdp_event_output_proto = { .arg5_type = ARG_CONST_SIZE, }; +BPF_CALL_1(bpf_get_socket_cookie, struct sk_buff *, skb) +{ +return skb->sk ?sock_gen_cookie (skb->sk) :0 ; +} + +static const struct bpf_func_proto bpf_get_socket_cookie_proto = { + .func = bpf_get_socket_cookie, + .gpl_only = false, + .ret_type =RET_INTEGER , + .arg1_type =ARG_PTR_TO_CTX , +}; +static const struct bpf_func_proto *bpf_base_func_proto (enum bpf_func_id func_id) {
@@ -2633,6 +2646,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)switch (func_id) {case BPF_FUNC_skb_load_bytes:return &bpf_skb_load_bytes_proto; +case BPF_FUNC_get_socket_cookie: +return &bpf_get_socket_cookie_proto;default :return bpf_base_func_proto (func_id); }
@@ -2692,6 +2707,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)return &bpf_get_smp_processor_id_proto;case BPF_FUNC_skb_under_cgroup:return &bpf_skb_under_cgroup_proto; +case BPF_FUNC_get_socket_cookie: +return &bpf_get_socket_cookie_proto;default :return bpf_base_func_proto (func_id); }
net/core/sock_diag.c +1 -1
@@ -19,7 +19,7 @@ static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);static DEFINE_MUTEX (sock_diag_table_mutex);static struct workqueue_struct *broadcast_wq; -static u64 sock_gen_cookie (struct sock *sk) +u64 sock_gen_cookie (struct sock *sk) {while (1 ) {u64 res =atomic64_read (&sk->sk_cookie);
tools/include/uapi/linux/bpf.h +2 -1
@@ -503,7 +503,8 @@ union bpf_attr {FN (get_numa_node_id), \FN (skb_change_head), \FN (xdp_adjust_head), \ -FN (probe_read_str), +FN (probe_read_str), \ +FN (get_socket_cookie),/* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call
Signature · 1 line
2.7.4
Re: [PATCH net-next v7 1/3] Add a helper function to get socket cookie in eBPF
Quoted 11 lines · Chenbo Feng
From: Chenbo Feng <[email protected]>
Retrieve the socket cookie generated by
sock_gen_cookie()from ask_buffwith a known socket. Generates a new cookie if one was not yet set.If the socket pointer insidesk_buffis NULL, 0 is returned. The helper function coud be useful in monitoring per socket networking traffic statistics and provide a unique socket identifier per namespace.Acked-by Daniel Borkmann <[email protected]>Signed-off-by Chenbo Feng <[email protected]>
PATCH v7 2/3 Add a eBPF helper function to retrieve socket uid
In reply to Chenbo FengFrom: Chenbo Feng <[email protected]>
Returns the owner uid of the socket inside a sk_buff. This is useful to perform per-UID accounting of network traffic or per-UID packet filtering. The socket need to be a fullsock otherwise overflowuid is returned.
--- include/uapi/linux/bpf.h | 9 ++++++++- net/core/filter.c | 22 ++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 3 ++- 3 files changed, 32 insertions(+), 2 deletions(-)
include/uapi/linux/bpf.h +8 -1
@@ -462,6 +462,12 @@ union bpf_attr {* @skb: pointer to skb * Return: 8 Bytes non-decreasing number on success or 0 if the socket * field is missing inside sk_buff +* +* u32 bpf_get_socket_uid(skb) +* Get the owner uid of the socket stored inside sk_buff. +* @skb: pointer to skb +* Return: uid of the socket owner on success or 0 if the socket pointer +* inside sk_buff is NULL */ #define __BPF_FUNC_MAPPER (FN ) \ FN(unspec), \
@@ -510,7 +516,8 @@ union bpf_attr {FN (skb_change_head), \FN (xdp_adjust_head), \FN (probe_read_str), \ -FN (get_socket_cookie), +FN (get_socket_cookie), \ +FN (get_socket_uid),/* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call
net/core/filter.c +22 -0
@@ -2612,6 +2612,24 @@ static const struct bpf_func_proto bpf_get_socket_cookie_proto = { .arg1_type = ARG_PTR_TO_CTX, }; +BPF_CALL_1(bpf_get_socket_uid, struct sk_buff *, skb) +{ +struct sock *sk =sk_to_full_sk (skb->sk); +kuid_t kuid; + +if (!sk || !sk_fullsock (sk)) +return overflowuid; + kuid =sock_net_uid (sock_net (sk), sk); +return from_kuid_munged (&init_user_ns, kuid); +} + +static const struct bpf_func_proto bpf_get_socket_uid_proto = { + .func = bpf_get_socket_uid, + .gpl_only = false, + .ret_type =RET_INTEGER , + .arg1_type =ARG_PTR_TO_CTX , +}; +static const struct bpf_func_proto *bpf_base_func_proto (enum bpf_func_id func_id) {
@@ -2648,6 +2666,8 @@ sk_filter_func_proto(enum bpf_func_id func_id)return &bpf_skb_load_bytes_proto;case BPF_FUNC_get_socket_cookie:return &bpf_get_socket_cookie_proto; +case BPF_FUNC_get_socket_uid: +return &bpf_get_socket_uid_proto;default :return bpf_base_func_proto (func_id); }
@@ -2709,6 +2729,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)return &bpf_skb_under_cgroup_proto;case BPF_FUNC_get_socket_cookie:return &bpf_get_socket_cookie_proto; +case BPF_FUNC_get_socket_uid: +return &bpf_get_socket_uid_proto;default :return bpf_base_func_proto (func_id); }
tools/include/uapi/linux/bpf.h +2 -1
@@ -504,7 +504,8 @@ union bpf_attr {FN (skb_change_head), \FN (xdp_adjust_head), \FN (probe_read_str), \ -FN (get_socket_cookie), +FN (get_socket_cookie), \ +FN (get_socket_uid),/* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call
Signature · 1 line
2.7.4
Re: [PATCH net-next v7 2/3] Add a eBPF helper function to retrieve socket uid
net/core/filter.c static const struct bpf_func_proto bpf_get_socket_cookie_proto = { · line 2623
Quoted 9 lines
net/core/filter.c +9
-0+BPF_CALL_1(bpf_get_socket_uid, struct sk_buff *, skb) +{ +struct sock *sk =sk_to_full_sk (skb->sk); +kuid_t kuid; + +if (!sk || !sk_fullsock (sk)) +return overflowuid; + kuid =sock_net_uid (sock_net (sk), sk); +return from_kuid_munged (&init_user_ns, kuid);
Ideally, this would be the user namespace relative to the BPF program.
With no such association stored, using init_user_ns is fine. But if we define it as such now, we cannot change it to resolve userns later.
We could associate a BPF program with the userns of the process that loads the program. And expose bpf_prog state to external functions, for instance through a perpcu local variable.
Also, unconditionally using init_user_ns will allow a process sandboxed in a user namespace to learn its uid in the initns. If the initns is not its parentns, this may be a new capability.
Re: [PATCH net-next v7 2/3] Add a eBPF helper function to retrieve socket uid
Quoted 6 lines · Willem de Bruijn
net/core/filter.c static const struct bpf_func_proto bpf_get_socket_cookie_proto = { · line 2623
Quoted 4 lines
net/core/filter.c +4
-0+if (!sk || !sk_fullsock (sk)) +return overflowuid; + kuid =sock_net_uid (sock_net (sk), sk); +return from_kuid_munged (&init_user_ns, kuid);Ideally, this would be the user namespace relative to the BPF program.
What about sock_net(sk)->user_ns? We've already matched a socket, and it's guaranteed to be a full socket and non-NULL (otherwise we've already returned overflowuid), so it seems like the most correct namespace to use is the one of the socket we've matched. Given that sk is non-NULL, sock_net_uid just returns sk->sk_uid, so I think you can just write this as:
if (!sk || !sk_fullsock(sk))
return overflowuid;
return from_kuid_munged(sock_net(sk)->user_ns, sk->uid);
Re: [PATCH net-next v7 2/3] Add a eBPF helper function to retrieve socket uid
Quoted 16 lines · Lorenzo Colitti
Quoted 6 lines · Willem de Bruijn
net/core/filter.c static const struct bpf_func_proto bpf_get_socket_cookie_proto = { · line 2623
Quoted 4 lines
net/core/filter.c +4
-0+if (!sk || !sk_fullsock (sk)) +return overflowuid; + kuid =sock_net_uid (sock_net (sk), sk); +return from_kuid_munged (&init_user_ns, kuid);Ideally, this would be the user namespace relative to the BPF program.
What about sock_net(sk)->user_ns? We've already matched a socket, and it's guaranteed to be a full socket and non-NULL (otherwise we've already returned overflowuid), so it seems like the most correct namespace to use is the one of the socket we've matched. Given that sk is non-NULL,
sock_net_uidjust returnssk->sk_uid, so I think you can just write this as:
Quoted 4 lines
if (!sk || !sk_fullsock(sk))
return overflowuid;return
from_kuid_munged(sock_net(sk)->user_ns, sk->uid);
makes sense to me.
PATCH v7 3/3 A Sample of using socket cookie and uid for traffic monitoring
In reply to Chenbo FengFrom: Chenbo Feng <[email protected]>
Add a sample program to demostrate the possible usage of get_socket_cookie and get_socket_uid helper function. The program will store bytes and packets counting of in/out traffic monitored by iptables and store the stats in a bpf map in per socket base. The owner uid of the socket will be stored as part of the data entry. A shell script for running the program is also included.
--- samples/bpf/Makefile | 3 + samples/bpf/cookie_uid_helper_example.c | 217 +++++++++++++++++++++++++++ samples/bpf/libbpf.h | 10 ++ samples/bpf/run_cookie_uid_helper_example.sh | 14 ++ 4 files changed, 244 insertions(+) create mode 100644 samples/bpf/cookie_uid_helper_example.c create mode 100755 samples/bpf/run_cookie_uid_helper_example.sh
samples/bpf/Makefile +3 -0
@@ -34,6 +34,7 @@ hostprogs-y += sampleip hostprogs-y += tc_l2_redirect hostprogs-y += lwt_len_hist hostprogs-y += xdp_tx_iptunnel +hostprogs-y += per_socket_stats_example # Libbpf dependencies LIBBPF := ../../tools/lib/bpf/bpf.o
@@ -72,6 +73,7 @@ sampleip-objs := bpf_load.o $(LIBBPF) sampleip_user.o tc_l2_redirect-objs := bpf_load.o $(LIBBPF) tc_l2_redirect_user.o lwt_len_hist-objs := bpf_load.o $(LIBBPF) lwt_len_hist_user.o xdp_tx_iptunnel-objs := bpf_load.o $(LIBBPF) xdp_tx_iptunnel_user.o +per_socket_stats_example-objs := $(LIBBPF) cookie_uid_helper_example.o # Tell kbuild to always build the programs always := $(hostprogs-y)
@@ -105,6 +107,7 @@ always += trace_event_kern.o always += sampleip_kern.o always += lwt_len_hist_kern.o always += xdp_tx_iptunnel_kern.o +always += cookie_uid_helper_example.o HOSTCFLAGS += -I$(objtree)/usr/include HOSTCFLAGS += -I$(srctree)/tools/lib/
samples/bpf/cookie_uid_helper_example.c new file +217 -0
217 lines not on this page · raw message
samples/bpf/libbpf.h +10 -0
@@ -135,6 +135,16 @@ struct bpf_insn; .off = OFF, \ .imm = 0 }) +/* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */ + +#define BPF_STX_XADD (SIZE ,DST ,SRC ,OFF ) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) +/* Memory store, *(uint *) (dst_reg + off16) = imm32 */ #define BPF_ST_MEM (SIZE ,DST ,OFF ,IMM ) \
samples/bpf/run_cookie_uid_helper_example.sh new file +14 -0
@@ -0,0 +1,14 @@ +#!/bin/bash +local_dir="$(pwd)" +root_dir=$local_dir/../.. +mnt_dir=$(mktemp -d --tmp) + +on_exit() { + iptables -D INPUT -m bpf --object-pinned ${mnt_dir}/bpf_prog -j ACCEPT + umount ${mnt_dir} + rm -r ${mnt_dir} +} + +trap on_exit EXIT +mount -t bpf bpf ${mnt_dir} +./per_socket_stats_example ${mnt_dir}/bpf_prog
Signature · 1 line
2.7.4
Re: [PATCH net-next v7 3/3] A Sample of using socket cookie and uid for traffic monitoring
Quoted 11 lines · Chenbo Feng
From: Chenbo Feng <[email protected]>
Add a sample program to demostrate the possible usage of
get_socket_cookieandget_socket_uidhelper function. The program will store bytes and packets counting of in/out traffic monitored by iptables and store the stats in a bpf map in per socket base. The owner uid of the socket will be stored as part of the data entry. A shell script for running the program is also included.Signed-off-by Chenbo Feng <[email protected]>