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
|
#define _GNU_SOURCE
#define _LARGEFILE64_SOURCE
#include <asm/unistd_32.h>
#include <fcntl.h>
#include <limits.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <sys/types.h>
#include <unistd.h>
#if !defined(__i386__)
#error "Compile this helper with -m32 so it exercises the compat syscall ABI."
#endif
static void
die(const char *msg)
{
perror(msg);
exit(1);
}
static void
must(bool ok, const char *msg)
{
if (!ok)
die(msg);
}
static void
must_eq(long rc, const char *msg)
{
if (rc == -1)
die(msg);
}
static void
write_pid_file(const char *path)
{
FILE *fp = fopen(path, "w");
must(fp != NULL, "fopen pid file");
fprintf(fp, "%ld\n", (long)getpid());
fclose(fp);
}
static void
wait_for_go(const char *path)
{
while (access(path, F_OK) != 0)
usleep(10000);
}
static void
write_full(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t written = write(fd, buf, len);
must_eq(written, "write");
buf += written;
len -= (size_t)written;
}
}
int
main(int argc, char **argv)
{
if (argc != 5) {
fprintf(stderr, "usage: %s PID_FILE GO_FILE BASE_DIR USER\n", argv[0]);
return 2;
}
const char *pid_file = argv[1];
const char *go_file = argv[2];
const char *base = argv[3];
const char *user = argv[4];
struct passwd *pw = getpwnam(user);
must(pw != NULL, "getpwnam");
must(pw->pw_uid <= USHRT_MAX, "uid fits 16-bit compat ABI");
must(pw->pw_gid <= USHRT_MAX, "gid fits 16-bit compat ABI");
write_pid_file(pid_file);
wait_for_go(go_file);
char path_file[1024];
char path_link[1024];
snprintf(path_file, sizeof(path_file), "%s/compat-open.txt", base);
snprintf(path_link, sizeof(path_link), "%s/compat-link.txt", base);
must_eq(mkdir(base, 0777), "mkdir compat base");
int dirfd = open(base, O_RDONLY | O_DIRECTORY);
must_eq(dirfd, "open compat base");
int fd = open(path_file, O_CREAT | O_RDWR | O_TRUNC, 0644);
must_eq(fd, "open compat-open.txt");
write_full(fd, "compat-data", 11);
must_eq(lseek(fd, 0, SEEK_SET), "lseek compat-open.txt");
must_eq(symlink(path_file, path_link), "symlink compat-link.txt");
char dir_buf[4096];
long long llseek_result = 0;
struct statfs64 sfs;
must_eq(syscall(__NR_readdir, dirfd, dir_buf, sizeof(dir_buf)),
"compat readdir");
must_eq(syscall(__NR__llseek, fd, 0UL, 0UL, &llseek_result, SEEK_END),
"compat _llseek");
must_eq(syscall(__NR_statfs64, base, sizeof(sfs), &sfs),
"compat statfs64");
must_eq(syscall(__NR_fstatfs64, fd, sizeof(sfs), &sfs),
"compat fstatfs64");
must_eq(syscall(__NR_chown, path_file, pw->pw_uid, pw->pw_gid),
"compat chown16");
must_eq(syscall(__NR_lchown, path_link, pw->pw_uid, pw->pw_gid),
"compat lchown16");
must_eq(syscall(__NR_fchown, fd, pw->pw_uid, pw->pw_gid),
"compat fchown16");
must_eq(close(fd), "close compat-open.txt");
must_eq(close(dirfd), "close compat base");
return 0;
}
|