Symlink-race-safe variant of do_unlink() for receiver-side use. See the comment on do_chmod_at() for the threat model. unlink() resolves parent components, so a parent-symlink swap can delete an outside file under the daemon's authority. Defence: open the parent of path under secure_relative_open() and use unlinkat() (flags=0) against that dirfd. Falls through to do_unlink() for the s
| 105 | chrooted / no-parent / absolute-path cases as the other wrappers. |
| 106 | */ |
| 107 | int do_unlink_at(const char *path) |
| 108 | { |
| 109 | #ifdef AT_FDCWD |
| 110 | extern int am_daemon, am_chrooted; |
| 111 | char dirpath[MAXPATHLEN]; |
| 112 | const char *bname; |
| 113 | const char *slash; |
| 114 | int dfd, ret, e; |
| 115 | size_t dlen; |
| 116 | |
| 117 | if (dry_run) return 0; |
| 118 | RETURN_ERROR_IF_RO_OR_LO; |
| 119 | |
| 120 | if (!am_daemon || am_chrooted) |
| 121 | return unlink(path); |
| 122 | |
| 123 | if (!path || !*path || *path == '/') |
| 124 | return unlink(path); |
| 125 | |
| 126 | slash = strrchr(path, '/'); |
| 127 | if (!slash) |
| 128 | return unlink(path); |
| 129 | |
| 130 | dlen = slash - path; |
| 131 | if (dlen >= sizeof dirpath) { |
| 132 | errno = ENAMETOOLONG; |
| 133 | return -1; |
| 134 | } |
| 135 | memcpy(dirpath, path, dlen); |
| 136 | dirpath[dlen] = '\0'; |
| 137 | bname = slash + 1; |
| 138 | |
| 139 | dfd = secure_relative_open(NULL, dirpath, O_RDONLY | O_DIRECTORY, 0); |
| 140 | if (dfd < 0) |
| 141 | return -1; |
| 142 | |
| 143 | ret = unlinkat(dfd, bname, 0); |
| 144 | e = errno; |
| 145 | close(dfd); |
| 146 | errno = e; |
| 147 | return ret; |
| 148 | #else |
| 149 | return do_unlink(path); |
| 150 | #endif |
| 151 | } |
| 152 | |
| 153 | #ifdef SUPPORT_LINKS |
| 154 | int do_symlink(const char *lnk, const char *path) |
no test coverage detected