Skip to content
Permalink
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
karelzak committed Jan 24, 2022
1 parent f5ea9ee commit 57202f5
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 11 deletions.
14 changes: 3 additions & 11 deletions libmount/src/context_umount.c
Expand Up @@ -452,10 +452,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;

Expand All @@ -472,11 +469,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 */
Expand All @@ -493,8 +486,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;
}

/*
Expand Down
1 change: 1 addition & 0 deletions libmount/src/mountP.h
Expand Up @@ -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);
Expand Down
42 changes: 42 additions & 0 deletions libmount/src/optstr.c
Expand Up @@ -1083,6 +1083,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
Expand Down

0 comments on commit 57202f5

Please sign in to comment.