-
Notifications
You must be signed in to change notification settings - Fork 71
/
utils.h
376 lines (312 loc) · 10 KB
/
utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __IDMAP_UTILS_H
#define __IDMAP_UTILS_H
#include "../global.h"
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <linux/types.h>
#include <sched.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syscall.h>
#include <sys/fsuid.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_SYS_CAPABILITY_H
#include <sys/capability.h>
#endif
#ifdef HAVE_LIBURING_H
#include <liburing.h>
#endif
#include "missing.h"
/* Flags for which functionality is required by the test */
#define T_REQUIRE_IDMAPPED_MOUNTS (1U << 0)
#define T_REQUIRE_USERNS (1U << 1)
#define T_DIR1 "idmapped_mounts_1"
#define FILE1 "file1"
#define FILE1_RENAME "file1_rename"
#define FILE2 "file2"
#define FILE3 "file3"
#define FILE2_RENAME "file2_rename"
#define DIR1 "dir1"
#define DIR2 "dir2"
#define DIR3 "dir3"
#define DIR1_RENAME "dir1_rename"
// This directory may be used by tests that call another test.
#define DIR0 "dir0"
#define HARDLINK1 "hardlink1"
#define SYMLINK1 "symlink1"
#define SYMLINK_USER1 "symlink_user1"
#define SYMLINK_USER2 "symlink_user2"
#define SYMLINK_USER3 "symlink_user3"
#define CHRDEV1 "chrdev1"
/* Maximum number of nested user namespaces in the kernel. */
#define MAX_USERNS_LEVEL 32
/* A few helpful macros. */
#define STRLITERALLEN(x) (sizeof(""x"") - 1)
#define INTTYPE_TO_STRLEN(type) \
(2 + (sizeof(type) <= 1 \
? 3 \
: sizeof(type) <= 2 \
? 5 \
: sizeof(type) <= 4 \
? 10 \
: sizeof(type) <= 8 ? 20 : sizeof(int[-2 * (sizeof(type) > 8)])))
#define log_stderr(format, ...) \
fprintf(stderr, "%s: %d: %s - %m - " format "\n", __FILE__, __LINE__, __func__, \
##__VA_ARGS__)
#ifdef DEBUG_TRACE
#define log_debug(format, ...) \
fprintf(stderr, "%s: %d: %s - " format "\n", __FILE__, __LINE__, \
__func__, ##__VA_ARGS__)
#else
#define log_debug(format, ...)
#endif
#define log_error_errno(__ret__, __errno__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
errno = (__errno__); \
log_stderr(format, ##__VA_ARGS__); \
__internal_ret__; \
})
#define log_errno(__ret__, format, ...) log_error_errno(__ret__, errno, format, ##__VA_ARGS__)
#define die_errno(__errno__, format, ...) \
({ \
errno = (__errno__); \
log_stderr(format, ##__VA_ARGS__); \
exit(EXIT_FAILURE); \
})
#define die(format, ...) die_errno(errno, format, ##__VA_ARGS__)
#define syserror(format, ...) \
({ \
fprintf(stderr, "%m - " format "\n", ##__VA_ARGS__); \
(-errno); \
})
#define syserror_set(__ret__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
errno = labs(__ret__); \
fprintf(stderr, "%m - " format "\n", ##__VA_ARGS__); \
__internal_ret__; \
})
#define safe_close(fd) \
if (fd >= 0) { \
int _e_ = errno; \
close(fd); \
errno = _e_; \
fd = -EBADF; \
}
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
#ifndef CAP_NET_RAW
#define CAP_NET_RAW 13
#endif
#ifndef VFS_CAP_FLAGS_EFFECTIVE
#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
#endif
#ifndef VFS_CAP_U32_3
#define VFS_CAP_U32_3 2
#endif
#ifndef VFS_CAP_U32
#define VFS_CAP_U32 VFS_CAP_U32_3
#endif
#ifndef VFS_CAP_REVISION_1
#define VFS_CAP_REVISION_1 0x01000000
#endif
#ifndef VFS_CAP_REVISION_2
#define VFS_CAP_REVISION_2 0x02000000
#endif
#ifndef VFS_CAP_REVISION_3
#define VFS_CAP_REVISION_3 0x03000000
struct vfs_ns_cap_data {
__le32 magic_etc;
struct {
__le32 permitted;
__le32 inheritable;
} data[VFS_CAP_U32];
__le32 rootid;
};
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le16(w16) le16_to_cpu(w16)
#define le16_to_cpu(w16) ((u_int16_t)((u_int16_t)(w16) >> 8) | (u_int16_t)((u_int16_t)(w16) << 8))
#define cpu_to_le32(w32) le32_to_cpu(w32)
#define le32_to_cpu(w32) \
((u_int32_t)((u_int32_t)(w32) >> 24) | (u_int32_t)(((u_int32_t)(w32) >> 8) & 0xFF00) | \
(u_int32_t)(((u_int32_t)(w32) << 8) & 0xFF0000) | (u_int32_t)((u_int32_t)(w32) << 24))
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le16(w16) ((u_int16_t)(w16))
#define le16_to_cpu(w16) ((u_int16_t)(w16))
#define cpu_to_le32(w32) ((u_int32_t)(w32))
#define le32_to_cpu(w32) ((u_int32_t)(w32))
#else
#error Expected endianess macro to be set
#endif
struct vfstest_info {
uid_t t_overflowuid;
gid_t t_overflowgid;
/* Filesystem type of the mountpoint */
const char *t_fstype;
/* path of the test device */
const char *t_device;
/* path of the test scratch device */
const char *t_device_scratch;
/* mountpoint of the test device */
const char *t_mountpoint;
/* mountpoint of the test device */
const char *t_mountpoint_scratch;
/* fd for @t_mountpoint */
int t_mnt_fd;
/* fd for @t_mountpoint_scratch */
int t_mnt_scratch_fd;
/* fd for @T_DIR1 */
int t_dir1_fd;
/* whether the underlying filesystem supports idmapped mounts */
bool t_fs_allow_idmap;
/* whether user namespaces are supported */
bool t_has_userns;
};
struct test_struct {
int (*test)(const struct vfstest_info *info);
unsigned int support_flags;
const char *description;
};
struct test_suite {
size_t nr_tests;
const struct test_struct *tests;
};
typedef enum idmap_type_t {
ID_TYPE_UID,
ID_TYPE_GID
} idmap_type_t;
struct id_map {
idmap_type_t map_type;
__u32 nsid;
__u32 hostid;
__u32 range;
};
struct list {
void *elem;
struct list *next;
struct list *prev;
};
struct userns_hierarchy {
int fd_userns;
int fd_event;
unsigned int level;
struct list id_map;
};
#define list_for_each(__iterator, __list) \
for (__iterator = (__list)->next; __iterator != __list; __iterator = __iterator->next)
#define list_for_each_safe(__iterator, __list, __next) \
for (__iterator = (__list)->next, __next = __iterator->next; \
__iterator != __list; __iterator = __next, __next = __next->next)
static inline void list_init(struct list *list)
{
list->elem = NULL;
list->next = list->prev = list;
}
static inline int list_empty(const struct list *list)
{
return list == list->next;
}
static inline void __list_add(struct list *new, struct list *prev, struct list *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add_tail(struct list *head, struct list *list)
{
__list_add(list, head->prev, head);
}
static inline void list_del(struct list *list)
{
struct list *next, *prev;
next = list->next;
prev = list->prev;
next->prev = prev;
prev->next = next;
}
extern pid_t do_clone(int (*fn)(void *), void *arg, int flags);
extern int get_userns_fd(unsigned long nsid, unsigned long hostid,
unsigned long range);
extern int get_userns_fd_from_idmap(struct list *idmap);
extern ssize_t read_nointr(int fd, void *buf, size_t count);
extern int wait_for_pid(pid_t pid);
extern ssize_t write_nointr(int fd, const void *buf, size_t count);
extern int caps_down(void);
extern int caps_down_fsetid(void);
extern int caps_up(void);
static inline bool caps_supported(void)
{
bool ret = false;
#ifdef HAVE_SYS_CAPABILITY_H
ret = true;
#endif
return ret;
}
extern bool expected_dummy_vfs_caps_uid(int fd, uid_t expected_uid);
extern int set_dummy_vfs_caps(int fd, int flags, int rootuid);
extern bool switch_ids(uid_t uid, gid_t gid);
extern int create_userns_hierarchy(struct userns_hierarchy *h);
extern int add_map_entry(struct list *head, __u32 id_host, __u32 id_ns,
__u32 range, idmap_type_t map_type);
extern bool __expected_uid_gid(int dfd, const char *path, int flags,
uid_t expected_uid, gid_t expected_gid, bool log);
static inline bool expected_uid_gid(int dfd, const char *path, int flags,
uid_t expected_uid, gid_t expected_gid)
{
return __expected_uid_gid(dfd, path, flags, expected_uid, expected_gid, true);
}
static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps)
{
if (setns(fd, CLONE_NEWUSER))
return log_errno(false, "failure: setns");
if (!switch_ids(uid, gid))
return log_errno(false, "failure: switch_ids");
if (drop_caps && !caps_down())
return log_errno(false, "failure: caps_down");
return true;
}
extern bool switch_resids(uid_t uid, gid_t gid);
static inline bool switch_fsids(uid_t fsuid, gid_t fsgid)
{
if (setfsgid(fsgid))
return log_errno(false, "failure: setfsgid");
if (setfsgid(-1) != fsgid)
return log_errno(false, "failure: setfsgid(-1)");
if (setfsuid(fsuid))
return log_errno(false, "failure: setfsuid");
if (setfsuid(-1) != fsuid)
return log_errno(false, "failure: setfsuid(-1)");
return true;
}
#ifdef HAVE_LIBURING_H
extern int io_uring_openat_with_creds(struct io_uring *ring, int dfd,
const char *path, int cred_id,
bool with_link, int *ret_cqe);
#endif /* HAVE_LIBURING_H */
extern int chown_r(int fd, const char *path, uid_t uid, gid_t gid);
extern int rm_r(int fd, const char *path);
#ifdef DEBUG_TRACE
extern int print_r(int fd, const char *path);
#else
static inline int print_r(int fd, const char *path) { return 0; }
#endif
extern int fd_to_fd(int from, int to);
extern bool protected_symlinks_enabled(void);
extern bool xfs_irix_sgid_inherit_enabled(const char *fstype);
extern bool expected_file_size(int dfd, const char *path, int flags,
off_t expected_size);
extern bool is_setid(int dfd, const char *path, int flags);
extern bool is_setgid(int dfd, const char *path, int flags);
extern bool is_sticky(int dfd, const char *path, int flags);
extern bool is_ixgrp(int dfd, const char *path, int flags);
extern bool openat_tmpfile_supported(int dirfd);
#endif /* __IDMAP_UTILS_H */