mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Add message table entry on binary verification failure
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
+1
-1
@@ -555,7 +555,7 @@ void parse_args(int argc, char* argv[])
|
||||
{
|
||||
// Enable stdout printing
|
||||
cli_mode = true;
|
||||
const bool match = verify_self_hash(true);
|
||||
const bool match = verify_FTL(true);
|
||||
if(match)
|
||||
printf("%s SHA256 checksum matches\n", cli_tick());
|
||||
else
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "database/query-table.h"
|
||||
// escape_html()
|
||||
#include "webserver/http-common.h"
|
||||
// GIT_HASH, FTL_ARCH
|
||||
#include "version.h"
|
||||
|
||||
// Number of arguments in a variadic macro
|
||||
// Credit: https://stackoverflow.com/a/35693080/2087442
|
||||
@@ -99,6 +101,8 @@ static const char *get_message_type_str(const enum message_type type)
|
||||
return "CONNECTION_ERROR";
|
||||
case NTP_MESSAGE:
|
||||
return "NTP";
|
||||
case VERIFY_MESSAGE:
|
||||
return "VERIFY";
|
||||
case MAX_MESSAGE:
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
@@ -135,6 +139,8 @@ static enum message_type get_message_type_from_string(const char *typestr)
|
||||
return CONNECTION_ERROR_MESSAGE;
|
||||
else if (strcmp(typestr, "NTP") == 0)
|
||||
return NTP_MESSAGE;
|
||||
else if (strcmp(typestr, "VERIFY") == 0)
|
||||
return VERIFY_MESSAGE;
|
||||
else
|
||||
return MAX_MESSAGE;
|
||||
}
|
||||
@@ -242,6 +248,14 @@ static unsigned char message_blob_types[MAX_MESSAGE][5] =
|
||||
SQLITE_NULL, // not used
|
||||
SQLITE_NULL, // not used
|
||||
SQLITE_NULL // not used
|
||||
},
|
||||
{
|
||||
// VERIFY_MESSAGE: The message column contains the error
|
||||
SQLITE_TEXT, // expected checksum
|
||||
SQLITE_TEXT, // actual checksum
|
||||
SQLITE_TEXT, // FTL commit hash
|
||||
SQLITE_TEXT, // FTL architecture
|
||||
SQLITE_NULL // not used
|
||||
}
|
||||
};
|
||||
// Create message table in the database
|
||||
@@ -928,6 +942,39 @@ static void format_ntp_message(char *plain, const int sizeof_plain, char *html,
|
||||
log_warn("format_ntp_message(): Buffer too small to hold HTML message, warning truncated");
|
||||
}
|
||||
|
||||
static void format_verify_message(char *plain, const int sizeof_plain, char *html, const int sizeof_html,
|
||||
const char *message, const char *expected, const char *actual,
|
||||
const char *commit, const char *arch)
|
||||
{
|
||||
if(snprintf(plain, sizeof_plain, "%s - expected \"%s\", but got \"%s\" - FTL commit is %s on %s",
|
||||
message, expected, actual, commit, arch) > sizeof_plain)
|
||||
log_warn("format_verify_message(): Buffer too small to hold plain message, warning truncated");
|
||||
|
||||
// Return early if HTML text is not required
|
||||
if(sizeof_html < 1 || html == NULL)
|
||||
return;
|
||||
|
||||
char *escaped_message = escape_html(message);
|
||||
char *escaped_expected = escape_html(expected);
|
||||
char *escaped_actual = escape_html(actual);
|
||||
char *escaped_commit = escape_html(commit);
|
||||
char *escaped_arch = escape_html(arch);
|
||||
|
||||
// Return early if memory allocation failed
|
||||
if(escaped_message == NULL || escaped_expected == NULL || escaped_actual == NULL || escaped_commit == NULL || escaped_arch == NULL)
|
||||
return;
|
||||
|
||||
if(snprintf(html, sizeof_html, "%s<br>Expected: <pre>%s</pre><br>Actual: <pre>%s</pre><br>FTL commit is <code>%s</code> on <code>%s</code>",
|
||||
escaped_message, escaped_expected, escaped_actual, escaped_commit, escaped_arch) > sizeof_html)
|
||||
log_warn("format_verify_message(): Buffer too small to hold HTML message, warning truncated");
|
||||
|
||||
free(escaped_message);
|
||||
free(escaped_expected);
|
||||
free(escaped_actual);
|
||||
free(escaped_commit);
|
||||
free(escaped_arch);
|
||||
}
|
||||
|
||||
int count_messages(const bool filter_dnsmasq_warnings)
|
||||
{
|
||||
int count = 0;
|
||||
@@ -1187,6 +1234,20 @@ bool format_messages(cJSON *array)
|
||||
break;
|
||||
}
|
||||
|
||||
case VERIFY_MESSAGE:
|
||||
{
|
||||
const char *message = (const char*)sqlite3_column_text(stmt, 3);
|
||||
const char *expected = (const char*)sqlite3_column_text(stmt, 4);
|
||||
const char *actual = (const char*)sqlite3_column_text(stmt, 5);
|
||||
const char *hash = (const char*)sqlite3_column_text(stmt, 6);
|
||||
const char *arch = (const char*)sqlite3_column_text(stmt, 7);
|
||||
|
||||
format_verify_message(plain, sizeof(plain), html, sizeof(html),
|
||||
message, expected, actual, hash, arch);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MAX_MESSAGE: // Fall through
|
||||
default:
|
||||
log_warn("format_messages() - Unknown message type: %s", mtypestr);
|
||||
@@ -1458,3 +1519,17 @@ void log_ntp_message(const bool error, const bool server, const char *message)
|
||||
add_message(NTP_MESSAGE, message, level, who);
|
||||
|
||||
}
|
||||
|
||||
void log_verify_message(const char *expected, const char *actual)
|
||||
{
|
||||
// Create message
|
||||
char buf[2048];
|
||||
snprintf(buf, sizeof(buf), "Corrupt binary detected - this may lead to unexpected behaviour!");
|
||||
|
||||
// Log to FTL.log
|
||||
log_crit("%s", buf);
|
||||
|
||||
// Log to database
|
||||
add_message(VERIFY_MESSAGE, buf, expected, actual, GIT_HASH, FTL_ARCH);
|
||||
|
||||
}
|
||||
|
||||
@@ -31,5 +31,6 @@ void logg_inaccessible_adlist(const int dbindex, const char *address);
|
||||
void log_certificate_domain_mismatch(const char *certfile, const char *domain);
|
||||
void log_connection_error(const char *server, const char *reason, const char *error);
|
||||
void log_ntp_message(const bool error, const bool server, const char *message);
|
||||
void log_verify_message(const char *expected, const char *actual);
|
||||
|
||||
#endif //MESSAGETABLE_H
|
||||
|
||||
@@ -3130,6 +3130,12 @@ void FTL_fork_and_bind_sockets(struct passwd *ent_pw, bool dnsmasq_start)
|
||||
// Flush messages stored in the long-term database
|
||||
flush_message_table();
|
||||
|
||||
// Verify checksum of this binary early on to ensure that the binary is
|
||||
// not corrupted and that the binary is not tampered with. We can only
|
||||
// do this here as we need the database to be properly initialized
|
||||
// in case we need to store the verification result
|
||||
verify_FTL(false);
|
||||
|
||||
// Initialize in-memory database starting index
|
||||
update_disk_db_idx();
|
||||
|
||||
|
||||
@@ -264,6 +264,7 @@ enum message_type {
|
||||
CERTIFICATE_DOMAIN_MISMATCH_MESSAGE,
|
||||
CONNECTION_ERROR_MESSAGE,
|
||||
NTP_MESSAGE,
|
||||
VERIFY_MESSAGE,
|
||||
MAX_MESSAGE,
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
+11
-8
@@ -15,6 +15,8 @@
|
||||
#include "log.h"
|
||||
// sha256_raw_to_hex()
|
||||
#include "config/password.h"
|
||||
// log_verify_message()
|
||||
#include "database/message-table.h"
|
||||
|
||||
// opendir(), readdir()
|
||||
#include <dirent.h>
|
||||
@@ -776,7 +778,7 @@ bool sha256sum(const char *path, uint8_t checksum[SHA256_DIGEST_SIZE], const boo
|
||||
* @return Returns true if the checksum matches the expected value, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool verify_self_hash(bool verbose)
|
||||
bool verify_FTL(bool verbose)
|
||||
{
|
||||
// Get the filename of the current executable
|
||||
char filename[PATH_MAX] = { 0 };
|
||||
@@ -820,11 +822,6 @@ bool verify_self_hash(bool verbose)
|
||||
// Compare the checksums
|
||||
bool success = memcmp(checksum, self_hash, SHA256_DIGEST_SIZE) == 0;
|
||||
if(!success)
|
||||
log_err("SHA256 checksum of %s does not match the expected value", filename);
|
||||
|
||||
// Log the checksums if the verification failed or if verbose output is
|
||||
// requested
|
||||
if(!success || verbose)
|
||||
{
|
||||
// Convert checksums to human-readable hex strings
|
||||
char expected_hex[SHA256_DIGEST_SIZE*2+1];
|
||||
@@ -832,8 +829,14 @@ bool verify_self_hash(bool verbose)
|
||||
char actual_hex[SHA256_DIGEST_SIZE*2+1];
|
||||
sha256_raw_to_hex(checksum, actual_hex);
|
||||
|
||||
log_info("Expected: %s", expected_hex);
|
||||
log_info("Actual: %s", actual_hex);
|
||||
if(!verbose) // during startup
|
||||
log_verify_message(expected_hex, actual_hex);
|
||||
else // CLI verification
|
||||
{
|
||||
log_err("Checksum verification failed!");
|
||||
log_err("Expected: %s", expected_hex);
|
||||
log_err("Actual: %s", actual_hex);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ bool chown_pihole(const char *path, struct passwd *pwd);
|
||||
void rotate_files(const char *path, char **first_file);
|
||||
bool files_different(const char *pathA, const char* pathB, unsigned int from);
|
||||
bool sha256sum(const char *path, uint8_t checksum[SHA256_DIGEST_SIZE], const bool skip_end);
|
||||
bool verify_self_hash(bool verbose);
|
||||
bool verify_FTL(bool verbose);
|
||||
|
||||
int parse_line(char *line, char **key, char **value);
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "overTime.h"
|
||||
// export_queries_to_disk()
|
||||
#include "database/query-table.h"
|
||||
// verify_FTL()
|
||||
#include "files.h"
|
||||
|
||||
char *username;
|
||||
bool needGC = false;
|
||||
|
||||
Reference in New Issue
Block a user