]> git.alsa-project.org Git - alsa-lib.git/commitdiff
conf,ucm,topology: reject relative paths that escape their base directory HEAD master
authorJaroslav Kysela <perex@perex.cz>
Mon, 19 Oct 2026 14:31:54 +0000 (16:31 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 19 Oct 2026 18:16:40 +0000 (20:16 +0200)
Apply the lexical snd_relative_path_check() guard to more places.

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/conf.c
src/topology/data.c
src/ucm/main.c
src/ucm/parser.c
src/ucm/ucm_subs.c

index ef152289b8d7454fb88604bf1d58e79f5ae0979a..d0e4ec90c5578ea635e46e6669eda95eae18e3d0 100644 (file)
@@ -809,7 +809,14 @@ static int get_char_skip_comments(input_t *input)
 
                        if (!strncmp(str, "searchdir:", 10)) {
                                /* directory to search included files */
-                               char *tmp = _snd_config_path(str + 10);
+                               char *tmp;
+                               err = snd_relative_path_check(str + 10);
+                               if (err < 0) {
+                                       snd_error(CONFIG, "Search dir path '%s' escapes the configuration directory", str + 10);
+                                       free(str);
+                                       return err;
+                               }
+                               tmp = _snd_config_path(str + 10);
                                free(str);
                                if (tmp == NULL)
                                        return -ENOMEM;
@@ -835,7 +842,14 @@ static int get_char_skip_comments(input_t *input)
 
                        if (!strncmp(str, "confdir:", 8)) {
                                /* file in the specified directory */
-                               char *tmp = _snd_config_path(str + 8);
+                               char *tmp;
+                               err = snd_relative_path_check(str + 8);
+                               if (err < 0) {
+                                       snd_error(CONFIG, "Config dir path '%s' escapes the configuration directory", str + 8);
+                                       free(str);
+                                       return err;
+                               }
+                               tmp = _snd_config_path(str + 8);
                                free(str);
                                if (tmp == NULL)
                                        return -ENOMEM;
index 1753d0c7ae18868730c8a45c0540f2cfa09e530a..144af63181a32134b59ddef1e42ff02d7e62b54c 100644 (file)
@@ -175,6 +175,11 @@ static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
        if (snd_config_get_string(cfg, &value) < 0)
                return -EINVAL;
 
+       if (snd_relative_path_check(value) < 0) {
+               snd_error(TOPOLOGY, "data file path '%s' escapes the topology directory", value);
+               return -EINVAL;
+       }
+
        /* prepend alsa config directory to path */
        if (env)
                snprintf(filename, sizeof(filename), "%s/%s", env, value);
index d2b3c2d93b82167edc4937de1be77d6bfbda4196..c31d8f985ed3836d8351922d65d559aa1a9fa67b 100644 (file)
@@ -563,6 +563,12 @@ static int execute_sysw(const char *sysw)
                return -EINVAL;
        }
 
+       if (snd_relative_path_check(s) < 0) {
+               snd_error(UCM, "sysw path '%s' escapes the sysfs root", s);
+               free(s);
+               return -EINVAL;
+       }
+
        e = uc_mgr_sysfs_root();
        if (e == NULL) {
                free(s);
index 4cde91941b6eaef3cf2242d0db2f844bd4e8ed4c..fdd39902a1e39aa14f1c2171add0566029291210 100644 (file)
@@ -46,13 +46,19 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
 /*
  * compose the absolute ucm filename
  */
-static void ucm_filename(char *fn, size_t fn_len, long version,
-                         const char *dir, const char *file)
+static int ucm_filename(char *fn, size_t fn_len, long version,
+                        const char *dir, const char *file)
 {
        const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR);
 
        if (file[0] == '/')
                file++;
+       if (snd_relative_path_check(file) < 0 ||
+           (dir && snd_relative_path_check(dir) < 0)) {
+               snd_error(UCM, "config file path '%s%s%s' escapes the configuration directory",
+                         dir ?: "", dir ? "/" : "", file);
+               return -EINVAL;
+       }
        if (env == NULL)
                snprintf(fn, fn_len, "%s/%s/%s%s%s",
                         snd_config_topdir(), version > 1 ? "ucm2" : "ucm",
@@ -60,6 +66,7 @@ static void ucm_filename(char *fn, size_t fn_len, long version,
        else
                snprintf(fn, fn_len, "%s/%s%s%s",
                         env, dir ?: "", dir ? "/" : "", file);
+       return 0;
 }
 
 /*
@@ -71,9 +78,11 @@ int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr,
        char filename[PATH_MAX];
        int err;
 
-       ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
-                    file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
-                    file);
+       err = ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
+                          file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
+                          file);
+       if (err < 0)
+               return err;
        err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg, optional);
        if (err < 0) {
                if (!optional || (err != -ENOENT && err != -EACCES))
@@ -842,9 +851,11 @@ static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
                } else {
                        char filename[PATH_MAX];
 
-                       ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
-                                    file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
-                                    file);
+                       err = ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
+                                          file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
+                                          file);
+                       if (err < 0)
+                               return err;
                        err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config, false);
                        if (err < 0)
                                return err;
@@ -3438,7 +3449,8 @@ static int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr,
                        goto __next;
                }
 
-               ucm_filename(fn, sizeof(fn), version, dir, file);
+               if (ucm_filename(fn, sizeof(fn), version, dir, file) < 0)
+                       goto __next;
                snd_trace(UCM, "probing configuration file '%s'", fn);
                if (access(fn, R_OK) == 0 && lstat64(fn, &st) == 0) {
                        if (S_ISLNK(st.st_mode)) {
@@ -3785,7 +3797,8 @@ int uc_mgr_scan_master_configs(const char **_list[])
                d_name = namelist[i]->d_name;
 
                snprintf(fn, sizeof(fn), "%s.conf", d_name);
-               ucm_filename(filename, sizeof(filename), 2, d_name, fn);
+               if (ucm_filename(filename, sizeof(filename), 2, d_name, fn) < 0)
+                       continue;
 #ifdef HAVE_EACCESS
                if (eaccess(filename, R_OK))
 #else
index c8b13648bc93b55d6160f9c696a3aa3fa8767449..e4a238a9f8921b96cf76f76b1099b8a81947b4a1 100644 (file)
@@ -736,6 +736,10 @@ static char *rval_sysfs_main(snd_use_case_mgr_t *uc_mgr, const char *top_path, c
        }
        if (id[0] == '/')
                id++;
+       if (snd_relative_path_check(id) < 0) {
+               snd_error(UCM, "sysfs path '%s' escapes the sysfs root", id);
+               return NULL;
+       }
        if (top_path)
                snprintf(path, sizeof(path), "%s/%s/%s", e, top_path, id);
        else