]> git.alsa-project.org Git - alsa-lib.git/commitdiff
conf: reject relative include paths that escape the include directory
authorJaroslav Kysela <perex@perex.cz>
Mon, 19 Oct 2026 14:19:58 +0000 (16:19 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 19 Oct 2026 14:24:15 +0000 (16:24 +0200)
Note this is a lexical check only; it does not resolve symlinks (not a filesystem sandbox).

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
include/input.h
src/Versions.in.in
src/conf.c
src/input.c

index 80fc862428f686f3a5183665c6d0652082977b0a..fb1e8c194b6d2f34a7a9396793ed0dbeb8b9f4f3 100644 (file)
@@ -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
index efe1e62ba9485c99972072f22c3bde11d4820c75..b66a07383cd6386eb512205f7a105aca9faeb849 100644 (file)
@@ -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;
index a27e6786e79e64437a0f6160b1e161595c52752e..ef152289b8d7454fb88604bf1d58e79f5ae0979a 100644 (file)
@@ -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.
         */
index 9bd17b0c748b8ad1c2ee7d52a1d9c0f1c24b4bb8..29dbebabcd2be8b2408bcf6804db0d1557212f91 100644 (file)
@@ -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;
+}