Package: busybox

Version: v131.1
Severity: wishlist


This patch adds the ability for tar to extract security capabilities, stored in 
pax headers. I have tested this on Linux Ubuntu x86_64 and it works. I have 
tested it against GNU tar and the outputs are the same (except for the use of 
setxattrat vs setxattr in a warning message). I have ran the tests in the 
testsuite directory, and nothing breaks.


File capabilities divide the permissions of superuser into distinct units, 
these finer grained permissions aid in securing systems. For this reason it 
would be good to get these added to busybox tar.


Thanks

diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 4c95db4a6..24d3c91a1 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -2,9 +2,47 @@
 /*
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
+#if ENABLE_FEATURE_TAR_SEC_CAPABILITY
+#include <sys/types.h>
+#include <sys/xattr.h>
+#endif
 #include "libbb.h"
 #include "bb_archive.h"
 
+#if ENABLE_FEATURE_TAR_SEC_CAPABILITY
+static inline void FAST_FUNC data_apply_capability(file_header_t *file_header, const char *filename, bool is_symlnk)
+{
+#  define SEC_CAPABILITY_FILE_CONTEXT_KEYWORD "security.capability"
+	if (file_header->sec_cap && file_header->sec_cap_len > 0) {
+		const char *sysname = "setxattr";
+		int ret = -1;
+
+		/* lsetxattr works on normal files but GNU tar 1.32 only uses it
+		 * for symlinks.
+		 */
+		if (is_symlnk) {
+			sysname = "lsetxattr";
+			ret = lsetxattr(filename, SEC_CAPABILITY_FILE_CONTEXT_KEYWORD,
+							file_header->sec_cap,
+							file_header->sec_cap_len, 0);
+		} else {
+			ret = setxattr(filename, SEC_CAPABILITY_FILE_CONTEXT_KEYWORD,
+							file_header->sec_cap,
+							file_header->sec_cap_len, 0);
+		}
+
+		if (ret == -1) {
+			bb_error_msg("%s: Cannot set '" SEC_CAPABILITY_FILE_CONTEXT_KEYWORD "' extended attribute for file '%s'", sysname, filename);
+		}
+		free(file_header->sec_cap);
+		file_header->sec_cap = NULL;
+		file_header->sec_cap_len = 0;
+	}
+}
+#else
+static inline void FAST_FUNC data_apply_capability(const file_header_t *file_header, const char *filename, bool is_symlnk) {}
+#endif
+
 void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
 {
 	file_header_t *file_header = archive_handle->file_header;
@@ -245,6 +283,12 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
 		}
 	}
 
+	/**
+	 * the file security capability must be applied after
+	 * chmod (as per GNU tar)
+	 */
+	data_apply_capability(file_header, dst_name, (file_header->mode & S_IFMT) == S_IFLNK);
+
  ret: ;
 #if ENABLE_FEATURE_TAR_SELINUX
 	if (sctx) {
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index 52fa4554a..30ba90c67 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -60,7 +60,7 @@ static unsigned long long getOctal(char *str, int len)
 }
 #define GET_OCTAL(a) getOctal((a), sizeof(a))
 
-#define TAR_EXTD (ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX)
+#define TAR_EXTD (ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX || ENABLE_FEATURE_TAR_SEC_CAPABILITY)
 #if !TAR_EXTD
 #define process_pax_hdr(archive_handle, sz, global) \
 	process_pax_hdr(archive_handle, sz)
@@ -129,6 +129,23 @@ static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int g
 		}
 # endif
 
+# if ENABLE_FEATURE_TAR_SEC_CAPABILITY
+		if (!global) {
+		/* Scan for security capabilities, via "SCHILY.xattr.security.capability".
+		 * This is what GNU tar uses.
+		 */
+#  define SEC_CAPABILITY_TAR_CONTEXT_KEYWORD "SCHILY.xattr.security.capability"
+			if (is_prefixed_with(value, SEC_CAPABILITY_TAR_CONTEXT_KEYWORD"=")) {
+				free(archive_handle->tar__sec_cap);
+				value += sizeof(SEC_CAPABILITY_TAR_CONTEXT_KEYWORD"=") - 1;
+				archive_handle->tar__sec_cap_len = (size_t)(p - value) - 1;
+				archive_handle->tar__sec_cap = malloc(archive_handle->tar__sec_cap_len);
+				archive_handle->tar__sec_cap = memcpy(archive_handle->tar__sec_cap, value, archive_handle->tar__sec_cap_len);
+				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.
@@ -383,6 +400,12 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
 		if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
 			goto skip_ext_hdr;
 		process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g'));
+#if ENABLE_FEATURE_TAR_SEC_CAPABILITY
+		file_header->sec_cap = archive_handle->tar__sec_cap;
+		file_header->sec_cap_len = archive_handle->tar__sec_cap_len;
+		archive_handle->tar__sec_cap = NULL;
+		archive_handle->tar__sec_cap_len = 0;
+#endif
 		goto again_after_align;
 #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
 /* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */
diff --git a/archival/tar.c b/archival/tar.c
index 3ef89fb0a..c158ec121 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -110,6 +110,14 @@
 //config:	help
 //config:	With this option busybox supports restoring SELinux labels
 //config:	when extracting files from tar archives.
+//config:
+//config:config FEATURE_TAR_SEC_CAPABILITY
+//config:	bool "Support extracting security capability"
+//config:	default n
+//config:	depends on TAR
+//config:	help
+//config:	With this option busybox supports restoring security capability
+//config:	when extracting files from tar archives.
 
 //applet:IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP))
 
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 9b1db5b3e..40d9394fc 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -41,6 +41,10 @@ typedef struct file_header_t {
 	mode_t mode;
 	time_t mtime;
 	dev_t device;
+#if ENABLE_FEATURE_TAR_SEC_CAPABILITY
+	char *sec_cap;
+	size_t *sec_cap_len;
+#endif
 } file_header_t;
 
 struct hardlinks_t;
@@ -121,6 +125,10 @@ typedef struct archive_handle_t {
 	char *ar__long_names;
 	unsigned ar__long_name_size;
 #endif
+#if ENABLE_FEATURE_TAR_SEC_CAPABILITY
+	char *tar__sec_cap;
+	size_t tar__sec_cap_len;
+#endif
 } archive_handle_t;
 /* bits in ah_flags */
 #define ARCHIVE_RESTORE_DATE        (1 << 0)
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to