Re: New bcc helpers


Yonghong Song
 

Hi, Carlos,

Thanks for the prototyping. See comments below.

On Sat, Sep 9, 2017 at 6:47 AM, carlos antonio neira bustos via
iovisor-dev <iovisor-dev@...> wrote:
Hi All,

I was working on this bcc issue https://github.com/iovisor/bcc/issues/1329
(PID filtering issues when running bpf script inside container). The current
issue is that bpf_get_current_pid_tgid() gets the pid outside the container.
I have created a couple of helpers that could help on this issue, I have add
them to bcc but currently I'm testing them.
I would like to know if my current approach is correct.

These are the helpers implemented in this patch.

int bpf_get_current_ns_id(void)
Return namespace id associated with current task
Return: ts->nsproxy->pid_ns_for_children->ns.inum
We already have helper to get current task structure. From there, bpf_probe_read
should get you to read namespace ID.


u64 bpf_get_current_pid_ns(void)
Return pid_namespace struct
Return: struct pid_namespace
Do you have a use case for this?


u64 bpf_get_current_pid(void)
Returns pid of current task as seen from pid namespace
Return: (u64) ts->tgid << 32 | task_pid_vnr(current);
This is useful, but need extension. But in typical use case, a helper
to get nsid, ns_tgid and ns_pid should be good
enough. Maybe something like:

struct bpf_current_ns_info {
u64 ns_id; /* namespace id */
u32 tgid; /* tgid inside namespace */
u32 gid; /* gid inside namespace */
}
int bpf_get_current_ns_info(void *buf, int size)

(1). In filter case, user can call this helper to get ns_nsid and
ns_tgid/ns_pid. user can already get its own
from getpid() and /proc/<pid>/ns/pid. They can compare the values
returned from the helper to the value
currently in the container (or even the host), for filtering purpose.
(2). For map key purpose, the helper returned values can be a key in
the map to differentiate between different
process instances.



