[PATCH v2]: write SELinux contexts when extracting a tar file
J. Tang
tang at jtang.org
Tue Mar 16 14:58:56 UTC 2010
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 <tang at jtang.org>
---
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 / tang at jtang.org / http://www.jtang.org
More information about the busybox
mailing list