Skip to content

Commit

Permalink
Take user namespaces into account in policy checks
Browse files Browse the repository at this point in the history
Change file related checks to use user namespaces and make
sure involved uids/gids are mappable in the current
namespace.

Note that checks without file ownership information will
still not take user namespaces into account, as some of
these should be handled via 'zfs allow' (otherwise root in a
user namespace could issue commands such as `zpool export`).

Signed-off-by: Wolfgang Bumiller <[email protected]>
Closes openzfs#6800
  • Loading branch information
Blub committed Nov 8, 2017
1 parent 87fbf43 commit 5b7b119
Showing 1 changed file with 35 additions and 8 deletions.
43 changes: 35 additions & 8 deletions module/zfs/policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,32 @@
* all other cases this function must fail and return the passed err.
*/
static int
priv_policy(const cred_t *cr, int capability, boolean_t all, int err)
priv_policy_ns(const cred_t *cr, int capability, boolean_t all, int err,
struct user_namespace *ns)
{
ASSERT3S(all, ==, B_FALSE);

if (cr != CRED() && (cr != kcred))
return (err);

if (!capable(capability))
if (!(ns ? ns_capable(ns, capability) : capable(capability)))
return (err);

return (0);
}

static int
priv_policy(const cred_t *cr, int capability, boolean_t all, int err)
{
return priv_policy_ns(cr, capability, all, err, NULL);
}

static int
priv_policy_user(const cred_t *cr, int capability, boolean_t all, int err)
{
return priv_policy_ns(cr, capability, all, err, cr->user_ns);
}

/*
* Checks for operations that are either client-only or are used by
* both clients and servers.
Expand Down Expand Up @@ -102,10 +115,13 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner)
if (zpl_inode_owner_or_capable(ip))
return (0);

if (priv_policy(cr, CAP_DAC_OVERRIDE, B_FALSE, EPERM) == 0)
if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
return (EPERM);

if (priv_policy_user(cr, CAP_DAC_OVERRIDE, B_FALSE, EPERM) == 0)
return (0);

if (priv_policy(cr, CAP_DAC_READ_SEARCH, B_FALSE, EPERM) == 0)
if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, B_FALSE, EPERM) == 0)
return (0);

return (EPERM);
Expand All @@ -120,7 +136,10 @@ secpolicy_vnode_chown(const cred_t *cr, uid_t owner)
if (crgetfsuid(cr) == owner)
return (0);

return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM));
if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
return (EPERM);

return (priv_policy_user(cr, CAP_FOWNER, B_FALSE, EPERM));
}

/*
Expand Down Expand Up @@ -152,7 +171,10 @@ secpolicy_vnode_setdac(const cred_t *cr, uid_t owner)
if (crgetfsuid(cr) == owner)
return (0);

return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM));
if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
return (EPERM);

return (priv_policy_user(cr, CAP_FOWNER, B_FALSE, EPERM));
}

/*
Expand All @@ -175,8 +197,10 @@ secpolicy_vnode_setid_retain(const cred_t *cr, boolean_t issuidroot)
int
secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid)
{
if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid)))
return (EPERM);
if (crgetfsgid(cr) != gid && !groupmember(gid, cr))
return (priv_policy(cr, CAP_FSETID, B_FALSE, EPERM));
return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM));

return (0);
}
Expand Down Expand Up @@ -222,7 +246,10 @@ secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner)
if (crgetfsuid(cr) == owner)
return (0);

return (priv_policy(cr, CAP_FSETID, B_FALSE, EPERM));
if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner)))
return (EPERM);

return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM));
}

/*
Expand Down

0 comments on commit 5b7b119

Please sign in to comment.