def _compile_single_range(entry, accept_action, reject_action, lower_bound=0, upper_bound=1e99): action = accept_action if entry.filter: action = entry.filter if entry.numbers[1] - entry.numbers[0] == 1: # Single syscall. # Accept if |X == nr|. return (1, bpf.SyscallEntry(entry.numbers[0], action, reject_action, op=bpf.BPF_JEQ)) elif entry.numbers[0] == lower_bound: # Syscall range aligned with the lower bound. # Accept if |X < nr[1]|. return (1, bpf.SyscallEntry(entry.numbers[1], reject_action, action, op=bpf.BPF_JGE)) elif entry.numbers[1] == upper_bound: # Syscall range aligned with the upper bound. # Accept if |X >= nr[0]|. return (1, bpf.SyscallEntry(entry.numbers[0], action, reject_action, op=bpf.BPF_JGE)) # Syscall range in the middle. # Accept if |nr[0] <= X < nr[1]|. upper_entry = bpf.SyscallEntry(entry.numbers[1], reject_action, action, op=bpf.BPF_JGE) return (2, bpf.SyscallEntry(entry.numbers[0], upper_entry, reject_action, op=bpf.BPF_JGE))
def _generate_syscall_bst(ranges, indices, bounds=(0, 2**64 - 1)): assert bounds[0] <= ranges[indices[0]].numbers[0], (indices, bounds) assert ranges[indices[1] - 1].numbers[1] <= bounds[1], (indices, bounds) if bounds in memoized_costs: return memoized_costs[bounds] if indices[1] - indices[0] == 1: if bounds == ranges[indices[0]].numbers: # If bounds are tight around the syscall, it costs nothing. memoized_costs[bounds] = (0, ranges[indices[0]].filter or accept_action) return memoized_costs[bounds] result = _compile_single_range(ranges[indices[0]], accept_action, reject_action) memoized_costs[bounds] = (result[0] * ranges[indices[0]].frequency, result[1]) return memoized_costs[bounds] # Try the linear model first and use that as the best estimate so far. best_cost = _compile_ranges_linear(ranges[slice(*indices)], accept_action, reject_action) # Now recursively go through all possible partitions of the interval # currently being considered. previous_accumulated = ranges[indices[0]].accumulated - ranges[ indices[0]].frequency bst_comparison_cost = (ranges[indices[1] - 1].accumulated - previous_accumulated) for i, entry in enumerate(ranges[slice(*indices)]): candidates = [entry.numbers[0]] if i: candidates.append(ranges[i - 1 + indices[0]].numbers[1]) for cutoff_bound in candidates: if not bounds[0] < cutoff_bound < bounds[1]: continue if not indices[0] < i + indices[0] < indices[1]: continue left_subtree = _generate_syscall_bst( ranges, (indices[0], i + indices[0]), (bounds[0], cutoff_bound)) right_subtree = _generate_syscall_bst( ranges, (i + indices[0], indices[1]), (cutoff_bound, bounds[1])) best_cost = min( best_cost, (bst_comparison_cost + left_subtree[0] + right_subtree[0], bpf.SyscallEntry(cutoff_bound, right_subtree[1], left_subtree[1], op=bpf.BPF_JGE))) memoized_costs[bounds] = best_cost return memoized_costs[bounds]