def test_multiple_profiles(bpf_program: BPFProgram, caplog): """ Make sure that multiple profiles are created properly. """ ls = which('ls') ps = which('ps') # There should be one profile after this subprocess.Popen(ls).wait() assert len(bpf_program.bpf['profiles']) >= 1 # There should be two profiles after this subprocess.Popen(ps).wait() assert len(bpf_program.bpf['profiles']) >= 2 # Make sure we can look up the profile by its key profile_key = calculate_profile_key(ls) bpf_program.bpf['profiles'][ct.c_uint64(profile_key)] # Make sure the profile has the correct name associated with it bpf_program.on_tick() assert bpf_program.profile_key_to_exe[profile_key] in ['ls', ls] # Make sure we can look up the profile by its key profile_key = calculate_profile_key(ps) bpf_program.bpf['profiles'][ct.c_uint64(profile_key)] # Make sure the profile has the correct name associated with it bpf_program.on_tick() assert bpf_program.profile_key_to_exe[profile_key] in ['ps', ps]
def test_normal(bpf_program: BPFProgram, caplog): """ Make sure that profiles normalize properly. """ hello = project_path('tests/driver/hello') # Set normal wait so that we normalize right away bpf_program.change_setting(EBPH_SETTINGS.NORMAL_WAIT, 0) # Spawn several hello processes so that we can freeze AND normalize for _ in range(50): subprocess.Popen(hello, stdout=subprocess.DEVNULL).wait() bpf_program.on_tick() assert len(bpf_program.bpf['profiles']) >= 1 # Fetch the profile for hello profile_key = calculate_profile_key(hello) profile = bpf_program.get_profile(profile_key) # We should now be normal assert profile.status & EBPH_PROFILE_STATUS.NORMAL assert not (profile.status & (EBPH_PROFILE_STATUS.FROZEN | EBPH_PROFILE_STATUS.TRAINING)) assert profile.anomaly_count == 0
def test_freeze(bpf_program: BPFProgram, caplog): """ Make sure that profiles freeze properly. """ hello = project_path('tests/driver/hello') # We want normal wait to be pretty high, but not so high that it wraps # around when the BPF program adds it to the current time. # # FIXME: We probably want to add a hard limit for normal wait # in the BPF program itself, since it probably doesn't make sense # to have normal wait be super long regardless. bpf_program.change_setting(EBPH_SETTINGS.NORMAL_WAIT, 2**60) # Spawn several hello processes so that we can freeze for _ in range(50): subprocess.Popen(hello, stdout=subprocess.DEVNULL).wait() bpf_program.on_tick() assert len(bpf_program.bpf['profiles']) >= 1 # Fetch the profile for hello profile_key = calculate_profile_key(hello) profile = bpf_program.get_profile(profile_key) # We should be frozen with zero anomalies assert profile.status & (EBPH_PROFILE_STATUS.FROZEN | EBPH_PROFILE_STATUS.TRAINING) assert not (profile.status & EBPH_PROFILE_STATUS.NORMAL) assert profile.anomaly_count == 0
def test_one_profile(bpf_program: BPFProgram, caplog): """ Make sure that a single profile is created properly. """ ls = which('ls') # There should be at least one profile after this subprocess.Popen(ls).wait() assert len(bpf_program.bpf['profiles']) >= 1 # Make sure we can look up the profile by its key profile_key = calculate_profile_key(ls) bpf_program.bpf['profiles'][ct.c_uint64(profile_key)] # Force a tick update here bpf_program.on_tick() # Make sure the profile has the correct name associated with it assert bpf_program.profile_key_to_exe[profile_key] in ['ls', ls]
def test_sample_workload(bpf_program: BPFProgram, caplog): """ Test profile creation for several processes executed within a shell script. """ sample_workload = project_path('tests/driver/sample_workload.sh') subprocess.Popen(sample_workload).wait() # Profiles should at least include the following: profile_names = ['bash', 'ls', 'wc', 'ps', 'cat', 'echo', 'grep'] profile_locations = [which(n) for n in profile_names] assert len(bpf_program.bpf['profiles']) >= 7 # Force a tick update here bpf_program.on_tick() for n, p in zip(profile_names, profile_locations): # Make sure we can look up the profile by its key profile_key = calculate_profile_key(p) bpf_program.bpf['profiles'][ct.c_uint64(profile_key)] # Make sure the profile has the correct name associated with it assert bpf_program.profile_key_to_exe[profile_key] in [n, p]
def test_anomaly(bpf_program: BPFProgram, caplog): """ Make sure that anomalies in normal profiles are detected. """ hello = project_path('tests/driver/hello') # Set normal wait so that we normalize right away bpf_program.change_setting(EBPH_SETTINGS.NORMAL_WAIT, 0) # Spawn several hello processes so that we can freeze AND normalize for _ in range(50): subprocess.Popen(hello, stdout=subprocess.DEVNULL).wait() bpf_program.on_tick() assert len(bpf_program.bpf['profiles']) >= 1 # Fetch the profile for hello profile_key = calculate_profile_key(hello) profile = bpf_program.get_profile(profile_key) assert profile.status & EBPH_PROFILE_STATUS.NORMAL assert not (profile.status & (EBPH_PROFILE_STATUS.FROZEN | EBPH_PROFILE_STATUS.TRAINING)) assert profile.anomaly_count == 0 # This will cause an anomaly subprocess.Popen([hello, 'foo'], stdout=subprocess.DEVNULL).wait() bpf_program.on_tick() # Fetch profile again profile = bpf_program.get_profile(profile_key) # We should have seen an anomaly for the write system call # (as well as some others (e.g. EXIT_GROUP), but don't test for that) assert profile.anomaly_count > 0 assert 'Anomalous WRITE' in caplog.text