From: Mimi Zohar zohar@linux.vnet.ibm.com
euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I7QZ2M CVE: NA
-------------------------------------------------
This patch adds metadata to a file from a supplied buffer. The buffer might contains multiple metadata records. The format of each record is:
<metadata len (ASCII, 8 chars)><version><type><metadata>
For now, only the TYPE_XATTR metadata type is supported. The specific format of this metadata type is:
<xattr #N name>\0<xattr #N value>
[kamensky: fixed restoring of xattrs for symbolic links by using sys_lsetxattr() instead of sys_setxattr()]
[sassu: removed state management, kept only do_setxattrs(), added support for generic file metadata, replaced sys_lsetxattr() with vfs_setxattr(), added check for entry_size, added check for hdr->c_size, replaced strlen() with strnlen(); moved do_setxattrs() before do_name()]
Signed-off-by: Mimi Zohar zohar@linux.vnet.ibm.com Signed-off-by: Victor Kamensky kamensky@cisco.com Signed-off-by: Taras Kondratiuk takondra@cisco.com Signed-off-by: Roberto Sassu roberto.sassu@huawei.com Signed-off-by: Tianxing Zhang zhangtianxing3@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com Signed-off-by: zhoushuiqing zhoushuiqing2@huawei.com --- include/linux/initramfs.h | 21 ++++++++++ init/initramfs.c | 88 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 include/linux/initramfs.h
diff --git a/include/linux/initramfs.h b/include/linux/initramfs.h new file mode 100644 index 000000000000..2f8cee441236 --- /dev/null +++ b/include/linux/initramfs.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * include/linux/initramfs.h + * + * Include file for file metadata in the initial ram disk. + */ +#ifndef _LINUX_INITRAMFS_H +#define _LINUX_INITRAMFS_H + +#define METADATA_FILENAME "METADATA!!!" + +enum metadata_types { TYPE_NONE, TYPE_XATTR, TYPE__LAST }; + +struct metadata_hdr { + char c_size[8]; /* total size including c_size field */ + char c_version; /* header version */ + char c_type; /* metadata type */ + char c_metadata[]; /* metadata */ +} __packed; + +#endif /*LINUX_INITRAMFS_H*/ diff --git a/init/initramfs.c b/init/initramfs.c index e7a01c2ccd1b..3b272c56a987 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -15,6 +15,8 @@ #include <linux/memblock.h> #include <linux/mm.h> #include <linux/namei.h> +#include <linux/xattr.h> +#include <linux/initramfs.h> #include <linux/init_syscalls.h> #include <linux/task_work.h> #include <linux/umh.h> @@ -177,7 +179,7 @@ static __initdata time64_t mtime;
static __initdata unsigned long ino, major, minor, nlink; static __initdata umode_t mode; -static __initdata unsigned long body_len, name_len; +static __initdata unsigned long body_len, name_len, metadata_len; static __initdata uid_t uid; static __initdata gid_t gid; static __initdata unsigned rdev; @@ -250,7 +252,7 @@ static void __init read_into(char *buf, unsigned size, enum state next) } }
-static __initdata char *header_buf, *symlink_buf, *name_buf; +static __initdata char *header_buf, *symlink_buf, *name_buf, *metadata_buf;
static int __init do_start(void) { @@ -351,6 +353,88 @@ static int __init maybe_link(void) return 0; }
+static int __init do_setxattrs(char *pathname, char *buf, size_t size) +{ + struct path path; + char *xattr_name, *xattr_value; + uint32_t xattr_name_size, xattr_value_size; + int ret; + + xattr_name = buf; + xattr_name_size = strnlen(xattr_name, size); + if (xattr_name_size == size) { + error("malformed xattrs"); + return -EINVAL; + } + + xattr_value = xattr_name + xattr_name_size + 1; + xattr_value_size = buf + size - xattr_value; + + ret = kern_path(pathname, 0, &path); + if (!ret) { + ret = vfs_setxattr(&nop_mnt_idmap, path.dentry, xattr_name, xattr_value, + xattr_value_size, 0); + + path_put(&path); + } + + pr_debug("%s: %s size: %u val: %s (ret: %d)\n", pathname, + xattr_name, xattr_value_size, xattr_value, ret); + + return ret; +} + +static int __init __maybe_unused do_parse_metadata(char *pathname) +{ + char *buf = metadata_buf; + char *bufend = metadata_buf + metadata_len; + struct metadata_hdr *hdr; + char str[sizeof(hdr->c_size) + 1]; + uint32_t entry_size; + + if (!metadata_len) + return 0; + + str[sizeof(hdr->c_size)] = 0; + + while (buf < bufend) { + int ret; + + if (buf + sizeof(*hdr) > bufend) { + error("malformed metadata"); + break; + } + + hdr = (struct metadata_hdr *)buf; + if (hdr->c_version != 1) { + pr_debug("Unsupported header version\n"); + break; + } + + memcpy(str, hdr->c_size, sizeof(hdr->c_size)); + ret = kstrtou32(str, 16, &entry_size); + if (ret || buf + entry_size > bufend || + entry_size < sizeof(*hdr)) { + error("malformed xattrs"); + break; + } + + switch (hdr->c_type) { + case TYPE_XATTR: + do_setxattrs(pathname, buf + sizeof(*hdr), + entry_size - sizeof(*hdr)); + break; + default: + pr_debug("Unsupported metadata type\n"); + break; + } + + buf += entry_size; + } + + return 0; +} + static __initdata struct file *wfile; static __initdata loff_t wfile_pos;