this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement vchroot in userspace

+437 -2
+1 -1
src/kernel/emulation/linux/CMakeLists.txt
··· 277 277 psynch/ulock_wake.c 278 278 conf/pathconf.c 279 279 conf/fpathconf.c 280 - vchroot_expand.c 280 + vchroot_userspace.c 281 281 syscalls-table.S 282 282 linux-syscall.S 283 283 )
+2 -1
src/kernel/emulation/linux/fdpath.c
··· 10 10 .maxlen = bufsiz 11 11 }; 12 12 13 - return lkm_call(NR_vchroot_fdpath, &args); 13 + // return lkm_call(NR_vchroot_fdpath, &args); 14 + return vchroot_fdpath(&args); 14 15 } 15 16
+434
src/kernel/emulation/linux/vchroot_userspace.c
··· 1 + 2 + #include <lkm/api.h> 3 + #ifdef TEST 4 + # include <unistd.h> 5 + # include <sys/stat.h> 6 + # include <sys/syscall.h> 7 + # include <stdio.h> 8 + # include <stdbool.h> 9 + # include <stdlib.h> 10 + # include <string.h> 11 + # include <errno.h> 12 + # include <dirent.h> 13 + # include <fcntl.h> 14 + 15 + # define LINUX_SYSCALL(...) ({ int __rv = syscall(__VA_ARGS__); if (__rv == -1) __rv = -errno; __rv; }) 16 + # define LINUX_ENOENT ENOENT 17 + # define LINUX_ELOOP ELOOP 18 + # define LINUX_ENAMETOOLONG ENAMETOOLONG 19 + 20 + # define LINUX_S_IFMT S_IFMT 21 + # define LINUX_S_IFLNK S_IFLNK 22 + 23 + # define LINUX_O_RDONLY O_RDONLY 24 + 25 + # define __simple_sprintf sprintf 26 + # define linux_dirent64 dirent 27 + typedef struct stat stat_t; 28 + #else 29 + # include "base.h" 30 + # include <mach/lkm.h> 31 + # include <linux-syscalls/linux.h> 32 + # include <fcntl/open.h> 33 + # include "simple.h" 34 + # include <stdbool.h> 35 + # include "errno.h" 36 + # include "duct_errno.h" 37 + # include "stat/common.h" 38 + # include "dirent/getdirentries.h" 39 + typedef struct linux_stat stat_t; 40 + 41 + extern __SIZE_TYPE__ strlen(const char* s); 42 + extern char* strcpy(char* dest, const char* src); 43 + extern int strcmp(const char* str1, const char* str2); 44 + extern int strncmp(const char* str1, const char* str2, __SIZE_TYPE__ n); 45 + extern int strncasecmp(const char* str1, const char* str2, __SIZE_TYPE__ n); 46 + extern int strcasecmp(const char* str1, const char* str2); 47 + extern void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n); 48 + 49 + #define LINUX_S_IFMT 00170000 50 + #define LINUX_S_IFLNK 0120000 51 + 52 + #define __simple_printf(...) 53 + 54 + #endif 55 + 56 + static bool next_component(const char* from, const char** end); 57 + 58 + static char prefix_path[4096] = {0}; // MUST NOT end with '/' 59 + static int prefix_path_len = -1; 60 + 61 + static const char EXIT_PATH[] = "/Volumes/SystemRoot"; 62 + static bool icase_enabled = false; 63 + static const int MAX_SYMLINK_DEPTH = 10; 64 + 65 + struct context 66 + { 67 + const char* current_root; 68 + int current_root_len; 69 + 70 + char current_path[4096]; 71 + int current_path_len; 72 + 73 + int symlink_depth; 74 + bool unknown_component; 75 + }; 76 + 77 + static int vchroot_run(const char* path, struct context* ctxt); 78 + 79 + #ifndef TEST 80 + VISIBLE 81 + #endif 82 + int __darling_vchroot(int dfd) 83 + { 84 + int rv; 85 + 86 + #ifndef TEST 87 + rv = lkm_call(NR_vchroot, dfd); 88 + if (rv != 0) 89 + return rv; 90 + #endif 91 + 92 + char buf[50]; 93 + 94 + __simple_sprintf(buf, "/proc/self/fd/%d", dfd); 95 + 96 + rv = LINUX_SYSCALL(__NR_readlink, buf, prefix_path, sizeof(prefix_path) - 1); 97 + prefix_path[rv] = '\0'; 98 + prefix_path_len = rv; 99 + 100 + return 0; 101 + } 102 + 103 + static void init_vchroot_path(void) 104 + { 105 + struct vchroot_expand_args a = { 106 + .path = "/", 107 + .dfd = -100, 108 + .flags = 0 109 + }; 110 + 111 + lkm_call(NR_vchroot_expand, &a); 112 + 113 + int len = strlen(a.path); 114 + if (len > 0 && a.path[len-1] == '/') 115 + a.path[--len] = '\0'; 116 + 117 + strcpy(prefix_path, a.path); 118 + prefix_path_len = len; 119 + 120 + #ifndef TEST 121 + __simple_printf("init_vchroot_path: %s\n", prefix_path); 122 + #endif 123 + } 124 + 125 + int vchroot_expand(struct vchroot_expand_args* args) 126 + { 127 + struct context ctxt; 128 + 129 + #ifndef TEST 130 + if (prefix_path_len == -1) 131 + init_vchroot_path(); 132 + __simple_printf("vchroot_expand(): input %s\n", args->path); 133 + #endif 134 + 135 + ctxt.unknown_component = false; 136 + ctxt.symlink_depth = 0; 137 + ctxt.current_root = prefix_path; 138 + ctxt.current_root_len = prefix_path_len; 139 + 140 + const char* input_path = args->path; 141 + 142 + if (*input_path != '/') 143 + { 144 + char buf[50]; 145 + 146 + if (args->dfd != -100) 147 + __simple_sprintf(buf, "/proc/self/fd/%d", args->dfd); 148 + else 149 + strcpy(buf, "/proc/self/cwd"); 150 + 151 + int rv = LINUX_SYSCALL(__NR_readlink, buf, ctxt.current_path, sizeof(ctxt.current_path) - 1); 152 + 153 + if (rv < 0) 154 + { 155 + #ifndef TEST 156 + __simple_printf(" dfd %d -> err %d!\n", args->dfd, rv); 157 + #endif 158 + return rv; 159 + } 160 + 161 + ctxt.current_path_len = rv; 162 + ctxt.current_path[rv] = '\0'; 163 + } 164 + 165 + int rv = vchroot_run(input_path, &ctxt); 166 + if (ctxt.current_path_len > 0) 167 + strcpy(args->path, ctxt.current_path); 168 + else 169 + strcpy(args->path, "/"); 170 + 171 + #ifndef TEST 172 + __simple_printf(" vchroot_expand(): rv=%d, expanded to %s\n", rv, args->path); 173 + #endif 174 + 175 + return rv; 176 + } 177 + 178 + static int vchroot_run(const char* input_path, struct context* ctxt) 179 + { 180 + if (ctxt->symlink_depth > MAX_SYMLINK_DEPTH) 181 + return -LINUX_ELOOP; 182 + 183 + if (*input_path == '/') 184 + { 185 + strcpy(ctxt->current_path, ctxt->current_root); 186 + ctxt->current_path_len = strlen(ctxt->current_path); 187 + input_path++; 188 + } 189 + 190 + const char* end; 191 + while (next_component(input_path, &end)) 192 + { 193 + const unsigned int len = end - input_path; 194 + 195 + if ((len == 1 && input_path[0] == '.') || len == 0) // . or nothing (//) 196 + { 197 + // nothing to do 198 + } 199 + else 200 + { 201 + // append / 202 + ctxt->current_path[ctxt->current_path_len++] = '/'; 203 + ctxt->current_path[ctxt->current_path_len] = '\0'; 204 + 205 + if (len == 2 && input_path[0] == '.' && input_path[1] == '.') // .. 206 + { 207 + if (ctxt->current_path_len <= 1) 208 + return -LINUX_ENOENT; 209 + 210 + // current_path always ends with a slash 211 + // p points before the last / 212 + char* p = ctxt->current_path + ctxt->current_path_len - 2; 213 + 214 + while (true) 215 + { 216 + if (*p == '/') 217 + { 218 + *p = '\0'; 219 + ctxt->current_path_len = p - ctxt->current_path; 220 + 221 + // We cannot exit current_root via .. 222 + if (ctxt->current_path_len < ctxt->current_root_len) 223 + return -LINUX_ENOENT; 224 + break; 225 + } 226 + p--; 227 + } 228 + } 229 + else 230 + { 231 + if (len + ctxt->current_path_len + 2 > sizeof(ctxt->current_path)) 232 + return -LINUX_ENOENT; 233 + 234 + // Append the component 235 + const int prevlen = ctxt->current_path_len; 236 + 237 + memcpy(ctxt->current_path + ctxt->current_path_len, input_path, len); 238 + ctxt->current_path_len += len; 239 + ctxt->current_path[ctxt->current_path_len] = '\0'; 240 + 241 + // Only analyze the last path component if we haven't had an unresolvent ENOENT before 242 + if (!ctxt->unknown_component) 243 + { 244 + stat_t st; 245 + int status = LINUX_SYSCALL(__NR_lstat, ctxt->current_path, &st); 246 + 247 + if (icase_enabled && status == -LINUX_ENOENT) 248 + { 249 + // Case insensitive search 250 + 251 + // Examine the directory above 252 + ctxt->current_path[prevlen-1] = '\0'; 253 + 254 + int dfd = LINUX_SYSCALL(__NR_open, (prevlen > 1) ? ctxt->current_path : "/", LINUX_O_RDONLY); 255 + char dirents[4096]; // buffer space for struct linux_dirent64 entries 256 + int len; 257 + 258 + if (dfd < 0) 259 + return dfd; 260 + 261 + // Get a batch of directory entries 262 + while ((len = LINUX_SYSCALL(__NR_getdents64, dfd, dirents, sizeof(dirents))) > 0) 263 + { 264 + int pos = 0; 265 + 266 + // Iterate through directory entries 267 + while (pos < len) 268 + { 269 + struct linux_dirent64* de = (struct linux_dirent64*) &dirents[pos]; 270 + if (strcasecmp(de->d_name, ctxt->current_path + prevlen) == 0) 271 + { 272 + // Fix up the case and be done with it 273 + strcpy(ctxt->current_path + prevlen, de->d_name); 274 + goto done_getdents; 275 + } 276 + pos += de->d_reclen; 277 + } 278 + } 279 + ctxt->unknown_component = true; 280 + done_getdents: 281 + // Restore the / we removed a few lines above 282 + ctxt->current_path[prevlen-1] = '/'; 283 + LINUX_SYSCALL(__NR_close, dfd); 284 + } 285 + else if ((st.st_mode & LINUX_S_IFMT) == LINUX_S_IFLNK) 286 + { 287 + char link[512]; 288 + int rv; 289 + 290 + rv = LINUX_SYSCALL(__NR_readlink, ctxt->current_path, link, sizeof(link) - 1); 291 + 292 + if (rv < 0) 293 + return rv; 294 + 295 + link[rv] = '\0'; 296 + 297 + // Remove the last component (because it will be substituted with symlink contents) 298 + if (link[0] != '/') // Only bother to do that if we know that the symlink is not absolute 299 + { 300 + ctxt->current_path_len = prevlen - 1; // kill the last slash as well 301 + ctxt->current_path[ctxt->current_path_len] = '\0'; 302 + } 303 + 304 + // Symbolic link resolution 305 + ctxt->symlink_depth++; 306 + rv = vchroot_run(link, ctxt); 307 + ctxt->symlink_depth--; 308 + 309 + if (rv != 0) 310 + return rv; 311 + } 312 + } 313 + 314 + if (ctxt->current_root_len > 0 && ctxt->current_path_len - ctxt->current_root_len == sizeof(EXIT_PATH)-1) 315 + { 316 + if (strncasecmp(ctxt->current_path + ctxt->current_root_len, EXIT_PATH, sizeof(EXIT_PATH) - 1) == 0) 317 + { 318 + // Switch to the real system root 319 + ctxt->current_path[0] = '\0'; 320 + ctxt->current_path_len = 0; 321 + ctxt->current_root = ""; 322 + ctxt->current_root_len = 0; 323 + } 324 + } 325 + } 326 + } 327 + 328 + // Move on to the next component 329 + input_path = end; 330 + while (*input_path == '/') 331 + input_path++; 332 + } 333 + 334 + return 0; 335 + } 336 + 337 + static bool next_component(const char* from, const char** end) 338 + { 339 + const char* pos = from; 340 + while (*pos != '/' && *pos) 341 + pos++; 342 + *end = pos; 343 + return pos != from; 344 + } 345 + 346 + int vchroot_fdpath(struct vchroot_fdpath_args* args) 347 + { 348 + #ifndef TEST 349 + if (prefix_path_len == -1) 350 + init_vchroot_path(); 351 + #endif 352 + 353 + char buf[50]; 354 + char link[4096]; 355 + 356 + __simple_sprintf(buf, "/proc/self/fd/%d", args->fd); 357 + 358 + int rv = LINUX_SYSCALL(__NR_readlink, buf, link, sizeof(link) - 1); 359 + if (rv < 0) 360 + return rv; 361 + 362 + link[rv] = '\0'; 363 + 364 + if (rv >= prefix_path_len && strncmp(link, prefix_path, prefix_path_len) == 0) 365 + { 366 + if (args->maxlen-1 < rv - prefix_path_len) 367 + return -LINUX_ENAMETOOLONG; 368 + strcpy(args->path, link + prefix_path_len); 369 + 370 + if (args->path[0] == '\0') 371 + strcpy(args->path, "/"); 372 + } 373 + else 374 + { 375 + if (args->maxlen < sizeof(EXIT_PATH) + rv) 376 + return -LINUX_ENAMETOOLONG; 377 + 378 + memcpy(args->path, EXIT_PATH, sizeof(EXIT_PATH) - 1); 379 + memcpy(args->path + sizeof(EXIT_PATH) - 1, link, rv+1); 380 + } 381 + 382 + #ifndef TEST 383 + __simple_printf("fdpath %d -> %s\n", args->fd, args->path); 384 + #endif 385 + 386 + return 0; 387 + } 388 + 389 + #ifdef TEST 390 + int main(int argc, const char** argv) 391 + { 392 + if (argc != 3) 393 + { 394 + printf("Usage: vchroot_expand <vchroot_dir> <path_to_expand>\n"); 395 + return 1; 396 + } 397 + 398 + int dfd = open(argv[1], O_RDONLY | O_DIRECTORY); 399 + __darling_vchroot(dfd); 400 + close(dfd); 401 + 402 + if (getenv("ICASE")) 403 + icase_enabled = true; 404 + 405 + struct vchroot_expand_args args; 406 + strcpy(args.path, argv[2]); 407 + 408 + int rv = vchroot_expand(&args); 409 + printf("vchroot_expand() rv = %d\n", rv); 410 + printf("-> path = %s\n", args.path); 411 + 412 + if (rv == 0) 413 + { 414 + int fd = open(args.path, O_RDONLY); 415 + struct vchroot_fdpath_args fdpath_args; 416 + char buf[4096]; 417 + 418 + fdpath_args.path = buf; 419 + fdpath_args.maxlen = sizeof(buf); 420 + fdpath_args.fd = fd; 421 + 422 + rv = vchroot_fdpath(&fdpath_args); 423 + 424 + printf("vchroot_fdpath() rv = %d\n", rv); 425 + if (rv >= 0) 426 + printf("-> path = %s\n", buf); 427 + 428 + close(fd); 429 + } 430 + 431 + return 0; 432 + } 433 + #endif 434 +