initial verify_ramdisk_digest()

This is a patch by Maxim Suhanov <suhanov/group-ib.ru>
aiming to provide integrity and authenticity check for
stage2 rootfs image when required:

- media bootloader passes sha256 hash of stage2 image;
- stage1 early userspace code (that is, propagator)
  checks the candidate files against that during search;
- existing file with different checksum results in a warning
  with a dialog to just say NO, continue searching for the
  proper squashfs image and have a look at that weird one;
- existing file with correct checksum results in booting
  as usual.

The check is triggered by "hash=..." kernel boot parameter.

See also http://www.forensicswiki.org/wiki/Forensic_Live_CD_issues
This commit is contained in:
Michael Shigorin 2014-04-19 10:50:25 +04:00
parent 6080f294e4
commit 8d2cd5aec8
5 changed files with 65 additions and 6 deletions

View File

@ -81,7 +81,8 @@ STAGE1_NETWORK_LIBS = $($(L)_STAGE1_NETWORK_LIBS)
STAGE1SRC = stage1.c log.c tools.c modules.c probing.c \
mount.c lomount.c automatic.c frontend-common.c \
cdrom.c disk.c common.c \
network.c dhcp.c url.c dns.c adsl.c
network.c dhcp.c url.c dns.c adsl.c \
sha256.c
STAGE1OBJS = $(addprefix $(L)-,$(subst .c,.o,$(STAGE1SRC)))

15
cdrom.c
View File

@ -64,9 +64,10 @@ static int mount_that_cd_device(char * dev_name)
return mount_iso9660(device_fullname);
}
static int test_that_cd()
/* test_that_cd() returns 0 on success */
static int test_that_cd(int no_digest)
{
if (IS_VERIFICATION && !no_digest) return !verify_ramdisk_digest(get_ramdisk_path(NULL), get_param_valued("hash"));
log_message("test file on cd: %s\n", get_ramdisk_path(NULL));
return access(get_ramdisk_path(NULL), R_OK);
}
@ -79,10 +80,14 @@ static enum return_type do_with_device(char * dev_name, char * dev_model)
struct stat st;
char msg[256];
char * ramdisk_path;
if (test_that_cd()) {
if (test_that_cd(0)) {
enum return_type results;
umount(IMAGE_LOCATION);
snprintf(msg, sizeof(msg), "That ISO does not seem like proper %s"
if (IS_VERIFICATION)
snprintf(msg, sizeof(msg), "That ISO (on %s) does not seem like proper %s"
" media: hash verification failed.\nRetry with another one?", dev_name, version);
else
snprintf(msg, sizeof(msg), "That ISO does not seem like proper %s"
" media.\nRetry with another one?", version);
results = ask_yes_no(msg);
if (results == RETURN_OK)
@ -150,7 +155,7 @@ int try_automatic(char ** medias, char ** medias_models)
wait_message("Trying to access media in drive %s", *model);
if (mount_that_cd_device(*ptr) != -1) {
if (!test_that_cd()) {
if (!test_that_cd(1)) {
remove_wait_message();
return i;
}

View File

@ -43,6 +43,7 @@ extern char * interactive_fifo;
#define MODE_CHANGEDISK (1 << 10)
#define MODE_UPDATEMODULES (1 << 11)
#define MODE_SPLASH (1 << 12)
#define MODE_VERIFICATION (1 << 13)
#define IS_TESTING (get_param(MODE_TESTING))
#define IS_EXPERT (get_param(MODE_EXPERT))
@ -56,6 +57,7 @@ extern char * interactive_fifo;
#define IS_CHANGEDISK (get_param(MODE_CHANGEDISK))
#define IS_UPDATEMODULES (get_param(MODE_UPDATEMODULES))
#define IS_SPLASH (get_param(MODE_SPLASH))
#define IS_VERIFICATION (get_param(MODE_VERIFICATION))
void fatal_error(char *msg) __attribute__ ((noreturn));

50
tools.c
View File

@ -42,6 +42,7 @@
#include <linux/loop.h>
#include "tools.h"
#include "modules.h"
#include "sha256.h"
#ifdef SPAWN_SPLASH
#include "init.h"
#endif
@ -98,6 +99,7 @@ void process_cmdline(void)
if (!strcmp(name, "live")) set_param(MODE_LIVE);
if (!strcmp(name, "stagename")) set_param(MODE_STAGENAME);
if (!strcmp(name, "lowmem")) set_param(MODE_LOWMEM);
if (!strcmp(name, "hash")) set_param(MODE_VERIFICATION);
if (!strcmp(name, "automatic")) {
set_param(MODE_AUTOMATIC);
grab_automatic_params(value);
@ -352,6 +354,54 @@ char * get_ramdisk_path(const char *mount_path)
return strdup(img_name);
}
/* This function is used to protect against stage2 (aka ramdisk) spoofing */
int verify_ramdisk_digest(const char *filename, const char *sha256_hash)
{
FILE *fp;
char buffer[8192];
size_t len;
sha256_context ctx;
uint8 digest[32];
char computed_hash[64];
char * wait_msg = "Verifying stage2 authenticity...";
struct stat st;
int bytes_read = 0;
int ramdisk_size;
if(sha256_hash == NULL) return 0;
if(stat(filename, &st)) return 0;
ramdisk_size = st.st_size;
fp = fopen(filename, "rb");
if(fp == NULL) return 0;
init_progression(wait_msg, ramdisk_size);
sha256_starts(&ctx);
while((len = fread(buffer, 1, sizeof(buffer), fp)) > 0)
{
if(ferror(fp))
{
fclose(fp);
log_message("error reading ramdisk");
remove_wait_message();
return 0;
}
sha256_update(&ctx, buffer, len);
update_progression((int)(bytes_read += len));
}
sha256_finish(&ctx, digest);
end_progression();
fclose(fp);
len = 0;
int i = 0;
for (i; i < 32; i++) len += sprintf(computed_hash + len, "%02x", digest[i]);
return (strcmp(computed_hash, sha256_hash) == 0);
}
enum return_type load_ramdisk(char *mount_path)
{
int st2_fd;

View File

@ -43,6 +43,7 @@ char ** list_directory(char * direct);
int string_array_length(char ** a);
int do_losetup(char * device, char * target);
char * get_ramdisk_path(const char *);
int verify_ramdisk_digest(const char *filename, const char *sha256_hash);
int splash_verbose();
int update_splash(char * state);
int prepare_progress(void);