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
41#define G_LOG_DOMAIN "sd main"
42
46#define MAX_PROCESSES 32
47
51struct running
52{
54 struct timeval start;
55 pid_t pid;
56 int timeout;
58};
59
60extern int global_min_memory;
61extern int global_max_sysload;
62
67static GSList *non_simult_ports = NULL;
68const char *hostname = NULL;
69
75static 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
108static 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. */
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. */
210 bzero (&(processes[i]), sizeof (processes[i]));
211 }
212 }
213 }
214 }
215}
216
217static int
218common (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
237static GSList *
238required_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
269static int
270simult_ports (const char *oid, const char *next_oid)
271{
272 int ret = 0;
273 GSList *common_ports1 = NULL, *common_ports2 = NULL;
274
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
291static int
292next_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
314void
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
339void
341{
343}
344
345void
347{
349}
350
351void
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. */
366 bzero (&(processes[i]), sizeof (struct running));
367 }
368 }
369}
370
371static int
372plugin_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
398static 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
420static 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
434static 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
457int
458plugin_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
494void
496{
498 {
501 waitpid (-1, NULL, 0);
502 }
503}
504
508static 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
527void
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}
kb_t main_kb
Definition: kb_cache.c:15
const char * oid
static struct timeval timeval(unsigned long val)
static pid_t pid
Definition: nasl_cmd_exec.c:39
const char * name
Definition: nasl_init.c:411
uint8_t len
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
@ ACT_SCANNER
void pluginlaunch_enable_parallel_checks(void)
Definition: pluginlaunch.c:346
void pluginlaunch_init(const char *host)
Definition: pluginlaunch.c:315
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
static struct running processes[MAX_PROCESSES]
Definition: pluginlaunch.c:63
static int common(GSList *list1, GSList *list2)
Definition: pluginlaunch.c:218
int global_max_sysload
Definition: openvas.c:87
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
int global_min_memory
Definition: openvas.c:86
static int get_available_memory()
Definition: pluginlaunch.c:399
static int max_running_processes
Definition: pluginlaunch.c:65
static int simult_ports(const char *oid, const char *next_oid)
Definition: pluginlaunch.c:270
static int check_memory()
Definition: pluginlaunch.c:421
static int check_sysload()
Definition: pluginlaunch.c:435
void pluginlaunch_stop(void)
Definition: pluginlaunch.c:352
#define MAX_PROCESSES
'Hard' limit of the max. number of concurrent plugins per host.
Definition: pluginlaunch.c:46
static GSList * non_simult_ports
Definition: pluginlaunch.c:67
static GSList * required_ports_in_list(const char *oid, GSList *list)
Definition: pluginlaunch.c:238
const char * hostname
Definition: pluginlaunch.c:68
static void update_running_processes(kb_t main_kb, kb_t kb)
Definition: pluginlaunch.c:109
static int num_running_processes
Definition: pluginlaunch.c:64
static int timeout_running_processes(void)
Return shortest timeout of the running processes.
Definition: pluginlaunch.c:509
void pluginlaunch_wait(kb_t main_kb, kb_t kb)
Waits and 'pushes' processes until num_running_processes is 0.
Definition: pluginlaunch.c:495
static int max_nvt_timeouts_reached()
Check if max_nvt_timeouts is set and if has been reached.
Definition: pluginlaunch.c:76
void pluginlaunch_disable_parallel_checks(void)
Definition: pluginlaunch.c:340
static int next_free_process(kb_t main_kb, kb_t kb, struct scheduler_plugin *upcoming)
Definition: pluginlaunch.c:292
static int old_max_running_processes
Definition: pluginlaunch.c:66
static int plugin_timeout(nvti_t *nvti)
Definition: pluginlaunch.c:372
pluginlaunch.c header.
#define ERR_CANT_FORK
Error for when it is not possible to fork a new plugin process.
Definition: pluginlaunch.h:22
#define ERR_NO_FREE_SLOT
Error for when the process table is full.
Definition: pluginlaunch.h:26
pluginload.c header.
header for pluginscheduler.c
@ PLUGIN_STATUS_DONE
@ PLUGIN_STATUS_UNRUN
plugs_req.c header.
char * get_plugin_preference(const char *oid, const char *name, int pref_id)
Get the a plugins preference.
Definition: plugutils.c:743
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
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
int terminate_process(pid_t pid)
Terminates a given process. If termination does not work, the process will get killed....
Definition: processes.c:96
processes.c header.
headerfile for sighand.c.
Host information, implemented as doubly linked list.
Definition: hosts.c:37
Structure to represent a process in the sense of a running NVT.
Definition: pluginlaunch.c:52
struct scheduler_plugin * plugin
Definition: pluginlaunch.c:53
struct timeval start
Definition: pluginlaunch.c:54
pid_t pid
Definition: pluginlaunch.c:55
int timeout
Definition: pluginlaunch.c:56
enum plugin_status running_state
int get_max_checks_number(void)
Definition: utils.c:165
int process_alive(pid_t pid)
Definition: utils.c:195
utils.c headerfile.
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