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

Handle removed CPEs and CVEs in SCAP sync (9.0) #1107

Merged
merged 6 commits into from
May 27, 2020
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 @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed
- Fix NVTs list in CVE details [#1098](https://github.com/greenbone/gvmd/pull/1098)
- Handle removed CPEs and CVEs in SCAP sync [#1107](https://github.com/greenbone/gvmd/pull/1107)

[9.0.2]: https://github.com/greenbone/gvmd/compare/v9.0.1...gvmd-9.0

Expand Down
156 changes: 147 additions & 9 deletions src/manage_sql_secinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -2384,11 +2384,13 @@ insert_scap_cpe (inserts_t *inserts, element_t cpe_item, element_t item_metadata
*
* @param[in] path Path to file.
* @param[in] last_cve_update Time of last CVE update.
* @param[in] all_xml_cpes String to add all CPEs to.
*
* @return 0 nothing to do, 1 updated, -1 error.
*/
static int
update_scap_cpes_from_file (const gchar *path, int last_cve_update)
update_scap_cpes_from_file (const gchar *path, int last_cve_update,
GString *all_xml_cpes)
{
GError *error;
element_t element, cpe_list, cpe_item;
Expand Down Expand Up @@ -2448,7 +2450,7 @@ update_scap_cpes_from_file (const gchar *path, int last_cve_update)
cpe_item = element_first_child (cpe_list);
while (cpe_item)
{
gchar *modification_date;
gchar *modification_date, *name;
int modification_time;
element_t item_metadata;

Expand All @@ -2473,6 +2475,19 @@ update_scap_cpes_from_file (const gchar *path, int last_cve_update)
goto fail;
}

name = element_attribute (cpe_item, "name");
if (name == NULL)
{
g_warning ("%s: name missing", __func__);
goto fail;
}

if (all_xml_cpes->str[0] == '\0')
g_string_append_printf (all_xml_cpes, "'%s'", name);
else
g_string_append_printf (all_xml_cpes, ",'%s'", name);
g_free (name);

modification_time = parse_iso_time (modification_date);
g_free (modification_date);

Expand Down Expand Up @@ -2506,11 +2521,12 @@ update_scap_cpes_from_file (const gchar *path, int last_cve_update)
* @brief Update SCAP CPEs.
*
* @param[in] last_scap_update Time of last SCAP update.
* @param[in] all_xml_cpes String to add all CPEs to.
*
* @return 0 nothing to do, 1 updated, -1 error.
*/
static int
update_scap_cpes (int last_scap_update)
update_scap_cpes (int last_scap_update, GString *all_xml_cpes)
{
gchar *full_path;
const gchar *split_dir;
Expand Down Expand Up @@ -2550,7 +2566,8 @@ update_scap_cpes (int last_scap_update)
g_warning ("%s: Failed to split CPEs, attempting with full file",
__func__);
updated_scap_cpes = update_scap_cpes_from_file (full_path,
last_cve_update);
last_cve_update,
all_xml_cpes);
g_free (full_path);
return updated_scap_cpes;
}
Expand All @@ -2571,7 +2588,7 @@ update_scap_cpes (int last_scap_update)
break;
}

ret = update_scap_cpes_from_file (path, last_cve_update);
ret = update_scap_cpes_from_file (path, last_cve_update, all_xml_cpes);
g_free (path);
if (ret < 0)
{
Expand Down Expand Up @@ -2635,6 +2652,19 @@ hashed_cpes_cpe_id (GHashTable *hashed_cpes, const gchar *product_tilde)
return GPOINTER_TO_INT (g_hash_table_lookup (hashed_cpes, product_tilde));
}

/**
* @brief Push a generic pointer onto an array.
*
* @param[in] array Array.
* @param[in] pointer Pointer.
*/
static void
array_remove (array_t *array, gpointer pointer)
{
if (array)
g_ptr_array_remove_fast (array, pointer);
}

/**
* @brief Insert products for a CVE.
*
Expand All @@ -2653,6 +2683,8 @@ insert_cve_products (element_t list, resource_t cve,
element_t product;
int first_product, first_affected;
GString *sql_cpes, *sql_affected;
array_t *initial_affected;
iterator_t rows;

if (list == NULL)
return;
Expand All @@ -2670,6 +2702,17 @@ insert_cve_products (element_t list, resource_t cve,
" (cve, cpe)"
" VALUES");

/* Record existing affected products. */

initial_affected = make_array ();
init_iterator (&rows,
"SELECT cpe FROM scap.affected_products"
" WHERE cve = %llu;",
cve);
while (next (&rows))
array_add (initial_affected, GINT_TO_POINTER (iterator_int64 (&rows, 0)));
cleanup_iterator (&rows);

/* Buffer the SQL. */

first_product = first_affected = 1;
Expand Down Expand Up @@ -2734,15 +2777,22 @@ insert_cve_products (element_t list, resource_t cve,
}
else
{
int cpe;

/* The product is in the db.
*
* So we don't need to insert it. */

cpe = hashed_cpes_cpe_id (hashed_cpes, product_tilde);

g_string_append_printf
(sql_affected,
"%s (%llu, %i)",
first_affected ? "" : ",", cve,
hashed_cpes_cpe_id (hashed_cpes, product_tilde));
cpe);

/* Remove the affected product from initial_affected. */
array_remove (initial_affected, GINT_TO_POINTER (cpe));
}

first_affected = 0;
Expand All @@ -2755,6 +2805,27 @@ insert_cve_products (element_t list, resource_t cve,
product = element_next (product);
}

/* Remove affected_products that remain in initial_affected. */

if (initial_affected->len)
{
guint index;
GString *ids;

ids = g_string_new ("");
for (index = 0; index < initial_affected->len; index++)
g_string_append_printf (ids,
"%s%i",
index == 0 ? "" : ",",
GPOINTER_TO_INT (g_ptr_array_index
(initial_affected, index)));
sql ("DELETE from scap.affected_products"
" WHERE cve = %llu AND cpe = ANY(array[%s]);",
cve, ids->str);
g_string_free (ids, TRUE);
}
g_ptr_array_free (initial_affected, TRUE);

/* Run the SQL. */

if (first_product == 0)
Expand Down Expand Up @@ -3023,12 +3094,14 @@ insert_cve_from_entry (element_t entry, element_t last_modified,
* @param[in] last_scap_update Time of last SCAP update.
* @param[in] last_cve_update Time of last update to a DFN.
* @param[in] hashed_cpes Hashed CPEs.
* @param[in] all_xml_cves String to add all CVEs to.
*
* @return 0 nothing to do, 1 updated, -1 error.
*/
static int
update_cve_xml (const gchar *xml_path, int last_scap_update,
int last_cve_update, GHashTable *hashed_cpes)
int last_cve_update, GHashTable *hashed_cpes,
GString *all_xml_cves)
{
GError *error;
element_t element, entry;
Expand Down Expand Up @@ -3087,6 +3160,7 @@ update_cve_xml (const gchar *xml_path, int last_scap_update,
{
if (strcmp (element_name (entry), "entry") == 0)
{
gchar *id;
element_t last_modified;

last_modified = element_child (entry, "vuln:last-modified-datetime");
Expand All @@ -3096,6 +3170,21 @@ update_cve_xml (const gchar *xml_path, int last_scap_update,
__FUNCTION__);
goto fail;
}

id = element_attribute (entry, "id");
if (id == NULL)
{
g_warning ("%s: id missing",
__func__);
goto fail;
}

if (all_xml_cves->str[0] == '\0')
g_string_append_printf (all_xml_cves, "'%s'", id);
else
g_string_append_printf (all_xml_cves, ",'%s'", id);
g_free (id);

if (parse_iso_time_element_text (last_modified) > last_cve_update)
{
if (insert_cve_from_entry (entry, last_modified, hashed_cpes,
Expand Down Expand Up @@ -3139,6 +3228,7 @@ update_scap_cves (int last_scap_update)
const gchar *xml_path;
GHashTable *hashed_cpes;
iterator_t cpes;
GString *all_xml_cves;

error = NULL;
dir = g_dir_open (GVM_SCAP_DATA_DIR, 0, &error);
Expand All @@ -3160,13 +3250,15 @@ update_scap_cves (int last_scap_update)
(gpointer*) iterator_string (&cpes, 0),
GINT_TO_POINTER (iterator_int (&cpes, 1)));

all_xml_cves = g_string_new ("");

count = 0;
updated_scap_cves = 0;
while ((xml_path = g_dir_read_name (dir)))
if (fnmatch ("nvdcve-2.0-*.xml", xml_path, 0) == 0)
{
switch (update_cve_xml (xml_path, last_scap_update, last_cve_update,
hashed_cpes))
hashed_cpes, all_xml_cves))
{
case 0:
break;
Expand All @@ -3176,12 +3268,35 @@ update_scap_cves (int last_scap_update)
default:
g_dir_close (dir);
g_hash_table_destroy (hashed_cpes);
g_string_free (all_xml_cves, TRUE);
cleanup_iterator (&cpes);
return -1;
}
count++;
}

if (strlen (all_xml_cves->str) > 0)
{
/* Remove CVES from the db that are not in all_xml_cves. */

g_string_prepend
(all_xml_cves, "WITH"
" removed AS (SELECT id FROM scap.cves"
" WHERE NOT uuid = ANY(array[");

g_string_append
(all_xml_cves, "])),"
" dummy AS (DELETE FROM scap.affected_products"
" WHERE cve IN (SELECT id FROM removed)"
" RETURNING *)"
" DELETE FROM scap.cves"
" WHERE id IN (SELECT id FROM removed);");

sql (all_xml_cves->str);
updated_scap_cves = 1;
}
g_string_free (all_xml_cves, TRUE);

if (count == 0)
g_warning ("No CVEs found in %s", GVM_SCAP_DATA_DIR);

Expand Down Expand Up @@ -4986,6 +5101,7 @@ update_scap (int lockfile,
{
int last_feed_update, last_scap_update;
int updated_scap_ovaldefs, updated_scap_cpes, updated_scap_cves;
GString *all_xml_cpes;

updated_scap_ovaldefs = 0;
updated_scap_cpes = 0;
Expand Down Expand Up @@ -5058,14 +5174,17 @@ update_scap (int lockfile,

g_info ("%s: Updating data from feed", __FUNCTION__);

all_xml_cpes = g_string_new ("");

if (update_cpes)
{
g_debug ("%s: update cpes", __FUNCTION__);
proctitle_set ("gvmd: Syncing SCAP: Updating CPEs");

updated_scap_cpes = update_scap_cpes (last_scap_update);
updated_scap_cpes = update_scap_cpes (last_scap_update, all_xml_cpes);
if (updated_scap_cpes == -1)
{
g_string_free (all_xml_cpes, TRUE);
manage_update_scap_db_cleanup ();
goto fail;
}
Expand All @@ -5079,11 +5198,30 @@ update_scap (int lockfile,
updated_scap_cves = update_scap_cves (last_scap_update);
if (updated_scap_cves == -1)
{
g_string_free (all_xml_cpes, TRUE);
manage_update_scap_db_cleanup ();
goto fail;
}
}

if (strlen (all_xml_cpes->str) > 0)
{
/* Remove CPES not in all_xml_cpes, except those in affected_products. */

g_string_prepend
(all_xml_cpes, "DELETE FROM scap.cpes"
" WHERE NOT EXISTS (SELECT * FROM scap.affected_products"
" WHERE cpe = scap.cpes.id)"
" AND NOT uuid = ANY(array[");

g_string_append
(all_xml_cpes, "]);");

sql (all_xml_cpes->str);
updated_scap_cpes = 1;
}
g_string_free (all_xml_cpes, TRUE);

if (update_ovaldefs)
{
g_debug ("%s: update ovaldefs", __FUNCTION__);
Expand Down