diff options
author | J. Tang <tang@jtang.org> | 2010-03-19 14:48:51 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-03-19 14:48:51 +0100 |
commit | 77a2c51e79eb54c8f5cc8903465223cbac6e8d50 (patch) | |
tree | 932aff055f4e16da85fe2dbb0c02404407077799 | |
parent | bcda0042e2313d65a835b874c78bf215d743a844 (diff) | |
download | busybox-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.in | 8 | ||||
-rw-r--r-- | archival/libunarchive/data_extract_all.c | 21 | ||||
-rw-r--r-- | archival/libunarchive/get_header_tar.c | 78 | ||||
-rw-r--r-- | include/unarchive.h | 4 |
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 | ||
292 | config 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 | |||
292 | config UNCOMPRESS | 300 | config 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" | ||
111 | static 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 | |||
106 | void BUG_tar_header_size(void); | 163 | void BUG_tar_header_size(void); |
107 | char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) | 164 | char 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; |