comparison mrjunejune/latex_renderer.c @ 248:b8b6e726964a

[style] Use Dowa type aliases in C Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Tue, 04 Aug 2026 02:44:06 -0700
parents 70f2a3dafc1c
children
comparison
equal deleted inserted replaced
247:70f2a3dafc1c 248:b8b6e726964a
10 #include <linux/landlock.h> 10 #include <linux/landlock.h>
11 #include <linux/seccomp.h> 11 #include <linux/seccomp.h>
12 #include <limits.h> 12 #include <limits.h>
13 #include <poll.h> 13 #include <poll.h>
14 #include <signal.h> 14 #include <signal.h>
15 #include <stdbool.h>
16 #include <stddef.h> 15 #include <stddef.h>
17 #include <stdio.h> 16 #include <stdio.h>
18 #include <stdlib.h> 17 #include <stdlib.h>
19 #include <string.h> 18 #include <string.h>
20 #include <sys/prctl.h> 19 #include <sys/prctl.h>
66 .status = status, 65 .status = status,
67 .diagnostics = duplicate_message(message), 66 .diagnostics = duplicate_message(message),
68 }; 67 };
69 } 68 }
70 69
71 static bool write_all(int fd, const uint8_t *data, size_t size) 70 static boolean write_all(int fd, const uint8 *data, size_t size)
72 { 71 {
73 while (size > 0) 72 while (size > 0)
74 { 73 {
75 ssize_t written = write(fd, data, size); 74 ssize_t written = write(fd, data, size);
76 if (written < 0) 75 if (written < 0)
77 { 76 {
78 if (errno == EINTR) 77 if (errno == EINTR)
79 continue; 78 continue;
80 return false; 79 return FALSE;
81 } 80 }
82 data += written; 81 data += written;
83 size -= (size_t)written; 82 size -= (size_t)written;
84 } 83 }
85 return true; 84 return TRUE;
86 } 85 }
87 86
88 static int remove_tree(const char *path, unsigned depth) 87 static int remove_tree(const char *path, unsigned depth)
89 { 88 {
90 if (depth > 16) 89 if (depth > 16)
125 } 124 }
126 closedir(directory); 125 closedir(directory);
127 return result == 0 ? rmdir(path) : result; 126 return result == 0 ? rmdir(path) : result;
128 } 127 }
129 128
130 static bool set_limit(int resource, rlim_t value) 129 static boolean set_limit(int resource, rlim_t value)
131 { 130 {
132 struct rlimit limit = { 131 struct rlimit limit = {
133 .rlim_cur = value, 132 .rlim_cur = value,
134 .rlim_max = value, 133 .rlim_max = value,
135 }; 134 };
136 return setrlimit(resource, &limit) == 0; 135 return setrlimit(resource, &limit) == 0;
137 } 136 }
138 137
139 static bool add_landlock_path_rule( 138 static boolean add_landlock_path_rule(
140 int ruleset_fd, 139 int ruleset_fd,
141 const char *path, 140 const char *path,
142 uint64_t access, 141 uint64 access,
143 bool required) 142 boolean required)
144 { 143 {
145 int path_fd = open(path, O_PATH | O_CLOEXEC); 144 int path_fd = open(path, O_PATH | O_CLOEXEC);
146 if (path_fd < 0) 145 if (path_fd < 0)
147 return !required && errno == ENOENT; 146 return !required && errno == ENOENT;
148 147
149 struct stat status; 148 struct stat status;
150 bool ok = fstat(path_fd, &status) == 0; 149 boolean ok = fstat(path_fd, &status) == 0;
151 if (ok && !S_ISDIR(status.st_mode)) 150 if (ok && !S_ISDIR(status.st_mode))
152 { 151 {
153 access &= LANDLOCK_ACCESS_FS_EXECUTE | 152 access &= LANDLOCK_ACCESS_FS_EXECUTE |
154 LANDLOCK_ACCESS_FS_READ_FILE | 153 LANDLOCK_ACCESS_FS_READ_FILE |
155 LANDLOCK_ACCESS_FS_WRITE_FILE; 154 LANDLOCK_ACCESS_FS_WRITE_FILE;
168 0) == 0; 167 0) == 0;
169 close(path_fd); 168 close(path_fd);
170 return ok; 169 return ok;
171 } 170 }
172 171
173 static bool add_landlock_tree_rules( 172 static boolean add_landlock_tree_rules(
174 int ruleset_fd, 173 int ruleset_fd,
175 const char *path, 174 const char *path,
176 uint64_t access, 175 uint64 access,
177 unsigned depth) 176 unsigned depth)
178 { 177 {
179 if (depth > 32 || 178 if (depth > 32 ||
180 !add_landlock_path_rule(ruleset_fd, path, access, true)) 179 !add_landlock_path_rule(ruleset_fd, path, access, TRUE))
181 return false; 180 return FALSE;
182 181
183 struct stat status; 182 struct stat status;
184 if (lstat(path, &status) != 0) 183 if (lstat(path, &status) != 0)
185 return false; 184 return FALSE;
186 if (!S_ISDIR(status.st_mode)) 185 if (!S_ISDIR(status.st_mode))
187 return true; 186 return TRUE;
188 187
189 DIR *directory = opendir(path); 188 DIR *directory = opendir(path);
190 if (!directory) 189 if (!directory)
191 return false; 190 return FALSE;
192 bool ok = true; 191 boolean ok = TRUE;
193 struct dirent *entry; 192 struct dirent *entry;
194 while (ok && (entry = readdir(directory)) != NULL) 193 while (ok && (entry = readdir(directory)) != NULL)
195 { 194 {
196 if (strcmp(entry->d_name, ".") == 0 || 195 if (strcmp(entry->d_name, ".") == 0 ||
197 strcmp(entry->d_name, "..") == 0) 196 strcmp(entry->d_name, "..") == 0)
213 } 212 }
214 closedir(directory); 213 closedir(directory);
215 return ok; 214 return ok;
216 } 215 }
217 216
218 static bool apply_filesystem_sandbox( 217 static boolean apply_filesystem_sandbox(
219 const char *job_directory, 218 const char *job_directory,
220 const char *compiler, 219 const char *compiler,
221 const char *cache_directory, 220 const char *cache_directory,
222 const char *fontconfig_sysroot) 221 const char *fontconfig_sysroot)
223 { 222 {
225 SYS_landlock_create_ruleset, 224 SYS_landlock_create_ruleset,
226 NULL, 225 NULL,
227 0, 226 0,
228 LANDLOCK_CREATE_RULESET_VERSION); 227 LANDLOCK_CREATE_RULESET_VERSION);
229 if (abi < 1) 228 if (abi < 1)
230 return false; 229 return FALSE;
231 230
232 uint64_t read_access = 231 uint64 read_access =
233 LANDLOCK_ACCESS_FS_EXECUTE | 232 LANDLOCK_ACCESS_FS_EXECUTE |
234 LANDLOCK_ACCESS_FS_READ_FILE | 233 LANDLOCK_ACCESS_FS_READ_FILE |
235 LANDLOCK_ACCESS_FS_READ_DIR; 234 LANDLOCK_ACCESS_FS_READ_DIR;
236 uint64_t write_access = 235 uint64 write_access =
237 LANDLOCK_ACCESS_FS_WRITE_FILE | 236 LANDLOCK_ACCESS_FS_WRITE_FILE |
238 LANDLOCK_ACCESS_FS_REMOVE_DIR | 237 LANDLOCK_ACCESS_FS_REMOVE_DIR |
239 LANDLOCK_ACCESS_FS_REMOVE_FILE | 238 LANDLOCK_ACCESS_FS_REMOVE_FILE |
240 LANDLOCK_ACCESS_FS_MAKE_CHAR | 239 LANDLOCK_ACCESS_FS_MAKE_CHAR |
241 LANDLOCK_ACCESS_FS_MAKE_DIR | 240 LANDLOCK_ACCESS_FS_MAKE_DIR |
256 SYS_landlock_create_ruleset, 255 SYS_landlock_create_ruleset,
257 &ruleset, 256 &ruleset,
258 sizeof(ruleset), 257 sizeof(ruleset),
259 0); 258 0);
260 if (ruleset_fd < 0) 259 if (ruleset_fd < 0)
261 return false; 260 return FALSE;
262 261
263 bool ok = true; 262 boolean ok = TRUE;
264 if (ok) 263 if (ok)
265 ok = add_landlock_path_rule( 264 ok = add_landlock_path_rule(
266 ruleset_fd, 265 ruleset_fd,
267 compiler, 266 compiler,
268 LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE, 267 LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE,
269 true); 268 TRUE);
270 if (ok) 269 if (ok)
271 ok = add_landlock_tree_rules( 270 ok = add_landlock_tree_rules(
272 ruleset_fd, 271 ruleset_fd,
273 cache_directory, 272 cache_directory,
274 read_access | LANDLOCK_ACCESS_FS_MAKE_DIR, 273 read_access | LANDLOCK_ACCESS_FS_MAKE_DIR,
282 if (ok) 281 if (ok)
283 ok = add_landlock_path_rule( 282 ok = add_landlock_path_rule(
284 ruleset_fd, 283 ruleset_fd,
285 "/dev/null", 284 "/dev/null",
286 LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE, 285 LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_WRITE_FILE,
287 true); 286 TRUE);
288 if (ok) 287 if (ok)
289 ok = add_landlock_path_rule( 288 ok = add_landlock_path_rule(
290 ruleset_fd, 289 ruleset_fd,
291 "/dev/urandom", 290 "/dev/urandom",
292 LANDLOCK_ACCESS_FS_READ_FILE, 291 LANDLOCK_ACCESS_FS_READ_FILE,
293 false); 292 FALSE);
294 if (ok) 293 if (ok)
295 ok = add_landlock_path_rule( 294 ok = add_landlock_path_rule(
296 ruleset_fd, 295 ruleset_fd,
297 job_directory, 296 job_directory,
298 read_access | write_access, 297 read_access | write_access,
299 true); 298 TRUE);
300 if (ok) 299 if (ok)
301 ok = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0; 300 ok = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == 0;
302 if (ok) 301 if (ok)
303 ok = syscall( 302 ok = syscall(
304 SYS_landlock_restrict_self, 303 SYS_landlock_restrict_self,
306 0) == 0; 305 0) == 0;
307 close(ruleset_fd); 306 close(ruleset_fd);
308 return ok; 307 return ok;
309 } 308 }
310 309
311 static bool apply_network_sandbox(void) 310 static boolean apply_network_sandbox(void)
312 { 311 {
313 if (LATEX_AUDIT_ARCH == 0) 312 if (LATEX_AUDIT_ARCH == 0)
314 return false; 313 return FALSE;
315 314
316 struct sock_filter filters[64]; 315 struct sock_filter filters[64];
317 size_t count = 0; 316 size_t count = 0;
318 #define ADD_FILTER(value) filters[count++] = (struct sock_filter)value 317 #define ADD_FILTER(value) filters[count++] = (struct sock_filter)value
319 #define DENY_SYSCALL(number) \ 318 #define DENY_SYSCALL(number) \
467 static int wait_for_compiler( 466 static int wait_for_compiler(
468 pid_t child, 467 pid_t child,
469 int output_fd, 468 int output_fd,
470 char *diagnostics, 469 char *diagnostics,
471 size_t diagnostics_size, 470 size_t diagnostics_size,
472 bool *timed_out) 471 boolean *timed_out)
473 { 472 {
474 int flags = fcntl(output_fd, F_GETFL, 0); 473 int flags = fcntl(output_fd, F_GETFL, 0);
475 if (flags >= 0) 474 if (flags >= 0)
476 fcntl(output_fd, F_SETFL, flags | O_NONBLOCK); 475 fcntl(output_fd, F_SETFL, flags | O_NONBLOCK);
477 476
478 size_t used = 0; 477 size_t used = 0;
479 int child_status = 0; 478 int child_status = 0;
480 bool child_done = false; 479 boolean child_done = FALSE;
481 struct timespec start; 480 struct timespec start;
482 clock_gettime(CLOCK_MONOTONIC, &start); 481 clock_gettime(CLOCK_MONOTONIC, &start);
483 482
484 while (!child_done) 483 while (!child_done)
485 { 484 {
497 } 496 }
498 497
499 pid_t waited = waitpid(child, &child_status, WNOHANG); 498 pid_t waited = waitpid(child, &child_status, WNOHANG);
500 if (waited == child) 499 if (waited == child)
501 { 500 {
502 child_done = true; 501 child_done = TRUE;
503 break; 502 break;
504 } 503 }
505 if (waited < 0 && errno != EINTR) 504 if (waited < 0 && errno != EINTR)
506 break; 505 break;
507 506
508 struct timespec now; 507 struct timespec now;
509 clock_gettime(CLOCK_MONOTONIC, &now); 508 clock_gettime(CLOCK_MONOTONIC, &now);
510 if (elapsed_seconds(&start, &now) >= LATEX_WALL_TIMEOUT_SECONDS) 509 if (elapsed_seconds(&start, &now) >= LATEX_WALL_TIMEOUT_SECONDS)
511 { 510 {
512 *timed_out = true; 511 *timed_out = TRUE;
513 kill(-child, SIGKILL); 512 kill(-child, SIGKILL);
514 while (waitpid(child, &child_status, 0) < 0 && errno == EINTR) 513 while (waitpid(child, &child_status, 0) < 0 && errno == EINTR)
515 { 514 {
516 } 515 }
517 child_done = true; 516 child_done = TRUE;
518 break; 517 break;
519 } 518 }
520 519
521 struct pollfd poll_fd = { 520 struct pollfd poll_fd = {
522 .fd = output_fd, 521 .fd = output_fd,
540 diagnostics[used] = '\0'; 539 diagnostics[used] = '\0';
541 kill(-child, SIGKILL); 540 kill(-child, SIGKILL);
542 return child_status; 541 return child_status;
543 } 542 }
544 543
545 static bool read_pdf( 544 static boolean read_pdf(
546 const char *path, 545 const char *path,
547 uint8_t **data, 546 uint8 **data,
548 size_t *size) 547 size_t *size)
549 { 548 {
550 int fd = open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); 549 int fd = open(path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
551 if (fd < 0) 550 if (fd < 0)
552 return false; 551 return FALSE;
553 552
554 struct stat status; 553 struct stat status;
555 bool ok = fstat(fd, &status) == 0 && 554 boolean ok = fstat(fd, &status) == 0 &&
556 S_ISREG(status.st_mode) && 555 S_ISREG(status.st_mode) &&
557 status.st_size > 4 && 556 status.st_size > 4 &&
558 status.st_size <= LATEX_PDF_MAX_BYTES; 557 status.st_size <= LATEX_PDF_MAX_BYTES;
559 uint8_t *content = NULL; 558 uint8 *content = NULL;
560 if (ok) 559 if (ok)
561 { 560 {
562 content = malloc((size_t)status.st_size); 561 content = malloc((size_t)status.st_size);
563 ok = content != NULL; 562 ok = content != NULL;
564 } 563 }
571 (size_t)status.st_size - offset); 570 (size_t)status.st_size - offset);
572 if (count < 0 && errno == EINTR) 571 if (count < 0 && errno == EINTR)
573 continue; 572 continue;
574 if (count <= 0) 573 if (count <= 0)
575 { 574 {
576 ok = false; 575 ok = FALSE;
577 break; 576 break;
578 } 577 }
579 offset += (size_t)count; 578 offset += (size_t)count;
580 } 579 }
581 close(fd); 580 close(fd);
582 581
583 if (!ok || 582 if (!ok ||
584 memcmp(content, "%PDF-", 5) != 0) 583 memcmp(content, "%PDF-", 5) != 0)
585 { 584 {
586 free(content); 585 free(content);
587 return false; 586 return FALSE;
588 } 587 }
589 *data = content; 588 *data = content;
590 *size = offset; 589 *size = offset;
591 return true; 590 return TRUE;
592 } 591 }
593 592
594 static bool resolve_runtime_path( 593 static boolean resolve_runtime_path(
595 const char *relative_path, 594 const char *relative_path,
596 char resolved[PATH_MAX]) 595 char resolved[PATH_MAX])
597 { 596 {
598 if (realpath(relative_path, resolved)) 597 if (realpath(relative_path, resolved))
599 return true; 598 return TRUE;
600 599
601 const char *runfiles = getenv("RUNFILES_DIR"); 600 const char *runfiles = getenv("RUNFILES_DIR");
602 const char *workspace = getenv("TEST_WORKSPACE"); 601 const char *workspace = getenv("TEST_WORKSPACE");
603 char candidate[PATH_MAX]; 602 char candidate[PATH_MAX];
604 if (runfiles && workspace) 603 if (runfiles && workspace)
611 workspace, 610 workspace,
612 relative_path); 611 relative_path);
613 if (length >= 0 && 612 if (length >= 0 &&
614 (size_t)length < sizeof(candidate) && 613 (size_t)length < sizeof(candidate) &&
615 realpath(candidate, resolved)) 614 realpath(candidate, resolved))
616 return true; 615 return TRUE;
617 } 616 }
618 617
619 char executable[PATH_MAX]; 618 char executable[PATH_MAX];
620 ssize_t executable_length = readlink( 619 ssize_t executable_length = readlink(
621 "/proc/self/exe", 620 "/proc/self/exe",
622 executable, 621 executable,
623 sizeof(executable) - 1); 622 sizeof(executable) - 1);
624 if (executable_length <= 0) 623 if (executable_length <= 0)
625 return false; 624 return FALSE;
626 executable[executable_length] = '\0'; 625 executable[executable_length] = '\0';
627 626
628 char *last_slash = strrchr(executable, '/'); 627 char *last_slash = strrchr(executable, '/');
629 if (last_slash) 628 if (last_slash)
630 { 629 {
636 executable, 635 executable,
637 relative_path); 636 relative_path);
638 if (length >= 0 && 637 if (length >= 0 &&
639 (size_t)length < sizeof(candidate) && 638 (size_t)length < sizeof(candidate) &&
640 realpath(candidate, resolved)) 639 realpath(candidate, resolved))
641 return true; 640 return TRUE;
642 } 641 }
643 642
644 char *package = strstr(executable, "/mrjunejune/"); 643 char *package = strstr(executable, "/mrjunejune/");
645 if (!package) 644 if (!package)
646 return false; 645 return FALSE;
647 *package = '\0'; 646 *package = '\0';
648 int length = snprintf( 647 int length = snprintf(
649 candidate, 648 candidate,
650 sizeof(candidate), 649 sizeof(candidate),
651 "%s/%s", 650 "%s/%s",
654 return length >= 0 && 653 return length >= 0 &&
655 (size_t)length < sizeof(candidate) && 654 (size_t)length < sizeof(candidate) &&
656 realpath(candidate, resolved) != NULL; 655 realpath(candidate, resolved) != NULL;
657 } 656 }
658 657
659 Latex_Render_Result Latex_Render(const uint8_t *source, size_t source_size) 658 Latex_Render_Result Latex_Render(const uint8 *source, size_t source_size)
660 { 659 {
661 if (!source || source_size == 0) 660 if (!source || source_size == 0)
662 return result_with_message( 661 return result_with_message(
663 LATEX_RENDER_INVALID_INPUT, 662 LATEX_RENDER_INVALID_INPUT,
664 "LaTeX source is required."); 663 "LaTeX source is required.");
753 return result_with_message( 752 return result_with_message(
754 LATEX_RENDER_INTERNAL_ERROR, 753 LATEX_RENDER_INTERNAL_ERROR,
755 "Unable to allocate compiler diagnostics."); 754 "Unable to allocate compiler diagnostics.");
756 } 755 }
757 756
758 bool timed_out = false; 757 boolean timed_out = FALSE;
759 int child_status = wait_for_compiler( 758 int child_status = wait_for_compiler(
760 child, 759 child,
761 output_pipe[0], 760 output_pipe[0],
762 diagnostics, 761 diagnostics,
763 LATEX_DIAGNOSTICS_MAX_BYTES + 1, 762 LATEX_DIAGNOSTICS_MAX_BYTES + 1,
839 #else 838 #else
840 839
841 #include <stdlib.h> 840 #include <stdlib.h>
842 #include <string.h> 841 #include <string.h>
843 842
844 Latex_Render_Result Latex_Render(const uint8_t *source, size_t source_size) 843 Latex_Render_Result Latex_Render(const uint8 *source, size_t source_size)
845 { 844 {
846 (void)source; 845 (void)source;
847 (void)source_size; 846 (void)source_size;
848 const char *message = 847 const char *message =
849 "The LaTeX security sandbox is only available on Linux."; 848 "The LaTeX security sandbox is only available on Linux.";