Browse code

avoid calling non-async-signal-safe functions between fork() and exec() (bb #889) unit_tests: add unit-test for virusaction

git-svn: trunk@4034

Török Edvin authored on 2008/07/31 02:26:46
Showing 4 changed files
... ...
@@ -1,3 +1,9 @@
1
+Wed Jul 30 20:09:03 EEST 2008 (edwin)
2
+-------------------------------------
3
+  * clamd/others.c: avoid calling non-async-signal-safe functions between fork()
4
+  and exec() (bb #889)
5
+  * unit_tests: add unit-test for virusaction
6
+
1 7
 Wed Jul 30 17:02:40 CEST 2008 (tk)
2 8
 ----------------------------------
3 9
   * clamscan, clamav-milter: catch and ignore SIGXFSZ; display warning if
... ...
@@ -90,61 +90,67 @@ void virusaction(const char *filename, const char *virname, const struct cfgstru
90 90
 }
91 91
 
92 92
 #else
93
-
94 93
 void virusaction(const char *filename, const char *virname, const struct cfgstruct *copt)
95 94
 {
96 95
 	pid_t pid;
97 96
 	const struct cfgstruct *cpt;
97
+	char *buffer, *pt, *cmd, *buffer_file, *buffer_vir;
98
+	size_t j;
99
+	char *env[4];
98 100
 
99
-    if(!(cpt = cfgopt(copt, "VirusEvent"))->enabled)
100
-	return;
101
+	if(!(cpt = cfgopt(copt, "VirusEvent"))->enabled)
102
+		return;
101 103
 
102
-    /* NB: we need to fork here since this function modifies the environment. 
103
-       (Modifications to the env. are not reentrant, but we need to be.) */
104
-    pid = fork();
104
+	env[0] = getenv("PATH");
105
+	j = env[0] ? 1 : 0;
106
+	/* Allocate env vars.. to be portable env vars should not be freed */
107
+	buffer_file = (char *) malloc(strlen(ENV_FILE) + strlen(filename) + 2);
108
+	if(buffer_file) {
109
+		sprintf(buffer_file, "%s=%s", ENV_FILE, filename);
110
+		env[j++] = buffer_file;
111
+	}
105 112
 
106
-    if ( pid == 0 ) {
107
-	/* child... */
108
-	char *buffer, *pt, *cmd;
113
+	buffer_vir = (char *) malloc(strlen(ENV_VIRUS) + strlen(virname) + 2);
114
+	if(buffer_vir) {
115
+		sprintf(buffer_vir, "%s=%s", ENV_VIRUS, virname);
116
+		env[j++] = buffer_vir;
117
+	}
118
+	env[j++] = NULL;
109 119
 
110 120
 	cmd = strdup(cpt->strarg);
111 121
 
112 122
 	if(cmd && (pt = strstr(cmd, "%v"))) {
113
-	    buffer = (char *) malloc(strlen(cmd) + strlen(virname) + 10);
114
-	    if(buffer) {
115
-		*pt = 0; pt += 2;
116
-		strcpy(buffer, cmd);
117
-		strcat(buffer, virname);
118
-		strcat(buffer, pt);
119
-		free(cmd);
120
-		cmd = strdup(buffer);
121
-		free(buffer);
122
-	    }
123
-	}
124
-
125
-	/* Allocate env vars.. to be portable env vars should not be freed */
126
-	buffer = (char *) malloc(strlen(ENV_FILE) + strlen(filename) + 2);
127
-	if(buffer) {
128
-	    sprintf(buffer, "%s=%s", ENV_FILE, filename);
129
-	    putenv(buffer);
123
+		buffer = (char *) malloc(strlen(cmd) + strlen(virname) + 10);
124
+		if(buffer) {
125
+			*pt = 0; pt += 2;
126
+			strcpy(buffer, cmd);
127
+			strcat(buffer, virname);
128
+			strcat(buffer, pt);
129
+			free(cmd);
130
+			cmd = strdup(buffer);
131
+			free(buffer);
132
+		}
130 133
 	}
131 134
 
132
-	buffer = (char *) malloc(strlen(ENV_VIRUS) + strlen(virname) + 2);
133
-	if(buffer) {
134
-	    sprintf(buffer, "%s=%s", ENV_VIRUS, virname);
135
-	    putenv(buffer);
135
+	if(!cmd)
136
+		return;
137
+	/* We can only call async-signal-safe functions after fork(). */
138
+	pid = fork();
139
+
140
+	if ( pid == 0 ) {
141
+		/* child... */
142
+		/* WARNING: this is uninterruptable ! */
143
+		exit(execle("/bin/sh", "sh", "-c", cmd, NULL, env));
144
+	} else if (pid > 0) {
145
+		/* parent */
146
+		waitpid(pid, NULL, 0);
147
+	} else {
148
+		/* error.. */
149
+		logg("!VirusAction: fork failed.\n");
136 150
 	}
137
-	/* WARNING: this is uninterruptable ! */
138
-	if(cmd)
139
-	    exit(system(cmd));
140
-
141
-    } else if (pid > 0) {
142
-	/* parent */      
143
-	waitpid(pid, NULL, 0);
144
-    } else {
145
-	/* error.. */
146
-	logg("!VirusAction: fork failed.\n");
147
-    }
151
+	free(cmd);
152
+	free(buffer_file);
153
+	free(buffer_vir);
148 154
 }
149 155
 #endif /* C_WINDOWS */
150 156
 
... ...
@@ -1,7 +1,7 @@
1 1
 #!/bin/sh
2 2
 die() {
3 3
 	test /tmp/clamd-test.pid && kill `cat /tmp/clamd-test.pid` 
4
-	rm -r test-db
4
+	rm -rf test-db test-clamd-viraction.conf test-clamd.log
5 5
 	exit $1
6 6
 }
7 7
 
... ...
@@ -26,4 +26,15 @@ if test "$NFILES" -ne "$NINFECTED"; then
26 26
 	grep OK clamdscan.log >&2;
27 27
 	die 4;
28 28
 fi
29
+cp $srcdir/test-clamd.conf test-clamd-viraction.conf
30
+echo "VirusEvent `pwd`/$srcdir/virusaction-test.sh `pwd` \"Virus found: %v\"" >>test-clamd-viraction.conf
31
+rm -f test-clamd.log
32
+test /tmp/clamd-test.pid && kill `cat /tmp/clamd-test.pid` 
33
+../clamd/.libs/lt-clamd -c test-clamd-viraction.conf || { echo "Failed to start clamd!" >&2; die 1;}
34
+../clamdscan/clamdscan --quiet --config-file test-clamd-viraction.conf ../test/clam.exe 
35
+if ! grep "Virus found: ClamAV-Test-File.UNOFFICIAL" test-clamd.log >/dev/null 2>/dev/null; then
36
+	echo "Virusaction test failed!" >&2;
37
+	cat test-clamd.log
38
+	die 2;
39
+fi
29 40
 die 0;
30 41
new file mode 100755
... ...
@@ -0,0 +1,10 @@
0
+#!/bin/sh
1
+if test ! "x$CLAM_VIRUSEVENT_FILENAME" = "x$1/../test/clam.exe"; then
2
+	echo "VirusEvent incorrect: $CLAM_VIRUSEVENT_FILENAME" >$1/test-clamd.log
3
+	exit 1
4
+fi
5
+if test ! "x$CLAM_VIRUSEVENT_VIRUSNAME" = "xClamAV-Test-File.UNOFFICIAL"; then
6
+	echo "VirusName incorrect: $CLAM_VIRUSEVENT_VIRUSNAME" >$1/test-clamd.log
7
+	exit 2
8
+fi
9
+echo $2 >$1/test-clamd.log