1 /* Author: Jason Tang <[email protected]>
2 * Christopher Ashworth <[email protected]>
3 * Ondrej Mosnacek <[email protected]>
4 *
5 * Copyright (C) 2004-2006 Tresys Technology, LLC
6 * Copyright (C) 2005-2021 Red Hat, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26
27 #include <unistd.h>
28 #include <fcntl.h>
29
30 #include <bzlib.h>
31
32 #include "compressed_file.h"
33
34 #include "debug.h"
35
36 #define BZ2_MAGICSTR "BZh"
37 #define BZ2_MAGICLEN (sizeof(BZ2_MAGICSTR)-1)
38
39 /* bzip() a data to a file, returning the total number of compressed bytes
40 * in the file. Returns -1 if file could not be compressed. */
bzip(semanage_handle_t * sh,const char * filename,void * data,size_t num_bytes)41 static int bzip(semanage_handle_t *sh, const char *filename, void *data,
42 size_t num_bytes)
43 {
44 BZFILE* b;
45 size_t size = 1<<16;
46 int bzerror;
47 size_t total = 0;
48 size_t len = 0;
49 FILE *f;
50
51 if ((f = fopen(filename, "wb")) == NULL) {
52 return -1;
53 }
54
55 if (!sh->conf->bzip_blocksize) {
56 if (fwrite(data, 1, num_bytes, f) < num_bytes) {
57 fclose(f);
58 return -1;
59 }
60 fclose(f);
61 return 0;
62 }
63
64 b = BZ2_bzWriteOpen( &bzerror, f, sh->conf->bzip_blocksize, 0, 0);
65 if (bzerror != BZ_OK) {
66 BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
67 fclose(f);
68 return -1;
69 }
70
71 while ( num_bytes > total ) {
72 if (num_bytes - total > size) {
73 len = size;
74 } else {
75 len = num_bytes - total;
76 }
77 BZ2_bzWrite ( &bzerror, b, (uint8_t *)data + total, len );
78 if (bzerror == BZ_IO_ERROR) {
79 BZ2_bzWriteClose ( &bzerror, b, 1, 0, 0 );
80 fclose(f);
81 return -1;
82 }
83 total += len;
84 }
85
86 BZ2_bzWriteClose ( &bzerror, b, 0, 0, 0 );
87 fclose(f);
88 if (bzerror == BZ_IO_ERROR) {
89 return -1;
90 }
91 return 0;
92 }
93
94 /* bunzip() a file to '*data', returning the total number of uncompressed bytes
95 * in the file. Returns -1 if file could not be decompressed. */
bunzip(semanage_handle_t * sh,FILE * f,void ** data)96 static ssize_t bunzip(semanage_handle_t *sh, FILE *f, void **data)
97 {
98 BZFILE* b = NULL;
99 size_t nBuf;
100 uint8_t* buf = NULL;
101 size_t size = 1<<18;
102 size_t bufsize = size;
103 int bzerror;
104 size_t total = 0;
105 uint8_t* uncompress = NULL;
106 uint8_t* tmpalloc = NULL;
107 int ret = -1;
108
109 buf = malloc(bufsize);
110 if (buf == NULL) {
111 ERR(sh, "Failure allocating memory.");
112 goto exit;
113 }
114
115 /* Check if the file is bzipped */
116 bzerror = fread(buf, 1, BZ2_MAGICLEN, f);
117
118 if (fseek(f, 0L, SEEK_SET) == -1) {
119 ERR(sh, "Failure rewinding file.");
120 goto exit;
121 }
122
123 if ((bzerror != BZ2_MAGICLEN) || memcmp(buf, BZ2_MAGICSTR, BZ2_MAGICLEN)) {
124 goto exit;
125 }
126
127 b = BZ2_bzReadOpen ( &bzerror, f, 0, sh->conf->bzip_small, NULL, 0 );
128 if ( bzerror != BZ_OK ) {
129 ERR(sh, "Failure opening bz2 archive.");
130 goto exit;
131 }
132
133 uncompress = malloc(size);
134 if (uncompress == NULL) {
135 ERR(sh, "Failure allocating memory.");
136 goto exit;
137 }
138
139 while ( bzerror == BZ_OK) {
140 nBuf = BZ2_bzRead ( &bzerror, b, buf, bufsize);
141 if (( bzerror == BZ_OK ) || ( bzerror == BZ_STREAM_END )) {
142 if (total + nBuf > size) {
143 size *= 2;
144 tmpalloc = realloc(uncompress, size);
145 if (tmpalloc == NULL) {
146 ERR(sh, "Failure allocating memory.");
147 goto exit;
148 }
149 uncompress = tmpalloc;
150 }
151 memcpy(&uncompress[total], buf, nBuf);
152 total += nBuf;
153 }
154 }
155 if ( bzerror != BZ_STREAM_END ) {
156 ERR(sh, "Failure reading bz2 archive.");
157 goto exit;
158 }
159
160 ret = total;
161 *data = uncompress;
162
163 exit:
164 BZ2_bzReadClose ( &bzerror, b );
165 free(buf);
166 if ( ret < 0 ) {
167 free(uncompress);
168 }
169 return ret;
170 }
171
map_compressed_file(semanage_handle_t * sh,const char * path,struct file_contents * contents)172 int map_compressed_file(semanage_handle_t *sh, const char *path,
173 struct file_contents *contents)
174 {
175 ssize_t size = -1;
176 void *uncompress;
177 int ret = 0, fd = -1;
178 FILE *file = NULL;
179
180 fd = open(path, O_RDONLY);
181 if (fd == -1) {
182 ERR(sh, "Unable to open %s\n", path);
183 return -1;
184 }
185
186 file = fdopen(fd, "r");
187 if (file == NULL) {
188 ERR(sh, "Unable to open %s\n", path);
189 close(fd);
190 return -1;
191 }
192
193 if ((size = bunzip(sh, file, &uncompress)) >= 0) {
194 contents->data = uncompress;
195 contents->len = size;
196 contents->compressed = 1;
197 } else {
198 struct stat sb;
199 if (fstat(fd, &sb) == -1 ||
200 (uncompress = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) ==
201 MAP_FAILED) {
202 ret = -1;
203 } else {
204 contents->data = uncompress;
205 contents->len = sb.st_size;
206 contents->compressed = 0;
207 }
208 }
209 fclose(file);
210 return ret;
211 }
212
unmap_compressed_file(struct file_contents * contents)213 void unmap_compressed_file(struct file_contents *contents)
214 {
215 if (!contents->data)
216 return;
217
218 if (contents->compressed) {
219 free(contents->data);
220 } else {
221 munmap(contents->data, contents->len);
222 }
223 }
224
write_compressed_file(semanage_handle_t * sh,const char * path,void * data,size_t len)225 int write_compressed_file(semanage_handle_t *sh, const char *path,
226 void *data, size_t len)
227 {
228 return bzip(sh, path, data, len);
229 }
230