]> granicus.if.org Git - strace/blob - tests/kcmp.c
Remove XLAT_END
[strace] / tests / kcmp.c
1 /*
2  * Check decoding of kcmp syscall.
3  *
4  * Copyright (c) 2016-2017 Eugene Syromyatnikov <evgsyr@gmail.com>
5  * Copyright (c) 2016-2019 The strace developers.
6  * All rights reserved.
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "tests.h"
12
13 #include "scno.h"
14
15 #ifdef __NR_kcmp
16
17 # include <fcntl.h>
18 # include <stdarg.h>
19 # include <stdint.h>
20 # include <stdio.h>
21 # include <string.h>
22 # include <unistd.h>
23
24 # ifndef VERBOSE_FD
25 #  define VERBOSE_FD 0
26 # endif
27
28 /*
29  * We prefer to use system headers in order to catch some possible deviations in
30  * system's headers from our perception of reality, but happy to include our own
31  * definitions as well.
32  */
33 # ifdef HAVE_LINUX_KCMP_H
34 #  include <linux/kcmp.h>
35 # else
36 #  define KCMP_FILE     0
37 #  define KCMP_VM       1
38 #  define KCMP_FILES    2
39 #  define KCMP_FS       3
40 #  define KCMP_SIGHAND  4
41 #  define KCMP_IO       5
42 #  define KCMP_SYSVSEM  6
43 # endif
44
45 /* All other kcmp types have been added atomically */
46 # define KCMP_EPOLL_TFD 7
47
48 # ifndef HAVE_STRUCT_KCMP_EPOLL_SLOT
49 struct kcmp_epoll_slot {
50         uint32_t efd;
51         uint32_t tfd;
52         uint32_t toff;
53 };
54 # endif
55
56 static const kernel_ulong_t kcmp_max_type = KCMP_EPOLL_TFD;
57
58 static const char null_path[] = "/dev/null";
59 static const char zero_path[] = "/dev/zero";
60
61 # define NULL_FD 23
62 # define ZERO_FD 42
63
64 static void
65 printpidfd(const char *prefix, pid_t pid, unsigned fd)
66 {
67         printf("%s%d", prefix, fd);
68 }
69
70 /*
71  * Last argument is optional and is used as follows:
72  *  * When type is KCMP_EPOLL_TFD, it signalises whether idx2 is a valid
73  *    pointer.
74  */
75 static void
76 do_kcmp(kernel_ulong_t pid1, kernel_ulong_t pid2, kernel_ulong_t type,
77         const char *type_str, kernel_ulong_t idx1, kernel_ulong_t idx2, ...)
78 {
79         long rc;
80         const char *errstr;
81
82         rc = syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
83         errstr = sprintrc(rc);
84
85         printf("kcmp(%d, %d, ", (int) pid1, (int) pid2);
86
87         if (type_str)
88                 printf("%s", type_str);
89         else
90                 printf("%#x /* KCMP_??? */", (int) type);
91
92         if (type == KCMP_FILE) {
93                 printpidfd(", ", pid1, idx1);
94                 printpidfd(", ", pid2, idx2);
95         } else if (type == KCMP_EPOLL_TFD) {
96                 va_list ap;
97                 int valid_ptr;
98
99                 va_start(ap, idx2);
100                 valid_ptr = va_arg(ap, int);
101                 va_end(ap);
102
103                 printpidfd(", ", pid1, idx1);
104                 printf(", ");
105
106                 if (valid_ptr) {
107                         struct kcmp_epoll_slot *slot =
108                                 (struct kcmp_epoll_slot *) (uintptr_t) idx2;
109
110                         printpidfd("{efd=", pid2, slot->efd);
111                         printpidfd(", tfd=", pid2, slot->tfd);
112                         printf(", toff=%llu}", (unsigned long long) slot->toff);
113                 } else {
114                         if (idx2)
115                                 printf("%#llx", (unsigned long long) idx2);
116                         else
117                                 printf("NULL");
118                 }
119         } else if (type > kcmp_max_type) {
120                 printf(", %#llx, %#llx",
121                        (unsigned long long) idx1, (unsigned long long) idx2);
122         }
123
124         printf(") = %s\n", errstr);
125 }
126
127 int
128 main(void)
129 {
130         static const kernel_ulong_t bogus_pid1 =
131                 (kernel_ulong_t) 0xdeadca75face1057ULL;
132         static const kernel_ulong_t bogus_pid2 =
133                 (kernel_ulong_t) 0xdefaced1defaced2ULL;
134         static const kernel_ulong_t bogus_type =
135                 (kernel_ulong_t) 0xbadc0dedda7adeadULL;
136         static const kernel_ulong_t bogus_idx1 =
137                 (kernel_ulong_t) 0xdec0ded3dec0ded4ULL;
138         static const kernel_ulong_t bogus_idx2 =
139                 (kernel_ulong_t) 0xba5e1e55deadc0deULL;
140         static const struct kcmp_epoll_slot slot_data[] = {
141                 { 0xdeadc0de, 0xfacef157, 0xbadc0ded },
142                 { NULL_FD, ZERO_FD, 0 },
143                 { 0, 0, 0 },
144         };
145         static kernel_ulong_t ptr_check =
146                 F8ILL_KULONG_SUPPORTED ? F8ILL_KULONG_MASK : 0;
147
148         int fd;
149         unsigned i;
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(-1, -1, 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 (i = 0; i < ARRAY_SIZE(slot_data); i++) {
199                 memcpy(slot, slot_data + i, sizeof(*slot));
200
201                 do_kcmp(getpid(), getppid(), ARG_STR(KCMP_EPOLL_TFD), NULL_FD,
202                         (uintptr_t) slot, 1);
203         }
204
205         puts("+++ exited with 0 +++");
206
207         return 0;
208 }
209
210 #else
211
212 SKIP_MAIN_UNDEFINED("__NR_kcmp");
213
214 #endif