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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool path_is_valid(const char *p) {
|
bool path_is_valid_full(const char *p, bool accept_dot_dot) {
|
||||||
if (isempty(p))
|
if (isempty(p))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (const char *e = p;;) {
|
for (const char *e = p;;) {
|
||||||
int r;
|
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)
|
if (r < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,13 @@ int path_extract_filename(const char *p, char **ret);
|
|||||||
int path_extract_directory(const char *p, char **ret);
|
int path_extract_directory(const char *p, char **ret);
|
||||||
|
|
||||||
bool filename_is_valid(const char *p) _pure_;
|
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_;
|
bool path_is_normalized(const char *p) _pure_;
|
||||||
|
|
||||||
char *file_in_same_dir(const char *path, const char *filename);
|
char *file_in_same_dir(const char *path, const char *filename);
|
||||||
|
|||||||
+31
-19
@@ -806,36 +806,48 @@ static void test_filename_is_valid(void) {
|
|||||||
assert_se(filename_is_valid("o.o"));
|
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];
|
char foo[PATH_MAX+2];
|
||||||
const char *c;
|
const char *c;
|
||||||
|
|
||||||
log_info("/* %s */", __func__);
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
assert_se(!path_is_valid(""));
|
test_path_is_valid_and_safe_one("", false);
|
||||||
assert_se(path_is_valid("/bar/foo"));
|
test_path_is_valid_and_safe_one("/bar/foo", true);
|
||||||
assert_se(path_is_valid("/bar/foo/"));
|
test_path_is_valid_and_safe_one("/bar/foo/", true);
|
||||||
assert_se(path_is_valid("/bar/foo/"));
|
test_path_is_valid_and_safe_one("/bar/foo/", true);
|
||||||
assert_se(path_is_valid("//bar//foo//"));
|
test_path_is_valid_and_safe_one("//bar//foo//", true);
|
||||||
assert_se(path_is_valid("/"));
|
test_path_is_valid_and_safe_one("/", true);
|
||||||
assert_se(path_is_valid("/////"));
|
test_path_is_valid_and_safe_one("/////", true);
|
||||||
assert_se(path_is_valid("/////.///.////...///..//."));
|
test_path_is_valid_and_safe_one("/////.///.////...///..//.", true);
|
||||||
assert_se(path_is_valid("."));
|
test_path_is_valid_and_safe_one(".", true);
|
||||||
assert_se(path_is_valid(".."));
|
test_path_is_valid_and_safe_one("..", true);
|
||||||
assert_se(path_is_valid("bar/foo"));
|
test_path_is_valid_and_safe_one("bar/foo", true);
|
||||||
assert_se(path_is_valid("bar/foo/"));
|
test_path_is_valid_and_safe_one("bar/foo/", true);
|
||||||
assert_se(path_is_valid("bar//"));
|
test_path_is_valid_and_safe_one("bar//", true);
|
||||||
|
|
||||||
memset(foo, 'a', sizeof(foo) -1);
|
memset(foo, 'a', sizeof(foo) -1);
|
||||||
char_array_0(foo);
|
char_array_0(foo);
|
||||||
|
|
||||||
assert_se(!path_is_valid(foo));
|
test_path_is_valid_and_safe_one(foo, false);
|
||||||
|
|
||||||
c = strjoina("/xxx/", foo, "/yyy");
|
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"));
|
test_path_is_valid_and_safe_one("foo_bar-333", true);
|
||||||
assert_se(path_is_valid("o.o"));
|
test_path_is_valid_and_safe_one("o.o", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_hidden_or_backup_file(void) {
|
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_filename();
|
||||||
test_path_extract_directory();
|
test_path_extract_directory();
|
||||||
test_filename_is_valid();
|
test_filename_is_valid();
|
||||||
test_path_is_valid();
|
test_path_is_valid_and_safe();
|
||||||
test_hidden_or_backup_file();
|
test_hidden_or_backup_file();
|
||||||
test_skip_dev_prefix();
|
test_skip_dev_prefix();
|
||||||
test_empty_or_root();
|
test_empty_or_root();
|
||||||
|
|||||||
Reference in New Issue
Block a user