blob: 99af4cea110253126e6a1c7069aef8c82cf535e6 [file] [log] [blame]
Yonghong Songeaaacd22020-05-09 10:59:11 -07001// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (c) 2020 Facebook */
3
4#include <linux/init.h>
5#include <linux/namei.h>
6#include <linux/pid_namespace.h>
7#include <linux/fs.h>
8#include <linux/fdtable.h>
9#include <linux/filter.h>
Yonghong Song951cf362020-07-20 09:34:03 -070010#include <linux/btf_ids.h>
Yonghong Songeaaacd22020-05-09 10:59:11 -070011
12struct bpf_iter_seq_task_common {
13 struct pid_namespace *ns;
14};
15
16struct bpf_iter_seq_task_info {
17 /* The first field must be struct bpf_iter_seq_task_common.
18 * this is assumed by {init, fini}_seq_pidns() callback functions.
19 */
20 struct bpf_iter_seq_task_common common;
21 u32 tid;
22};
23
24static struct task_struct *task_seq_get_next(struct pid_namespace *ns,
25 u32 *tid)
26{
27 struct task_struct *task = NULL;
28 struct pid *pid;
29
30 rcu_read_lock();
Andrii Nakryikoc70f34a2020-05-13 22:51:37 -070031retry:
Yonghong Songe60572b2020-08-18 15:23:10 -070032 pid = find_ge_pid(*tid, ns);
Andrii Nakryikoc70f34a2020-05-13 22:51:37 -070033 if (pid) {
Yonghong Songe60572b2020-08-18 15:23:10 -070034 *tid = pid_nr_ns(pid, ns);
Yonghong Songeaaacd22020-05-09 10:59:11 -070035 task = get_pid_task(pid, PIDTYPE_PID);
Andrii Nakryikoc70f34a2020-05-13 22:51:37 -070036 if (!task) {
37 ++*tid;
38 goto retry;
39 }
40 }
Yonghong Songeaaacd22020-05-09 10:59:11 -070041 rcu_read_unlock();
42
43 return task;
44}
45
46static void *task_seq_start(struct seq_file *seq, loff_t *pos)
47{
48 struct bpf_iter_seq_task_info *info = seq->private;
49 struct task_struct *task;
50
51 task = task_seq_get_next(info->common.ns, &info->tid);
52 if (!task)
53 return NULL;
54
Yonghong Song3f9969f2020-07-22 12:51:56 -070055 if (*pos == 0)
56 ++*pos;
Yonghong Songeaaacd22020-05-09 10:59:11 -070057 return task;
58}
59
60static void *task_seq_next(struct seq_file *seq, void *v, loff_t *pos)
61{
62 struct bpf_iter_seq_task_info *info = seq->private;
63 struct task_struct *task;
64
65 ++*pos;
66 ++info->tid;
67 put_task_struct((struct task_struct *)v);
68 task = task_seq_get_next(info->common.ns, &info->tid);
69 if (!task)
70 return NULL;
71
72 return task;
73}
74
75struct bpf_iter__task {
76 __bpf_md_ptr(struct bpf_iter_meta *, meta);
77 __bpf_md_ptr(struct task_struct *, task);
78};
79
80DEFINE_BPF_ITER_FUNC(task, struct bpf_iter_meta *meta, struct task_struct *task)
81
82static int __task_seq_show(struct seq_file *seq, struct task_struct *task,
83 bool in_stop)
84{
85 struct bpf_iter_meta meta;
86 struct bpf_iter__task ctx;
87 struct bpf_prog *prog;
88
89 meta.seq = seq;
90 prog = bpf_iter_get_info(&meta, in_stop);
91 if (!prog)
92 return 0;
93
94 meta.seq = seq;
95 ctx.meta = &meta;
96 ctx.task = task;
97 return bpf_iter_run_prog(prog, &ctx);
98}
99
100static int task_seq_show(struct seq_file *seq, void *v)
101{
102 return __task_seq_show(seq, v, false);
103}
104
105static void task_seq_stop(struct seq_file *seq, void *v)
106{
107 if (!v)
108 (void)__task_seq_show(seq, v, true);
109 else
110 put_task_struct((struct task_struct *)v);
111}
112
113static const struct seq_operations task_seq_ops = {
114 .start = task_seq_start,
115 .next = task_seq_next,
116 .stop = task_seq_stop,
117 .show = task_seq_show,
118};
119
120struct bpf_iter_seq_task_file_info {
121 /* The first field must be struct bpf_iter_seq_task_common.
122 * this is assumed by {init, fini}_seq_pidns() callback functions.
123 */
124 struct bpf_iter_seq_task_common common;
125 struct task_struct *task;
126 struct files_struct *files;
127 u32 tid;
128 u32 fd;
129};
130
131static struct file *
132task_file_seq_get_next(struct bpf_iter_seq_task_file_info *info,
133 struct task_struct **task, struct files_struct **fstruct)
134{
135 struct pid_namespace *ns = info->common.ns;
136 u32 curr_tid = info->tid, max_fds;
137 struct files_struct *curr_files;
138 struct task_struct *curr_task;
139 int curr_fd = info->fd;
140
141 /* If this function returns a non-NULL file object,
142 * it held a reference to the task/files_struct/file.
143 * Otherwise, it does not hold any reference.
144 */
145again:
146 if (*task) {
147 curr_task = *task;
148 curr_files = *fstruct;
149 curr_fd = info->fd;
150 } else {
151 curr_task = task_seq_get_next(ns, &curr_tid);
152 if (!curr_task)
153 return NULL;
154
155 curr_files = get_files_struct(curr_task);
156 if (!curr_files) {
157 put_task_struct(curr_task);
158 curr_tid = ++(info->tid);
159 info->fd = 0;
160 goto again;
161 }
162
163 /* set *fstruct, *task and info->tid */
164 *fstruct = curr_files;
165 *task = curr_task;
166 if (curr_tid == info->tid) {
167 curr_fd = info->fd;
168 } else {
169 info->tid = curr_tid;
170 curr_fd = 0;
171 }
172 }
173
174 rcu_read_lock();
175 max_fds = files_fdtable(curr_files)->max_fds;
176 for (; curr_fd < max_fds; curr_fd++) {
177 struct file *f;
178
179 f = fcheck_files(curr_files, curr_fd);
180 if (!f)
181 continue;
Yonghong Songcf28f3b2020-08-17 10:42:14 -0700182 if (!get_file_rcu(f))
183 continue;
Yonghong Songeaaacd22020-05-09 10:59:11 -0700184
185 /* set info->fd */
186 info->fd = curr_fd;
Yonghong Songeaaacd22020-05-09 10:59:11 -0700187 rcu_read_unlock();
188 return f;
189 }
190
191 /* the current task is done, go to the next task */
192 rcu_read_unlock();
193 put_files_struct(curr_files);
194 put_task_struct(curr_task);
195 *task = NULL;
196 *fstruct = NULL;
197 info->fd = 0;
198 curr_tid = ++(info->tid);
199 goto again;
200}
201
202static void *task_file_seq_start(struct seq_file *seq, loff_t *pos)
203{
204 struct bpf_iter_seq_task_file_info *info = seq->private;
205 struct files_struct *files = NULL;
206 struct task_struct *task = NULL;
207 struct file *file;
208
209 file = task_file_seq_get_next(info, &task, &files);
210 if (!file) {
211 info->files = NULL;
212 info->task = NULL;
213 return NULL;
214 }
215
Yonghong Song3f9969f2020-07-22 12:51:56 -0700216 if (*pos == 0)
217 ++*pos;
Yonghong Songeaaacd22020-05-09 10:59:11 -0700218 info->task = task;
219 info->files = files;
220
221 return file;
222}
223
224static void *task_file_seq_next(struct seq_file *seq, void *v, loff_t *pos)
225{
226 struct bpf_iter_seq_task_file_info *info = seq->private;
227 struct files_struct *files = info->files;
228 struct task_struct *task = info->task;
229 struct file *file;
230
231 ++*pos;
232 ++info->fd;
233 fput((struct file *)v);
234 file = task_file_seq_get_next(info, &task, &files);
235 if (!file) {
236 info->files = NULL;
237 info->task = NULL;
238 return NULL;
239 }
240
241 info->task = task;
242 info->files = files;
243
244 return file;
245}
246
247struct bpf_iter__task_file {
248 __bpf_md_ptr(struct bpf_iter_meta *, meta);
249 __bpf_md_ptr(struct task_struct *, task);
250 u32 fd __aligned(8);
251 __bpf_md_ptr(struct file *, file);
252};
253
254DEFINE_BPF_ITER_FUNC(task_file, struct bpf_iter_meta *meta,
255 struct task_struct *task, u32 fd,
256 struct file *file)
257
258static int __task_file_seq_show(struct seq_file *seq, struct file *file,
259 bool in_stop)
260{
261 struct bpf_iter_seq_task_file_info *info = seq->private;
262 struct bpf_iter__task_file ctx;
263 struct bpf_iter_meta meta;
264 struct bpf_prog *prog;
265
266 meta.seq = seq;
267 prog = bpf_iter_get_info(&meta, in_stop);
268 if (!prog)
269 return 0;
270
271 ctx.meta = &meta;
272 ctx.task = info->task;
273 ctx.fd = info->fd;
274 ctx.file = file;
275 return bpf_iter_run_prog(prog, &ctx);
276}
277
278static int task_file_seq_show(struct seq_file *seq, void *v)
279{
280 return __task_file_seq_show(seq, v, false);
281}
282
283static void task_file_seq_stop(struct seq_file *seq, void *v)
284{
285 struct bpf_iter_seq_task_file_info *info = seq->private;
286
287 if (!v) {
288 (void)__task_file_seq_show(seq, v, true);
289 } else {
290 fput((struct file *)v);
291 put_files_struct(info->files);
292 put_task_struct(info->task);
293 info->files = NULL;
294 info->task = NULL;
295 }
296}
297
Yonghong Songf9c79272020-07-23 11:41:10 -0700298static int init_seq_pidns(void *priv_data, struct bpf_iter_aux_info *aux)
Yonghong Songeaaacd22020-05-09 10:59:11 -0700299{
300 struct bpf_iter_seq_task_common *common = priv_data;
301
302 common->ns = get_pid_ns(task_active_pid_ns(current));
303 return 0;
304}
305
306static void fini_seq_pidns(void *priv_data)
307{
308 struct bpf_iter_seq_task_common *common = priv_data;
309
310 put_pid_ns(common->ns);
311}
312
313static const struct seq_operations task_file_seq_ops = {
314 .start = task_file_seq_start,
315 .next = task_file_seq_next,
316 .stop = task_file_seq_stop,
317 .show = task_file_seq_show,
318};
319
Yonghong Song951cf362020-07-20 09:34:03 -0700320BTF_ID_LIST(btf_task_file_ids)
321BTF_ID(struct, task_struct)
322BTF_ID(struct, file)
323
Yonghong Song14fc6bd62020-07-23 11:41:09 -0700324static const struct bpf_iter_seq_info task_seq_info = {
Yonghong Song15172a42020-05-13 11:02:19 -0700325 .seq_ops = &task_seq_ops,
326 .init_seq_private = init_seq_pidns,
327 .fini_seq_private = fini_seq_pidns,
328 .seq_priv_size = sizeof(struct bpf_iter_seq_task_info),
Yonghong Song14fc6bd62020-07-23 11:41:09 -0700329};
330
331static struct bpf_iter_reg task_reg_info = {
332 .target = "task",
Yonghong Song3c32cc12020-05-13 11:02:21 -0700333 .ctx_arg_info_size = 1,
334 .ctx_arg_info = {
335 { offsetof(struct bpf_iter__task, task),
336 PTR_TO_BTF_ID_OR_NULL },
337 },
Yonghong Song14fc6bd62020-07-23 11:41:09 -0700338 .seq_info = &task_seq_info,
Yonghong Song15172a42020-05-13 11:02:19 -0700339};
340
Yonghong Song14fc6bd62020-07-23 11:41:09 -0700341static const struct bpf_iter_seq_info task_file_seq_info = {
Yonghong Song15172a42020-05-13 11:02:19 -0700342 .seq_ops = &task_file_seq_ops,
343 .init_seq_private = init_seq_pidns,
344 .fini_seq_private = fini_seq_pidns,
345 .seq_priv_size = sizeof(struct bpf_iter_seq_task_file_info),
Yonghong Song14fc6bd62020-07-23 11:41:09 -0700346};
347
348static struct bpf_iter_reg task_file_reg_info = {
349 .target = "task_file",
Yonghong Song3c32cc12020-05-13 11:02:21 -0700350 .ctx_arg_info_size = 2,
351 .ctx_arg_info = {
352 { offsetof(struct bpf_iter__task_file, task),
353 PTR_TO_BTF_ID_OR_NULL },
354 { offsetof(struct bpf_iter__task_file, file),
355 PTR_TO_BTF_ID_OR_NULL },
356 },
Yonghong Song14fc6bd62020-07-23 11:41:09 -0700357 .seq_info = &task_file_seq_info,
Yonghong Song15172a42020-05-13 11:02:19 -0700358};
359
Yonghong Songeaaacd22020-05-09 10:59:11 -0700360static int __init task_iter_init(void)
361{
Yonghong Songeaaacd22020-05-09 10:59:11 -0700362 int ret;
363
Yonghong Song951cf362020-07-20 09:34:03 -0700364 task_reg_info.ctx_arg_info[0].btf_id = btf_task_file_ids[0];
Yonghong Songeaaacd22020-05-09 10:59:11 -0700365 ret = bpf_iter_reg_target(&task_reg_info);
366 if (ret)
367 return ret;
368
Yonghong Song951cf362020-07-20 09:34:03 -0700369 task_file_reg_info.ctx_arg_info[0].btf_id = btf_task_file_ids[0];
370 task_file_reg_info.ctx_arg_info[1].btf_id = btf_task_file_ids[1];
Yonghong Songeaaacd22020-05-09 10:59:11 -0700371 return bpf_iter_reg_target(&task_file_reg_info);
372}
373late_initcall(task_iter_init);