From mboxrd@z Thu Jan 1 00:00:00 1970 From: Roberto Sassu Subject: Re: [PATCH v3 2/2] initramfs: introduce do_readxattrs() Date: Mon, 20 May 2019 10:47:27 +0200 Message-ID: <2fbe55dc-2f4a-e476-79d0-06931b4f1dee@huawei.com> References: <20190517165519.11507-1-roberto.sassu@huawei.com> <20190517165519.11507-3-roberto.sassu@huawei.com> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: Content-Language: en-US Sender: linux-kernel-owner@vger.kernel.org List-ID: Content-Type: text/plain; charset="us-ascii"; format="flowed" To: hpa@zytor.com, viro@zeniv.linux.org.uk Cc: linux-security-module@vger.kernel.org, linux-integrity@vger.kernel.org, initramfs@vger.kernel.org, linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, zohar@linux.vnet.ibm.com, silviu.vlasceanu@huawei.com, dmitry.kasatkin@huawei.com, takondra@cisco.com, kamensky@cisco.com, arnd@arndb.de, rob@landley.net, james.w.mcmechan@gmail.com, niveditas98@gmail.com On 5/17/2019 10:18 PM, hpa@zytor.com wrote: > On May 17, 2019 9:55:19 AM PDT, Roberto Sassu 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: >> >> \0 >> \0 >> >> .xattr-list can be generated by executing: >> >> $ getfattr --absolute-names -d -h -R -e hex -m - \ >> | 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 >> --- >> 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 >> #include >> >> +#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[]; /* \0 */ >> +}; >> + >> +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