mm/memory-failure: send SIGBUS(BUS_MCEERR_AR) only to current thread
[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
11 struct bpf_iter_seq_task_common {
12         struct pid_namespace *ns;
13 };
14
15 struct bpf_iter_seq_task_info {
16         /* The first field must be struct bpf_iter_seq_task_common.
17          * this is assumed by {init, fini}_seq_pidns() callback functions.
18          */
19         struct bpf_iter_seq_task_common common;
20         u32 tid;
21 };
22
23 static struct task_struct *task_seq_get_next(struct pid_namespace *ns,
24                                              u32 *tid)
25 {
26         struct task_struct *task = NULL;
27         struct pid *pid;
28
29         rcu_read_lock();
30 retry:
31         pid = idr_get_next(&ns->idr, tid);
32         if (pid) {
33                 task = get_pid_task(pid, PIDTYPE_PID);
34                 if (!task) {
35                         ++*tid;
36                         goto retry;
37                 }
38         }
39         rcu_read_unlock();
40
41         return task;
42 }
43
44 static void *task_seq_start(struct seq_file *seq, loff_t *pos)
45 {
46         struct bpf_iter_seq_task_info *info = seq->private;
47         struct task_struct *task;
48
49         task = task_seq_get_next(info->common.ns, &info->tid);
50         if (!task)
51                 return NULL;
52
53         ++*pos;
54         return task;
55 }
56
57 static void *task_seq_next(struct seq_file *seq, void *v, loff_t *pos)
58 {
59         struct bpf_iter_seq_task_info *info = seq->private;
60         struct task_struct *task;
61
62         ++*pos;
63         ++info->tid;
64         put_task_struct((struct task_struct *)v);
65         task = task_seq_get_next(info->common.ns, &info->tid);
66         if (!task)
67                 return NULL;
68
69         return task;
70 }
71
72 struct bpf_iter__task {
73         __bpf_md_ptr(struct bpf_iter_meta *, meta);
74         __bpf_md_ptr(struct task_struct *, task);
75 };
76
77 DEFINE_BPF_ITER_FUNC(task, struct bpf_iter_meta *meta, struct task_struct *task)
78
79 static int __task_seq_show(struct seq_file *seq, struct task_struct *task,
80                            bool in_stop)
81 {
82         struct bpf_iter_meta meta;
83         struct bpf_iter__task ctx;
84         struct bpf_prog *prog;
85
86         meta.seq = seq;
87         prog = bpf_iter_get_info(&meta, in_stop);
88         if (!prog)
89                 return 0;
90
91         meta.seq = seq;
92         ctx.meta = &meta;
93         ctx.task = task;
94         return bpf_iter_run_prog(prog, &ctx);
95 }
96
97 static int task_seq_show(struct seq_file *seq, void *v)
98 {
99         return __task_seq_show(seq, v, false);
100 }
101
102 static void task_seq_stop(struct seq_file *seq, void *v)
103 {
104         if (!v)
105                 (void)__task_seq_show(seq, v, true);
106         else
107                 put_task_struct((struct task_struct *)v);
108 }
109
110 static const struct seq_operations task_seq_ops = {
111         .start  = task_seq_start,
112         .next   = task_seq_next,
113         .stop   = task_seq_stop,
114         .show   = task_seq_show,
115 };
116
117 struct bpf_iter_seq_task_file_info {
118         /* The first field must be struct bpf_iter_seq_task_common.
119          * this is assumed by {init, fini}_seq_pidns() callback functions.
120          */
121         struct bpf_iter_seq_task_common common;
122         struct task_struct *task;
123         struct files_struct *files;
124         u32 tid;
125         u32 fd;
126 };
127
128 static struct file *
129 task_file_seq_get_next(struct bpf_iter_seq_task_file_info *info,
130                        struct task_struct **task, struct files_struct **fstruct)
131 {
132         struct pid_namespace *ns = info->common.ns;
133         u32 curr_tid = info->tid, max_fds;
134         struct files_struct *curr_files;
135         struct task_struct *curr_task;
136         int curr_fd = info->fd;
137
138         /* If this function returns a non-NULL file object,
139          * it held a reference to the task/files_struct/file.
140          * Otherwise, it does not hold any reference.
141          */
142 again:
143         if (*task) {
144                 curr_task = *task;
145                 curr_files = *fstruct;
146                 curr_fd = info->fd;
147         } else {
148                 curr_task = task_seq_get_next(ns, &curr_tid);
149                 if (!curr_task)
150                         return NULL;
151
152                 curr_files = get_files_struct(curr_task);
153                 if (!curr_files) {
154                         put_task_struct(curr_task);
155                         curr_tid = ++(info->tid);
156                         info->fd = 0;
157                         goto again;
158                 }
159
160                 /* set *fstruct, *task and info->tid */
161                 *fstruct = curr_files;
162                 *task = curr_task;
163                 if (curr_tid == info->tid) {
164                         curr_fd = info->fd;
165                 } else {
166                         info->tid = curr_tid;
167                         curr_fd = 0;
168                 }
169         }
170
171         rcu_read_lock();
172         max_fds = files_fdtable(curr_files)->max_fds;
173         for (; curr_fd < max_fds; curr_fd++) {
174                 struct file *f;
175
176                 f = fcheck_files(curr_files, curr_fd);
177                 if (!f)
178                         continue;
179
180                 /* set info->fd */
181                 info->fd = curr_fd;
182                 get_file(f);
183                 rcu_read_unlock();
184                 return f;
185         }
186
187         /* the current task is done, go to the next task */
188         rcu_read_unlock();
189         put_files_struct(curr_files);
190         put_task_struct(curr_task);
191         *task = NULL;
192         *fstruct = NULL;
193         info->fd = 0;
194         curr_tid = ++(info->tid);
195         goto again;
196 }
197
198 static void *task_file_seq_start(struct seq_file *seq, loff_t *pos)
199 {
200         struct bpf_iter_seq_task_file_info *info = seq->private;
201         struct files_struct *files = NULL;
202         struct task_struct *task = NULL;
203         struct file *file;
204
205         file = task_file_seq_get_next(info, &task, &files);
206         if (!file) {
207                 info->files = NULL;
208                 info->task = NULL;
209                 return NULL;
210         }
211
212         ++*pos;
213         info->task = task;
214         info->files = files;
215
216         return file;
217 }
218
219 static void *task_file_seq_next(struct seq_file *seq, void *v, loff_t *pos)
220 {
221         struct bpf_iter_seq_task_file_info *info = seq->private;
222         struct files_struct *files = info->files;
223         struct task_struct *task = info->task;
224         struct file *file;
225
226         ++*pos;
227         ++info->fd;
228         fput((struct file *)v);
229         file = task_file_seq_get_next(info, &task, &files);
230         if (!file) {
231                 info->files = NULL;
232                 info->task = NULL;
233                 return NULL;
234         }
235
236         info->task = task;
237         info->files = files;
238
239         return file;
240 }
241
242 struct bpf_iter__task_file {
243         __bpf_md_ptr(struct bpf_iter_meta *, meta);
244         __bpf_md_ptr(struct task_struct *, task);
245         u32 fd __aligned(8);
246         __bpf_md_ptr(struct file *, file);
247 };
248
249 DEFINE_BPF_ITER_FUNC(task_file, struct bpf_iter_meta *meta,
250                      struct task_struct *task, u32 fd,
251                      struct file *file)
252
253 static int __task_file_seq_show(struct seq_file *seq, struct file *file,
254                                 bool in_stop)
255 {
256         struct bpf_iter_seq_task_file_info *info = seq->private;
257         struct bpf_iter__task_file ctx;
258         struct bpf_iter_meta meta;
259         struct bpf_prog *prog;
260
261         meta.seq = seq;
262         prog = bpf_iter_get_info(&meta, in_stop);
263         if (!prog)
264                 return 0;
265
266         ctx.meta = &meta;
267         ctx.task = info->task;
268         ctx.fd = info->fd;
269         ctx.file = file;
270         return bpf_iter_run_prog(prog, &ctx);
271 }
272
273 static int task_file_seq_show(struct seq_file *seq, void *v)
274 {
275         return __task_file_seq_show(seq, v, false);
276 }
277
278 static void task_file_seq_stop(struct seq_file *seq, void *v)
279 {
280         struct bpf_iter_seq_task_file_info *info = seq->private;
281
282         if (!v) {
283                 (void)__task_file_seq_show(seq, v, true);
284         } else {
285                 fput((struct file *)v);
286                 put_files_struct(info->files);
287                 put_task_struct(info->task);
288                 info->files = NULL;
289                 info->task = NULL;
290         }
291 }
292
293 static int init_seq_pidns(void *priv_data)
294 {
295         struct bpf_iter_seq_task_common *common = priv_data;
296
297         common->ns = get_pid_ns(task_active_pid_ns(current));
298         return 0;
299 }
300
301 static void fini_seq_pidns(void *priv_data)
302 {
303         struct bpf_iter_seq_task_common *common = priv_data;
304
305         put_pid_ns(common->ns);
306 }
307
308 static const struct seq_operations task_file_seq_ops = {
309         .start  = task_file_seq_start,
310         .next   = task_file_seq_next,
311         .stop   = task_file_seq_stop,
312         .show   = task_file_seq_show,
313 };
314
315 static const struct bpf_iter_reg task_reg_info = {
316         .target                 = "task",
317         .seq_ops                = &task_seq_ops,
318         .init_seq_private       = init_seq_pidns,
319         .fini_seq_private       = fini_seq_pidns,
320         .seq_priv_size          = sizeof(struct bpf_iter_seq_task_info),
321         .ctx_arg_info_size      = 1,
322         .ctx_arg_info           = {
323                 { offsetof(struct bpf_iter__task, task),
324                   PTR_TO_BTF_ID_OR_NULL },
325         },
326 };
327
328 static const struct bpf_iter_reg task_file_reg_info = {
329         .target                 = "task_file",
330         .seq_ops                = &task_file_seq_ops,
331         .init_seq_private       = init_seq_pidns,
332         .fini_seq_private       = fini_seq_pidns,
333         .seq_priv_size          = sizeof(struct bpf_iter_seq_task_file_info),
334         .ctx_arg_info_size      = 2,
335         .ctx_arg_info           = {
336                 { offsetof(struct bpf_iter__task_file, task),
337                   PTR_TO_BTF_ID_OR_NULL },
338                 { offsetof(struct bpf_iter__task_file, file),
339                   PTR_TO_BTF_ID_OR_NULL },
340         },
341 };
342
343 static int __init task_iter_init(void)
344 {
345         int ret;
346
347         ret = bpf_iter_reg_target(&task_reg_info);
348         if (ret)
349                 return ret;
350
351         return bpf_iter_reg_target(&task_file_reg_info);
352 }
353 late_initcall(task_iter_init);