fu_history: fu_security_attr: Convert secutiry attr to json and write to DB.

1. Create hsi_history table to store the security attributes.
2. Convert all security entities to a json string and write to database.

Signed-off-by: Kate Hsuan <hpa@redhat.com>

Changes in v1:
1. Fixed typo: "his_history" to "hsi_history"
2. g_autofree all gchar pointer.
3. Removed unnecessary g_warning messages.
4. Moved the json format comment to Document comment.
5. Add an error handling for json converter.

Changes in v2:
1. Declare all pointers using g_auto_ptr.
2. The warning messages of JSON conversion and DB writing errors were added.
3. "Since: 1.7.0" was added to the document comment.

Changes in v3:
1. Fix variable declaration.
2. Remove unecessary data type casting.

Changes in v4:
1. Fix migration schema.

Changes in v5:
1. Fix hsi_history column name declaration.

Changes in v6:
Column name was modified from last to timestamp.
This commit is contained in:
Kate Hsuan 2021-08-24 03:16:31 -04:00 committed by Richard Hughes
parent 5c60beae29
commit db04223167
5 changed files with 168 additions and 1 deletions

View File

@ -5908,6 +5908,8 @@ fu_engine_ensure_security_attrs(FuEngine *self)
GPtrArray *plugins = fu_plugin_list_get_all(self->plugin_list);
g_autoptr(GPtrArray) devices = fu_device_list_get_all(self->device_list);
g_autoptr(GPtrArray) items = NULL;
g_autoptr(GError) error = NULL;
g_autofree gchar *data = NULL;
/* already valid */
if (self->host_security_id != NULL)
@ -5952,6 +5954,20 @@ fu_engine_ensure_security_attrs(FuEngine *self)
/* distil into one simple string */
g_free(self->host_security_id);
self->host_security_id = fu_engine_attrs_calculate_hsi_for_chassis(self);
/* Convert Security attribute to json string */
data = fu_security_attrs_to_json_string(self->host_security_attrs, &error);
/* Store string to db */
if (data == NULL) {
g_warning("Fail to convert security attributes to string: %s", error->message);
} else {
if (fu_history_add_security_attribute(self->history,
data,
self->host_security_id,
&error) == FALSE)
g_warning("Fail to write security attribute to DB: %s", error->message);
}
}
const gchar *

View File

