Browse code

libclamav/untar.c: scan output at end of truncated tar bb#4625 0.97-specific version

David Raynor authored on 2012/06/02 02:15:50
Showing 1 changed files
... ...
@@ -124,8 +124,10 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx)
124 124
 	int size = 0, ret, fout=-1;
125 125
 	int in_block = 0;
126 126
 	int last_header_bad = 0;
127
+	int limitnear = 0;
127 128
 	unsigned int files = 0;
128 129
 	char fullname[NAME_MAX + 1];
130
+	size_t currsize = 0;
129 131
 
130 132
 	cli_dbgmsg("In untar(%s, %d)\n", dir, desc);
131 133
 
... ...
@@ -149,6 +151,7 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx)
149 149
 			int directory, skipEntry = 0;
150 150
 			int checksum = -1;
151 151
 			char magic[7], name[101], osize[TARSIZELEN + 1];
152
+			currsize = 0;
152 153
 
153 154
 			if(fout>=0) {
154 155
 				lseek(fout, 0, SEEK_SET);
... ...
@@ -243,8 +246,20 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx)
243 243
 				skipEntry++;
244 244
 			} else {
245 245
 				cli_dbgmsg("cli_untar: size = %d\n", size);
246
-				if((ret=cli_checklimits("cli_untar", ctx, size, 0, 0))!=CL_CLEAN)
247
-					skipEntry++;
246
+				ret = cli_checklimits("cli_untar", ctx, size, 0, 0);
247
+				switch(ret) {
248
+					case CL_EMAXFILES: // Scan no more files
249
+						skipEntry++;
250
+						limitnear = 0;
251
+						break;
252
+					case CL_EMAXSIZE: // Either single file limit or total byte limit would be exceeded
253
+						cli_dbgmsg("cli_untar: would exceed limit, will try up to max");
254
+						limitnear = 1;
255
+						break;
256
+					default: // Ok based on reported content size
257
+						limitnear = 0;
258
+						break;
259
+				}
248 260
 			}
249 261
 
250 262
 			if(skipEntry) {
... ...
@@ -278,16 +293,40 @@ cli_untar(const char *dir, int desc, unsigned int posix, cli_ctx *ctx)
278 278
 
279 279
 			in_block = 1;
280 280
 		} else { /* write or continue writing file contents */
281
-			const int nbytes = size>512? 512:size;
282
-			const int nwritten = (int)write(fout, block, (size_t)nbytes);
281
+			int nbytes, nwritten;
282
+			int skipwrite = 0;
283
+			char err[128];
284
+
285
+			nbytes = size>512? 512:size;
286
+			if (nread && nread < nbytes)
287
+				nbytes = nread;
288
+
289
+			if (limitnear > 0) {
290
+				currsize += nbytes;
291
+				cli_dbgmsg("cli_untar: Approaching limit...\n");
292
+				if (cli_checklimits("cli_untar", ctx, (unsigned long)currsize, 0, 0) != CL_SUCCESS) {
293
+					// Limit would be exceeded by this file, suppress writing beyond limit
294
+					// Need to keep reading to get to end of file chunk
295
+					skipwrite++;
296
+				}
297
+			}
283 298
 
284
-			if(nwritten != nbytes) {
285
-				cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?)\n",
286
-					nwritten, fullname);
287
-				close(fout);
288
-				return CL_EWRITE;
299
+			if (skipwrite == 0) {
300
+				nwritten = (int)write(fout, block, (size_t)nbytes);
301
+
302
+				if(nwritten != nbytes) {
303
+					cli_errmsg("cli_untar: only wrote %d bytes to file %s (out of disc space?)\n",
304
+						nwritten, fullname);
305
+					close(fout);
306
+					return CL_EWRITE;
307
+				}
289 308
 			}
290 309
 			size -= nbytes;
310
+			if ((size != 0) && (nread == 0)) {
311
+				// Truncated tar file, so end file content like tar behavior
312
+				cli_dbgmsg("cli_untar: No bytes read! Forcing end of file content.\n");
313
+				size = 0;
314
+			}
291 315
 		}
292 316
 		if (size == 0)
293 317
 			in_block = 0;