mirror of
https://github.com/systemd/systemd.git
synced 2026-08-09 17:38:42 +00:00
chase: put limit on overall chase cycles
Let's add some protections in case we deal with inodes owned by an untrusted person, with concurrent access: let's put a limit on how long we traverse, and fail eventually so that live changes cannot send us in circles indefinitely. This reworks the current CHASE_MAX logic so that it not only applies to symlinks transitions, but to any transitions. This also bumps CHASE_MAX a bit, given that it's now bumped on every single iteration of the loop.
This commit is contained in:
@@ -128,7 +128,6 @@ static int chaseat_needs_absolute(int dir_fd, const char *path) {
|
||||
int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int *ret_fd) {
|
||||
_cleanup_free_ char *buffer = NULL, *done = NULL;
|
||||
_cleanup_close_ int fd = -EBADF, root_fd = -EBADF;
|
||||
unsigned max_follow = CHASE_MAX; /* how many symlinks to follow before giving up and returning ELOOP */
|
||||
bool exists = true, append_trail_slash = false;
|
||||
struct stat st; /* stat obtained from fd */
|
||||
bool need_absolute = false; /* allocate early to avoid compiler warnings around goto */
|
||||
@@ -334,12 +333,18 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
|
||||
if (FLAGS_SET(flags, CHASE_MUST_BE_DIRECTORY) + FLAGS_SET(flags, CHASE_MUST_BE_REGULAR) + FLAGS_SET(flags, CHASE_MUST_BE_SOCKET) > 1)
|
||||
return -EBADSLT;
|
||||
|
||||
for (todo = buffer;;) {
|
||||
todo = buffer;
|
||||
for (unsigned n_steps = 0;; n_steps++) {
|
||||
_cleanup_free_ char *first = NULL;
|
||||
_cleanup_close_ int child = -EBADF;
|
||||
struct stat st_child;
|
||||
const char *e;
|
||||
|
||||
/* If people change our tree behind our back, they might send us in circles. Put a limit on
|
||||
* things */
|
||||
if (n_steps > CHASE_MAX)
|
||||
return -ELOOP;
|
||||
|
||||
r = path_find_first_component(&todo, /* accept_dot_dot= */ true, &e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -495,11 +500,6 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
|
||||
if (FLAGS_SET(flags, CHASE_PROHIBIT_SYMLINKS))
|
||||
return log_prohibited_symlink(child, flags);
|
||||
|
||||
/* This is a symlink, in this case read the destination. But let's make sure we
|
||||
* don't follow symlinks without bounds. */
|
||||
if (--max_follow <= 0)
|
||||
return -ELOOP;
|
||||
|
||||
r = readlinkat_malloc(fd, first, &destination);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -35,7 +35,7 @@ typedef enum ChaseFlags {
|
||||
bool unsafe_transition(const struct stat *a, const struct stat *b);
|
||||
|
||||
/* How many iterations to execute before returning -ELOOP */
|
||||
#define CHASE_MAX 32
|
||||
#define CHASE_MAX 128U
|
||||
|
||||
int chase(const char *path_with_prefix, const char *root, ChaseFlags flags, char **ret_path, int *ret_fd);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user