cnb@Debian9:~/ebpf-backports/new-bcc-helpers/linux-4.13$ cat
new-helpers.patch
diff -uN /home/cnb/linux/linux-4.13/kernel/bpf/core.c
/home/cnb/ebpf-backports/new-bcc-helpers/linux-4.13/kernel/bpf/core.c
--- /home/cnb/linux/linux-4.13/kernel/bpf/core.c 2017-09-03
13:56:17.000000000 -0700
+++ /home/cnb/ebpf-backports/new-bcc-helpers/linux-4.13/kernel/bpf/core.c
2017-09-07 18:50:13.956874952 -0700
@@ -1379,6 +1379,10 @@
const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak;
const struct bpf_func_proto bpf_get_current_comm_proto __weak;
+const struct bpf_func_proto bpf_get_current_pid_ns_proto __weak;
+const struct bpf_func_proto bpf_get_current_ns_id_proto __weak;
+const struct bpf_func_proto bpf_get_current_pid_proto __weak;
+
const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void)
{
return NULL;
diff -uN /home/cnb/linux/linux-4.13/kernel/bpf/helpers.c
/home/cnb/ebpf-backports/new-bcc-helpers/linux-4.13/kernel/bpf/helpers.c
--- /home/cnb/linux/linux-4.13/kernel/bpf/helpers.c 2017-09-03
13:56:17.000000000 -0700
+++ /home/cnb/ebpf-backports/new-bcc-helpers/linux-4.13/kernel/bpf/helpers.c
2017-09-09 05:57:27.970448102 -0700
@@ -18,6 +18,7 @@
#include <linux/sched.h>
#include <linux/uidgid.h>
#include <linux/filter.h>
+#include <linux/pid_namespace.h>
/* If kernel subsystem is allowing eBPF programs to call this function,
* inside its own verifier_ops->get_func_proto() callback it should return
@@ -179,3 +180,64 @@
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_CONST_SIZE,
};
+
+BPF_CALL_0(bpf_get_current_pid_ns)
+{
+#ifdef CONFIG_PID_NS
+ struct pid_namespace *current_ns =
+ task_active_pid_ns(current);
+
+ if (unlikely(!current_ns))
+ return -EINVAL;
+
+ return (u64) current_ns;
+#else
+
+ return 0;
+#endif
+
+}
+
+const struct bpf_func_proto bpf_get_current_pid_ns_proto = {
+ .func = bpf_get_current_pid_ns,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
+BPF_CALL_0(bpf_get_current_ns_id)
+{
+ struct task_struct *ts = current;
+
+ if (unlikely(!ts))
+ return -EINVAL;
+
+ return (unsigned int)
+ ts->nsproxy->pid_ns_for_children->ns.inum;
+
+}
+
+const struct bpf_func_proto bpf_get_current_ns_id_proto = {
+ .func = bpf_get_current_ns_id,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
+BPF_CALL_0(bpf_get_current_pid)
+{
+ struct task_struct *ts = current;
+ pid_t pid;
+ if (unlikely(!ts))
+ return -EINVAL;
+
+ pid = task_pid_vnr(ts);
+
+ return (u64) ts->tgid << 32 | pid;
+}
+
+const struct bpf_func_proto bpf_get_current_pid_proto = {
+ .func = bpf_get_current_pid,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
+
--- /home/cnb/linux/linux-4.13/include/uapi/linux/bpf.h 2017-09-03
13:56:17.000000000 -0700
+++
/home/cnb/ebpf-backports/new-bcc-helpers/linux-4.13/include/uapi/linux/bpf.h
2017-09-09 06:22:46.763652066 -0700
@@ -539,6 +539,19 @@
* @mode: operation mode (enum bpf_adj_room_mode)
* @flags: reserved for future use
* Return: 0 on success or negative error code
+ *
+ * int bpf_get_current_ns_id(void)
+ * Return namespace id associated with current task
+ * Return: ts->nsproxy->pid_ns_for_children->ns.inum
+ *
+ * u64 bpf_get_current_pid_ns(void)
+ * Return pid_namespace struct
+ * Return: struct pid_namespace
+ *
+ * u64 bpf_get_current_pid(void)
+ * Returns pid of current task as seen from pid namespace
+ * return (u64) ts->tgid << 32 | task_pid_vnr(current);
+ *
*/
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
@@ -591,7 +604,11 @@
FN(get_socket_uid), \
FN(set_hash), \
FN(setsockopt), \
- FN(skb_adjust_room),
+ FN(skb_adjust_room), \
+ FN(get_current_pid_ns), \
+ FN(get_current_ns_id), \
+ FN(get_current_pid),
+
/* integer value in 'imm' field of BPF_CALL instruction selects which
helper
* function eBPF program intends to call




Bests

On Fri, Sep 8, 2017 at 2:39 PM, carlos antonio neira bustos
<cneirabustos@...> wrote:

Thank you very much.

On Sep 8, 2017 6:35 PM, "Y Song" <ys114321@...> wrote:



On Fri, Sep 8, 2017 at 12:21 PM, carlos antonio neira bustos via
iovisor-dev <iovisor-dev@...> wrote:

Hi,

I'm trying to add new helpers to obtain a pid namespace, I'm working on
kernel 4.13

--- linux/linux-4.13/kernel/bpf/helpers.c 2017-09-03 13:56:17.000000000
-0700
+++
/home/cnb/ebpf-backports/new-bcc-helpers/linux-4.13/kernel/bpf/helpers.c
2017-09-07 18:52:40.839525862 -0700
@@ -18,6 +18,7 @@
#include <linux/sched.h>
#include <linux/uidgid.h>
#include <linux/filter.h>
+#include <linux/pid_namespace.h>

/* If kernel subsystem is allowing eBPF programs to call this function,
* inside its own verifier_ops->get_func_proto() callback it should
return
@@ -179,3 +180,64 @@
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
.arg2_type = ARG_CONST_SIZE,
};
+
+BPF_CALL_0(bpf_get_current_pid_ns)
+{
+#ifdef CONFIG_PID_NS
+ struct pid_namespace *current_ns =
+ task_active_pid_ns(current);
+
+ if (unlikely(!current_ns))
+ return -EINVAL;
+
+ return (long) current_ns;
+#else
+
+ return 0;
+#endif
+
+}
+
+const struct bpf_func_proto bpf_get_current_pid_ns_proto = {
+ .func = bpf_get_current_pid_ns,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
+BPF_CALL_0(bpf_get_current_ns_id)
+{
+ struct task_struct *ts = current;
+
+ if (unlikely(!ts))
+ return -EINVAL;
+
+ return (unsigned int)
+ ts->nsproxy->pid_ns_for_children->ns.inum;
+
+}
+
+const struct bpf_func_proto bpf_get_current_ns_id_proto = {
+ .func = bpf_get_current_ns_id,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
+BPF_CALL_0(bpf_get_current_pid)
+{
+ struct task_struct *ts = current;
+
+ if (unlikely(!ts))
+ return -EINVAL;
+
+ pid_t pid = task_pid_vnr(ts);
+
+ return (u64) ts->tgid << 32 | pid;
+}
+
+const struct bpf_func_proto bpf_get_current_pid_proto = {
+ .func = bpf_get_current_pid,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
+
I wanted to integrate this on bcc tools, so I added these helpers on
bcc/src/cc/compat/linux/virtual_bpf.h
bcc/src/cc/compat/linux/bpf.h
bcc/src/cc/export/helpers.h
bcc/src/cc/export/helpers.h

then just to test one of them I modified bcc/tools/funccount.py

--- funccount.py 2017-09-08 12:14:57.601604654 -0700
+++ /home/cnb/bcc-new-helpers/bcc/tools/funccount.py 2017-09-07
20:27:32.982815146 -0700
@@ -185,7 +185,7 @@
# the top 32 bits of bpf_get_current_pid_tgid().
if self.pid:
trace_count_text = trace_count_text.replace('FILTER',
- """u32 pid = bpf_get_current_pid_tgid() >> 32;
+ """u32 pid = bpf_get_current_pid() >> 32;
if (pid != %d) { return 0; }""" % self.pid)
else:
trace_count_text = trace_count_text.replace('FILTER', '')


but I'm getting this error

cnb@Debian9:~/bcc/tools$ sudo /usr/share/bcc/tools/funccount -p 385
c:malloc
bpf: Invalid argument
0: (85) call unknown#51
invalid func unknown#51
Failed to load BPF program trace_count_0: Invalid argument


Is something that I'm missing on the bcc side or on bpf side ?

In kernel, you need to add your function proto to kprobe_prog_func_proto
in kernel/trace/bpf_trace.c



Bests


_______________________________________________
iovisor-dev mailing list
iovisor-dev@...
https://lists.iovisor.org/mailman/listinfo/iovisor-dev

_______________________________________________
iovisor-dev mailing list
iovisor-dev@...
https://lists.iovisor.org/mailman/listinfo/iovisor-dev

Join iovisor-dev@lists.iovisor.org to automatically receive all group messages.