Skip to content

Commit

Permalink
Merge pull request #835 from greenbone/mergify/bp/openvas-20.08/pr-832
Browse files Browse the repository at this point in the history
Fix interrupted scans (backport #832)
  • Loading branch information
jjnicola committed Aug 9, 2021
2 parents 509ace1 + eece1b1 commit 0a7e022
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).


## [20.8.4] (unreleased)
### Added
### Changed
Expand All @@ -16,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Deprecated
### Removed
### Fixed
Backport #832. Fix interrupted scan, when the process table is full. [#835](https://github.com/greenbone/openvas-scanner/pull/835)

[20.8.4]: https://github.com/greenbone/openvas-scanner/compare/v20.8.3...openvas-20.08

Expand Down
33 changes: 24 additions & 9 deletions src/attack.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
#include <unistd.h> /* for close() */

#define ERR_HOST_DEAD -1
#define ERR_CANT_FORK -2

#define MAX_FORK_RETRIES 10
/**
Expand Down Expand Up @@ -345,13 +344,14 @@ check_new_vhosts (void)
* Does not launch a plugin twice if !save_kb_replay.
*
* @return ERR_HOST_DEAD if host died, ERR_CANT_FORK if forking failed,
* 0 otherwise.
* ERR_NO_FREE_SLOT if the process table is full, 0 otherwise.
*/
static int
launch_plugin (struct scan_globals *globals, struct scheduler_plugin *plugin,
struct in6_addr *ip, GSList *vhosts, kb_t kb)
{
int optimize = prefs_get_bool ("optimize_test"), pid, ret = 0;
int optimize = prefs_get_bool ("optimize_test");
int launch_error, pid, ret = 0;
char *oid, *name, *error = NULL, ip_str[INET6_ADDRSTRLEN];
nvti_t *nvti;

Expand Down Expand Up @@ -426,11 +426,12 @@ launch_plugin (struct scan_globals *globals, struct scheduler_plugin *plugin,

/* Update vhosts list and start the plugin */
check_new_vhosts ();
pid = plugin_launch (globals, plugin, ip, vhosts, kb, nvti);
if (pid < 0)
launch_error = 0;
pid = plugin_launch (globals, plugin, ip, vhosts, kb, nvti, &launch_error);
if (launch_error == ERR_NO_FREE_SLOT || launch_error == ERR_CANT_FORK)
{
plugin->running_state = PLUGIN_STATUS_UNRUN;
ret = ERR_CANT_FORK;
ret = launch_error;
goto finish_launch_plugin;
}

Expand Down Expand Up @@ -514,19 +515,33 @@ attack_host (struct scan_globals *globals, struct in6_addr *ip, GSList *vhosts,
kb_item_push_str (kb, "internal/results", buffer);
goto host_died;
}
else if (e == ERR_NO_FREE_SLOT)
{
if (forks_retry < MAX_FORK_RETRIES)
{
forks_retry++;
g_warning ("Launch failed for %s. No free slot available "
"in the internal process table for starting a "
"plugin.",
plugin->oid);
fork_sleep (forks_retry);
goto again;
}
}
else if (e == ERR_CANT_FORK)
{
if (forks_retry < MAX_FORK_RETRIES)
{
forks_retry++;
g_debug ("fork() failed - sleeping %d seconds (%s)",
forks_retry, strerror (errno));
g_warning (
"fork() failed for %s - sleeping %d seconds (%s)",
plugin->oid, forks_retry, strerror (errno));
fork_sleep (forks_retry);
goto again;
}
else
{
g_debug ("fork() failed too many times - aborting");
g_warning ("fork() failed too many times - aborting");
goto host_died;
}
}
Expand Down
40 changes: 31 additions & 9 deletions src/pluginlaunch.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ simult_ports (const char *oid, const char *next_oid)
/**
* If another NVT with same port requirements is running, wait.
*
* @return -1 if MAX_PROCESSES are running, the index of the first free "slot"
* in the processes array otherwise.
* @return ERR_NO_FREE_SLOT if MAX_PROCESSES are running, the index of the first
* free "slot" in the processes array otherwise.
*/
static int
next_free_process (kb_t kb, struct scheduler_plugin *upcoming)
Expand All @@ -258,7 +258,7 @@ next_free_process (kb_t kb, struct scheduler_plugin *upcoming)
for (r = 0; r < MAX_PROCESSES; r++)
if (processes[r].pid <= 0)
return r;
return -1;
return ERR_NO_FREE_SLOT;
}

void
Expand Down Expand Up @@ -336,20 +336,35 @@ plugin_timeout (nvti_t *nvti)
}

