All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philip Tricca <flihp@twobit.us>
To: "Huang, Jie (Jackie)" <Jackie.Huang@windriver.com>
Cc: "yocto@yoctoproject.org" <yocto@yoctoproject.org>
Subject: Re: [meta-selinux][PATCHv2 6/8] e2fsprogs: Copy xattr block from source file.
Date: Fri, 21 Aug 2015 09:14:40 -0700	[thread overview]
Message-ID: <55D74E70.3000005@twobit.us> (raw)
In-Reply-To: <1B858668EC6A94408DCA5225FDFA85AAFC70B693@ALA-MBB.corp.ad.wrs.com>

Hey Jackie,

On 08/20/2015 11:25 PM, Huang, Jie (Jackie) wrote:
>> -----Original Message-----
>> From: yocto-bounces@yoctoproject.org [mailto:yocto-bounces@yoctoproject.org] On Behalf Of Philip
>> Tricca
>> Sent: Thursday, June 18, 2015 6:31 AM
>> To: yocto@yoctoproject.org
>> Subject: [yocto] [meta-selinux][PATCHv2 6/8] e2fsprogs: Copy xattr block from source file.
>>
>> Signed-off-by: Philip Tricca <flihp@twobit.us>
>> ---
>>  .../e2fsprogs/misc-xattr-create-xattr-block.patch  | 341 +++++++++++++++++++++
>>  .../e2fsprogs/e2fsprogs_1.42.9.bbappend            |   1 +
>>  2 files changed, 342 insertions(+)
>>  create mode 100644 recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch
>>
>> diff --git a/recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch b/recipes-
>> devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block.patch
>> new file mode 100644
>> index 0000000..5955b44
>> --- /dev/null
>> +++ b/recipes-devtools/e2fsprogs/e2fsprogs/misc-xattr-create-xattr-block
>> +++ .patch
>> @@ -0,0 +1,341 @@
>> +To build the xattr disk block we process the output from listxattr and
>> +lgetxattr from the source file system object. This data is formated in
>> +a disk block according to the format specified in the kernel ext2 file system driver.
>> +See the comment block at the beginning of fs/ext2/xattr.c for details.
>> +
>> +Currently we only process attributes with the 'security.' prefix as our
>> +use case is SELinux labels and IMA. Additional prefixes can likely be
>> +supported with minimal effort but none have been tested.
>> +
>> +Once the xattr block has been created it is written to disk. The xattr
>> +block is associated with the appropriate file system object through the
>> +i_file_acl inode member and the inode is updated on disk.
>> +
>> +Signed-off-by: Philip Tricca <flihp@twobit.us>
>> +
>> +Index: e2fsprogs-1.42.9/misc/xattr.c
>> +===================================================================
>> +--- e2fsprogs-1.42.9.orig/misc/xattr.c
>> ++++ e2fsprogs-1.42.9/misc/xattr.c
>> +@@ -1,6 +1,23 @@
>> + #include "xattr.h"
>> +
>> ++#include <attr/xattr.h>
>> ++#include <ctype.h>
>> ++#include <errno.h>
>> ++#include <ext2fs/ext2_ext_attr.h>
>> ++#include <linux/xattr.h>
>> ++#include <stdint.h>
>> + #include <stdio.h>
>> ++#include <stdlib.h>
>> ++#include <string.h>
>> ++#include <sys/stat.h>
>> ++#include <sys/types.h>
>> ++#include <unistd.h>
>> ++
>> ++#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) #define HEADER(ptr)
>> ++((struct ext2_ext_attr_header *)(ptr)) #define ENTRY(ptr)  ((struct
>> ++ext2_ext_attr_entry *)(ptr)) #define FIRST_ENTRY(ptr)
>> ++ENTRY(HEADER(ptr) + 1) #define VALUE(hdr, ent) (((char*)hdr) +
>> ++(ent->e_value_offs))
>> +
>> + #ifdef XATTR_DEBUG
>> + #define XATTR_STDERR(fmt, args...) fprintf (stderr, fmt, ##args) @@
>> +-8,6 +25,28 @@  #define XATTR_STDERR(fmt, args...) do {} while (0)
>> +#endif
>> +
>> ++/* structure for mapping xattr name prefix data */ typedef struct
>> ++xattr_prefix {
>> ++	int index;
>> ++	char *name;
>> ++	size_t length;
>> ++} xattr_prefix_t;
>> ++
>> ++xattr_prefix_t xattr_prefixes [] = {
>> ++/* Only interested in security prefix. Can support others though.
>> ++	{
>> ++		.index = EXT2_XATTR_INDEX_USER,
>> ++		.name = XATTR_USER_PREFIX,
>> ++		.length = XATTR_USER_PREFIX_LEN,
>> ++	},
>> ++*/
>> ++	{
>> ++		.index = EXT2_XATTR_INDEX_SECURITY,
>> ++		.name = XATTR_SECURITY_PREFIX,
>> ++		.length = XATTR_SECURITY_PREFIX_LEN,
> 
> Hi Philip,
> 
> This cause build errors on some host OS when building e2fsprogs-native:
> 
> | /build/yp/y_x64_150821/tmp/work/x86_64-linux/e2fsprogs-native/1.42.9-r0/e2fsprogs-1.42.9/debugfs/../misc/xattr.c:62:11: error: 'XATTR_SECURITY_PREFIX' undeclared here (not in a function)
> |    .name = XATTR_SECURITY_PREFIX,
> |            ^
> | /build/yp/y_x64_150821/tmp/work/x86_64-linux/e2fsprogs-native/1.42.9-r0/e2fsprogs-1.42.9/debugfs/../misc/xattr.c:63:13: error: 'XATTR_SECURITY_PREFIX_LEN' undeclared here (not in a function)
> |    .length = XATTR_SECURITY_PREFIX_LEN,
> |              ^
> 
> I did some investigate and found that your patch needs the header linux/xattr.h,
> which is provided by linux-libc-headers, but for -native package, there is no linux-libc-headers-native,
> so it search the one from host OS, but the problem is, there is no XATTR_SECURITY_PREFIX definition
> in the linux/xattr.h on some host OS like: SUSE 11.x, centos 6, etc.
> 
> I'm not sure if your patch is really needed by the e2fsprogs-native, if not, I think we can make this
> patch only apply for target package. If yes, you may need to make it avoid the dependency on host's
> header or you may have a better idea about this.

Apologies for the breakage and thanks for testing. This patch is only
intended for e2fsprogs-native since the use-case is to preserve xattrs
when OE creates root filesystems. So it looks to me like you found a
real problem. Likely OE was falling back to using the headers on my
build host.

I don't have an immediate fix but I'll take a look over the weekend.
Thanks again for catching this.

Best,
hilip

>> ++	},
>> ++	{ 0 },
>> ++};
>> +
>> + /* Free remaining resources after all files have been processed. */
>> +void @@ -16,6 +55,211 @@ xattr_cleanup ()
>> + 	XATTR_STDERR ("Cleaning up resources from xattrs.\n");  }
>> +
>> ++/* Get value for named xattr from file at path.
>> ++ * Returns pointer to allocated block for value and length in length param.
>> ++ * If no value, return NULL pointer and length of 0.
>> ++ * On error return NULL pointer and length set to -1.
>> ++ */
>> ++static char*
>> ++xattr_get_value (const char *path, const char *name, ssize_t *length)
>> ++{
>> ++	char *value = NULL;
>> ++
>> ++	*length = lgetxattr (path, name, NULL, 0);
>> ++	if (*length == -1) {
>> ++		com_err (__func__, errno, "lgetattr");
>> ++		goto out;
>> ++	}
>> ++	if (*length == 0) {
>> ++		fprintf (stderr, "xattr %s has value length 0\n", name);
>> ++		goto out;
>> ++	}
>> ++	value = calloc (1, *length);
>> ++	if (value == NULL) {
>> ++		com_err (__func__, errno, "calloc");
>> ++		goto out;
>> ++	}
>> ++	*length = lgetxattr (path, name, value, *length);
>> ++	if (*length == -1) {
>> ++		com_err (__func__, errno, "lgetattr");
>> ++		goto value_err;
>> ++	}
>> ++out:
>> ++	return value;
>> ++
>> ++value_err:
>> ++	if (value)
>> ++		free (value);
>> ++	return NULL;
>> ++}
>> ++
>> ++/* Get all attribute names for file at path. Return pointer to
>> ++allocated memory
>> ++ * block holding all names and the length through parameter size.
>> ++ * If no xattrs: return NULL and set size to 0
>> ++ * If error: return NULL and set size to -1  */ static char*
>> ++xattr_get_names (const char *path, ssize_t *size) {
>> ++	char *names = NULL;
>> ++
>> ++	*size = llistxattr (path, NULL, 0);
>> ++	if (*size == -1) {
>> ++		com_err (__func__, errno, "llistxattr");
>> ++		goto out;
>> ++	}
>> ++	if (*size == 0) {
>> ++		/* no xattrs */
>> ++		goto out;
>> ++	}
>> ++	names = calloc (1, *size);
>> ++	if (names == NULL) {
>> ++		com_err (__func__, errno, "calloc");
>> ++		goto out;
>> ++	}
>> ++	*size = llistxattr (path, names, *size);
>> ++	if (*size == -1) {
>> ++		com_err (__func__, errno, "llistxattr");
>> ++		goto cleanup;
>> ++	}
>> ++	if (*size == 0) {
>> ++		fprintf (stdout, "Conflicting data, no xattrs for file: %s\n", path);
>> ++		goto cleanup;
>> ++	}
>> ++out:
>> ++	return names;
>> ++
>> ++cleanup:
>> ++	if (names)
>> ++		free (names);
>> ++	return NULL;
>> ++}
>> ++
>> ++/* return pointer to next string in xattr name block, don't go beyond
>> ++length  */ static inline char* next_name (char *name, size_t length) {
>> ++	int i = 0;
>> ++
>> ++	for (i = 0; i < length; ++i)
>> ++		if (name [i] == '\0') {
>> ++			++i;
>> ++			break;
>> ++		}
>> ++
>> ++	return name + i;
>> ++}
>> ++
>> ++/* Find entry in xattr_table with matching prefix. */ static const
>> ++xattr_prefix_t* xattr_find_prefix (char *name, size_t length) {
>> ++	int i = 0;
>> ++
>> ++	XATTR_STDERR ("find_attr_data: searching for prefix from xattr name: %s\n", name);
>> ++	for (i = 0; xattr_prefixes[i].index != 0; ++i) {
>> ++		if (!strncmp (name, xattr_prefixes[i].name, MIN (length, xattr_prefixes[i].length))) {
>> ++			XATTR_STDERR ("found match in table with index: %d\n",
>> xattr_prefixes[i].index);
>> ++			return &xattr_prefixes[i];
>> ++		}
>> ++	}
>> ++	return NULL;
>> ++}
>> ++
>> ++/* Query file at path for attributes. build up structure the file
>> ++system
>> ++ * expects of an extended attribute disk block (header parameter).
>> ++ *
>> ++ * The main loop walks through the xattr names one at a time. It gets
>> ++the value
>> ++ * for each named xattr and copies the data into the xattr block
>> ++pointed to by
>> ++ * the header parameter. To do this the loop also tracks the location
>> ++of the
>> ++ * associated entry and value. Values start at the end of the buffer
>> ++and grow
>> ++ * back towards the header while the entries start immediately after
>> ++the header
>> ++ * and grow towards the end of the block.
>> ++ *
>> ++ * See the comment block at the beginning of the xattr.c file in the
>> ++ext2 file
>> ++ * system code in the kernel: fs/ext2/xattr.c
>> ++ * Assume the xattr block pointed to by header parameter is initialized to 0s.
>> ++ */
>> ++static int
>> ++xattr_build_block (const char *path,
>> ++		struct ext2_ext_attr_header **header,
>> ++		size_t header_length)
>> ++{
>> ++	struct ext2_ext_attr_entry *entry = NULL;
>> ++	char *names = NULL, *value = NULL, *name_curr = NULL;
>> ++	ssize_t names_length = 0, value_length = 0;
>> ++	size_t name_length = 0, value_index = 0, len_rem = 0;
>> ++	const xattr_prefix_t *prefix = NULL;
>> ++	int ret = 0;
>> ++
>> ++	XATTR_STDERR ("xattr_build_block for file: %s\n", path);
>> ++	*header = NULL;
>> ++	names = xattr_get_names (path, &names_length);
>> ++	if (names == NULL) {
>> ++		// no xattrs for file @ path or error
>> ++		ret = names_length;
>> ++		goto out;
>> ++	}
>> ++	*header = calloc (1, header_length);
>> ++	if (*header == NULL) {
>> ++		com_err (__func__, errno, "calloc");
>> ++		goto out;
>> ++	}
>> ++	(*header)->h_magic = EXT2_EXT_ATTR_MAGIC;
>> ++	(*header)->h_blocks = 1;
>> ++	/* Values start at end of buffer. NOTE: It must be moved before a value can
>> ++	 * be stored.
>> ++	 */
>> ++	value_index = header_length;
>> ++	for (name_curr = names, entry = FIRST_ENTRY(*header), len_rem = names_length;
>> ++		name_curr < names + names_length;
>> ++		len_rem = names_length - (name_curr - names),
>> ++			name_curr = next_name (name_curr, len_rem),
>> ++			entry = EXT2_EXT_ATTR_NEXT(entry))
>> ++	{
>> ++		XATTR_STDERR ("xattr_build_block: processing xattr with name %s\n", name_curr);
>> ++		name_length = strnlen (name_curr, len_rem);
>> ++		prefix = xattr_find_prefix (name_curr, name_length);
>> ++		if (!prefix) {
>> ++			fprintf (stderr, "Don't currently handle xattr: %s\n", name_curr);
>> ++			continue;
>> ++		}
>> ++		value = xattr_get_value (path, name_curr, &value_length);
>> ++		if (value == NULL) {
>> ++			// no xattr value or error
>> ++			fprintf (stderr, "failed to get value, skipping\n");
>> ++			goto next;
>> ++		}
>> ++		/* setup offsets and lengths for name and value */
>> ++		entry->e_name_len = name_length - prefix->length;
>> ++		entry->e_name_index = prefix->index;
>> ++		/* Can't know these till we know the length of the value. */
>> ++		entry->e_value_offs = value_index -= EXT2_EXT_ATTR_SIZE(value_length);
>> ++		entry->e_value_size = value_length;
>> ++		/* Check to be sure entry name and value don't overlap before copy. */
>> ++		if (EXT2_EXT_ATTR_NAME(entry) + entry->e_name_len > VALUE(*header, entry)) {
>> ++			fprintf (stderr, "xattr entry name and value overlap! Too much xattr data.");
>> ++			ret = -1;
>> ++			goto out;
>> ++		}
>> ++		/* copy name and value data then calculate the hash */
>> ++		memcpy (EXT2_EXT_ATTR_NAME(entry),
>> ++			name_curr + prefix->length,
>> ++			entry->e_name_len);
>> ++		memcpy (VALUE(*header, entry), value, entry->e_value_size);
>> ++		entry->e_hash = ext2fs_ext_attr_hash_entry (entry, VALUE(*header,
>> ++entry));
>> ++next:
>> ++		if (value)
>> ++			free (value);
>> ++	}
>> ++	XATTR_STDERR ("xattr_build_block: done building xattr buffer\n");
>> ++out:
>> ++	if (names)
>> ++		free (names);
>> ++	return ret;
>> ++}
>> ++
>> + /* This is the entry point to the xattr module. This function copies
>> +the xattrs
>> +  * from the file at 'path' to the file system object at 'ino'.
>> +  *
>> +@@ -28,7 +272,56 @@ errcode_t
>> + set_inode_xattr (ext2_filsys fs, ext2_ino_t ino, const char *path)  {
>> + 	errcode_t ret = 0;
>> ++	char *buf = NULL;
>> ++	struct ext2_inode inode = { 0 };
>> ++	blk_t block = 0;
>> ++	struct ext2_ext_attr_header *header = NULL;
>> ++	uint32_t newcount = 0;
>> +
>> + 	XATTR_STDERR ("Copying xattrs from %s to inode 0x%x.\n", path, ino);
>> ++	/* Populate the xattr block for the file at path */
>> ++	if (ret = xattr_build_block (path, &header, fs->blocksize)) {
>> ++		goto out;
>> ++	}
>> ++	if (header == NULL) {
>> ++		XATTR_STDERR ("set_inode_xattrs: no xattrs for %s\n", path);
>> ++		goto out;
>> ++	}
>> ++	if (ret = ext2fs_read_inode (fs, ino, &inode)) {
>> ++		com_err(__func__, ret, "ext2fs_read_inode");
>> ++		goto out;
>> ++	}
>> ++	if (ret = ext2fs_alloc_block (fs, 0, NULL, &block)) {
>> ++		com_err(__func__, ret, "ext2fs_alloc_block: returned %d", ret);
>> ++		goto out;
>> ++	}
>> ++	ext2fs_mark_block_bitmap2 (fs->block_map, block);
>> ++	XATTR_STDERR ("writing xattr block 0x%x to disk:\n", block);
>> ++	if (ret = ext2fs_write_ext_attr (fs, block, header)) {
>> ++		com_err(__func__, ret, "ext2fs_write_ext_attr: returned %d", ret);
>> ++		goto out;
>> ++	}
>> ++	/* point inode for current file to xattr block, update block count and
>> ++	 * write inode to disk
>> ++	 */
>> ++	inode.i_file_acl = block;
>> ++	if (ret = ext2fs_adjust_ea_refcount2(fs,
>> ++					block,
>> ++					(char*)header,
>> ++					1,
>> ++					&newcount))
>> ++	{
>> ++		com_err(__func__, ret, "ext2fs_adjust_ea_refcount");
>> ++		goto out;
>> ++	}
>> ++	if (ret = ext2fs_iblk_add_blocks (fs, &inode, 1)) {
>> ++		com_err(__func__, ret, "ext2fs_iblk_add_blocks failed");
>> ++		goto out;
>> ++	}
>> ++	if (ret = ext2fs_write_inode (fs, ino, &inode))
>> ++		com_err(__func__, ret, "ext2fs_write_inode: returned %d", ret);
>> ++out:
>> ++	if (header)
>> ++		free (header);
>> + 	return ret;
>> + }
>> diff --git a/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend b/recipes-
>> devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend
>> index a4576b1..edc94d8 100644
>> --- a/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend
>> +++ b/recipes-devtools/e2fsprogs/e2fsprogs_1.42.9.bbappend
>> @@ -4,4 +4,5 @@ SRC_URI += " \
>>      file://misc-xattr-add-xattr-module-stub.patch \
>>      file://mke2fs.c-create_inode.c-copy-xattrs.patch \
>>      file://lib-ext2fs-ext2_ext_attr.h-add-xattr-index.patch \
>> +    file://misc-xattr-create-xattr-block.patch \
>>  "
>> --
>> 2.1.4
>>
>> --
>> _______________________________________________
>> yocto mailing list
>> yocto@yoctoproject.org
>> https://lists.yoctoproject.org/listinfo/yocto



  reply	other threads:[~2015-08-21 16:14 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-17 22:30 [meta-selinux][PATCHv2 0/8] Label file system in build Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 1/8] policycoreutils: Patch setfiles to add FTS_NOCHDIR to fts_flags Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 2/8] selinux-image: Add new image class to label the rootfs, use it for selinux images Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 3/8] e2fsprogs: Add bbappend and stub for xattr module Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 4/8] e2fsprogs: Insert calls to xattr module into mke2fs and build xattr code Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 5/8] e2fsprogs: Add xattr security prefix data to lib/ext2fs/ext2_ext_attr.h Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 6/8] e2fsprogs: Copy xattr block from source file Philip Tricca
2015-08-21  6:25   ` Huang, Jie (Jackie)
2015-08-21 16:14     ` Philip Tricca [this message]
2015-08-23 22:24     ` Philip Tricca
2015-08-24  5:27       ` Huang, Jie (Jackie)
2015-09-05 17:59         ` Philip Tricca
2015-09-08 17:36           ` Joe MacDonald
2015-06-17 22:30 ` [meta-selinux][PATCHv2 7/8] e2fsprogs: Add stub functions for an xattr cache and struct to hold the header and block data Philip Tricca
2015-06-17 22:30 ` [meta-selinux][PATCHv2 8/8] e2fsprogs: Implement xattr block cache with simple linked list Philip Tricca
2015-08-08 21:00 ` [meta-selinux][PATCHv2 0/8] Label file system in build Joe MacDonald
2015-08-11  4:10   ` Philip Tricca
2015-08-11  5:40     ` Philip Tricca

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55D74E70.3000005@twobit.us \
    --to=flihp@twobit.us \
    --cc=Jackie.Huang@windriver.com \
    --cc=yocto@yoctoproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.