aboutsummaryrefslogtreecommitdiff
path: root/archival/libunarchive
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 /archival/libunarchive
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>
Diffstat (limited to 'archival/libunarchive')
-rw-r--r--archival/libunarchive/data_extract_all.c21
-rw-r--r--archival/libunarchive/get_header_tar.c78
2 files changed, 96 insertions, 3 deletions
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 }