Browse code

Guard against infinite loops

git-svn: trunk@2509

Nigel Horne authored on 2006/11/19 07:46:01
Showing 2 changed files
... ...
@@ -1,3 +1,9 @@
1
+Sat Nov 18 22:44:37 GMT 2006 (njh)
2
+----------------------------------
3
+ * libclamav:	Don't implement the sleep function
4
+ 		Handle DoS attacks on the JS VM by adding a timeout guarding
5
+			against infinite loops
6
+
1 7
 Sat Nov 18 21:46:10 CET 2006 (tk)
2 8
 ---------------------------------
3 9
   * libclamav/matcher-ac.c: multipart signatures: give higher priority to new
... ...
@@ -28,7 +28,7 @@
28 28
  * TODO:	Add mailfollowurls type feature
29 29
  * TODO:	Check for vulnerabilities, leaks etc.
30 30
  */
31
-static	char	const	rcsid[] = "$Id: jscript.c,v 1.5 2006/11/11 17:18:10 njh Exp $";
31
+static	char	const	rcsid[] = "$Id: jscript.c,v 1.6 2006/11/18 22:42:40 njh Exp $";
32 32
 
33 33
 #if HAVE_CONFIG_H
34 34
 #include "clamav-config.h"
... ...
@@ -70,6 +70,16 @@ static	char	const	rcsid[] = "$Id: jscript.c,v 1.5 2006/11/11 17:18:10 njh Exp $"
70 70
 # endif
71 71
 #endif
72 72
 
73
+#ifdef	CL_THREAD_SAFE
74
+#define	VM_TIMEOUT	5	/* In seconds: FIXME should be configurable */
75
+#endif
76
+
77
+#if	defined(VM_TIMEOUT) && (VM_TIMEOUT > 0)
78
+#include <pthread.h>
79
+#include <sys/time.h>
80
+#include <signal.h>
81
+#endif
82
+
73 83
 static	int	run_js(const char *filename, const char *dir);
74 84
 static	const	char	*cli_pmemstr(const char *haystack, size_t hs, const char *needle, size_t ns);
75 85
 
... ...
@@ -268,6 +278,111 @@ write_to_fout(void *context, unsigned char *buf, unsigned int len)
268 268
 	return (int)fwrite(buf, (size_t)len, 1, fout);
269 269
 }
270 270
 
271
+#if	defined(VM_TIMEOUT) && (VM_TIMEOUT > 0)
272
+
273
+struct args {
274
+	const char *filename;
275
+	const char *dir;
276
+	pthread_cond_t	*cond;
277
+	int	result;
278
+};
279
+
280
+static void
281
+sigrecv(int sig)
282
+{
283
+	/* pthread_cond_broadcast(&cond); */
284
+	pthread_exit(NULL);	/* FIXME: interp isn't destroyed - mem leak? */
285
+}
286
+
287
+static void *
288
+js_thread(void *a)
289
+{
290
+	JSInterpPtr interp;
291
+	char *outputfilename;
292
+	struct args *args = (struct args *)a;
293
+	const char *dir = args->dir;
294
+	const char *filename = args->filename;
295
+
296
+	cli_dbgmsg("run_js(%s)\n", filename);
297
+
298
+	outputfilename = cli_gentemp(dir);
299
+	if(outputfilename == NULL) {
300
+		pthread_cond_broadcast(args->cond);
301
+		args->result = CL_ETMPFILE;
302
+		return NULL;
303
+	}
304
+
305
+	fout = fopen(outputfilename, "wb");
306
+	if(fout == NULL) {
307
+		pthread_cond_broadcast(args->cond);
308
+		cli_warnmsg("Can't create %s\n", outputfilename);
309
+		free(outputfilename);
310
+		args->result = CL_ETMPFILE;
311
+		return NULL;
312
+	}
313
+
314
+	cli_dbgmsg("Redirecting JS VM stdout to %s\n", outputfilename);
315
+	free(outputfilename);
316
+
317
+	/*
318
+	 * Run NGS on the file
319
+	 */
320
+	interp = create_interp(write_to_fout);
321
+
322
+	args->result = CL_EIO;	/* TODO: CL_TIMEOUT */
323
+
324
+	if(!js_eval_file(interp, filename)) {
325
+		cli_warnmsg("JS failed: %s\n", js_error_message(interp));
326
+		/*rc = CL_EIO;*/
327
+	}
328
+
329
+	if(pthread_cond_broadcast(args->cond) < 0)
330
+		perror("pthread_cond_broadcast");
331
+
332
+	js_destroy_interp(interp);
333
+
334
+	fclose(fout);
335
+
336
+	args->result = CL_SUCCESS;
337
+	return NULL;
338
+}
339
+
340
+static int
341
+run_js(const char *filename, const char *dir)
342
+{
343
+	struct args args;
344
+	pthread_t tid;
345
+	struct timespec ts;
346
+	struct timeval tp;
347
+	pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
348
+	pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
349
+	void (*oldkill)(int);
350
+
351
+	args.filename = filename;
352
+	args.dir = dir;
353
+	args.cond = &cond;
354
+
355
+	pthread_create(&tid, NULL, js_thread, &args);
356
+
357
+	gettimeofday(&tp, NULL);
358
+
359
+	ts.tv_sec = tp.tv_sec + VM_TIMEOUT;
360
+	ts.tv_nsec = tp.tv_usec * 1000;
361
+
362
+	oldkill = signal(SIGUSR1, sigrecv);
363
+	pthread_mutex_lock(&mutex);
364
+	if(pthread_cond_timedwait(&cond, &mutex, &ts) == ETIMEDOUT) {
365
+		cli_warnmsg("Run away javascript stopped after %d seconds\n",
366
+			VM_TIMEOUT);
367
+		pthread_kill(tid, SIGUSR1);
368
+	}
369
+	pthread_mutex_unlock(&mutex);
370
+	pthread_join(tid, NULL);
371
+	signal(SIGUSR1, oldkill);
372
+
373
+	return args.result;
374
+}
375
+#else
271 376
 static int
272 377
 run_js(const char *filename, const char *dir)
273 378
 {
... ...
@@ -306,6 +421,7 @@ run_js(const char *filename, const char *dir)
306 306
 
307 307
 	return CL_SUCCESS;
308 308
 }
309
+#endif
309 310
 
310 311
 /* Copied from pdf.c :-( */
311 312
 /*