From 7bb7ec09ade2feb6491ae04c8a091713885509a0 Mon Sep 17 00:00:00 2001
From: whh8b <whh8b@git.zephyr-software.com>
Date: Fri, 11 Mar 2016 23:30:00 +0000
Subject: [PATCH] Set top of stack in fs0x28 at start.

---
 canaries/canaries_callbacks.c     | 18 +++++-
 canaries/debug_canary_callbacks.c | 96 +++++++++++++++++++++++++++++++
 2 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/canaries/canaries_callbacks.c b/canaries/canaries_callbacks.c
index 037c21f..d64998f 100644
--- a/canaries/canaries_callbacks.c
+++ b/canaries/canaries_callbacks.c
@@ -27,7 +27,7 @@
 #include "null.h"
 #endif
 #define DEBUG_ADD
-static unsigned long long canaries_top_of_stack = 0;
+unsigned long long canaries_top_of_stack = 0;
 
 #ifdef DEBUG
 	#define print_str_debug canaries_print_str
@@ -104,6 +104,8 @@ void zipr_set_top_of_stack(unsigned long long ignore,
 	print_str_debug("\n");
 #endif
 	canaries_top_of_stack = rsp;
+
+	asm volatile ("mov %%dx, %%fs:0x28\n":::);
 }
 
 void rewrite_canaries(uint64_t new_canary) {
@@ -155,6 +157,15 @@ void rewrite_canaries(uint64_t new_canary) {
 	printf("offset:                  0x%x\n", offset);
 	printf("replacement canary:      0x%lx\n", replacement_canary);
 */
+	print_str_debug("fs:0x28:                 0x");
+	print_unsigned_long_long_debug(old_canary);
+	print_str_debug("\n");
+	print_str_debug("offset:                    ");
+	print_unsigned_long_long_debug(offset);
+	print_str_debug("\n");
+	print_str_debug("replacement canary:        ");
+	print_unsigned_long_long_debug(replacement_canary);
+	print_str_debug("\n");
 #endif
 	/*
 	 * The last 16 bits don't matter for
@@ -166,7 +177,7 @@ void rewrite_canaries(uint64_t new_canary) {
 	 * Walk the canary stack and
 	 * update as we go.
 	 */
-	while ((uint64_t)canary_loc <= canaries_top_of_stack) {
+	while ((uint64_t)canary_loc < canaries_top_of_stack) {
 #if DEBUG
 		print_str_debug("We are inside the rewriting loop.\n");
 		print_str_debug("canary_loc:");
@@ -219,6 +230,7 @@ void rewrite_canaries(uint64_t new_canary) {
 /*
  */
 #define FORK 57
+#define ACCEPT 57
 #define PTHREAD_CREATE 58
 void zipr_hook_dynamic_callback(unsigned int id, unsigned long long rax, unsigned long long rsp)
 {
@@ -233,7 +245,7 @@ void zipr_hook_dynamic_callback(unsigned int id, unsigned long long rax, unsigne
 #endif
 		zipr_set_top_of_stack(0ll, rsp);
 	}
-	else if (id == FORK && rax!=0) {
+	else if (id == FORK /*&& rax!=0*/) {
 #ifdef DEBUG
 	print_str_debug("In zipr_rewrite_canaries_callback, id=");
 	print_int_debug(id);
diff --git a/canaries/debug_canary_callbacks.c b/canaries/debug_canary_callbacks.c
index a8a65c7..63e8c90 100644
--- a/canaries/debug_canary_callbacks.c
+++ b/canaries/debug_canary_callbacks.c
@@ -53,6 +53,101 @@ void print_unsigned_long_long(unsigned long long x)
 }
 #endif
 
+extern unsigned long long canaries_top_of_stack;
+ 
+void verify_all_canaries(void) {
+	void *canary_loc = NULL; 
+	uint16_t offset = 0;
+	uint64_t canary = 0;
+	uint64_t old_canary = 0;
+	uint16_t distance_to_first_canary = 0;
+	/*
+	 * Without the nop here, fix_canaries
+	 * believes that this is a push canary operation.
+	 */
+	asm volatile ("mov %%fs:0x28, %0\n"
+	              "nop\n"
+	     : "+r" (old_canary)
+			 :
+			 :);
+	/*
+	 * A trick to learn nearly the value of RSP,
+	 * without resorting to ASM.
+	 */
+	canary_loc = &canary_loc;
+
+	/*
+	 * Emulate the logic for calculating a new canary value
+	 * to learn the value of the most recent canary.
+	 */
+	distance_to_first_canary=(old_canary&0xFFFF)-(((uint64_t)canary_loc)&0xFFFF);
+	canary_loc = (void*)(((uint64_t)canary_loc) + distance_to_first_canary);
+	/*
+	 * Offset is really only the last 16 bits.
+	 */
+	offset = old_canary & 0xFFFF;
+
+#ifdef DEBUG
+	print_str_debug("initial canary distance: 0x");
+	print_unsigned_long_long_debug(distance_to_first_canary);
+	print_str_debug("\n");
+	print_str_debug("fs:0x28:                 0x");
+	print_unsigned_long_long_debug(old_canary);
+	print_str_debug("\n");
+	print_str_debug("offset:                    ");
+	print_unsigned_long_long_debug(offset);
+	print_str_debug("\n");
+#endif
+	/*
+	 * The last 16 bits don't matter for
+	 * the canary value.
+	 */
+	old_canary >>= 16;
+
+	/*
+	 * Walk the canary stack and
+	 * update as we go.
+	 */
+	while ((uint64_t)canary_loc < canaries_top_of_stack) {
+#if DEBUG
+		print_str_debug("We are inside the rewriting loop.\n");
+		print_str_debug("canary_loc:");
+		print_unsigned_long_long_debug(canary_loc);
+		print_str_debug("\n");
+#endif
+/*
+		printf("*canary_loc: 0x%lx\n", *((uint64_t*)(canary_loc)));
+*/
+#if DEBUG
+		print_str_debug("Check: ");
+		print_unsigned_long_long_debug((*((uint64_t*)(canary_loc)))>>16);
+		print_str_debug(" ?= ");
+		print_unsigned_long_long_debug(old_canary);
+		print_str_debug("\n");
+#endif
+		if (((*((uint64_t*)(canary_loc))) >> 16) != old_canary) {
+			__stack_chk_fail();
+			break;
+		}
+	
+		canary_loc += *(uint64_t*)canary_loc & 0xFFFF;
+
+#if DEBUG
+		print_str_debug("canary_loc':");
+		print_unsigned_long_long_debug(canary_loc);
+		print_str_debug("\n");
+#endif
+
+		/*
+		 * TODO: Defend against nefariousness: 
+		 * 1. Attacker setting offset to 0 -> infinite loop
+		 * 2. Really deep stacks?
+		 * 3. etc?
+		 */
+	}
+	print_str_debug("successfully done rewriting all canary values.\n");
+}
+
 /*
  */
 void zipr_debug_canary_callback(unsigned long long fs0x28,
@@ -69,5 +164,6 @@ void zipr_debug_canary_callback(unsigned long long fs0x28,
 	print_str_debug("rsp    =");
 	print_unsigned_long_long_debug(rsp);
 	print_str_debug("\n");
+	verify_all_canaries();
 #endif
 }
-- 
GitLab