1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2020 Facebook */
4 #include <linux/init.h>
5 #include <linux/namei.h>
6 #include <linux/pid_namespace.h>
8 #include <linux/fdtable.h>
9 #include <linux/filter.h>
11 struct bpf_iter_seq_task_common
{
12 struct pid_namespace
*ns
;
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.
19 struct bpf_iter_seq_task_common common
;
23 static struct task_struct
*task_seq_get_next(struct pid_namespace
*ns
,
26 struct task_struct
*task
= NULL
;
31 pid
= idr_get_next(&ns
->idr
, tid
);
33 task
= get_pid_task(pid
, PIDTYPE_PID
);
44 static void *task_seq_start(struct seq_file
*seq
, loff_t
*pos
)
46 struct bpf_iter_seq_task_info
*info
= seq
->private;
47 struct task_struct
*task
;
49 task
= task_seq_get_next(info
->common
.ns
, &info
->tid
);
57 static void *task_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
59 struct bpf_iter_seq_task_info
*info
= seq
->private;
60 struct task_struct
*task
;
64 put_task_struct((struct task_struct
*)v
);
65 task
= task_seq_get_next(info
->common
.ns
, &info
->tid
);
72 struct bpf_iter__task
{
73 __bpf_md_ptr(struct bpf_iter_meta
*, meta
);
74 __bpf_md_ptr(struct task_struct
*, task
);
77 DEFINE_BPF_ITER_FUNC(task
, struct bpf_iter_meta
*meta
, struct task_struct
*task
)
79 static int __task_seq_show(struct seq_file
*seq
, struct task_struct
*task
,
82 struct bpf_iter_meta meta
;
83 struct bpf_iter__task ctx
;
84 struct bpf_prog
*prog
;
87 prog
= bpf_iter_get_info(&meta
, in_stop
);
94 return bpf_iter_run_prog(prog
, &ctx
);
97 static int task_seq_show(struct seq_file
*seq
, void *v
)
99 return __task_seq_show(seq
, v
, false);
102 static void task_seq_stop(struct seq_file
*seq
, void *v
)
105 (void)__task_seq_show(seq
, v
, true);
107 put_task_struct((struct task_struct
*)v
);
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
,
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.
121 struct bpf_iter_seq_task_common common
;
122 struct task_struct
*task
;
123 struct files_struct
*files
;
129 task_file_seq_get_next(struct bpf_iter_seq_task_file_info
*info
,
130 struct task_struct
**task
, struct files_struct
**fstruct
)
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
;
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.
145 curr_files
= *fstruct
;
148 curr_task
= task_seq_get_next(ns
, &curr_tid
);
152 curr_files
= get_files_struct(curr_task
);
154 put_task_struct(curr_task
);
155 curr_tid
= ++(info
->tid
);
160 /* set *fstruct, *task and info->tid */
161 *fstruct
= curr_files
;
163 if (curr_tid
== info
->tid
) {
166 info
->tid
= curr_tid
;
172 max_fds
= files_fdtable(curr_files
)->max_fds
;
173 for (; curr_fd
< max_fds
; curr_fd
++) {
176 f
= fcheck_files(curr_files
, curr_fd
);
187 /* the current task is done, go to the next task */
189 put_files_struct(curr_files
);
190 put_task_struct(curr_task
);
194 curr_tid
= ++(info
->tid
);
198 static void *task_file_seq_start(struct seq_file
*seq
, loff_t
*pos
)
200 struct bpf_iter_seq_task_file_info
*info
= seq
->private;
201 struct files_struct
*files
= NULL
;
202 struct task_struct
*task
= NULL
;
205 file
= task_file_seq_get_next(info
, &task
, &files
);
219 static void *task_file_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
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
;
228 fput((struct file
*)v
);
229 file
= task_file_seq_get_next(info
, &task
, &files
);
242 struct bpf_iter__task_file
{
243 __bpf_md_ptr(struct bpf_iter_meta
*, meta
);
244 __bpf_md_ptr(struct task_struct
*, task
);
246 __bpf_md_ptr(struct file
*, file
);
249 DEFINE_BPF_ITER_FUNC(task_file
, struct bpf_iter_meta
*meta
,
250 struct task_struct
*task
, u32 fd
,
253 static int __task_file_seq_show(struct seq_file
*seq
, struct file
*file
,
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
;
262 prog
= bpf_iter_get_info(&meta
, in_stop
);
267 ctx
.task
= info
->task
;
270 return bpf_iter_run_prog(prog
, &ctx
);
273 static int task_file_seq_show(struct seq_file
*seq
, void *v
)
275 return __task_file_seq_show(seq
, v
, false);
278 static void task_file_seq_stop(struct seq_file
*seq
, void *v
)
280 struct bpf_iter_seq_task_file_info
*info
= seq
->private;
283 (void)__task_file_seq_show(seq
, v
, true);
285 fput((struct file
*)v
);
286 put_files_struct(info
->files
);
287 put_task_struct(info
->task
);
293 static int init_seq_pidns(void *priv_data
)
295 struct bpf_iter_seq_task_common
*common
= priv_data
;
297 common
->ns
= get_pid_ns(task_active_pid_ns(current
));
301 static void fini_seq_pidns(void *priv_data
)
303 struct bpf_iter_seq_task_common
*common
= priv_data
;
305 put_pid_ns(common
->ns
);
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
,
315 static const struct bpf_iter_reg task_reg_info
= {
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,
323 { offsetof(struct bpf_iter__task
, task
),
324 PTR_TO_BTF_ID_OR_NULL
},
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,
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
},
343 static int __init
task_iter_init(void)
347 ret
= bpf_iter_reg_target(&task_reg_info
);
351 return bpf_iter_reg_target(&task_file_reg_info
);
353 late_initcall(task_iter_init
);