OpenVAS Scanner  22.7.9
pluginlaunch.c
Go to the documentation of this file.
1 /* SPDX-FileCopyrightText: 2023 Greenbone AG
2  * SPDX-FileCopyrightText: 2006 Software in the Public Interest, Inc.
3  * SPDX-FileCopyrightText: 1998-2006 Tenable Network Security, Inc.
4  *
5  * SPDX-License-Identifier: GPL-2.0-only
6  */
7 
13 #include "pluginlaunch.h"
14 
15 #include "../misc/heartbeat.h" /* for check_host_still_alive */
16 #include "../misc/network.h"
17 #include "../misc/nvt_categories.h" /* for ACT_SCANNER */
18 #include "../misc/plugutils.h" /* for get_plugin_preference */
19 #include "pluginload.h"
20 #include "pluginscheduler.h"
21 #include "plugs_req.h"
22 #include "processes.h"
23 #include "sighand.h"
24 #include "utils.h"
25 
26 #include <errno.h> /* for errno() */
27 #include <gvm/base/prefs.h> /* for prefs_get_bool() */
28 #include <gvm/util/nvticache.h>
29 #include <stdio.h> /* for perror() */
30 #include <stdlib.h> /* for atoi() */
31 #include <string.h>
32 #include <strings.h> /* for bzero() */
33 #include <sys/time.h> /* for gettimeofday() */
34 #include <sys/wait.h> /* for waitpid() */
35 #include <unistd.h> /* for close() */
36 
37 #undef G_LOG_DOMAIN
38 
41 #define G_LOG_DOMAIN "sd main"
42 
46 #define MAX_PROCESSES 32
47 
51 struct running
52 {
54  struct timeval start;
55  pid_t pid;
56  int timeout;
58 };
59 
60 extern int global_min_memory;
61 extern int global_max_sysload;
62 
63 static struct running processes[MAX_PROCESSES];
67 static GSList *non_simult_ports = NULL;
68 const char *hostname = NULL;
69 
75 static int
77 {
78  static int vts_timeouts_counter = 0;
79  int max_vts_timeouts = 0;
80  const gchar *max_vts_timeouts_str = NULL;
81 
82  /* Check if set */
83  if ((max_vts_timeouts_str = prefs_get ("max_vts_timeouts")) == NULL)
84  {
85  g_debug ("%s: max_vts_timeouts not set.", __func__);
86  return 0;
87  }
88 
89  /* Check if enabled and valid value */
90  max_vts_timeouts = atoi (max_vts_timeouts_str);
91  if (max_vts_timeouts <= 0)
92  {
93  g_debug ("%s: max_vts_timeouts disabled", __func__);
94  return 0;
95  }
96 
97  vts_timeouts_counter++;
98  /* Check if reached */
99  if (vts_timeouts_counter >= max_vts_timeouts)
100  return 1;
101 
102  return 0;
103 }
104 
108 static void
110 {
111  int i;
112  struct timeval now;
113  int log_whole = prefs_get_bool ("log_whole_attack");
114 
115  if (num_running_processes == 0)
116  return;
117 
118  gettimeofday (&now, NULL);
119  for (i = 0; i < MAX_PROCESSES; i++)
120  {
121  if (processes[i].pid > 0)
122  {
123  int is_alive = process_alive (processes[i].pid);
124  int ret_terminate = 0;
125 
126  // If process dead or timed out
127  if (!is_alive
128  || (processes[i].timeout > 0
129  && ((now.tv_sec - processes[i].start.tv_sec)
130  > processes[i].timeout)))
131  {
132  char *oid = processes[i].plugin->oid;
133 
134  if (is_alive) // Alive and timed out
135  {
136  char msg[2048];
137  if (log_whole)
138  g_message ("%s (pid %d) is slow to finish - killing it",
139  oid, processes[i].pid);
140 
141  g_snprintf (msg, sizeof (msg),
142  "ERRMSG|||%s||| |||general/tcp|||%s|||"
143  "NVT timed out after %d seconds.",
144  hostname, oid ? oid : " ", processes[i].timeout);
146  "internal/results", msg);
147 
148  /* Check for max VTs timeouts */
150  {
151  /* Check if host is still alive and send a message
152  if it is dead. */
153  if (check_host_still_alive (kb, hostname) == 0)
154  {
155  g_snprintf (msg, sizeof (msg),
156  "ERRMSG|||%s||| |||general/tcp||| |||"
157  "Host has been marked as dead. Too many "
158  "NVT_TIMEOUTs.",
159  hostname);
161  main_kb, "internal/results", msg);
162  }
163  }
164 
165  ret_terminate = terminate_process (processes[i].pid);
166  if (ret_terminate == 0)
167  {
168  /* Since the plugin process is a group leader process
169  * we can send the signal to -PID process to kill
170  * also the plugin's child processes. */
171  terminate_process (processes[i].pid * -1);
174  bzero (&(processes[i]), sizeof (processes[i]));
175  }
176  }
177  else
178  {
179  struct timeval old_now = now;
180  int e;
181  if (now.tv_usec < processes[i].start.tv_usec)
182  {
183  processes[i].start.tv_sec++;
184  now.tv_usec += 1000000;
185  }
186  if (log_whole)
187  {
188  char *name = nvticache_get_filename (oid);
189  g_message (
190  "%s (%s) [%d] finished its job in %ld.%.3ld seconds",
191  name, oid, processes[i].pid,
192  (long) (now.tv_sec - processes[i].start.tv_sec),
193  (long) ((now.tv_usec - processes[i].start.tv_usec)
194  / 1000));
195  g_free (name);
196  }
197  now = old_now;
198  do
199  {
200  e = waitpid (processes[i].pid, NULL, 0);
201  }
202  while (e < 0 && errno == EINTR);
203 
204  /* Since the plugin process is a group leader process
205  * we can send the signal to -PID process to kill
206  * also the plugin's child processes. */
207  terminate_process (processes[i].pid * -1);
210  bzero (&(processes[i]), sizeof (processes[i]));
211  }
212  }
213  }
214  }
215 }
216 
217 static int
218 common (GSList *list1, GSList *list2)
219 {
220  if (!list1 || !list2)
221  return 0;
222 
223  while (list1)
224  {
225  GSList *tmp = list2;
226  while (tmp)
227  {
228  if (!strcmp (list1->data, tmp->data))
229  return 1;
230  tmp = tmp->next;
231  }
232  list1 = list1->next;
233  }
234  return 0;
235 }
236 
237 static GSList *
238 required_ports_in_list (const char *oid, GSList *list)
239 {
240  GSList *common_ports = NULL;
241  char **array, *ports;
242  int i;
243 
244  if (!oid || !list)
245  return 0;
246  ports = nvticache_get_required_ports (oid);
247  if (!ports)
248  return 0;
249  array = g_strsplit (ports, ", ", 0);
250  g_free (ports);
251  if (!array)
252  return 0;
253 
254  for (i = 0; array[i]; i++)
255  {
256  GSList *tmp = list;
257  while (tmp)
258  {
259  if (!strcmp (tmp->data, array[i]))
260  common_ports = g_slist_prepend (common_ports, g_strdup (tmp->data));
261  tmp = tmp->next;
262  }
263  }
264 
265  g_strfreev (array);
266  return common_ports;
267 }
268 
269 static int
270 simult_ports (const char *oid, const char *next_oid)
271 {
272  int ret = 0;
273  GSList *common_ports1 = NULL, *common_ports2 = NULL;
274 
275  common_ports1 = required_ports_in_list (oid, non_simult_ports);
276  if (common_ports1)
277  common_ports2 = required_ports_in_list (next_oid, non_simult_ports);
278  if (common_ports1 && common_ports2 && common (common_ports1, common_ports2))
279  ret = 1;
280  g_slist_free_full (common_ports1, g_free);
281  g_slist_free_full (common_ports2, g_free);
282  return ret;
283 }
284 
291 static int
292 next_free_process (kb_t main_kb, kb_t kb, struct scheduler_plugin *upcoming)
293 {
294  int r;
295 
296  for (r = 0; r < MAX_PROCESSES; r++)
297  {
298  if (processes[r].pid > 0
299  && simult_ports (processes[r].plugin->oid, upcoming->oid))
300  {
301  while (process_alive (processes[r].pid))
302  {
304  usleep (250000);
305  }
306  }
307  }
308  for (r = 0; r < MAX_PROCESSES; r++)
309  if (processes[r].pid <= 0)
310  return r;
311  return ERR_NO_FREE_SLOT;
312 }
313 
314 void
315 pluginlaunch_init (const char *host)
316 {
317  int i;
318 
319  char **split = g_strsplit (prefs_get ("non_simult_ports"), ", ", 0);
320  for (i = 0; split[i]; i++)
321  non_simult_ports = g_slist_prepend (non_simult_ports, g_strdup (split[i]));
322  g_strfreev (split);
325  hostname = host;
326 
328  {
329  g_debug ("max_checks (%d) > MAX_PROCESSES (%d) - modify "
330  "openvas/openvas/pluginlaunch.c",
333  }
334 
336  bzero (&(processes), sizeof (processes));
337 }
338 
339 void
341 {
343 }
344 
345 void
347 {
349 }
350 
351 void
353 {
354  int i;
355 
356  for (i = 0; i < MAX_PROCESSES; i++)
357  {
358  if (processes[i].pid > 0)
359  {
360  /* Since the plugin process is a group leader process
361  * we can send the signal to -PID process to kill
362  * also the plugin's child processes. */
363  terminate_process (processes[i].pid * -1);
366  bzero (&(processes[i]), sizeof (struct running));
367  }
368  }
369 }
370 
371 static int
372 plugin_timeout (nvti_t *nvti)
373 {
374  int timeout, tmp;
375  gchar *timeout_str;
376 
377  timeout = 0;
378  if ((timeout_str = get_plugin_preference (nvti_oid (nvti), "timeout", 0))
379  != NULL)
380  timeout = atoi (timeout_str);
381 
382  if (timeout == 0)
383  {
384  if (nvti_category (nvti) == ACT_SCANNER)
385  {
386  tmp = atoi (prefs_get ("scanner_plugins_timeout"));
387  timeout = tmp ? tmp : SCANNER_NVT_TIMEOUT;
388  }
389  else
390  {
391  tmp = atoi (prefs_get ("plugins_timeout"));
392  timeout = tmp ? tmp : NVT_TIMEOUT;
393  }
394  }
395  return timeout;
396 }
397 
398 static int
400 {
401  char buf[8192], *hit;
402  FILE *fd;
403  size_t len;
404 
405  fd = fopen ("/proc/meminfo", "r");
406  len = fread (buf, 1, sizeof (buf) - 1, fd);
407  fclose (fd);
408  if (len == 0)
409  {
410  g_warning ("Couldn't read /proc/meminfo");
411  return 0;
412  }
413  hit = strstr (buf, "MemAvailable:");
414  if (!hit)
415  return 0;
416 
417  return atoi (hit + 14) / 1000;
418 }
419 
420 static int
422 {
423  int available_mem;
424 
425  if (global_min_memory <= 0)
426  return 0;
427 
428  available_mem = get_available_memory ();
429  if (available_mem == 0 || available_mem > global_min_memory)
430  return 0;
431  return 1;
432 }
433 
434 static int
436 {
437  double sysload;
438 
439  if (global_max_sysload <= 0)
440  return 0;
441  if (getloadavg (&sysload, 1) < 0 || sysload <= global_max_sysload)
442  return 0;
443  return 1;
444 }
445 
457 int
458 plugin_launch (struct scan_globals *globals, struct scheduler_plugin *plugin,
459  struct in6_addr *ip, GSList *vhosts, kb_t kb, kb_t main_kb,
460  nvti_t *nvti, int *error)
461 {
462  int p;
463 
464  /* Wait for a free slot */
466  p = next_free_process (main_kb, kb, plugin);
467  if (p < 0)
468  {
469  g_warning ("%s. There is currently no free slot available for starting a "
470  "new plugin.",
471  __func__);
472  *error = ERR_NO_FREE_SLOT;
473  return -1;
474  }
475 
476  processes[p].plugin = plugin;
477  processes[p].timeout = plugin_timeout (nvti);
478  gettimeofday (&(processes[p].start), NULL);
479  processes[p].pid = nasl_plugin_launch (globals, ip, vhosts, kb, plugin->oid);
480 
481  if (processes[p].pid > 0)
483  else
484  {
486  *error = ERR_CANT_FORK;
487  }
488  return processes[p].pid;
489 }
490 
494 void
495 pluginlaunch_wait (kb_t main_kb, kb_t kb)
496 {
497  while (num_running_processes)
498  {
501  waitpid (-1, NULL, 0);
502  }
503 }
504 
508 static int
510 {
511  int i, timeout = 0;
512 
513  for (i = 0; i < MAX_PROCESSES; i++)
514  {
515  if (processes[i].pid <= 0)
516  continue;
517  if (!timeout || processes[i].timeout < timeout)
518  timeout = processes[i].timeout;
519  }
520  return timeout;
521 }
522 
527 void
529 {
531  return;
533  /* Max number of processes are still running, wait for a child to exit or
534  * to timeout. */
535 
537  g_debug ("%s. Number of running processes >= maximum running processes (%d "
538  ">= %d). "
539  "Waiting for free slot for processes.",
541 
542  /* Be careful with changing the max_running_process value.
543  * The plugin scheduler can change this value for running one plugin at
544  * time. */
545  while (
547  || (num_running_processes > 0 && (check_memory () || check_sysload ())))
548  {
549  sigset_t mask;
550  struct timespec ts = {0, 0};
551 
552  ts.tv_sec = timeout_running_processes ();
553  assert (ts.tv_sec);
554  sigemptyset (&mask);
555  sigaddset (&mask, SIGCHLD);
556  sigaddset (&mask, SIGUSR1);
557  /* Wait here for the shortest plugins timeout or for a child which ended.
558  * Also, it handles signal SIGUSR1 to stop a scan. Otherwise the signa is
559  * ignored, the plugin is never stopped and the scanner keeps waiting. */
560  int sig = sigtimedwait (&mask, NULL, &ts);
561  if (sig < 0 && errno != EAGAIN)
562  g_warning ("%s: %s (%d)", __func__, strerror (errno), errno);
563  else if (sig == SIGUSR1)
564  {
565  /* SIGUSR1 signal is sent during scan stop to all host processes.
566  Therefore pluginlaunch_stop() is called here, for the
567  special case in which we are waiting for the last plugin, of the
568  last host, to finish.
569  */
571  }
572  // cleanup ipcc cache
575  }
576 }
global_min_memory
int global_min_memory
Definition: openvas.c:86
terminate_process
int terminate_process(pid_t pid)
Terminates a given process. If termination does not work, the process will get killed....
Definition: processes.c:96
update_running_processes
static void update_running_processes(kb_t main_kb, kb_t kb)
Definition: pluginlaunch.c:109
processes.h
processes.c header.
plugin_timeout
static int plugin_timeout(nvti_t *nvti)
Definition: pluginlaunch.c:372
non_simult_ports
static GSList * non_simult_ports
Definition: pluginlaunch.c:67
simult_ports
static int simult_ports(const char *oid, const char *next_oid)
Definition: pluginlaunch.c:270
timeout_running_processes
static int timeout_running_processes(void)
Return shortest timeout of the running processes.
Definition: pluginlaunch.c:509
running::timeout
int timeout
Definition: pluginlaunch.c:56
global_max_sysload
int global_max_sysload
Definition: openvas.c:87
scheduler_plugin
Definition: pluginscheduler.h:28
pluginlaunch_disable_parallel_checks
void pluginlaunch_disable_parallel_checks(void)
Definition: pluginlaunch.c:340
pluginlaunch_stop
void pluginlaunch_stop(void)
Definition: pluginlaunch.c:352
main_kb
kb_t main_kb
Definition: kb_cache.c:15
running
Structure to represent a process in the sense of a running NVT.
Definition: pluginlaunch.c:52
get_available_memory
static int get_available_memory()
Definition: pluginlaunch.c:399
sighand.h
headerfile for sighand.c.
check_host_still_alive
int check_host_still_alive(kb_t, const char *)
Check if the hosts is still alive and set it as dead if not.
Definition: heartbeat.c:33
running::start
struct timeval start
Definition: pluginlaunch.c:54
num_running_processes
static int num_running_processes
Definition: pluginlaunch.c:64
plugin_launch
int plugin_launch(struct scan_globals *globals, struct scheduler_plugin *plugin, struct in6_addr *ip, GSList *vhosts, kb_t kb, kb_t main_kb, nvti_t *nvti, int *error)
Start a plugin.
Definition: pluginlaunch.c:458
common
static int common(GSList *list1, GSList *list2)
Definition: pluginlaunch.c:218
PLUGIN_STATUS_DONE
@ PLUGIN_STATUS_DONE
Definition: pluginscheduler.h:24
pluginlaunch_wait
void pluginlaunch_wait(kb_t main_kb, kb_t kb)
Waits and 'pushes' processes until num_running_processes is 0.
Definition: pluginlaunch.c:495
name
const char * name
Definition: nasl_init.c:411
pluginload.h
pluginload.c header.
oid
const char * oid
Definition: nasl_builtin_find_service.c:51
scheduler_plugin::running_state
enum plugin_status running_state
Definition: pluginscheduler.h:31
check_memory
static int check_memory()
Definition: pluginlaunch.c:421
utils.h
utils.c headerfile.
required_ports_in_list
static GSList * required_ports_in_list(const char *oid, GSList *list)
Definition: pluginlaunch.c:238
pluginlaunch_init
void pluginlaunch_init(const char *host)
Definition: pluginlaunch.c:315
MAX_PROCESSES
#define MAX_PROCESSES
'Hard' limit of the max. number of concurrent plugins per host.
Definition: pluginlaunch.c:46
ERR_CANT_FORK
#define ERR_CANT_FORK
Error for when it is not possible to fork a new plugin process.
Definition: pluginlaunch.h:22
pid
static pid_t pid
Definition: nasl_cmd_exec.c:39
running::pid
pid_t pid
Definition: pluginlaunch.c:55
ERR_NO_FREE_SLOT
#define ERR_NO_FREE_SLOT
Error for when the process table is full.
Definition: pluginlaunch.h:26
len
uint8_t len
Definition: nasl_packet_forgery.c:1
procs_cleanup_children
int procs_cleanup_children(void)
iterates through ipcc and verify if a child is stopped or killed to free the file handler.
Definition: processes.c:47
get_plugin_preference
char * get_plugin_preference(const char *oid, const char *name, int pref_id)
Get the a plugins preference.
Definition: plugutils.c:743
check_sysload
static int check_sysload()
Definition: pluginlaunch.c:435
process_alive
int process_alive(pid_t pid)
Definition: utils.c:195
scan_globals
Definition: scanneraux.h:19
pluginlaunch_wait_for_free_process
void pluginlaunch_wait_for_free_process(kb_t main_kb, kb_t kb)
Waits and 'pushes' processes until the number of running processes has changed.
Definition: pluginlaunch.c:528
timeval
static struct timeval timeval(unsigned long val)
Definition: nasl_builtin_synscan.c:94
scheduler_plugin::oid
char * oid
Definition: pluginscheduler.h:29
PLUGIN_STATUS_UNRUN
@ PLUGIN_STATUS_UNRUN
Definition: pluginscheduler.h:22
host
Host information, implemented as doubly linked list.
Definition: hosts.c:37
get_max_checks_number
int get_max_checks_number(void)
Definition: utils.c:165
ACT_SCANNER
@ ACT_SCANNER
Definition: nvt_categories.h:25
pluginscheduler.h
header for pluginscheduler.c
hostname
const char * hostname
Definition: pluginlaunch.c:68
pluginlaunch.h
pluginlaunch.c header.
running::plugin
struct scheduler_plugin * plugin
Definition: pluginlaunch.c:53
nasl_plugin_launch
int nasl_plugin_launch(struct scan_globals *globals, struct in6_addr *ip, GSList *vhosts, kb_t kb, const char *oid)
Launch a NASL plugin.
Definition: nasl_plugins.c:166
max_nvt_timeouts_reached
static int max_nvt_timeouts_reached()
Check if max_nvt_timeouts is set and if has been reached.
Definition: pluginlaunch.c:76
pluginlaunch_enable_parallel_checks
void pluginlaunch_enable_parallel_checks(void)
Definition: pluginlaunch.c:346
kb_item_push_str_with_main_kb_check
int kb_item_push_str_with_main_kb_check(kb_t kb, const char *name, const char *value)
Check if the current kb corresponds to the original scanid, if it matches it kb_item_push_str....
Definition: plugutils.c:478
plugs_req.h
plugs_req.c header.
max_running_processes
static int max_running_processes
Definition: pluginlaunch.c:65
next_free_process
static int next_free_process(kb_t main_kb, kb_t kb, struct scheduler_plugin *upcoming)
Definition: pluginlaunch.c:292
list
Definition: nasl_builtin_synscan.c:249
processes
static struct running processes[MAX_PROCESSES]
Definition: pluginlaunch.c:63
old_max_running_processes
static int old_max_running_processes
Definition: pluginlaunch.c:66