Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 327262
b: refs/heads/master
c: 2f6f065
h: refs/heads/master
v: v3
  • Loading branch information
Eric W. Biederman committed Sep 18, 2012
1 parent 61d4ec0 commit 294dbf5
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d20b92ab668cc44fc84bba0001839c5a8013a5cd
refs/heads/master: 2f6f0654ab61961fd0f7701fe3be89ea111f0cda
30 changes: 15 additions & 15 deletions trunk/fs/posix_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ posix_acl_valid(const struct posix_acl *acl)
{
const struct posix_acl_entry *pa, *pe;
int state = ACL_USER_OBJ;
unsigned int id = 0; /* keep gcc happy */
kuid_t prev_uid = INVALID_UID;
kgid_t prev_gid = INVALID_GID;
int needs_mask = 0;

FOREACH_ACL_ENTRY(pa, acl, pe) {
Expand All @@ -87,7 +88,6 @@ posix_acl_valid(const struct posix_acl *acl)
switch (pa->e_tag) {
case ACL_USER_OBJ:
if (state == ACL_USER_OBJ) {
id = 0;
state = ACL_USER;
break;
}
Expand All @@ -96,16 +96,17 @@ posix_acl_valid(const struct posix_acl *acl)
case ACL_USER:
if (state != ACL_USER)
return -EINVAL;
if (pa->e_id == ACL_UNDEFINED_ID ||
pa->e_id < id)
if (!uid_valid(pa->e_uid))
return -EINVAL;
id = pa->e_id + 1;
if (uid_valid(prev_uid) &&
uid_lte(pa->e_uid, prev_uid))
return -EINVAL;
prev_uid = pa->e_uid;
needs_mask = 1;
break;

case ACL_GROUP_OBJ:
if (state == ACL_USER) {
id = 0;
state = ACL_GROUP;
break;
}
Expand All @@ -114,10 +115,12 @@ posix_acl_valid(const struct posix_acl *acl)
case ACL_GROUP:
if (state != ACL_GROUP)
return -EINVAL;
if (pa->e_id == ACL_UNDEFINED_ID ||
pa->e_id < id)
if (!gid_valid(pa->e_gid))
return -EINVAL;
if (gid_valid(prev_gid) &&
gid_lte(pa->e_gid, prev_gid))
return -EINVAL;
id = pa->e_id + 1;
prev_gid = pa->e_gid;
needs_mask = 1;
break;

Expand Down Expand Up @@ -195,15 +198,12 @@ posix_acl_from_mode(umode_t mode, gfp_t flags)
return ERR_PTR(-ENOMEM);

acl->a_entries[0].e_tag = ACL_USER_OBJ;
acl->a_entries[0].e_id = ACL_UNDEFINED_ID;
acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6;

acl->a_entries[1].e_tag = ACL_GROUP_OBJ;
acl->a_entries[1].e_id = ACL_UNDEFINED_ID;
acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3;

acl->a_entries[2].e_tag = ACL_OTHER;
acl->a_entries[2].e_id = ACL_UNDEFINED_ID;
acl->a_entries[2].e_perm = (mode & S_IRWXO);
return acl;
}
Expand All @@ -224,11 +224,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
switch(pa->e_tag) {
case ACL_USER_OBJ:
/* (May have been checked already) */
if (inode->i_uid == current_fsuid())
if (uid_eq(inode->i_uid, current_fsuid()))
goto check_perm;
break;
case ACL_USER:
if (pa->e_id == current_fsuid())
if (uid_eq(pa->e_uid, current_fsuid()))
goto mask;
break;
case ACL_GROUP_OBJ:
Expand All @@ -239,7 +239,7 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
}
break;
case ACL_GROUP:
if (in_group_p(pa->e_id)) {
if (in_group_p(pa->e_gid)) {
found = 1;
if ((pa->e_perm & want) == want)
goto mask;
Expand Down
7 changes: 7 additions & 0 deletions trunk/fs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/fsnotify.h>
#include <linux/audit.h>
#include <linux/vmalloc.h>
#include <linux/posix_acl_xattr.h>

#include <asm/uaccess.h>

Expand Down Expand Up @@ -347,6 +348,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
error = -EFAULT;
goto out;
}
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_from_user(kvalue, size);
}

error = vfs_setxattr(d, kname, kvalue, size, flags);
Expand Down Expand Up @@ -450,6 +454,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,

error = vfs_getxattr(d, kname, kvalue, size);
if (error > 0) {
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_to_user(kvalue, size);
if (size && copy_to_user(value, kvalue, error))
error = -EFAULT;
} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
Expand Down
90 changes: 85 additions & 5 deletions trunk/fs/xattr_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,65 @@
#include <linux/fs.h>
#include <linux/posix_acl_xattr.h>
#include <linux/gfp.h>
#include <linux/user_namespace.h>

/*
* Fix up the uids and gids in posix acl extended attributes in place.
*/
static void posix_acl_fix_xattr_userns(
struct user_namespace *to, struct user_namespace *from,
void *value, size_t size)
{
posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
int count;
kuid_t uid;
kgid_t gid;

if (!value)
return;
if (size < sizeof(posix_acl_xattr_header))
return;
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
return;

count = posix_acl_xattr_count(size);
if (count < 0)
return;
if (count == 0)
return;

for (end = entry + count; entry != end; entry++) {
switch(le16_to_cpu(entry->e_tag)) {
case ACL_USER:
uid = make_kuid(from, le32_to_cpu(entry->e_id));
entry->e_id = cpu_to_le32(from_kuid(to, uid));
break;
case ACL_GROUP:
gid = make_kgid(from, le32_to_cpu(entry->e_id));
entry->e_id = cpu_to_le32(from_kuid(to, uid));
break;
default:
break;
}
}
}

void posix_acl_fix_xattr_from_user(void *value, size_t size)
{
struct user_namespace *user_ns = current_user_ns();
if (user_ns == &init_user_ns)
return;
posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
}

void posix_acl_fix_xattr_to_user(void *value, size_t size)
{
struct user_namespace *user_ns = current_user_ns();
if (user_ns == &init_user_ns)
return;
posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
}

/*
* Convert from extended attribute to in-memory representation.
Expand Down Expand Up @@ -50,12 +108,21 @@ posix_acl_from_xattr(const void *value, size_t size)
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
acl_e->e_id = ACL_UNDEFINED_ID;
break;

case ACL_USER:
acl_e->e_uid =
make_kuid(&init_user_ns,
le32_to_cpu(entry->e_id));
if (!uid_valid(acl_e->e_uid))
goto fail;
break;
case ACL_GROUP:
acl_e->e_id = le32_to_cpu(entry->e_id);
acl_e->e_gid =
make_kgid(&init_user_ns,
le32_to_cpu(entry->e_id));
if (!gid_valid(acl_e->e_gid))
goto fail;
break;

default:
Expand Down Expand Up @@ -89,9 +156,22 @@ posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size)
ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);

for (n=0; n < acl->a_count; n++, ext_entry++) {
ext_entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
ext_entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
ext_entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
const struct posix_acl_entry *acl_e = &acl->a_entries[n];
ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
switch(acl_e->e_tag) {
case ACL_USER:
ext_entry->e_id =
cpu_to_le32(from_kuid(&init_user_ns, acl_e->e_uid));
break;
case ACL_GROUP:
ext_entry->e_id =
cpu_to_le32(from_kgid(&init_user_ns, acl_e->e_gid));
break;
default:
ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
break;
}
}
return real_size;
}
Expand Down
8 changes: 7 additions & 1 deletion trunk/include/linux/posix_acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@
struct posix_acl_entry {
short e_tag;
unsigned short e_perm;
unsigned int e_id;
union {
kuid_t e_uid;
kgid_t e_gid;
#ifndef CONFIG_UIDGID_STRICT_TYPE_CHECKS
unsigned int e_id;
#endif
};
};

struct posix_acl {
Expand Down
12 changes: 12 additions & 0 deletions trunk/include/linux/posix_acl_xattr.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ posix_acl_xattr_count(size_t size)
return size / sizeof(posix_acl_xattr_entry);
}

#ifdef CONFIG_FS_POSIX_ACL
void posix_acl_fix_xattr_from_user(void *value, size_t size);
void posix_acl_fix_xattr_to_user(void *value, size_t size);
#else
static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
{
}
static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
{
}
#endif

struct posix_acl *posix_acl_from_xattr(const void *value, size_t size);
int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size);

Expand Down

0 comments on commit 294dbf5

Please sign in to comment.