1 /*
2 * Copyright (c) 2015 Dmitry V. Levin <ldv@strace.io>
3 * Copyright (c) 2015-2021 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #include "defs.h"
10 #include "kernel_fcntl.h"
11 #include <linux/ioctl.h>
12 #include <linux/userfaultfd.h>
13
14 #include "xlat/uffd_flags.h"
15
16 SYS_FUNC(userfaultfd)
17 {
18 printflags(uffd_flags, tcp->u_arg[0], "UFFD_???");
19
20 return RVAL_DECODED | RVAL_FD;
21 }
22
23
24 #include "xlat/uffd_api_features.h"
25 #include "xlat/uffd_api_flags.h"
26 #include "xlat/uffd_copy_flags.h"
27 #include "xlat/uffd_register_ioctl_flags.h"
28 #include "xlat/uffd_register_mode_flags.h"
29 #include "xlat/uffd_zeropage_flags.h"
30
31 static void
32 tprintf_uffdio_range(const struct uffdio_range *range)
33 {
34 tprint_struct_begin();
35 PRINT_FIELD_X(*range, start);
36 tprint_struct_next();
37 PRINT_FIELD_X(*range, len);
38 tprint_struct_end();
39 }
40
41 int
42 uffdio_ioctl(struct tcb *const tcp, const unsigned int code,
43 const kernel_ulong_t arg)
44 {
45 switch (code) {
46 case UFFDIO_API: {
47 uint64_t *entering_features;
48 struct uffdio_api ua;
49
50 if (entering(tcp)) {
51 tprint_arg_next();
52 if (umove_or_printaddr(tcp, arg, &ua))
53 break;
54 tprint_struct_begin();
55 PRINT_FIELD_X(ua, api);
56 tprint_struct_next();
57 PRINT_FIELD_FLAGS(ua, features, uffd_api_features,
58 "UFFD_FEATURE_???");
59 entering_features = malloc(sizeof(*entering_features));
60 if (entering_features) {
61 *entering_features = ua.features;
62 set_tcb_priv_data(tcp, entering_features, free);
63 }
64
65 return 0;
66 }
67
68 if (!syserror(tcp) && !umove(tcp, arg, &ua)) {
69 entering_features = get_tcb_priv_data(tcp);
70
71 if (!entering_features
72 || *entering_features != ua.features) {
73 tprint_value_changed();
74 PRINT_FIELD_FLAGS(ua, features,
75 uffd_api_features,
76 "UFFD_FEATURE_???");
77 }
78
79 tprint_struct_next();
80 PRINT_FIELD_FLAGS(ua, ioctls, uffd_api_flags,
81 "_UFFDIO_???");
82 }
83
84 tprint_struct_end();
85
86 break;
87 }
88
89 case UFFDIO_COPY: {
90 struct uffdio_copy uc;
91
92 if (entering(tcp)) {
93 tprint_arg_next();
94 if (umove_or_printaddr(tcp, arg, &uc))
95 return RVAL_IOCTL_DECODED;
96 tprint_struct_begin();
97 PRINT_FIELD_X(uc, dst);
98 tprint_struct_next();
99 PRINT_FIELD_X(uc, src);
100 tprint_struct_next();
101 PRINT_FIELD_X(uc, len);
102 tprint_struct_next();
103 PRINT_FIELD_FLAGS(uc, mode, uffd_copy_flags,
104 "UFFDIO_COPY_???");
105
106 return 0;
107 }
108
109 if (!syserror(tcp) && !umove(tcp, arg, &uc)) {
110 tprint_struct_next();
111 PRINT_FIELD_X(uc, copy);
112 }
113
114 tprint_struct_end();
115
116 break;
117 }
118
119 case UFFDIO_REGISTER: {
120 struct uffdio_register ur;
121
122 if (entering(tcp)) {
123 tprint_arg_next();
124 if (umove_or_printaddr(tcp, arg, &ur))
125 return RVAL_IOCTL_DECODED;
126 tprint_struct_begin();
127 PRINT_FIELD_OBJ_PTR(ur, range,
128 tprintf_uffdio_range);
129 tprint_struct_next();
130 PRINT_FIELD_FLAGS(ur, mode,
131 uffd_register_mode_flags,
132 "UFFDIO_REGISTER_MODE_???");
133
134 return 0;
135 }
136
137 if (!syserror(tcp) && !umove(tcp, arg, &ur)) {
138 tprint_struct_next();
139 PRINT_FIELD_FLAGS(ur, ioctls,
140 uffd_register_ioctl_flags,
141 "UFFDIO_???");
142 }
143
144 tprint_struct_end();
145
146 break;
147 }
148
149 case UFFDIO_UNREGISTER:
150 case UFFDIO_WAKE: {
151 struct uffdio_range ura;
152
153 tprint_arg_next();
154 if (!umove_or_printaddr(tcp, arg, &ura))
155 tprintf_uffdio_range(&ura);
156
157 break;
158 }
159
160 case UFFDIO_ZEROPAGE: {
161 struct uffdio_zeropage uz;
162
163 if (entering(tcp)) {
164 tprint_arg_next();
165 if (umove_or_printaddr(tcp, arg, &uz))
166 return RVAL_IOCTL_DECODED;
167 tprint_struct_begin();
168 PRINT_FIELD_OBJ_PTR(uz, range,
169 tprintf_uffdio_range);
170 tprint_struct_next();
171 PRINT_FIELD_FLAGS(uz, mode, uffd_zeropage_flags,
172 "UFFDIO_ZEROPAGE_???");
173
174 return 0;
175 }
176
177 if (!syserror(tcp) && !umove(tcp, arg, &uz)) {
178 tprint_struct_next();
179 PRINT_FIELD_X(uz, zeropage);
180 }
181
182 tprint_struct_end();
183
184 break;
185 }
186
187 default:
188 return RVAL_DECODED;
189 }
190
191 return RVAL_IOCTL_DECODED;
192 }