History

bpf: introduce current->pid, tgid, uid, gid, comm accessors

eBPF programs attached to kprobes need to filter based on current->pid, uid and other fields, so introduce helper functions: u64 bpf_get_current_pid_tgid(void) Return: current->tgid << 32 | current->pid u64 bpf_get_current_uid_gid(void) Return: current_gid << 32 | current_uid bpf_get_current_comm(char *buf, int size_of_buf) stores current->comm into buf They can be used from the programs attached to TC as well to classify packets based on current task fields. Update tracex2 example to print histogram of write syscalls for each process instead of aggregated for all.

Alexei Starovoitov committed 11 years ago

Commit ffeedaf1 parent ada6c1d9 files · +178 −14Browse files

Unified · Split

9 files
  1. include/linux/bpf.h +3 −0
  2. include/uapi/linux/bpf.h +19 −0
  3. kernel/bpf/core.c +3 −0
  4. kernel/bpf/helpers.c +58 −0
  5. kernel/trace/bpf_trace.c +6 −0
  6. net/core/filter.c +6 −0
  7. samples/bpf/bpf_helpers.h +6 −0
  8. samples/bpf/tracex2_kern.c +19 −5
  9. samples/bpf/tracex2_user.c +58 −9
include/linux/bpf.h+3−0
@@ -188,5 +188,8 @@ extern const struct bpf_func_proto bpf_get_prandom_u32_proto; · 187 unmodified lines
188188 extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;
189189 extern const struct bpf_func_proto bpf_tail_call_proto;
190190 extern const struct bpf_func_proto bpf_ktime_get_ns_proto;
191+extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto;
192+extern const struct bpf_func_proto bpf_get_current_uid_gid_proto;
193+extern const struct bpf_func_proto bpf_get_current_comm_proto;
191194
192195 #endif /* _LINUX_BPF_H */
include/uapi/linux/bpf.h+19−0
@@ -230,6 +230,25 @@ enum bpf_func_id { · 229 unmodified lines
230230 * Return: 0 on success
231231 */
232232 BPF_FUNC_clone_redirect,
233+
234+ /**
235+ * u64 bpf_get_current_pid_tgid(void)
236+ * Return: current->tgid << 32 | current->pid
237+ */
238+ BPF_FUNC_get_current_pid_tgid,
239+
240+ /**
241+ * u64 bpf_get_current_uid_gid(void)
242+ * Return: current_gid << 32 | current_uid
243+ */
244+ BPF_FUNC_get_current_uid_gid,
245+
246+ /**
247+ * bpf_get_current_comm(char *buf, int size_of_buf)
248+ * stores current->comm into buf
249+ * Return: 0 on success
250+ */
251+ BPF_FUNC_get_current_comm,
233252 __BPF_FUNC_MAX_ID,
234253 };
235254
kernel/bpf/core.c+3−0
@@ -730,6 +730,9 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak; · 729 unmodified lines
730730 const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
731731 const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
732732 const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;
733+const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak;
734+const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak;
735+const struct bpf_func_proto bpf_get_current_comm_proto __weak;
733736
734737 /* Always built-in helper functions. */
735738 const struct bpf_func_proto bpf_tail_call_proto = {
kernel/bpf/helpers.c+58−0
@@ -14,6 +14,8 @@ · 13 unmodified lines
1414 #include <linux/random.h>
1515 #include <linux/smp.h>
1616 #include <linux/ktime.h>
17+#include <linux/sched.h>
18+#include <linux/uidgid.h>
1719
1820 /* If kernel subsystem is allowing eBPF programs to call this function,
1921 * inside its own verifier_ops->get_func_proto() callback it should return
@@ -124,3 +126,59 @@ const struct bpf_func_proto bpf_ktime_get_ns_proto = { · 104 unmodified lines
124126 .gpl_only = true,
125127 .ret_type = RET_INTEGER,
126128 };
129+
130+static u64 bpf_get_current_pid_tgid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
131+{
132+ struct task_struct *task = current;
133+
134+ if (!task)
135+ return -EINVAL;
136+
137+ return (u64) task->tgid << 32 | task->pid;
138+}
139+
140+const struct bpf_func_proto bpf_get_current_pid_tgid_proto = {
141+ .func = bpf_get_current_pid_tgid,
142+ .gpl_only = false,
143+ .ret_type = RET_INTEGER,
144+};
145+
146+static u64 bpf_get_current_uid_gid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
147+{
148+ struct task_struct *task = current;
149+ kuid_t uid;
150+ kgid_t gid;
151+
152+ if (!task)
153+ return -EINVAL;
154+
155+ current_uid_gid(&uid, &gid);
156+ return (u64) from_kgid(&init_user_ns, gid) << 32 |
157+ from_kuid(&init_user_ns, uid);
158+}
159+
160+const struct bpf_func_proto bpf_get_current_uid_gid_proto = {
161+ .func = bpf_get_current_uid_gid,
162+ .gpl_only = false,
163+ .ret_type = RET_INTEGER,
164+};
165+
166+static u64 bpf_get_current_comm(u64 r1, u64 size, u64 r3, u64 r4, u64 r5)
167+{
168+ struct task_struct *task = current;
169+ char *buf = (char *) (long) r1;
170+
171+ if (!task)
172+ return -EINVAL;
173+
174+ memcpy(buf, task->comm, min_t(size_t, size, sizeof(task->comm)));
175+ return 0;
176+}
177+
178+const struct bpf_func_proto bpf_get_current_comm_proto = {
179+ .func = bpf_get_current_comm,
180+ .gpl_only = false,
181+ .ret_type = RET_INTEGER,
182+ .arg1_type = ARG_PTR_TO_STACK,
183+ .arg2_type = ARG_CONST_STACK_SIZE,
184+};
kernel/trace/bpf_trace.c+6−0
@@ -162,6 +162,12 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func · 161 unmodified lines
162162 return &bpf_ktime_get_ns_proto;
163163 case BPF_FUNC_tail_call:
164164 return &bpf_tail_call_proto;
165+ case BPF_FUNC_get_current_pid_tgid:
166+ return &bpf_get_current_pid_tgid_proto;
167+ case BPF_FUNC_get_current_uid_gid:
168+ return &bpf_get_current_uid_gid_proto;
169+ case BPF_FUNC_get_current_comm:
170+ return &bpf_get_current_comm_proto;
165171
166172 case BPF_FUNC_trace_printk:
167173 /*
net/core/filter.c+6−0
@@ -1459,6 +1459,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) · 1458 unmodified lines
14591459 return &bpf_l4_csum_replace_proto;
14601460 case BPF_FUNC_clone_redirect:
14611461 return &bpf_clone_redirect_proto;
1462+ case BPF_FUNC_get_current_pid_tgid:
1463+ return &bpf_get_current_pid_tgid_proto;
1464+ case BPF_FUNC_get_current_uid_gid:
1465+ return &bpf_get_current_uid_gid_proto;
1466+ case BPF_FUNC_get_current_comm:
1467+ return &bpf_get_current_comm_proto;
14621468 default:
14631469 return sk_filter_func_proto(func_id);
14641470 }
samples/bpf/bpf_helpers.h+6−0
@@ -25,6 +25,12 @@ static void (*bpf_tail_call)(void *ctx, void *map, int index) = · 24 unmodified lines
2525 (void *) BPF_FUNC_tail_call;
2626 static unsigned long long (*bpf_get_smp_processor_id)(void) =
2727 (void *) BPF_FUNC_get_smp_processor_id;
28+static unsigned long long (*bpf_get_current_pid_tgid)(void) =
29+ (void *) BPF_FUNC_get_current_pid_tgid;
30+static unsigned long long (*bpf_get_current_uid_gid)(void) =
31+ (void *) BPF_FUNC_get_current_uid_gid;
32+static int (*bpf_get_current_comm)(void *buf, int buf_size) =
33+ (void *) BPF_FUNC_get_current_comm;
2834
2935 /* llvm builtin functions that eBPF C program may use to
3036 * emit BPF_LD_ABS and BPF_LD_IND instructions
samples/bpf/tracex2_kern.c+19−5
@@ -62,11 +62,18 @@ static unsigned int log2l(unsigned long v) · 61 unmodified lines
6262 return log2(v);
6363 }
6464
65+struct hist_key {
66+ char comm[16];
67+ u64 pid_tgid;
68+ u64 uid_gid;
69+ u32 index;
70+};
71+
6572 struct bpf_map_def SEC("maps") my_hist_map = {
66− .type = BPF_MAP_TYPE_ARRAY,
67− .key_size = sizeof(u32),
73+ .type = BPF_MAP_TYPE_HASH,
74+ .key_size = sizeof(struct hist_key),
6875 .value_size = sizeof(long),
69− .max_entries = 64,
76+ .max_entries = 1024,
7077 };
7178
7279 SEC("kprobe/sys_write")
@@ -75,11 +82,18 @@ int bpf_prog3(struct pt_regs *ctx) · 2 unmodified lines
7582 long write_size = ctx->dx; /* arg3 */
7683 long init_val = 1;
7784 long *value;
78− u32 index = log2l(write_size);
85+ struct hist_key key = {};
86+
87+ key.index = log2l(write_size);
88+ key.pid_tgid = bpf_get_current_pid_tgid();
89+ key.uid_gid = bpf_get_current_uid_gid();
90+ bpf_get_current_comm(&key.comm, sizeof(key.comm));
7991
80− value = bpf_map_lookup_elem(&my_hist_map, &index);
92+ value = bpf_map_lookup_elem(&my_hist_map, &key);
8193 if (value)
8294 __sync_fetch_and_add(value, 1);
95+ else
96+ bpf_map_update_elem(&my_hist_map, &key, &init_val, BPF_ANY);
8397 return 0;
8498 }
8599 char _license[] SEC("license") = "GPL";
samples/bpf/tracex2_user.c+58−9
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 #include <stdlib.h>
44 #include <signal.h>
55 #include <linux/bpf.h>
6+#include <string.h>
67 #include "libbpf.h"
78 #include "bpf_load.h"
89
@@ -20,23 +21,42 @@ static void stars(char *str, long val, long max, int width) · 11 unmodified lines
2021 str[i] = '\0';
2122 }
2223
23−static void print_hist(int fd)
24+struct task {
25+ char comm[16];
26+ __u64 pid_tgid;
27+ __u64 uid_gid;
28+};
29+
30+struct hist_key {
31+ struct task t;
32+ __u32 index;
33+};
34+
35+#define SIZE sizeof(struct task)
36+
37+static void print_hist_for_pid(int fd, void *task)
2438 {
25− int key;
39+ struct hist_key key = {}, next_key;
40+ char starstr[MAX_STARS];
2641 long value;
2742 long data[MAX_INDEX] = {};
28− char starstr[MAX_STARS];
29− int i;
3043 int max_ind = -1;
3144 long max_value = 0;
45+ int i, ind;
3246
33− for (key = 0; key < MAX_INDEX; key++) {
34− bpf_lookup_elem(fd, &key, &value);
35− data[key] = value;
36− if (value && key > max_ind)
37− max_ind = key;
47+ while (bpf_get_next_key(fd, &key, &next_key) == 0) {
48+ if (memcmp(&next_key, task, SIZE)) {
49+ key = next_key;
50+ continue;
51+ }
52+ bpf_lookup_elem(fd, &next_key, &value);
53+ ind = next_key.index;
54+ data[ind] = value;
55+ if (value && ind > max_ind)
56+ max_ind = ind;
3857 if (value > max_value)
3958 max_value = value;
59+ key = next_key;
4060 }
4161
4262 printf(" syscall write() stats\n");
@@ -48,6 +68,35 @@ static void print_hist(int fd) · 5 unmodified lines
4868 MAX_STARS, starstr);
4969 }
5070 }
71+
72+static void print_hist(int fd)
73+{
74+ struct hist_key key = {}, next_key;
75+ static struct task tasks[1024];
76+ int task_cnt = 0;
77+ int i;
78+
79+ while (bpf_get_next_key(fd, &key, &next_key) == 0) {
80+ int found = 0;
81+
82+ for (i = 0; i < task_cnt; i++)
83+ if (memcmp(&tasks[i], &next_key, SIZE) == 0)
84+ found = 1;
85+ if (!found)
86+ memcpy(&tasks[task_cnt++], &next_key, SIZE);
87+ key = next_key;
88+ }
89+
90+ for (i = 0; i < task_cnt; i++) {
91+ printf("\npid %d cmd %s uid %d\n",
92+ (__u32) tasks[i].pid_tgid,
93+ tasks[i].comm,
94+ (__u32) tasks[i].uid_gid);
95+ print_hist_for_pid(fd, &tasks[i]);
96+ }
97+
98+}
99+
51100 static void int_exit(int sig)
52101 {
53102 print_hist(map_fd[1]);