Merge tag 'nfs-for-5.7-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[linux-2.6-microblaze.git] / tools / testing / selftests / bpf / test_current_pid_tgid_new_ns.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2020 Carlos Neira cneirabustos@gmail.com */
3 #define _GNU_SOURCE
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7 #include <sys/syscall.h>
8 #include <sched.h>
9 #include <sys/wait.h>
10 #include <sys/mount.h>
11 #include "test_progs.h"
12
13 #define CHECK_NEWNS(condition, tag, format...) ({               \
14         int __ret = !!(condition);                      \
15         if (__ret) {                                    \
16                 printf("%s:FAIL:%s ", __func__, tag);   \
17                 printf(format);                         \
18         } else {                                        \
19                 printf("%s:PASS:%s\n", __func__, tag);  \
20         }                                               \
21         __ret;                                          \
22 })
23
24 struct bss {
25         __u64 dev;
26         __u64 ino;
27         __u64 pid_tgid;
28         __u64 user_pid_tgid;
29 };
30
31 int main(int argc, char **argv)
32 {
33         pid_t pid;
34         int exit_code = 1;
35         struct stat st;
36
37         printf("Testing bpf_get_ns_current_pid_tgid helper in new ns\n");
38
39         if (stat("/proc/self/ns/pid", &st)) {
40                 perror("stat failed on /proc/self/ns/pid ns\n");
41                 printf("%s:FAILED\n", argv[0]);
42                 return exit_code;
43         }
44
45         if (CHECK_NEWNS(unshare(CLONE_NEWPID | CLONE_NEWNS),
46                         "unshare CLONE_NEWPID | CLONE_NEWNS", "error errno=%d\n", errno))
47                 return exit_code;
48
49         pid = fork();
50         if (pid == -1) {
51                 perror("Fork() failed\n");
52                 printf("%s:FAILED\n", argv[0]);
53                 return exit_code;
54         }
55
56         if (pid > 0) {
57                 int status;
58
59                 usleep(5);
60                 waitpid(pid, &status, 0);
61                 return 0;
62         } else {
63
64                 pid = fork();
65                 if (pid == -1) {
66                         perror("Fork() failed\n");
67                         printf("%s:FAILED\n", argv[0]);
68                         return exit_code;
69                 }
70
71                 if (pid > 0) {
72                         int status;
73                         waitpid(pid, &status, 0);
74                         return 0;
75                 } else {
76                         if (CHECK_NEWNS(mount("none", "/proc", NULL, MS_PRIVATE|MS_REC, NULL),
77                                 "Unmounting proc", "Cannot umount proc! errno=%d\n", errno))
78                                 return exit_code;
79
80                         if (CHECK_NEWNS(mount("proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL),
81                                 "Mounting proc", "Cannot mount proc! errno=%d\n", errno))
82                                 return exit_code;
83
84                         const char *probe_name = "raw_tracepoint/sys_enter";
85                         const char *file = "test_ns_current_pid_tgid.o";
86                         struct bpf_link *link = NULL;
87                         struct bpf_program *prog;
88                         struct bpf_map *bss_map;
89                         struct bpf_object *obj;
90                         int exit_code = 1;
91                         int err, key = 0;
92                         struct bss bss;
93                         struct stat st;
94                         __u64 id;
95
96                         obj = bpf_object__open_file(file, NULL);
97                         if (CHECK_NEWNS(IS_ERR(obj), "obj_open", "err %ld\n", PTR_ERR(obj)))
98                                 return exit_code;
99
100                         err = bpf_object__load(obj);
101                         if (CHECK_NEWNS(err, "obj_load", "err %d errno %d\n", err, errno))
102                                 goto cleanup;
103
104                         bss_map = bpf_object__find_map_by_name(obj, "test_ns_.bss");
105                         if (CHECK_NEWNS(!bss_map, "find_bss_map", "failed\n"))
106                                 goto cleanup;
107
108                         prog = bpf_object__find_program_by_title(obj, probe_name);
109                         if (CHECK_NEWNS(!prog, "find_prog", "prog '%s' not found\n",
110                                                 probe_name))
111                                 goto cleanup;
112
113                         memset(&bss, 0, sizeof(bss));
114                         pid_t tid = syscall(SYS_gettid);
115                         pid_t pid = getpid();
116
117                         id = (__u64) tid << 32 | pid;
118                         bss.user_pid_tgid = id;
119
120                         if (CHECK_NEWNS(stat("/proc/self/ns/pid", &st),
121                                 "stat new ns", "Failed to stat /proc/self/ns/pid errno=%d\n", errno))
122                                 goto cleanup;
123
124                         bss.dev = st.st_dev;
125                         bss.ino = st.st_ino;
126
127                         err = bpf_map_update_elem(bpf_map__fd(bss_map), &key, &bss, 0);
128                         if (CHECK_NEWNS(err, "setting_bss", "failed to set bss : %d\n", err))
129                                 goto cleanup;
130
131                         link = bpf_program__attach_raw_tracepoint(prog, "sys_enter");
132                         if (CHECK_NEWNS(IS_ERR(link), "attach_raw_tp", "err %ld\n",
133                                                 PTR_ERR(link))) {
134                                 link = NULL;
135                                 goto cleanup;
136                         }
137
138                         /* trigger some syscalls */
139                         usleep(1);
140
141                         err = bpf_map_lookup_elem(bpf_map__fd(bss_map), &key, &bss);
142                         if (CHECK_NEWNS(err, "set_bss", "failed to get bss : %d\n", err))
143                                 goto cleanup;
144
145                         if (CHECK_NEWNS(id != bss.pid_tgid, "Compare user pid/tgid vs. bpf pid/tgid",
146                                                 "User pid/tgid %llu BPF pid/tgid %llu\n", id, bss.pid_tgid))
147                                 goto cleanup;
148
149                         exit_code = 0;
150                         printf("%s:PASS\n", argv[0]);
151 cleanup:
152                         if (!link) {
153                                 bpf_link__destroy(link);
154                                 link = NULL;
155                         }
156                         bpf_object__close(obj);
157                 }
158         }
159 }