mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
path-util: introduce path_is_safe()
The function is similar to path_is_valid(), but it refuses paths which contain ".." component.
This commit is contained in:
@@ -1037,14 +1037,14 @@ bool filename_is_valid(const char *p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool path_is_valid(const char *p) {
|
||||
bool path_is_valid_full(const char *p, bool accept_dot_dot) {
|
||||
if (isempty(p))
|
||||
return false;
|
||||
|
||||
for (const char *e = p;;) {
|
||||
int r;
|
||||
|
||||
r = path_find_first_component(&e, /* accept_dot_dot= */ true, NULL);
|
||||
r = path_find_first_component(&e, accept_dot_dot, NULL);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -155,7 +155,13 @@ int path_extract_filename(const char *p, char **ret);
|
||||
int path_extract_directory(const char *p, char **ret);
|
||||
|
||||
bool filename_is_valid(const char *p) _pure_;
|
||||
bool path_is_valid(const char *p) _pure_;
|
||||
bool path_is_valid_full(const char *p, bool accept_dot_dot) _pure_;
|
||||
static inline bool path_is_valid(const char *p) {
|
||||
return path_is_valid_full(p, true);
|
||||
}
|
||||
static inline bool path_is_safe(const char *p) {
|
||||
return path_is_valid_full(p, false);
|
||||
}
|
||||
bool path_is_normalized(const char *p) _pure_;
|
||||
|
||||
char *file_in_same_dir(const char *path, const char *filename);
|
||||
|
||||
@@ -806,36 +806,48 @@ static void test_filename_is_valid(void) {
|
||||
assert_se(filename_is_valid("o.o"));
|
||||
}
|
||||
|
||||
static void test_path_is_valid(void) {
|
||||
static void test_path_is_valid_and_safe_one(const char *p, bool ret) {
|
||||
log_debug("/* %s(\"%s\")*/", __func__, strnull(p));
|
||||
|
||||
assert_se(path_is_valid(p) == ret);
|
||||
if (ret)
|
||||
ret = !streq(p, "..") &&
|
||||
!startswith(p, "../") &&
|
||||
!endswith(p, "/..") &&
|
||||
!strstr(p, "/../");
|
||||
assert_se(path_is_safe(p) == ret);
|
||||
}
|
||||
|
||||
static void test_path_is_valid_and_safe(void) {
|
||||
char foo[PATH_MAX+2];
|
||||
const char *c;
|
||||
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(!path_is_valid(""));
|
||||
assert_se(path_is_valid("/bar/foo"));
|
||||
assert_se(path_is_valid("/bar/foo/"));
|
||||
assert_se(path_is_valid("/bar/foo/"));
|
||||
assert_se(path_is_valid("//bar//foo//"));
|
||||
assert_se(path_is_valid("/"));
|
||||
assert_se(path_is_valid("/////"));
|
||||
assert_se(path_is_valid("/////.///.////...///..//."));
|
||||
assert_se(path_is_valid("."));
|
||||
assert_se(path_is_valid(".."));
|
||||
assert_se(path_is_valid("bar/foo"));
|
||||
assert_se(path_is_valid("bar/foo/"));
|
||||
assert_se(path_is_valid("bar//"));
|
||||
test_path_is_valid_and_safe_one("", false);
|
||||
test_path_is_valid_and_safe_one("/bar/foo", true);
|
||||
test_path_is_valid_and_safe_one("/bar/foo/", true);
|
||||
test_path_is_valid_and_safe_one("/bar/foo/", true);
|
||||
test_path_is_valid_and_safe_one("//bar//foo//", true);
|
||||
test_path_is_valid_and_safe_one("/", true);
|
||||
test_path_is_valid_and_safe_one("/////", true);
|
||||
test_path_is_valid_and_safe_one("/////.///.////...///..//.", true);
|
||||
test_path_is_valid_and_safe_one(".", true);
|
||||
test_path_is_valid_and_safe_one("..", true);
|
||||
test_path_is_valid_and_safe_one("bar/foo", true);
|
||||
test_path_is_valid_and_safe_one("bar/foo/", true);
|
||||
test_path_is_valid_and_safe_one("bar//", true);
|
||||
|
||||
memset(foo, 'a', sizeof(foo) -1);
|
||||
char_array_0(foo);
|
||||
|
||||
assert_se(!path_is_valid(foo));
|
||||
test_path_is_valid_and_safe_one(foo, false);
|
||||
|
||||
c = strjoina("/xxx/", foo, "/yyy");
|
||||
assert_se(!path_is_valid(c));
|
||||
test_path_is_valid_and_safe_one(c, false);
|
||||
|
||||
assert_se(path_is_valid("foo_bar-333"));
|
||||
assert_se(path_is_valid("o.o"));
|
||||
test_path_is_valid_and_safe_one("foo_bar-333", true);
|
||||
test_path_is_valid_and_safe_one("o.o", true);
|
||||
}
|
||||
|
||||
static void test_hidden_or_backup_file(void) {
|
||||
@@ -983,7 +995,7 @@ int main(int argc, char **argv) {
|
||||
test_path_extract_filename();
|
||||
test_path_extract_directory();
|
||||
test_filename_is_valid();
|
||||
test_path_is_valid();
|
||||
test_path_is_valid_and_safe();
|
||||
test_hidden_or_backup_file();
|
||||
test_skip_dev_prefix();
|
||||
test_empty_or_root();
|
||||
|
||||
Reference in New Issue
Block a user