1 /*
2 * Check decoding of kcmp syscall.
3 *
4 * Copyright (c) 2016-2017 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2016-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include "scno.h"
13 #include "pidns.h"
14
15 #include <fcntl.h>
16 #include <stdarg.h>
17 #include <stdint.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <linux/kcmp.h>
22
23 #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
24 # define SKIP_IF_PROC_IS_UNAVAILABLE
25 #endif
26
27 #ifndef VERBOSE_FD
28 # define VERBOSE_FD 0
29 #endif
30
31 static const kernel_ulong_t kcmp_max_type = KCMP_EPOLL_TFD;
32
33 static const char null_path[] = "/dev/null";
34 static const char zero_path[] = "/dev/zero";
35
36 #define NULL_FD 23
37 #define ZERO_FD 42
38
39 static void
40 printpidfd(const char *prefix, pid_t pid, unsigned fd)
41 {
42 const char *path = NULL;
43
44 #if VERBOSE_FD
45 if (pid == getpid()) {
46 switch (fd)
47 {
48 case NULL_FD:
49 path = null_path;
50 break;
51 case ZERO_FD:
52 path = zero_path;
53 break;
54 }
55 }
56 #endif
57
58 if (path)
59 printf("%s%d<%s>", prefix, fd, path);
60 else
61 printf("%s%d", prefix, fd);
62 }
63
64 /*
65 * Last argument is optional and is used as follows:
66 * * When type is KCMP_EPOLL_TFD, it signalises whether idx2 is a valid
67 * pointer.
68 */
69 static void
70 do_kcmp(kernel_ulong_t pid1, kernel_ulong_t pid2, kernel_ulong_t type,
71 const char *type_str, kernel_ulong_t idx1, kernel_ulong_t idx2, ...)
72 {
73 long rc;
74 const char *errstr;
75
76 rc = syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
77 errstr = sprintrc(rc);
78
79 const char *pid_str = pidns_pid2str(PT_TGID);
80 pidns_print_leader();
81 printf("kcmp(%d%s, %d%s, ",
82 (int) pid1, (int) pid1 == getpid() ? pid_str : "",
83 (int) pid2, (int) pid2 == getpid() ? pid_str : "");
84
85 if (type_str)
86 printf("%s", type_str);
87 else
88 printf("%#x /* KCMP_??? */", (int) type);
89
90 if (type == KCMP_FILE) {
91 printpidfd(", ", pid1, idx1);
92 printpidfd(", ", pid2, idx2);
93 } else if (type == KCMP_EPOLL_TFD) {
94 va_list ap;
95 int valid_ptr;
96
97 va_start(ap, idx2);
98 valid_ptr = va_arg(ap, int);
99 va_end(ap);
100
101 printpidfd(", ", pid1, idx1);
102 printf(", ");
103
104 if (valid_ptr) {
105 struct kcmp_epoll_slot *slot =
106 (struct kcmp_epoll_slot *) (uintptr_t) idx2;
107
108 printpidfd("{efd=", pid2, slot->efd);
109 printpidfd(", tfd=", pid2, slot->tfd);
110 printf(", toff=%llu}", (unsigned long long) slot->toff);
111 } else {
112 if (idx2)
113 printf("%#llx", (unsigned long long) idx2);
114 else
115 printf("NULL");
116 }
117 } else if (type > kcmp_max_type) {
118 printf(", %#llx, %#llx",
119 (unsigned long long) idx1, (unsigned long long) idx2);
120 }
121
122 printf(") = %s\n", errstr);
123 }
124
125 int
126 main(void)
127 {
128 SKIP_IF_PROC_IS_UNAVAILABLE;
129 PIDNS_TEST_INIT;
130
131 static const kernel_ulong_t bogus_pid1 =
132 (kernel_ulong_t) 0xdeadca75face1057ULL;
133 static const kernel_ulong_t bogus_pid2 =
134 (kernel_ulong_t) 0xdefaced1defaced2ULL;
135 static const kernel_ulong_t bogus_type =
136 (kernel_ulong_t) 0xbadc0dedda7adeadULL;
137 static const kernel_ulong_t bogus_idx1 =
138 (kernel_ulong_t) 0xdec0ded3dec0ded4ULL;
139 static const kernel_ulong_t bogus_idx2 =
140 (kernel_ulong_t) 0xba5e1e55deadc0deULL;
141 static const struct kcmp_epoll_slot slot_data[] = {
142 { 0xdeadc0de, 0xfacef157, 0xbadc0ded },
143 { NULL_FD, ZERO_FD, 0 },
144 { 0, 0, 0 },
145 };
146 static kernel_ulong_t ptr_check =
147 F8ILL_KULONG_SUPPORTED ? F8ILL_KULONG_MASK : 0;
148
149 int fd;
150 TAIL_ALLOC_OBJECT_CONST_PTR(struct kcmp_epoll_slot, slot);
151
152 /* Open some files to test printpidfd */
153 fd = open(null_path, O_RDONLY);
154 if (fd < 0)
155 perror_msg_and_fail("open(\"%s\")", null_path);
156 if (fd != NULL_FD) {
157 if (dup2(fd, NULL_FD) < 0)
158 perror_msg_and_fail("dup2(fd, NULL_FD)");
159 close(fd);
160 }
161
162 fd = open(zero_path, O_RDONLY);
163 if (fd < 0)
164 perror_msg_and_fail("open(\"%s\")", zero_path);
165 if (fd != ZERO_FD) {
166 if (dup2(fd, ZERO_FD) < 0)
167 perror_msg_and_fail("dup2(fd, ZERO_FD)");
168 close(fd);
169 }
170
171 close(0);
172
173 /* Invalid values */
174 do_kcmp(bogus_pid1, bogus_pid2, bogus_type, NULL, bogus_idx1,
175 bogus_idx2);
176 do_kcmp(F8ILL_KULONG_MASK, F8ILL_KULONG_MASK, kcmp_max_type + 1, NULL,
177 0, 0);
178
179 /* KCMP_FILE is the only type which has additional args */
180 do_kcmp(3141592653U, 2718281828U, ARG_STR(KCMP_FILE), bogus_idx1,
181 bogus_idx2);
182 do_kcmp(getpid(), getpid(), ARG_STR(KCMP_FILE), NULL_FD, ZERO_FD);
183
184 /* Types without additional args */
185 do_kcmp(-1, -1, ARG_STR(KCMP_VM), bogus_idx1, bogus_idx2);
186 do_kcmp(-1, -1, ARG_STR(KCMP_FILES), bogus_idx1, bogus_idx2);
187 do_kcmp(-1, -1, ARG_STR(KCMP_FS), bogus_idx1, bogus_idx2);
188 do_kcmp(-1, -1, ARG_STR(KCMP_SIGHAND), bogus_idx1, bogus_idx2);
189 do_kcmp(-1, -1, ARG_STR(KCMP_IO), bogus_idx1, bogus_idx2);
190 do_kcmp(-1, -1, ARG_STR(KCMP_SYSVSEM), bogus_idx1, bogus_idx2);
191
192 /* KCMP_EPOLL_TFD checks */
193 do_kcmp(-1, -1, ARG_STR(KCMP_EPOLL_TFD),
194 F8ILL_KULONG_MASK | 2718281828U, ptr_check, 0);
195 do_kcmp(-1, -1, ARG_STR(KCMP_EPOLL_TFD),
196 3141592653U, (uintptr_t) slot + 1, 0);
197
198 for (unsigned int i = 0; i < ARRAY_SIZE(slot_data); ++i) {
199 memcpy(slot, slot_data + i, sizeof(*slot));
200
201 do_kcmp(getpid(), -1, ARG_STR(KCMP_EPOLL_TFD), NULL_FD,
202 (uintptr_t) slot, 1);
203 }
204
205 pidns_print_leader();
206 puts("+++ exited with 0 +++");
207
208 return 0;
209 }