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>
10 #include <linux/btf_ids.h>
12 struct bpf_iter_seq_task_common
{
13 struct pid_namespace
*ns
;
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.
20 struct bpf_iter_seq_task_common common
;
24 static struct task_struct
*task_seq_get_next(struct pid_namespace
*ns
,
26 bool skip_if_dup_files
)
28 struct task_struct
*task
= NULL
;
33 pid
= find_ge_pid(*tid
, ns
);
35 *tid
= pid_nr_ns(pid
, ns
);
36 task
= get_pid_task(pid
, PIDTYPE_PID
);
40 } else if (skip_if_dup_files
&& !thread_group_leader(task
) &&
41 task
->files
== task
->group_leader
->files
) {
42 put_task_struct(task
);
53 static void *task_seq_start(struct seq_file
*seq
, loff_t
*pos
)
55 struct bpf_iter_seq_task_info
*info
= seq
->private;
56 struct task_struct
*task
;
58 task
= task_seq_get_next(info
->common
.ns
, &info
->tid
, false);
67 static void *task_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
69 struct bpf_iter_seq_task_info
*info
= seq
->private;
70 struct task_struct
*task
;
74 put_task_struct((struct task_struct
*)v
);
75 task
= task_seq_get_next(info
->common
.ns
, &info
->tid
, false);
82 struct bpf_iter__task
{
83 __bpf_md_ptr(struct bpf_iter_meta
*, meta
);
84 __bpf_md_ptr(struct task_struct
*, task
);
87 DEFINE_BPF_ITER_FUNC(task
, struct bpf_iter_meta
*meta
, struct task_struct
*task
)
89 static int __task_seq_show(struct seq_file
*seq
, struct task_struct
*task
,
92 struct bpf_iter_meta meta
;
93 struct bpf_iter__task ctx
;
94 struct bpf_prog
*prog
;
97 prog
= bpf_iter_get_info(&meta
, in_stop
);
104 return bpf_iter_run_prog(prog
, &ctx
);
107 static int task_seq_show(struct seq_file
*seq
, void *v
)
109 return __task_seq_show(seq
, v
, false);
112 static void task_seq_stop(struct seq_file
*seq
, void *v
)
115 (void)__task_seq_show(seq
, v
, true);
117 put_task_struct((struct task_struct
*)v
);
120 static const struct seq_operations task_seq_ops
= {
121 .start
= task_seq_start
,
122 .next
= task_seq_next
,
123 .stop
= task_seq_stop
,
124 .show
= task_seq_show
,
127 struct bpf_iter_seq_task_file_info
{
128 /* The first field must be struct bpf_iter_seq_task_common.
129 * this is assumed by {init, fini}_seq_pidns() callback functions.
131 struct bpf_iter_seq_task_common common
;
132 struct task_struct
*task
;
138 task_file_seq_get_next(struct bpf_iter_seq_task_file_info
*info
)
140 struct pid_namespace
*ns
= info
->common
.ns
;
141 u32 curr_tid
= info
->tid
;
142 struct task_struct
*curr_task
;
143 unsigned int curr_fd
= info
->fd
;
145 /* If this function returns a non-NULL file object,
146 * it held a reference to the task/file.
147 * Otherwise, it does not hold any reference.
151 curr_task
= info
->task
;
154 curr_task
= task_seq_get_next(ns
, &curr_tid
, true);
157 info
->tid
= curr_tid
;
161 /* set info->task and info->tid */
162 info
->task
= curr_task
;
163 if (curr_tid
== info
->tid
) {
166 info
->tid
= curr_tid
;
174 f
= task_lookup_next_fd_rcu(curr_task
, &curr_fd
);
177 if (!get_file_rcu(f
))
186 /* the current task is done, go to the next task */
188 put_task_struct(curr_task
);
191 curr_tid
= ++(info
->tid
);
195 static void *task_file_seq_start(struct seq_file
*seq
, loff_t
*pos
)
197 struct bpf_iter_seq_task_file_info
*info
= seq
->private;
201 file
= task_file_seq_get_next(info
);
202 if (file
&& *pos
== 0)
208 static void *task_file_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
210 struct bpf_iter_seq_task_file_info
*info
= seq
->private;
214 fput((struct file
*)v
);
215 return task_file_seq_get_next(info
);
218 struct bpf_iter__task_file
{
219 __bpf_md_ptr(struct bpf_iter_meta
*, meta
);
220 __bpf_md_ptr(struct task_struct
*, task
);
222 __bpf_md_ptr(struct file
*, file
);
225 DEFINE_BPF_ITER_FUNC(task_file
, struct bpf_iter_meta
*meta
,
226 struct task_struct
*task
, u32 fd
,
229 static int __task_file_seq_show(struct seq_file
*seq
, struct file
*file
,
232 struct bpf_iter_seq_task_file_info
*info
= seq
->private;
233 struct bpf_iter__task_file ctx
;
234 struct bpf_iter_meta meta
;
235 struct bpf_prog
*prog
;
238 prog
= bpf_iter_get_info(&meta
, in_stop
);
243 ctx
.task
= info
->task
;
246 return bpf_iter_run_prog(prog
, &ctx
);
249 static int task_file_seq_show(struct seq_file
*seq
, void *v
)
251 return __task_file_seq_show(seq
, v
, false);
254 static void task_file_seq_stop(struct seq_file
*seq
, void *v
)
256 struct bpf_iter_seq_task_file_info
*info
= seq
->private;
259 (void)__task_file_seq_show(seq
, v
, true);
261 fput((struct file
*)v
);
262 put_task_struct(info
->task
);
267 static int init_seq_pidns(void *priv_data
, struct bpf_iter_aux_info
*aux
)
269 struct bpf_iter_seq_task_common
*common
= priv_data
;
271 common
->ns
= get_pid_ns(task_active_pid_ns(current
));
275 static void fini_seq_pidns(void *priv_data
)
277 struct bpf_iter_seq_task_common
*common
= priv_data
;
279 put_pid_ns(common
->ns
);
282 static const struct seq_operations task_file_seq_ops
= {
283 .start
= task_file_seq_start
,
284 .next
= task_file_seq_next
,
285 .stop
= task_file_seq_stop
,
286 .show
= task_file_seq_show
,
289 BTF_ID_LIST(btf_task_file_ids
)
290 BTF_ID(struct, task_struct
)
293 static const struct bpf_iter_seq_info task_seq_info
= {
294 .seq_ops
= &task_seq_ops
,
295 .init_seq_private
= init_seq_pidns
,
296 .fini_seq_private
= fini_seq_pidns
,
297 .seq_priv_size
= sizeof(struct bpf_iter_seq_task_info
),
300 static struct bpf_iter_reg task_reg_info
= {
302 .feature
= BPF_ITER_RESCHED
,
303 .ctx_arg_info_size
= 1,
305 { offsetof(struct bpf_iter__task
, task
),
306 PTR_TO_BTF_ID_OR_NULL
},
308 .seq_info
= &task_seq_info
,
311 static const struct bpf_iter_seq_info task_file_seq_info
= {
312 .seq_ops
= &task_file_seq_ops
,
313 .init_seq_private
= init_seq_pidns
,
314 .fini_seq_private
= fini_seq_pidns
,
315 .seq_priv_size
= sizeof(struct bpf_iter_seq_task_file_info
),
318 static struct bpf_iter_reg task_file_reg_info
= {
319 .target
= "task_file",
320 .feature
= BPF_ITER_RESCHED
,
321 .ctx_arg_info_size
= 2,
323 { offsetof(struct bpf_iter__task_file
, task
),
324 PTR_TO_BTF_ID_OR_NULL
},
325 { offsetof(struct bpf_iter__task_file
, file
),
326 PTR_TO_BTF_ID_OR_NULL
},
328 .seq_info
= &task_file_seq_info
,
331 static int __init
task_iter_init(void)
335 task_reg_info
.ctx_arg_info
[0].btf_id
= btf_task_file_ids
[0];
336 ret
= bpf_iter_reg_target(&task_reg_info
);
340 task_file_reg_info
.ctx_arg_info
[0].btf_id
= btf_task_file_ids
[0];
341 task_file_reg_info
.ctx_arg_info
[1].btf_id
= btf_task_file_ids
[1];
342 return bpf_iter_reg_target(&task_file_reg_info
);
344 late_initcall(task_iter_init
);