From: Jaroslav Kysela Date: Mon, 19 Oct 2026 14:19:58 +0000 (+0200) Subject: conf: reject relative include paths that escape the include directory X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=a3b1dfbfede63f64e61906b31e64ce2bd2598620;p=alsa-lib.git conf: reject relative include paths that escape the include directory Note this is a lexical check only; it does not resolve symlinks (not a filesystem sandbox). Signed-off-by: Jaroslav Kysela --- diff --git a/include/input.h b/include/input.h index 80fc8624..fb1e8c19 100644 --- a/include/input.h +++ b/include/input.h @@ -82,6 +82,8 @@ char *snd_input_gets(snd_input_t *input, char *str, size_t size); int snd_input_getc(snd_input_t *input); int snd_input_ungetc(snd_input_t *input, int c); +int snd_relative_path_check(const char *path); + /** \} */ #ifdef __cplusplus diff --git a/src/Versions.in.in b/src/Versions.in.in index efe1e62b..b66a0738 100644 --- a/src/Versions.in.in +++ b/src/Versions.in.in @@ -233,4 +233,5 @@ ALSA_1.2.17 { global: @SYMBOL_PREFIX@snd_config_get_llong; + @SYMBOL_PREFIX@snd_relative_path_check; } ALSA_1.2.15; diff --git a/src/conf.c b/src/conf.c index a27e6786..ef152289 100644 --- a/src/conf.c +++ b/src/conf.c @@ -646,6 +646,12 @@ static int input_stdio_open(snd_input_t **inputp, const char *file, if (file[0] == '/') return snd_input_stdio_open(inputp, file, "r"); + err = snd_relative_path_check(file); + if (err < 0) { + snd_error(CONFIG, "Include file path '%s' escapes the include directory", file); + return err; + } + /* search file in user specified include paths. These directories * are subdirectories of /usr/share/alsa. */ diff --git a/src/input.c b/src/input.c index 9bd17b0c..29dbebab 100644 --- a/src/input.c +++ b/src/input.c @@ -335,3 +335,45 @@ int snd_input_buffer_open(snd_input_t **inputp, const char *buf, ssize_t size) return 0; } +/* + * \brief Verify that a relative path does not escape its base directory via ".." components. + * \param path Relative path to check. + * \return Zero if successful, otherwise -EINVAL. + * + * The check is purely lexical. + * + * Examples (base = root directory): + * a/../b -> allowed (depth: 1, 0, 1) + * ../b -> rejected (depth: -1) + * a/b/c/../d/../../../../../x -> rejected + */ +int snd_relative_path_check(const char *path) +{ + const char *p = path; + int depth = 0; + + while (*p) { + const char *comp = p; + size_t len; + + while (*p && *p != '/') + p++; + len = p - comp; + + while (*p == '/') + p++; + + if (len == 0) + continue; + if (len == 1 && comp[0] == '.') + continue; + if (len == 2 && comp[0] == '.' && comp[1] == '.') { + if (--depth < 0) + return -EINVAL; + continue; + } + depth++; + } + + return 0; +}