| 1708 | } |
| 1709 | |
| 1710 | static int secure_relative_open_linux(const char *basedir, const char *relpath, int flags, mode_t mode) |
| 1711 | { |
| 1712 | struct open_how how; |
| 1713 | int dirfd, retfd; |
| 1714 | |
| 1715 | memset(&how, 0, sizeof how); |
| 1716 | how.flags = flags; |
| 1717 | how.mode = mode; |
| 1718 | how.resolve = RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS; |
| 1719 | |
| 1720 | if (basedir == NULL) { |
| 1721 | dirfd = AT_FDCWD; |
| 1722 | } else if (basedir[0] == '/') { |
| 1723 | /* Absolute basedir: operator-trusted (module_dir and the |
| 1724 | * like). Plain openat. */ |
| 1725 | dirfd = openat(AT_FDCWD, basedir, O_RDONLY | O_DIRECTORY); |
| 1726 | if (dirfd == -1) |
| 1727 | return -1; |
| 1728 | } else { |
| 1729 | /* Relative basedir: may be wire-influenced via |
| 1730 | * --link-dest / --copy-dest / --compare-dest. Resolve it |
| 1731 | * under the same RESOLVE_BENEATH guarantee as relpath, so |
| 1732 | * a parent symlink on basedir cannot redirect the dirfd |
| 1733 | * outside the CWD anchor. */ |
| 1734 | struct open_how bhow; |
| 1735 | memset(&bhow, 0, sizeof bhow); |
| 1736 | bhow.flags = O_RDONLY | O_DIRECTORY; |
| 1737 | bhow.resolve = RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS; |
| 1738 | dirfd = openat2_beneath(AT_FDCWD, basedir, &bhow); |
| 1739 | if (dirfd == -1) |
| 1740 | return -1; |
| 1741 | } |
| 1742 | |
| 1743 | retfd = openat2_beneath(dirfd, relpath, &how); |
| 1744 | |
| 1745 | if (dirfd != AT_FDCWD) |
| 1746 | close(dirfd); |
| 1747 | return retfd; |
| 1748 | } |
| 1749 | #endif |
| 1750 | |
| 1751 | #ifdef O_RESOLVE_BENEATH |
no test coverage detected