1 /*
2 * Check decoding of fchmodat2 syscall.
3 *
4 * Copyright (c) 2016-2023 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 #include "secontext.h"
13
14 #include <fcntl.h>
15 #include <stdio.h>
16 #include <unistd.h>
17
18 #ifndef AT_SYMLINK_NOFOLLOW
19 # define AT_SYMLINK_NOFOLLOW 0x100
20 #endif
21 #ifndef AT_EMPTY_PATH
22 # define AT_EMPTY_PATH 0x1000
23 #endif
24
25 static const char *errstr;
26
27 static long
28 k_fchmodat2(const unsigned int dfd, const void *path,
29 const unsigned short mode, const unsigned int flags)
30 {
31 const kernel_ulong_t fill = (kernel_ulong_t) 0xbadc0ded00000000ULL;
32 const kernel_ulong_t fill_short = fill | 0xdead0000ULL;
33 const kernel_ulong_t arg1 = fill | dfd;
34 const kernel_ulong_t arg2 = (uintptr_t) path;
35 const kernel_ulong_t arg3 = fill_short | mode;
36 const kernel_ulong_t arg4 = fill | flags;
37 const kernel_ulong_t arg5 = fill | 0xdecaffed;
38 const kernel_ulong_t arg6 = fill | 0xdeefaced;
39 const long rc = syscall(__NR_fchmodat2,
40 arg1, arg2, arg3, arg4, arg5, arg6);
41 errstr = sprintrc(rc);
42 return rc;
43 }
44
45 int
46 main(void)
47 {
48 /*
49 * Make sure the current workdir of the tracee
50 * is different from the current workdir of the tracer.
51 */
52 create_and_enter_subdir("fchmodat2_subdir");
53
54 char *my_secontext = SECONTEXT_PID_MY();
55
56 static const char sample[] = "fchmodat2_sample_file";
57 if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
58 perror_msg_and_fail("open");
59
60 char *sample_secontext = SECONTEXT_FILE(sample);
61
62 /*
63 * Tests with AT_FDCWD.
64 */
65
66 k_fchmodat2(-100, sample, 0600, 0);
67 printf("%s%s(%s, \"%s\"%s, 0600, 0) = %s\n",
68 my_secontext, "fchmodat2", "AT_FDCWD",
69 sample, sample_secontext, errstr);
70
71 if (unlink(sample))
72 perror_msg_and_fail("unlink");
73
74 k_fchmodat2(-100, sample, 051, AT_SYMLINK_NOFOLLOW);
75 printf("%s%s(%s, \"%s\", 051, AT_SYMLINK_NOFOLLOW) = %s\n",
76 my_secontext, "fchmodat2", "AT_FDCWD", sample, errstr);
77
78 k_fchmodat2(-100, sample, 0700, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH);
79 printf("%s%s(%s, \"%s\", 0700, AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH)"
80 " = %s\n",
81 my_secontext, "fchmodat2", "AT_FDCWD", sample, errstr);
82
83 k_fchmodat2(-100, sample, 004,
84 -1U & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH));
85 printf("%s%s(%s, \"%s\", 004, 0xffffeeff /* AT_??? */) = %s\n",
86 my_secontext, "fchmodat2", "AT_FDCWD", sample, errstr);
87
88 /*
89 * Tests with dirfd.
90 */
91
92 int cwd_fd = get_dir_fd(".");
93 char *cwd = get_fd_path(cwd_fd);
94 char *cwd_secontext = SECONTEXT_FILE(".");
95 char *sample_realpath = xasprintf("%s/%s", cwd, sample);
96
97 /* no file */
98 k_fchmodat2(cwd_fd, sample, 0400, 0);
99 printf("%s%s(%d%s, \"%s\", 0400, 0) = %s\n",
100 my_secontext, "fchmodat2",
101 cwd_fd, cwd_secontext, sample, errstr);
102
103 if (open(sample, O_RDONLY | O_CREAT, 0400) < 0)
104 perror_msg_and_fail("open");
105
106 k_fchmodat2(cwd_fd, sample, 0400, AT_SYMLINK_NOFOLLOW);
107 printf("%s%s(%d%s, \"%s\"%s, 0400, AT_SYMLINK_NOFOLLOW) = %s\n",
108 my_secontext, "fchmodat2",
109 cwd_fd, cwd_secontext, sample, sample_secontext, errstr);
110
111 /* cwd_fd ignored when path is absolute */
112 if (chdir("../.."))
113 perror_msg_and_fail("chdir");
114
115 k_fchmodat2(cwd_fd, sample_realpath, 0700, AT_EMPTY_PATH);
116 printf("%s%s(%d%s, \"%s\"%s, 0700, AT_EMPTY_PATH) = %s\n",
117 my_secontext, "fchmodat2",
118 cwd_fd, cwd_secontext,
119 sample_realpath, sample_secontext, errstr);
120
121 if (fchdir(cwd_fd))
122 perror_msg_and_fail("fchdir");
123
124 if (unlink(sample))
125 perror_msg_and_fail("unlink");
126
127 leave_and_remove_subdir();
128
129 puts("+++ exited with 0 +++");
130 return 0;
131 }