From ec1b0eb36bd6c5a5079293ab03241163f61a8bf4 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 28 Nov 2023 14:40:48 +0100 Subject: [PATCH] libmount: accept '\' as escape for options separator The libmount library can accept any characters as an option value when the value is quoted (e.g., foo="b,a,r"). However, overlayfs users have been using '\' as an escape character (e.g., lowerdir=foo\,bar). Although this escaping mechanism was never officially supported by libmount/mount, it worked for the old mount(2) API because it kept the options string unparsed for the mount(2) syscall. The introduction of the new mount API, which utilizes fsconfig(2) per option, has brought attention to this issue. This patch addresses the problem by introducing official support for '\' as an escape character for options separator. Suggested-by: Miklos Szeredi References: https://lore.kernel.org/all/CAOQ4uxhgUSPkYAV8SJu-SFszkJcVO3-M4DXf46nJUtXODrPk2g@mail.gmail.com/T/#ma8e6cfc1ce7229abc089e03eed99b23b90d701e5 Signed-off-by: Karel Zak (cherry picked from commit f6c29efa929cb8c741591ab38061e7921d53a997) --- lib/strutils.c | 2 +- libmount/src/hook_mount.c | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/strutils.c b/lib/strutils.c index 21751fd89e..6229a6e676 100644 --- a/lib/strutils.c +++ b/lib/strutils.c @@ -1190,7 +1190,7 @@ int ul_optstr_next(char **optstr, char **name, size_t *namesz, continue; /* still in quoted block */ if (!sep && p > start && *p == '=') sep = p; /* name and value separator */ - if (*p == ',') + if (*p == ',' && (p == optstr0 || *(p - 1) != '\\')) stop = p; /* terminate the option item */ else if (*(p + 1) == '\0') stop = p + 1; /* end of optstr */ diff --git a/libmount/src/hook_mount.c b/libmount/src/hook_mount.c index 4b2a534f74..dc3dfa71ad 100644 --- a/libmount/src/hook_mount.c +++ b/libmount/src/hook_mount.c @@ -45,6 +45,7 @@ #include "mountP.h" #include "fileutils.h" /* statx() fallback */ +#include "strutils.h" #include "mount-api-utils.h" #include "linux_version.h" @@ -121,12 +122,23 @@ static inline int fsconfig_set_value( const char *name, const char *value) { int rc; + char *p = NULL; - DBG(HOOK, ul_debugobj(hs, " fsconfig(name=%s,value=%s)", name, + if (value && strstr(value, "\\,")) { + p = strdup(value); + if (!p) + return -EINVAL; + + strrem(p, '\\'); + value = p; + } + + DBG(HOOK, ul_debugobj(hs, " fsconfig(name=\"%s\" value=\"%s\")", name, value ? : "")); - if (value) + if (value) { rc = fsconfig(fd, FSCONFIG_SET_STRING, name, value, 0); - else + free(p); + } else rc = fsconfig(fd, FSCONFIG_SET_FLAG, name, NULL, 0); set_syscall_status(cxt, "fsconfig", rc == 0); -- 2.47.2