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
188extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;188extern const struct bpf_func_proto bpf_get_smp_processor_id_proto;
189extern const struct bpf_func_proto bpf_tail_call_proto;189extern const struct bpf_func_proto bpf_tail_call_proto;
190extern const struct bpf_func_proto bpf_ktime_get_ns_proto;190extern const struct bpf_func_proto bpf_ktime_get_ns_proto;
191extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto;
192extern const struct bpf_func_proto bpf_get_current_uid_gid_proto;
193extern const struct bpf_func_proto bpf_get_current_comm_proto;
191 194
192#endif /* _LINUX_BPF_H */195#endif /* _LINUX_BPF_H */
include/uapi/linux/bpf.h+19−0
@@ -230,6 +230,25 @@ enum bpf_func_id { · 229 unmodified lines
230 * Return: 0 on success230 * Return: 0 on success
231 */231 */
232 BPF_FUNC_clone_redirect,232 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,
233 __BPF_FUNC_MAX_ID,252 __BPF_FUNC_MAX_ID,
234};253};
235 254
kernel/bpf/core.c+3−0
@@ -730,6 +730,9 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak; · 729 unmodified lines
730const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;730const struct bpf_func_proto bpf_get_prandom_u32_proto __weak;
731const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;731const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak;
732const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;732const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;
733const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak;
734const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak;
735const struct bpf_func_proto bpf_get_current_comm_proto __weak;
733 736
734/* Always built-in helper functions. */737/* Always built-in helper functions. */
735const struct bpf_func_proto bpf_tail_call_proto = {738const struct bpf_func_proto bpf_tail_call_proto = {
kernel/bpf/helpers.c+58−0
@@ -14,6 +14,8 @@ · 13 unmodified lines
14#include <linux/random.h>14#include <linux/random.h>
15#include <linux/smp.h>15#include <linux/smp.h>
16#include <linux/ktime.h>16#include <linux/ktime.h>
17#include <linux/sched.h>
18#include <linux/uidgid.h>
17 19
18/* If kernel subsystem is allowing eBPF programs to call this function,20/* If kernel subsystem is allowing eBPF programs to call this function,
19 * inside its own verifier_ops->get_func_proto() callback it should return21 * 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
124 .gpl_only = true,126 .gpl_only = true,
125 .ret_type = RET_INTEGER,127 .ret_type = RET_INTEGER,
126};128};
129
130static 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
140const 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
146static 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
160const 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
166static 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
178const 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
162 return &bpf_ktime_get_ns_proto;162 return &bpf_ktime_get_ns_proto;
163 case BPF_FUNC_tail_call:163 case BPF_FUNC_tail_call:
164 return &bpf_tail_call_proto;164 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;
165 171
166 case BPF_FUNC_trace_printk:172 case BPF_FUNC_trace_printk:
167 /*173 /*
net/core/filter.c+6−0
@@ -1459,6 +1459,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) · 1458 unmodified lines
1459 return &bpf_l4_csum_replace_proto;1459 return &bpf_l4_csum_replace_proto;
1460 case BPF_FUNC_clone_redirect:1460 case BPF_FUNC_clone_redirect:
1461 return &bpf_clone_redirect_proto;1461 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;
1462 default:1468 default:
1463 return sk_filter_func_proto(func_id);1469 return sk_filter_func_proto(func_id);
1464 }1470 }
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
25 (void *) BPF_FUNC_tail_call;25 (void *) BPF_FUNC_tail_call;
26static unsigned long long (*bpf_get_smp_processor_id)(void) =26static unsigned long long (*bpf_get_smp_processor_id)(void) =
27 (void *) BPF_FUNC_get_smp_processor_id;27 (void *) BPF_FUNC_get_smp_processor_id;
28static unsigned long long (*bpf_get_current_pid_tgid)(void) =
29 (void *) BPF_FUNC_get_current_pid_tgid;
30static unsigned long long (*bpf_get_current_uid_gid)(void) =
31 (void *) BPF_FUNC_get_current_uid_gid;
32static int (*bpf_get_current_comm)(void *buf, int buf_size) =
33 (void *) BPF_FUNC_get_current_comm;
28 34
29/* llvm builtin functions that eBPF C program may use to35/* llvm builtin functions that eBPF C program may use to
30 * emit BPF_LD_ABS and BPF_LD_IND instructions36 * 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
62 return log2(v);62 return log2(v);
63}63}
64 64
65struct hist_key {
66 char comm[16];
67 u64 pid_tgid;
68 u64 uid_gid;
69 u32 index;
70};
71
65struct bpf_map_def SEC("maps") my_hist_map = {72struct bpf_map_def SEC("maps") my_hist_map = {
66 .type = BPF_MAP_TYPE_ARRAY,73 .type = BPF_MAP_TYPE_HASH,
67 .key_size = sizeof(u32),74 .key_size = sizeof(struct hist_key),
68 .value_size = sizeof(long),75 .value_size = sizeof(long),
69 .max_entries = 64,76 .max_entries = 1024,
70};77};
71 78
72SEC("kprobe/sys_write")79SEC("kprobe/sys_write")
@@ -75,11 +82,18 @@ int bpf_prog3(struct pt_regs *ctx) · 2 unmodified lines
75 long write_size = ctx->dx; /* arg3 */82 long write_size = ctx->dx; /* arg3 */
76 long init_val = 1;83 long init_val = 1;
77 long *value;84 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));
79 91
80 value = bpf_map_lookup_elem(&my_hist_map, &index);92 value = bpf_map_lookup_elem(&my_hist_map, &key);
81 if (value)93 if (value)
82 __sync_fetch_and_add(value, 1);94 __sync_fetch_and_add(value, 1);
95 else
96 bpf_map_update_elem(&my_hist_map, &key, &init_val, BPF_ANY);
83 return 0;97 return 0;
84}98}
85char _license[] SEC("license") = "GPL";99char _license[] SEC("license") = "GPL";
samples/bpf/tracex2_user.c+58−9
@@ -3,6 +3,7 @@ · 2 unmodified lines
3#include <stdlib.h>3#include <stdlib.h>
4#include <signal.h>4#include <signal.h>
5#include <linux/bpf.h>5#include <linux/bpf.h>
6#include <string.h>
6#include "libbpf.h"7#include "libbpf.h"
7#include "bpf_load.h"8#include "bpf_load.h"
8 9
@@ -20,23 +21,42 @@ static void stars(char *str, long val, long max, int width) · 11 unmodified lines
20 str[i] = '\0';21 str[i] = '\0';
21}22}
22 23
23static void print_hist(int fd)24struct task {
25 char comm[16];
26 __u64 pid_tgid;
27 __u64 uid_gid;
28};
29
30struct hist_key {
31 struct task t;
32 __u32 index;
33};
34
35#define SIZE sizeof(struct task)
36
37static void print_hist_for_pid(int fd, void *task)
24{38{
25 int key;39 struct hist_key key = {}, next_key;
40 char starstr[MAX_STARS];
26 long value;41 long value;
27 long data[MAX_INDEX] = {};42 long data[MAX_INDEX] = {};
28 char starstr[MAX_STARS];
29 int i;
30 int max_ind = -1;43 int max_ind = -1;
31 long max_value = 0;44 long max_value = 0;
45 int i, ind;
32 46
33 for (key = 0; key < MAX_INDEX; key++) {47 while (bpf_get_next_key(fd, &key, &next_key) == 0) {
34 bpf_lookup_elem(fd, &key, &value);48 if (memcmp(&next_key, task, SIZE)) {
35 data[key] = value;49 key = next_key;
36 if (value && key > max_ind)50 continue;
37 max_ind = key;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;
38 if (value > max_value)57 if (value > max_value)
39 max_value = value;58 max_value = value;
59 key = next_key;
40 }60 }
41 61
42 printf(" syscall write() stats\n");62 printf(" syscall write() stats\n");
@@ -48,6 +68,35 @@ static void print_hist(int fd) · 5 unmodified lines
48 MAX_STARS, starstr);68 MAX_STARS, starstr);
49 }69 }
50}70}
71
72static 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
51static void int_exit(int sig)100static void int_exit(int sig)
52{101{
53 print_hist(map_fd[1]);102 print_hist(map_fd[1]);