@@ -463,23 +463,28 @@ richacl_set_owner_permissions(struct richacl_alloc *alloc)
/**
* richacl_set_other_permissions - set the other permissions to the other mask
+ * @alloc: acl and number of allocated entries
+ * @added: permissions added for everyone@
*
* Change the acl so that everyone@ is granted the permissions set in the other
* mask. This leaves at most one efective everyone@ allow entry at the end of
- * the acl.
+ * the acl. If everyone@ end up being granted additional permissions, these
+ * permissions are returned in @added.
*/
static int
-richacl_set_other_permissions(struct richacl_alloc *alloc)
+richacl_set_other_permissions(struct richacl_alloc *alloc, unsigned int *added)
{
struct richacl *acl = alloc->acl;
unsigned int x = RICHACE_POSIX_ALWAYS_ALLOWED;
unsigned int other_mask = acl->a_other_mask & ~x;
- struct richace *ace = acl->a_entries + acl->a_count - 1;
+ struct richace *ace;
if (!(other_mask &&
(acl->a_flags & RICHACL_WRITE_THROUGH)))
return 0;
+ *added = other_mask;
+ ace = acl->a_entries + acl->a_count - 1;
if (acl->a_count == 0 ||
!richace_is_everyone(ace) ||
richace_is_inherit_only(ace)) {
@@ -490,8 +495,10 @@ richacl_set_other_permissions(struct richacl_alloc *alloc)
ace->e_flags = RICHACE_SPECIAL_WHO;
ace->e_mask = other_mask;
ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
- } else
+ } else {
+ *added &= ~ace->e_mask;
richace_change_mask(alloc, &ace, other_mask);
+ }
return 0;
}
@@ -645,6 +652,7 @@ __richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
/**
* richacl_isolate_group_class - limit the group class to the group file mask
* @alloc: acl and number of allocated entries
+ * @deny: additional permissions to deny
*
* POSIX requires that after a chmod, the group class is granted no more
* permissions than the group file permission bits. For richacls, this
@@ -679,21 +687,20 @@ __richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
* everyone@:rw::allow
*/
static int
-richacl_isolate_group_class(struct richacl_alloc *alloc)
+richacl_isolate_group_class(struct richacl_alloc *alloc, unsigned int deny)
{
struct richace who = {
.e_flags = RICHACE_SPECIAL_WHO,
.e_id.special = RICHACE_GROUP_SPECIAL_ID,
};
struct richace *ace;
- unsigned int deny;
if (!alloc->acl->a_count)
return 0;
ace = alloc->acl->a_entries + alloc->acl->a_count - 1;
if (richace_is_inherit_only(ace) || !richace_is_everyone(ace))
return 0;
- deny = ace->e_mask & ~alloc->acl->a_group_mask;
+ deny |= ace->e_mask & ~alloc->acl->a_group_mask;
if (deny) {
unsigned int n;
@@ -806,16 +813,17 @@ richacl_apply_masks(struct richacl **acl, kuid_t owner)
.acl = richacl_clone(*acl, GFP_KERNEL),
.count = (*acl)->a_count,
};
+ unsigned int added = 0;
+
if (!alloc.acl)
return -ENOMEM;
-
if (richacl_move_everyone_aces_down(&alloc) ||
richacl_propagate_everyone(&alloc) ||
__richacl_apply_masks(&alloc, owner) ||
+ richacl_set_other_permissions(&alloc, &added) ||
+ richacl_isolate_group_class(&alloc, added) ||
richacl_set_owner_permissions(&alloc) ||
- richacl_set_other_permissions(&alloc) ||
- richacl_isolate_owner_class(&alloc) ||
- richacl_isolate_group_class(&alloc)) {
+ richacl_isolate_owner_class(&alloc)) {
richacl_put(alloc.acl);
return -ENOMEM;
}