@ -20,7 +20,7 @@
#include "fu-history.h"
#include "fu-mutex.h"
#define FU_HISTORY_CURRENT_SCHEMA_VERSION 6
#define FU_HISTORY_CURRENT_SCHEMA_VERSION 7
static void
fu_history_finalize(GObject *object);
@ -183,6 +183,10 @@ fu_history_create_database(FuHistory *self, GError **error)
"checksum TEXT);"
"CREATE TABLE IF NOT EXISTS blocked_firmware ("
"checksum TEXT);"
"CREATE TABLE IF NOT EXISTS hsi_history ("
"timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
"hsi_details TEXT DEFAULT NULL,"
"hsi_score TEXT DEFAULT NULL);"
"COMMIT;",
NULL,
NULL,
@ -307,6 +311,29 @@ fu_history_migrate_database_v5(FuHistory *self, GError **error)
return TRUE;
}
static gboolean
fu_history_migrate_database_v6(FuHistory *self, GError **error)
{
gint rc;
rc = sqlite3_exec(self->db,
"CREATE TABLE IF NOT EXISTS hsi_history ("
"timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,"
"hsi_details TEXT DEFAULT NULL,"
"hsi_score TEXT DEFAULT NULL);",
NULL,
NULL,
NULL);
if (rc != SQLITE_OK) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Failed to create table: %s",
sqlite3_errmsg(self->db));
return FALSE;
}
return TRUE;
}
/* returns 0 if database is not initialized */
static guint
fu_history_get_schema_version(FuHistory *self)
@ -363,6 +390,10 @@ fu_history_create_or_migrate(FuHistory *self, guint schema_ver, GError **error)
case 5:
if (!fu_history_migrate_database_v5(self, error))
return FALSE;
/* fall through */
case 6:
if (!fu_history_migrate_database_v6(self, error))
return FALSE;
break;
default:
/* this is probably okay, but return an error if we ever delete
@ -1283,6 +1314,42 @@ fu_history_add_blocked_firmware(FuHistory *self, const gchar *checksum, GError *
return fu_history_stmt_exec(self, stmt, NULL, error);
}
gboolean
fu_history_add_security_attribute(FuHistory *self,
const gchar *security_attr_json,
const gchar *hsi_score,
GError **error)
{
gint rc;
g_autoptr(sqlite3_stmt) stmt = NULL;
g_autoptr(GRWLockWriterLocker) locker = NULL;
g_return_val_if_fail(FU_IS_HISTORY(self), FALSE);
/* lazy load */
if (!fu_history_load(self, error))
return FALSE;
/* remove entries */
locker = g_rw_lock_writer_locker_new(&self->db_mutex);
g_return_val_if_fail(locker != NULL, FALSE);
rc = sqlite3_prepare_v2(self->db,
"INSERT INTO hsi_history (hsi_details, hsi_score)"
"VALUES (?1, ?2)",
-1,
&stmt,
NULL);
if (rc != SQLITE_OK) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Failed to prepare SQL to write security attribute: %s",
sqlite3_errmsg(self->db));
return FALSE;
}
sqlite3_bind_text(stmt, 1, security_attr_json, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, hsi_score, -1, SQLITE_STATIC);
return fu_history_stmt_exec(self, stmt, NULL, error);
}
static void
fu_history_class_init(FuHistoryClass *klass)
{

View File

@ -48,3 +48,8 @@ gboolean
fu_history_add_blocked_firmware(FuHistory *self, const gchar *checksum, GError **error);
GPtrArray *
fu_history_get_blocked_firmware(FuHistory *self, GError **error);
gboolean
fu_history_add_security_attribute(FuHistory *self,
const gchar *security_attr_json,
const gchar *hsi_score,
GError **error);

View File

@ -8,9 +8,12 @@
#include <config.h>
#include <glib/gi18n.h>
#include <json-glib/json-glib.h>
#include "fwupd-security-attr-private.h"
#include "fu-security-attrs-private.h"
gchar *
fu_security_attr_get_name(FwupdSecurityAttr *attr)
{
@ -247,3 +250,72 @@ fu_security_attr_get_result(FwupdSecurityAttr *attr)
/* TRANSLATORS: Suffix: the fallback HSI result */
return _("Failed");
}
/**
* fu_security_attrs_to_json_string
* Convert security attribute to JSON string.
* @attrs: a pointer for a FuSecurityAttrs data structure.
* @error: return location for an error
*
* fu_security_attrs_to_json_string() converts FuSecurityAttrs and return the
* string pointer. The converted JSON format is shown as follows:
* {
* "SecurityAttrs": {
* "Attrs": [
* {
* "name": "aaa",
* "value": "bbb"
* }
* ]
* }
* }
*
* Returns: A string and NULL on fail.
*
* Since: 1.7.0
*
*/
gchar *
fu_security_attrs_to_json_string(FuSecurityAttrs *attrs, GError **error)
{
g_autofree gchar *data = NULL;
g_autoptr(JsonGenerator) json_generator = NULL;
g_autoptr(JsonBuilder) builder = json_builder_new();
g_autoptr(JsonNode) json_root = NULL;
fu_security_attrs_to_json(attrs, builder);
json_root = json_builder_get_root(builder);
json_generator = json_generator_new();
json_generator_set_pretty(json_generator, TRUE);
json_generator_set_root(json_generator, json_root);
data = json_generator_to_data(json_generator, NULL);
if (data == NULL) {
g_set_error(error,
FWUPD_ERROR,
FWUPD_ERROR_INTERNAL,
"Failed to convert security attribute to json.");
return NULL;
}
return g_steal_pointer(&data);
}
void
fu_security_attrs_to_json(FuSecurityAttrs *attrs, JsonBuilder *builder)
{
g_autoptr(GPtrArray) items = NULL;
g_autoptr(GError) error = NULL;
json_builder_begin_object(builder);
json_builder_set_member_name(builder, "SecurityAttrs");
json_builder_begin_object(builder);
json_builder_set_member_name(builder, "Attrs");
json_builder_begin_array(builder);
items = fu_security_attrs_get_all(attrs);
for (guint i = 0; i < items->len; i++) {
FwupdSecurityAttr *attr = g_ptr_array_index(items, i);
json_builder_begin_object(builder);
fwupd_security_attr_to_json(attr, builder);
json_builder_end_object(builder);
}
json_builder_end_array(builder);
json_builder_end_object(builder);
json_builder_end_object(builder);
}

View File

@ -7,8 +7,15 @@
#pragma once
#include <fwupd.h>
#include <json-glib/json-glib.h>
#include "fu-security-attrs-private.h"
gchar *
fu_security_attr_get_name(FwupdSecurityAttr *attr);
const gchar *
fu_security_attr_get_result(FwupdSecurityAttr *attr);
void
fu_security_attrs_to_json(FuSecurityAttrs *attrs, JsonBuilder *builder);
gchar *
fu_security_attrs_to_json_string(FuSecurityAttrs *attrs, GError **error);