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_* */ 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_clone) 367 /* See the note in sys_fork(). */ 368 return my_syscall5(__NR_clone, CLONE_VM | CLONE_VFORK | SIGCHLD, 0, 0, 0, 0); 369 #elif defined(__NR_vfork) 370 return my_syscall0(__NR_vfork); 371 #endif 372 } 373 #endif 374 375 static __attribute__((unused)) 376 pid_t vfork(void) 377 { 378 return __sysret(sys_vfork()); 379 } 380 381 /* 382 * int fsync(int fd); 383 */ 384 385 static __attribute__((unused)) 386 int sys_fsync(int fd) 387 { 388 return my_syscall1(__NR_fsync, fd); 389 } 390 391 static __attribute__((unused)) 392 int fsync(int fd) 393 { 394 return __sysret(sys_fsync(fd)); 395 } 396 397 398 /* 399 * int getdents64(int fd, struct linux_dirent64 *dirp, int count); 400 */ 401 402 static __attribute__((unused)) 403 int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) 404 { 405 return my_syscall3(__NR_getdents64, fd, dirp, count); 406 } 407 408 static __attribute__((unused)) 409 int getdents64(int fd, struct linux_dirent64 *dirp, int count) 410 { 411 return __sysret(sys_getdents64(fd, dirp, count)); 412 } 413 414 415 /* 416 * uid_t geteuid(void); 417 */ 418 419 static __attribute__((unused)) 420 uid_t sys_geteuid(void) 421 { 422 #if defined(__NR_geteuid32) 423 return my_syscall0(__NR_geteuid32); 424 #else 425 return my_syscall0(__NR_geteuid); 426 #endif 427 } 428 429 static __attribute__((unused)) 430 uid_t geteuid(void) 431 { 432 return sys_geteuid(); 433 } 434 435 436 /* 437 * pid_t getpgid(pid_t pid); 438 */ 439 440 static __attribute__((unused)) 441 pid_t sys_getpgid(pid_t pid) 442 { 443 return my_syscall1(__NR_getpgid, pid); 444 } 445 446 static __attribute__((unused)) 447 pid_t getpgid(pid_t pid) 448 { 449 return __sysret(sys_getpgid(pid)); 450 } 451 452 453 /* 454 * pid_t getpgrp(void); 455 */ 456 457 static __attribute__((unused)) 458 pid_t sys_getpgrp(void) 459 { 460 return sys_getpgid(0); 461 } 462 463 static __attribute__((unused)) 464 pid_t getpgrp(void) 465 { 466 return sys_getpgrp(); 467 } 468 469 470 /* 471 * pid_t getpid(void); 472 */ 473 474 static __attribute__((unused)) 475 pid_t sys_getpid(void) 476 { 477 return my_syscall0(__NR_getpid); 478 } 479 480 static __attribute__((unused)) 481 pid_t getpid(void) 482 { 483 return sys_getpid(); 484 } 485 486 487 /* 488 * pid_t getppid(void); 489 */ 490 491 static __attribute__((unused)) 492 pid_t sys_getppid(void) 493 { 494 return my_syscall0(__NR_getppid); 495 } 496 497 static __attribute__((unused)) 498 pid_t getppid(void) 499 { 500 return sys_getppid(); 501 } 502 503 504 /* 505 * pid_t gettid(void); 506 */ 507 508 static __attribute__((unused)) 509 pid_t sys_gettid(void) 510 { 511 return my_syscall0(__NR_gettid); 512 } 513 514 static __attribute__((unused)) 515 pid_t gettid(void) 516 { 517 return sys_gettid(); 518 } 519 520 #ifndef NOLIBC_NO_RUNTIME 521 static unsigned long getauxval(unsigned long key); 522 523 /* 524 * int getpagesize(void); 525 */ 526 527 static __attribute__((unused)) 528 int getpagesize(void) 529 { 530 return __sysret((int)getauxval(AT_PAGESZ) ?: -ENOENT); 531 } 532 #endif /* NOLIBC_NO_RUNTIME */ 533 534 /* 535 * uid_t getuid(void); 536 */ 537 538 static __attribute__((unused)) 539 uid_t sys_getuid(void) 540 { 541 #if defined(__NR_getuid32) 542 return my_syscall0(__NR_getuid32); 543 #else 544 return my_syscall0(__NR_getuid); 545 #endif 546 } 547 548 static __attribute__((unused)) 549 uid_t getuid(void) 550 { 551 return sys_getuid(); 552 } 553 554 555 /* 556 * int kill(pid_t pid, int signal); 557 */ 558 559 static __attribute__((unused)) 560 int sys_kill(pid_t pid, int signal) 561 { 562 return my_syscall2(__NR_kill, pid, signal); 563 } 564 565 static __attribute__((unused)) 566 int kill(pid_t pid, int signal) 567 { 568 return __sysret(sys_kill(pid, signal)); 569 } 570 571 572 /* 573 * int link(const char *old, const char *new); 574 */ 575 576 static __attribute__((unused)) 577 int sys_link(const char *old, const char *new) 578 { 579 #if defined(__NR_linkat) 580 return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); 581 #else 582 return my_syscall2(__NR_link, old, new); 583 #endif 584 } 585 586 static __attribute__((unused)) 587 int link(const char *old, const char *new) 588 { 589 return __sysret(sys_link(old, new)); 590 } 591 592 593 /* 594 * off_t lseek(int fd, off_t offset, int whence); 595 */ 596 597 static __attribute__((unused)) 598 off_t sys_lseek(int fd, off_t offset, int whence) 599 { 600 #if defined(__NR_llseek) 601 __kernel_loff_t loff = 0; 602 off_t result; 603 int ret; 604 605 ret = my_syscall5(__NR_llseek, fd, offset >> 32, (uint32_t)offset, &loff, whence); 606 if (ret < 0) 607 result = ret; 608 else 609 result = loff; 610 611 return result; 612 #else 613 return my_syscall3(__NR_lseek, fd, offset, whence); 614 #endif 615 } 616 617 static __attribute__((unused)) 618 off_t lseek(int fd, off_t offset, int whence) 619 { 620 return __sysret(sys_lseek(fd, offset, whence)); 621 } 622 623 624 /* 625 * int mkdir(const char *path, mode_t mode); 626 */ 627 628 static __attribute__((unused)) 629 int sys_mkdir(const char *path, mode_t mode) 630 { 631 #if defined(__NR_mkdirat) 632 return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); 633 #else 634 return my_syscall2(__NR_mkdir, path, mode); 635 #endif 636 } 637 638 static __attribute__((unused)) 639 int mkdir(const char *path, mode_t mode) 640 { 641 return __sysret(sys_mkdir(path, mode)); 642 } 643 644 /* 645 * int rmdir(const char *path); 646 */ 647 648 static __attribute__((unused)) 649 int sys_rmdir(const char *path) 650 { 651 #if defined(__NR_rmdir) 652 return my_syscall1(__NR_rmdir, path); 653 #else 654 return my_syscall3(__NR_unlinkat, AT_FDCWD, path, AT_REMOVEDIR); 655 #endif 656 } 657 658 static __attribute__((unused)) 659 int rmdir(const char *path) 660 { 661 return __sysret(sys_rmdir(path)); 662 } 663 664 665 /* 666 * int mknod(const char *path, mode_t mode, dev_t dev); 667 */ 668 669 static __attribute__((unused)) 670 long sys_mknod(const char *path, mode_t mode, dev_t dev) 671 { 672 #if defined(__NR_mknodat) 673 return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); 674 #else 675 return my_syscall3(__NR_mknod, path, mode, dev); 676 #endif 677 } 678 679 static __attribute__((unused)) 680 int mknod(const char *path, mode_t mode, dev_t dev) 681 { 682 return __sysret(sys_mknod(path, mode, dev)); 683 } 684 685 686 /* 687 * int pipe2(int pipefd[2], int flags); 688 * int pipe(int pipefd[2]); 689 */ 690 691 static __attribute__((unused)) 692 int sys_pipe2(int pipefd[2], int flags) 693 { 694 return my_syscall2(__NR_pipe2, pipefd, flags); 695 } 696 697 static __attribute__((unused)) 698 int pipe2(int pipefd[2], int flags) 699 { 700 return __sysret(sys_pipe2(pipefd, flags)); 701 } 702 703 static __attribute__((unused)) 704 int pipe(int pipefd[2]) 705 { 706 return pipe2(pipefd, 0); 707 } 708 709 710 /* 711 * int pivot_root(const char *new, const char *old); 712 */ 713 714 static __attribute__((unused)) 715 int sys_pivot_root(const char *new, const char *old) 716 { 717 return my_syscall2(__NR_pivot_root, new, old); 718 } 719 720 static __attribute__((unused)) 721 int pivot_root(const char *new, const char *old) 722 { 723 return __sysret(sys_pivot_root(new, old)); 724 } 725 726 727 /* 728 * ssize_t read(int fd, void *buf, size_t count); 729 */ 730 731 static __attribute__((unused)) 732 ssize_t sys_read(int fd, void *buf, size_t count) 733 { 734 return my_syscall3(__NR_read, fd, buf, count); 735 } 736 737 static __attribute__((unused)) 738 ssize_t read(int fd, void *buf, size_t count) 739 { 740 return __sysret(sys_read(fd, buf, count)); 741 } 742 743 744 /* 745 * int sched_yield(void); 746 */ 747 748 static __attribute__((unused)) 749 int sys_sched_yield(void) 750 { 751 return my_syscall0(__NR_sched_yield); 752 } 753 754 static __attribute__((unused)) 755 int sched_yield(void) 756 { 757 return __sysret(sys_sched_yield()); 758 } 759 760 761 /* 762 * int setpgid(pid_t pid, pid_t pgid); 763 */ 764 765 static __attribute__((unused)) 766 int sys_setpgid(pid_t pid, pid_t pgid) 767 { 768 return my_syscall2(__NR_setpgid, pid, pgid); 769 } 770 771 static __attribute__((unused)) 772 int setpgid(pid_t pid, pid_t pgid) 773 { 774 return __sysret(sys_setpgid(pid, pgid)); 775 } 776 777 /* 778 * pid_t setpgrp(void) 779 */ 780 781 static __attribute__((unused)) 782 pid_t setpgrp(void) 783 { 784 return setpgid(0, 0); 785 } 786 787 788 /* 789 * pid_t setsid(void); 790 */ 791 792 static __attribute__((unused)) 793 pid_t sys_setsid(void) 794 { 795 return my_syscall0(__NR_setsid); 796 } 797 798 static __attribute__((unused)) 799 pid_t setsid(void) 800 { 801 return __sysret(sys_setsid()); 802 } 803 804 805 /* 806 * int symlink(const char *old, const char *new); 807 */ 808 809 static __attribute__((unused)) 810 int sys_symlink(const char *old, const char *new) 811 { 812 #if defined(__NR_symlinkat) 813 return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); 814 #else 815 return my_syscall2(__NR_symlink, old, new); 816 #endif 817 } 818 819 static __attribute__((unused)) 820 int symlink(const char *old, const char *new) 821 { 822 return __sysret(sys_symlink(old, new)); 823 } 824 825 826 /* 827 * mode_t umask(mode_t mode); 828 */ 829 830 static __attribute__((unused)) 831 mode_t sys_umask(mode_t mode) 832 { 833 return my_syscall1(__NR_umask, mode); 834 } 835 836 static __attribute__((unused)) 837 mode_t umask(mode_t mode) 838 { 839 return sys_umask(mode); 840 } 841 842 843 /* 844 * int umount2(const char *path, int flags); 845 */ 846 847 static __attribute__((unused)) 848 int sys_umount2(const char *path, int flags) 849 { 850 return my_syscall2(__NR_umount2, path, flags); 851 } 852 853 static __attribute__((unused)) 854 int umount2(const char *path, int flags) 855 { 856 return __sysret(sys_umount2(path, flags)); 857 } 858 859 860 /* 861 * int unlink(const char *path); 862 */ 863 864 static __attribute__((unused)) 865 int sys_unlink(const char *path) 866 { 867 #if defined(__NR_unlinkat) 868 return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); 869 #else 870 return my_syscall1(__NR_unlink, path); 871 #endif 872 } 873 874 static __attribute__((unused)) 875 int unlink(const char *path) 876 { 877 return __sysret(sys_unlink(path)); 878 } 879 880 881 /* 882 * ssize_t write(int fd, const void *buf, size_t count); 883 */ 884 885 static __attribute__((unused)) 886 ssize_t sys_write(int fd, const void *buf, size_t count) 887 { 888 return my_syscall3(__NR_write, fd, buf, count); 889 } 890 891 static __attribute__((unused)) 892 ssize_t write(int fd, const void *buf, size_t count) 893 { 894 return __sysret(sys_write(fd, buf, count)); 895 } 896 897 898 /* 899 * int memfd_create(const char *name, unsigned int flags); 900 */ 901 902 static __attribute__((unused)) 903 int sys_memfd_create(const char *name, unsigned int flags) 904 { 905 return my_syscall2(__NR_memfd_create, name, flags); 906 } 907 908 static __attribute__((unused)) 909 int memfd_create(const char *name, unsigned int flags) 910 { 911 return __sysret(sys_memfd_create(name, flags)); 912 } 913 914 #endif /* _NOLIBC_SYS_H */ 915