Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check feed status without acquiring lock #1266

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed
- Extended the output of invalid / missing --feed parameter given to greenbone-feed-sync [#1255](https://github.com/greenbone/gvmd/pull/1255)
- The xsltproc binary is now marked as mandatory [#1259](https://github.com/greenbone/gvmd/pull/1259)
- Check feed status without acquiring lock [#1266](https://github.com/greenbone/gvmd/pull/1266)

### Fixed
- Add dummy functions to allow restoring old dumps [#1251](https://github.com/greenbone/gvmd/pull/1251)
Expand Down
103 changes: 98 additions & 5 deletions src/gvmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,11 @@ static gchar *dh_params_option = NULL;
*/
static int update_in_progress = 0;

/**
* @brief Whether a feed version check is in progress.
*/
static int feed_version_check_in_progress = 0;

/**
* @brief Logging parameters, as passed to setup_log_handlers.
*/
Expand Down Expand Up @@ -1014,9 +1019,15 @@ handle_sigchld (/* unused */ int given_signal, siginfo_t *info, void *ucontext)
{
int status, pid;
while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
if (update_in_progress == pid)
/* This was the NVT update child, so allow updates again. */
update_in_progress = 0;
{
if (update_in_progress == pid)
/* This was the NVT update child, so allow updates again. */
update_in_progress = 0;

if (feed_version_check_in_progress == pid)
/* This was a version check child, so allow version checks again */
feed_version_check_in_progress = 0;
}
}


Expand Down Expand Up @@ -1190,6 +1201,88 @@ fork_update_nvt_cache ()
}
}

/**
* @brief Forks a process to sync the feed.
*
* @return 0 success, 1 check in progress, -1 error. Always exits with
* EXIT_SUCCESS in child.
*/
static int
fork_feed_sync ()
{
int pid;
sigset_t sigmask_all, sigmask_current;

if (feed_version_check_in_progress)
{
g_debug ("%s: Feed version check skipped because one"
" is already in progress",
__func__);
return 1;
}

feed_version_check_in_progress = 1;

/* Block SIGCHLD until parent records the value of the child PID. */
if (sigemptyset (&sigmask_all))
{
g_critical ("%s: Error emptying signal set", __func__);
return -1;
}
if (pthread_sigmask (SIG_BLOCK, &sigmask_all, &sigmask_current))
{
g_critical ("%s: Error setting signal mask", __func__);
return -1;
}

pid = fork_with_handlers ();
switch (pid)
{
case 0:
/* Child. */

proctitle_set ("gvmd: Synchronizing feed data");

/* Clean up the process. */

if (sigmask_normal)
pthread_sigmask (SIG_SETMASK, sigmask_normal, NULL);
else
pthread_sigmask (SIG_SETMASK, &sigmask_current, NULL);
/** @todo This should happen via gmp, maybe with "cleanup_gmp ();". */
cleanup_manage_process (FALSE);
if (manager_socket > -1) close (manager_socket);
if (manager_socket_2 > -1) close (manager_socket_2);

/* Check the feed version. */

manage_sync (sigmask_normal, fork_update_nvt_cache);

/* Exit. */

cleanup_manage_process (FALSE);
exit (EXIT_SUCCESS);

break;

case -1:
/* Parent when error. */
g_warning ("%s: fork: %s", __func__, strerror (errno));
feed_version_check_in_progress = 0;
if (pthread_sigmask (SIG_SETMASK, &sigmask_current, NULL))
g_warning ("%s: Error resetting signal mask", __func__);
return -1;

default:
/* Parent. Unblock signals and continue. */
g_debug ("%s: %i forked %i", __func__, getpid (), pid);
feed_version_check_in_progress = pid;
if (pthread_sigmask (SIG_SETMASK, &sigmask_current, NULL))
g_warning ("%s: Error resetting signal mask", __func__);
return 0;
}
}

/**
* @brief Serve incoming connections, scheduling periodically.
*
Expand Down Expand Up @@ -1267,7 +1360,7 @@ serve_and_schedule ()

if ((time (NULL) - last_sync_time) >= SCHEDULE_PERIOD)
{
manage_sync (sigmask_normal, fork_update_nvt_cache);
fork_feed_sync ();
last_sync_time = time (NULL);
}

Expand Down Expand Up @@ -1323,7 +1416,7 @@ serve_and_schedule ()

if ((time (NULL) - last_sync_time) >= SCHEDULE_PERIOD)
{
manage_sync (sigmask_normal, fork_update_nvt_cache);
fork_feed_sync ();
last_sync_time = time (NULL);
}

Expand Down
63 changes: 58 additions & 5 deletions src/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -7277,6 +7277,53 @@ scheduled_task_stop (scheduled_task_t *scheduled_task,
exit (EXIT_SUCCESS);
}

/**
* @brief Check if a feed sync is needed without acquiring the feed lock.
*
* @return TRUE if a feed sync is needed, FALSE otherwise.
*/
gboolean
feed_sync_required ()
{
int feed_status_ret;

feed_status_ret = secinfo_feed_version_status ("cert");
switch (feed_status_ret)
{
case 1:
case 2:
case 3:
case 4:
g_debug ("%s: CERT database needs to be updated (status %d)",
__func__, feed_status_ret);
return TRUE;
default:
break;
}

feed_status_ret = secinfo_feed_version_status ("scap");
switch (feed_status_ret)
{
case 1:
case 2:
case 3:
case 4:
g_debug ("%s: SCAP database needs to be updated (status %d)",
__func__, feed_status_ret);
return TRUE;
default:
break;
}

if (nvts_feed_version_status () == 1)
{
g_debug ("%s: NVTs need to be updated", __func__);
return TRUE;
}

return FALSE;
}

/**
* @brief Perform any syncing that is due.
*
Expand All @@ -7292,13 +7339,19 @@ manage_sync (sigset_t *sigmask_current,
{
lockfile_t lockfile;

if (feed_lockfile_lock (&lockfile) == 0)
reinit_manage_process ();
manage_session_init (current_credentials.uuid);

if (feed_sync_required ())
{
manage_sync_nvts (fork_update_nvt_cache);
manage_sync_scap (sigmask_current);
manage_sync_cert (sigmask_current);
if (feed_lockfile_lock (&lockfile) == 0)
{
manage_sync_nvts (fork_update_nvt_cache);
manage_sync_scap (sigmask_current);
manage_sync_cert (sigmask_current);

lockfile_unlock (&lockfile);
lockfile_unlock (&lockfile);
}
}

manage_sync_configs ();
Expand Down
122 changes: 99 additions & 23 deletions src/manage_sql_nvts.c
Original file line number Diff line number Diff line change
Expand Up @@ -1790,36 +1790,26 @@ update_nvt_cache_osp (const gchar *update_socket, gchar *db_feed_version,
}

/**
* @brief Update VTs via OSP.
*
* Expect to be called in the child after a fork.
* @brief Get the VTs feed version from an OSP scanner.
*
* @param[in] update_socket Socket to use to contact ospd-openvas scanner.
*
* @return 0 success, -1 error, 1 VT integrity check failed.
* @return The feed version or NULL on error.
*/
int
manage_update_nvt_cache_osp (const gchar *update_socket)
static char *
osp_scanner_feed_version (const gchar *update_socket)
{
osp_connection_t *connection;
gchar *db_feed_version, *scanner_feed_version;
gchar *error;
gchar *scanner_feed_version;

/* Re-open DB after fork. */

reinit_manage_process ();
manage_session_init (current_credentials.uuid);

/* Try update VTs. */

db_feed_version = nvts_feed_version ();
g_debug ("%s: db_feed_version: %s", __func__, db_feed_version);
scanner_feed_version = NULL;

connection = osp_connection_new (update_socket, 0, NULL, NULL, NULL);
if (!connection)
{
g_debug ("%s: failed to connect to %s", __func__, update_socket);
return -1;
return NULL;
}

error = NULL;
Expand All @@ -1828,27 +1818,113 @@ manage_update_nvt_cache_osp (const gchar *update_socket)
g_debug ("%s: failed to get scanner_feed_version. %s",
__func__, error ? : "");
g_free (error);
return -1;
osp_connection_close (connection);
return NULL;
}
g_debug ("%s: scanner_feed_version: %s", __func__, scanner_feed_version);

osp_connection_close (connection);

return scanner_feed_version;
}

/**
* @brief Check VTs feed version status via OSP, optionally get versions.
*
* @param[in] update_socket Socket to use to contact ospd-openvas scanner.
* @param[out] db_feed_version_out Output of database feed version.
* @param[out] scanner_feed_version_out Output of scanner feed version.
*
* @return 0 VTs feed current, -1 error, 1 VT update needed.
*/
static int
nvts_feed_version_status_internal (const gchar *update_socket,
gchar **db_feed_version_out,
gchar **scanner_feed_version_out)
{
gchar *db_feed_version, *scanner_feed_version;

if (db_feed_version_out)
*db_feed_version_out = NULL;
if (scanner_feed_version_out)
*scanner_feed_version_out = NULL;

db_feed_version = nvts_feed_version ();
g_debug ("%s: db_feed_version: %s", __func__, db_feed_version);
if (db_feed_version_out && db_feed_version)
*db_feed_version_out = g_strdup (db_feed_version);

scanner_feed_version = osp_scanner_feed_version (update_socket);
g_debug ("%s: scanner_feed_version: %s", __func__, scanner_feed_version);
if (scanner_feed_version == NULL)
return -1;
if (scanner_feed_version_out && scanner_feed_version)
*scanner_feed_version_out = g_strdup (scanner_feed_version);

if ((db_feed_version == NULL)
|| strcmp (scanner_feed_version, db_feed_version))
{
int ret;
g_free (db_feed_version);
g_free (scanner_feed_version);
return 1;
}

g_info ("OSP service has different VT status (version %s) from database (version %s, %i VTs). Starting update ...",
scanner_feed_version, db_feed_version, sql_int ("SELECT count (*) FROM nvts;"));
return 0;
}

/**
* @brief Check VTs feed version status
*
* @return 0 VTs feed current, 1 VT update needed, -1 error.
*/
int
nvts_feed_version_status ()
{
return nvts_feed_version_status_internal (get_osp_vt_update_socket (),
NULL,
NULL);
}

/**
* @brief Update VTs via OSP.
*
* Expect to be called in the child after a fork.
*
* @param[in] update_socket Socket to use to contact ospd-openvas scanner.
*
* @return 0 success, -1 error, 1 VT integrity check failed.
*/
int
manage_update_nvt_cache_osp (const gchar *update_socket)
{
gchar *db_feed_version, *scanner_feed_version;
int ret;

/* Re-open DB after fork. */

reinit_manage_process ();
manage_session_init (current_credentials.uuid);

/* Try update VTs. */

ret = nvts_feed_version_status_internal (update_socket,
&db_feed_version,
&scanner_feed_version);
if (ret == 1)
{
g_info ("OSP service has different VT status (version %s)"
" from database (version %s, %i VTs). Starting update ...",
scanner_feed_version, db_feed_version,
sql_int ("SELECT count (*) FROM nvts;"));

ret = update_nvt_cache_osp (update_socket, db_feed_version,
scanner_feed_version);

g_free (db_feed_version);
g_free (scanner_feed_version);
return ret;
}

return 0;
return ret;
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/manage_sql_nvts.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ manage_sync_nvts (int (*) ());
int
update_or_rebuild_nvts (int);

int
nvts_feed_version_status ();

int
manage_update_nvt_cache_osp (const gchar *);

Expand Down
Loading