blob: 4984bd90c3af69b5e9f907118d389306e6ccbc09 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2005-2010 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.
*/
#ifndef _DETERMINA_SHAREUTILS_H_
#define _DETERMINA_SHAREUTILS_H_
#include "share.h"
#include "lib/dr_config.h"
#include "our_tchar.h"
#ifdef WINDOWS
# include "config.h"
#endif
#ifdef DEBUG
# include <stdio.h>
#endif
#if defined(WINDOWS) && defined(_DEBUG)
# include <crtdbg.h>
#endif
#ifdef __cplusplus
extern "C"{
#endif
const TCHAR *
get_dynamorio_home(void);
const TCHAR *
get_dynamorio_logdir(void);
bool
file_exists(const TCHAR *fn);
void
set_dr_platform(dr_platform_t platform);
/* return DR_PLATFORM_32BIT or DR_PLATFORM_64BIT */
dr_platform_t
get_dr_platform(void);
/* XXX: Rest are unported. */
#ifdef WINDOWS
void
wcstolower(WCHAR *str);
WCHAR *
get_exename_from_path(const WCHAR *path);
BOOL
get_commandline_qualifier(const WCHAR* command_line,
WCHAR* derived_name,
UINT max_derived_length /* in elements */,
BOOL no_strip);
DWORD
acquire_shutdown_privilege();
DWORD
reboot_system();
/* grokked from the core.
* FIXME: shareme!
* if NULL is passed for directory, then it is ignored and no directory
* check is done, and filename_base is assumed to be absolute.
* TODO: make this a proactive check: make sure the file can be
* opened, eg, do a create/delete on the filename to be returned.
*/
BOOL
get_unique_filename(const WCHAR* directory,
const WCHAR* filename_base,
const WCHAR* file_type,
WCHAR* filename_buffer,
UINT maxlen);
DWORD
delete_file_rename_in_use(WCHAR *filename);
DWORD
delete_file_on_boot(WCHAR *filename);
DWORD
delete_tree(const WCHAR *path);
DWORD
copy_file_permissions(WCHAR *filedst, WCHAR *filesrc);
DWORD
get_platform(DWORD *platform);
BOOL
is_wow64(HANDLE hProcess);
BOOL
using_system32_for_preinject(const WCHAR *preinject);
DWORD
get_preinject_path(WCHAR *buf, int nchars, BOOL force_local_path, BOOL short_path);
DWORD
get_preinject_name(WCHAR *buf, int nchars);
/* PR 244206: these flags should be used for all Reg{Create,Open,Delete}KeyEx calls
* for HKLM\Software keys
*/
DWORD
platform_key_flags();
/* PR 244206: use this instead of RegDeleteKey for HKLM\Software keys */
DWORD
delete_product_key(HKEY hkey, LPCWSTR subkey);
DWORD
create_root_key();
DWORD
destroy_root_key();
/* note that this checks the opstring against the
* version of core that matches this build, NOT the version
* of the core that's actually installed! */
BOOL
check_opstring(const WCHAR *opstring);
/* acquires the privileges necessary to perform tasks like detach,
* nudge, etc. */
DWORD
acquire_privileges();
/* said privileges should always be released after usage */
DWORD
release_privileges();
void
ensure_directory_exists_for_file(WCHAR *filename);
void
mkdir_with_parents(const WCHAR *dirname);
DWORD
write_file_contents(WCHAR *path, char *contents, BOOL overwrite);
DWORD
write_file_contents_if_different(WCHAR *path, char *contents, BOOL *changed);
DWORD
read_file_contents(WCHAR *path, char *contents,
SIZE_T maxchars, SIZE_T *needed);
DWORD
setup_installation(const WCHAR *path, BOOL overwrite);
DWORD
setup_cache_shared_directories(const WCHAR *cache_root);
DWORD
setup_cache_shared_registry(const WCHAR *cache_root,
ConfigGroup *policy);
DWORD
set_registry_permissions_for_user(WCHAR *hklm_keyname, WCHAR *user);
/* used by get_violation_info() */
typedef struct _VIOLATION_INFO {
DWORD flags; /* IN, NYI */
const WCHAR *report; /* OUT, Filename of generated report file. NULL if error.*/
WCHAR buf[MAX_PATH]; /* space for filename */
} VIOLATION_INFO;
/* Takes in a MSG_SEC_FORENSICS event log record pevlr and generates a report file
* (info->report) as specified by the flags field in info. On success returns
* ERROR_SUCCESS, else returns a failure code. */
DWORD
get_violation_info(EVENTLOGRECORD *pevlr, /* INOUT */ VIOLATION_INFO *info);
/* The final canary code is (FAIL_CODE << 16) | (TEST_TYPE && 0xffff) */
#define CANARY_UNABLE_TO_TEST 1
#define CANARY_SUCCESS 0
#define CANARY_FAIL_HUNG -1
#define CANARY_FAIL_CRASH -2
#define CANARY_FAIL_VIOLATION -3
#define CANARY_FAIL_DR_ERROR -4
#define CANARY_FAIL_APP_INIT_INJECTION -5
#define CANARY_FAIL_EARLY_INJECTION -6
/* future error codes */
#define CANARY_TEST_TYPE_NATIVE 1
#define CANARY_TEST_TYPE_THIN_CLIENT 2
#define CANARY_TEST_TYPE_CLIENT 3
#define CANARY_TEST_TYPE_MF 4
/* future types */
#define GET_CANARY_CODE(test_type, fail_code) ((fail_code << 16) | (test_type && 0xffff))
#define CANARY_RUN_NO_REQUIRE_PASS(run) (run|(run << 16))
#define CANARY_RUN_REQUIRES_PASS(run, flags) (((flags >> 16) & run) == 0)
#define CANARY_RUN_NATIVE 0x0001
#define CANARY_RUN_THIN_CLIENT_INJECT 0x0002
#define CANARY_RUN_THIN_CLIENT 0x0004
#define CANARY_RUN_CLIENT 0x0008
#define CANARY_RUN_MF 0x0010
#define CANARY_RUN_FLAGS_DEFAULT \
(CANARY_RUN_NATIVE | CANARY_RUN_THIN_CLIENT_INJECT | CANARY_RUN_THIN_CLIENT | \
CANARY_RUN_CLIENT | CANARY_RUN_NO_REQUIRE_PASS(CANARY_RUN_MF))
/* NYI */
#define CANARY_INFO_FLAGS_DEFAULT 0
#define CANARY_URL_SIZE 20 /* NYI so arbitrary */
#define CANARY_MESSAGE_SIZE 1024 /* NYI so arbitrary */
typedef struct _CANARY_INFO {
DWORD run_flags; /* tests to run */
DWORD info_flags; /* info to gather, NYI */
int canary_code; /* canary return code, like an NTSTATUS */
const WCHAR *report; /* OUT, filename of generated report file */
const WCHAR *url; /* OUT, url string to use for querying determina */
const WCHAR *msg; /* OUT, msg to display to user */
WCHAR buf_report[MAX_PATH]; /* space for report filename */
WCHAR buf_url[CANARY_URL_SIZE]; /* space for url */
WCHAR buf_message[CANARY_MESSAGE_SIZE]; /* space for use message */
/* Used by DRcontrol to inject faults, FIXME get rid of these and the flags and
* go to a more data driven model. Other users should set fault_run to 0. */
DWORD fault_run;
WCHAR *canary_fault_args;
} CANARY_INFO;
/* NOTE - arbitrary value, but shouldn't be -1 (core kill_proc value) or overlapping
* an NTSTATUS (such as ACCESS_DENIED etc.). */
#define CANARY_PROCESS_EXP_EXIT_CODE 0
/* Returns TRUE if the canary tests succeeded and protection should be enabled. Returns
* FALSE if one of the canary tests failed and therefore protection should not be
* enabled. Flags fields of info are used to specify which tests to run and what
* information to gather, other fields are used to return additional information
* to the caller. */
BOOL
run_canary_test(/* INOUT */ CANARY_INFO *info, WCHAR *version_msg);
/* Like run_canary_test(), except takes in as args what run_canary_test() implicitly
* finds via the registry for greater customization. */
BOOL
run_canary_test_ex(FILE *file, /* INOUT */ CANARY_INFO *info,
const WCHAR *scratch_folder, const WCHAR *canary_process);
#endif /* WINDOWS */
# ifdef DEBUG
extern int debuglevel;
extern int abortlevel;
void
set_debuglevel(int level);
void
set_debugfile(FILE *fp);
void
set_abortlevel(int level);
# define DL_FATAL 0
# define DL_ERROR 2
# define DL_WARN 4
# define DL_INFO 6
# define DL_VERB 8
# define DL_FINEST 10
# ifdef WINDOWS
# pragma warning(disable : 4127)
# endif
# ifndef EXIT_ON_ASSERT
# define EXIT_ON_ASSERT true
# endif
# ifndef ASSERTION_EXPRESSION
# ifdef _DEBUG
# define ASSERTION_EXPRESSION(msg) _ASSERTE(0)
# else
# define ASSERTION_EXPRESSION(msg)
# endif
# endif
# define DO_ASSERT_EXPR(msg, expr, handle, handler) { \
if ( ! (expr) ) { \
char ___buf[MAXIMUM_PATH]; \
_snprintf(___buf, MAXIMUM_PATH, "%s:%d [%s]", \
__FILE__, __LINE__, msg); \
if (handle) { \
handler \
} \
else if (EXIT_ON_ASSERT) { \
fprintf(stderr, "ASSERT: %s\n", ___buf); \
fflush(stderr); \
exit(-1); \
} \
else { \
ASSERTION_EXPRESSION(msg); \
} \
} \
}
# define NULL_HANDLER ;
# define DO_ASSERT(expr) DO_ASSERT_EXPR(#expr, expr, 0, NULL_HANDLER)
# define DO_ASSERT_HANDLE(expr, handler) DO_ASSERT_EXPR(#expr, expr, 1, handler)
# define DO_DEBUG(l,expr) { \
if ( (l) <= debuglevel ) { \
expr \
} \
if ( (l) <= abortlevel ) { \
DO_ASSERT_EXPR("DEBUG failure", 0, 0, NULL_HANDLER); \
} \
fflush(stdout); \
fflush(stderr); \
}
# define DO_ASSERT_WSTR_EQ(s1, s2) \
DO_ASSERT(s1 != NULL); \
DO_ASSERT(s2 != NULL); \
DO_ASSERT(0 == wcscmp(s1, s2))
# define DO_ASSERT_STR_EQ(s1, s2) \
DO_ASSERT(s1 != NULL); \
DO_ASSERT(s2 != NULL); \
if (s1 != NULL && s2 != NULL) { DO_ASSERT(0 == strcmp(s1, s2)); }
# define CHECKED_OPERATION(expr) { \
DWORD res = expr; \
if (res != ERROR_SUCCESS) \
printf("res=%d\n", res); \
DO_ASSERT(res == ERROR_SUCCESS); \
}
#define LAUNCH_APP_WAIT_HANDLE(relpath, pidvar, wait, handle) { \
STARTUPINFO si = { 0 }; \
PROCESS_INFORMATION pi = { 0 }; \
WCHAR cmdl[MAX_PATH]; \
_snwprintf(cmdl, MAX_PATH, L"%s", relpath); \
DO_ASSERT(CreateProcess(NULL, \
cmdl, \
NULL, NULL, FALSE, \
0, \
NULL, \
NULL, \
&si, &pi)); \
*pidvar = pi.dwProcessId; \
DO_DEBUG(DL_VERB, \
printf("Launched %d=%S\n", *pidvar, cmdl); \
); \
if (wait) { \
DWORD waitres = WaitForSingleObject(pi.hProcess, 5000); \
DO_ASSERT(waitres == WAIT_OBJECT_0); \
} \
else { \
Sleep(100); \
} \
if (handle == NULL) { \
CloseHandle(pi.hThread); \
CloseHandle(pi.hProcess); \
} \
else { \
*handle = pi.hProcess; \
} \
}
#define LAUNCH_APP_HANDLE(relpath, pidvar, handle) LAUNCH_APP_WAIT_HANDLE(relpath, pidvar, FALSE, handle)
#define LAUNCH_APP_WAIT(relpath, pidvar, wait) LAUNCH_APP_WAIT_HANDLE(relpath, pidvar, wait, dummy)
#define LAUNCH_APP(relpath, pidvar) LAUNCH_APP_WAIT(relpath, pidvar, FALSE)
#define LAUNCH_APP_AND_WAIT(relpath, pidvar) LAUNCH_APP_WAIT(relpath, pidvar, TRUE)
# define TERMINATE_PROCESS(pid) { \
DO_DEBUG(DL_VERB, \
printf("terminating %d\n", pid); \
); \
terminate_process(pid); \
Sleep(100); \
}
# define VERIFY_UNDER_DR(pid) { \
int stat = under_dynamorio(pid); \
DO_ASSERT(stat != DLL_NONE && stat != DLL_UNKNOWN); \
}
# define VERIFY_NOT_UNDER_DR(pid) { \
int stat = under_dynamorio(pid); \
DO_ASSERT(stat == DLL_NONE); \
}
# ifdef WINDOWS
DWORD
load_test_config(const char *snippet, BOOL use_hotpatch_defs);
void
get_testdir(WCHAR *buf, UINT maxchars);
/* quick helpers for unit tests */
BOOL
check_for_event(DWORD type, WCHAR *exename, ULONG pid,
WCHAR *s3, WCHAR *s4, UINT maxchars);
void
reset_last_event();
void
show_all_events();
# endif
# else //#ifdef DEBUG
# define DO_DEBUG(l,x)
# define DO_ASSERT(x)
# define CHECKED_OPERATION(expr) { \
DWORD res = expr; \
if (res != ERROR_SUCCESS) \
return res; \
}
# endif /* DEBUG */
/* alignment helpers, alignment must be power of 2 */
#define ALIGNED(x, alignment) ((((INT_PTR)x) & ((alignment)-1)) == 0)
#define ALIGN_BACKWARD(x, alignment) (((INT_PTR)x) & (~((alignment)-1)))
#define ALIGN_FORWARD(x, alignment) \
((((INT_PTR)x) + ((alignment)-1)) & (~((alignment)-1)))
#ifdef __cplusplus
}
#endif
#endif