|
@@ -372,6 +372,31 @@ error_put:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static bool cred_cap_issubset(const struct cred *set, const struct cred *subset)
|
|
|
+{
|
|
|
+ const struct user_namespace *set_ns = set->user_ns;
|
|
|
+ const struct user_namespace *subset_ns = subset->user_ns;
|
|
|
+
|
|
|
+ /* If the two credentials are in the same user namespace see if
|
|
|
+ * the capabilities of subset are a subset of set.
|
|
|
+ */
|
|
|
+ if (set_ns == subset_ns)
|
|
|
+ return cap_issubset(subset->cap_permitted, set->cap_permitted);
|
|
|
+
|
|
|
+ /* The credentials are in a different user namespaces
|
|
|
+ * therefore one is a subset of the other only if a set is an
|
|
|
+ * ancestor of subset and set->euid is owner of subset or one
|
|
|
+ * of subsets ancestors.
|
|
|
+ */
|
|
|
+ for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) {
|
|
|
+ if ((set_ns == subset_ns->parent) &&
|
|
|
+ uid_eq(subset_ns->owner, set->euid))
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* commit_creds - Install new credentials upon the current task
|
|
|
* @new: The credentials to be assigned
|
|
@@ -410,7 +435,7 @@ int commit_creds(struct cred *new)
|
|
|
!gid_eq(old->egid, new->egid) ||
|
|
|
!uid_eq(old->fsuid, new->fsuid) ||
|
|
|
!gid_eq(old->fsgid, new->fsgid) ||
|
|
|
- !cap_issubset(new->cap_permitted, old->cap_permitted)) {
|
|
|
+ !cred_cap_issubset(old, new)) {
|
|
|
if (task->mm)
|
|
|
set_dumpable(task->mm, suid_dumpable);
|
|
|
task->pdeath_signal = 0;
|