From a47c8bc3fef190e7eb463283230263c82208597a Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Thu, 1 Oct 2026 00:29:06 +0530 Subject: [PATCH] ucm: confine sysw and cfg-save paths with realpath() 1: execute_sysw() concatenated the sysfs root with a caller path via snprintf() with no traversal check. Use realpath() and reject paths that escape the sysfs root. 2: execute_cfgsave() opened a caller-supplied filename with no restriction. Confine writes to XDG_RUNTIME_DIR (or /tmp) via realpath(). [ rewritten with check_realpath() helper function -- tiwai ] Closes: https://github.com/alsa-project/alsa-lib/pull/527 Signed-off-by: Harsh Raj Singhania Signed-off-by: Takashi Iwai --- src/ucm/main.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/ucm/main.c b/src/ucm/main.c index d2b3c2d9..b27e71f0 100644 --- a/src/ucm/main.c +++ b/src/ucm/main.c @@ -523,6 +523,20 @@ static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) return err; } +static bool check_realpath(const char *path, const char *target) +{ + char *resolved = realpath(path, NULL); + + if (!resolved) + return false; + if (strncmp(resolved, target, strlen(target)) != 0) { + free(resolved); + return false; + } + free(resolved); + return true; +} + static int execute_sysw(const char *sysw) { char path[PATH_MAX]; @@ -570,6 +584,12 @@ static int execute_sysw(const char *sysw) } snprintf(path, sizeof(path), "%s/%s", e, s); + if (!check_realpath(path, e)) { + free(s); + snd_error(UCM, "sysw path escapes sysfs root: '%s'", path); + return -EINVAL; + } + fd = open(path, O_WRONLY|O_CLOEXEC); if (fd < 0) { free(s); @@ -603,6 +623,7 @@ static int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename) snd_config_t *config = uc_mgr->local_config; char *file, *root; snd_output_t *out; + const char *runtime; bool with_root = false; int err = 0; @@ -625,6 +646,13 @@ static int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename) } } + runtime = getenv("XDG_RUNTIME_DIR"); + if (!runtime) + runtime = "/tmp"; + if (!check_realpath(file, runtime)) { + snd_error(UCM, "cfg-save path escapes runtime dir: '%s'", file); + return -EINVAL; + } err = snd_output_stdio_open(&out, file, "w+"); if (err < 0) { snd_error(UCM, "unable to open file '%s': %s", file, snd_strerror(err)); -- 2.52.0