chase: handle root path more carefully in chase_and_open()

chase_and_open() may be called with relative root path.
This commit is contained in:
Yu Watanabe
2023-06-05 14:47:42 +09:00
parent c0dff4205b
commit 3991f35fbd
3 changed files with 72 additions and 8 deletions

View File

@@ -618,11 +618,51 @@ int chaseat_prefix_root(const char *path, const char *root, char **ret) {
return 0;
}
int chase_extract_filename(const char *path, const char *root, char **ret) {
int r;
/* This is similar to path_extract_filename(), but takes root directory.
* The result should be consistent with chase() with CHASE_EXTRACT_FILENAME. */
assert(path);
assert(ret);
if (isempty(path))
return -EINVAL;
if (!path_is_absolute(path))
return -EINVAL;
if (!empty_or_root(root)) {
_cleanup_free_ char *root_abs = NULL;
r = path_make_absolute_cwd(root, &root_abs);
if (r < 0)
return r;
path = path_startswith(path, root_abs);
if (!path)
return -EINVAL;
}
if (!isempty(path)) {
r = path_extract_filename(path, ret);
if (r != -EADDRNOTAVAIL)
return r;
}
char *fname = strdup(".");
if (!fname)
return -ENOMEM;
*ret = fname;
return 0;
}
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path) {
_cleanup_close_ int path_fd = -EBADF;
_cleanup_free_ char *p = NULL, *fname = NULL;
mode_t mode = open_flags & O_DIRECTORY ? 0755 : 0644;
const char *q;
int r;
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
@@ -640,13 +680,10 @@ int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, i
return r;
assert(path_fd >= 0);
assert_se(q = path_startswith(p, empty_to_root(root)));
if (isempty(q))
q = ".";
if (!FLAGS_SET(chase_flags, CHASE_PARENT)) {
r = path_extract_filename(q, &fname);
if (r < 0 && r != -EADDRNOTAVAIL)
if (!FLAGS_SET(chase_flags, CHASE_PARENT) &&
!FLAGS_SET(chase_flags, CHASE_EXTRACT_FILENAME)) {
r = chase_extract_filename(p, root, &fname);
if (r < 0)
return r;
}

View File

@@ -43,6 +43,7 @@ bool unsafe_transition(const struct stat *a, const struct stat *b);
int chase(const char *path_with_prefix, const char *root, ChaseFlags chase_flags, char **ret_path, int *ret_fd);
int chaseat_prefix_root(const char *path, const char *root, char **ret);
int chase_extract_filename(const char *path, const char *root, char **ret);
int chase_and_open(const char *path, const char *root, ChaseFlags chase_flags, int open_flags, char **ret_path);
int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags, char **ret_path, DIR **ret_dir);

View File

@@ -17,6 +17,19 @@
static const char *arg_test_dir = NULL;
static void test_chase_extract_filename_one(const char *path, const char *root, const char *expected) {
_cleanup_free_ char *ret1 = NULL, *ret2 = NULL, *fname = NULL;
log_debug("/* %s(path=%s, root=%s) */", __func__, path, strnull(root));
assert_se(chase(path, root, CHASE_EXTRACT_FILENAME, &ret1, NULL) > 0);
assert_se(streq(ret1, expected));
assert_se(chase(path, root, 0, &ret2, NULL) > 0);
assert_se(chase_extract_filename(ret2, root, &fname) >= 0);
assert_se(streq(fname, expected));
}
TEST(chase) {
_cleanup_free_ char *result = NULL, *pwd = NULL;
_cleanup_close_ int pfd = -EBADF;
@@ -111,6 +124,19 @@ TEST(chase) {
assert_se(path_equal(result, temp));
result = mfree(result);
/* Tests for CHASE_EXTRACT_FILENAME and chase_extract_filename() */
p = strjoina(temp, "/start");
pslash = strjoina(p, "/");
test_chase_extract_filename_one(p, NULL, "usr");
test_chase_extract_filename_one(pslash, NULL, "usr");
test_chase_extract_filename_one(p, temp, "usr");
test_chase_extract_filename_one(pslash, temp, "usr");
p = strjoina(temp, "/slash");
test_chase_extract_filename_one(p, NULL, ".");
test_chase_extract_filename_one(p, temp, ".");
/* Paths that would "escape" outside of the "root" */
p = strjoina(temp, "/6dots");