chase: check root path in more detail

In chaseat() we call dir_fd_is_root() several places, and the final
result depends on it. If the root path specified to `chase()` is not
normalized but points to "/", e.g. "/../", assertions in `chaseat()` or
`chase()` may be triggered.
This commit is contained in:
Yu Watanabe
2023-07-29 22:09:28 +09:00
parent 4de5b4e375
commit 83c57d8cde
3 changed files with 43 additions and 1 deletions
+35 -1
View File
@@ -518,6 +518,27 @@ chased_one:
return 0;
}
static int empty_or_root_to_null(const char **path) {
int r;
assert(path);
/* This nullifies the input path when the path is empty or points to "/". */
if (empty_or_root(*path)) {
*path = NULL;
return 0;
}
r = path_is_root(*path);
if (r < 0)
return r;
if (r > 0)
*path = NULL;
return 0;
}
int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path, int *ret_fd) {
_cleanup_free_ char *root_abs = NULL, *absolute = NULL, *p = NULL;
_cleanup_close_ int fd = -EBADF, pfd = -EBADF;
@@ -528,6 +549,10 @@ int chase(const char *path, const char *root, ChaseFlags flags, char **ret_path,
if (isempty(path))
return -EINVAL;
r = empty_or_root_to_null(&root);
if (r < 0)
return r;
/* A root directory of "/" or "" is identical to "/". */
if (empty_or_root(root)) {
root = "/";
@@ -624,8 +649,13 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) {
if (!path_is_absolute(path)) {
_cleanup_free_ char *root_abs = NULL;
r = empty_or_root_to_null(&root);
if (r < 0 && r != -ENOENT)
return r;
/* If the dir_fd points to the root directory, chaseat() always returns an absolute path. */
assert(!empty_or_root(root));
if (empty_or_root(root))
return -EINVAL;
r = path_make_absolute_cwd(root, &root_abs);
if (r < 0)
@@ -658,6 +688,10 @@ int chase_extract_filename(const char *path, const char *root, char **ret) {
if (!path_is_absolute(path))
return -EINVAL;
r = empty_or_root_to_null(&root);
if (r < 0 && r != -ENOENT)
return r;
if (!empty_or_root(root)) {
_cleanup_free_ char *root_abs = NULL;
+3
View File
@@ -102,6 +102,9 @@ int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret);
int path_is_root_at(int dir_fd, const char *path);
static inline int path_is_root(const char *path) {
return path_is_root_at(AT_FDCWD, path);
}
static inline int dir_fd_is_root(int dir_fd) {
return path_is_root_at(dir_fd, NULL);
}