xref: /aosp_15_r20/external/selinux/libsemanage/src/compressed_file.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
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