Merge tag 'printk-for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/printk...
[linux-2.6-microblaze.git] / kernel / bpf / task_iter.c
1 // 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>
10 #include <linux/btf_ids.h>
11
12 struct bpf_iter_seq_task_common {
13         struct pid_namespace *ns;
14 };
15
16 struct 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
24 static 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();
31 retry:
32         pid = find_ge_pid(*tid, ns);
33         if (pid) {
34                 *tid = pid_nr_ns(pid, ns);
35                 task = get_pid_task(pid, PIDTYPE_PID);
36                 if (!task) {
37                         ++*tid;
38                         goto retry;
39                 }
40         }
41         rcu_read_unlock();
42
43         return task;
44 }
45
46 static 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
55         if (*pos == 0)
56                 ++*pos;
57         return task;
58 }
59
60 static 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
75 struct bpf_iter__task {
76         __bpf_md_ptr(struct bpf_iter_meta *, meta);
77         __bpf_md_ptr(struct task_struct *, task);
78 };
79
80 DEFINE_BPF_ITER_FUNC(task, struct bpf_iter_meta *meta, struct task_struct *task)
81
82 static 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
100 static int task_seq_show(struct seq_file *seq, void *v)
101 {
102         return __task_seq_show(seq, v, false);
103 }
104
105 static 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
113 static 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
120 struct 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
131 static struct file *
132 task_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          */
145 again:
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;
182                 if (!get_file_rcu(f))
183                         continue;
184
185                 /* set info->fd */
186                 info->fd = curr_fd;
187                 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
202 static 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
216         if (*pos == 0)
217                 ++*pos;
218         info->task = task;
219         info->files = files;
220
221         return file;
222 }
223
224 static 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
247 struct 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
254 DEFINE_BPF_ITER_FUNC(task_file, struct bpf_iter_meta *meta,
255                      struct task_struct *task, u32 fd,
256                      struct file *file)
257
258 static 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
278 static int task_file_seq_show(struct seq_file *seq, void *v)
279 {
280         return __task_file_seq_show(seq, v, false);
281 }
282
283 static 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
298 static int init_seq_pidns(void *priv_data, struct bpf_iter_aux_info *aux)
299 {
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
306 static 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
313 static 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
320 BTF_ID_LIST(btf_task_file_ids)
321 BTF_ID(struct, task_struct)
322 BTF_ID(struct, file)
323
324 static const struct bpf_iter_seq_info task_seq_info = {
325         .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),
329 };
330
331 static struct bpf_iter_reg task_reg_info = {
332         .target                 = "task",
333         .ctx_arg_info_size      = 1,
334         .ctx_arg_info           = {
335                 { offsetof(struct bpf_iter__task, task),
336                   PTR_TO_BTF_ID_OR_NULL },
337         },
338         .seq_info               = &task_seq_info,
339 };
340
341 static const struct bpf_iter_seq_info task_file_seq_info = {
342         .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),
346 };
347
348 static struct bpf_iter_reg task_file_reg_info = {
349         .target                 = "task_file",
350         .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         },
357         .seq_info               = &task_file_seq_info,
358 };
359
360 static int __init task_iter_init(void)
361 {
362         int ret;
363
364         task_reg_info.ctx_arg_info[0].btf_id = btf_task_file_ids[0];
365         ret = bpf_iter_reg_target(&task_reg_info);
366         if (ret)
367                 return ret;
368
369         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];
371         return bpf_iter_reg_target(&task_file_reg_info);
372 }
373 late_initcall(task_iter_init);