aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2015-06-12 22:39:12 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-15 18:53:50 -0400
commitffeedafbf0236f03aeb2e8db273b3e5ae5f5bc89 (patch)
treee00f1b0bba1c217afbcf4dda00ef950afdfcafbc
parentada6c1de9ecabcfc5619479bcd29a208f2e248a0 (diff)
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. Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/bpf.h3
-rw-r--r--include/uapi/linux/bpf.h19
-rw-r--r--kernel/bpf/core.c3
-rw-r--r--kernel/bpf/helpers.c58
-rw-r--r--kernel/trace/bpf_trace.c6
-rw-r--r--net/core/filter.c6
-rw-r--r--samples/bpf/bpf_helpers.h6
-rw-r--r--samples/bpf/tracex2_kern.c24
-rw-r--r--samples/bpf/tracex2_user.c67
9 files changed, 178 insertions, 14 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 2235aee8096a..1b9a3f5b27f6 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -188,5 +188,8 @@ extern const struct bpf_func_proto bpf_get_prandom_u32_proto;
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 */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 602f05b7a275..29ef6f99e43d 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -230,6 +230,25 @@ enum bpf_func_id {
230 * Return: 0 on success 230 * 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
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 1e00aa3316dc..1fc45cc83076 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -730,6 +730,9 @@ const struct bpf_func_proto bpf_map_delete_elem_proto __weak;
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 = {
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 7ad5d8842d5b..1447ec09421e 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -14,6 +14,8 @@
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 return 21 * 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 = {
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};
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 50c4015a8ad3..3a17638cdf46 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -162,6 +162,12 @@ static const struct bpf_func_proto *kprobe_prog_func_proto(enum bpf_func_id func
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 /*
diff --git a/net/core/filter.c b/net/core/filter.c
index d271c06bf01f..20aa51ccbf9d 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1459,6 +1459,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id)
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 }
diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h
index f531a0b3282d..bdf1c1607b80 100644
--- a/samples/bpf/bpf_helpers.h
+++ b/samples/bpf/bpf_helpers.h
@@ -25,6 +25,12 @@ static void (*bpf_tail_call)(void *ctx, void *map, int index) =
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 to 35/* llvm builtin functions that eBPF C program may use to
30 * emit BPF_LD_ABS and BPF_LD_IND instructions 36 * emit BPF_LD_ABS and BPF_LD_IND instructions
diff --git a/samples/bpf/tracex2_kern.c b/samples/bpf/tracex2_kern.c
index 19ec1cfc45db..dc50f4f2943f 100644
--- a/samples/bpf/tracex2_kern.c
+++ b/samples/bpf/tracex2_kern.c
@@ -62,11 +62,18 @@ static unsigned int log2l(unsigned long v)
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)
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";
diff --git a/samples/bpf/tracex2_user.c b/samples/bpf/tracex2_user.c
index 91b8d0896fbb..cd0241c1447a 100644
--- a/samples/bpf/tracex2_user.c
+++ b/samples/bpf/tracex2_user.c
@@ -3,6 +3,7 @@
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)
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)
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]);