diff --git a/Makefile b/Makefile index a79c6dd..67d1dac 100644 --- a/Makefile +++ b/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))) diff --git a/cdrom.c b/cdrom.c index b0924ea..f06368b 100644 --- a/cdrom.c +++ b/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; } diff --git a/stage1.h b/stage1.h index c9875db..5bd5c60 100644 --- a/stage1.h +++ b/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)); diff --git a/tools.c b/tools.c index 674b777..c6e8790 100644 --- a/tools.c +++ b/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; diff --git a/tools.h b/tools.h index 8545d46..469102f 100644 --- a/tools.h +++ b/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);