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:
parent
6080f294e4
commit
8d2cd5aec8
3
Makefile
3
Makefile
@ -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
15
cdrom.c
@ -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;
|
||||
}
|
||||
|
2
stage1.h
2
stage1.h
@ -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
50
tools.c
@ -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;
|
||||
|
1
tools.h
1
tools.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user