blob: 272ca00e79a2999a69960700e56cf7ff522be6c6 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2005-2006 VMware, Inc. All rights reserved.
* **********************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/* DR core / shared library interface unit tests */
/* executed as part of the unit tests for processes.c */
/* need to have a core build anyway for these tests to work */
#include "win32/events.h"
/* nudge tends to hang/timeout if you nudge right after the
* process starts. so in order to let the basic tests pass,
* they all sleep for at least this long before trying to
* nudge.
* of course this should be fixed and then we should create
* stress tests to address this specifically. */
#define NUDGE_LET_PROCESS_START_WAIT 500
#define TEST_TIMEOUT 2000
#define LAUNCH_TIMEOUT 1000
#define WAIT_FOR_APP(hProc) \
DO_ASSERT(WAIT_OBJECT_0 == WaitForSingleObject(hProc, TEST_TIMEOUT * 2))
#define LONG_WAIT_FOR_APP(hProc) \
DO_ASSERT(WAIT_OBJECT_0 == WaitForSingleObject(hProc, TEST_TIMEOUT * 20))
#define DO_TEST(name, appstr, block) DO_TEST_HP(name, appstr, TRUE, block)
#define TESTER_1_BLOCK \
"BEGIN_BLOCK\n" \
"APP_NAME=tester_1.exe\n" \
"DYNAMORIO_OPTIONS=-kill_thread -kill_thread_max 1000 -report_max 0 -dumpcore_mask " \
"0xff\n" \
"END_BLOCK\n"
#define TESTER_2_BLOCK \
"BEGIN_BLOCK\n" \
"APP_NAME=tester_2.exe\n" \
"DYNAMORIO_OPTIONS=-dumpcore_mask 0xff\n" \
"END_BLOCK\n"
#define TESTER_1_HOT_PATCH_BLOCK \
"BEGIN_BLOCK\n" \
"APP_NAME=tester_1.exe\n" \
"DYNAMORIO_OPTIONS=-kill_thread -dumpcore_mask 0xff\n" \
"DYNAMORIO_HOT_PATCH_MODES=\\conf\\test-modes.cfg\n" \
"BEGIN_MP_MODES\n" \
"1\n" \
"TEST.000A:2\n" \
"END_MP_MODES\n" \
"END_BLOCK\n"
#define TESTER_1_HOT_PATCH_DETECT_BLOCK \
"BEGIN_BLOCK\n" \
"APP_NAME=tester_1.exe\n" \
"DYNAMORIO_OPTIONS=-kill_thread -dumpcore_mask 0xff\n" \
"DYNAMORIO_HOT_PATCH_MODES=\\conf\\test-modes.cfg\n" \
"BEGIN_MP_MODES\n" \
"1\n" \
"TEST.000A:1\n" \
"END_MP_MODES\n" \
"END_BLOCK\n"
/* simple detach */
DO_TEST(detach, TESTER_1_BLOCK, {
UINT pid;
LAUNCH_APP(L"tester_1.exe 5000", &pid);
/* FIXME: if this isn't here, the first run (right after
* building the tests) always fails. */
Sleep(LAUNCH_TIMEOUT * 2);
VERIFY_UNDER_DR(pid);
CHECKED_OPERATION(detach(pid, TRUE, DETACH_RECOMMENDED_TIMEOUT));
VERIFY_NOT_UNDER_DR(pid);
TERMINATE_PROCESS(pid);
});
/* pending restart */
DO_TEST(pending_restart, TESTER_1_BLOCK, {
UINT pid;
LAUNCH_APP(L"tester_1.exe 5000", &pid);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
CHECKED_OPERATION(detach(pid, TRUE, DETACH_RECOMMENDED_TIMEOUT));
VERIFY_NOT_UNDER_DR(pid);
DO_ASSERT(is_process_pending_restart(pid));
DO_ASSERT(is_any_process_pending_restart());
TERMINATE_PROCESS(pid);
});
/* detach_exe */
DO_TEST(detach_exe, TESTER_1_BLOCK TESTER_2_BLOCK, {
UINT pid1;
UINT pid2;
UINT pid3;
LAUNCH_APP(L"tester_1.exe", &pid1);
LAUNCH_APP(L"tester_2.exe", &pid2);
LAUNCH_APP(L"tester_1.exe", &pid3);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid1);
VERIFY_UNDER_DR(pid2);
VERIFY_UNDER_DR(pid3);
CHECKED_OPERATION(detach_exe(L"tester_1.exe", DETACH_RECOMMENDED_TIMEOUT));
VERIFY_NOT_UNDER_DR(pid1);
VERIFY_UNDER_DR(pid2);
VERIFY_NOT_UNDER_DR(pid3);
DO_ASSERT(is_process_pending_restart(pid1));
DO_ASSERT(!is_process_pending_restart(pid2));
DO_ASSERT(is_any_process_pending_restart());
TERMINATE_PROCESS(pid1);
TERMINATE_PROCESS(pid2);
TERMINATE_PROCESS(pid3);
});
/* detach_all */
DO_TEST(detach_all, TESTER_1_BLOCK TESTER_2_BLOCK, {
UINT pid1;
UINT pid2;
UINT pid3;
LAUNCH_APP(L"tester_1.exe", &pid1);
LAUNCH_APP(L"tester_2.exe", &pid2);
LAUNCH_APP(L"tester_1.exe", &pid3);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid1);
VERIFY_UNDER_DR(pid2);
VERIFY_UNDER_DR(pid3);
CHECKED_OPERATION(detach_all(DETACH_RECOMMENDED_TIMEOUT));
VERIFY_NOT_UNDER_DR(pid1);
VERIFY_NOT_UNDER_DR(pid2);
VERIFY_NOT_UNDER_DR(pid3);
DO_ASSERT(is_process_pending_restart(pid1));
DO_ASSERT(is_any_process_pending_restart());
TERMINATE_PROCESS(pid1);
TERMINATE_PROCESS(pid2);
TERMINATE_PROCESS(pid3);
});
/* consistency_detach */
DO_TEST(consistency_detach, TESTER_1_BLOCK TESTER_2_BLOCK, {
UINT pid1;
UINT pid2;
UINT pid3;
LAUNCH_APP(L"tester_1.exe", &pid1);
LAUNCH_APP(L"tester_2.exe", &pid2);
LAUNCH_APP(L"tester_1.exe", &pid3);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid1);
VERIFY_UNDER_DR(pid2);
VERIFY_UNDER_DR(pid3);
CHECKED_OPERATION(load_test_config(TESTER_2_BLOCK, FALSE));
CHECKED_OPERATION(consistency_detach(DETACH_RECOMMENDED_TIMEOUT));
VERIFY_NOT_UNDER_DR(pid1);
VERIFY_UNDER_DR(pid2);
VERIFY_NOT_UNDER_DR(pid3);
TERMINATE_PROCESS(pid1);
TERMINATE_PROCESS(pid2);
TERMINATE_PROCESS(pid3);
});
/* check start/stop events */
DO_TEST(start_stop_event, TESTER_1_BLOCK, {
UINT pid;
HANDLE hProc;
LAUNCH_APP_HANDLE(L"tester_1.exe 10", &pid, &hProc);
WAIT_FOR_APP(hProc);
DO_ASSERT(
check_for_event(MSG_INFO_PROCESS_START, L"tester_1.exe", pid, NULL, NULL, 0));
DO_ASSERT(
check_for_event(MSG_INFO_PROCESS_STOP, L"tester_1.exe", pid, NULL, NULL, 0));
});
/* check detach event */
DO_TEST(detach_event, TESTER_1_BLOCK, {
UINT pid;
LAUNCH_APP(L"tester_1.exe 2000", &pid);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
CHECKED_OPERATION(detach(pid, TRUE, DETACH_RECOMMENDED_TIMEOUT));
VERIFY_NOT_UNDER_DR(pid);
Sleep(100);
DO_ASSERT(
check_for_event(MSG_INFO_PROCESS_START, L"tester_1.exe", pid, NULL, NULL, 0));
DO_ASSERT(check_for_event(MSG_INFO_DETACHING, L"tester_1.exe", pid, NULL, NULL, 0));
TERMINATE_PROCESS(pid);
});
/* check attack event */
DO_TEST(attack_event, TESTER_1_BLOCK, {
UINT pid;
HANDLE hProc;
WCHAR s3[MAX_PATH];
WCHAR s4[MAX_PATH];
LAUNCH_APP_HANDLE(L"tester_1.exe 10 10 1", &pid, &hProc);
WAIT_FOR_APP(hProc);
DO_ASSERT(check_for_event(MSG_SEC_VIOLATION_THREAD, L"tester_1.exe", pid, s3, s4,
MAX_PATH));
/* make sure threat id looks ok */
DO_ASSERT(11 == wcslen(s3));
});
/* check forensics event/file */
DO_TEST(forensics_file, TESTER_1_BLOCK, {
UINT pid;
HANDLE hProc;
WCHAR s3[MAX_PATH];
WCHAR s4[MAX_PATH];
LAUNCH_APP_HANDLE(L"tester_1.exe 10 10 1", &pid, &hProc);
WAIT_FOR_APP(hProc);
DO_ASSERT(
check_for_event(MSG_SEC_VIOLATION_THREAD, L"tester_1.exe", pid, NULL, NULL, 0));
DO_ASSERT(check_for_event(MSG_SEC_FORENSICS, L"tester_1.exe", pid, s3, s4, MAX_PATH));
DO_ASSERT(file_exists(s3));
});
/* stress forensics event/file */
DO_TEST(forensics_stress, TESTER_1_BLOCK, {
UINT pid;
HANDLE hProc;
WCHAR s3[MAX_PATH];
WCHAR s4[MAX_PATH];
int i;
LAUNCH_APP_HANDLE(L"tester_1.exe 10 10 0 100", &pid, &hProc);
LONG_WAIT_FOR_APP(hProc);
for (i = 0; i < 100; i++) {
DO_ASSERT(check_for_event(MSG_SEC_VIOLATION_THREAD, L"tester_1.exe", pid, NULL,
NULL, 0));
DO_ASSERT(
check_for_event(MSG_SEC_FORENSICS, L"tester_1.exe", pid, s3, s4, MAX_PATH));
DO_ASSERT(file_exists(s3));
}
DO_ASSERT(
check_for_event(MSG_INFO_PROCESS_STOP, L"tester_1.exe", pid, NULL, NULL, 0));
});
/* check to make sure nudge doesn't leave the code lying around */
DO_TEST(check_nudge, TESTER_1_BLOCK, {
UINT pid;
WCHAR nudge_code_buf[MAX_PATH];
LAUNCH_APP(L"tester_1.exe", &pid);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
Sleep(NUDGE_LET_PROCESS_START_WAIT);
CHECKED_OPERATION(hotp_notify_modes_update(pid, TRUE, TEST_TIMEOUT));
DO_ASSERT(ERROR_SUCCESS !=
get_config_parameter(L_PRODUCT_NAME, FALSE, L_DYNAMORIO_VAR_NUDGE,
nudge_code_buf, MAX_PATH));
TERMINATE_PROCESS(pid);
});
/* simple test for hotpatching */
DO_TEST(hotp_protect, TESTER_1_HOT_PATCH_BLOCK, {
UINT pid;
char fc[MAX_PATH];
LAUNCH_APP_AND_WAIT(L"tester_1.exe 100", &pid);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "10", 2));
});
/* detect should report 00 */
DO_TEST(hotp_detect, TESTER_1_HOT_PATCH_DETECT_BLOCK, {
UINT pid;
char fc[MAX_PATH];
LAUNCH_APP_AND_WAIT(L"tester_1.exe 100", &pid);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "00", 2));
});
/* basic nudge test */
DO_TEST_HP(hotp_defs_nudge, TESTER_1_BLOCK, FALSE, /* don't load the modes file! */
{
UINT pid;
char fc[MAX_PATH];
HANDLE hProc;
hotp_policy_status_table_t *status_table = NULL;
/* first launch app w/o hotpatch */
LAUNCH_APP_AND_WAIT(L"tester_1.exe 10", &pid);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "00", 2));
/* now, same thing with longer wait */
LAUNCH_APP_HANDLE(L"tester_1.exe 2000", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
/* make sure nothing's there */
DO_ASSERT(ERROR_DRMARKER_ERROR == get_hotp_status(pid, &status_table));
/* load the new config -- this time with hot patching*/
CHECKED_OPERATION(load_test_config(TESTER_1_HOT_PATCH_BLOCK, TRUE));
/* and nudge */
Sleep(NUDGE_LET_PROCESS_START_WAIT);
CHECKED_OPERATION(hotp_notify_defs_update(pid, TRUE, TEST_TIMEOUT));
VERIFY_UNDER_DR(pid);
WAIT_FOR_APP(hProc);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "10", 2));
});
DO_TEST(hotp_modes_nudge, TESTER_1_HOT_PATCH_BLOCK, {
UINT pid;
char fc[MAX_PATH];
HANDLE hProc;
/* first launch app w/hotpatch protect */
LAUNCH_APP_AND_WAIT(L"tester_1.exe 10", &pid);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "10", 2));
/* now, same thing with longer wait */
LAUNCH_APP_HANDLE(L"tester_1.exe 2000", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
/* load the new config */
CHECKED_OPERATION(load_test_config(TESTER_1_HOT_PATCH_DETECT_BLOCK, TRUE));
/* and do a modes nudge */
Sleep(NUDGE_LET_PROCESS_START_WAIT);
CHECKED_OPERATION(hotp_notify_modes_update(pid, TRUE, TEST_TIMEOUT));
VERIFY_UNDER_DR(pid);
WAIT_FOR_APP(hProc);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "00", 2));
});
/* nudge twice to make sure we don't die */
DO_TEST_HP(hotp_nudge_twice, TESTER_1_BLOCK, FALSE, {
UINT pid;
char fc[MAX_PATH];
HANDLE hProc;
/* first launch app w/o hotpatch */
LAUNCH_APP_AND_WAIT(L"tester_1.exe 10", &pid);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "00", 2));
LAUNCH_APP_HANDLE(L"tester_1.exe 2000", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
/* load the new config */
CHECKED_OPERATION(load_test_config(TESTER_1_HOT_PATCH_BLOCK, TRUE));
Sleep(NUDGE_LET_PROCESS_START_WAIT);
CHECKED_OPERATION(hotp_notify_defs_update(pid, TRUE, TEST_TIMEOUT));
VERIFY_UNDER_DR(pid);
/* load the old config back */
CHECKED_OPERATION(load_test_config(TESTER_1_HOT_PATCH_DETECT_BLOCK, TRUE));
CHECKED_OPERATION(hotp_notify_defs_update(pid, TRUE, TEST_TIMEOUT));
VERIFY_UNDER_DR(pid);
WAIT_FOR_APP(hProc);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "00", 2));
});
/* tests state of the patches */
DO_TEST(hotp_protect_status, TESTER_1_HOT_PATCH_BLOCK, {
UINT pid;
HANDLE hProc;
hotp_policy_status_table_t *status_table = NULL;
LAUNCH_APP_HANDLE(L"tester_1.exe 10 2500", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
Sleep(500);
CHECKED_OPERATION(get_hotp_status(pid, &status_table));
DO_ASSERT(status_table != NULL && status_table->num_policies > 0);
if (status_table != NULL && status_table->num_policies > 0) {
UINT j;
for (j = 0; j < status_table->num_policies; j++) {
if (0 ==
strcmp(status_table->policy_status_array[j].policy_id, "TEST.000A") ||
0 ==
strcmp(status_table->policy_status_array[j].policy_id, "TEST.000B")) {
DO_ASSERT(status_table->policy_status_array[j].inject_status ==
HOTP_INJECT_PROTECT);
}
}
free_hotp_status_table(status_table);
}
WAIT_FOR_APP(hProc);
});
/* tests state of the patches */
DO_TEST(hotp_pending_status, TESTER_1_HOT_PATCH_BLOCK, {
UINT pid;
HANDLE hProc;
hotp_policy_status_table_t *status_table = NULL;
LAUNCH_APP_HANDLE(L"tester_1.exe 2500", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
Sleep(200);
CHECKED_OPERATION(get_hotp_status(pid, &status_table));
DO_ASSERT(status_table != NULL && status_table->num_policies > 0);
if (status_table != NULL && status_table->num_policies > 0) {
UINT j;
for (j = 0; j < status_table->num_policies; j++) {
if (0 ==
strcmp(status_table->policy_status_array[j].policy_id, "TEST.000A") ||
0 ==
strcmp(status_table->policy_status_array[j].policy_id, "TEST.000B")) {
DO_ASSERT(status_table->policy_status_array[j].inject_status ==
HOTP_INJECT_PENDING);
}
}
free_hotp_status_table(status_table);
}
WAIT_FOR_APP(hProc);
});
/* sanity check to make sure we have different state */
DO_TEST(hotp_detect_status, TESTER_1_HOT_PATCH_DETECT_BLOCK, {
UINT pid;
HANDLE hProc;
hotp_policy_status_table_t *status_table = NULL;
LAUNCH_APP_HANDLE(L"tester_1.exe 10 2500", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
Sleep(500);
CHECKED_OPERATION(get_hotp_status(pid, &status_table));
DO_ASSERT(status_table != NULL && status_table->num_policies > 0);
if (status_table != NULL && status_table->num_policies > 0) {
UINT j;
for (j = 0; j < status_table->num_policies; j++) {
if (0 ==
strcmp(status_table->policy_status_array[j].policy_id, "TEST.000A") ||
0 ==
strcmp(status_table->policy_status_array[j].policy_id, "TEST.000B")) {
DO_ASSERT(status_table->policy_status_array[j].inject_status ==
HOTP_INJECT_DETECT);
}
}
free_hotp_status_table(status_table);
}
WAIT_FOR_APP(hProc);
});
DO_TEST(hotp_modes_nudge_all, TESTER_1_HOT_PATCH_BLOCK, {
UINT pid;
char fc[MAX_PATH];
HANDLE hProc;
/* first launch app w/hotpatch protect */
LAUNCH_APP_AND_WAIT(L"tester_1.exe 10", &pid);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "10", 2));
/* now, same thing with longer wait */
LAUNCH_APP_HANDLE(L"tester_1.exe 2000", &pid, &hProc);
Sleep(LAUNCH_TIMEOUT);
VERIFY_UNDER_DR(pid);
/* load the new config */
CHECKED_OPERATION(load_test_config(TESTER_1_HOT_PATCH_DETECT_BLOCK, TRUE));
/* and do a modes nudge */
Sleep(NUDGE_LET_PROCESS_START_WAIT);
CHECKED_OPERATION(hotp_notify_all_modes_update(TEST_TIMEOUT));
VERIFY_UNDER_DR(pid);
WAIT_FOR_APP(hProc);
CHECKED_OPERATION(read_file_contents(L"tester.out", fc, MAX_PATH, NULL));
DO_ASSERT(0 == strncmp(fc, "00", 2));
});