Example #1
0
int 
main(int argc, char **argv)
{
    int res=0,
        run=0,
        dump=0,
        reset=0,
        detachall=0,
        detachpid=0,
        all=0,                  /* applies to all running processes */
        pid=-1,                 /* applies to pid, -1 means -all */
        hotp_nudge_pid=0,
        hotp_modes_nudge_pid=0,
        hotp_nudge_all=0,
        hotp_modes_nudge_all=0,
        nudge=0,                /* generic nudge with argument */
        nudge_action_mask=0,    /* generic nudge action mask */
        delay_ms_all=           /* delay between acting on processes */
                NUDGE_NO_DELAY,         
        timeout_ms=             /* timeout for finishing a nudge on a single process */
                DETACH_RECOMMENDED_TIMEOUT,
        runval=0,
        canary_default=0,
        canary_run = CANARY_RUN_FLAGS_DEFAULT,
        canary_fault_run = 0,
        exists = 0,
        destroy = 0,
        free_eventlog = 0;

    uint64 nudge_client_arg=0;     /* client nudge argument */

    int verbose = 0;

    char *create=NULL,
        *addapp=NULL, 
        *appdump=NULL, 
        *removeapp=NULL, 
        *opstring=NULL,
        *drdll=NULL,
        *preinject=NULL,
        *logdir=NULL,
        *sharedcache=NULL,
        *appname=NULL,
        *drhome=NULL,
        *modes=NULL,
        *defs=NULL,
        *detach_exename=NULL,
        *load=NULL,
        *save=NULL,
        *eventlog=NULL,
        *canary_process=NULL,
        *scratch_folder=NULL,
        *canary_fault_ops=NULL;

    dr_platform_t dr_platform = DR_PLATFORM_DEFAULT;
    
    int argidx=1;

    WCHAR wbuf[MAX_PATH];
    ConfigGroup *policy = NULL, *working_group;

    if (argc < 2) 
        usage();

    while (argidx < argc) {

        if (!strcmp(argv[argidx], "-help")) {
  	    help();
	}
        /* ******************** actions on active processes ******************** */
	else if (!strcmp(argv[argidx], "-detachall")) {
	    detachall=1;
	}
	else if (!strcmp(argv[argidx], "-detach")) {
            if (++argidx >= argc)
                usage();
	    detachpid=atoi(argv[argidx]);
	}
	else if (!strcmp(argv[argidx], "-detachexe")) {
            if (++argidx >= argc)
                usage();
	    detach_exename=argv[argidx];
	}
        else if (!strcmp(argv[argidx], "-pid") || !strcmp(argv[argidx], "-p")) {
            if (++argidx >= argc)
                usage();
            pid=atoi(argv[argidx]);
        }
	else if (!strcmp(argv[argidx], "-all")) {
	    all=1;
	}
        else if (!strcmp(argv[argidx], "-delay")) {
            /* in milliseconds */
            if (++argidx >= argc)
                usage();
            delay_ms_all=atoi(argv[argidx]);
        }
        else if (!strcmp(argv[argidx], "-timeout")) {
            /* in milliseconds */
            if (++argidx >= argc)
                usage();
            timeout_ms=atoi(argv[argidx]);
        }
	else if (!strcmp(argv[argidx], "-hot_patch_nudge")) {
            if (++argidx >= argc)
                usage();
	    hotp_nudge_pid=atoi(argv[argidx]);
	}
	else if (!strcmp(argv[argidx], "-hot_patch_modes_nudge")) {
            if (++argidx >= argc)
                usage();
	    hotp_modes_nudge_pid=atoi(argv[argidx]);
	}
	else if (!strcmp(argv[argidx], "-hot_patch_nudge_all")) {
	    hotp_nudge_all = 1;
	}
	else if (!strcmp(argv[argidx], "-verbose")) {
	    verbose = 1;
	}
	else if (!strcmp(argv[argidx], "-hot_patch_modes_nudge_all")) {
	    hotp_modes_nudge_all = 1;
	}
	else if (!strcmp(argv[argidx], "-drpop")) {
	    nudge = 1;
            /* allow composition */
	    nudge_action_mask |= NUDGE_GENERIC(opt) | NUDGE_GENERIC(reset);
	}
	else if (!strcmp(argv[argidx], "-nudge")) {
            int nudge_numeric;
            if (++argidx >= argc)
                usage();
            nudge_numeric = atoi(argv[argidx]); /* 0 if fails */
            nudge_action_mask |= nudge_numeric;

            /* compare against numeric new code, or against symbolic names */
            /* -nudge opt -nudge reset -nudge stats -nudge 30000 */
            {
                int found = 0;
#define NUDGE_DEF(name, comment) if (strcmp(#name, argv[argidx]) == 0) { found = 1; nudge_action_mask |= NUDGE_GENERIC(name);}
                NUDGE_DEFINITIONS();
#undef NUDGE_DEF
                if (!found && nudge_numeric == 0) {
                    printf("unknown -nudge %s\n", argv[argidx]);
                    usage();
                }
            }   

	    nudge=1;
	}
        else if (!strcmp(argv[argidx], "-client_nudge")) {
            if (++argidx >= argc)
                usage();
            nudge_client_arg = _strtoui64(argv[argidx], NULL, 16);
            nudge_action_mask |= NUDGE_GENERIC(client);
            nudge = 1;
        }
        /* ******************** configuration actions ******************** */
	else if (!strcmp(argv[argidx], "-reset")) {
	    reset=1;
	}
	else if (!strcmp(argv[argidx], "-create")) {
            if (++argidx >= argc)
                usage();
	    create = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-destroy")) {
            destroy = 1;
	}
	else if (!strcmp(argv[argidx], "-exists")) {
            exists = 1;
	}
	else if (!strcmp(argv[argidx], "-run")) {
            run = 1;
            if (++argidx >= argc)
                usage();
            runval = atoi(argv[argidx]);
	}
	else if (!strcmp(argv[argidx], "-app")) {
            if (++argidx >= argc)
                usage();
            appname = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-add")) {
            if (++argidx >= argc)
                usage();
	    addapp = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-remove")) {
            if (++argidx >= argc)
                usage();
	    removeapp = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-options")) {
            if (++argidx >= argc)
                usage();
	    opstring = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-drlib")) {
            if (++argidx >= argc)
                usage();
	    drdll = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-preinject")) {
            if (++argidx >= argc)
                usage();
            preinject = argv[argidx];
	}
        else if (!strcmp(argv[argidx], "-create_eventlog")) {
            if (++argidx >= argc)
                usage();
            eventlog = argv[argidx];
        }
	else if (!strcmp(argv[argidx], "-destroy_eventlog")) {
            free_eventlog = 1;
	}
	else if (!strcmp(argv[argidx], "-drhome")) {
            if (++argidx >= argc)
                usage();
            drhome = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-modes")) {
            if (++argidx >= argc)
                usage();
            modes = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-defs")) {
            if (++argidx >= argc)
                usage();
            defs = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-logdir")) {
            if (++argidx >= argc)
                usage();
	    logdir = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-sharedcache")) {
            if (++argidx >= argc)
                usage();
	    sharedcache = argv[argidx];
	}
	else if (!strcmp(argv[argidx], "-load")) {
            if (++argidx >= argc)
                usage();
	    load = argv[argidx];
	}
        else if (!strcmp(argv[argidx], "-save")) {
            if (++argidx >= argc)
                usage();
            save = argv[argidx];
        }
	else if (!strcmp(argv[argidx], "-dump")) {
	    dump = 1;
	}
	else if (!strcmp(argv[argidx], "-appdump")) {
            if (++argidx >= argc)
                usage();
            appdump = argv[argidx];	    
	}
	else if (!strcmp(argv[argidx], "-fulldump")) {
	    dump = 1;
	}
	else if (!strcmp(argv[argidx], "-v")) {
#ifdef BUILD_NUMBER
	  printf("DRcontrol.exe build %d -- %s", BUILD_NUMBER, __DATE__);
#else
	  printf("DRcontrol.exe custom build -- %s, %s", __DATE__, __TIME__);
#endif
	} else if (!strcmp(argv[argidx], "-canary_default")) {
            canary_default = 1;
	} else if (!strcmp(argv[argidx], "-canary")) {
            if (++argidx >= argc)
                usage();
	    canary_process=argv[argidx];
            if (++argidx >= argc)
                usage();
	    scratch_folder=argv[argidx];
	} else if (!strcmp(argv[argidx], "-canary_run")) {
            if (++argidx >= argc)
                usage();
	    canary_run = strtol(argv[argidx], NULL, 0);
	} else if (!strcmp(argv[argidx], "-canary_fault")) {
            char *dummy;
            if (++argidx >= argc)
                usage();
            canary_fault_run = strtol(argv[argidx], &dummy, 0);
            if (++argidx >= argc)
                usage();
            canary_fault_ops = argv[argidx];
	} else if (!strcmp(argv[argidx], "-32")) {
	    dr_platform = DR_PLATFORM_32BIT;
	} else if (!strcmp(argv[argidx], "-64")) {
	    dr_platform = DR_PLATFORM_64BIT;
	} else {
	    fprintf(stderr, "Unknown option: %s\n", argv[argidx]);
	    usage();
	}
	argidx++;
    }
  
    /* PR 244206: set the registry view before any registry access */
    set_dr_platform(dr_platform);

    if (canary_process != NULL || canary_default != 0) {
        BOOL result = TRUE;
        WCHAR canary_fault_args[MAX_PATH];
        CANARY_INFO info = {0};

        info.run_flags = canary_run;
        info.info_flags = CANARY_INFO_FLAGS_DEFAULT;
        info.fault_run = canary_fault_run;
        _snwprintf(canary_fault_args, BUFFER_SIZE_ELEMENTS(canary_fault_args),
                   L"%S", canary_fault_ops);
        NULL_TERMINATE_BUFFER(canary_fault_args);
        info.canary_fault_args = canary_fault_args;

        if (canary_process != NULL && *canary_process != '\0' &&
            scratch_folder != NULL && *scratch_folder != '\0') {
            wchar_t canary[MAX_PATH], scratch[MAX_PATH], out[MAX_PATH];
            FILE *out_file;
            _snwprintf(canary, BUFFER_SIZE_ELEMENTS(canary), L"%S", canary_process);
            NULL_TERMINATE_BUFFER(canary);
            _snwprintf(scratch, BUFFER_SIZE_ELEMENTS(scratch), L"%S\\canary_test",
                       scratch_folder);
            NULL_TERMINATE_BUFFER(scratch);
            CreateDirectory(scratch, NULL);
            _snwprintf(out, BUFFER_SIZE_ELEMENTS(out), L"%S\\canary_report.crep",
                       scratch_folder);
            out_file = _wfopen(out, L"wb");
            /* FIXME - check directory, out_file, and canary proc exist */
            result = run_canary_test_ex(out_file, &info, scratch, canary);
        } else if (canary_default != 0) {
            result = run_canary_test(&info, L_EXPAND_LEVEL(STRINGIFY(BUILD_NUMBER)));
            printf("See report file \"%S\"\n", info.report);
        }
        printf("Canary test - %s enable protection - code 0x%08x\n"
               "  msg=\"%S\"\n  url=\"%S\"\n", result ? "do" : "don\'t",
               info.canary_code, info.msg, info.url);
        return info.canary_code;
    }

    if (exists) {
        if (get_dynamorio_home() != NULL) {
            printf("Registry setup exists\n");
            return 0;
        }
        printf("Registry setup doesn't exist\n");
        return 1;
    }    

    if (save) {
        _snwprintf(wbuf, MAX_PATH, L"%S", save);
        NULL_TERMINATE_BUFFER(wbuf);
        checked_operation("save policy", save_policy(wbuf));
    }

    if (destroy) {
        checked_operation("delete product key", destroy_root_key());
        if (!load && create == NULL)
            return 0;
    }

    if (load) {
        _snwprintf(wbuf, MAX_PATH, L"%S", load);
        NULL_TERMINATE_BUFFER(wbuf);
        checked_operation("load policy", load_policy(wbuf, FALSE, NULL));
    }

    if (create != NULL) {
        _snwprintf(wbuf, MAX_PATH, L"%S", create);
        NULL_TERMINATE_BUFFER(wbuf);
        /* FALSE: do not overwrite (preserves old behavior) */
        checked_operation("create registry", setup_installation(wbuf, FALSE));
    }

    /* ensure we init dynamorio_home, case 4009 */
    get_dynamorio_home(); /* ignore return value */

    if (nudge) {
        if (verbose)
            printf("-nudge %d -pid %d %s\n", nudge_action_mask, pid, all ? "all" : "");
        if (pid == -1)           /* explicitly set */
            all = 1;

        if (all)
            checked_operation("nudge all", 
                              generic_nudge_all(nudge_action_mask, nudge_client_arg,
                                                timeout_ms, delay_ms_all));
        else
            checked_operation("nudge", 
                              generic_nudge(pid, TRUE,
                                            nudge_action_mask,
                                            0, /* client ID (ignored here) */
                                            nudge_client_arg,
                                            timeout_ms));
        goto finished;
    }

    if (detachall) {
        checked_operation("detach all", 
                          detach_all(timeout_ms));
        goto finished;
    }
    if (detachpid) {
        checked_operation("detach", 
                          detach(detachpid, TRUE, timeout_ms));
        goto finished;
    }

    if (detach_exename) {
        _snwprintf(wbuf, MAX_PATH, L"%S", detach_exename);
        NULL_TERMINATE_BUFFER(wbuf);
        checked_operation("detach-exe", 
                          detach_exe(wbuf, timeout_ms));
        goto finished;
    }

    
    if (hotp_nudge_pid) {
        checked_operation("hot patch update", 
                          hotp_notify_defs_update(hotp_nudge_pid, TRUE,
                                                  timeout_ms));
        goto finished;
    }

    if (hotp_modes_nudge_pid) {
        checked_operation("hot patch modes update", 
                          hotp_notify_modes_update(hotp_modes_nudge_pid, TRUE,
                                                   timeout_ms));
        goto finished;
    }

    if (hotp_nudge_all) {
        checked_operation("hot patch nudge all", 
                          hotp_notify_all_defs_update(timeout_ms));
        goto finished;
    }

    if (hotp_modes_nudge_all) {
        checked_operation("hot patch modes nudge all", 
                          hotp_notify_all_modes_update(timeout_ms));
        goto finished;
    }

    checked_operation("read config",
                      read_config_group(&policy, L_PRODUCT_NAME, TRUE));
    
    if (reset) {
        remove_children(policy);
        policy->should_clear = TRUE;
        checked_operation("write registry", write_config_group(policy));
    }

    working_group = policy;

    if (dump || appdump)
        goto dumponly;

    if (preinject) {
        if (0 == strcmp(preinject, "OFF")) {
            checked_operation("unset autoinject", unset_autoinjection());
        }
        else if (0 == strcmp(preinject, "ON")) {
            checked_operation("set autoinject", set_autoinjection());
        }
        else if (0 == strcmp(preinject, "CLEAR")) {
            checked_operation("clear autoinject", 
                              set_autoinjection_ex(FALSE, 
                                                   APPINIT_USE_WHITELIST,
                                                   NULL,
                                                   L"",
                                                   NULL,
                                                   NULL,
                                                   NULL,
                                                   0));
        }
        else if (0 == strcmp(preinject, "LIST")) {
            WCHAR list[MAX_PARAM_LEN];
            checked_operation("read appinit",
                              get_config_parameter(INJECT_ALL_KEY_L, 
                                                   TRUE, 
                                                   INJECT_ALL_SUBKEY_L, 
                                                   list, 
                                                   MAX_PARAM_LEN));
            printf("%S\n", list);
            if (is_vista()) {
                printf("LoadAppInit is %s\n",
                       is_loadappinit_set() ? "on" : "off");
            }
        }
        else if (0 == strcmp(preinject, "REPORT")) {
            WCHAR list[MAX_PARAM_LEN], *entry, *sep;
            checked_operation("read appinit",
                              get_config_parameter(INJECT_ALL_KEY_L, 
                                                   TRUE, 
                                                   INJECT_ALL_SUBKEY_L, 
                                                   list, 
                                                   MAX_PARAM_LEN));
            entry = get_entry_location(list, L_EXPAND_LEVEL(INJECT_DLL_8_3_NAME),
                                       APPINIT_SEPARATOR_CHAR);
            if (NULL != entry) {
                sep = wcschr(entry, APPINIT_SEPARATOR_CHAR);
                if (NULL != sep)
                    *sep = L'\0';
                printf("%S\n", entry);
                if (is_vista()) {
                    printf("LoadAppInit is %s\n",
                           is_loadappinit_set() ? "on" : "off");
                }
            }
        }
        else if (0 == strcmp(preinject, "LOAD_OFF")) {
            checked_operation("unset load autoinject", unset_loadappinit());
        }
        else if (0 == strcmp(preinject, "LOAD_ON")) {
            checked_operation("set load autoinject", set_loadappinit());
        }
        else {
            _snwprintf(wbuf, MAX_PATH, L"%S", preinject);
            NULL_TERMINATE_BUFFER(wbuf);
            checked_operation("set custom autoinject", 
                              set_autoinjection_ex(TRUE, APPINIT_OVERWRITE,
                                                   NULL, NULL, NULL, wbuf,
                                                   NULL, 0));
        }

        if (0 != strcmp(preinject, "LIST") &&
            0 != strcmp(preinject, "REPORT") &&
            using_system32_for_preinject(NULL)) {
            DWORD platform;
            if (get_platform(&platform) == ERROR_SUCCESS &&
                platform == PLATFORM_WIN_NT_4) {
                fprintf(stderr, "Warning! On NT4, new AppInit_DLLs setting will not take effect until reboot!\n");
            }
        }

    }

    if (free_eventlog) {
        checked_operation("free eventlog", destroy_eventlog());
    }

    if (eventlog) {
        _snwprintf(wbuf, BUFFER_SIZE_ELEMENTS(wbuf), L"%S", eventlog);
        NULL_TERMINATE_BUFFER(wbuf);
        checked_operation("create eventlog", create_eventlog(wbuf));
    }

    /* configuration */


    if (addapp) {
        _snwprintf(wbuf, MAX_PATH, L"%S", addapp);
        NULL_TERMINATE_BUFFER(wbuf);
        if (NULL == get_child(wbuf, policy)) {
            add_config_group(policy, new_config_group(wbuf));
        }
    }

    if (removeapp) {
        _snwprintf(wbuf, MAX_PATH, L"%S", removeapp);
        NULL_TERMINATE_BUFFER(wbuf);
        remove_child(wbuf, policy);
        policy->should_clear = TRUE;
    }

    if (appname) {
        _snwprintf(wbuf, MAX_PATH, L"%S", appname);
        NULL_TERMINATE_BUFFER(wbuf);
        working_group = get_child(wbuf, policy);

        if (NULL == working_group) {
            working_group = new_config_group(wbuf);
            add_config_group(policy, working_group);
        }
    }
    
    if (run) {
        _snwprintf(wbuf, MAX_PATH, L"%d", runval);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group, 
                                   L_DYNAMORIO_VAR_RUNUNDER, wbuf);
    }

    if (opstring) {
        _snwprintf(wbuf, MAX_PATH, L"%S", opstring);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group,
                                   L_DYNAMORIO_VAR_OPTIONS, wbuf);
    }
    
    if (drdll) {
        _snwprintf(wbuf, MAX_PATH, L"%S", drdll);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group, 
                                   L_DYNAMORIO_VAR_AUTOINJECT, wbuf);
    }

    if (drhome) {
        _snwprintf(wbuf, MAX_PATH, L"%S", drhome);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group, 
                                   L_DYNAMORIO_VAR_HOME, wbuf);
    }

    if (modes) {
        _snwprintf(wbuf, MAX_PATH, L"%S", modes);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group, 
                                   L_DYNAMORIO_VAR_HOT_PATCH_MODES, wbuf);
    }

    if (defs) {
        _snwprintf(wbuf, MAX_PATH, L"%S", defs);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group, 
                                   L_DYNAMORIO_VAR_HOT_PATCH_POLICIES, wbuf);
    }

    if (logdir) {
        _snwprintf(wbuf, MAX_PATH, L"%S", logdir);
        NULL_TERMINATE_BUFFER(wbuf);
        set_config_group_parameter(working_group, 
                                   L_DYNAMORIO_VAR_LOGDIR, wbuf);
    }

    if (sharedcache) {
        /* note if the sharedcache root directory doesn't exist it should be
         * created before calling this function */
        _snwprintf(wbuf, MAX_PATH, L"%S", sharedcache);
        NULL_TERMINATE_BUFFER(wbuf);

        res = setup_cache_shared_directories(wbuf);
        if (res != ERROR_SUCCESS) {
            fprintf(stderr, "error %d creating directories!\n", res);
        }
        setup_cache_shared_registry(wbuf, working_group);
    }

    checked_operation("write policy", write_config_group(policy));

 dumponly:

    if (appdump) {
        _snwprintf(wbuf, MAX_PATH, L"%S", appdump);
        NULL_TERMINATE_BUFFER(wbuf);
        working_group = get_child(wbuf, policy);
    }
    else {
        working_group = policy;
    }

    if (dump || appdump) {
        if (NULL == working_group)
            fprintf(stderr, "No Configuration Exists!\n");
        else
            dump_config_group("","  ",working_group,FALSE);
    }

 finished:
    if (policy != NULL)
        free_config_group(policy);

    return 0;

}
Example #2
0
int
main(int argc, const char *argv[])
{
    process_id_t target_pid = 0;
    uint action_mask = 0;
    client_id_t client_id = 0;
    uint64 client_arg = 0;
    int i;
    siginfo_t info;
    int arg_offs = 1;
    bool success;

    /* parse command line */
    if (argc <= 1)
        return usage();
    while (arg_offs < argc && argv[arg_offs][0] == '-') {
        if (strcmp(argv[arg_offs], "-help") == 0) {
            return usage();
        } else if (strcmp(argv[arg_offs], "-v") == 0) {
            printf("nudgeunix version %s -- build %d\n",
                   STRINGIFY(VERSION_NUMBER), BUILD_NUMBER);
            exit(0);
        } else if (strcmp(argv[arg_offs], "-pid") == 0) {
            if (argc <= arg_offs+1)
                return usage();
            target_pid = strtoul(argv[arg_offs+1], NULL, 10);
            arg_offs += 2;
        } else if (strcmp(argv[arg_offs], "-client") == 0) {
            if (argc <= arg_offs+2)
                return usage();
            action_mask |= NUDGE_GENERIC(client);
            client_id = strtoul(argv[arg_offs+1], NULL, 16);
            client_arg = strtoull(argv[arg_offs+2], NULL, 16);
            arg_offs += 3;
        } else if (strcmp(argv[arg_offs], "-type") == 0) {
            int type_numeric;
            if (argc <= arg_offs+1)
                return usage();
            type_numeric = strtoul(argv[arg_offs+1], NULL, 10);
            action_mask |= type_numeric;

            /* compare against symbolic names */
            {
                int found = 0;
#define NUDGE_DEF(name, comment) \
                if (strcmp(#name, argv[arg_offs+1]) == 0) { \
                    found = 1; \
                    action_mask |= NUDGE_GENERIC(name); \
                }
                NUDGE_DEFINITIONS();
#undef NUDGE_DEF
                if (!found && type_numeric == 0) {
                    fprintf(stderr, "ERROR: unknown -nudge %s\n", argv[arg_offs+1]);
                    return usage();
                }
            }

            arg_offs += 2;
        } else
            return usage();
    }
    if (arg_offs < argc)
        return usage();

    /* construct the payload */
    success = create_nudge_signal_payload(&info, action_mask, client_id, client_arg);
    assert(success); /* failure means kernel's sigqueueinfo has changed */

    /* send the nudge */
    i = syscall(SYS_rt_sigqueueinfo, target_pid, NUDGESIG_SIGNUM, &info);
    if (i < 0)
        fprintf(stderr, "nudge FAILED with error %d\n", i);
    return i;
}
Example #3
0
static
#endif
void
handle_nudge(dcontext_t *dcontext, nudge_arg_t *arg)
{
    uint nudge_action_mask = arg->nudge_action_mask;

    /* Future version checks would go here. */
    ASSERT_CURIOSITY(arg->version == NUDGE_ARG_CURRENT_VERSION);

    /* Nudge shouldn't start with any locks held.  Do this assert after the
     * dynamo_exited check, other wise the locks may be deleted. */
    ASSERT_OWN_NO_LOCKS();

    STATS_INC(num_nudges);

#ifdef WINDOWS
    /* Linux does this in signal.c */
    SYSLOG_INTERNAL_INFO("received nudge mask=0x%x id=0x%08x arg=0x"ZHEX64_FORMAT_STRING,
                         arg->nudge_action_mask, arg->client_id, arg->client_arg);
#endif

    if (nudge_action_mask == 0) {
        ASSERT_CURIOSITY(false && "Nudge: no action specified");
        return;
    } else if (nudge_action_mask >= NUDGE_GENERIC(PARAMETRIZED_END)) {
        ASSERT(false && "Nudge: unknown nudge action");
        return;
    }

    /* In -thin_client mode only detach and process_control nudges are allowed;
     * case 8888. */
#define VALID_THIN_CLIENT_NUDGES (NUDGE_GENERIC(process_control)|NUDGE_GENERIC(detach))
    if (DYNAMO_OPTION(thin_client)) {
        if (TEST(VALID_THIN_CLIENT_NUDGES, nudge_action_mask)) {
             /* If it is a valid thin client nudge, then disable all others. */
             nudge_action_mask &= VALID_THIN_CLIENT_NUDGES;
        } else {
            return;   /* invalid nudge for thin_client, so mute it */
        }
    }

    /* FIXME: NYI action handlers. As implemented move to desired order. */
    if (TEST(NUDGE_GENERIC(upgrade), nudge_action_mask)) {
        /* FIXME: watch out for flushed clean-call fragment */
        nudge_action_mask &= ~NUDGE_GENERIC(upgrade);
        ASSERT_NOT_IMPLEMENTED(false && "case 4179");
    }
    if (TEST(NUDGE_GENERIC(kstats), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(kstats);
        ASSERT_NOT_IMPLEMENTED(false);
    }
#ifdef INTERNAL
    if (TEST(NUDGE_GENERIC(stats), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(stats);
        ASSERT_NOT_IMPLEMENTED(false);
    }
    if (TEST(NUDGE_GENERIC(invalidate), nudge_action_mask)) {
        /* FIXME: watch out for flushed clean-call fragment  */
        nudge_action_mask &= ~NUDGE_GENERIC(invalidate);
        ASSERT_NOT_IMPLEMENTED(false);
    }
    if (TEST(NUDGE_GENERIC(recreate_pc), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(recreate_pc);
        ASSERT_NOT_IMPLEMENTED(false);
    }
    if (TEST(NUDGE_GENERIC(recreate_state), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(recreate_state);
        ASSERT_NOT_IMPLEMENTED(false);
    }
    if (TEST(NUDGE_GENERIC(reattach), nudge_action_mask)) {
        /* FIXME: watch out for flushed clean-call fragment */
        nudge_action_mask &= ~NUDGE_GENERIC(reattach);
        ASSERT_NOT_IMPLEMENTED(false);
    }
#endif /* INTERNAL */
    if (TEST(NUDGE_GENERIC(diagnose), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(diagnose);
        ASSERT_NOT_IMPLEMENTED(false);
    }

    /* Implemented action handlers */
    if (TEST(NUDGE_GENERIC(opt), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(opt);
        synchronize_dynamic_options();
    }
    if (TEST(NUDGE_GENERIC(ldmp), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(ldmp);
        os_dump_core("Nudge triggered ldmp.");
    }
    if (TEST(NUDGE_GENERIC(freeze), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(freeze);
        coarse_units_freeze_all(true/*in-place: FIXME: separate nudge for non?*/);
    }
    if (TEST(NUDGE_GENERIC(persist), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(persist);
        coarse_units_freeze_all(false/*!in-place==persist*/);
    }
#ifdef CLIENT_INTERFACE
    if (TEST(NUDGE_GENERIC(client), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(client);
        instrument_nudge(dcontext, arg->client_id, arg->client_arg);
    }
#endif
#ifdef PROCESS_CONTROL
    if (TEST(NUDGE_GENERIC(process_control), nudge_action_mask)) {  /* Case 8594 */
        nudge_action_mask &= ~NUDGE_GENERIC(process_control);
        /* Need to synchronize because process control can be switched between
         * on (white or black list) & off.  FIXME - the nudge mask should specify this,
         * but doesn't hurt to do it again. */
        synchronize_dynamic_options();
        if (IS_PROCESS_CONTROL_ON())
            process_control();

        /* If process control is enforced then control won't come back.  If
         * either -detect_mode is on or if there was nothing to enforce, control
         * comes back in which case it is safe to let remaining nudges be
         * processed because no core state would have been changed. */
    }
#endif
#ifdef HOTPATCHING
    if (DYNAMO_OPTION(hot_patching) && DYNAMO_OPTION(liveshields) &&
        TEST_ANY(NUDGE_GENERIC(policy)|NUDGE_GENERIC(mode)|NUDGE_GENERIC(lstats),
                 nudge_action_mask)) {
        hotp_nudge_update(nudge_action_mask &
                          (NUDGE_GENERIC(policy)|NUDGE_GENERIC(mode)|NUDGE_GENERIC(lstats)));
        nudge_action_mask &= ~(NUDGE_GENERIC(policy)|NUDGE_GENERIC(mode)|NUDGE_GENERIC(lstats));
    }
#endif
#ifdef PROGRAM_SHEPHERDING
    if (TEST(NUDGE_GENERIC(violation), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(violation);
        /* Use nudge mechanism to trigger a security violation at an
         * arbitrary time. Note - is only useful for testing kill process attack
         * handling as this is not an app thread (we injected it). */
        /* see bug 652 for planned improvements */
        security_violation(dcontext, dcontext->next_tag,
                           ATTACK_SIM_NUDGE_VIOLATION, OPTION_BLOCK|OPTION_REPORT);
    }
#endif
    if (TEST(NUDGE_GENERIC(reset), nudge_action_mask)) {
        nudge_action_mask &= ~NUDGE_GENERIC(reset);
        if (DYNAMO_OPTION(enable_reset)) {
            mutex_lock(&reset_pending_lock);
            /* fcache_reset_all_caches_proactively() will unlock */
            fcache_reset_all_caches_proactively(RESET_ALL);
            /* NOTE - reset is safe since we won't return to the code cache below (we
             * will in fact not return at all). */
        } else {
            SYSLOG_INTERNAL_WARNING("nudge reset ignored since resets are disabled");
        }
    }
#ifdef WINDOWS
    /* The detach handler is last since in the common case it doesn't return. */
    if (TEST(NUDGE_GENERIC(detach), nudge_action_mask)) {
        dcontext->free_app_stack = false;
        nudge_action_mask &= ~NUDGE_GENERIC(detach);
        detach_helper(DETACH_NORMAL_TYPE);
    }
#endif
}