diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2021-11-01 10:57:28 -0400 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2021-11-09 15:17:17 +0000 |
commit | bef02d3e638ce8c95c9e63622b46d87a0f8ee2b2 (patch) | |
tree | 5982af2e8e7f3b2996dcc65edcd5d3f42bd04118 | |
parent | 63e36c53caa8c3f1581471de64bbef3ca87f3921 (diff) | |
download | libgit2-bef02d3e638ce8c95c9e63622b46d87a0f8ee2b2.tar.gz |
fs_path: introduce `str_is_valid`
Provide a mechanism for users to limit the number of characters that are
examined; `git_fs_path_str_is_valid` and friends will only examine up to
`str->size` bytes.
`git_fs_path_is_valid` delegates to these new functions by passing
`SIZE_MAX` (instead of doing a `strlen`), which is a sentinel value
meaning "look for a NUL terminator".
-rw-r--r-- | src/fs_path.c | 21 | ||||
-rw-r--r-- | src/fs_path.h | 52 | ||||
-rw-r--r-- | tests/path/core.c | 27 |
3 files changed, 81 insertions, 19 deletions
diff --git a/src/fs_path.c b/src/fs_path.c index ceba02d62..fa27a6e73 100644 --- a/src/fs_path.c +++ b/src/fs_path.c @@ -1634,16 +1634,17 @@ static bool validate_component( return true; } -bool git_fs_path_is_valid_ext( - const char *path, +bool git_fs_path_is_valid_str_ext( + const git_str *path, unsigned int flags, bool (*validate_char_cb)(char ch, void *payload), bool (*validate_component_cb)(const char *component, size_t len, void *payload), void *payload) { const char *start, *c; + size_t len = 0; - for (start = c = path; *c; c++) { + for (start = c = path->ptr; *c && len < path->size; c++, len++) { if (!validate_char(*c, flags)) return false; @@ -1663,6 +1664,15 @@ bool git_fs_path_is_valid_ext( start = c + 1; } + /* + * We want to support paths specified as either `const char *` + * or `git_str *`; we pass size as `SIZE_MAX` when we use a + * `const char *` to avoid a `strlen`. Ensure that we didn't + * have a NUL in the buffer if there was a non-SIZE_MAX length. + */ + if (path->size != SIZE_MAX && len != path->size) + return false; + if (!validate_component(start, (c - start), flags)) return false; @@ -1673,11 +1683,6 @@ bool git_fs_path_is_valid_ext( return true; } -bool git_fs_path_is_valid(const char *path, unsigned int flags) -{ - return git_fs_path_is_valid_ext(path, flags, NULL, NULL, NULL); -} - #ifdef GIT_WIN32 GIT_INLINE(bool) should_validate_longpaths(git_repository *repo) { diff --git a/src/fs_path.h b/src/fs_path.h index 991e7cd83..2f4bc9f79 100644 --- a/src/fs_path.h +++ b/src/fs_path.h @@ -621,25 +621,55 @@ extern int git_fs_path_from_url_or_path(git_str *local_path_out, const char *url #endif /** - * Validate a filesystem path. This ensures that the given path is legal - * and does not contain any "unsafe" components like path traversal ('.' - * or '..'), characters that are inappropriate for lesser filesystems - * (trailing ' ' or ':' characters), or filenames ("component names") - * that are not supported ('AUX', 'COM1"). - */ -extern bool git_fs_path_is_valid(const char *path, unsigned int flags); - -/** * Validate a filesystem path; with custom callbacks per-character and * per-path component. */ -extern bool git_fs_path_is_valid_ext( - const char *path, +extern bool git_fs_path_is_valid_str_ext( + const git_str *path, unsigned int flags, bool (*validate_char_cb)(char ch, void *payload), bool (*validate_component_cb)(const char *component, size_t len, void *payload), void *payload); +GIT_INLINE(bool) git_fs_path_is_valid_ext( + const char *path, + unsigned int flags, + bool (*validate_char_cb)(char ch, void *payload), + bool (*validate_component_cb)(const char *component, size_t len, void *payload), + void *payload) +{ + const git_str str = GIT_STR_INIT_CONST(path, SIZE_MAX); + return git_fs_path_is_valid_str_ext( + &str, + flags, + validate_char_cb, + validate_component_cb, + payload); +} + +/** + * Validate a filesystem path. This ensures that the given path is legal + * and does not contain any "unsafe" components like path traversal ('.' + * or '..'), characters that are inappropriate for lesser filesystems + * (trailing ' ' or ':' characters), or filenames ("component names") + * that are not supported ('AUX', 'COM1"). + */ +GIT_INLINE(bool) git_fs_path_is_valid( + const char *path, + unsigned int flags) +{ + const git_str str = GIT_STR_INIT_CONST(path, SIZE_MAX); + return git_fs_path_is_valid_str_ext(&str, flags, NULL, NULL, NULL); +} + +/** Validate a filesystem path in a `git_str`. */ +GIT_INLINE(bool) git_fs_path_is_valid_str( + const git_str *path, + unsigned int flags) +{ + return git_fs_path_is_valid_str_ext(path, flags, NULL, NULL, NULL); +} + /** * Validate an on-disk path, taking into account that it will have a * suffix appended (eg, `.lock`). diff --git a/tests/path/core.c b/tests/path/core.c index f48a76957..6fa0450ca 100644 --- a/tests/path/core.c +++ b/tests/path/core.c @@ -64,6 +64,33 @@ void test_path_core__isvalid_standard(void) cl_assert_equal_b(true, git_fs_path_is_valid("foo/bar/.file", 0)); } +/* Ensure that `is_valid_str` only reads str->size bytes */ +void test_path_core__isvalid_standard_str(void) +{ + git_str str = GIT_STR_INIT_CONST("foo/bar//zap", 0); + + str.size = 0; + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + + str.size = 3; + cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, 0)); + + str.size = 4; + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + + str.size = 5; + cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, 0)); + + str.size = 7; + cl_assert_equal_b(true, git_fs_path_is_valid_str(&str, 0)); + + str.size = 8; + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); + + str.size = strlen(str.ptr); + cl_assert_equal_b(false, git_fs_path_is_valid_str(&str, 0)); +} + void test_path_core__isvalid_empty_dir_component(void) { cl_assert_equal_b(false, git_fs_path_is_valid("foo//bar", 0)); |