Blame


1 2c6298d5 2021-09-24 thomas /*
2 2c6298d5 2021-09-24 thomas * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 2c6298d5 2021-09-24 thomas *
4 2c6298d5 2021-09-24 thomas * Permission to use, copy, modify, and distribute this software for any
5 2c6298d5 2021-09-24 thomas * purpose with or without fee is hereby granted, provided that the above
6 2c6298d5 2021-09-24 thomas * copyright notice and this permission notice appear in all copies.
7 2c6298d5 2021-09-24 thomas *
8 2c6298d5 2021-09-24 thomas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 2c6298d5 2021-09-24 thomas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 2c6298d5 2021-09-24 thomas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 2c6298d5 2021-09-24 thomas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 2c6298d5 2021-09-24 thomas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 2c6298d5 2021-09-24 thomas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 2c6298d5 2021-09-24 thomas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 2c6298d5 2021-09-24 thomas */
16 2c6298d5 2021-09-24 thomas
17 2c6298d5 2021-09-24 thomas /*
18 2c6298d5 2021-09-24 thomas * This an implementation of an OpenBSD' unveil(2) compatible API on
19 2c6298d5 2021-09-24 thomas * top of Linux' landlock.
20 2c6298d5 2021-09-24 thomas */
21 2c6298d5 2021-09-24 thomas
22 2c6298d5 2021-09-24 thomas #include <linux/landlock.h>
23 2c6298d5 2021-09-24 thomas #include <linux/prctl.h>
24 2c6298d5 2021-09-24 thomas
25 2c6298d5 2021-09-24 thomas #include <sys/prctl.h>
26 2c6298d5 2021-09-24 thomas #include <sys/stat.h>
27 2c6298d5 2021-09-24 thomas #include <sys/syscall.h>
28 2c6298d5 2021-09-24 thomas
29 2c6298d5 2021-09-24 thomas #include <errno.h>
30 2c6298d5 2021-09-24 thomas #include <fcntl.h>
31 2c6298d5 2021-09-24 thomas #include <libgen.h>
32 2c6298d5 2021-09-24 thomas #include <limits.h>
33 2c6298d5 2021-09-24 thomas #include <string.h>
34 2c6298d5 2021-09-24 thomas #include <unistd.h>
35 2c6298d5 2021-09-24 thomas
36 2c6298d5 2021-09-24 thomas #include "got_compat.h"
37 2c6298d5 2021-09-24 thomas
38 2c6298d5 2021-09-24 thomas /*
39 2c6298d5 2021-09-24 thomas * What's the deal with landlock? While distro with linux >= 5.13
40 2c6298d5 2021-09-24 thomas * have the struct declarations, libc wrappers are missing. The
41 2c6298d5 2021-09-24 thomas * sample landlock code provided by the authors includes these "shims"
42 2c6298d5 2021-09-24 thomas * in their example for the landlock API until libc provides them.
43 2c6298d5 2021-09-24 thomas */
44 2c6298d5 2021-09-24 thomas
45 2c6298d5 2021-09-24 thomas #ifndef landlock_create_ruleset
46 2c6298d5 2021-09-24 thomas static inline int
47 2c6298d5 2021-09-24 thomas landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size,
48 2c6298d5 2021-09-24 thomas __u32 flags)
49 2c6298d5 2021-09-24 thomas {
50 2c6298d5 2021-09-24 thomas return syscall(__NR_landlock_create_ruleset, attr, size, flags);
51 2c6298d5 2021-09-24 thomas }
52 2c6298d5 2021-09-24 thomas #endif
53 2c6298d5 2021-09-24 thomas
54 2c6298d5 2021-09-24 thomas #ifndef landlock_add_rule
55 2c6298d5 2021-09-24 thomas static inline int
56 2c6298d5 2021-09-24 thomas landlock_add_rule(int ruleset_fd, enum landlock_rule_type type,
57 2c6298d5 2021-09-24 thomas const void *attr, __u32 flags)
58 2c6298d5 2021-09-24 thomas {
59 2c6298d5 2021-09-24 thomas return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags);
60 2c6298d5 2021-09-24 thomas }
61 2c6298d5 2021-09-24 thomas #endif
62 2c6298d5 2021-09-24 thomas
63 2c6298d5 2021-09-24 thomas #ifndef landlock_restrict_self
64 2c6298d5 2021-09-24 thomas static inline int
65 2c6298d5 2021-09-24 thomas landlock_restrict_self(int ruleset_fd, __u32 flags)
66 2c6298d5 2021-09-24 thomas {
67 2c6298d5 2021-09-24 thomas return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
68 2c6298d5 2021-09-24 thomas }
69 2c6298d5 2021-09-24 thomas #endif
70 2c6298d5 2021-09-24 thomas
71 2c6298d5 2021-09-24 thomas static int landlock_fd = -1;
72 2c6298d5 2021-09-24 thomas
73 2c6298d5 2021-09-24 thomas static int
74 2c6298d5 2021-09-24 thomas open_landlock(void)
75 2c6298d5 2021-09-24 thomas {
76 2c6298d5 2021-09-24 thomas struct landlock_ruleset_attr rattr = {
77 2c6298d5 2021-09-24 thomas .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE |
78 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_WRITE_FILE |
79 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_READ_FILE |
80 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_READ_DIR |
81 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_REMOVE_DIR |
82 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_REMOVE_FILE |
83 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_CHAR |
84 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_DIR |
85 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_REG |
86 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_SOCK |
87 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_FIFO |
88 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_BLOCK |
89 2c6298d5 2021-09-24 thomas LANDLOCK_ACCESS_FS_MAKE_SYM,
90 2c6298d5 2021-09-24 thomas };
91 2c6298d5 2021-09-24 thomas
92 2c6298d5 2021-09-24 thomas return landlock_create_ruleset(&rattr, sizeof(rattr), 0);
93 2c6298d5 2021-09-24 thomas }
94 2c6298d5 2021-09-24 thomas
95 2c6298d5 2021-09-24 thomas static int
96 2c6298d5 2021-09-24 thomas landlock_apply(void)
97 2c6298d5 2021-09-24 thomas {
98 2c6298d5 2021-09-24 thomas if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
99 2c6298d5 2021-09-24 thomas return -1;
100 2c6298d5 2021-09-24 thomas
101 2c6298d5 2021-09-24 thomas if (landlock_restrict_self(landlock_fd, 0))
102 2c6298d5 2021-09-24 thomas return -1;
103 2c6298d5 2021-09-24 thomas
104 2c6298d5 2021-09-24 thomas close(landlock_fd);
105 2c6298d5 2021-09-24 thomas landlock_fd = -1;
106 2c6298d5 2021-09-24 thomas return 0;
107 2c6298d5 2021-09-24 thomas }
108 2c6298d5 2021-09-24 thomas
109 2c6298d5 2021-09-24 thomas static int
110 2c6298d5 2021-09-24 thomas parse_permissions(const char *permission)
111 2c6298d5 2021-09-24 thomas {
112 2c6298d5 2021-09-24 thomas int perm = 0;
113 2c6298d5 2021-09-24 thomas
114 2c6298d5 2021-09-24 thomas for (; *permission; ++permission) {
115 2c6298d5 2021-09-24 thomas switch (*permission) {
116 2c6298d5 2021-09-24 thomas case 'r':
117 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_READ_FILE;
118 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_READ_DIR;
119 2c6298d5 2021-09-24 thomas break;
120 2c6298d5 2021-09-24 thomas case 'w':
121 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_WRITE_FILE;
122 2c6298d5 2021-09-24 thomas break;
123 2c6298d5 2021-09-24 thomas case 'x':
124 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_EXECUTE;
125 2c6298d5 2021-09-24 thomas break;
126 2c6298d5 2021-09-24 thomas case 'c':
127 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_REMOVE_DIR;
128 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_REMOVE_FILE;
129 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_CHAR;
130 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_DIR;
131 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_REG;
132 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_SOCK;
133 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_FIFO;
134 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_BLOCK;
135 2c6298d5 2021-09-24 thomas perm |= LANDLOCK_ACCESS_FS_MAKE_SYM;
136 2c6298d5 2021-09-24 thomas break;
137 2c6298d5 2021-09-24 thomas default:
138 2c6298d5 2021-09-24 thomas return -1;
139 2c6298d5 2021-09-24 thomas }
140 2c6298d5 2021-09-24 thomas }
141 2c6298d5 2021-09-24 thomas
142 2c6298d5 2021-09-24 thomas return perm;
143 2c6298d5 2021-09-24 thomas }
144 2c6298d5 2021-09-24 thomas
145 2c6298d5 2021-09-24 thomas static int
146 2c6298d5 2021-09-24 thomas landlock_unveil_path(const char *path, int permissions)
147 2c6298d5 2021-09-24 thomas {
148 2c6298d5 2021-09-24 thomas struct landlock_path_beneath_attr pb;
149 2c6298d5 2021-09-24 thomas struct stat sb;
150 2c6298d5 2021-09-24 thomas int fd, err, saved_errno;
151 2c6298d5 2021-09-24 thomas char fpath[PATH_MAX];
152 2c6298d5 2021-09-24 thomas
153 2c6298d5 2021-09-24 thomas pb.allowed_access = permissions;
154 2c6298d5 2021-09-24 thomas if ((pb.parent_fd = open(path, O_PATH)) == -1)
155 2c6298d5 2021-09-24 thomas return -1;
156 2c6298d5 2021-09-24 thomas
157 2c6298d5 2021-09-24 thomas if (fstat(pb.parent_fd, &sb) == -1)
158 2c6298d5 2021-09-24 thomas return -1;
159 2c6298d5 2021-09-24 thomas
160 2c6298d5 2021-09-24 thomas if (!S_ISDIR(sb.st_mode)) {
161 2c6298d5 2021-09-24 thomas close(pb.parent_fd);
162 2c6298d5 2021-09-24 thomas
163 2c6298d5 2021-09-24 thomas if (strlcpy(fpath, path, sizeof(fpath)) >= sizeof(fpath)) {
164 2c6298d5 2021-09-24 thomas errno = ENAMETOOLONG;
165 2c6298d5 2021-09-24 thomas return -1;
166 2c6298d5 2021-09-24 thomas }
167 2c6298d5 2021-09-24 thomas
168 2c6298d5 2021-09-24 thomas permissions |= LANDLOCK_ACCESS_FS_READ_FILE;
169 2c6298d5 2021-09-24 thomas permissions |= LANDLOCK_ACCESS_FS_READ_DIR;
170 2c6298d5 2021-09-24 thomas return landlock_unveil_path(dirname(fpath), permissions);
171 2c6298d5 2021-09-24 thomas }
172 2c6298d5 2021-09-24 thomas
173 2c6298d5 2021-09-24 thomas err = landlock_add_rule(landlock_fd, LANDLOCK_RULE_PATH_BENEATH,
174 2c6298d5 2021-09-24 thomas &pb, 0);
175 2c6298d5 2021-09-24 thomas saved_errno = errno;
176 2c6298d5 2021-09-24 thomas close(pb.parent_fd);
177 2c6298d5 2021-09-24 thomas errno = saved_errno;
178 2c6298d5 2021-09-24 thomas return err ? -1 : 0;
179 2c6298d5 2021-09-24 thomas }
180 2c6298d5 2021-09-24 thomas
181 2c6298d5 2021-09-24 thomas int
182 2c6298d5 2021-09-24 thomas landlock_unveil(const char *path, const char *permissions)
183 2c6298d5 2021-09-24 thomas {
184 2c6298d5 2021-09-24 thomas int perms;
185 2c6298d5 2021-09-24 thomas
186 2c6298d5 2021-09-24 thomas if (landlock_fd == -1) {
187 2c6298d5 2021-09-24 thomas if ((landlock_fd = open_landlock()) == -1)
188 2c6298d5 2021-09-24 thomas return -1;
189 2c6298d5 2021-09-24 thomas
190 2c6298d5 2021-09-24 thomas /* XXX: use rpath on the current executable */
191 2c6298d5 2021-09-24 thomas if (landlock_unveil("/lib64", "rx") == -1)
192 2c6298d5 2021-09-24 thomas return -1;
193 2c6298d5 2021-09-24 thomas }
194 2c6298d5 2021-09-24 thomas
195 2c6298d5 2021-09-24 thomas if (path == NULL && permissions == NULL)
196 2c6298d5 2021-09-24 thomas return landlock_apply();
197 2c6298d5 2021-09-24 thomas
198 2c6298d5 2021-09-24 thomas if (path == NULL ||
199 2c6298d5 2021-09-24 thomas permissions == NULL ||
200 2c6298d5 2021-09-24 thomas (perms = parse_permissions(permissions)) == -1) {
201 2c6298d5 2021-09-24 thomas errno = EINVAL;
202 2c6298d5 2021-09-24 thomas return -1;
203 2c6298d5 2021-09-24 thomas }
204 2c6298d5 2021-09-24 thomas
205 2c6298d5 2021-09-24 thomas return landlock_unveil_path(path, perms);
206 2c6298d5 2021-09-24 thomas }
207 2c6298d5 2021-09-24 thomas
208 2c6298d5 2021-09-24 thomas int
209 2c6298d5 2021-09-24 thomas landlock_no_fs(void)
210 2c6298d5 2021-09-24 thomas {
211 2c6298d5 2021-09-24 thomas if ((landlock_fd = open_landlock()) == -1)
212 2c6298d5 2021-09-24 thomas return -1;
213 2c6298d5 2021-09-24 thomas
214 2c6298d5 2021-09-24 thomas return landlock_apply();
215 2c6298d5 2021-09-24 thomas }