#!/bin/bash # # Copyright (C) 2016 Julien Desfossez # # SPDX-License-Identifier: GPL-2.0-only # TEST_DESC="Kernel tracer - select, poll and epoll payload extraction" CURDIR=$(dirname "$0")/ TESTDIR=$CURDIR/../.. VALIDATE_SCRIPT="$CURDIR/validate_select_poll_epoll.py" DISABLE_VALIDATE=0 # Babeltrace python bindings are required for the validation, but # it is not a mandatory dependancy of the project, so fail run the # without the content validation, at least we test that we are not # crashing the kernel. $VALIDATE_SCRIPT --help >/dev/null 2>&1 if test $? != 0; then echo "# Failed to run the validation script, Babeltrace Python bindings might be missing" DISABLE_VALIDATE=1 fi LAST_WARNING=$(dmesg | grep " WARNING:" | cut -d' ' -f1 | tail -1) LAST_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1) LAST_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1) SUPPORTED_SYSCALLS_LIST=$("$CURDIR"/select_poll_epoll --list-supported-test-syscalls) SUPPORTED_SYSCALLS_COUNT=$(echo $SUPPORTED_SYSCALLS_LIST | awk -F '[\t,]' '{print NF}') # Two tests validate their trace for every supported syscall NUM_TESTS=$((88+(2*SUPPORTED_SYSCALLS_COUNT))) # shellcheck source=../../utils/utils.sh source $TESTDIR/utils/utils.sh function check_trace_content() { if test $DISABLE_VALIDATE == 1; then ok 0 "Validation skipped" return fi $VALIDATE_SCRIPT $@ if test $? = 0; then ok 0 "Validation success" else fail "Validation" fi } function test_working_cases() { SESSION_NAME="syscall_payload" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "Working cases for select, pselect6, poll, ppoll and epoll, waiting for input" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SUPPORTED_SYSCALLS_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t working_cases stop_lttng_tracing_ok validate_trace "$SUPPORTED_SYSCALLS_LIST" "$TRACE_PATH" check_trace_content -t working_cases --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_timeout_cases() { SESSION_NAME="syscall_payload" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "Timeout cases (1ms) for select, pselect6, poll, ppoll and epoll" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME "$SUPPORTED_SYSCALLS_LIST" add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t working_cases_timeout stop_lttng_tracing_ok validate_trace "$SUPPORTED_SYSCALLS_LIST" "$TRACE_PATH" check_trace_content -t working_cases_timeout --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_pselect_invalid_fd() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="pselect6" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "pselect with invalid FD" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t pselect_invalid_fd stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t pselect_invalid_fd --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_ppoll_big() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="ppoll" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "ppoll with 2047 FDs" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_big stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t ppoll_big --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_ppoll_fds_buffer_overflow() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="ppoll" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "ppoll buffer overflow, should segfault, waits for input" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok diag "Expect segfaults" yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_fds_buffer_overflow stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t ppoll_fds_buffer_overflow --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_pselect_invalid_pointer() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="pselect6" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "pselect with invalid pointer, waits for input" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t pselect_invalid_pointer stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t pselect_invalid_pointer --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_ppoll_fds_ulong_max() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="ppoll" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "ppoll with ulong_max fds, waits for input" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_fds_ulong_max stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t ppoll_fds_ulong_max --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_epoll_pwait_invalid_pointer() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="epoll_pwait" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "epoll_pwait with invalid pointer, waits for input" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t epoll_pwait_invalid_pointer stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t epoll_pwait_invalid_pointer --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_epoll_pwait_fds_int_max() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="epoll_pwait" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "epoll_pwait with maxevents set to INT_MAX, waits for input" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t epoll_pwait_int_max stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t epoll_pwait_int_max --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_ppoll_concurrent_write() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="ppoll" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "ppoll with concurrent updates of the structure from user-space, stress test (3000 iterations), waits for input + timeout 1ms" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t ppoll_concurrent_write stop_lttng_tracing_ok validate_trace "$SYSCALL_LIST" "$TRACE_PATH" check_trace_content -t ppoll_concurrent_write --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } function test_epoll_pwait_concurrent_unmap() { SESSION_NAME="syscall_payload" local SYSCALL_LIST="epoll_ctl,epoll_pwait" TRACE_PATH=$(mktemp -d -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_trace_path.XXXXXX") TEST_VALIDATION_OUTPUT_PATH=$(mktemp -u -t "tmp.test_kernel_select_poll_epoll_${FUNCNAME[0]}_validation.XXXXXX") diag "epoll_pwait with concurrent munmap of the buffer from user-space, should randomly segfault, run multiple times, waits for input + timeout 1ms" create_lttng_session_ok $SESSION_NAME "$TRACE_PATH" lttng_enable_kernel_syscall_ok $SESSION_NAME $SYSCALL_LIST add_context_kernel_ok $SESSION_NAME channel0 pid start_lttng_tracing_ok diag "Expect segfaults" for i in $(seq 1 100); do yes | "$CURDIR"/select_poll_epoll --validation-file "$TEST_VALIDATION_OUTPUT_PATH" -t epoll_pwait_concurrent_munmap done stop_lttng_tracing_ok # epoll_wait is not always generated in the trace (stress test) validate_trace "epoll_ctl" "$TRACE_PATH" check_trace_content -t epoll_pwait_concurrent_munmap --validation-file "$TEST_VALIDATION_OUTPUT_PATH" "$TRACE_PATH" 2>/dev/null destroy_lttng_session_ok $SESSION_NAME rm -rf "$TRACE_PATH" rm -f "$TEST_VALIDATION_OUTPUT_PATH" } # MUST set TESTDIR before calling those functions plan_tests $NUM_TESTS print_test_banner "$TEST_DESC" # Only run this test on x86 and arm uname -m | grep -E "x86|i686|arm|aarch64" >/dev/null 2>&1 if test $? != 0; then skip 0 "Run only on x86 and arm. Skipping all tests." $NUM_TESTS exit 0 fi diag "Supported syscalls are $SUPPORTED_SYSCALLS_LIST" check_skip_kernel_test "$NUM_TESTS" "Skipping all tests." || { validate_lttng_modules_present start_lttng_sessiond test_working_cases test_timeout_cases test_pselect_invalid_fd test_ppoll_big test_ppoll_fds_buffer_overflow test_pselect_invalid_pointer test_ppoll_fds_ulong_max test_epoll_pwait_invalid_pointer test_epoll_pwait_fds_int_max test_ppoll_concurrent_write test_epoll_pwait_concurrent_unmap stop_lttng_sessiond NEW_WARNING=$(dmesg | grep " WARNING:" | cut -d' ' -f1 | tail -1) NEW_OOPS=$(dmesg | grep " OOPS:" | cut -d' ' -f1 | tail -1) NEW_BUG=$(dmesg | grep " BUG:" | cut -d' ' -f1 | tail -1) if test "$LAST_WARNING" != "$NEW_WARNING"; then diag "Last WARNING before tests: ${LAST_WARNING}" diag "Last WARNING after tests: ${NEW_WARNING}" fail "New WARNING generated" fi if test "$LAST_OOPS" != "$NEW_OOPS"; then diag "Last OOPS before tests: ${LAST_OOPS}" diag "Last OOPS after tests: ${NEW_OOPS}" fail "New OOPS generated" fi if test "$LAST_BUG" != "$NEW_BUG"; then diag "Last BUG before tests: ${LAST_BUG}" diag "Last BUG after tests: ${NEW_BUG}" fail "New BUG generated" fi }