147 lines
4.1 KiB
Diff
147 lines
4.1 KiB
Diff
Fix CVE-2021-3995:
|
|
|
|
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3995
|
|
https://seclists.org/oss-sec/2022/q1/66
|
|
|
|
Patch copied from upstream source repository:
|
|
|
|
https://github.com/util-linux/util-linux/commit/f3db9bd609494099f0c1b95231c5dfe383346929
|
|
|
|
From f3db9bd609494099f0c1b95231c5dfe383346929 Mon Sep 17 00:00:00 2001
|
|
From: Karel Zak <kzak@redhat.com>
|
|
Date: Wed, 24 Nov 2021 13:53:25 +0100
|
|
Subject: [PATCH] libmount: fix UID check for FUSE umount [CVE-2021-3995]
|
|
|
|
Improper UID check allows an unprivileged user to unmount FUSE
|
|
filesystems of users with similar UID.
|
|
|
|
Signed-off-by: Karel Zak <kzak@redhat.com>
|
|
---
|
|
include/strutils.h | 2 +-
|
|
libmount/src/context_umount.c | 14 +++---------
|
|
libmount/src/mountP.h | 1 +
|
|
libmount/src/optstr.c | 42 +++++++++++++++++++++++++++++++++++
|
|
4 files changed, 47 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/include/strutils.h b/include/strutils.h
|
|
index 6e95707ea..a84d29594 100644
|
|
--- a/include/strutils.h
|
|
+++ b/include/strutils.h
|
|
@@ -106,8 +106,8 @@ static inline char *mem2strcpy(char *dest, const void *src, size_t n, size_t nma
|
|
if (n + 1 > nmax)
|
|
n = nmax - 1;
|
|
|
|
+ memset(dest, '\0', nmax);
|
|
memcpy(dest, src, n);
|
|
- dest[nmax-1] = '\0';
|
|
return dest;
|
|
}
|
|
|
|
diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
|
|
index 173637a15..8773c65ff 100644
|
|
--- a/libmount/src/context_umount.c
|
|
+++ b/libmount/src/context_umount.c
|
|
@@ -453,10 +453,7 @@ static int is_fuse_usermount(struct libmnt_context *cxt, int *errsv)
|
|
struct libmnt_ns *ns_old;
|
|
const char *type = mnt_fs_get_fstype(cxt->fs);
|
|
const char *optstr;
|
|
- char *user_id = NULL;
|
|
- size_t sz;
|
|
- uid_t uid;
|
|
- char uidstr[sizeof(stringify_value(ULONG_MAX))];
|
|
+ uid_t uid, entry_uid;
|
|
|
|
*errsv = 0;
|
|
|
|
@@ -473,11 +470,7 @@ static int is_fuse_usermount(struct libmnt_context *cxt, int *errsv)
|
|
optstr = mnt_fs_get_fs_options(cxt->fs);
|
|
if (!optstr)
|
|
return 0;
|
|
-
|
|
- if (mnt_optstr_get_option(optstr, "user_id", &user_id, &sz) != 0)
|
|
- return 0;
|
|
-
|
|
- if (sz == 0 || user_id == NULL)
|
|
+ if (mnt_optstr_get_uid(optstr, "user_id", &entry_uid) != 0)
|
|
return 0;
|
|
|
|
/* get current user */
|
|
@@ -494,8 +487,7 @@ static int is_fuse_usermount(struct libmnt_context *cxt, int *errsv)
|
|
return 0;
|
|
}
|
|
|
|
- snprintf(uidstr, sizeof(uidstr), "%lu", (unsigned long) uid);
|
|
- return strncmp(user_id, uidstr, sz) == 0;
|
|
+ return uid == entry_uid;
|
|
}
|
|
|
|
/*
|
|
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
|
|
index d43a83541..22442ec55 100644
|
|
--- a/libmount/src/mountP.h
|
|
+++ b/libmount/src/mountP.h
|
|
@@ -399,6 +399,7 @@ extern const struct libmnt_optmap *mnt_optmap_get_entry(
|
|
const struct libmnt_optmap **mapent);
|
|
|
|
/* optstr.c */
|
|
+extern int mnt_optstr_get_uid(const char *optstr, const char *name, uid_t *uid);
|
|
extern int mnt_optstr_remove_option_at(char **optstr, char *begin, char *end);
|
|
extern int mnt_optstr_fix_gid(char **optstr, char *value, size_t valsz, char **next);
|
|
extern int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next);
|
|
diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c
|
|
index 921b9318e..16800f571 100644
|
|
--- a/libmount/src/optstr.c
|
|
+++ b/libmount/src/optstr.c
|
|
@@ -1076,6 +1076,48 @@ int mnt_optstr_fix_user(char **optstr)
|
|
return rc;
|
|
}
|
|
|
|
+/*
|
|
+ * Converts value from @optstr addressed by @name to uid.
|
|
+ *
|
|
+ * Returns: 0 on success, 1 if not found, <0 on error
|
|
+ */
|
|
+int mnt_optstr_get_uid(const char *optstr, const char *name, uid_t *uid)
|
|
+{
|
|
+ char *value = NULL;
|
|
+ size_t valsz = 0;
|
|
+ char buf[sizeof(stringify_value(UINT64_MAX))];
|
|
+ int rc;
|
|
+ uint64_t num;
|
|
+
|
|
+ assert(optstr);
|
|
+ assert(name);
|
|
+ assert(uid);
|
|
+
|
|
+ rc = mnt_optstr_get_option(optstr, name, &value, &valsz);
|
|
+ if (rc != 0)
|
|
+ goto fail;
|
|
+
|
|
+ if (valsz > sizeof(buf) - 1) {
|
|
+ rc = -ERANGE;
|
|
+ goto fail;
|
|
+ }
|
|
+ mem2strcpy(buf, value, valsz, sizeof(buf));
|
|
+
|
|
+ rc = ul_strtou64(buf, &num, 10);
|
|
+ if (rc != 0)
|
|
+ goto fail;
|
|
+ if (num > ULONG_MAX || (uid_t) num != num) {
|
|
+ rc = -ERANGE;
|
|
+ goto fail;
|
|
+ }
|
|
+ *uid = (uid_t) num;
|
|
+
|
|
+ return 0;
|
|
+fail:
|
|
+ DBG(UTILS, ul_debug("failed to convert '%s'= to number [rc=%d]", name, rc));
|
|
+ return rc;
|
|
+}
|
|
+
|
|
/**
|
|
* mnt_match_options:
|
|
* @optstr: options string
|
|
--
|
|
2.34.0
|
|
|