From db042231675f70f7b279fef8b33e66dbec55393e Mon Sep 17 00:00:00 2001 From: Kate Hsuan Date: Tue, 24 Aug 2021 03:16:31 -0400 Subject: [PATCH] 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 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. --- src/fu-engine.c | 16 ++++++++++ src/fu-history.c | 69 +++++++++++++++++++++++++++++++++++++++- src/fu-history.h | 5 +++ src/fu-security-attr.c | 72 ++++++++++++++++++++++++++++++++++++++++++ src/fu-security-attr.h | 7 ++++ 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/src/fu-engine.c b/src/fu-engine.c index 798ca9918..4b8b5e3d5 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -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 * diff --git a/src/fu-history.c b/src/fu-history.c index 719373125..70a4ee13c 100644 --- a/src/fu-history.c +++ b/src/fu-history.c @@ -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) { diff --git a/src/fu-history.h b/src/fu-history.h index c9287a645..b6eb55601 100644 --- a/src/fu-history.h +++ b/src/fu-history.h @@ -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); diff --git a/src/fu-security-attr.c b/src/fu-security-attr.c index ce6d58257..b96264866 100644 --- a/src/fu-security-attr.c +++ b/src/fu-security-attr.c @@ -8,9 +8,12 @@ #include #include +#include #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); +} diff --git a/src/fu-security-attr.h b/src/fu-security-attr.h index b9498e47c..a64fa8f5e 100644 --- a/src/fu-security-attr.h +++ b/src/fu-security-attr.h @@ -7,8 +7,15 @@ #pragma once #include +#include + +#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);