diff --git a/add-option-to-add-metadata-in-copy-out-mode.patch b/add-option-to-add-metadata-in-copy-out-mode.patch new file mode 100644 index 0000000..bedfeac --- /dev/null +++ b/add-option-to-add-metadata-in-copy-out-mode.patch @@ -0,0 +1,428 @@ +From 531cabc88e9ecdc3231fad6e4856869baa9a91ef Mon Sep 17 00:00:00 2001 +From: Roberto Sassu +Date: Wed, 22 May 2019 09:04:39 +0200 +Subject: [PATCH] cpio: add option to add file metadata in copy-out mode + +This patch adds the -e option to include file metadata in the +image. At the moment, only the xattr type is supported. + +If the xattr type is selected, the patch includes an additional file for +each file passed to stdin, with special name 'METADATA!!!'. The +additional file might contain multiple metadata records. The format of +each record is: + + + +The format of metadata for the xattr type is: + +\0 + +Signed-off-by: Roberto Sassu +--- + doc/cpio.texi | 3 ++ + src/copyout.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++-- + src/dstring.c | 26 +++++++-- + src/dstring.h | 1 + + src/extern.h | 4 +- + src/global.c | 2 + + src/initramfs.h | 21 ++++++++ + src/main.c | 22 ++++++++ + 8 files changed, 211 insertions(+), 8 deletions(-) + create mode 100644 src/initramfs.h + +diff --git a/doc/cpio.texi b/doc/cpio.texi +index a788b5d..df2d15d 100644 +--- a/doc/cpio.texi ++++ b/doc/cpio.texi +@@ -269,6 +269,9 @@ Set the I/O block size to the given @var{number} of bytes. + @item -D @var{dir} + @itemx --directory=@var{dir} + Change to directory @var{dir} ++@item -e @var{type} ++@itemx --file-metadata=@var{type} ++Include in the image file metadata with the specified type. + @item --force-local + Treat the archive file as local, even if its name contains colons. + @item -F [[@var{user}@@]@var{host}:]@var{archive-file} +diff --git a/src/copyout.c b/src/copyout.c +index 1ae5477..a7fc593 100644 +--- a/src/copyout.c ++++ b/src/copyout.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include "filetypes.h" + #include "cpiohdr.h" + #include "dstring.h" +@@ -589,6 +590,94 @@ assign_string (char **pvar, char *value) + *pvar = p; + } + ++static int ++write_xattrs (int metadata_fd, char *path) ++{ ++ struct metadata_hdr hdr = { .c_version = 1, .c_type = TYPE_XATTR }; ++ char str[sizeof(hdr.c_size) + 1]; ++ char *xattr_list = NULL; ++ char *list_ptr = NULL; ++ char *xattr_value = NULL; ++ ssize_t list_len, name_len, value_len, len; ++ int ret = -EINVAL; ++ ++ if (metadata_fd < 0) ++ return 0; ++ ++ list_len = llistxattr(path, NULL, 0); ++ if (list_len <= 0) ++ return -ENOENT; ++ ++ list_ptr = xattr_list = malloc(list_len); ++ if (!list_ptr) { ++ error (0, 0, _("out of memory")); ++ return ret; ++ } ++ ++ len = llistxattr(path, xattr_list, list_len); ++ if (len != list_len) ++ goto out; ++ ++ if (ftruncate(metadata_fd, 0)) ++ goto out; ++ ++ lseek(metadata_fd, 0, SEEK_SET); ++ ++ while (list_ptr < xattr_list + list_len) { ++ name_len = strlen(list_ptr); ++ ++ value_len = lgetxattr(path, list_ptr, NULL, 0); ++ if (value_len < 0) { ++ error (0, 0, _("cannot get xattrs")); ++ break; ++ } ++ ++ if (value_len) { ++ xattr_value = malloc(value_len); ++ if (!xattr_value) { ++ error (0, 0, _("out of memory")); ++ break; ++ } ++ } else { ++ xattr_value = NULL; ++ } ++ ++ len = lgetxattr(path, list_ptr, xattr_value, value_len); ++ if (len != value_len) ++ break; ++ ++ snprintf(str, sizeof(str), "%.8lx", ++ sizeof(hdr) + name_len + 1 + value_len); ++ ++ memcpy(hdr.c_size, str, sizeof(hdr.c_size)); ++ ++ if (write(metadata_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) ++ break; ++ ++ if (write(metadata_fd, list_ptr, name_len + 1) != name_len + 1) ++ break; ++ ++ if (write(metadata_fd, xattr_value, value_len) != value_len) ++ break; ++ ++ if (fsync(metadata_fd)) ++ break; ++ ++ list_ptr += name_len + 1; ++ free(xattr_value); ++ xattr_value = NULL; ++ } ++ ++ free(xattr_value); ++out: ++ free(xattr_list); ++ ++ if (list_ptr != xattr_list + list_len) ++ return ret; ++ ++ return 0; ++} ++ + /* Read a list of file names from the standard input + and write a cpio collection on the standard output. + The format of the header depends on the compatibility (-c) flag. */ +@@ -602,6 +691,8 @@ process_copy_out () + int in_file_des; /* Source file descriptor. */ + int out_file_des; /* Output file descriptor. */ + char *orig_file_name = NULL; ++ char template[] = "/tmp/cpio-metadata-XXXXXX"; ++ int ret, metadata_fd, metadata = 0, old_metadata, hard_link; + + /* Initialize the copy out. */ + ds_init (&input_name, 128); +@@ -634,9 +725,37 @@ process_copy_out () + prepare_append (out_file_des); + } + ++ /* Create a temporary file to store file metadata */ ++ if (metadata_type != TYPE_NONE) { ++ metadata_fd = mkstemp(template); ++ if (metadata_fd < 0) { ++ error (0, 0, _("cannot create temporary file")); ++ return; ++ } ++ } ++ + /* Copy files with names read from stdin. */ +- while (ds_fgetstr (stdin, &input_name, name_end) != NULL) ++ while ((metadata_type != TYPE_NONE && metadata) || ++ ds_fgetstr (stdin, &input_name, name_end) != NULL) + { ++ old_metadata = metadata; ++ hard_link = 0; ++ ++ if (metadata) { ++ metadata = 0; ++ ++ if (metadata_type != TYPE_XATTR) { ++ error (0, 0, _("metadata type not supported")); ++ continue; ++ } ++ ++ ret = write_xattrs(metadata_fd, orig_file_name); ++ if (ret < 0) ++ continue; ++ ++ ds_sgetstr (template, &input_name, name_end); ++ } ++ + /* Check for blank line. */ + if (input_name.ds_string[0] == 0) + { +@@ -666,8 +785,15 @@ process_copy_out () + } + } + } +- +- assign_string (&orig_file_name, input_name.ds_string); ++ ++ if (old_metadata) { ++ assign_string (&orig_file_name, template); ++ ds_sgetstr (METADATA_FILENAME, &input_name, name_end); ++ file_hdr.c_mode |= 0x10000; ++ } else { ++ assign_string (&orig_file_name, input_name.ds_string); ++ } ++ + cpio_safer_name_suffix (input_name.ds_string, false, + !no_abs_paths_flag, true); + #ifndef HPUX_CDF +@@ -721,6 +847,7 @@ process_copy_out () + else + { + add_link_defer (&file_hdr); ++ hard_link = 1; + break; + } + } +@@ -857,6 +984,8 @@ process_copy_out () + fprintf (stderr, "%s\n", orig_file_name); + if (dot_flag) + fputc ('.', stderr); ++ if (metadata_type != TYPE_NONE && !old_metadata && !hard_link) ++ metadata = 1; + } + } + +@@ -896,6 +1025,11 @@ process_copy_out () + ngettext ("%lu block\n", "%lu blocks\n", + (unsigned long) blocks), (unsigned long) blocks); + } ++ ++ if (metadata_type != TYPE_NONE) { ++ close(metadata_fd); ++ unlink(template); ++ } + } + + +diff --git a/src/dstring.c b/src/dstring.c +index 2e6b97b..2c1516e 100644 +--- a/src/dstring.c ++++ b/src/dstring.c +@@ -60,8 +60,8 @@ ds_resize (dynamic_string *string, int size) + Return NULL if end of file is detected. Otherwise, + Return a pointer to the null-terminated string in S. */ + +-char * +-ds_fgetstr (FILE *f, dynamic_string *s, char eos) ++static char * ++ds_fgetstr_common (FILE *f, char *input_string, dynamic_string *s, char eos) + { + int insize; /* Amount needed for line. */ + int strsize; /* Amount allocated for S. */ +@@ -72,7 +72,10 @@ ds_fgetstr (FILE *f, dynamic_string *s, char eos) + strsize = s->ds_length; + + /* Read the input string. */ +- next_ch = getc (f); ++ if (input_string) ++ next_ch = *input_string++; ++ else ++ next_ch = getc (f); + while (next_ch != eos && next_ch != EOF) + { + if (insize >= strsize - 1) +@@ -81,7 +84,10 @@ ds_fgetstr (FILE *f, dynamic_string *s, char eos) + strsize = s->ds_length; + } + s->ds_string[insize++] = next_ch; +- next_ch = getc (f); ++ if (input_string) ++ next_ch = *input_string++; ++ else ++ next_ch = getc (f); + } + s->ds_string[insize++] = '\0'; + +@@ -91,6 +97,12 @@ ds_fgetstr (FILE *f, dynamic_string *s, char eos) + return s->ds_string; + } + ++char * ++ds_fgetstr (FILE *f, dynamic_string *s, char eos) ++{ ++ return ds_fgetstr_common (f, NULL, s, eos); ++} ++ + char * + ds_fgets (FILE *f, dynamic_string *s) + { +@@ -102,3 +114,9 @@ ds_fgetname (FILE *f, dynamic_string *s) + { + return ds_fgetstr (f, s, '\0'); + } ++ ++char * ++ds_sgetstr (char *input_string, dynamic_string *s, char eos) ++{ ++ return ds_fgetstr_common (NULL, input_string, s, eos); ++} +diff --git a/src/dstring.h b/src/dstring.h +index 5b49def..a0f36fb 100644 +--- a/src/dstring.h ++++ b/src/dstring.h +@@ -49,3 +49,4 @@ void ds_resize (dynamic_string *string, int size); + char *ds_fgetname (FILE *f, dynamic_string *s); + char *ds_fgets (FILE *f, dynamic_string *s); + char *ds_fgetstr (FILE *f, dynamic_string *s, char eos); ++char *ds_sgetstr (char *input_string, dynamic_string *s, char eos); +diff --git a/src/extern.h b/src/extern.h +index f9ef56a..935f8f8 100644 +--- a/src/extern.h ++++ b/src/extern.h +@@ -19,6 +19,7 @@ + + #include "paxlib.h" + #include "quotearg.h" ++#include "initramfs.h" + #include "quote.h" + + enum archive_format +@@ -99,7 +100,8 @@ extern char output_is_seekable; + extern int (*xstat) (); + extern void (*copy_function) (); + extern char *change_directory_option; +- ++extern enum metadata_types metadata_type; ++ + + /* copyin.c */ + void warn_junk_bytes (long bytes_skipped); +diff --git a/src/global.c b/src/global.c +index 57e505a..34ea42d 100644 +--- a/src/global.c ++++ b/src/global.c +@@ -199,3 +199,5 @@ char *change_directory_option; + int renumber_inodes_option; + int ignore_devno_option; + ++/* include file metadata into the image */ ++enum metadata_types metadata_type = TYPE_NONE; +diff --git a/src/initramfs.h b/src/initramfs.h +new file mode 100644 +index 0000000..88abae7 +--- /dev/null ++++ b/src/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 */ ++} __attribute__((packed)); ++ ++#endif /*_LINUX_INITRAMFS_H*/ +diff --git a/src/main.c b/src/main.c +index 72ed25d..9206917 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -200,6 +200,8 @@ static struct argp_option options[] = { + {"device-independent", DEVICE_INDEPENDENT_OPTION, NULL, 0, + N_("Create device-independent (reproducible) archives") }, + {"reproducible", 0, NULL, OPTION_ALIAS }, ++ {"file-metadata", 'e', N_("TYPE"), 0, ++ N_("Include file metadata"), GRID+1 }, + #undef GRID + + /* ********** */ +@@ -293,6 +295,22 @@ warn_control (char *arg) + return 1; + } + ++static enum metadata_types ++parse_metadata_type(char *arg) ++{ ++ static char *metadata_type_str[TYPE__LAST] = { ++ [TYPE_NONE] = "none", ++ [TYPE_XATTR] = "xattr", ++ }; ++ int i; ++ ++ for (i = 0; i < TYPE__LAST; i++) ++ if (!strcmp (metadata_type_str[i], arg)) ++ return i; ++ ++ return TYPE_NONE; ++} ++ + static error_t + parse_opt (int key, char *arg, struct argp_state *state) + { +@@ -355,6 +373,10 @@ parse_opt (int key, char *arg, struct argp_state *state) + copy_matching_files = false; + break; + ++ case 'e': /* Metadata type. */ ++ metadata_type = parse_metadata_type(arg); ++ break; ++ + case 'E': /* Pattern file name. */ + pattern_file_name = arg; + break; +-- +2.19.1 + diff --git a/cpio.spec b/cpio.spec index 55de345..3796705 100644 --- a/cpio.spec +++ b/cpio.spec @@ -1,6 +1,6 @@ Name: cpio Version: 2.12 -Release: 14 +Release: 15 Summary: A GNU archiving program License: GPLv3+ @@ -17,6 +17,7 @@ Patch6: cpio-2.11-crc-fips-nit.patch Patch6000: Fix-out-of-bounds-read.patch Patch6001: Fix-signed-integer-overflow-big-block-sizes.patch Patch6002: Fix-CVE-2019-14866.patch +Patch6003: add-option-to-add-metadata-in-copy-out-mode.patch Provides: bundled(gnulib) Provides: /bin/cpio @@ -59,6 +60,12 @@ make check %{_datadir}/man/man1/%{name}.1.gz %changelog +* Thu Jul 2 2020 Anakin Zhang - 2.12-15 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:add option to add file metadata in copy-out mode + * Sat Dec 21 2019 openEuler Buildteam - 2.12-14 - Fix CVE-2019-14866