Open a basis/output path that may legitimately be an operator-trusted * ABSOLUTE path -- e.g. an absolute --partial-dir ("a directory reserved for * partial-dir work") or --backup-dir. secure_relative_open() deliberately * rejects an absolute relpath, so feeding it the whole absolute partialptr * (with a NULL basedir) returns EINVAL: the basis fd is then -1, no basis is * mapped, and receive_
| 98 | * open already trusts an absolute basedir while O_NOFOLLOW-confining the leaf. |
| 99 | * Anything else is a straight pass-through that preserves the strict contract. */ |
| 100 | static int secure_basis_open(const char *basedir, const char *relpath, int flags, mode_t mode) |
| 101 | { |
| 102 | extern int am_daemon, am_chrooted; |
| 103 | |
| 104 | /* The confined resolver is only needed for the sanitizing daemon |
| 105 | * (am_daemon && !am_chrooted, i.e. use_secure_symlinks). Local / |
| 106 | * remote-shell mode has no module boundary, and "use chroot = yes" makes |
| 107 | * the kernel root the boundary, so there an alt-dest basis like |
| 108 | * --link-dest=../01 must resolve against the cwd as a bare open did before |
| 109 | * the hardening (confining it would reject the legitimate sibling "..", |
| 110 | * #915). */ |
| 111 | if (!am_daemon || am_chrooted) { |
| 112 | if (basedir) { |
| 113 | char fullpath[MAXPATHLEN]; |
| 114 | if (pathjoin(fullpath, sizeof fullpath, basedir, relpath) >= sizeof fullpath) { |
| 115 | errno = ENAMETOOLONG; |
| 116 | return -1; |
| 117 | } |
| 118 | return do_open(fullpath, flags, mode); |
| 119 | } |
| 120 | return do_open(relpath, flags, mode); |
| 121 | } |
| 122 | |
| 123 | if (!basedir && relpath && *relpath == '/') { |
| 124 | const char *slash = strrchr(relpath, '/'); |
| 125 | const char *leaf = slash + 1; |
| 126 | char dirbuf[MAXPATHLEN]; |
| 127 | const char *dir; |
| 128 | if (slash == relpath) |
| 129 | dir = "/"; |
| 130 | else { |
| 131 | size_t dlen = slash - relpath; |
| 132 | if (dlen >= sizeof dirbuf) { |
| 133 | errno = ENAMETOOLONG; |
| 134 | return -1; |
| 135 | } |
| 136 | memcpy(dirbuf, relpath, dlen); |
| 137 | dirbuf[dlen] = '\0'; |
| 138 | dir = dirbuf; |
| 139 | } |
| 140 | return secure_relative_open(dir, leaf, flags, mode); |
| 141 | } |
| 142 | return secure_relative_open(basedir, relpath, flags, mode); |
| 143 | } |
| 144 | |
| 145 | /* get_tmpname() - create a tmp filename for a given filename |
| 146 | * |
no test coverage detected