/**
* @brief Start a plugin.
*
* Check for free slots available in the process table. Set error with
* ERR_NO_FREE_SLOT if the process table is full. Set error with ERR_CANT_FORK
* if was not possible to fork() a new child.
*
* @return PID of process that is connected to the plugin as returned by plugin
* classes pl_launch function (<=0 means there was a problem).
* classes pl_launch function. Less than 0 means there was a problem,
* but error param should be checked.
*/
int
plugin_launch (struct scan_globals *globals, struct scheduler_plugin *plugin,
struct in6_addr *ip, GSList *vhosts, kb_t kb, nvti_t *nvti)
struct in6_addr *ip, GSList *vhosts, kb_t kb, nvti_t *nvti,
int *error)
{
int p;

/* Wait for a free slot */
pluginlaunch_wait_for_free_process (kb);
p = next_free_process (kb, plugin);
if (p < 0)
return -1;
{
g_warning ("%s. There is currently no free slot available for starting a "
"new plugin.",
__func__);
*error = ERR_NO_FREE_SLOT;
return -1;
}

processes[p].plugin = plugin;
processes[p].timeout = plugin_timeout (nvti);
gettimeofday (&(processes[p].start), NULL);
Expand All @@ -358,8 +373,10 @@ plugin_launch (struct scan_globals *globals, struct scheduler_plugin *plugin,
if (processes[p].pid > 0)
num_running_processes++;
else
processes[p].plugin->running_state = PLUGIN_STATUS_UNRUN;

{
processes[p].plugin->running_state = PLUGIN_STATUS_UNRUN;
*error = ERR_CANT_FORK;
}
return processes[p].pid;
}

Expand Down Expand Up @@ -407,11 +424,16 @@ pluginlaunch_wait_for_free_process (kb_t kb)
update_running_processes (kb);
/* Max number of processes are still running, wait for a child to exit or
* to timeout. */
if (num_running_processes == max_running_processes)

if (num_running_processes >= max_running_processes)
{
sigset_t mask;
struct timespec ts = {0, 0};

g_debug ("%s. Number of running processes >= maximum running processes "
"(%d >= %d). Waiting for free slot for processes.",
__func__, num_running_processes, max_running_processes);

ts.tv_sec = timeout_running_processes ();
assert (ts.tv_sec);
sigemptyset (&mask);
Expand Down
11 changes: 10 additions & 1 deletion src/pluginlaunch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
#include "pluginload.h" /* for struct pl_class_t */
#include "pluginscheduler.h" /* for struct plugins_scheduler_t */

/**
* @brief Error for when it is not possible to fork a new plugin process.
*/
#define ERR_CANT_FORK -2
/**
* @brief Error for when the process table is full
*/
#define ERR_NO_FREE_SLOT -99

void
pluginlaunch_init (const char *);
void pluginlaunch_wait (kb_t);
Expand All @@ -39,7 +48,7 @@ pluginlaunch_stop (void);

int
plugin_launch (struct scan_globals *, struct scheduler_plugin *,
struct in6_addr *, GSList *, kb_t, nvti_t *);
struct in6_addr *, GSList *, kb_t, nvti_t *, int *);

void
pluginlaunch_disable_parallel_checks (void);
Expand Down

0 comments on commit 0a7e022

Please sign in to comment.