FreeBSD 13+ and macOS 15+ (Sequoia) / iOS 18+: O_RESOLVE_BENEATH is * an openat() flag with the same "must not escape dirfd" semantics as * Linux's RESOLVE_BENEATH. The kernel rejects ".." escapes, absolute * symlinks, and symlinks whose target lies outside dirfd. (FreeBSD and * Apple use different flag bit values, but the same symbolic name.) */
| 1755 | * symlinks, and symlinks whose target lies outside dirfd. (FreeBSD and |
| 1756 | * Apple use different flag bit values, but the same symbolic name.) */ |
| 1757 | static int secure_relative_open_resolve_beneath(const char *basedir, const char *relpath, int flags, mode_t mode) |
| 1758 | { |
| 1759 | int dirfd, retfd; |
| 1760 | |
| 1761 | if (basedir == NULL) { |
| 1762 | dirfd = AT_FDCWD; |
| 1763 | } else if (basedir[0] == '/') { |
| 1764 | /* Absolute basedir: operator-trusted, plain openat. */ |
| 1765 | dirfd = openat(AT_FDCWD, basedir, O_RDONLY | O_DIRECTORY); |
| 1766 | if (dirfd == -1) |
| 1767 | return -1; |
| 1768 | } else { |
| 1769 | /* Relative basedir: confine its resolution beneath CWD |
| 1770 | * (see secure_relative_open_linux for the rationale). */ |
| 1771 | dirfd = openat(AT_FDCWD, basedir, O_RDONLY | O_DIRECTORY | O_RESOLVE_BENEATH); |
| 1772 | if (dirfd == -1) |
| 1773 | return -1; |
| 1774 | } |
| 1775 | |
| 1776 | retfd = openat(dirfd, relpath, flags | O_RESOLVE_BENEATH, mode); |
| 1777 | |
| 1778 | if (dirfd != AT_FDCWD) |
| 1779 | close(dirfd); |
| 1780 | return retfd; |
| 1781 | } |
| 1782 | #endif |
| 1783 | |
| 1784 | /* The logical current directory (maintained by change_dir() in util1.c). |
no outgoing calls
no test coverage detected