libext2fs: translate internal ext4 acl to Posix ACL in ext2fs_xattr_[sg]et()

ext2fs_xattr_[sg]et() will now translate the Posix ACL xattrs to and
from the internal ext4 attr format, since the callers of the libext2fs
are much more likely to want to use the public Posix ACL format.

For debugfs and those applications that want to see the on-disk
format, the new ext4fs_xattr_flags() function will allow those callers
to request the raw format.

Addresses-Launchpad-Bug: #1645232

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Theodore Ts'o 2017-01-28 22:34:16 -05:00
parent 997e213ba4
commit 0ee1eaf70c
6 changed files with 258 additions and 24 deletions

View File

@ -146,10 +146,11 @@ void do_get_xattr(int argc, char **argv)
size_t buflen;
int i;
int print_flags = 0;
int handle_flags = 0;
errcode_t err;
reset_getopt();
while ((i = getopt(argc, argv, "Cf:xV")) != -1) {
while ((i = getopt(argc, argv, "Cf:rxV")) != -1) {
switch (i) {
case 'f':
if (fp)
@ -160,6 +161,9 @@ void do_get_xattr(int argc, char **argv)
return;
}
break;
case 'r':
handle_flags |= XATTR_HANDLE_FLAG_RAW;
break;
case 'x':
print_flags |= PRINT_XATTR_HEX;
break;
@ -176,8 +180,9 @@ void do_get_xattr(int argc, char **argv)
if (optind != argc - 2) {
usage:
printf("%s: Usage: %s <file> <attr> [-f outfile]|[-xVC]\n",
printf("%s: Usage: %s [-f outfile]|[-xVC] [-r] <file> <attr>\n",
argv[0], argv[0]);
goto out2;
}
@ -192,6 +197,10 @@ void do_get_xattr(int argc, char **argv)
if (err)
goto out2;
err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
if (err)
goto out;
err = ext2fs_xattrs_read(h);
if (err)
goto out;
@ -231,11 +240,13 @@ void do_set_xattr(int argc, char **argv)
FILE *fp = NULL;
char *buf = NULL;
size_t buflen;
int print_flags = 0;
int handle_flags = 0;
int i;
errcode_t err;
reset_getopt();
while ((i = getopt(argc, argv, "f:")) != -1) {
while ((i = getopt(argc, argv, "f:r")) != -1) {
switch (i) {
case 'f':
if (fp)
@ -246,6 +257,9 @@ void do_set_xattr(int argc, char **argv)
return;
}
break;
case 'r':
handle_flags |= XATTR_HANDLE_FLAG_RAW;
break;
default:
goto print_usage;
}
@ -254,7 +268,7 @@ void do_set_xattr(int argc, char **argv)
if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) {
print_usage:
printf("Usage:\t%s <file> <attr> <value>\n", argv[0]);
printf("\t%s -f <value_file> <file> <attr>\n", argv[0]);
printf("\t%s -f <value_file> [-r] <file> <attr>\n", argv[0]);
goto out2;
}
@ -273,6 +287,10 @@ void do_set_xattr(int argc, char **argv)
if (err)
goto out2;
err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
if (err)
goto out;
err = ext2fs_xattrs_read(h);
if (err)
goto out;

View File

@ -789,8 +789,8 @@ expanddir.o: $(srcdir)/expanddir.c $(top_builddir)/lib/config.h \
ext_attr.o: $(srcdir)/ext_attr.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2_ext_attr.h \
$(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
$(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
$(srcdir)/ext4_acl.h $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h \
$(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
$(srcdir)/bitops.h
extent.o: $(srcdir)/extent.c $(top_builddir)/lib/config.h \
@ -1319,11 +1319,11 @@ quota.o: $(top_srcdir)/debugfs/quota.c $(top_builddir)/lib/config.h \
$(top_srcdir)/lib/support/dqblk_v2.h \
$(top_srcdir)/lib/support/quotaio_tree.h
xattrs.o: $(top_srcdir)/debugfs/xattrs.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
$(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
$(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/support/cstring.h \
$(top_srcdir)/debugfs/debugfs.h $(top_srcdir)/lib/ss/ss.h \
$(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(srcdir)/ext2fs.h $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
$(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
$(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \

View File

@ -1218,6 +1218,9 @@ errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count);
errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
size_t *size);
#define XATTR_HANDLE_FLAG_RAW 0x0001
errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle,
unsigned int *new_flags, unsigned int *old_flags);
/* extent.c */
extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);

55
lib/ext2fs/ext4_acl.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Ext4's on-disk acl format. From linux/fs/ext4/acl.h
*/
#define EXT4_ACL_VERSION 0x0001
/* 23.2.5 acl_tag_t values */
#define ACL_UNDEFINED_TAG (0x00)
#define ACL_USER_OBJ (0x01)
#define ACL_USER (0x02)
#define ACL_GROUP_OBJ (0x04)
#define ACL_GROUP (0x08)
#define ACL_MASK (0x10)
#define ACL_OTHER (0x20)
/* 23.3.6 acl_type_t values */
#define ACL_TYPE_ACCESS (0x8000)
#define ACL_TYPE_DEFAULT (0x4000)
/* 23.2.7 ACL qualifier constants */
#define ACL_UNDEFINED_ID ((id_t)-1)
typedef struct {
__le16 e_tag;
__le16 e_perm;
__le32 e_id;
} ext4_acl_entry;
typedef struct {
__le16 e_tag;
__le16 e_perm;
} ext4_acl_entry_short;
typedef struct {
__le32 a_version;
} ext4_acl_header;
/* Supported ACL a_version fields */
#define POSIX_ACL_XATTR_VERSION 0x0002
typedef struct {
__le16 e_tag;
__le16 e_perm;
__le32 e_id;
} posix_acl_xattr_entry;
typedef struct {
__le32 a_version;
posix_acl_xattr_entry a_entries[0];
} posix_acl_xattr_header;

View File

@ -21,6 +21,7 @@
#include "ext2_fs.h"
#include "ext2_ext_attr.h"
#include "ext4_acl.h"
#include "ext2fs.h"
@ -215,6 +216,7 @@ struct ext2_xattr_handle {
struct ext2_xattr *attrs;
size_t length, count;
ext2_ino_t ino;
unsigned int flags;
int dirty;
};
@ -452,6 +454,136 @@ out:
}
static inline int
posix_acl_xattr_count(size_t size)
{
if (size < sizeof(posix_acl_xattr_header))
return -1;
size -= sizeof(posix_acl_xattr_header);
if (size % sizeof(posix_acl_xattr_entry))
return -1;
return size / sizeof(posix_acl_xattr_entry);
}
/*
* The lgetxattr function returns data formatted in the POSIX extended
* attribute format. The on-disk format uses a more compact encoding.
* See the ext4_acl_to_disk in fs/ext4/acl.c.
*/
static errcode_t convert_posix_acl_to_disk_buffer(const void *value, size_t size,
void *out_buf, size_t *size_out)
{
posix_acl_xattr_header *header = (posix_acl_xattr_header*) value;
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
ext4_acl_header *ext_acl;
size_t s;
void *e;
int err;
int count;
if (!value)
return EINVAL;
if (size < sizeof(posix_acl_xattr_header))
return ENOMEM;
if (header->a_version != ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION))
return EINVAL;
count = posix_acl_xattr_count(size);
ext_acl = out_buf;
ext_acl->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION);
if (count <= 0)
return EINVAL;
e = (char *) out_buf + sizeof(ext4_acl_header);
s = sizeof(ext4_acl_header);
for (end = entry + count; entry != end;entry++) {
ext4_acl_entry *disk_entry = (ext4_acl_entry*) e;
disk_entry->e_tag = ext2fs_cpu_to_le16(entry->e_tag);
disk_entry->e_perm = ext2fs_cpu_to_le16(entry->e_perm);
switch(entry->e_tag) {
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
e += sizeof(ext4_acl_entry_short);
s += sizeof(ext4_acl_entry_short);
break;
case ACL_USER:
case ACL_GROUP:
disk_entry->e_id = ext2fs_cpu_to_le32(entry->e_id);
e += sizeof(ext4_acl_entry);
s += sizeof(ext4_acl_entry);
break;
}
}
*size_out = s;
return 0;
}
static errcode_t convert_disk_buffer_to_posix_acl(const void *value, size_t size,
void **out_buf, size_t *size_out)
{
posix_acl_xattr_header *header;
posix_acl_xattr_entry *entry;
ext4_acl_header *ext_acl = (ext4_acl_header *) value;
errcode_t err;
const char *cp;
char *out;
int count;
if ((!value) ||
(size < sizeof(ext4_acl_header)) ||
(ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)))
return EINVAL;
err = ext2fs_get_mem(size * 2, &out);
if (err)
return err;
header = (posix_acl_xattr_header *) out;
header->a_version = ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION);
entry = (posix_acl_xattr_entry *) (out + sizeof(posix_acl_xattr_header));
cp = value + sizeof(ext4_acl_header);
size -= sizeof(ext4_acl_header);
while (size > 0) {
const ext4_acl_entry *disk_entry = (const ext4_acl_entry *) cp;
entry->e_tag = ext2fs_le16_to_cpu(disk_entry->e_tag);
entry->e_perm = ext2fs_le16_to_cpu(disk_entry->e_perm);
switch(entry->e_tag) {
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
entry->e_id = 0;
cp += sizeof(ext4_acl_entry_short);
size -= sizeof(ext4_acl_entry_short);
break;
case ACL_USER:
case ACL_GROUP:
entry->e_id = ext2fs_le32_to_cpu(disk_entry->e_id);
cp += sizeof(ext4_acl_entry);
size -= sizeof(ext4_acl_entry);
break;
default:
ext2fs_free_mem(&out);
return EINVAL;
break;
}
entry++;
}
*out_buf = out;
*size_out = ((char *) entry - out);
return 0;
}
static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
struct ext2_xattr **pos,
void *entries_start,
@ -914,10 +1046,16 @@ errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
for (x = h->attrs; x < h->attrs + h->length; x++) {
if (!x->name)
if (!x->name || strcmp(x->name, key))
continue;
if (strcmp(x->name, key) == 0) {
if (!(h->flags & XATTR_HANDLE_FLAG_RAW) &&
((strcmp(key, "system.posix_acl_default") == 0) ||
(strcmp(key, "system.posix_acl_access") == 0))) {
err = convert_disk_buffer_to_posix_acl(x->value, x->value_len,
value, value_len);
return err;
} else {
err = ext2fs_get_mem(x->value_len, &val);
if (err)
return err;
@ -1002,6 +1140,20 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
last_empty = NULL;
err = ext2fs_get_mem(value_len, &new_value);
if (err)
return err;
if (!(handle->flags & XATTR_HANDLE_FLAG_RAW) &&
((strcmp(key, "system.posix_acl_default") == 0) ||
(strcmp(key, "system.posix_acl_access") == 0))) {
err = convert_posix_acl_to_disk_buffer(value, value_len,
new_value, &value_len);
if (err)
goto errout;
} else
memcpy(new_value, value, value_len);
for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
if (!x->name) {
last_empty = x;
@ -1010,10 +1162,6 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
/* Replace xattr */
if (strcmp(x->name, key) == 0) {
err = ext2fs_get_mem(value_len, &new_value);
if (err)
return err;
memcpy(new_value, value, value_len);
ext2fs_free_mem(&x->value);
x->value = new_value;
x->value_len = value_len;
@ -1026,13 +1174,9 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
if (last_empty) {
err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
if (err)
return err;
goto errout;
strcpy(last_empty->name, key);
err = ext2fs_get_mem(value_len, &last_empty->value);
if (err)
return err;
memcpy(last_empty->value, value, value_len);
last_empty->value = new_value;
last_empty->value_len = value_len;
handle->dirty = 1;
handle->count++;
@ -1058,6 +1202,9 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
handle->dirty = 1;
handle->count++;
return 0;
errout:
ext2fs_free_mem(&new_value);
return err;
}
errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
@ -1137,3 +1284,14 @@ errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count)
*count = handle->count;
return 0;
}
errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle,
unsigned int *new_flags, unsigned int *old_flags)
{
EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
if (old_flags)
*old_flags = handle->flags;
if (new_flags)
handle->flags = *new_flags;
return 0;
}

View File

@ -104,7 +104,7 @@ $(OBJS):
argv_parse.o: $(srcdir)/argv_parse.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/argv_parse.h
cstring.o: $(srcdir)/cstring.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h
$(top_builddir)/lib/dirpaths.h $(srcdir)/cstring.h
mkquota.o: $(srcdir)/mkquota.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \