Skip to content
Snippets Groups Projects
Commit 817e293b authored by an7s's avatar an7s
Browse files

Data shadow / func ptr shadowing callback code

parent d018a6a3
No related branches found
No related tags found
No related merge requests found
......@@ -14,6 +14,13 @@ canaries/debug_canary_callbacks.c -text
/configure_for_rss -text
cookbook/Makefile.in -text
cookbook/instructionCountCallback.c -text
datashadow/LICENSE.txt -text
datashadow/Makefile.in -text
datashadow/catch.hpp -text
datashadow/datashadow.c -text
datashadow/datashadow.h -text
datashadow/datashadow_callbacks.c -text
datashadow/test_datashadow.cpp -text
example/Makefile.in -text
example/callback.c -text
hookdynamic/Makefile.in -text
......
The software in this directory and its subdirectories was developed
with SBIR funding and is subject to SBIR Data Rights, as detailed
below.
SBIR DATA RIGHTS
Contract No. __N00014-14-C-0197___W31P4Q-14-C-0086________.
Contractor Name __Zephyr Software LLC_____________________.
Address __2040 Tremont Road, Charlottesville, VA 22911____.
Expiration of SBIR Data Rights Period __16-JUNE-2021______.
#
# Makefile.in - DESCRIPTION.
#
# Copyright (c) 2000, 2001, 2010 - Zephyr Software
#
# This file may be used and modified for non-commercial purposes as long as
# all copyright, permission, and nonwarranty notices are preserved.
# Redistribution is prohibited without prior written consent from Zephyr
# Software.
#
# Please contact the authors for restrictions applying to commercial use.
#
# THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# Author: Zephyr Software
# e-mail: jwd@zephyr-software.com
# URL : http://www.zephyr-software.com/
#
#
CC=@CC@
CFLAGS=@CFLAGS@
LIB=@LIB@
AR=@AR@
AS=@AS@
OBJS=datashadow.o datashadow_callbacks.o
TESTS=test_datashadow.exe
.SUFFIXES: .o .c
.c.o:
$(CC) $(CFLAGS) $(INCLUDE) -c $<
ar -r $(LIB) $*.o
all: $(OBJS)
@echo data shadow build complete
test: $(TESTS)
clean:
rm -f *.o core *.exe
test_datashadow.exe: $(OBJS) test_datashadow.cpp
g++ test_datashadow.cpp $(OBJS) -o $@
This diff is collapsed.
#include "null.h"
#include "datashadow.h"
/*
* Multi-valued lookup table implementation
* to store/retrieve/lookup shadow data (addresses)
* using an index as the key value
*
* Implements per-entry lock using gcc builtins for atomic lock operations
* see lock_shadow_table(index), unlock_shadow_table(index)
*/
/* data shadow table */
static struct data_shadow_entry_manager DataShadowTable[DATA_SHADOW_TABLE_SIZE];
/* preallocate pool of data shadow entries */
static struct data_shadow_entry DataShadowEntryPool[MAX_DATA_SHADOW_ENTRIES];
static int module_initialized = 0;
// #define lock_shadow_table(X) while (__sync_lock_test_and_set(&DataShadowTable[X].locked, 1));
// #define unlock_shadow_table(X) __sync_lock_release(&DataShadowTable[X].locked);
void lock_shadow_table(int p_idx)
{
// NOP for now
// (1) start with global lock
// (2) then continue with fine-grained (per shadow index) lobal lock
}
void unlock_shadow_table(int p_idx)
{
// NOOP for now
// __sync_lock_release(&DataShadowTable[p_idx].locked);
}
void initialize_data_shadow_module()
{
int i;
if (module_initialized) return;
// initialize shadow table
for (i = 0; i < DATA_SHADOW_TABLE_SIZE; ++i)
{
DataShadowTable[i].shadow_entry = NO_SHADOW_ENTRY;
}
// initialize preallocated shadow data entries
for (i = 0; i < MAX_DATA_SHADOW_ENTRIES; ++i)
{
DataShadowEntryPool[i].val.addr = NULL;
DataShadowEntryPool[i].next_shadow_entry = NO_SHADOW_ENTRY;
}
module_initialized = 1;
}
static int get_next_free_entry()
{
static int next_free_entry = 0;
if (next_free_entry >= (MAX_DATA_SHADOW_ENTRIES - 1))
return -1;
int current_free_entry = next_free_entry;
next_free_entry++;
return current_free_entry;
}
static int find_shadow_entry(int p_idx, void *p_addr)
{
int entry = DataShadowTable[p_idx].shadow_entry;
while (entry != NO_SHADOW_ENTRY)
{
if (DataShadowEntryPool[entry].val.addr == p_addr)
{
return 1;
}
entry = DataShadowEntryPool[entry].next_shadow_entry;
}
return 0;
}
int add_shadow_entry(int p_idx, void *p_addr)
{
if (!module_initialized)
initialize_data_shadow_module();
if (p_idx < 0 || p_idx >= DATA_SHADOW_TABLE_SIZE) return 0;
lock_shadow_table(p_idx);
if (!find_shadow_entry(p_idx, p_addr))
{
int new_entry = get_next_free_entry();
DataShadowEntryPool[new_entry].val.addr = p_addr;
if (DataShadowTable[p_idx].shadow_entry == NO_SHADOW_ENTRY)
{
// completely new entry
DataShadowTable[p_idx].shadow_entry = new_entry;
DataShadowEntryPool[new_entry].next_shadow_entry = NO_SHADOW_ENTRY;
}
else
{
// insert to front
SHADOW_ENTRY_INDEX old_entry = DataShadowTable[p_idx].shadow_entry;
DataShadowTable[p_idx].shadow_entry = new_entry;
DataShadowEntryPool[new_entry].next_shadow_entry = old_entry;
}
}
unlock_shadow_table(p_idx);
return 1;
}
/*
* \param p_idx index into global shadow table
* \param p_addr address to check
* \param p_restore_addr (out) set to shadowed value
* \returns 1 if found, 0 if not found
*/
int check_shadow_value(int p_idx, void *p_addr, void **p_restore_addr, int *count)
{
int entry;
int matched = 0;
void *address_visited = NULL;
if (!module_initialized)
initialize_data_shadow_module();
lock_shadow_table(p_idx);
*p_restore_addr = NULL;
*count = 0;
// traverse all entries, find a match
entry = DataShadowTable[p_idx].shadow_entry;
while (entry != NO_SHADOW_ENTRY)
{
(*count)++;
address_visited = DataShadowEntryPool[entry].val.addr;
if (address_visited == p_addr)
{
*p_restore_addr = p_addr;
unlock_shadow_table(p_idx);
return 1;
}
entry = DataShadowEntryPool[entry].next_shadow_entry;
}
//
// if we get here, we found no matching address
// ==> <p_addr> is invalid
//
if (*count == 0)
{
// no entry in the table, this is an error
*p_restore_addr = NULL;
}
else if (*count == 1)
{
// common case: only 1 entry -- set to shadowed value
*p_restore_addr = address_visited;
}
else
{
// multiple entries -- what to do?
// for now return one of the entries
*p_restore_addr = address_visited;
}
unlock_shadow_table(p_idx);
return matched;
}
#ifndef DATA_SHADOW_H
#define DATA_SHADOW_H
#define DATA_SHADOW_TABLE_SIZE 1000
#define MAX_DATA_SHADOW_ENTRIES 2000
#define NO_SHADOW_ENTRY -1
typedef int SHADOW_ENTRY_INDEX;
typedef struct data_shadow_entry {
union {
void* addr; // right now, we just store addresses
} val;
SHADOW_ENTRY_INDEX next_shadow_entry;
} data_shadow_entry;
typedef struct data_shadow_entry_manager {
SHADOW_ENTRY_INDEX shadow_entry;
} data_shadow_entry_manager;
extern void initialize_data_shadow_module();
extern int add_shadow_entry(int p_idx, void *p_addr);
extern int check_shadow_value(int p_idx, void *p_addr, void **p_restore_addr, int *);
#endif
/*
* Function pointer shadowing
*/
#ifdef STRATA
#include "all.h"
#include "../insn.h"
// possible policies expressed as strings passed on the strata command line
#define DETECTOR_POLICY_EXIT_STRING "exit"
#define DETECTOR_POLICY_CONTINUE_STRING "continue"
static char strata_detector_policy_str[128]; // "exit" or "continue"
// specifies policy when detector triggers
static int strata_detector_policy = P_CONTROLLED_EXIT;
__attribute__ ((externally_visible)) __attribute((used)) void fptr_shadow_define_64(void *p_retAddress, reg_values_t *p_rv, void *p_instrumented, int p_shadowIndex, void *p_shadowValue);
__attribute__ ((externally_visible)) __attribute((used)) void fptr_shadow_check_64(void *p_retAddress, reg_values_t *p_rv, void *p_instrumented, int p_shadowIndex, void **p_shadowValue);
#endif
//
// When writing a callback handler/detector
//
// argument #1 : return address
// argument #2 : register data structure
// argument #3..#6: optional set of args specific to the callback handler
//
#define MAX_DIAGNOSTIC_SIZE 1024
// put this in a include somewher
typedef struct
{
int edi;
int esi;
int ebp;
int esp_dummy;
int ebx;
int edx;
int ecx;
int eax;
int flags;
} reg_values_t;
#ifdef STRATA
// leave this function so that the linker includes this file
void data_shadow_init()
{
}
static void getDiagnostics(char *p_diagnostic, int p_shadowIndex, void* p_shadow, char *p_msg)
{
strata_sprintf(p_msg, "diagnosis:%s shadowid:%d shadowval:0x%p",
p_diagnostic,
p_shadowIndex,
p_shadow);
}
#endif
// void signedness_detector_signed(void *p_retAddress, reg_values_t *p_rv, void* p_addressTruncated, volatile long int p_policy)
// shadowMap[p_shadowIndex] = p_shadowValue
// add to multi-valued table
void fptr_shadow_define_64(void *p_retAddress, reg_values_t *p_rv, void *p_instrumented, int p_shadowIndex, void *p_shadowValue)
{
char msg[MAX_DIAGNOSTIC_SIZE];
add_shadow_entry(p_shadowIndex, p_shadowValue);
#ifdef STRATA
strata_sprintf(msg,"FPTRSHADOW:DEFINE shadowid[%d] shadowvalue[0x%p]", p_shadowIndex, p_shadowValue);
detected_error(CWE_NONE, CWE_NONE, E_FPTR_OVERWRITE, msg, D_BUFFER, P_CONTINUE_EXECUTION);
#endif
}
// check to make sure values match
void fptr_shadow_check_64(void *p_retAddress, reg_values_t *p_rv, void *p_instrumented, int p_shadowIndex, void **p_shadow)
{
char msg[MAX_DIAGNOSTIC_SIZE];
void *restored;
int count = 0;
/*
sprintf(msg, "FPTRCHECK:ENTER shadowid[%d] value[0x%p]", p_shadowIndex, *p_shadow);
detected_error(CWE_NONE, CWE_NONE, E_FPTR_OVERWRITE, msg, D_BUFFER, P_CONTINUE_EXECUTION);
*/
int success = check_shadow_value(p_shadowIndex, *p_shadow, &restored, &count);
if (!success) {
// oh oh, need to restore
#ifdef STRATA
strata_sprintf(msg,"FPTRCHECK:RESTORE shadowid[%d] value[0x%p] restored[0x%p] #[%d]", p_shadowIndex, *p_shadow, restored, count);
#endif
*p_shadow = restored;
#ifdef STRATA
detected_error(CWE_NONE, CWE_NONE, E_FPTR_OVERWRITE, msg, D_BUFFER, P_CONTINUE_EXECUTION);
#endif
}
else
{
#ifdef STRATA
strata_sprintf(msg,"FPTRCHECK:OK shadowid[%d] value[0x%p] shadow[0x%p] #[%d]", p_shadowIndex, *p_shadow, restored, count);
detected_error(CWE_NONE, CWE_NONE, E_FPTR_OVERWRITE, msg, D_BUFFER, P_CONTINUE_EXECUTION);
#endif
}
}
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
extern "C" {
#include "datashadow.h"
}
TEST_CASE("Test edge/error cases", "[datashadow]" ) {
// this setup code is shared across sections w/in the test case
initialize_data_shadow_module();
SECTION("Test out-of-bounds shadow access") {
REQUIRE ( add_shadow_entry(-5, 0L)==0 );
REQUIRE ( add_shadow_entry(5000000, 0L)==0 );
}
SECTION("Test non-existent entry") {
void *restored = NULL;
int count = 0;
REQUIRE ( check_shadow_value(5, (void*)0x12345678L, &restored, &count) == 0 );
}
}
TEST_CASE( "Test normal operations", "[datashadow]" ) {
void *restored = NULL;
int count = 0;
initialize_data_shadow_module();
SECTION( "Test single shadow entry") {
void *address = (void*) 0x12345678L;
REQUIRE ( add_shadow_entry(0, address) == 1 );
REQUIRE ( check_shadow_value(0, address, &restored, &count) == 1 );
REQUIRE ( restored == address );
}
SECTION( "Test multiple shadow entries") {
void *address1 = (void*) 0x12345678L;
void *address2 = (void*) 0x11111111L;
void *address3 = (void*) 0x22222222L;
void *bogus_address = (void*) 0xaabbccdd;
add_shadow_entry(2, address1);
add_shadow_entry(2, address2);
add_shadow_entry(2, address3);
REQUIRE ( check_shadow_value(2, address1, &restored, &count) == 1 );
REQUIRE ( restored == address1 );
REQUIRE ( check_shadow_value(2, address2, &restored, &count) == 1 );
REQUIRE ( restored == address2 );
REQUIRE ( check_shadow_value(2, address3, &restored, &count) == 1 );
REQUIRE ( restored == address3 );
REQUIRE ( check_shadow_value(2, bogus_address, &restored, &count) == 0);
REQUIRE ( (restored == address1 || restored == address2 || restored == address3) );
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment