chase: introduce CHASE_NO_SHORTCUT_MASK

This commit is contained in:
Yu Watanabe
2025-08-20 02:24:39 +09:00
parent 2e7d7e929e
commit 9dcd034085
+18 -21
View File
@@ -18,6 +18,15 @@
#include "strv.h"
#include "user-util.h"
#define CHASE_NO_SHORTCUT_MASK \
(CHASE_NONEXISTENT | \
CHASE_NO_AUTOFS | \
CHASE_SAFE | \
CHASE_STEP | \
CHASE_PROHIBIT_SYMLINKS | \
CHASE_PARENT | \
CHASE_MKDIR_0755)
bool unsafe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
@@ -218,11 +227,7 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
flags &= ~CHASE_AT_RESOLVE_IN_ROOT;
}
if (!(flags &
(CHASE_AT_RESOLVE_IN_ROOT|CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_STEP|
CHASE_PROHIBIT_SYMLINKS|CHASE_MKDIR_0755|CHASE_PARENT)) &&
!ret_path && ret_fd) {
if (!ret_path && ret_fd && (flags & (CHASE_AT_RESOLVE_IN_ROOT|CHASE_NO_SHORTCUT_MASK)) == 0) {
/* Shortcut the ret_fd case if the caller isn't interested in the actual path and has no root
* set and doesn't care about any of the other special features we provide either. */
r = openat(dir_fd, path, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0));
@@ -782,8 +787,7 @@ int chase_and_open(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(AT_FDCWD, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
@@ -821,8 +825,7 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
assert(ret_dir);
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@@ -857,8 +860,7 @@ int chase_and_stat(const char *path, const char *root, ChaseFlags chase_flags, c
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
assert(ret_stat);
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@@ -885,8 +887,7 @@ int chase_and_access(const char *path, const char *root, ChaseFlags chase_flags,
assert(path);
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (empty_or_root(root) && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@@ -991,8 +992,7 @@ int chase_and_openat(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(dir_fd, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
@@ -1028,8 +1028,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
assert(ret_dir);
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0) {
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
@@ -1064,8 +1063,7 @@ int chase_and_statat(int dir_fd, const char *path, ChaseFlags chase_flags, char
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
assert(ret_stat);
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(fstatat(AT_FDCWD, path, ret_stat,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));
@@ -1092,8 +1090,7 @@ int chase_and_accessat(int dir_fd, const char *path, ChaseFlags chase_flags, int
assert(path);
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
if (dir_fd == AT_FDCWD && !ret_path &&
(chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS|CHASE_PARENT|CHASE_MKDIR_0755)) == 0)
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return RET_NERRNO(faccessat(AT_FDCWD, path, access_mode,
FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? AT_SYMLINK_NOFOLLOW : 0));