Commit 3dc856d1 authored by fangzongwu's avatar fangzongwu

1)upload syscall_intercept source code

parent 090d45f0
name: CMake
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: [ubuntu-20.04]
steps:
- uses: actions/checkout@v3
- name: Install Packages
run: sudo apt-get install -y build-essential pkg-config libcapstone-dev
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}
tags
/.project
/.cproject
/.settings
/build-deb
/syscall_intercept-*.tar.gz
language: c
dist: bionic
addons:
apt:
packages:
- libcapstone-dev
- pandoc
services:
- docker
env:
jobs:
- PUSH_IMAGE=1 MAKE_PKG=1 OS=ubuntu OS_VER=16.04
- PUSH_IMAGE=1 MAKE_PKG=1 OS=fedora OS_VER=25
- MAKE_PKG=0 OS=ubuntu OS_VER=16.04 C_COMPILER=clang CPP_COMPILER=clang++
- MAKE_PKG=0 OS=fedora OS_VER=25 C_COMPILER=clang CPP_COMPILER=clang++
- MAKE_PKG=0 OS=ubuntu OS_VER=16.04
- MAKE_PKG=0 OS=fedora OS_VER=25
- MAKE_PKG=0 CAPSTONE_EXPERIMENTAL=1 OS=ubuntu OS_VER=16.04
- COVERITY=1 OS=ubuntu OS_VER=16.04
- COVERAGE=1 OS=ubuntu OS_VER=16.04
- NO_DOCKER=1 CMAKE_BUILD_TYPE=Release
- NO_DOCKER=1 CMAKE_BUILD_TYPE=Debug
before_install:
- if [[ $NO_DOCKER -ne 1 ]]; then pwd ; ls ; source travis_prepare_docker.sh ; fi
script:
- if [[ $NO_DOCKER -eq 1 ]]; then source travis_simple_build.sh ; else source build.sh ; fi
after_success:
- if [[ $PUSH_THE_IMAGE -eq 1 ]]; then images/push-image.sh $OS-$OS_VER; fi
#
# Copyright 2017-2020, Intel Corporation
#
# 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 the copyright holder 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 THE COPYRIGHT
# OWNER 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.
cmake_minimum_required(VERSION 3.3)
project(syscall_intercept C ASM)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
# Setting CMAKE_DISABLE_IN_SOURCE_BUILD to ON should
# disallow in source builds, but in practice it doesn't seem
# to disallow it. Check the paths as well:
if(",${CMAKE_SOURCE_DIR}," STREQUAL ",${CMAKE_BINARY_DIR},")
message(FATAL_ERROR "In-source builds are not supported.")
endif()
option(PERFORM_STYLE_CHECKS
"check coding style, license headers (requires perl)" ON)
option(BUILD_TESTS "build and enable tests" ON)
option(BUILD_EXAMPLES "build examples" ON)
option(TREAT_WARNINGS_AS_ERRORS
"make the build fail on any warnings during compilation, or linking" ON)
option(EXPECT_SPURIOUS_SYSCALLS
"account for some unexpected syscalls in tests - enable while using sanitizers, gcov" OFF)
option(STATIC_CAPSTONE "statically link libcapstone into the shared library" OFF)
find_program(CTAGS ctags)
if(CTAGS)
option(AUTO_RUN_CTAGS "create tags file every on every rebuild" ON)
endif()
set(TEST_EXTRA_PRELOAD "" CACHE STRING "path to preloadable lib used while running tests e.g.: /usr/lib/gcc/x86_64-linux-gnu/6/libasan.so")
set(SYSCALL_INTERCEPT_VERSION_MAJOR 0)
set(SYSCALL_INTERCEPT_VERSION_MINOR 1)
set(SYSCALL_INTERCEPT_VERSION_PATCH 0)
set(SYSCALL_INTERCEPT_VERSION
${SYSCALL_INTERCEPT_VERSION_MAJOR}.${SYSCALL_INTERCEPT_VERSION_MINOR}.${SYSCALL_INTERCEPT_VERSION_PATCH})
if (NOT DEFINED capstone_LIBRARIES AND NOT DEFINED capstone_INCLUDEDIR AND NOT DEFINED capstone_LIBRARIES_PATH)
include(cmake/find_capstone.cmake)
else()
include_directories(${capstone_INCLUDEDIR})
link_directories(${capstone_LIBRARIES_PATH})
endif()
include(GNUInstallDirs)
include(cmake/toolchain_features.cmake)
include(CheckLanguage)
# main source files - intentionally excluding src/cmdline_filter.c
set(SOURCES_C
src/disasm_wrapper.c
src/intercept.c
src/intercept_desc.c
src/intercept_log.c
src/intercept_util.c
src/patcher.c
src/magic_syscalls.c
src/syscall_formats.c)
set(SOURCES_ASM
src/intercept_template.S
src/util.S
src/intercept_wrapper.S)
include_directories(include)
link_directories(${capstone_LIBRARY_DIRS})
add_compile_options(-fPIC)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Main object files of the library, the entry point in entry.c
# is only built into the final libraries. This way, testing code
# can use the internal interface of the libraries (linking
# with syscall_intercept_base instead of the actual lib ), without
# the library trying to hotpatch libc every time.
add_library(syscall_intercept_base_c OBJECT ${SOURCES_C})
add_library(syscall_intercept_base_asm OBJECT ${SOURCES_ASM})
add_library(syscall_intercept_base_clf OBJECT src/cmdline_filter.c)
if(HAS_NOUNUSEDARG)
target_compile_options(syscall_intercept_base_asm BEFORE
PRIVATE "-Wno-unused-command-line-argument")
endif()
set_property(TARGET syscall_intercept_base_c
APPEND PROPERTY COMPILE_FLAGS ${capstone_CFLAGS})
add_library(syscall_intercept_unscoped STATIC
$<TARGET_OBJECTS:syscall_intercept_base_c>
$<TARGET_OBJECTS:syscall_intercept_base_asm>
$<TARGET_OBJECTS:syscall_intercept_base_clf>)
set(syscall_intercept_unscoped_a $<TARGET_FILE:syscall_intercept_unscoped>)
add_custom_command(
OUTPUT syscall_intercept_unscoped.o
COMMAND ${CMAKE_LINKER}
-r --whole-archive ${syscall_intercept_unscoped_a}
-o syscall_intercept_unscoped.o
DEPENDS syscall_intercept_unscoped)
add_custom_command(
OUTPUT syscall_intercept_scoped.o
COMMAND ${CMAKE_OBJCOPY}
--localize-hidden
syscall_intercept_unscoped.o
syscall_intercept_scoped.o
DEPENDS syscall_intercept_unscoped.o)
add_custom_target(generate_syscall_intercept_scoped
DEPENDS syscall_intercept_scoped.o)
add_library(syscall_intercept_shared SHARED syscall_intercept_scoped.o)
add_library(syscall_intercept_static STATIC syscall_intercept_scoped.o)
add_dependencies(syscall_intercept_shared generate_syscall_intercept_scoped)
add_dependencies(syscall_intercept_static generate_syscall_intercept_scoped)
set_target_properties(syscall_intercept_base_c
PROPERTIES C_VISIBILITY_PRESET hidden)
set(CAPSTONE_LINK_MODE "-Bdynamic")
if (STATIC_CAPSTONE)
set(CAPSTONE_LINK_MODE "-Bstatic")
endif()
target_link_libraries(syscall_intercept_shared
PRIVATE ${CMAKE_DL_LIBS}
"-Wl,--push-state,${CAPSTONE_LINK_MODE} -lcapstone -Wl,--pop-state"
"-Wl,--version-script=${CMAKE_SOURCE_DIR}/version.map")
target_link_libraries(syscall_intercept_static
INTERFACE ${CMAKE_DL_LIBS} ${capstone_LIBRARIES})
set_target_properties(syscall_intercept_shared
PROPERTIES VERSION ${SYSCALL_INTERCEPT_VERSION}
SOVERSION ${SYSCALL_INTERCEPT_VERSION_MAJOR})
set_target_properties(syscall_intercept_shared syscall_intercept_static
PROPERTIES
LINKER_LANGUAGE C
PUBLIC_HEADER "include/libsyscall_intercept_hook_point.h"
OUTPUT_NAME syscall_intercept)
check_language(CXX)
if(CMAKE_CXX_COMPILER)
enable_language(CXX)
add_executable(cpp_test src/cpp_compile_test.cc src/cpp_compile_mock.c)
add_dependencies(syscall_intercept_base_c cpp_test)
endif()
if(PERFORM_STYLE_CHECKS)
include(FindPerl)
if(${PERL_FOUND})
add_custom_target(cstyle
COMMAND ${PERL_EXECUTABLE} ${PROJECT_SOURCE_DIR}/utils/cstyle.pl
-pP ${PROJECT_SOURCE_DIR}/src/*.[ch]
${PROJECT_SOURCE_DIR}/include/*.h
${PROJECT_SOURCE_DIR}/test/*.c
${PROJECT_SOURCE_DIR}/examples/*.c)
add_custom_target(check_whitespace
COMMAND ${PERL_EXECUTABLE} ${PROJECT_SOURCE_DIR}/utils/check_whitespace.pl
-r ${PROJECT_SOURCE_DIR}/src)
add_dependencies(syscall_intercept_base_c cstyle check_whitespace)
else()
message(FATAL_ERROR
"Perl not found. Perl is required for checking coding style. "
"To disable such checks, build with PERFORM_STYLE_CHECKS=OFF.")
endif()
add_executable(check_license_executable utils/check_license/check-license.c)
add_custom_target(check-license
COMMAND
${PROJECT_SOURCE_DIR}/utils/check_license/check-headers.sh
${PROJECT_SOURCE_DIR}
$<TARGET_FILE:check_license_executable>
${PROJECT_SOURCE_DIR}/LICENSE -a)
add_dependencies(check-license check_license_executable)
endif()
configure_file(libsyscall_intercept.pc.in libsyscall_intercept.pc)
install(TARGETS syscall_intercept_shared syscall_intercept_static
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${CMAKE_BINARY_DIR}/libsyscall_intercept.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake")
add_subdirectory(doc)
if(AUTO_RUN_CTAGS)
add_custom_target(gen_ctags ALL
${CTAGS} -R ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/test)
endif()
if(BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if(BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif()
Copyright 2016-2017, Intel Corporation
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 the copyright holder 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 THE COPYRIGHT
OWNER 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.
Everything in this source tree is covered by the previous license
with the following exceptions:
* utils/cstyle (used only during development) licensed under CDDL.
* cmake/cmake_uninstall.cmake.in licensed under Creative Commons.
This diff is collapsed.
# From: https://cmake.org/Wiki/CMake_FAQ
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)
#
# Copyright 2017, Intel Corporation
#
# 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 the copyright holder 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 THE COPYRIGHT
# OWNER 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.
find_package(capstone QUIET)
if(NOT capstone_FOUND)
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_search_module(capstone capstone QUIET)
endif()
endif()
if(NOT capstone_FOUND)
message(FATAL_ERROR
"Unable to find capstone. Please install pkg-config and capstone development files, e.g.:
sudo apt-get install pkg-config libcapstone-dev (on Debian, Ubuntu)
or
sudo dnf install capstone-devel (on Fedora)
or see instructions for other ways of installing capstone: http://www.capstone-engine.org/download.html
If casptone is installed, but cmake didn't manage to find it, there is a slight chance of fixing things by setting some of the following environment variables:
PKG_CONFIG_PATH, CMAKE_PREFIX_PATH, CMAKE_MODULE_PATH")
endif()
/* Used in toolchain_features.cmake */
#pragma GCC system_header
#
# Copyright 2017, Intel Corporation
#
# 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 the copyright holder 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 THE COPYRIGHT
# OWNER 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.
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckCSourceCompiles)
include(CheckIncludeFiles)
include(CheckFunctionExists)
if (NOT CMAKE_VERSION VERSION_LESS 3.1.0)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 11)
else()
check_c_compiler_flag(-std=c99 HAS_STDC99)
if(HAS_STDC99)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
else()
check_c_compiler_flag(-std=gnu99 HAS_STDGNU99)
if(HAS_STDGNU99)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
endif()
endif()
check_cxx_compiler_flag(-std=c++11 HAS_STDCPP11)
if(HAS_STDCPP11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
endif()
check_c_compiler_flag(-Werror HAS_WERROR)
check_c_compiler_flag(-Wall HAS_WALL)
check_c_compiler_flag(-Wextra HAS_WEXTRA)
check_c_compiler_flag(-pedantic HAS_PEDANTIC)
check_c_compiler_flag(-Wno-missing-field-initializers HAS_NOMFI)
check_c_compiler_flag(-Wno-c90-c99-compat HAS_NO9099)
check_c_compiler_flag(-Wl,-nostdlib LINKER_HAS_NOSTDLIB)
check_c_compiler_flag(-Wl,--fatal-warnings HAS_WLFATAL)
check_c_compiler_flag(-Wno-unused-command-line-argument HAS_NOUNUSEDARG)
check_c_compiler_flag(-pie HAS_ARG_PIE)
check_c_compiler_flag(-nopie HAS_ARG_NOPIE)
check_c_compiler_flag(-no-pie HAS_ARG_NO_PIE)
if(HAS_WERROR AND TREAT_WARNINGS_AS_ERRORS)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
endif()
if(HAS_WLFATAL AND TREAT_WARNINGS_AS_ERRORS)
set(CMAKE_LD_FLAGS ${CMAKE_LD_FLAGS} -Wl,--fatal-warnings)
endif()
if(HAS_WALL)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
endif()
if(HAS_WEXTRA)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
endif()
if(HAS_PEDANTIC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic")
endif()
if(HAS_NO9099)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-c90-c99-compat")
endif()
if("${CMAKE_C_COMPILER_ID}" MATCHES "Clang" AND HAS_NOMFI)
# See: https://llvm.org/bugs/show_bug.cgi?id=21689
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -Wno-missing-field-initializers")
endif()
# Hack, adding _GNU_SOURCE macro is just hardwired here for now.
# XXX: only do it when building with glibc.
# The only possible target in the foreseeable future is GNU/Linux x86_64
# so it doesn't matter.
# The only library extension used is dlinfo.
add_definitions(-D_GNU_SOURCE)
# GNUC extension
check_c_source_compiles("
static __attribute__((constructor)) void
entry_point(void) {}
int main(void) { return 0; }
"
HAS_GCC_ATTR_CONSTR)
if(NOT HAS_GCC_ATTR_CONSTR)
message(FATAL_ERROR "constructor attribute support required")
endif()
# GNUC extension -- system header pragma
set(orig_req_incs ${CMAKE_REQUIRED_INCLUDES})
set(CMAKE_REQUIRED_INCLUDES
"${CMAKE_REQUIRED_INCLUDES} ${PROJECT_SOURCE_DIR}/cmake")
check_c_source_compiles("
#include \"test_header.h\"
int main(void) { return 0; }
"
HAS_GCC_PRAGMA_SYSH)
set(CMAKE_REQUIRED_INCLUDES ${orig_req_incs})
if(HAS_GCC_PRAGMA_SYSH)
add_definitions(-DHAS_GCC_PRAGMA_SYSH)
endif()
# elf.h -- syscall_intercept can only decode ELFs
check_include_files(elf.h HAS_ELF_H)
if(NOT HAS_ELF_H)
message(FATAL_ERROR "elf.h not found")
endif()
# dladdr -- GNU libc extension
set(orig_req_libs ${CMAKE_REQUIRED_LIBRARIES})
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS})
check_function_exists(dladdr HAS_DLADDR)
set(CMAKE_REQUIRED_LIBRARIES ${orig_req_libs})
if(NOT HAS_DLADDR)
message(FATAL_ERROR "dladdr not found")
endif()
ignore:
- utils/check_license/check-license.c
- src/cpp_compile_mock.c
- src/cpp_compile_test.cc
- examples/icap.c
- examples/fork_ban.c
- test/
syscall-intercept (0.1-1) UNRELEASED; urgency=medium
* Initial release.
-- Marcin Ślusarz <marcin.slusarz@intel.com> Mon, 13 Feb 2017 13:31:12 +0100
Source: syscall-intercept
Maintainer: Marcin Ślusarz <marcin.slusarz@intel.com>
Section: misc
Priority: optional
Standards-version: 3.9.8
Build-Depends: cmake (>= 3.3), debhelper (>= 9), libcapstone-dev (>= 3.0), pkg-config
Package: libsyscall-intercept0
Architecture: amd64
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: System call intercepting library
The system call intercepting library provides a low-level interface
for hooking Linux system calls in user space. This is achieved
by hotpatching the machine code of the standard C library in the
memory of a process. The user of this library can provide the
functionality of almost any syscall in user space, using the very
simple API specified in the libsyscall_intercept_hook_point.h header file.
Package: libsyscall-intercept-dev
Section: libdevel
Architecture: amd64
Depends: ${misc:Depends}, libsyscall-intercept0 (=${binary:Version})
Description: Development files for libsyscall_intercept
Development files for libsyscall_intercept library.
Copyright 2016-2017, Intel Corporation
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 the copyright holder 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 THE COPYRIGHT
OWNER 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.
usr/lib/*/pkgconfig/libsyscall_intercept.pc
usr/lib/*/libsyscall_intercept.so
usr/lib/*/libsyscall_intercept.a
usr/include/libsyscall_intercept_hook_point.h
# https://lintian.debian.org/tags/new-package-should-close-itp-bug.html
new-package-should-close-itp-bug
# https://lintian.debian.org/tags/new-package-should-close-itp-bug.html
new-package-should-close-itp-bug
# https://lintian.debian.org/tags/shlib-with-executable-stack.html
# by design
shlib-with-executable-stack usr/lib/x86_64-linux-gnu/libsyscall_intercept.so.0.1.0
#!/usr/bin/make -f
#export DH_VERBOSE=1
%:
dh $@ --buildsystem=cmake
#
# Copyright 2017, Intel Corporation
#
# 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 the copyright holder 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 THE COPYRIGHT
# OWNER 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.
find_program(PANDOC pandoc)
if (NOT PANDOC)
message(WARNING "pandoc not found")
endif()
add_custom_target(manpages)
function(generate_manpage name)
add_custom_target(manpage-${name}
COMMAND ${CMAKE_SOURCE_DIR}/utils/md2man.sh
${CMAKE_CURRENT_SOURCE_DIR}/${name}.md
${CMAKE_CURRENT_SOURCE_DIR}/default.man
${CMAKE_CURRENT_SOURCE_DIR}/generated/${name})
add_dependencies(manpages manpage-${name})
endfunction()
generate_manpage(libsyscall_intercept.3)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/generated/libsyscall_intercept.3
DESTINATION ${CMAKE_INSTALL_MANDIR}/man3 CONFIGURATIONS Release None)
$if(has-tables)$
.\"t
$endif$
$if(pandoc-version)$
.\" Automatically generated by Pandoc $pandoc-version$
.\"
$endif$
$if(adjusting)$
.ad $adjusting$
$endif$
.TH "$title$" "$section$" "$version$" "$date$" "$footer$" "$header$"
$if(hyphenate)$
.hy
$else$
.nh \" Turn off hyphenation by default.
$endif$
$for(header-includes)$
$header-includes$
$endfor$
.\" Copyright 2016-$year$, Intel Corporation
.\"
.\" 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 the copyright holder 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 THE COPYRIGHT
.\" OWNER 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.
$for(include-before)$
$include-before$
$endfor$
$body$
$for(include-after)$
$include-after$
$endfor$
$if(author)$
.SH AUTHORS
$for(author)$$author$$sep$; $endfor$.
$endif$
.\" Automatically generated by Pandoc 1.17.2
.\"
.TH "libsyscall_intercept" "3" "syscall_intercept API version 0.1.0" "" "" ""
.hy
.\" Copyright 2016-2017, Intel Corporation
.\"
.\" 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 the copyright holder 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 THE COPYRIGHT
.\" OWNER 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.
.SH NAME
.PP
\f[B]libsyscall_intercept\f[] \-\- User space syscall intercepting
library
.SH SYNOPSIS
.IP
.nf
\f[C]
#include\ <libsyscall_intercept_hook_point.h>
\f[]
.fi
.IP
.nf
\f[C]
cc\ \-lsyscall_intercept\ \-fpic\ \-shared\ source.c\ \-o\ preloadlib.so
LD_PRELOAD=preloadlib.so\ ./application
\f[]
.fi
.SH DESCRIPTION
.PP
The system call intercepting library provides a low\-level interface for
hooking Linux system calls in user space.
This is achieved by hotpatching the machine code of the standard C
library in the memory of a process.
The user of this library can provide the functionality of almost any
syscall in user space, using the very simple API specified in the
libsyscall_intercept_hook_point.h header file:
.IP
.nf
\f[C]
int\ (*intercept_hook_point)(long\ syscall_number,
\ \ \ \ \ \ \ \ \ \ \ \ long\ arg0,\ long\ arg1,
\ \ \ \ \ \ \ \ \ \ \ \ long\ arg2,\ long\ arg3,
\ \ \ \ \ \ \ \ \ \ \ \ long\ arg4,\ long\ arg5,
\ \ \ \ \ \ \ \ \ \ \ \ long\ *result);
\f[]
.fi
.PP
The user of the library shall assign to the variable called
intercept_hook_point a pointer to the address of a callback function.
A non\-zero return value returned by the callback function is used to
signal to the intercepting library that the specific system call was
ignored by the user and the original syscall should be executed.
A zero return value signals that the user takes over the system call.
In this case, the result of the system call (the value stored in the RAX
register after the system call) can be set via the *result pointer.
In order to use the library, the intercepting code is expected to be
loaded using the LD_PRELOAD feature provided by the system loader.
.PP
All syscalls issued by libc are intercepted.
Syscalls made by code outside libc are not intercepted.
In order to be able to issue syscalls that are not intercepted, a
convenience function is provided by the library:
.IP
.nf
\f[C]
long\ syscall_no_intercept(long\ syscall_number,\ ...);
\f[]
.fi
.PP
In addition to hooking syscalls before they would be called, the API has
one special hook point that is executed after thread creation, right
after a clone syscall creating a thread returns in a child thread:
.IP
.nf
\f[C]
void\ (*intercept_hook_point_clone_child)(void);
\f[]
.fi
.PP
Using \f[C]intercept_hook_point_clone_child\f[], one can be notified of
thread creations.
.PP
To make it easy to detect syscall return values indicating errors, one
can use the syscall_error_code function:
.IP
.nf
\f[C]
int\ syscall_error_code(long\ result);
\f[]
.fi
.PP
When passed a return value from syscall_no_intercept, this function can
translate it to an error code equivalent to a libc error code:
.IP
.nf
\f[C]
int\ fd\ =\ (int)syscall_no_intercept(SYS_open,\ "file",\ O_RDWR);
if\ (syscall_error_code(fd)\ !=\ 0)
\ \ \ \ fprintf(stderr,\ strerror(syscall_error_code(fd)));
\f[]
.fi
.SH ENVIRONMENT VARIABLES
.PP
Three environment variables control the operation of the library:
.PP
\f[I]INTERCEPT_LOG\f[] \-\- when set, the library logs each syscall
intercepted to a file.
If it ends with "\-" the path of the file is formed by appending a
process id to the value provided in the environment variable.
E.g.: initializing the library in a process with pid 123 when the
INTERCEPT_LOG is set to "intercept.log\-" will result in a log file
named intercept.log\-123.
.PP
*INTERCEPT_LOG_TRUNC \-\- when set to 0, the log file from INTERCEPT_LOG
is not truncated.
.PP
\f[I]INTERCEPT_HOOK_CMDLINE_FILTER\f[] \-\- when set, the library checks
the contents of the /proc/self/cmdline file.
Hotpatching, and syscall intercepting is only done, if the last
component of the first zero terminated string in /proc/self/cmdline
matches the string provided in the environment variable.
This can also be queried by the user of the library:
.IP
.nf
\f[C]
int\ syscall_hook_in_process_allowed(void);
\f[]
.fi
.SH EXAMPLE
.IP
.nf
\f[C]
#include\ <libsyscall_intercept_hook_point.h>
#include\ <syscall.h>
#include\ <errno.h>
static\ int
hook(long\ syscall_number,
\ \ \ \ \ \ \ \ \ \ \ \ long\ arg0,\ long\ arg1,
\ \ \ \ \ \ \ \ \ \ \ \ long\ arg2,\ long\ arg3,
\ \ \ \ \ \ \ \ \ \ \ \ long\ arg4,\ long\ arg5,
\ \ \ \ \ \ \ \ \ \ \ \ long\ *result)
{
\ \ \ \ if\ (syscall_number\ ==\ SYS_getdents)\ {
\ \ \ \ \ \ \ \ /*
\ \ \ \ \ \ \ \ \ *\ Prevent\ the\ application\ from
\ \ \ \ \ \ \ \ \ *\ using\ the\ getdents\ syscall.\ From
\ \ \ \ \ \ \ \ \ *\ the\ point\ of\ view\ of\ the\ calling
\ \ \ \ \ \ \ \ \ *\ process,\ it\ is\ as\ if\ the\ kernel
\ \ \ \ \ \ \ \ \ *\ would\ return\ the\ ENOTSUP\ error
\ \ \ \ \ \ \ \ \ *\ code\ from\ the\ syscall.
\ \ \ \ \ \ \ \ \ */
\ \ \ \ \ \ \ \ *result\ =\ \-ENOTSUP;
\ \ \ \ \ \ \ \ return\ 0;
\ \ \ \ }\ else\ {
\ \ \ \ \ \ \ \ /*
\ \ \ \ \ \ \ \ \ *\ Ignore\ any\ other\ syscalls
\ \ \ \ \ \ \ \ \ *\ i.e.:\ pass\ them\ on\ to\ the\ kernel
\ \ \ \ \ \ \ \ \ *\ as\ would\ normally\ happen.
\ \ \ \ \ \ \ \ \ */
\ \ \ \ \ \ \ \ return\ 1;
\ \ \ \ }
}
static\ __attribute__((constructor))\ void
init(void)
{
\ \ \ \ //\ Set\ up\ the\ callback\ function
\ \ \ \ intercept_hook_point\ =\ hook;
}
\f[]
.fi
.IP
.nf
\f[C]
$\ cc\ example.c\ \-lsyscall_intercept\ \-fpic\ \-shared\ \-o\ example.so
$\ LD_LIBRARY_PATH=.\ LD_PRELOAD=example.so\ ls
ls:\ reading\ directory\ \[aq].\[aq]:\ Operation\ not\ supported
\f[]
.fi
.SH SEE ALSO
.PP
\f[B]syscall\f[](2)
---
layout: manual
Content-Style: 'text/css'
title: libsyscall_intercept(3)
header: SYSCALL_INTERCEPT
date: syscall_intercept API version 0.1.0
...
[comment]: <> (Copyright 2017, Intel Corporation)
[comment]: <> (Redistribution and use in source and binary forms, with or without)
[comment]: <> (modification, are permitted provided that the following conditions)
[comment]: <> (are met:)
[comment]: <> ( * Redistributions of source code must retain the above copyright)
[comment]: <> ( notice, this list of conditions and the following disclaimer.)
[comment]: <> ( * Redistributions in binary form must reproduce the above copyright)
[comment]: <> ( notice, this list of conditions and the following disclaimer in)
[comment]: <> ( the documentation and/or other materials provided with the)
[comment]: <> ( distribution.)
[comment]: <> ( * Neither the name of the copyright holder nor the names of its)
[comment]: <> ( contributors may be used to endorse or promote products derived)
[comment]: <> ( from this software without specific prior written permission.)
[comment]: <> (THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS)
[comment]: <> ("AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT)
[comment]: <> (LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR)
[comment]: <> (A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT)
[comment]: <> (OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,)
[comment]: <> (SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT)
[comment]: <> (LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,)
[comment]: <> (DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY)
[comment]: <> (THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT)
[comment]: <> ((INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE)
[comment]: <> (OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.)
[comment]: <> (libsyscall_intercept.3 -- man page for libsyscall_intercept)
[NAME](#name)<br />
[SYNOPSIS](#synopsis)<br />
[DESCRIPTION](#description)<br />
[ENVIRONMENT VARIABLES](#environment-variables)<br />
[EXAMPLE](#example)<br />
[SEE ALSO](#see-also)
# NAME #
**libsyscall_intercept** -- User space syscall intercepting library
# SYNOPSIS #
```c
#include <libsyscall_intercept_hook_point.h>
```
```sh
cc -lsyscall_intercept -fpic -shared source.c -o preloadlib.so
LD_PRELOAD=preloadlib.so ./application
```
# DESCRIPTION #
The system call intercepting library provides a low-level interface
for hooking Linux system calls in user space. This is achieved
by hotpatching the machine code of the standard C library in the
memory of a process. The user of this library can provide the
functionality of almost any syscall in user space, using the very
simple API specified in the libsyscall_intercept\_hook\_point.h header file:
```c
int (*intercept_hook_point)(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result);
```
The user of the library shall assign to the variable called
intercept_hook_point a pointer to the address of a callback function.
A non-zero return value returned by the callback function is used
to signal to the intercepting library that the specific system
call was ignored by the user and the original syscall should be
executed. A zero return value signals that the user takes over the
system call. In this case, the result of the system call
(the value stored in the RAX register after the system call)
can be set via the \*result pointer. In order to use the library,
the intercepting code is expected to be loaded using the
LD_PRELOAD feature provided by the system loader.
All syscalls issued by libc are intercepted. Syscalls made
by code outside libc are not intercepted. In order to
be able to issue syscalls that are not intercepted, a
convenience function is provided by the library:
```c
long syscall_no_intercept(long syscall_number, ...);
```
In addition to hooking syscalls before they would be called, the API
has one special hook point that is executed after thread creation, right
after a clone syscall creating a thread returns in a child thread:
```c
void (*intercept_hook_point_clone_child)(void);
```
Using `intercept_hook_point_clone_child`, one can be notified of thread
creations.
To make it easy to detect syscall return values indicating errors, one
can use the syscall_error_code function:
```c
int syscall_error_code(long result);
```
When passed a return value from syscall_no_intercept, this function
can translate it to an error code equivalent to a libc error code:
```c
int fd = (int)syscall_no_intercept(SYS_open, "file", O_RDWR);
if (syscall_error_code(fd) != 0)
fprintf(stderr, strerror(syscall_error_code(fd)));
```
# ENVIRONMENT VARIABLES #
Three environment variables control the operation of the library:
*INTERCEPT_LOG* -- when set, the library logs each syscall intercepted
to a file. If it ends with "-" the path of the file is formed by appending
a process id to the value provided in the environment variable.
E.g.: initializing the library in a process with pid 123 when the
INTERCEPT_LOG is set to "intercept.log-" will result in a log file named
intercept.log-123.
*INTERCEPT_LOG_TRUNC -- when set to 0, the log file from INTERCEPT_LOG
is not truncated.
*INTERCEPT_HOOK_CMDLINE_FILTER* -- when set, the library
checks the contents of the /proc/self/cmdline file.
Hotpatching, and syscall intercepting is only done, if the
last component of the first zero terminated string in
/proc/self/cmdline matches the string provided
in the environment variable. This can also be queried
by the user of the library:
```c
int syscall_hook_in_process_allowed(void);
```
# EXAMPLE #
```c
#include <libsyscall_intercept_hook_point.h>
#include <syscall.h>
#include <errno.h>
static int
hook(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result)
{
if (syscall_number == SYS_getdents) {
/*
* Prevent the application from
* using the getdents syscall. From
* the point of view of the calling
* process, it is as if the kernel
* would return the ENOTSUP error
* code from the syscall.
*/
*result = -ENOTSUP;
return 0;
} else {
/*
* Ignore any other syscalls
* i.e.: pass them on to the kernel
* as would normally happen.
*/
return 1;
}
}
static __attribute__((constructor)) void
init(void)
{
// Set up the callback function
intercept_hook_point = hook;
}
```
```sh
$ cc example.c -lsyscall_intercept -fpic -shared -o example.so
$ LD_LIBRARY_PATH=. LD_PRELOAD=example.so ls
ls: reading directory '.': Operation not supported
```
# SEE ALSO #
**syscall**(2)
#
# Copyright 2017, Intel Corporation
#
# 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 the copyright holder 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 THE COPYRIGHT
# OWNER 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.
add_library(icap SHARED icap.c)
target_link_libraries(icap PRIVATE syscall_intercept_shared)
add_library(fork_ban SHARED fork_ban.c)
target_link_libraries(fork_ban PRIVATE syscall_intercept_shared)
add_library(syscall_logger SHARED syscall_logger.c syscall_desc.c)
target_link_libraries(syscall_logger PRIVATE syscall_intercept_shared)
/*
* Copyright 2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* fork_ban.c - Block forking new processes after a maximum number of
* forks.
* This library demonstrates a way to handle fork syscalls. In contrast
* to thread creation (for an example see test/test_clone_thread_preload.c)
* the fork can be done right inside of a hook routine.
*/
#include "libsyscall_intercept_hook_point.h"
#include <errno.h>
#include <stdbool.h>
#include <sched.h>
#include <syscall.h>
#include <stdlib.h>
#define FORK_MAX_COUNT 16
/*
* specifies_new_stack - does the syscall ask for a new stack?
*
* The second argument of a clone syscall specifies the
* top of a stack area for the new child thread/process.
* Zero is a special value, which means not using a new stack
* pointer. A fork() is expected to not change the stack
* pointer, but it is checked here anyways.
*/
static bool
specifies_new_stack(long syscall_number, long arg0, long arg1)
{
(void) arg0;
return syscall_number == SYS_clone && (arg1 != 0);
}
/*
* is_syscall_fork
* Is it a syscall creating a new process, that does not share virtual
* memory with the parent process?
*/
static bool
is_syscall_fork(long syscall_number, long arg0)
{
if (syscall_number == SYS_fork || syscall_number == SYS_vfork)
return true;
if (syscall_number == SYS_clone && (arg0 & CLONE_THREAD) == 0)
return true;
return false;
}
static int fork_counter; /* how many forks intercepted so far? */
/* how many are allowed to pass through, before blocking? */
static int fork_counter_max = FORK_MAX_COUNT;
static long
example_fork_hook(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5)
{
long result;
/* pass it on to the kernel */
result = syscall_no_intercept(syscall_number,
arg0, arg1, arg2, arg3, arg4, arg5);
if (fork_counter > 4 && result > 0) {
/*
* Messing with parent process: return wrong
* pid, just for fun.
*/
result += 16;
}
return result;
}
static int
hook(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result)
{
(void) arg2;
(void) arg3;
(void) arg4;
(void) arg5;
if (!is_syscall_fork(syscall_number, arg0))
return 1; /* ignore other syscalls */
if (fork_counter >= fork_counter_max) {
static const char msg[] = "fork count has exceeded maximum.\n";
syscall_no_intercept(SYS_write, 2, msg, sizeof(msg));
*result = -EAGAIN;
return 0;
}
++fork_counter;
if (specifies_new_stack(syscall_number, arg0, arg1)) {
/* Not messing with changing stack address */
return 1;
} else {
*result = example_fork_hook(syscall_number,
arg0, arg1, arg2, arg3, arg4, arg5);
return 0;
}
}
static __attribute__((constructor)) void
start(void)
{
const char *e = getenv("ALLOW_FORK_MAX");
if (e != NULL)
fork_counter_max = atoi(e);
intercept_hook_point = &hook;
}
/*
* Copyright 2016-2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* icap.c -- tiny syscall intercepting example library, turning every
* lower case letter 'i' to on upper case 'I' in buffers used in write syscalls.
*/
#include <stddef.h>
#include <string.h>
#include <syscall.h>
#include "libsyscall_intercept_hook_point.h"
static int hook(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result)
{
(void) arg3;
(void) arg4;
(void) arg5;
if (syscall_number == SYS_write) {
char buf_copy[0x1000];
size_t size = (size_t)arg2;
if (size > sizeof(buf_copy))
size = sizeof(buf_copy);
memcpy(buf_copy, (char *)arg1, size);
/* Capitalize the letter 'i', for fun */
for (size_t i = 0; i < size; ++i) {
if (buf_copy[i] == 'i')
buf_copy[i] = 'I';
}
*result = syscall_no_intercept(SYS_write, arg0, buf_copy, size);
return 0;
}
return 1;
}
static __attribute__((constructor)) void
start(void)
{
intercept_hook_point = &hook;
}
This diff is collapsed.
/*
* Copyright 2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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 SYSCALL_INTERCEPT_EXAMPLE_LOGGING_H
#define SYSCALL_INTERCEPT_EXAMPLE_LOGGING_H
enum arg_type {
arg_none,
arg_fd,
arg_atfd,
arg_cstr,
arg_open_flags,
arg_mode,
arg_ /* no special formatting implemented yet, print as hex number */
};
enum return_type {
rhex,
rdec,
runsigned,
rmode,
rnoreturn
};
struct syscall_desc {
const char *name;
enum return_type return_type;
enum arg_type args[6];
};
const struct syscall_desc *get_syscall_desc(long syscall_number,
const long args[static 6]);
#endif
This diff is collapsed.
/*
* Copyright 2016-2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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 LIBSYSCALL_INTERCEPT_HOOK_POINT_H
#define LIBSYSCALL_INTERCEPT_HOOK_POINT_H
/*
* The inteface for using the intercepting library.
* This callback function should be implemented by
* the code using the library.
*
* The syscall_number, and the six args describe the syscall
* currently being intercepted.
* A non-zero return value means libsyscall_intercept
* should execute the original syscall, use its result. A zero return value
* means libsyscall_intercept should not execute the syscall, and
* use the integer stored to *result as the result of the syscall
* to be returned in RAX to libc.
*/
#ifdef __cplusplus
extern "C" {
#endif
extern int (*intercept_hook_point)(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result);
extern void (*intercept_hook_point_clone_child)(void);
extern void (*intercept_hook_point_clone_parent)(long pid);
/*
* syscall_no_intercept - syscall without interception
*
* Call syscall_no_intercept to make syscalls
* from the interceptor library, once glibc is already patched.
* Don't use the syscall function from glibc, that
* would just result in an infinite recursion.
*/
long syscall_no_intercept(long syscall_number, ...);
/*
* syscall_error_code - examines a return value from
* syscall_no_intercept, and returns an error code if said
* return value indicates an error.
*/
static inline int
syscall_error_code(long result)
{
if (result < 0 && result >= -0x1000)
return (int)-result;
return 0;
}
/*
* The syscall intercepting library checks for the
* INTERCEPT_HOOK_CMDLINE_FILTER environment variable, with which one can
* control in which processes interception should actually happen.
* If the library is loaded in this process, but syscall interception
* is not allowed, the syscall_hook_in_process_allowed function returns zero,
* otherwise, it returns one. The user of the library can use it to notice
* such situations, where the code is loaded, but no syscall will be hooked.
*/
int syscall_hook_in_process_allowed(void);
#ifdef __cplusplus
}
#endif
#endif
prefix=@CMAKE_INSTALL_PREFIX@
libdir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@
version=@VERSION@
includedir=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@
Name: libsyscall_intercept
Description: libsyscall_intercept - system call intercepting library
Version: @VERSION@
URL: http://github.com/pmem/syscall_intercept
Requires.private: capstone
Libs: -L@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@ -lsyscall_intercept
Libs.private: -ldl
Cflags: -I@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@
# Assembly code used during interception #
### Introduction
This text is only valid in the context of the x86-64 ABI, and only on Linux.
One can not issue a jump from the place of a patched syscall instruction
to C function, due pesky ABI details. This is simply not supported, and is
only possible with taking some ISA specific knowledge, and some handwritten
assembly is required for this transition.
### Generating instances from intercept_template.s ###
The syscall instructions can't replaced with a call instruction (that could
ruin the stack by pushing a return value), and can't be returned to using a ret
instruction (the stack!). Thus the syscalls are replaced by jump instructions.
But the intercepting code must eventually jump back to the intercepted code,
and has no information about where that is. The solution is to jump to a
different destination from the place of each syscall, giving the intercepting
code the information about the origin of the jumps: its own address. Since all
jumps jump to different places, this can be used to infer the origin of those
jumps. The code in [intercept_template.s](intercept_template.s) serves
this purpose. Different instances are generated from this template to
different locations in memory, all of which are able to jump back to the
right address in the intercepted code. These instance are also equipped with
an another information specific to a syscall: a pointer to the
[struct patch_desc](intercept.h#L92) instance associated with the
particular patched syscall.
An illustration of this with two syscalls in a section of intercepted code:
```asm
0x0010 mov $2, %eax
0x0019 jmp $0x1100 # an overwritten syscall
0x0020 cmp $-4095, %rax
0x0026 jle $0x0100
0x0032 ret
0x0040 mov $3, %eax
0x0049 jmp $0x1200 # another overwritten syscall
0x0040 cmp $-4095, %rax
0x0049 jle $0x0100
0x0052 ret
```
This code has two jumps:
One jump to 0x1100, from where the intercepting code must jump back to 0x0020,
one jump to 0x1200, from where the intercepting code must jump back to 0x0040.
A simplifed version of the template in
[intercept_template.s](intercept_template.s#L65):
```asm
mov %rsp, %r11 # remember the original value of $rsp
sub $0x80, $rsp # respect the red zone
and $-32, %rsp # align the stack
sub $0x38, %rsp # allocate space for some locals
mov %r11, (%rsp) # save the original value of #rsp
mov $0x000000000000, %r11 # the address of a function to call
call *r11 # call into code common to all syscalls
mov (%rsp), %rsp # restore original %rsp, as it was in the intercepted code
```
Two copies of this template are generated, with some different additions, both
of which give eventually control to a function at address 0x3333330, and return
to the correct address:
```asm
0x1100 mov %rsp, %r11
0x1105 sub $0x80, $rsp
0x110a and $-32, %rsp
0x1110 sub $0x38, %rsp
0x1116 mov %r11, (%rsp)
0x111b mov $0x000003333330, %r11
0x113a call *%r11
0x1140 mov (%rsp), %rsp
0x1144 jmp absolute address 0x0020 # instruction appended to the template
...
0x1200 mov %rsp, %r11
0x1205 sub $0x80, $rsp
0x120a and $-32, %rsp
0x1210 sub $0x38, %rsp
0x1216 mov %r11, (%rsp)
0x121b mov $0x000003333330, %r11
0x113a call *%r11
0x1140 mov (%rsp), %rsp
0x1144 jmp absolute address 0x0040 # instruction appended to the template
```
Both copies of the template must be patched to contain the address of the
common function, and both are appended with a jump instruction.
### Life is difficult near a syscall instruction ###
The code around the syscall instruction does not expect a C function
to be executed at that point. There are some differences between the
two scenario, which must be hidden from the calling code.
One important difference is the set of registers being callee-saved,
and the set of caller-saved registers [[1]](#1-x86-64-abi). The code in
[intercept_wrapper.s](intercept_wrapper.s#L93) saves all registers
it can on the stack, and restores them before returning to the caller.
Recently both clang and GCC implemented a function attribute called
no_caller_saved_registers [[2]](#2-gcc-attributes) [[4]](#4-clang-attributes),
which could be used to solve this without handwritten assembly, but as of
September 2017 these new compiler versions are not widespread enough.
The stack pointer is not necessarily correctly
aligned [[1]](#1-x86-64-abi) for a C function call. This is easily fixed
in [intercept_template.s](intercept_template.s#L70).
It is very easy to think that the force_align_arg_pointer [[2]](#2-gcc-attributes)
function attribute available in GNUC can be used to solve this issue without
handwritten assembly, but that is not the case [[3]](#3-about-force-align-arg-pointer-function).
Also, the code aligns the stack to a 32 byte boundary, rather than the 16 byte
boundary required for regular C functions. This is because the AVX registers
are saved on this stack (if they are available).
If the syscall instruction is in a leaf function, the routine containing
it might be using the red zone [[1]](#1-x86-64-abi) for local variables.
This is also solved trivially in [intercept_template.s](intercept_template.s#L69)
by adjusting the stack pointer.
In the case of most syscalls, this first level wrapper code doesn't do anything
other than calling the other [intercept_wrapper](intercept_wrapper.s#L75), and
jumping back to the intercepted code, once everything is done.
### The attack of the clones ###
Following a clone syscall, the execution of a program might continue with
a different stack pointer (e.g. after creating a new thread). This poses a problem
when such a syscall is executed in the [intercept_routine](intercept.c#L650),
which is a C function. This function would attempt to log the result of the syscall,
then proceed to return to the calling side, which involves restoring the saved
registers. But the saved registers would be restored from a location
relative to the stack pointer. The result would be reading unspecified values
form the new stack location, and very likely a page fault.
To avoid this problem, this sort of clone syscall is not executed in the C
function. Instead, the C function returns without executing the syscall, and
of course without logging its result. It asks the assembly wrapper code to
execute the syscall in its original context - which means first restoring all
the registers, and then executing the syscall instead of returning to the caller
site. At this point, no stack is used (all registers are already restored), so
the syscall's modification of the stack pointer is not relevant. The process is
as follows:
1) The C intercept_routine [indicates](intercept.c#L646) this
special case to the asm wrappers, by returning 2 in the rdx register.
The register RDX is used because the C ABI allows return two values
(a struct) in RAX and RDX. Normally RAX is used as the return value of
a syscall, thus a second register is needed to indicate such special
cases.
2) The register saving/restoring wrapper in
[intercept_wrapper.s](intercept_wrapper.s#L183) passes on this value
to the next level assembly wrapper in R11 -- it restores the original value
of RDX from the stack, so it can't use RDX for RDX for this.
3) The next level assembly wrapper, which assumes the stack is already restored,
[examines](intercept_template.s#L80) the value in R11, and if it is 2,
[executes](intercept_template.s#L98) the clone syscall in its original
context i.e.: when all relevant registers, including the stack pointer are
as they were in the intercepted object.
The result of a successfull clone with a new stack pointer is the threads
executing simultaneously with their stack pointers pointing to different
addresses. But before returning to the intercepted library, it is useful to
notify the client of libsyscall_intercept about the result of the syscall,
and/or to log this result. To do this, the assembly wrappers go through the
process of saving registers, and calling a C function once again, simply by
jumping to back to the beginning of the wrapper code in
[intercept_template.s](intercept_template.s#L107). One difference in
this is case that the value of RAX is not a syscall number, but the result
of a clone syscall. Of course the hooking code would be able to figure this
out on its own, by just examining the value of RAX, so it is indicated by
calling a different C function: [intercept_routine_post_clone](intercept.c#L670).
Which function to call is controlled by another value passed in RCX, as seen in
the branch in [intercept_wrapper.s](intercept_wrapper.s#L165).
### Footnotes
###### [1] [x86-64 ABI](https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r252.pdf)
* Appendix A.2.1 "User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9."
* 3.2.2 "The end of the input argument area shall be aligned on a 16 byte boundary."
* 3.2.2 "The 128-byte area beyond the location pointed to by %rsp is considered to be reserved and shall not be modified by signal or interrupt handlers...This area is known as the red zone"
###### [2] [GCC attributes](https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html)
* "On x86 targets, the force_align_arg_pointer attribute may be applied to individual function definitions, generating an alternate prologue and epilogue that realigns the run-time stack if necessary."
###### [3] [about force-align-arg-pointer-function](http://clang-developers.42468.n3.nabble.com/Is-force-align-arg-pointer-function-attribute-supported-at-x86-td4057053.html)
###### [4] [clang attributes](https://clang.llvm.org/docs/AttributeReference.html)
/*
* Copyright 2016-2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* The syscall_intercept library might be compiled with stricter warning
* settings than what is by capstone developers. The system header pragma
* is used to make sure some diagnostics triggered by the capstone header
* don't break syscall_intercept build.
*/
#ifdef HAS_GCC_PRAGMA_SYSH
#pragma GCC system_header
#endif
#include <capstone.h>
/*
* Copyright 2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <syscall.h>
#include <fcntl.h>
#include <unistd.h>
#include "libsyscall_intercept_hook_point.h"
#include "intercept.h"
/*
* cmdline_match - match the last component of the path in cmdline
*/
static int
cmdline_match(const char *filter)
{
if (filter == NULL)
return 1;
size_t flen = strlen(filter);
size_t clen = strlen(cmdline);
if (flen > clen)
return 0; /* cmdline can't contain filter */
/*
* If cmdline is longer, it must end with a slash + filter:
* "./somewhere/a.out" matches "a.out"
* "./a.out" matches "a.out"
* "./xa.out" does not match "a.out"
*
* Of course if cmdline is not longer, the slash is not needed:
* "a.out" matches "a.out"
*/
if (clen > flen && cmdline[clen - flen - 1] != '/')
return 0;
return strcmp(cmdline + clen - flen, filter) == 0;
}
/*
* syscall_hook_in_process_allowed - checks if a filter should be applied
* for processes. If the users requests it (via an environment variable) the
* syscall interception should not be performed in the current process.
* This is part of syscall_intercept's public API.
*/
int
syscall_hook_in_process_allowed(void)
{
static bool is_decided;
static int result;
if (is_decided)
return result;
if (cmdline == NULL)
return 0;
result = cmdline_match(getenv("INTERCEPT_HOOK_CMDLINE_FILTER"));
is_decided = true;
return result;
}
/*
* Copyright 2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* check if the public header file is useable from C++
*
* These are mock definitions of symbols used in the
* cpp_compile_test.cc C++ source file. This way, it is verified that a C
* implementation can be linked correctly with a C++ code using the header,
* before building syscall_intercept.
*/
#include "libsyscall_intercept_hook_point.h"
int (*intercept_hook_point)(long syscall_number,
long arg0, long arg1,
long arg2, long arg3,
long arg4, long arg5,
long *result);
long
syscall_no_intercept(long syscall_number, ...)
{
(void) syscall_number;
return 0;
}
int
syscall_hook_in_process_allowed(void)
{
return 0;
}
/*
* Copyright 2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/* Check if the public header file is useable from C++ */
#include "libsyscall_intercept_hook_point.h"
int main()
{
intercept_hook_point = nullptr;
(void) syscall_no_intercept(0);
(void) syscall_hook_in_process_allowed();
}
/*
* Copyright 2016-2020, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* disasm_wrapper.c -- connecting the interceptor code
* to the disassembler code from the capstone project.
*
* See:
* http://www.capstone-engine.org/lang_c.html
*/
#include "intercept.h"
#include "intercept_util.h"
#include "disasm_wrapper.h"
#include <assert.h>
#include <string.h>
#include <syscall.h>
#include "capstone_wrapper.h"
struct intercept_disasm_context {
csh handle;
cs_insn *insn;
const unsigned char *begin;
const unsigned char *end;
};
/*
* nop_vsnprintf - A dummy function, serving as a callback called by
* the capstone implementation. The syscall_intercept library never makes
* any use of string representation of instructions, but there seems to no
* trivial way to use disassemble using capstone without it spending time
* on printing syscalls. This seems to be the most that can be done in
* this regard i.e. providing capstone with nop implementation of vsnprintf.
*/
static int
nop_vsnprintf()
{
return 0;
}
/*
* intercept_disasm_init -- should be called before disassembling a region of
* code. The context created contains the context capstone needs ( or generally
* the underlying disassembling library, if something other than capstone might
* be used ).
*
* One must pass this context pointer to intercept_disasm_destroy following
* a disassembling loop.
*/
struct intercept_disasm_context *
intercept_disasm_init(const unsigned char *begin, const unsigned char *end)
{
struct intercept_disasm_context *context;
context = xmmap_anon(sizeof(*context));
context->begin = begin;
context->end = end;
/*
* Initialize the disassembler.
* The handle here must be passed to capstone each time it is used.
*/
if (cs_open(CS_ARCH_X86, CS_MODE_64, &context->handle) != CS_ERR_OK)
xabort("cs_open");
/*
* Kindly ask capstone to return some details about the instruction.
* Without this, it only prints the instruction, and we would need
* to parse the resulting string.
*/
if (cs_option(context->handle, CS_OPT_DETAIL, CS_OPT_ON) != 0)
xabort("cs_option - CS_OPT_DETAIL");
/*
* Overriding the printing routine used by capstone,
* see comments above about nop_vsnprintf.
*/
cs_opt_mem x = {
.malloc = malloc,
.free = free,
.calloc = calloc,
.realloc = realloc,
.vsnprintf = nop_vsnprintf};
if (cs_option(context->handle, CS_OPT_MEM, (size_t)&x) != 0)
xabort("cs_option - CS_OPT_MEM");
if ((context->insn = cs_malloc(context->handle)) == NULL)
xabort("cs_malloc");
return context;
}
/*
* intercept_disasm_destroy -- see comments for above routine
*/
void
intercept_disasm_destroy(struct intercept_disasm_context *context)
{
cs_free(context->insn, 1);
cs_close(&context->handle);
xmunmap(context, sizeof(*context));
}
/*
* check_op - checks a single operand of an instruction, looking
* for RIP relative addressing.
*/
static void
check_op(struct intercept_disasm_result *result, cs_x86_op *op,
const unsigned char *code)
{
/*
* the address the RIP register is going to contain during the
* execution of this instruction
*/
const unsigned char *rip = code + result->length;
if (op->type == X86_OP_REG) {
if (op->reg == X86_REG_IP ||
op->reg == X86_REG_RIP) {
/*
* Example: mov %rip, %rax
*/
result->has_ip_relative_opr = true;
result->rip_disp = 0;
result->rip_ref_addr = rip;
}
if (result->is_jump) {
/*
* Example: jmp *(%rax)
*/
/*
* An indirect jump can't have arguments other
* than a register - therefore the asserts.
* ( I'm 99.99% sure this is true )
*/
assert(!result->is_rel_jump);
result->is_indirect_jump = true;
}
} else if (op->type == X86_OP_MEM) {
if (op->mem.base == X86_REG_IP ||
op->mem.base == X86_REG_RIP ||
op->mem.index == X86_REG_IP ||
op->mem.index == X86_REG_RIP ||
result->is_jump) {
result->has_ip_relative_opr = true;
assert(!result->is_indirect_jump);
if (result->is_jump)
result->is_rel_jump = true;
assert(op->mem.disp <= INT32_MAX);
assert(op->mem.disp >= INT32_MIN);
result->rip_disp = (int32_t)op->mem.disp;
result->rip_ref_addr = rip + result->rip_disp;
}
} else if (op->type == X86_OP_IMM) {
if (result->is_jump) {
assert(!result->is_indirect_jump);
result->has_ip_relative_opr = true;
result->is_rel_jump = true;
result->rip_ref_addr = (void *)op->imm;
result->rip_disp =
(int32_t)((unsigned char *)op->imm - rip);
}
}
}
/*
* intercept_disasm_next_instruction - Examines a single instruction
* in a text section. This is only a wrapper around capstone specific code,
* collecting data that can be used later to make decisions about patching.
*/
struct intercept_disasm_result
intercept_disasm_next_instruction(struct intercept_disasm_context *context,
const unsigned char *code)
{
static const unsigned char endbr64[] = {0xf3, 0x0f, 0x1e, 0xfa};
struct intercept_disasm_result result = {.address = code, 0, };
const unsigned char *start = code;
size_t size = (size_t)(context->end - code + 1);
uint64_t address = (uint64_t)code;
if (size >= sizeof(endbr64) &&
memcmp(code, endbr64, sizeof(endbr64)) == 0) {
result.is_set = true;
result.is_endbr = true;
result.length = 4;
#ifndef NDEBUG
result.mnemonic = "endbr64";
#endif
return result;
}
if (!cs_disasm_iter(context->handle, &start, &size,
&address, context->insn)) {
return result;
}
result.length = context->insn->size;
assert(result.length != 0);
result.is_syscall = (context->insn->id == X86_INS_SYSCALL);
result.is_call = (context->insn->id == X86_INS_CALL);
result.is_ret = (context->insn->id == X86_INS_RET);
result.is_rel_jump = false;
result.is_indirect_jump = false;
#ifndef NDEBUG
result.mnemonic = context->insn->mnemonic;
#endif
switch (context->insn->id) {
case X86_INS_JAE:
case X86_INS_JA:
case X86_INS_JBE:
case X86_INS_JB:
case X86_INS_JCXZ:
case X86_INS_JECXZ:
case X86_INS_JE:
case X86_INS_JGE:
case X86_INS_JG:
case X86_INS_JLE:
case X86_INS_JL:
case X86_INS_JMP:
case X86_INS_JNE:
case X86_INS_JNO:
case X86_INS_JNP:
case X86_INS_JNS:
case X86_INS_JO:
case X86_INS_JP:
case X86_INS_JRCXZ:
case X86_INS_JS:
case X86_INS_LOOP:
case X86_INS_CALL:
result.is_jump = true;
assert(context->insn->detail->x86.op_count == 1);
break;
case X86_INS_NOP:
result.is_nop = true;
break;
default:
result.is_jump = false;
break;
}
result.has_ip_relative_opr = false;
/*
* Loop over all operands of the instruction currently being decoded.
* These operands are decoded by capstone, and described in the
* context->insn->detail->x86.operands array.
*
* This operand checking serves multiple purposes:
* The destination of any jumping instruction is found here,
* The instructions using RIP relative addressing are found by this
* loop, e.g.: mov %rax, 0x36eb55d(%rip)
*
* Any instruction relying on the value of the RIP register can not
* be relocated ( including relative jumps, which naturally also
* rely on the RIP register ).
*/
for (uint8_t op_i = 0;
op_i < context->insn->detail->x86.op_count; ++op_i)
check_op(&result, context->insn->detail->x86.operands + op_i,
code);
result.is_lea_rip = (context->insn->id == X86_INS_LEA &&
result.has_ip_relative_opr);
if (result.is_lea_rip) {
/*
* Extract the four bits from the encoding, which
* specify the destination register.
*/
/* one bit from the REX prefix */
result.arg_register_bits = ((code[0] & 4) << 1);
/* three bits from the ModRM byte */
result.arg_register_bits |= ((code[2] >> 3) & 7);
}
result.is_set = true;
return result;
}
/*
* Copyright 2016-2020, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* Wrapper function to use with the disassembler.
* This should allow us to use a different disassembler,
* without changing the intercept.c source file.
*
* The result of disassembling deliberately lacks a lot
* of information about the instruction seen, to make it
* easy to interface a new disassembler.
*/
#ifndef INTERCEPT_DISASM_WRAPPER_H
#define INTERCEPT_DISASM_WRAPPER_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
struct intercept_disasm_result {
const unsigned char *address;
bool is_set;
bool is_syscall;
/* Length in bytes, zero if disasm was not successful. */
unsigned length;
/*
* Flag marking instructions that have a RIP relative address
* as an operand.
*/
bool has_ip_relative_opr;
/* as of now this only refers to endbr64 */
bool is_endbr;
/*
* Flag marking lea instructions setting a 64 bit register to a
* RIP relative address. They can be relocated -- but by simple memcpy.
*/
bool is_lea_rip;
/*
* The X86 encoding of 64 bit register being set in an instruction
* marked above as is_lea_rip.
*/
unsigned char arg_register_bits;
/* call instruction */
bool is_call;
bool is_jump;
/*
* The flag is_rel_jump marks any instruction that jumps, to
* a relative address encoded in its operand.
* This includes call as well.
*/
bool is_rel_jump;
bool is_indirect_jump;
bool is_ret;
bool is_nop;
/*
* Optional fields:
* The rip_disp field contains the displacement used in
* instructions referring to RIP relative addresses.
* The rip_ref_addr field contains the absolute address of
* such a reference, computed based on the rip_disp.
* These are only valid, when has_ip_relative_opr is true.
*/
int32_t rip_disp;
const unsigned char *rip_ref_addr;
#ifndef NDEBUG
const char *mnemonic;
#endif
};
struct intercept_disasm_context;
struct intercept_disasm_context *
intercept_disasm_init(const unsigned char *begin, const unsigned char *end);
void intercept_disasm_destroy(struct intercept_disasm_context *context);
struct intercept_disasm_result
intercept_disasm_next_instruction(struct intercept_disasm_context *context,
const unsigned char *code);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2016-2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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 INTERCEPT_LOG_H
#define INTERCEPT_LOG_H
#include <stddef.h>
struct patch_desc;
struct syscall_desc;
void intercept_setup_log(const char *path_base, const char *trunc);
void intercept_log(const char *buffer, size_t len);
enum intercept_log_result { KNOWN, UNKNOWN };
void intercept_log_syscall(const struct patch_desc *,
const struct syscall_desc *,
enum intercept_log_result result_known,
long result);
void intercept_log_close(void);
#endif
/*
* Copyright 2016-2017, Intel Corporation
*
* 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 the copyright holder 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 THE COPYRIGHT
* OWNER 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.
*/
/*
* intercept_template.s -- see asm_wrapper.md
*/
.global intercept_asm_wrapper_tmpl;
.hidden intercept_asm_wrapper_tmpl;
.global intercept_asm_wrapper_patch_desc_addr;
.hidden intercept_asm_wrapper_patch_desc_addr;
.global intercept_asm_wrapper_wrapper_level1_addr;
.hidden intercept_asm_wrapper_wrapper_level1_addr;
.global intercept_asm_wrapper_tmpl_end;
.hidden intercept_asm_wrapper_tmpl_end;
.text
/*
* Locals on the stack:
* 0(%rsp) the original value of %rsp, in the code around the syscall
* 8(%rsp) the pointer to the struct patch_desc instance
*
* The %rcx register controls which C function to call in intercept.c:
*
* if %rcx == 0 then call intercept_routine
* if %rcx == 1 then intercept_routine_post_clone
*
* This value in %rcx is passed to the function intercep_wrapper.
*
*
* Note: the subq instruction allocating stack for locals must not
* ruin the stack alignment. It must round up the number of bytes
* needed for locals.
*/
intercept_asm_wrapper_tmpl:
movq $0x0, %rcx /* choose intercept_routine */
0: movq %rsp, %r11 /* remember original rsp */
subq $0x80, %rsp /* avoid the red zone */
andq $-16, %rsp /* align the stack */
subq $0x20, %rsp /* allocate stack for some locals */
movq %r11, (%rsp) /* orignal rsp on stack */
intercept_asm_wrapper_patch_desc_addr:
movabsq $0x000000000000, %r11
movq %r11, 0x8 (%rsp) /* patch_desc pointer on stack */
intercept_asm_wrapper_wrapper_level1_addr:
movabsq $0x000000000000, %r11
callq *%r11 /* call intercept_wrapper */
movq (%rsp), %rsp /* restore original rsp */
/*
* The intercept_wrapper function did restore all registers to their
* original state, except for rax, rsp, rip, and r11.
*
* If r11 is zero, rax contains a syscall number, and that syscall
* is executed here.
* If r11 is 1, rax contains the return value of the hooked syscall.
* If r11 is 2, a clone syscall is executed here.
*/
cmp $0x0, %r11
je 2f
cmp $0x1, %r11
je 3f
cmp $0x2, %r11
je 1f
hlt /* r11 value is invalid? */
1:
/* execute the clone syscall in its original context */
syscall
movq $0x1, %rcx /* choose intercept_routine_post_clone */
/*
* Now goto 0, and call the C function named
* intercept_routine_post_clone both in the parent thread, adn the
* child thread.
*/
jmp 0b
2:
syscall
3:
intercept_asm_wrapper_tmpl_end:
/*
* This template must be appended here with a
* jump back to the intercepted code.
*/
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
$(S) $(XX) -- write(8765, "dummy_data\0", 11) = ?
$(S) $(XX) -- write(8765, "dummy_data\0", 11) = 5
$(S) $(XX) -- write(8765, "thin", 4) = ?
$(S) $(XX) -- write(8765, "thin", 4) = -9 EBADF (Bad file number)
$(S) $(XX) -- write(8765, "dummy_data\0", 11) = ?
$(S) $(XX) -- write(8765, "dummy_data\0", 11) = 5
$(S) $(XX) -- vfork()
$(S) $(XX) -- exit_group(0)
$(S) $(XX) -- write(1, "In original process, after first vfork\n", 39) = ?
$(S) $(XX) -- write(1, "In original process, after first vfork\n", 39) = 39
$(S) $(XX) -- vfork()
$(S) $(XX) -- execve("$(S)", $(XX), $(XX)) = ?
$(S) $(XX) -- write(1, "In original process, after second vfork\n", 40) = ?
$(S) $(XX) -- write(1, "In original process, after second vfork\n", 40) = 40
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment