Here is a second iteration of the patch to enhanch tar, incorporating
suggestions be Denys.  It is baselined against the most recent commit
to origin/master.

Signed-off-by: Jason Tang <[email protected]>

---
 archival/Config.in                       |    8 +++
 archival/libunarchive/data_extract_all.c |    4 +
 archival/libunarchive/get_header_tar.c   |  101 +++++++++++++++++++++++++++++-
 3 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/archival/Config.in b/archival/Config.in
index c99896b..deacc28 100644
--- a/archival/Config.in
+++ b/archival/Config.in
@@ -289,6 +289,14 @@ config FEATURE_TAR_NOPRESERVE_TIME
          With this option busybox supports GNU tar -m
          (do not preserve time) option.
 
+config FEATURE_TAR_SELINUX
+       bool "Support for extracting SELinux labels"
+       default n
+       depends on TAR && SELINUX
+       help
+         With this option busybox supports restoring SELinux labels
+         when extracting files from tar archives.
+
 config UNCOMPRESS
        bool "uncompress"
        default n
diff --git a/archival/libunarchive/data_extract_all.c 
b/archival/libunarchive/data_extract_all.c
index 58b0533..57c5ec4 100644
--- a/archival/libunarchive/data_extract_all.c
+++ b/archival/libunarchive/data_extract_all.c
@@ -158,4 +158,8 @@ void FAST_FUNC data_extract_all(archive_handle_t 
*archive_handle)
                        utimes(file_header->name, t);
                }
        }
+#if ENABLE_FEATURE_TAR_SELINUX
+       /* always reset the context after creating an entry */
+       (void) setfscreatecon(NULL);
+#endif
 }
diff --git a/archival/libunarchive/get_header_tar.c 
b/archival/libunarchive/get_header_tar.c
index d5b86ff..914f145 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -103,6 +103,92 @@ 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 extended header for SELinux contexts, via
+ * "RHT.security.selinux" keyword.  This is the same vendor specific
+ * keyword used by Red Hat's patched version of tar.
+ */
+#define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
+
+static void parse_extended_header(archive_handle_t *archive_handle, off_t sz)
+{
+       char *buf, *p, *next_p, *keyword, *value;
+       off_t len;
+
+       /* prevent a malloc of 0 */
+       if (sz == 0) {
+               return;
+       }
+
+       /* forcibly add a newline at the end of the buffer, to prevent
+          any buffer overflows */
+       p = buf = xmalloc(sz);
+       buf[sz - 1] = '\n';
+
+       xread(archive_handle->src_fd, buf, sz);
+       archive_handle->offset += sz;
+
+       do {
+               /* skip leading whitespace */
+               while (*p == ' ' || *p == '\t') {
+                       p++;
+               }
+
+               /* scan for the length of the record */
+               len = bb_strtou(p, &keyword, 10);
+               /* expect errno to be EINVAL, because the character
+                  following the digits is supposed to be a space */
+               if ((errno != EINVAL) || ((p + len) > (buf + sz))) {
+                       bb_error_msg("Malformed extended header: length is out 
of allowed range");
+                       return;
+               }
+
+               next_p = p + len;
+
+               p = keyword;
+
+               /* scan for the start of the keyword and the value;
+                  they are '=' separated */
+
+               while (*p == ' ' || *p == '\t') {
+                       p++;
+               }
+               keyword = p;
+
+               while (*p != '=' && *p != '\n') {
+                       p++;
+               }
+               if (*p != '=') {
+                       bb_error_msg("Malformed extended header: missing equal 
sign");
+                       return;
+               }
+
+               *p = '\0';
+
+               p++;
+               value = p;
+               while (*p != '\n') {
+                       p++;
+               }
+               *p = '\0';
+
+               p = next_p;
+
+               /* handle fields that are SELinux related */
+               if (strcmp(keyword, SELINUX_CONTEXT_KEYWORD) == 0) {
+                       /* free old context, in case context is given
+                          multiple times */
+                       if (setfscreatecon(value) < 0) {
+                               bb_perror_msg("cannot set label to '%s'", 
value);
+                       }
+               }
+
+       } while (p < buf + sz);
+
+       free(buf);
+}
+#endif
+
 void BUG_tar_header_size(void);
 char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
 {
@@ -150,7 +236,7 @@ char FAST_FUNC get_header_tar(archive_handle_t 
*archive_handle)
        if (sizeof(tar) != 512)
                BUG_tar_header_size();
 
-#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
  again:
 #endif
        /* Align header */
@@ -393,7 +479,10 @@ char FAST_FUNC get_header_tar(archive_handle_t 
*archive_handle)
        case 'V':       /* Volume header */
 #endif
        case 'g':       /* pax global header */
-       case 'x': {     /* pax extended header */
+#if !ENABLE_FEATURE_TAR_SELINUX
+       case 'x':       /* pax extended header, which is skipped */
+#endif
+       {
                off_t sz;
                bb_error_msg("warning: skipping header '%c'", tar.typeflag);
                sz = (file_header->size + 511) & ~(off_t)511;
@@ -404,6 +493,14 @@ 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 'x': {     /* pax extended header */
+               /* read the rest of the extended header, and then
+                  parse its contents */
+               parse_extended_header(archive_handle, file_header->size);
+               goto again;
+#endif
+       }
        default:
                bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
        }
-- 
1.6.6.1

-- 
Jason Tang  /  [email protected]  /  http://www.jtang.org
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to