1 /*
2 * Check decoding of mount_setattr syscall.
3 *
4 * Copyright (c) 2019-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12
13 #include <limits.h>
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <linux/fcntl.h>
19 #include <linux/mount.h>
20
21 static const char *rcstr;
22
23 static long
24 k_mount_setattr(const unsigned int dfd,
25 const void *fname,
26 const unsigned int flags,
27 const void *attr,
28 kernel_ulong_t size)
29 {
30 const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
31 const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
32 const kernel_ulong_t arg1 = fill | dfd;
33 const kernel_ulong_t arg2 = (uintptr_t) fname;
34 const kernel_ulong_t arg3 = fill | flags;
35 const kernel_ulong_t arg4 = (uintptr_t) attr;
36 const kernel_ulong_t arg5 = size;
37 const long rc =
38 syscall(__NR_mount_setattr, arg1, arg2, arg3, arg4, arg5, bad);
39 rcstr = sprintrc(rc);
40 return rc;
41 }
42
43 int
44 main(void)
45 {
46 skip_if_unavailable("/proc/self/fd/");
47
48 #ifndef PATH_TRACING
49 char *cwd = get_fd_path(get_dir_fd("."));
50 #endif
51 static const char path_full[] = "/dev/full";
52 const char *const path = tail_memdup(path_full, sizeof(path_full));
53 char *const fname = tail_alloc(PATH_MAX);
54 const void *const efault = fname + PATH_MAX;
55 const char *const empty = efault - 1;
56 fill_memory_ex(fname, PATH_MAX, '0', 10);
57 TAIL_ALLOC_OBJECT_CONST_PTR(struct mount_attr, attr);
58 struct mount_attr *const attr_big = tail_alloc(sizeof(*attr_big) + 8);
59 static const struct strval32 valid_flags =
60 { ARG_STR(AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT|AT_EMPTY_PATH|AT_RECURSIVE) };
61 const unsigned int dfd = 9;
62
63 k_mount_setattr(-1, 0, AT_SYMLINK_NOFOLLOW, efault, -1U);
64 #ifndef PATH_TRACING
65 printf("mount_setattr(-1, NULL, %s, %p, %u) = %s\n",
66 "AT_SYMLINK_NOFOLLOW", efault, -1U, rcstr);
67 #endif
68
69 k_mount_setattr(-100, fname, 0, attr, MOUNT_ATTR_SIZE_VER0 - 1);
70 #ifndef PATH_TRACING
71 printf("mount_setattr(AT_FDCWD<%s>, \"%.*s\"..., 0, %p, %u) = %s\n",
72 cwd, (int) PATH_MAX - 1, fname,
73 attr, MOUNT_ATTR_SIZE_VER0 - 1, rcstr);
74 #endif
75
76 fname[PATH_MAX - 1] = '\0';
77 k_mount_setattr(dfd, fname, -1U,
78 1 + (void *) attr, MOUNT_ATTR_SIZE_VER0);
79 printf("mount_setattr(%d<%s>, \"%s\", %s|%#x, %p, %u) = %s\n",
80 dfd, path, fname, valid_flags.str, ~valid_flags.val,
81 1 + (void *) attr, MOUNT_ATTR_SIZE_VER0, rcstr);
82
83 k_mount_setattr(-1, efault, valid_flags.val,
84 1 + (void *) attr, MOUNT_ATTR_SIZE_VER0 - 1);
85 #ifndef PATH_TRACING
86 printf("mount_setattr(-1, %p, %s, %p, %u) = %s\n",
87 efault, valid_flags.str,
88 1 + (void *) attr, MOUNT_ATTR_SIZE_VER0 - 1, rcstr);
89 #endif
90
91 k_mount_setattr(-1, empty, ~valid_flags.val, 0, MOUNT_ATTR_SIZE_VER0);
92 #ifndef PATH_TRACING
93 printf("mount_setattr(-1, \"\", %#x /* AT_??? */, NULL, %u) = %s\n",
94 ~valid_flags.val, MOUNT_ATTR_SIZE_VER0, rcstr);
95 #endif
96
97 static const struct strval64 valid_attr =
98 { ARG_STR(MOUNT_ATTR_RDONLY|MOUNT_ATTR_NOSUID|MOUNT_ATTR_NODEV|MOUNT_ATTR_NOEXEC|MOUNT_ATTR_NOATIME|MOUNT_ATTR_STRICTATIME|MOUNT_ATTR_NODIRATIME|MOUNT_ATTR_IDMAP|MOUNT_ATTR_NOSYMFOLLOW) };
99
100 for (unsigned int j = 0; j < 4; ++j) {
101 struct mount_attr *const a = j > 1 ? attr_big : attr;
102 const size_t size = j ? sizeof(*a) + 8 : sizeof(*a);
103
104 if (j == 3)
105 memset(attr_big + 1, 0, 8);
106 else
107 fill_memory(attr_big + 1, 8);
108
109 a->attr_set = 0xffffffff00000000ULL;
110 a->attr_clr = 0;
111 a->propagation = MS_UNBINDABLE;
112 a->userns_fd = dfd;
113
114 k_mount_setattr(-1, path, 0, a, size);
115 printf("mount_setattr(-1, \"%s\", 0"
116 ", {attr_set=0xffffffff00000000 /* MOUNT_ATTR_??? */"
117 ", attr_clr=0, propagation=%s, userns_fd=%u",
118 path, "MS_UNBINDABLE", dfd);
119 if (j == 1)
120 printf(", ???");
121 if (j == 2) {
122 printf(", /* bytes %zu..%zu */ \"\\x80\\x81"
123 "\\x82\\x83\\x84\\x85\\x86\\x87\"",
124 sizeof(*a), sizeof(*a) + 7);
125 }
126 printf("}, %zu) = %s\n", size, rcstr);
127
128 a->attr_set = valid_attr.val;
129 a->attr_clr = ~valid_attr.val;
130 a->propagation = MS_PRIVATE | MS_SHARED;
131 a->userns_fd = dfd;
132
133 k_mount_setattr(-1, path, 0, a, size);
134 printf("mount_setattr(-1, \"%s\", 0"
135 ", {attr_set=%s, attr_clr=%#llx /* MOUNT_ATTR_??? */"
136 ", propagation=%#x /* MS_??? */, userns_fd=%d<%s>",
137 path, valid_attr.str, (unsigned long long) a->attr_clr,
138 MS_PRIVATE | MS_SHARED, dfd, path);
139 if (j == 1)
140 printf(", ???");
141 if (j == 2) {
142 printf(", /* bytes %zu..%zu */ \"\\x80\\x81"
143 "\\x82\\x83\\x84\\x85\\x86\\x87\"",
144 sizeof(*a), sizeof(*a) + 7);
145 }
146 printf("}, %zu) = %s\n", size, rcstr);
147
148 a->attr_set = MOUNT_ATTR_NOSUID;
149 a->attr_clr = MOUNT_ATTR_NODEV;
150 a->propagation = MS_SLAVE;
151 a->userns_fd = 0xdefaced00000000ULL | dfd;
152
153 k_mount_setattr(dfd, empty, AT_EMPTY_PATH, a, size);
154 printf("mount_setattr(%d<%s>, \"\", %s, {attr_set=%s, attr_clr=%s"
155 ", propagation=%s, userns_fd=%llu",
156 dfd, path, "AT_EMPTY_PATH",
157 "MOUNT_ATTR_NOSUID", "MOUNT_ATTR_NODEV", "MS_SLAVE",
158 (unsigned long long) a->userns_fd);
159 if (j == 1)
160 printf(", ???");
161 if (j == 2) {
162 printf(", /* bytes %zu..%zu */ \"\\x80\\x81"
163 "\\x82\\x83\\x84\\x85\\x86\\x87\"",
164 sizeof(*a), sizeof(*a) + 7);
165 }
166 printf("}, %zu) = %s\n", size, rcstr);
167 }
168
169 puts("+++ exited with 0 +++");
170 return 0;
171 }