1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * Syscall definitions for NOLIBC (those in man(2)) 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 */ 6 7 /* make sure to include all global symbols */ 8 #include "nolibc.h" 9 10 #ifndef _NOLIBC_SYS_H 11 #define _NOLIBC_SYS_H 12 13 #include "std.h" 14 15 /* system includes */ 16 #include <linux/unistd.h> 17 #include <linux/signal.h> /* for SIGCHLD */ 18 #include <linux/termios.h> 19 #include <linux/mman.h> 20 #include <linux/fs.h> 21 #include <linux/loop.h> 22 #include <linux/time.h> 23 #include <linux/auxvec.h> 24 #include <linux/fcntl.h> /* for O_* and AT_* */ 25 #include <linux/sched.h> /* for clone_args */ 26 #include <linux/stat.h> /* for statx() */ 27 28 #include "errno.h" 29 #include "stdarg.h" 30 #include "types.h" 31 32 33 /* Syscall return helper: takes the syscall value in argument and checks for an 34 * error in it. This may only be used with signed returns (int or long), but 35 * not with pointers. An error is any value < 0. When an error is encountered, 36 * -ret is set into errno and -1 is returned. Otherwise the returned value is 37 * passed as-is with its type preserved. 38 */ 39 40 #define __sysret(arg) \ 41 ({ \ 42 __typeof__(arg) __sysret_arg = (arg); \ 43 (__sysret_arg < 0) /* error ? */ \ 44 ? (({ SET_ERRNO(-__sysret_arg); }), -1) /* ret -1 with errno = -arg */ \ 45 : __sysret_arg; /* return original value */ \ 46 }) 47 48 /* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a 49 * debugging hook. 50 */ 51 52 static __inline__ int __nolibc_enosys(const char *syscall, ...) 53 { 54 (void)syscall; 55 return -ENOSYS; 56 } 57 58 59 /* Functions in this file only describe syscalls. They're declared static so 60 * that the compiler usually decides to inline them while still being allowed 61 * to pass a pointer to one of their instances. Each syscall exists in two 62 * versions: 63 * - the "internal" ones, which matches the raw syscall interface at the 64 * kernel level, which may sometimes slightly differ from the documented 65 * libc-level ones. For example most of them return either a valid value 66 * or -errno. All of these are prefixed with "sys_". They may be called 67 * by non-portable applications if desired. 68 * 69 * - the "exported" ones, whose interface must closely match the one 70 * documented in man(2), that applications are supposed to expect. These 71 * ones rely on the internal ones, and set errno. 72 * 73 * Each syscall will be defined with the two functions, sorted in alphabetical 74 * order applied to the exported names. 75 * 76 * In case of doubt about the relevance of a function here, only those which 77 * set errno should be defined here. Wrappers like those appearing in man(3) 78 * should not be placed here. 79 */ 80 81 82 /* 83 * int brk(void *addr); 84 * void *sbrk(intptr_t inc) 85 */ 86 87 static __attribute__((unused)) 88 void *sys_brk(void *addr) 89 { 90 return (void *)my_syscall1(__NR_brk, addr); 91 } 92 93 static __attribute__((unused)) 94 int brk(void *addr) 95 { 96 void *ret = sys_brk(addr); 97 98 if (!ret) { 99 SET_ERRNO(ENOMEM); 100 return -1; 101 } 102 return 0; 103 } 104 105 static __attribute__((unused)) 106 void *sbrk(intptr_t inc) 107 { 108 /* first call to find current end */ 109 void *ret = sys_brk(NULL); 110 111 if (ret && sys_brk(ret + inc) == ret + inc) 112 return ret + inc; 113 114 SET_ERRNO(ENOMEM); 115 return (void *)-1; 116 } 117 118 119 /* 120 * int chdir(const char *path); 121 * int fchdir(int fildes); 122 */ 123 124 static __attribute__((unused)) 125 int sys_chdir(const char *path) 126 { 127 return my_syscall1(__NR_chdir, path); 128 } 129 130 static __attribute__((unused)) 131 int chdir(const char *path) 132 { 133 return __sysret(sys_chdir(path)); 134 } 135 136 static __attribute__((unused)) 137 int sys_fchdir(int fildes) 138 { 139 return my_syscall1(__NR_fchdir, fildes); 140 } 141 142 static __attribute__((unused)) 143 int fchdir(int fildes) 144 { 145 return __sysret(sys_fchdir(fildes)); 146 } 147 148 149 /* 150 * int chmod(const char *path, mode_t mode); 151 */ 152 153 static __attribute__((unused)) 154 int sys_chmod(const char *path, mode_t mode) 155 { 156 #if defined(__NR_fchmodat) 157 return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); 158 #else 159 return my_syscall2(__NR_chmod, path, mode); 160 #endif 161 } 162 163 static __attribute__((unused)) 164 int chmod(const char *path, mode_t mode) 165 { 166 return __sysret(sys_chmod(path, mode)); 167 } 168 169 170 /* 171 * int chown(const char *path, uid_t owner, gid_t group); 172 */ 173 174 static __attribute__((unused)) 175 int sys_chown(const char *path, uid_t owner, gid_t group) 176 { 177 #if defined(__NR_fchownat) 178 return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); 179 #else 180 return my_syscall3(__NR_chown, path, owner, group); 181 #endif 182 } 183 184 static __attribute__((unused)) 185 int chown(const char *path, uid_t owner, gid_t group) 186 { 187 return __sysret(sys_chown(path, owner, group)); 188 } 189 190 191 /* 192 * int chroot(const char *path); 193 */ 194 195 static __attribute__((unused)) 196 int sys_chroot(const char *path) 197 { 198 return my_syscall1(__NR_chroot, path); 199 } 200 201 static __attribute__((unused)) 202 int chroot(const char *path) 203 { 204 return __sysret(sys_chroot(path)); 205 } 206 207 208 /* 209 * int close(int fd); 210 */ 211 212 static __attribute__((unused)) 213 int sys_close(int fd) 214 { 215 return my_syscall1(__NR_close, fd); 216 } 217 218 static __attribute__((unused)) 219 int close(int fd) 220 { 221 return __sysret(sys_close(fd)); 222 } 223 224 225 /* 226 * int dup(int fd); 227 */ 228 229 static __attribute__((unused)) 230 int sys_dup(int fd) 231 { 232 return my_syscall1(__NR_dup, fd); 233 } 234 235 static __attribute__((unused)) 236 int dup(int fd) 237 { 238 return __sysret(sys_dup(fd)); 239 } 240 241 242 /* 243 * int dup2(int old, int new); 244 */ 245 246 static __attribute__((unused)) 247 int sys_dup2(int old, int new) 248 { 249 #if defined(__NR_dup3) 250 int ret, nr_fcntl; 251 252 #ifdef __NR_fcntl64 253 nr_fcntl = __NR_fcntl64; 254 #else 255 nr_fcntl = __NR_fcntl; 256 #endif 257 258 if (old == new) { 259 ret = my_syscall2(nr_fcntl, old, F_GETFD); 260 return ret < 0 ? ret : old; 261 } 262 263 return my_syscall3(__NR_dup3, old, new, 0); 264 #else 265 return my_syscall2(__NR_dup2, old, new); 266 #endif 267 } 268 269 static __attribute__((unused)) 270 int dup2(int old, int new) 271 { 272 return __sysret(sys_dup2(old, new)); 273 } 274 275 276 /* 277 * int dup3(int old, int new, int flags); 278 */ 279 280 #if defined(__NR_dup3) 281 static __attribute__((unused)) 282 int sys_dup3(int old, int new, int flags) 283 { 284 return my_syscall3(__NR_dup3, old, new, flags); 285 } 286 287 static __attribute__((unused)) 288 int dup3(int old, int new, int flags) 289 { 290 return __sysret(sys_dup3(old, new, flags)); 291 } 292 #endif 293 294 295 /* 296 * int execve(const char *filename, char *const argv[], char *const envp[]); 297 */ 298 299 static __attribute__((unused)) 300 int sys_execve(const char *filename, char *const argv[], char *const envp[]) 301 { 302 return my_syscall3(__NR_execve, filename, argv, envp); 303 } 304 305 static __attribute__((unused)) 306 int execve(const char *filename, char *const argv[], char *const envp[]) 307 { 308 return __sysret(sys_execve(filename, argv, envp)); 309 } 310 311 312 /* 313 * void exit(int status); 314 */ 315 316 static __attribute__((noreturn,unused)) 317 void sys_exit(int status) 318 { 319 my_syscall1(__NR_exit, status & 255); 320 while(1); /* shut the "noreturn" warnings. */ 321 } 322 323 static __attribute__((noreturn,unused)) 324 void _exit(int status) 325 { 326 sys_exit(status); 327 } 328 329 static __attribute__((noreturn,unused)) 330 void exit(int status) 331 { 332 _exit(status); 333 } 334 335 336 /* 337 * pid_t fork(void); 338 */ 339 340 #ifndef sys_fork 341 static __attribute__((unused)) 342 pid_t sys_fork(void) 343 { 344 #if defined(__NR_clone) 345 /* note: some archs only have clone() and not fork(). Different archs 346 * have a different API, but most archs have the flags on first arg and 347 * will not use the rest with no other flag. 348 */ 349 return my_syscall5(__NR_clone, SIGCHLD, 0, 0, 0, 0); 350 #else 351 return my_syscall0(__NR_fork); 352 #endif 353 } 354 #endif 355 356 static __attribute__((unused)) 357 pid_t fork(void) 358 { 359 return __sysret(sys_fork()); 360 } 361 362 #ifndef sys_vfork 363 static __attribute__((unused)) 364 pid_t sys_vfork(void) 365 { 366 #if defined(__NR_vfork) 367 return my_syscall0(__NR_vfork); 368 #else 369 /* 370 * clone() could be used but has different argument orders per 371 * architecture. 372 */ 373 struct clone_args args = { 374 .flags = CLONE_VM | CLONE_VFORK, 375 .exit_signal = SIGCHLD, 376 }; 377 378 return my_syscall2(__NR_clone3, &args, sizeof(args)); 379 #endif 380 } 381 #endif 382 383 static __attribute__((unused)) 384 pid_t vfork(void) 385 { 386 return __sysret(sys_vfork()); 387 } 388 389 /* 390 * int fsync(int fd); 391 */ 392 393 static __attribute__((unused)) 394 int sys_fsync(int fd) 395 { 396 return my_syscall1(__NR_fsync, fd); 397 } 398 399 static __attribute__((unused)) 400 int fsync(int fd) 401 { 402 return __sysret(sys_fsync(fd)); 403 } 404 405 406 /* 407 * int getdents64(int fd, struct linux_dirent64 *dirp, int count); 408 */ 409 410 static __attribute__((unused)) 411 int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) 412 { 413 return my_syscall3(__NR_getdents64, fd, dirp, count); 414 } 415 416 static __attribute__((unused)) 417 int getdents64(int fd, struct linux_dirent64 *dirp, int count) 418 { 419 return __sysret(sys_getdents64(fd, dirp, count)); 420 } 421 422 423 /* 424 * uid_t geteuid(void); 425 */ 426 427 static __attribute__((unused)) 428 uid_t sys_geteuid(void) 429 { 430 #if defined(__NR_geteuid32) 431 return my_syscall0(__NR_geteuid32); 432 #else 433 return my_syscall0(__NR_geteuid); 434 #endif 435 } 436 437 static __attribute__((unused)) 438 uid_t geteuid(void) 439 { 440 return sys_geteuid(); 441 } 442 443 444 /* 445 * pid_t getpgid(pid_t pid); 446 */ 447 448 static __attribute__((unused)) 449 pid_t sys_getpgid(pid_t pid) 450 { 451 return my_syscall1(__NR_getpgid, pid); 452 } 453 454 static __attribute__((unused)) 455 pid_t getpgid(pid_t pid) 456 { 457 return __sysret(sys_getpgid(pid)); 458 } 459 460 461 /* 462 * pid_t getpgrp(void); 463 */ 464 465 static __attribute__((unused)) 466 pid_t sys_getpgrp(void) 467 { 468 return sys_getpgid(0); 469 } 470 471 static __attribute__((unused)) 472 pid_t getpgrp(void) 473 { 474 return sys_getpgrp(); 475 } 476 477 478 /* 479 * pid_t getpid(void); 480 */ 481 482 static __attribute__((unused)) 483 pid_t sys_getpid(void) 484 { 485 return my_syscall0(__NR_getpid); 486 } 487 488 static __attribute__((unused)) 489 pid_t getpid(void) 490 { 491 return sys_getpid(); 492 } 493 494 495 /* 496 * pid_t getppid(void); 497 */ 498 499 static __attribute__((unused)) 500 pid_t sys_getppid(void) 501 { 502 return my_syscall0(__NR_getppid); 503 } 504 505 static __attribute__((unused)) 506 pid_t getppid(void) 507 { 508 return sys_getppid(); 509 } 510 511 512 /* 513 * pid_t gettid(void); 514 */ 515 516 static __attribute__((unused)) 517 pid_t sys_gettid(void) 518 { 519 return my_syscall0(__NR_gettid); 520 } 521 522 static __attribute__((unused)) 523 pid_t gettid(void) 524 { 525 return sys_gettid(); 526 } 527 528 #ifndef NOLIBC_NO_RUNTIME 529 static unsigned long getauxval(unsigned long key); 530 531 /* 532 * int getpagesize(void); 533 */ 534 535 static __attribute__((unused)) 536 int getpagesize(void) 537 { 538 return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); 539 } 540 #endif /* NOLIBC_NO_RUNTIME */ 541 542 /* 543 * uid_t getuid(void); 544 */ 545 546 static __attribute__((unused)) 547 uid_t sys_getuid(void) 548 { 549 #if defined(__NR_getuid32) 550 return my_syscall0(__NR_getuid32); 551 #else 552 return my_syscall0(__NR_getuid); 553 #endif 554 } 555 556 static __attribute__((unused)) 557 uid_t getuid(void) 558 { 559 return sys_getuid(); 560 } 561 562 563 /* 564 * int kill(pid_t pid, int signal); 565 */ 566 567 static __attribute__((unused)) 568 int sys_kill(pid_t pid, int signal) 569 { 570 return my_syscall2(__NR_kill, pid, signal); 571 } 572 573 static __attribute__((unused)) 574 int kill(pid_t pid, int signal) 575 { 576 return __sysret(sys_kill(pid, signal)); 577 } 578 579 580 /* 581 * int link(const char *old, const char *new); 582 */ 583 584 static __attribute__((unused)) 585 int sys_link(const char *old, const char *new) 586 { 587 #if defined(__NR_linkat) 588 return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); 589 #else 590 return my_syscall2(__NR_link, old, new); 591 #endif 592 } 593 594 static __attribute__((unused)) 595 int link(const char *old, const char *new) 596 { 597 return __sysret(sys_link(old, new)); 598 } 599 600 601 /* 602 * off_t lseek(int fd, off_t offset, int whence); 603 */ 604 605 static __attribute__((unused)) 606 off_t sys_lseek(int fd, off_t offset, int whence) 607 { 608 #if defined(__NR_llseek) 609 __kernel_loff_t loff = 0; 610 off_t result; 611 int ret; 612 613 ret = my_syscall5(__NR_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence); 614 if (ret < 0) 615 result = ret; 616 else 617 result = loff; 618 619 return result; 620 #else 621 return my_syscall3(__NR_lseek, fd, offset, whence); 622 #endif 623 } 624 625 static __attribute__((unused)) 626 off_t lseek(int fd, off_t offset, int whence) 627 { 628 return __sysret(sys_lseek(fd, offset, whence)); 629 } 630 631 632 /* 633 * int mkdir(const char *path, mode_t mode); 634 */ 635 636 static __attribute__((unused)) 637 int sys_mkdir(const char *path, mode_t mode) 638 { 639 #if defined(__NR_mkdirat) 640 return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); 641 #else 642 return my_syscall2(__NR_mkdir, path, mode); 643 #endif 644 } 645 646 static __attribute__((unused)) 647 int mkdir(const char *path, mode_t mode) 648 { 649 return __sysret(sys_mkdir(path, mode)); 650 } 651 652 /* 653 * int rmdir(const char *path); 654 */ 655 656 static __attribute__((unused)) 657 int sys_rmdir(const char *path) 658 { 659 #if defined(__NR_rmdir) 660 return my_syscall1(__NR_rmdir, path); 661 #else 662 return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); 663 #endif 664 } 665 666 static __attribute__((unused)) 667 int rmdir(const char *path) 668 { 669 return __sysret(sys_rmdir(path)); 670 } 671 672 673 /* 674 * int mknod(const char *path, mode_t mode, dev_t dev); 675 */ 676 677 static __attribute__((unused)) 678 long sys_mknod(const char *path, mode_t mode, dev_t dev) 679 { 680 #if defined(__NR_mknodat) 681 return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); 682 #else 683 return my_syscall3(__NR_mknod, path, mode, dev); 684 #endif 685 } 686 687 static __attribute__((unused)) 688 int mknod(const char *path, mode_t mode, dev_t dev) 689 { 690 return __sysret(sys_mknod(path, mode, dev)); 691 } 692 693 694 /* 695 * int pipe2(int pipefd[2], int flags); 696 * int pipe(int pipefd[2]); 697 */ 698 699 static __attribute__((unused)) 700 int sys_pipe2(int pipefd[2], int flags) 701 { 702 return my_syscall2(__NR_pipe2, pipefd, flags); 703 } 704 705 static __attribute__((unused)) 706 int pipe2(int pipefd[2], int flags) 707 { 708 return __sysret(sys_pipe2(pipefd, flags)); 709 } 710 711 static __attribute__((unused)) 712 int pipe(int pipefd[2]) 713 { 714 return pipe2(pipefd, 0); 715 } 716 717 718 /* 719 * int pivot_root(const char *new, const char *old); 720 */ 721 722 static __attribute__((unused)) 723 int sys_pivot_root(const char *new, const char *old) 724 { 725 return my_syscall2(__NR_pivot_root, new, old); 726 } 727 728 static __attribute__((unused)) 729 int pivot_root(const char *new, const char *old) 730 { 731 return __sysret(sys_pivot_root(new, old)); 732 } 733 734 735 /* 736 * ssize_t read(int fd, void *buf, size_t count); 737 */ 738 739 static __attribute__((unused)) 740 ssize_t sys_read(int fd, void *buf, size_t count) 741 { 742 return my_syscall3(__NR_read, fd, buf, count); 743 } 744 745 static __attribute__((unused)) 746 ssize_t read(int fd, void *buf, size_t count) 747 { 748 return __sysret(sys_read(fd, buf, count)); 749 } 750 751 752 /* 753 * int sched_yield(void); 754 */ 755 756 static __attribute__((unused)) 757 int sys_sched_yield(void) 758 { 759 return my_syscall0(__NR_sched_yield); 760 } 761 762 static __attribute__((unused)) 763 int sched_yield(void) 764 { 765 return __sysret(sys_sched_yield()); 766 } 767 768 769 /* 770 * int setpgid(pid_t pid, pid_t pgid); 771 */ 772 773 static __attribute__((unused)) 774 int sys_setpgid(pid_t pid, pid_t pgid) 775 { 776 return my_syscall2(__NR_setpgid, pid, pgid); 777 } 778 779 static __attribute__((unused)) 780 int setpgid(pid_t pid, pid_t pgid) 781 { 782 return __sysret(sys_setpgid(pid, pgid)); 783 } 784 785 /* 786 * pid_t setpgrp(void) 787 */ 788 789 static __attribute__((unused)) 790 pid_t setpgrp(void) 791 { 792 return setpgid(0, 0); 793 } 794 795 796 /* 797 * pid_t setsid(void); 798 */ 799 800 static __attribute__((unused)) 801 pid_t sys_setsid(void) 802 { 803 return my_syscall0(__NR_setsid); 804 } 805 806 static __attribute__((unused)) 807 pid_t setsid(void) 808 { 809 return __sysret(sys_setsid()); 810 } 811 812 813 /* 814 * int symlink(const char *old, const char *new); 815 */ 816 817 static __attribute__((unused)) 818 int sys_symlink(const char *old, const char *new) 819 { 820 #if defined(__NR_symlinkat) 821 return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); 822 #else 823 return my_syscall2(__NR_symlink, old, new); 824 #endif 825 } 826 827 static __attribute__((unused)) 828 int symlink(const char *old, const char *new) 829 { 830 return __sysret(sys_symlink(old, new)); 831 } 832 833 834 /* 835 * mode_t umask(mode_t mode); 836 */ 837 838 static __attribute__((unused)) 839 mode_t sys_umask(mode_t mode) 840 { 841 return my_syscall1(__NR_umask, mode); 842 } 843 844 static __attribute__((unused)) 845 mode_t umask(mode_t mode) 846 { 847 return sys_umask(mode); 848 } 849 850 851 /* 852 * int umount2(const char *path, int flags); 853 */ 854 855 static __attribute__((unused)) 856 int sys_umount2(const char *path, int flags) 857 { 858 return my_syscall2(__NR_umount2, path, flags); 859 } 860 861 static __attribute__((unused)) 862 int umount2(const char *path, int flags) 863 { 864 return __sysret(sys_umount2(path, flags)); 865 } 866 867 868 /* 869 * int unlink(const char *path); 870 */ 871 872 static __attribute__((unused)) 873 int sys_unlink(const char *path) 874 { 875 #if defined(__NR_unlinkat) 876 return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); 877 #else 878 return my_syscall1(__NR_unlink, path); 879 #endif 880 } 881 882 static __attribute__((unused)) 883 int unlink(const char *path) 884 { 885 return __sysret(sys_unlink(path)); 886 } 887 888 889 /* 890 * ssize_t write(int fd, const void *buf, size_t count); 891 */ 892 893 static __attribute__((unused)) 894 ssize_t sys_write(int fd, const void *buf, size_t count) 895 { 896 return my_syscall3(__NR_write, fd, buf, count); 897 } 898 899 static __attribute__((unused)) 900 ssize_t write(int fd, const void *buf, size_t count) 901 { 902 return __sysret(sys_write(fd, buf, count)); 903 } 904 905 906 /* 907 * int memfd_create(const char *name, unsigned int flags); 908 */ 909 910 static __attribute__((unused)) 911 int sys_memfd_create(const char *name, unsigned int flags) 912 { 913 return my_syscall2(__NR_memfd_create, name, flags); 914 } 915 916 static __attribute__((unused)) 917 int memfd_create(const char *name, unsigned int flags) 918 { 919 return __sysret(sys_memfd_create(name, flags)); 920 } 921 922 #endif /* _NOLIBC_SYS_H */ 923