aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJ. Tang <tang@jtang.org>2010-03-19 14:48:51 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-03-19 14:48:51 +0100
commit77a2c51e79eb54c8f5cc8903465223cbac6e8d50 (patch)
tree932aff055f4e16da85fe2dbb0c02404407077799
parentbcda0042e2313d65a835b874c78bf215d743a844 (diff)
downloadbusybox-w32-77a2c51e79eb54c8f5cc8903465223cbac6e8d50.tar.gz
busybox-w32-77a2c51e79eb54c8f5cc8903465223cbac6e8d50.tar.bz2
busybox-w32-77a2c51e79eb54c8f5cc8903465223cbac6e8d50.zip
tar: optional support for restoring selinux context
function old new delta get_header_tar 1690 1976 +286 data_extract_all 821 881 +60 .rodata 151446 151503 +57 get_header_cpio 1044 1077 +33 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 436/0) Total: 436 bytes Signed-off-by: J. Tang <tang@jtang.org> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/Config.in8
-rw-r--r--archival/libunarchive/data_extract_all.c21
-rw-r--r--archival/libunarchive/get_header_tar.c78
-rw-r--r--include/unarchive.h4
4 files changed, 108 insertions, 3 deletions
diff --git a/archival/Config.in b/archival/Config.in
index c99896b47..deacc2822 100644
--- a/archival/Config.in
+++ b/archival/Config.in
@@ -289,6 +289,14 @@ config FEATURE_TAR_NOPRESERVE_TIME
289 With this option busybox supports GNU tar -m 289 With this option busybox supports GNU tar -m
290 (do not preserve time) option. 290 (do not preserve time) option.
291 291
292config FEATURE_TAR_SELINUX
293 bool "Support for extracting SELinux labels"
294 default n
295 depends on TAR && SELINUX
296 help
297 With this option busybox supports restoring SELinux labels
298 when extracting files from tar archives.
299
292config UNCOMPRESS 300config UNCOMPRESS
293 bool "uncompress" 301 bool "uncompress"
294 default n 302 default n
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c
index 58b05335b..cc4894229 100644
--- a/archival/libunarchive/data_extract_all.c
+++ b/archival/libunarchive/data_extract_all.c
@@ -12,6 +12,17 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
12 int dst_fd; 12 int dst_fd;
13 int res; 13 int res;
14 14
15#if ENABLE_FEATURE_TAR_SELINUX
16 char *sctx = archive_handle->tar__next_file_sctx;
17 if (!sctx)
18 sctx = archive_handle->tar__global_sctx;
19 if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
20 setfscreatecon(sctx);
21 free(archive_handle->tar__next_file_sctx);
22 archive_handle->tar__next_file_sctx = NULL;
23 }
24#endif
25
15 if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { 26 if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
16 char *slash = strrchr(file_header->name, '/'); 27 char *slash = strrchr(file_header->name, '/');
17 if (slash) { 28 if (slash) {
@@ -45,7 +56,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
45 "same age file exists", file_header->name); 56 "same age file exists", file_header->name);
46 } 57 }
47 data_skip(archive_handle); 58 data_skip(archive_handle);
48 return; 59 goto ret;
49 } 60 }
50 else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { 61 else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
51 bb_perror_msg_and_die("can't remove old file %s", 62 bb_perror_msg_and_die("can't remove old file %s",
@@ -158,4 +169,12 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
158 utimes(file_header->name, t); 169 utimes(file_header->name, t);
159 } 170 }
160 } 171 }
172
173 ret: ;
174#if ENABLE_FEATURE_TAR_SELINUX
175 if (sctx) {
176 /* reset the context after creating an entry */
177 setfscreatecon(NULL);
178 }
179#endif
161} 180}
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c
index d5b86ff5c..cf0b9ab02 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -103,6 +103,63 @@ static unsigned long long getOctal(char *str, int len)
103} 103}
104#define GET_OCTAL(a) getOctal((a), sizeof(a)) 104#define GET_OCTAL(a) getOctal((a), sizeof(a))
105 105
106#if ENABLE_FEATURE_TAR_SELINUX
107/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword.
108 * This is what Red Hat's patched version of tar uses.
109 */
110# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
111static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz)
112{
113 char *buf, *p;
114 char *result;
115
116 p = buf = xmalloc(sz + 1);
117 /* prevent bb_strtou from running off the buffer */
118 buf[sz] = '\0';
119 xread(archive_handle->src_fd, buf, sz);
120 archive_handle->offset += sz;
121
122 result = NULL;
123 while (sz != 0) {
124 char *end, *value;
125 unsigned len;
126
127 /* Every record has this format: "LEN NAME=VALUE\n" */
128 len = bb_strtou(p, &end, 10);
129 /* expect errno to be EINVAL, because the character
130 * following the digits should be a space
131 */
132 p += len;
133 sz -= len;
134 if ((int)sz < 0
135 || len == 0
136 || errno != EINVAL
137 || *end != ' '
138 ) {
139 bb_error_msg("malformed extended header, skipped");
140 // More verbose version:
141 //bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped",
142 // archive_handle->offset - (sz + len));
143 break;
144 }
145 /* overwrite the terminating newline with NUL
146 * (we do not bother to check that it *was* a newline)
147 */
148 p[-1] = '\0';
149 /* Is it selinux security context? */
150 value = end + 1;
151 if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) {
152 value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
153 result = xstrdup(value);
154 break;
155 }
156 }
157
158 free(buf);
159 return result;
160}
161#endif
162
106void BUG_tar_header_size(void); 163void BUG_tar_header_size(void);
107char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) 164char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
108{ 165{
@@ -150,7 +207,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
150 if (sizeof(tar) != 512) 207 if (sizeof(tar) != 512)
151 BUG_tar_header_size(); 208 BUG_tar_header_size();
152 209
153#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 210#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX
154 again: 211 again:
155#endif 212#endif
156 /* Align header */ 213 /* Align header */
@@ -392,8 +449,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
392 case 'S': /* Sparse file */ 449 case 'S': /* Sparse file */
393 case 'V': /* Volume header */ 450 case 'V': /* Volume header */
394#endif 451#endif
452#if !ENABLE_FEATURE_TAR_SELINUX
395 case 'g': /* pax global header */ 453 case 'g': /* pax global header */
396 case 'x': { /* pax extended header */ 454 case 'x': /* pax extended header */
455#else
456 skip_ext_hdr:
457#endif
458 {
397 off_t sz; 459 off_t sz;
398 bb_error_msg("warning: skipping header '%c'", tar.typeflag); 460 bb_error_msg("warning: skipping header '%c'", tar.typeflag);
399 sz = (file_header->size + 511) & ~(off_t)511; 461 sz = (file_header->size + 511) & ~(off_t)511;
@@ -404,6 +466,18 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
404 /* return get_header_tar(archive_handle); */ 466 /* return get_header_tar(archive_handle); */
405 goto again_after_align; 467 goto again_after_align;
406 } 468 }
469#if ENABLE_FEATURE_TAR_SELINUX
470 case 'g': /* pax global header */
471 case 'x': { /* pax extended header */
472 char **pp;
473 if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
474 goto skip_ext_hdr;
475 pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx;
476 free(*pp);
477 *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size);
478 goto again;
479 }
480#endif
407 default: 481 default:
408 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); 482 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
409 } 483 }
diff --git a/include/unarchive.h b/include/unarchive.h
index 92ebd6565..a834816ba 100644
--- a/include/unarchive.h
+++ b/include/unarchive.h
@@ -59,6 +59,10 @@ typedef struct archive_handle_t {
59 char* tar__longname; 59 char* tar__longname;
60 char* tar__linkname; 60 char* tar__linkname;
61# endif 61# endif
62# if ENABLE_FEATURE_TAR_SELINUX
63 char* tar__global_sctx;
64 char* tar__next_file_sctx;
65# endif
62#endif 66#endif
63#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM 67#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM
64 uoff_t cpio__blocks; 68 uoff_t cpio__blocks;