ve_devmnt_check() duplicates the option string and tokenises the copy
with strsep(), which advances the passed pointer. It then frees that
advanced pointer instead of the start of the allocation: on success it
is NULL (leaking the kstrdup() buffer), and on the -EPERM exit it points
into the middle of the buffer (freeing an invalid pointer).
Keep the allocation base in its own variable and free that.
Fixes: 263467c864c5 ("ve/fs/devmnt: process mount options")
Signed-off-by: Pavel Tikhomirov <[email protected]>
Feature: ve: ve generic structures
---
fs/namespace.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 3a457588e96d9..4aa09dcf09609 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3139,8 +3139,8 @@ static char *strstr_separated(char *haystack, char
*needle, char sep)
static int ve_devmnt_check(char *options, char *allowed)
{
- char *p;
- char *tmp_options;
+ char *buff, *opts, *p;
+ int err = 0;
if (!options || !*options)
return 0;
@@ -3149,22 +3149,22 @@ static int ve_devmnt_check(char *options, char *allowed)
return -EPERM;
/* strsep() changes provided string: puts '\0' instead of separators */
- tmp_options = kstrdup(options, GFP_KERNEL);
- if (!tmp_options)
+ buff = opts = kstrdup(options, GFP_KERNEL);
+ if (!buff)
return -ENOMEM;
- while ((p = strsep(&tmp_options, ",")) != NULL) {
+ while ((p = strsep(&opts, ",")) != NULL) {
if (!*p)
continue;
if (!strstr_separated(allowed, p, ',')) {
- kfree(tmp_options);
- return -EPERM;
+ err = -EPERM;
+ break;
}
}
- kfree(tmp_options);
- return 0;
+ kfree(buff);
+ return err;
}
static int ve_devmnt_insert(char *options, char *hidden)
--
2.54.0
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel