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