[PATCH v3 2/2] initramfs: introduce do_readxattrs()
Roberto Sassu
roberto.sassu at huawei.com
Mon May 20 08:47:27 UTC 2019
On 5/17/2019 10:18 PM, hpa at zytor.com wrote:
> On May 17, 2019 9:55:19 AM PDT, Roberto Sassu <roberto.sassu at huawei.com> wrote:
>> This patch adds support for an alternative method to add xattrs to
>> files in
>> the rootfs filesystem. Instead of extracting them directly from the ram
>> disk image, they are extracted from a regular file called .xattr-list,
>> that
>> can be added by any ram disk generator available today. The file format
>> is:
>>
>> <file #N data len (ASCII, 10 chars)><file #N path>\0
>> <xattr #N data len (ASCII, 8 chars)><xattr #N name>\0<xattr #N value>
>>
>> .xattr-list can be generated by executing:
>>
>> $ getfattr --absolute-names -d -h -R -e hex -m - \
>> <file list> | xattr.awk -b > ${initdir}/.xattr-list
>>
>> where the content of the xattr.awk script is:
>>
>> #! /usr/bin/awk -f
>> {
>> if (!length($0)) {
>> printf("%.10x%s\0", len, file);
>> for (x in xattr) {
>> printf("%.8x%s\0", xattr_len[x], x);
>> for (i = 0; i < length(xattr[x]) / 2; i++) {
>> printf("%c", strtonum("0x"substr(xattr[x], i * 2 + 1, 2)));
>> }
>> }
>> i = 0;
>> delete xattr;
>> delete xattr_len;
>> next;
>> };
>> if (i == 0) {
>> file=$3;
>> len=length(file) + 8 + 1;
>> }
>> if (i > 0) {
>> split($0, a, "=");
>> xattr[a[1]]=substr(a[2], 3);
>> xattr_len[a[1]]=length(a[1]) + 1 + 8 + length(xattr[a[1]]) / 2;
>> len+=xattr_len[a[1]];
>> };
>> i++;
>> }
>>
>> Signed-off-by: Roberto Sassu <roberto.sassu at huawei.com>
>> ---
>> init/initramfs.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 99 insertions(+)
>>
>> diff --git a/init/initramfs.c b/init/initramfs.c
>> index 0c6dd1d5d3f6..6ec018c6279a 100644
>> --- a/init/initramfs.c
>> +++ b/init/initramfs.c
>> @@ -13,6 +13,8 @@
>> #include <linux/namei.h>
>> #include <linux/xattr.h>
>>
>> +#define XATTR_LIST_FILENAME ".xattr-list"
>> +
>> static ssize_t __init xwrite(int fd, const char *p, size_t count)
>> {
>> ssize_t out = 0;
>> @@ -382,6 +384,97 @@ static int __init __maybe_unused do_setxattrs(char
>> *pathname)
>> return 0;
>> }
>>
>> +struct path_hdr {
>> + char p_size[10]; /* total size including p_size field */
>> + char p_data[]; /* <path>\0<xattrs> */
>> +};
>> +
>> +static int __init do_readxattrs(void)
>> +{
>> + struct path_hdr hdr;
>> + char *path = NULL;
>> + char str[sizeof(hdr.p_size) + 1];
>> + unsigned long file_entry_size;
>> + size_t size, path_size, total_size;
>> + struct kstat st;
>> + struct file *file;
>> + loff_t pos;
>> + int ret;
>> +
>> + ret = vfs_lstat(XATTR_LIST_FILENAME, &st);
>> + if (ret < 0)
>> + return ret;
>> +
>> + total_size = st.size;
>> +
>> + file = filp_open(XATTR_LIST_FILENAME, O_RDONLY, 0);
>> + if (IS_ERR(file))
>> + return PTR_ERR(file);
>> +
>> + pos = file->f_pos;
>> +
>> + while (total_size) {
>> + size = kernel_read(file, (char *)&hdr, sizeof(hdr), &pos);
>> + if (size != sizeof(hdr)) {
>> + ret = -EIO;
>> + goto out;
>> + }
>> +
>> + total_size -= size;
>> +
>> + str[sizeof(hdr.p_size)] = 0;
>> + memcpy(str, hdr.p_size, sizeof(hdr.p_size));
>> + ret = kstrtoul(str, 16, &file_entry_size);
>> + if (ret < 0)
>> + goto out;
>> +
>> + file_entry_size -= sizeof(sizeof(hdr.p_size));
>> + if (file_entry_size > total_size) {
>> + ret = -EINVAL;
>> + goto out;
>> + }
>> +
>> + path = vmalloc(file_entry_size);
>> + if (!path) {
>> + ret = -ENOMEM;
>> + goto out;
>> + }
>> +
>> + size = kernel_read(file, path, file_entry_size, &pos);
>> + if (size != file_entry_size) {
>> + ret = -EIO;
>> + goto out_free;
>> + }
>> +
>> + total_size -= size;
>> +
>> + path_size = strnlen(path, file_entry_size);
>> + if (path_size == file_entry_size) {
>> + ret = -EINVAL;
>> + goto out_free;
>> + }
>> +
>> + xattr_buf = path + path_size + 1;
>> + xattr_len = file_entry_size - path_size - 1;
>> +
>> + ret = do_setxattrs(path);
>> + vfree(path);
>> + path = NULL;
>> +
>> + if (ret < 0)
>> + break;
>> + }
>> +out_free:
>> + vfree(path);
>> +out:
>> + fput(file);
>> +
>> + if (ret < 0)
>> + error("Unable to parse xattrs");
>> +
>> + return ret;
>> +}
>> +
>> static __initdata int wfd;
>>
>> static int __init do_name(void)
>> @@ -391,6 +484,11 @@ static int __init do_name(void)
>> if (strcmp(collected, "TRAILER!!!") == 0) {
>> free_hash();
>> return 0;
>> + } else if (strcmp(collected, XATTR_LIST_FILENAME) == 0) {
>> + struct kstat st;
>> +
>> + if (!vfs_lstat(collected, &st))
>> + do_readxattrs();
>> }
>> clean_path(collected, mode);
>> if (S_ISREG(mode)) {
>> @@ -562,6 +660,7 @@ static char * __init unpack_to_rootfs(char *buf,
>> unsigned long len)
>> buf += my_inptr;
>> len -= my_inptr;
>> }
>> + do_readxattrs();
>> dir_utime();
>> kfree(name_buf);
>> kfree(symlink_buf);
>
> Ok... I just realized this does not work for a modular initramfs, composed at load time from multiple files, which is a very real problem. Should be easy enough to deal with: instead of one large file, use one companion file per source file, perhaps something like filename..xattrs (suggesting double dots to make it less likely to conflict with a "real" file.) No leading dot, as it makes it more likely that archivers will sort them before the file proper.
Version 1 of the patch set worked exactly in this way. However, Rob
pointed out that this would be a problem if file names plus the suffix
exceed 255 characters.
Roberto
--
HUAWEI TECHNOLOGIES Duesseldorf GmbH, HRB 56063
Managing Director: Bo PENG, Jian LI, Yanli SHI
More information about the Linux-security-module-archive
mailing list