From: Taras Kondratiuk <takondra@cisco.com> To: "H. Peter Anvin" <hpa@zytor.com>, Al Viro <viro@zeniv.linux.org.uk>, Arnd Bergmann <arnd@arndb.de>, Rob Landley <rob@landley.net>, Mimi Zohar <zohar@linux.vnet.ibm.com>, Jonathan Corbet <corbet@lwn.net>, James McMechan <james.w.mcmechan@gmail.com> Cc: initramfs@vger.kernel.org, Victor Kamensky <kamensky@cisco.com>, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, xe-linux-external@cisco.com Subject: [PATCH v2 12/15] gen_init_cpio: set extended attributes for newcx format Date: Thu, 25 Jan 2018 03:27:52 +0000 [thread overview] Message-ID: <1516850875-25066-13-git-send-email-takondra@cisco.com> (raw) In-Reply-To: <1516850875-25066-1-git-send-email-takondra@cisco.com> gen_init_cpio creates CPIO archive according to cpio_list manifest file that contains list of archive entries (one per line). To be able to store extended attributes in newcx CPIO format we need to pass them via cpio_list file. One way of doing it would be to append xattrs to each entry line, but "file" lines have a variable number of elements because of hardlinks. It is not obvious how to mark end of hardlinks and start of xattrs in this case. This patch introduces a new entry type: "xattr". Each "xattr" line specify one name=value pair. xattr values are applied to the next non-xattr line. There can be multiple "xattr" lines before non-xattr line. It may be more logical to have xattr lines after corresponding file entry, but it makes parsing a bit more complex and needs more intrusive changes. Xattr value is hex-encoded (see getfattr(1)). Plain string variant would be easier to read, but special symbols have to be escaped. Hex encoding is much simpler. Signed-off-by: Taras Kondratiuk <takondra@cisco.com> --- usr/gen_init_cpio.c | 142 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 23 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 78a47a5bdcb1..e356f9e532a2 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -10,6 +10,7 @@ #include <errno.h> #include <ctype.h> #include <limits.h> +#include <sys/xattr.h> #include <assert.h> /* @@ -50,21 +51,10 @@ static void push_pad (void) } } -static void push_rest(const char *name) +static void push_string_padded(const char *name) { - unsigned int name_len = strlen(name) + 1; - unsigned int tmp_ofs; - - fputs(name, stdout); - putchar(0); - offset += name_len; - - tmp_ofs = name_len + cpio_hdr_size; - while (tmp_ofs & 3) { - putchar(0); - offset++; - tmp_ofs++; - } + push_string(name); + push_pad(); } struct cpio_header { @@ -137,7 +127,7 @@ static void cpio_trailer(void) }; push_hdr(&hdr); - push_rest(name); + push_string_padded(name); while (offset % 512) { putchar(0); @@ -145,6 +135,96 @@ static void cpio_trailer(void) } } +struct xattr_hdr { + char c_size[8]; /* total size including c_size field */ + char c_data[]; +}; +static unsigned int xattr_buflen; +static char xattr_buf[4096]; + +static void push_xattrs(void) +{ + if (!newcx || !xattr_buflen) + return; + + if (fwrite(xattr_buf, xattr_buflen, 1, stdout) != 1) + fprintf(stderr, "writing xattrs failed\n"); + offset += xattr_buflen; + xattr_buflen = 0; + + push_pad(); +} + +static int convert_hex_string(const char *hex_str, char *out, size_t out_size) +{ + char buf[3]; + size_t str_len = strlen(hex_str); + + if (str_len % 2 != 0 || str_len / 2 > out_size) + return 0; + + buf[2] = '\0'; + while (*hex_str != '\0') { + buf[0] = *hex_str++; + buf[1] = *hex_str++; + *out++ = (char)strtol(buf, NULL, 16); + } + + return str_len / 2; +} + +static int collect_xattr(const char *line) +{ + const char *name, *value; + size_t name_len, value_len; + char *buf = xattr_buf + xattr_buflen; + struct xattr_hdr *hdr = (struct xattr_hdr *)buf; + char *bufend = xattr_buf + sizeof(xattr_buf); + char *value_buf; + size_t xattr_entry_size; + char size_str[sizeof(hdr->c_size) + 1]; + + if (!newcx) + return 0; + + name = line; + value = strchr(line, '='); + if (!value) { + fprintf(stderr, "Unrecognized xattr format '%s'", line); + return -1; + } + name_len = value - name; + value++; + + /* + * For now we support only hex encoded values. + * String or base64 can be added later. + */ + if (strncmp(value, "0x", 2)) { + fprintf(stderr, + "Only hex encoded xattr value is supported '%s'", + value); + return -1; + } + + value += 2; + value_buf = buf + sizeof(struct xattr_hdr) + name_len + 1; + value_len = convert_hex_string(value, value_buf, bufend - value_buf); + if (value_len == 0) { + fprintf(stderr, "Failed to parse xattr value '%s'", line); + return -1; + } + xattr_entry_size = sizeof(struct xattr_hdr) + name_len + 1 + value_len; + + sprintf(size_str, "%08X", (unsigned int)xattr_entry_size); + memcpy(hdr->c_size, size_str, sizeof(hdr->c_size)); + memcpy(hdr->c_data, name, name_len); + hdr->c_data[name_len] = '\0'; + xattr_buflen += xattr_entry_size; + + return 0; +} + static int cpio_mkslink(const char *name, const char *target, unsigned int mode, uid_t uid, gid_t gid) { @@ -161,12 +241,12 @@ static int cpio_mkslink(const char *name, const char *target, .devmajor = 3, .devminor = 1, .namesize = strlen(name)+1, + .xattrsize = xattr_buflen, }; push_hdr(&hdr); - push_string(name); - push_pad(); - push_string(target); - push_pad(); + push_string_padded(name); + push_xattrs(); + push_string_padded(target); return 0; } @@ -203,9 +283,11 @@ static int cpio_mkgeneric(const char *name, unsigned int mode, .devmajor = 3, .devminor = 1, .namesize = strlen(name)+1, + .xattrsize = xattr_buflen, }; push_hdr(&hdr); - push_rest(name); + push_string_padded(name); + push_xattrs(); return 0; } @@ -292,9 +374,11 @@ static int cpio_mknod(const char *name, unsigned int mode, .rdevmajor = maj, .rdevminor = min, .namesize = strlen(name)+1, + .xattrsize = xattr_buflen, }; push_hdr(&hdr); - push_rest(name); + push_string_padded(name); + push_xattrs(); return 0; } @@ -377,10 +461,13 @@ static int cpio_mkfile(const char *name, const char *location, .devmajor = 3, .devminor = 1, .namesize = namesize, + /* xattrs go on last link */ + .xattrsize = (i == nlinks) ? xattr_buflen : 0, }; push_hdr(&hdr); - push_string(name); - push_pad(); + push_string_padded(name); + if (hdr.xattrsize) + push_xattrs(); if (size) { if (fwrite(filebuf, size, 1, stdout) != 1) { @@ -486,6 +573,8 @@ static void usage(const char *prog) "slink <name> <target> <mode> <uid> <gid>\n" "pipe <name> <mode> <uid> <gid>\n" "sock <name> <mode> <uid> <gid>\n" + "# xattr line is applied to the next non-xattr entry\n" + "xattr <xattr_name>=<xattr_val>\n" "\n" "<name> name of the file/dir/nod/etc in the archive\n" "<location> location of the file in the current filesystem\n" @@ -498,12 +587,16 @@ static void usage(const char *prog) "<maj> major number of nod\n" "<min> minor number of nod\n" "<hard links> space separated list of other links to file\n" + "<xattr_name> extended attribute name\n" + "<xattr_val> hex-encoded extended attribute value\n" "\n" "example:\n" "# A simple initramfs\n" "dir /dev 0755 0 0\n" "nod /dev/console 0600 0 0 c 5 1\n" "dir /root 0700 0 0\n" + "# set SELinux label 'system_u:object_r:bin_t:s0' for /sbin directory\n" + "xattr security.selinux=0x73797374656d5f753a6f626a6563745f723a62696e5f743a733000\n" "dir /sbin 0755 0 0\n" "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n" "\n" @@ -533,6 +626,9 @@ struct file_handler file_handler_table[] = { .type = "sock", .handler = cpio_mksock_line, }, { + .type = "xattr", + .handler = collect_xattr, + }, { .type = NULL, .handler = NULL, } -- 2.10.3.dirty
WARNING: multiple messages have this Message-ID (diff)
From: takondra@cisco.com (Taras Kondratiuk) To: linux-security-module@vger.kernel.org Subject: [PATCH v2 12/15] gen_init_cpio: set extended attributes for newcx format Date: Thu, 25 Jan 2018 03:27:52 +0000 [thread overview] Message-ID: <1516850875-25066-13-git-send-email-takondra@cisco.com> (raw) In-Reply-To: <1516850875-25066-1-git-send-email-takondra@cisco.com> gen_init_cpio creates CPIO archive according to cpio_list manifest file that contains list of archive entries (one per line). To be able to store extended attributes in newcx CPIO format we need to pass them via cpio_list file. One way of doing it would be to append xattrs to each entry line, but "file" lines have a variable number of elements because of hardlinks. It is not obvious how to mark end of hardlinks and start of xattrs in this case. This patch introduces a new entry type: "xattr". Each "xattr" line specify one name=value pair. xattr values are applied to the next non-xattr line. There can be multiple "xattr" lines before non-xattr line. It may be more logical to have xattr lines after corresponding file entry, but it makes parsing a bit more complex and needs more intrusive changes. Xattr value is hex-encoded (see getfattr(1)). Plain string variant would be easier to read, but special symbols have to be escaped. Hex encoding is much simpler. Signed-off-by: Taras Kondratiuk <takondra@cisco.com> --- usr/gen_init_cpio.c | 142 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 23 deletions(-) diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c index 78a47a5bdcb1..e356f9e532a2 100644 --- a/usr/gen_init_cpio.c +++ b/usr/gen_init_cpio.c @@ -10,6 +10,7 @@ #include <errno.h> #include <ctype.h> #include <limits.h> +#include <sys/xattr.h> #include <assert.h> /* @@ -50,21 +51,10 @@ static void push_pad (void) } } -static void push_rest(const char *name) +static void push_string_padded(const char *name) { - unsigned int name_len = strlen(name) + 1; - unsigned int tmp_ofs; - - fputs(name, stdout); - putchar(0); - offset += name_len; - - tmp_ofs = name_len + cpio_hdr_size; - while (tmp_ofs & 3) { - putchar(0); - offset++; - tmp_ofs++; - } + push_string(name); + push_pad(); } struct cpio_header { @@ -137,7 +127,7 @@ static void cpio_trailer(void) }; push_hdr(&hdr); - push_rest(name); + push_string_padded(name); while (offset % 512) { putchar(0); @@ -145,6 +135,96 @@ static void cpio_trailer(void) } } +struct xattr_hdr { + char c_size[8]; /* total size including c_size field */ + char c_data[]; +}; +static unsigned int xattr_buflen; +static char xattr_buf[4096]; + +static void push_xattrs(void) +{ + if (!newcx || !xattr_buflen) + return; + + if (fwrite(xattr_buf, xattr_buflen, 1, stdout) != 1) + fprintf(stderr, "writing xattrs failed\n"); + offset += xattr_buflen; + xattr_buflen = 0; + + push_pad(); +} + +static int convert_hex_string(const char *hex_str, char *out, size_t out_size) +{ + char buf[3]; + size_t str_len = strlen(hex_str); + + if (str_len % 2 != 0 || str_len / 2 > out_size) + return 0; + + buf[2] = '\0'; + while (*hex_str != '\0') { + buf[0] = *hex_str++; + buf[1] = *hex_str++; + *out++ = (char)strtol(buf, NULL, 16); + } + + return str_len / 2; +} + +static int collect_xattr(const char *line) +{ + const char *name, *value; + size_t name_len, value_len; + char *buf = xattr_buf + xattr_buflen; + struct xattr_hdr *hdr = (struct xattr_hdr *)buf; + char *bufend = xattr_buf + sizeof(xattr_buf); + char *value_buf; + size_t xattr_entry_size; + char size_str[sizeof(hdr->c_size) + 1]; + + if (!newcx) + return 0; + + name = line; + value = strchr(line, '='); + if (!value) { + fprintf(stderr, "Unrecognized xattr format '%s'", line); + return -1; + } + name_len = value - name; + value++; + + /* + * For now we support only hex encoded values. + * String or base64 can be added later. + */ + if (strncmp(value, "0x", 2)) { + fprintf(stderr, + "Only hex encoded xattr value is supported '%s'", + value); + return -1; + } + + value += 2; + value_buf = buf + sizeof(struct xattr_hdr) + name_len + 1; + value_len = convert_hex_string(value, value_buf, bufend - value_buf); + if (value_len == 0) { + fprintf(stderr, "Failed to parse xattr value '%s'", line); + return -1; + } + xattr_entry_size = sizeof(struct xattr_hdr) + name_len + 1 + value_len; + + sprintf(size_str, "%08X", (unsigned int)xattr_entry_size); + memcpy(hdr->c_size, size_str, sizeof(hdr->c_size)); + memcpy(hdr->c_data, name, name_len); + hdr->c_data[name_len] = '\0'; + xattr_buflen += xattr_entry_size; + + return 0; +} + static int cpio_mkslink(const char *name, const char *target, unsigned int mode, uid_t uid, gid_t gid) { @@ -161,12 +241,12 @@ static int cpio_mkslink(const char *name, const char *target, .devmajor = 3, .devminor = 1, .namesize = strlen(name)+1, + .xattrsize = xattr_buflen, }; push_hdr(&hdr); - push_string(name); - push_pad(); - push_string(target); - push_pad(); + push_string_padded(name); + push_xattrs(); + push_string_padded(target); return 0; } @@ -203,9 +283,11 @@ static int cpio_mkgeneric(const char *name, unsigned int mode, .devmajor = 3, .devminor = 1, .namesize = strlen(name)+1, + .xattrsize = xattr_buflen, }; push_hdr(&hdr); - push_rest(name); + push_string_padded(name); + push_xattrs(); return 0; } @@ -292,9 +374,11 @@ static int cpio_mknod(const char *name, unsigned int mode, .rdevmajor = maj, .rdevminor = min, .namesize = strlen(name)+1, + .xattrsize = xattr_buflen, }; push_hdr(&hdr); - push_rest(name); + push_string_padded(name); + push_xattrs(); return 0; } @@ -377,10 +461,13 @@ static int cpio_mkfile(const char *name, const char *location, .devmajor = 3, .devminor = 1, .namesize = namesize, + /* xattrs go on last link */ + .xattrsize = (i == nlinks) ? xattr_buflen : 0, }; push_hdr(&hdr); - push_string(name); - push_pad(); + push_string_padded(name); + if (hdr.xattrsize) + push_xattrs(); if (size) { if (fwrite(filebuf, size, 1, stdout) != 1) { @@ -486,6 +573,8 @@ static void usage(const char *prog) "slink <name> <target> <mode> <uid> <gid>\n" "pipe <name> <mode> <uid> <gid>\n" "sock <name> <mode> <uid> <gid>\n" + "# xattr line is applied to the next non-xattr entry\n" + "xattr <xattr_name>=<xattr_val>\n" "\n" "<name> name of the file/dir/nod/etc in the archive\n" "<location> location of the file in the current filesystem\n" @@ -498,12 +587,16 @@ static void usage(const char *prog) "<maj> major number of nod\n" "<min> minor number of nod\n" "<hard links> space separated list of other links to file\n" + "<xattr_name> extended attribute name\n" + "<xattr_val> hex-encoded extended attribute value\n" "\n" "example:\n" "# A simple initramfs\n" "dir /dev 0755 0 0\n" "nod /dev/console 0600 0 0 c 5 1\n" "dir /root 0700 0 0\n" + "# set SELinux label 'system_u:object_r:bin_t:s0' for /sbin directory\n" + "xattr security.selinux=0x73797374656d5f753a6f626a6563745f723a62696e5f743a733000\n" "dir /sbin 0755 0 0\n" "file /sbin/kinit /usr/src/klibc/kinit/kinit 0755 0 0\n" "\n" @@ -533,6 +626,9 @@ struct file_handler file_handler_table[] = { .type = "sock", .handler = cpio_mksock_line, }, { + .type = "xattr", + .handler = collect_xattr, + }, { .type = NULL, .handler = NULL, } -- 2.10.3.dirty -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo at vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2018-01-25 3:38 UTC|newest] Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-01-25 3:27 [PATCH v2 00/15] extend initramfs archive format to support xattrs Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 01/15] Documentation: add newcx initramfs format description Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 9:29 ` Arnd Bergmann 2018-01-25 9:29 ` Arnd Bergmann 2018-01-25 20:26 ` Taras Kondratiuk 2018-01-25 20:26 ` Taras Kondratiuk 2018-01-25 20:26 ` Taras Kondratiuk 2018-01-25 21:02 ` Arnd Bergmann 2018-01-25 21:02 ` Arnd Bergmann 2018-01-25 22:13 ` Taras Kondratiuk 2018-01-25 22:13 ` Taras Kondratiuk 2018-01-26 2:39 ` Rob Landley 2018-01-26 2:39 ` Rob Landley 2018-01-26 9:04 ` Arnd Bergmann 2018-01-26 9:04 ` Arnd Bergmann 2018-01-26 10:31 ` Henrique de Moraes Holschuh 2018-01-26 10:31 ` Henrique de Moraes Holschuh 2018-01-26 15:51 ` Victor Kamensky 2018-01-26 15:51 ` Victor Kamensky 2018-01-26 18:15 ` Henrique de Moraes Holschuh 2018-01-26 18:15 ` Henrique de Moraes Holschuh 2018-01-26 18:15 ` Henrique de Moraes Holschuh 2018-01-26 2:40 ` Rob Landley 2018-01-26 2:40 ` Rob Landley 2018-01-26 21:02 ` Taras Kondratiuk 2018-01-26 21:02 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 02/15] initramfs: replace states with function pointers Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 03/15] initramfs: store file name in name_buf Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 04/15] initramfs: remove unnecessary symlinks processing shortcut Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 05/15] initramfs: move files creation into separate state Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 06/15] initramfs: separate reading cpio method from header Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 07/15] initramfs: split header layout information from parsing function Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 08/15] initramfs: add newcx format Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 09/15] initramfs: set extended attributes Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 10/15] gen_init_cpio: move header formatting into function Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 11/15] gen_init_cpio: add newcx format Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-26 2:40 ` Rob Landley 2018-01-26 2:40 ` Rob Landley 2018-01-26 20:37 ` Taras Kondratiuk 2018-01-26 20:37 ` Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk [this message] 2018-01-25 3:27 ` [PATCH v2 12/15] gen_init_cpio: set extended attributes for " Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 13/15] gen_initramfs_list.sh: add -x option to enable " Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 3:27 ` [PATCH v2 14/15] selinux: allow setxattr on rootfs so initramfs code can set them Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 13:51 ` [Fwd: [PATCH v2 14/15] selinux: allow setxattr on rootfs so initramfs code can set them] Stephen Smalley 2018-01-25 3:27 ` [PATCH v2 15/15] selinux: delay sid population for rootfs till init is complete Taras Kondratiuk 2018-01-25 3:27 ` Taras Kondratiuk 2018-01-25 13:48 ` [Fwd: [PATCH v2 15/15] selinux: delay sid population for rootfs till init is complete] Stephen Smalley
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=1516850875-25066-13-git-send-email-takondra@cisco.com \ --to=takondra@cisco.com \ --cc=arnd@arndb.de \ --cc=corbet@lwn.net \ --cc=hpa@zytor.com \ --cc=initramfs@vger.kernel.org \ --cc=james.w.mcmechan@gmail.com \ --cc=kamensky@cisco.com \ --cc=linux-doc@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-security-module@vger.kernel.org \ --cc=rob@landley.net \ --cc=viro@zeniv.linux.org.uk \ --cc=xe-linux-external@cisco.com \ --cc=zohar@linux.vnet.ibm.com \ /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: linkBe 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.