fs-util: make chase_symlink() returns -ENOLINK when unsafe transitions are met

We previously returned -EPERM but it can be returned for various other reasons
too.

Let's use -ENOLINK instead as this value shouldn't be used currently. This
allows users of CHASE_SAFE to detect without any ambiguities when unsafe
transitions are encountered by chase_symlinks().

All current users of CHASE_SAFE that explicitly reacted on -EPERM have been
converted to react on -ENOLINK.
This commit is contained in:
Franck Bui 2018-11-30 15:13:44 +01:00
parent fd74c6f3f8
commit 36c97decbe
4 changed files with 12 additions and 8 deletions

View File

@ -649,12 +649,12 @@ static int log_unsafe_transition(int a, int b, const char *path, unsigned flags)
_cleanup_free_ char *n1 = NULL, *n2 = NULL;
if (!FLAGS_SET(flags, CHASE_WARN))
return -EPERM;
return -ENOLINK;
(void) fd_get_path(a, &n1);
(void) fd_get_path(b, &n2);
return log_warning_errno(SYNTHETIC_ERRNO(EPERM),
return log_warning_errno(SYNTHETIC_ERRNO(ENOLINK),
"Detected unsafe path transition %s %s %s during canonicalization of %s.",
n1, special_glyph(ARROW), n2, path);
}
@ -719,6 +719,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* path is fully normalized, and == 0 for each normalization step. This may be combined with
* CHASE_NONEXISTENT, in which case 1 is returned when a component is not found.
*
* 4. With CHASE_SAFE: in this case the path must not contain unsafe transitions, i.e. transitions from
* unprivileged to privileged files or directories. In such cases the return value is -ENOLINK. If
* CHASE_WARN is also set a warning describing the unsafe transition is emitted.
*
* */
/* A root directory of "/" or "" is identical to none */

View File

@ -934,8 +934,8 @@ static int service_load_pid_file(Service *s, bool may_warn) {
prio = may_warn ? LOG_INFO : LOG_DEBUG;
fd = chase_symlinks(s->pid_file, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
if (fd == -EPERM) {
log_unit_full(UNIT(s), LOG_DEBUG, fd, "Permission denied while opening PID file or potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
if (fd == -ENOLINK) {
log_unit_full(UNIT(s), LOG_DEBUG, fd, "Potentially unsafe symlink chain, will now retry with relaxed checks: %s", s->pid_file);
questionable_pid_file = true;

View File

@ -249,11 +249,11 @@ static void test_chase_symlinks(void) {
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
assert_se(chown(q, 0, 0) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
assert_se(rmdir(q) >= 0);
assert_se(symlink("/etc/passwd", q) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -ENOLINK);
assert_se(chown(p, 0, 0) >= 0);
assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);

View File

@ -862,7 +862,7 @@ static int path_open_parent_safe(const char *path) {
return log_oom();
fd = chase_symlinks(dn, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
if (fd == -EPERM)
if (fd == -ENOLINK)
return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
if (fd < 0)
return log_error_errno(fd, "Failed to validate path %s: %m", path);
@ -885,7 +885,7 @@ static int path_open_safe(const char *path) {
path);
fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_NOFOLLOW, NULL);
if (fd == -EPERM)
if (fd == -ENOLINK)
return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
if (fd < 0)
return log_error_errno(fd, "Failed to validate path %s: %m", path);