From 6111f967f5299d2eb82fb8eb4bf3b3a4272e3f44 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 23 Feb 2012 13:45:18 +0100 Subject: [PATCH] tar: add support for PAX-encoded path=LONGFILENAME function old new delta get_header_tar 1478 1759 +281 Signed-off-by: Denys Vlasenko --- archival/libarchive/data_extract_all.c | 8 +-- archival/libarchive/data_extract_to_command.c | 8 +-- archival/libarchive/get_header_tar.c | 65 ++++++++++--------- include/bb_archive.h | 9 +-- 4 files changed, 46 insertions(+), 44 deletions(-) diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index f565e5471..3f67b835f 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -13,13 +13,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) int res; #if ENABLE_FEATURE_TAR_SELINUX - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c index cc2ff7798..a2ce33b51 100644 --- a/archival/libarchive/data_extract_to_command.c +++ b/archival/libarchive/data_extract_to_command.c @@ -64,13 +64,13 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) file_header_t *file_header = archive_handle->file_header; #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index a63c0fb01..8c699754b 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -90,23 +90,20 @@ static unsigned long long getOctal(char *str, int len) } #define GET_OCTAL(a) getOctal((a), sizeof(a)) -#if ENABLE_FEATURE_TAR_SELINUX -/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword. - * This is what Red Hat's patched version of tar uses. - */ -# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" -static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz) +/* "global" is 0 or 1 */ +static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global) { char *buf, *p; - char *result; + unsigned blk_sz; + + blk_sz = (sz + 511) & (~511); + p = buf = xmalloc(blk_sz + 1); + xread(archive_handle->src_fd, buf, blk_sz); + archive_handle->offset += blk_sz; - p = buf = xmalloc(sz + 1); /* prevent bb_strtou from running off the buffer */ buf[sz] = '\0'; - xread(archive_handle->src_fd, buf, sz); - archive_handle->offset += sz; - result = NULL; while (sz != 0) { char *end, *value; unsigned len; @@ -133,19 +130,33 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns * (we do not bother to check that it *was* a newline) */ p[-1] = '\0'; - /* Is it selinux security context? */ value = end + 1; + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) { + value += sizeof("path=") - 1; + free(archive_handle->tar__longname); + archive_handle->tar__longname = xstrdup(value); + continue; + } +#endif + +#if ENABLE_FEATURE_TAR_SELINUX + /* Scan for SELinux contexts, via "RHT.security.selinux" keyword. + * This is what Red Hat's patched version of tar uses. + */ +# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; - result = xstrdup(value); - break; + free(archive_handle->tar__sctx[global]); + archive_handle->tar__sctx[global] = xstrdup(value); + continue; } +#endif } free(buf); - return result; } -#endif char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) { @@ -418,12 +429,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case 'S': /* Sparse file */ case 'V': /* Volume header */ #endif -#if !ENABLE_FEATURE_TAR_SELINUX case 'g': /* pax global header */ - case 'x': /* pax extended header */ -#else + case 'x': { /* pax extended header */ + if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ + goto skip_ext_hdr; + process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); + goto again_after_align; + } skip_ext_hdr: -#endif { off_t sz; bb_error_msg("warning: skipping header '%c'", tar.typeflag); @@ -435,18 +448,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* return get_header_tar(archive_handle); */ goto again_after_align; } -#if ENABLE_FEATURE_TAR_SELINUX - case 'g': /* pax global header */ - case 'x': { /* pax extended header */ - char **pp; - if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ - goto skip_ext_hdr; - pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx; - free(*pp); - *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size); - goto again; - } -#endif default: bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); } diff --git a/include/bb_archive.h b/include/bb_archive.h index d1a9a34ec..4987de6cf 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -77,19 +77,20 @@ typedef struct archive_handle_t { off_t offset; /* Archiver specific. Can make it a union if it ever gets big */ +#define PAX_NEXT_FILE 0 +#define PAX_GLOBAL 1 #if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB smallint tar__end; # if ENABLE_FEATURE_TAR_GNU_EXTENSIONS char* tar__longname; char* tar__linkname; # endif -#if ENABLE_FEATURE_TAR_TO_COMMAND +# if ENABLE_FEATURE_TAR_TO_COMMAND char* tar__to_command; const char* tar__to_command_shell; -#endif +# endif # if ENABLE_FEATURE_TAR_SELINUX - char* tar__global_sctx; - char* tar__next_file_sctx; + char* tar__sctx[2]; # endif #endif #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM