OpenVAS Scanner  5.1.3
pluginlaunch.c
Go to the documentation of this file.
1 /* OpenVAS
2 * $Id$
3 * Description: Manages the launching of plugins within processes.
4 *
5 * Authors: - Renaud Deraison <deraison@nessus.org> (Original pre-fork develoment)
6 * - Tim Brown <mailto:timb@openvas.org> (Initial fork)
7 * - Laban Mwangi <mailto:labanm@openvas.org> (Renaming work)
8 * - Tarik El-Yassem <mailto:tarik@openvas.org> (Headers section)
9 *
10 * Copyright:
11 * Portions Copyright (C) 2006 Software in the Public Interest, Inc.
12 * Based on work Copyright (C) 1998 - 2006 Tenable Network Security, Inc.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2,
16 * as published by the Free Software Foundation
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 */
27 
28 #include <stdio.h> /* for perror() */
29 #include <unistd.h> /* for close() */
30 #include <sys/wait.h> /* for waitpid() */
31 #include <strings.h> /* for bzero() */
32 #include <errno.h> /* for errno() */
33 #include <sys/time.h> /* for gettimeofday() */
34 
35 #include <openvas/misc/network.h> /* for internal_send */
36 #include <openvas/misc/nvt_categories.h> /* for ACT_SCANNER */
37 #include <openvas/misc/internal_com.h> /* for INTERNAL_COMM_MSG_TYPE_DATA */
38 #include <openvas/misc/prefs.h> /* for prefs_get_bool() */
39 #include <openvas/base/nvticache.h>
40 
41 #include "pluginload.h"
42 #include "utils.h"
43 #include "log.h"
44 #include "sighand.h"
45 #include "processes.h"
46 #include "pluginscheduler.h"
47 #include "plugs_req.h"
48 
52 #define MAX_PROCESSES 32
53 
54 #undef VERBOSE_LOGGING /* This really fills your openvassd.messages */
55 
56 #undef DEBUG_CONFLICTS
57 
61 struct running
62 {
64  struct timeval start;
65  int pid;
66  int timeout;
70  int alive;
71 };
72 
73 static void read_running_processes ();
74 static void update_running_processes ();
75 
76 static struct running processes[MAX_PROCESSES];
77 static int num_running_processes;
78 static int max_running_processes;
79 static int old_max_running_processes;
80 static struct arglist *non_simult_ports_list;
81 const char *hostname = NULL;
82 
83 
90 static int
91 process_internal_msg (int p)
92 {
93  int e = 0, bufsz = 0, type = 0;
94  char *buffer = NULL;
95 
96  e = internal_recv (processes[p].internal_soc, &buffer, &bufsz, &type);
97  if (e < 0)
98  {
99  log_write ("Process %d (OID: %s) seems to have died too early",
100  processes[p].pid, processes[p].plugin->oid);
101  processes[p].alive = 0;
102  return -1;
103  }
104 
105  if (type & INTERNAL_COMM_MSG_TYPE_DATA)
106  {
107  e = internal_send (processes[p].upstream_soc, buffer, type);
108  }
109  else if (type & INTERNAL_COMM_MSG_TYPE_CTRL)
110  {
111  if (type & INTERNAL_COMM_CTRL_FINISHED)
112  {
113  kill (processes[p].pid, SIGTERM);
114  processes[p].alive = 0;
115  }
116  }
117  else
118  log_write ("Received unknown message type %d", type);
119 
120  g_free (buffer);
121  return e;
122 }
123 
124 
125 void
127 {
128  int i;
129 
130  for (i = 0; i < MAX_PROCESSES; i++)
131  if (processes[i].pid != 0)
132  {
133  int ret;
134  do
135  {
136  ret = waitpid (-1, NULL, WNOHANG);
137  }
138  while (ret < 0 && errno == EINTR);
139  }
140 }
141 
145 static void
146 update_running_processes (void)
147 {
148  int i;
149  struct timeval now;
150  int log_whole = prefs_get_bool ("log_whole_attack");
151 
152  gettimeofday (&now, NULL);
153 
154  if (num_running_processes == 0)
155  return;
156 
157  for (i = 0; i < MAX_PROCESSES; i++)
158  {
159  if (processes[i].pid > 0)
160  {
161  // If process dead or timed out
162  if (processes[i].alive == 0
163  || (processes[i].timeout > 0
164  && ((now.tv_sec - processes[i].start.tv_sec) >
165  processes[i].timeout)))
166  {
167  char *oid = processes[i].plugin->oid;
168 
169  if (processes[i].alive)
170  {
171  gchar *msg;
172 
173  if (log_whole)
174  log_write ("%s (pid %d) is slow to finish - killing it",
175  oid, processes[i].pid);
176 
177  msg = g_strdup_printf
178  ("SERVER <|> ERRMSG <|> %s <|> general/tcp"
179  " <|> NVT timed out after %d seconds."
180  " <|> %s <|> SERVER\n",
181  hostname, processes[i].timeout, oid ?: "0");
182  internal_send (processes[i].upstream_soc,
183  msg, INTERNAL_COMM_MSG_TYPE_DATA);
184  g_free (msg);
185 
186  terminate_process (processes[i].pid);
187  processes[i].alive = 0;
188  }
189  else
190  {
191  struct timeval old_now = now;
192  int e;
193  if (now.tv_usec < processes[i].start.tv_usec)
194  {
195  processes[i].start.tv_sec++;
196  now.tv_usec += 1000000;
197  }
198  if (log_whole)
199  {
200  char *name = nvticache_get_filename (oid);
201  log_write
202  ("%s (%s) [%d] finished its job in %ld.%.3ld seconds",
203  name, oid, processes[i].pid,
204  (long) (now.tv_sec - processes[i].start.tv_sec),
205  (long) ((now.tv_usec -
206  processes[i].start.tv_usec) / 1000));
207  g_free (name);
208  }
209  now = old_now;
210  do
211  {
212  e = waitpid (processes[i].pid, NULL, 0);
213  }
214  while (e < 0 && errno == EINTR);
215 
216  }
217  num_running_processes--;
218  processes[i].plugin->running_state = PLUGIN_STATUS_DONE;
219  close (processes[i].internal_soc);
220  bzero (&(processes[i]), sizeof (processes[i]));
221  }
222  }
223  }
224 }
225 
232 static int
233 next_free_process (struct scheduler_plugin *upcoming)
234 {
235  int r;
236 
238  for (r = 0; r < MAX_PROCESSES; r++)
239  {
240  if (processes[r].pid > 0)
241  {
242  struct arglist *common_ports;
243  if ((common_ports =
244  requirements_common_ports (processes[r].plugin, upcoming)))
245  {
246  int do_wait = -1;
247  if (common (common_ports, non_simult_ports_list))
248  do_wait = r;
249  arg_free (common_ports);
250  if (do_wait >= 0)
251  {
252 #ifdef DEBUG_CONFLICT
253  log_write ("Waiting has been initiated...\n");
254  log_write ("Ports in common - waiting...");
255 #endif
256  while (process_alive (processes[r].pid))
257  {
258  read_running_processes ();
259  update_running_processes ();
261  }
262 #ifdef DEBUG_CONFLICT
263  log_write ("End of the wait - was that long ?\n");
264 #endif
265  }
266  }
267  }
268  }
269 
270  // Find the last "living" process.
271  r = 0;
272  while ((r < MAX_PROCESSES) && (processes[r].pid > 0))
273  r++;
274 
275  if (r >= MAX_PROCESSES)
276  return -1;
277  else
278  return r;
279 }
280 
284 static void
285 read_running_processes (void)
286 {
287  int i;
288  int flag = 0;
289  struct timeval tv;
290  fd_set rd;
291  int max = 0;
292  int e;
293 
294  if (num_running_processes == 0)
295  return;
296 
297  FD_ZERO (&rd);
298  for (i = 0; i < MAX_PROCESSES; i++)
299  {
300  if (processes[i].pid > 0)
301  {
302  FD_SET (processes[i].internal_soc, &rd);
303  if (processes[i].internal_soc > max)
304  max = processes[i].internal_soc;
305  }
306  }
307 
308  do
309  {
310  tv.tv_sec = 0;
311  tv.tv_usec = 500000;
312  e = select (max + 1, &rd, NULL, NULL, &tv);
313  }
314  while (e < 0 && errno == EINTR);
315 
316  if (e == 0)
317  return;
318 
319  for (i = 0; i < MAX_PROCESSES; i++)
320  {
321  if (processes[i].pid > 0)
322  {
323  flag++;
324  if (FD_ISSET (processes[i].internal_soc, &rd) != 0)
325  {
326  int result = process_internal_msg (i);
327  if (result)
328  {
329 #ifdef DEBUG
330  log_write ("process_internal_msg for %s returned %d",
331  processes[i].plugin->oid, result);
332 #endif
333  }
334  }
335  }
336  }
337 
338  if (flag == 0 && num_running_processes != 0)
339  num_running_processes = 0;
340 }
341 
342 
343 void
344 pluginlaunch_init (const char *host)
345 {
346  struct arglist *preferences = preferences_get ();
347  non_simult_ports_list = arg_get_value (preferences, "non_simult_ports_list");
348  max_running_processes = get_max_checks_number ();
349  old_max_running_processes = max_running_processes;
350  hostname = host;
351 
352  if (max_running_processes >= MAX_PROCESSES)
353  {
354  log_write
355  ("max_checks (%d) > MAX_PROCESSES (%d) - modify openvas-scanner/openvassd/pluginlaunch.c",
356  max_running_processes, MAX_PROCESSES);
357  max_running_processes = MAX_PROCESSES - 1;
358  }
359 
360 
361  num_running_processes = 0;
362  bzero (&(processes), sizeof (processes));
363 }
364 
365 void
367 {
368  max_running_processes = 1;
369 }
370 
371 void
373 {
374  max_running_processes = old_max_running_processes;
375 }
376 
377 
378 void
379 pluginlaunch_stop (int soft_stop)
380 {
381  int i;
382 
383  if (soft_stop)
384  {
385  read_running_processes ();
386 
387  for (i = 0; i < MAX_PROCESSES; i++)
388  {
389  if (processes[i].pid > 0)
390  kill (processes[i].pid, SIGTERM);
391  }
392  usleep (20000);
393  }
394 
395  for (i = 0; i < MAX_PROCESSES; i++)
396  {
397  if (processes[i].pid > 0)
398  {
399  kill (processes[i].pid, SIGKILL);
400  num_running_processes--;
401  processes[i].plugin->running_state = PLUGIN_STATUS_DONE;
402  close (processes[i].internal_soc);
403  bzero (&(processes[i]), sizeof (struct running));
404  }
405  }
406 }
407 
408 
413 int
414 plugin_launch (struct arglist *globals, struct scheduler_plugin *plugin,
415  struct host_info *hostinfo, kb_t kb, char *name)
416 {
417  int p;
418  int dsoc[2];
419 
420  /* Wait for a free slot while reading the input from the plugins */
421  while (num_running_processes >= max_running_processes)
422  {
423  read_running_processes ();
424  update_running_processes ();
425  }
426 
427  p = next_free_process (plugin);
428  processes[p].plugin = plugin;
429  processes[p].timeout = prefs_nvt_timeout (plugin->oid);
430  if (processes[p].timeout == 0)
431  processes[p].timeout = nvticache_get_timeout (plugin->oid);
432 
433  if (processes[p].timeout == 0)
434  {
435  int category = nvticache_get_category (plugin->oid);
436  if (category == ACT_SCANNER)
437  processes[p].timeout = atoi (prefs_get ("scanner_plugins_timeout")
438  ?: "-1");
439  else
440  processes[p].timeout = atoi (prefs_get ("plugins_timeout") ?: "-1");
441  }
442 
443  if (socketpair (AF_UNIX, SOCK_STREAM, 0, dsoc) < 0)
444  {
445  perror ("pluginlaunch.c:plugin_launch:socketpair(1) ");
446  }
447  gettimeofday (&(processes[p].start), NULL);
448 
449  processes[p].upstream_soc = arg_get_value_int (globals, "global_socket");
450  processes[p].internal_soc = dsoc[0];
451 
452  processes[p].pid =
453  nasl_plugin_launch (globals, hostinfo, kb, name, plugin->oid, dsoc[1]);
454 
455  processes[p].alive = 1;
456  close (dsoc[1]);
457  if (processes[p].pid > 0)
458  num_running_processes++;
459  else
460  processes[p].plugin->running_state = PLUGIN_STATUS_UNRUN;
461 
462  return processes[p].pid;
463 }
464 
465 
469 void
471 {
472  do
473  {
475  read_running_processes ();
476  update_running_processes ();
477  }
478  while (num_running_processes != 0);
479 }
480 
485 void
487 {
488  int i;
489  for (i = 0; i < MAX_PROCESSES; i++)
490  if (processes[i].internal_soc)
491  close (processes[i].internal_soc);
492 }
493 
498 void
500 {
501  int num = num_running_processes;
502  while (num && num_running_processes == num)
503  {
505  read_running_processes ();
506  update_running_processes ();
507  }
508 }
int process_alive(pid_t pid)
Definition: utils.c:180
void pluginlaunch_enable_parrallel_checks(void)
Definition: pluginlaunch.c:372
int alive
Definition: pluginlaunch.c:70
void log_write(const char *str,...)
Write into the logfile / syslog.
Definition: log.c:140
struct timeval start
Definition: pluginlaunch.c:64
struct scheduler_plugin * plugin
Definition: pluginlaunch.c:63
struct arglist * requirements_common_ports(struct scheduler_plugin *plugin1, struct scheduler_plugin *plugin2)
Returns <port> if the lists of the required ports between.
Definition: plugs_req.c:95
#define MAX_PROCESSES
'Hard' limit of the max. number of concurrent plugins per host.
Definition: pluginlaunch.c:52
int internal_soc
Definition: pluginlaunch.c:69
void pluginlaunch_wait_for_free_process(void)
Waits and 'pushes' processes until the number of running processes has changed.
Definition: pluginlaunch.c:499
#define PLUGIN_STATUS_DONE
int upstream_soc
Definition: pluginlaunch.c:68
int plugin_launch(struct arglist *globals, struct scheduler_plugin *plugin, struct host_info *hostinfo, kb_t kb, char *name)
Definition: pluginlaunch.c:414
Host information, implemented as doubly linked list.
Definition: hosts.c:44
int nasl_plugin_launch(struct arglist *globals, struct host_info *hostinfo, kb_t kb, char *name, const char *oid, int soc)
Launch a NASL plugin.
Definition: nasl_plugins.c:145
void pluginlaunch_wait(void)
Waits and 'pushes' processes until num_running_processes is 0.
Definition: pluginlaunch.c:470
int timeout
Definition: pluginlaunch.c:66
void pluginlaunch_child_cleanup(void)
Cleanup file descriptors used by the processes array. To be called by the child process running the p...
Definition: pluginlaunch.c:486
Structure to represent a process in the sense of a running NVT.
Definition: pluginlaunch.c:61
void pluginlaunch_disable_parrallel_checks(void)
Definition: pluginlaunch.c:366
void pluginlaunch_stop(int soft_stop)
Definition: pluginlaunch.c:379
void wait_for_children()
Definition: pluginlaunch.c:126
#define PLUGIN_STATUS_UNRUN
const char * hostname
Definition: pluginlaunch.c:81
int common(struct arglist *l1, struct arglist *l2)
Returns 1 if the two arglists have a name in common.
Definition: utils.c:54
int terminate_process(pid_t pid)
Definition: processes.c:43
int get_max_checks_number(void)
Definition: utils.c:150
void pluginlaunch_init(const char *host)
Definition: pluginlaunch.c:344