├── .clang-format ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .travis.yml ├── AUTHORS ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── LICENSE.BSD-3 ├── LICENSE.GPL-2 ├── LICENSE.GPL-3 ├── LICENSE.MIT ├── README.md ├── arch ├── riscv64 │ ├── CMakeLists.txt │ ├── clone_syscall.c │ ├── handle_syscall.s │ ├── handle_syscall_loader.s │ ├── handle_vdso.s │ ├── main.s │ ├── real_syscall.s │ ├── rewriter.c │ ├── riscv_decoder.c │ ├── riscv_decoder.h │ ├── riscv_utils.c │ ├── riscv_utils.h │ └── syscall_stackframe.c └── x86_64 │ ├── CMakeLists.txt │ ├── handle_rdtsc.s │ ├── handle_syscall.S │ ├── handle_syscall_loader.s │ ├── handle_vdso.s │ ├── main.s │ ├── rewriter.c │ ├── syscall_stackframe.c │ ├── x86_decoder.c │ └── x86_decoder.h ├── cmake ├── c_flags_override.cmake └── sabre_add_component.cmake ├── debug-tools └── gdb-symbol-loader.py ├── includes ├── arch │ ├── handle_rdtsc.h │ ├── handle_syscall.h │ ├── handle_syscall_loader.h │ ├── handle_vdso.h │ ├── rewriter_api.h │ ├── rewriter_tools.h │ └── syscall_stackframe.h ├── compiler.h ├── hash.h ├── hlist.h ├── jhash.h ├── kernel.h ├── list.h ├── loader │ ├── debuginfo.h │ ├── elf_loading.h │ ├── global_vars.h │ ├── ld_sc_handler.h │ ├── maps.h │ ├── patchelf.h │ ├── premain.h │ └── rewriter.h ├── macros.h ├── plugins │ ├── real_syscall.h │ └── sbr_api_defs.h ├── rbtree.h ├── rbtree_augmented.h └── stringutil.h ├── loader ├── CMakeLists.txt ├── debuginfo.c ├── elf_loading.c ├── ld_sc_handler.c ├── loader.c ├── maps.c ├── premain.c ├── rewriter.c └── tools │ ├── CMakeLists.txt │ ├── dump-vdso.c │ └── process-vdso.c ├── plugin_api ├── README.md ├── arch │ └── x86_64 │ │ ├── CMakeLists.txt │ │ ├── clone3_syscall.s │ │ ├── clone_syscall.s │ │ ├── real_syscall.s │ │ ├── vfork_return_from_child.s │ │ └── vfork_syscall.s └── recursion_protector.c ├── plugins ├── sbr-id │ ├── CMakeLists.txt │ └── identity.c ├── sbr-scfuzzer │ ├── CMakeLists.txt │ ├── sc-fuzzer.c │ └── sysent.h └── sbr-trace │ ├── CMakeLists.txt │ ├── sbr_api.h │ ├── strace.c │ ├── syscallent.h │ └── sysent.h └── tests ├── CMakeLists.txt ├── Simple ├── test_execve.c ├── test_fork.c ├── test_hello.c ├── test_name.c ├── test_read_write.c ├── test_sanitizers.c ├── test_stat.c ├── test_sys.c ├── test_time.c └── test_tsan.c ├── Utils ├── help │ ├── bash.sh │ ├── bunzip2.sh │ ├── bzip2.sh │ ├── cat.sh │ ├── chacl.sh │ ├── chgrp.sh │ ├── chmod │ ├── cp.sh │ ├── date.sh │ ├── dbus-uuidgen.sh │ ├── dd.sh │ ├── dmesg.sh │ ├── dumpkeys.sh │ ├── ed.sh │ ├── efibootmgr.sh │ ├── fgconsole.sh │ ├── fuser.sh │ ├── gcc.sh │ ├── grep.sh │ ├── gzip.sh │ ├── ip.sh │ ├── kill.sh │ ├── kmod.sh │ ├── lessecho.sh │ ├── ln.sh │ ├── loginctl.sh │ ├── ls.sh │ ├── lsmod.sh │ ├── mktemp.sh │ ├── mount.sh │ ├── nano.sh │ ├── nc.sh │ ├── ntfs-3g.sh │ ├── openvt.sh │ ├── ping.sh │ ├── ps.sh │ ├── sed.sh │ ├── setfacl.sh │ └── tar.sh ├── test_rm.sh ├── test_shebang.sh └── test_shebang2.sh ├── ld ├── lit.cfg.in └── test.c.in ├── lit.cfg.in ├── regression ├── test_ancillary.c ├── test_dlopen.c ├── test_execve_sigchld.c ├── test_mktemp.c ├── test_pthread.c ├── test_return_value.c └── test_select.c ├── smoke ├── hello.c.in └── lit.cfg.in ├── syscalls ├── test_chmod.c ├── test_chown.c ├── test_clone.c ├── test_fork.c ├── test_fork_simple.c ├── test_prlimit.c ├── test_utime.c ├── test_vfork.c └── test_xattr.c ├── test_sigill.S └── vdso ├── test_rip.c └── test_vdso_calls.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | ReflowComments: false 4 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.231.6/containers/ubuntu/.devcontainer/base.Dockerfile 2 | 3 | # [Choice] Ubuntu version (use hirsuite or bionic on local arm64/Apple Silicon): hirsute, focal, bionic 4 | ARG VARIANT="hirsute" 5 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 6 | 7 | # [Optional] Uncomment this section to install additional OS packages. 8 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | && apt-get -y install --no-install-recommends vim g++ cmake clang acl dbus \ 10 | kbd ed efibootmgr systemd kmod netcat-openbsd ntfs-3g inetutils-ping \ 11 | libelf-dev python3-pip python3-psutil libc6-dbg python3-setuptools make 12 | 13 | USER vscode 14 | RUN sudo -H pip3 install wheel lit 15 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.231.6/containers/ubuntu 3 | { 4 | "name": "Ubuntu", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick an Ubuntu version: hirsute, focal, bionic 8 | // Use hirsute or bionic on local arm64/Apple Silicon. 9 | "args": { 10 | "VARIANT": "bionic" 11 | } 12 | }, 13 | // Set *default* container specific settings.json values on container create. 14 | "settings": {}, 15 | // Add the IDs of extensions you want installed when the container is created. 16 | "extensions": [ 17 | "ms-vscode.cpptools-extension-pack", 18 | "streetsidesoftware.code-spell-checker" 19 | ], 20 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 21 | // "forwardPorts": [], 22 | // Use 'postCreateCommand' to run commands after the container is created. 23 | // "postCreateCommand": "uname -a", 24 | // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 25 | "remoteUser": "vscode" 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | check-format: 9 | name: Check Formatting 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout Sources 13 | uses: actions/checkout@v2 14 | 15 | - name: Run clang-format 16 | uses: jidicula/clang-format-action@v4.6.1 17 | with: 18 | clang-format-version: '12' 19 | check-path: '.' 20 | exclude-regex: '(libsqlfs|^./patchelf/elf.h$)' 21 | 22 | build: 23 | name: Build 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: Checkout Sources 27 | uses: actions/checkout@v2 28 | 29 | - name: Install CMake 30 | uses: lukka/get-cmake@latest 31 | 32 | - name: Install libelf 33 | run: sudo apt install -y libelf-dev 34 | 35 | - name: Run CMake 36 | uses: lukka/run-cmake@v10 37 | with: 38 | configurePreset: 'ninja' 39 | buildPreset: 'ninja' 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Anything pertaining to building the project 5 | build/ 6 | builds/ 7 | .vscode/ 8 | 9 | # Object files 10 | *.o 11 | *.ko 12 | *.obj 13 | *.elf 14 | 15 | # Linker output 16 | *.ilk 17 | *.map 18 | *.exp 19 | 20 | # Precompiled Headers 21 | *.gch 22 | *.pch 23 | 24 | # Libraries 25 | *.lib 26 | *.a 27 | *.la 28 | *.lo 29 | 30 | # Shared objects (inc. Windows DLLs) 31 | *.dll 32 | *.so 33 | *.so.* 34 | *.dylib 35 | 36 | # Executables 37 | *.exe 38 | *.out 39 | *.app 40 | *.i*86 41 | *.x86_64 42 | *.hex 43 | 44 | # Debug files 45 | *.dSYM/ 46 | *.su 47 | *.idb 48 | *.pdb 49 | 50 | # Kernel Module Compile Results 51 | *.mod* 52 | *.cmd 53 | .tmp_versions/ 54 | modules.order 55 | Module.symvers 56 | Mkfile.old 57 | dkms.conf 58 | 59 | .DS_Store 60 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | compiler: gcc 3 | dist: bionic 4 | 5 | before_install: 6 | - sudo apt-get install -y python3-pip python3-psutil python3-setuptools libc6-dbg 7 | - sudo -H pip3 install wheel lit 8 | addons: 9 | apt: 10 | update: true 11 | 12 | before_script: 13 | - mkdir build 14 | - cd build 15 | - cmake .. 16 | - make 17 | 18 | script: 19 | - make smoketests 20 | - make tests 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Anastasios Andronidis (@andronat) 2 | Paul-Antoine Arras (@parras) 3 | Cristian Cadar (@ccadar) 4 | Daniel Grumberg (@daniel-grumberg) 5 | Petr Hosek (@petrhosek) 6 | Karolis Mituzas (@K4rolis) 7 | Luís Pina (@luisggpina) 8 | Qianyi Shu (@roro47) 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | cmake_minimum_required(VERSION 3.10) 8 | 9 | set(CMAKE_USER_MAKE_RULES_OVERRIDE_C 10 | "${CMAKE_CURRENT_SOURCE_DIR}/cmake/c_flags_override.cmake") 11 | 12 | project(SaBRe C ASM CXX) 13 | 14 | find_program(GCC_PATH gcc) 15 | 16 | set(SABRE_COMPONENT_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/includes") 17 | set(SABRE_COMPONENT_C_DEFINES "") 18 | set(SABRE_COMPONENT_C_FLAGS 19 | "-std=gnu99" 20 | "-Wall" 21 | "-Wextra" 22 | "-Werror" 23 | "-fPIE" 24 | "-fstack-protector" 25 | "-fno-common") 26 | set(SABRE_EXE_LINK_FLAGS "-pie" "-rdynamic") 27 | set(SABRE_PLUGIN_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/includes/plugins") 28 | set(SABRE_PLUGIN_C_DEFINES "") 29 | set(SABRE_PLUGIN_C_FLAGS "-std=gnu99") 30 | 31 | option(DEBUG_INTERNAL "Print debug messages" OFF) 32 | if(DEBUG_INTERNAL) 33 | list(APPEND SABRE_COMPONENT_C_DEFINES "-DSBR_DEBUG") 34 | list(APPEND SABRE_PLUGIN_C_DEFINES "-DSBR_DEBUG") 35 | endif() 36 | 37 | if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") 38 | option(RDTSC "Intercept instruction RDTSC as a system call" ON) 39 | if(RDTSC) 40 | list(APPEND SABRE_COMPONENT_C_DEFINES "-D__NX_INTERCEPT_RDTSC") 41 | list(APPEND SABRE_PLUGIN_C_DEFINES "-D__NX_INTERCEPT_RDTSC") 42 | endif() 43 | endif() 44 | 45 | include("${CMAKE_SOURCE_DIR}/cmake/sabre_add_component.cmake") 46 | 47 | set(PROTECTOR ${CMAKE_CURRENT_SOURCE_DIR}/plugin_api/recursion_protector.c) 48 | 49 | # Sources 50 | add_subdirectory("arch/${CMAKE_SYSTEM_PROCESSOR}" arch) 51 | add_subdirectory("plugin_api/arch/${CMAKE_SYSTEM_PROCESSOR}" plugin_api) 52 | add_subdirectory("loader") 53 | file(GLOB subdirs CONFIGURE_DEPENDS "plugins/*") 54 | # When we are building under macos docker, we need to avoid these files. 55 | list(FILTER subdirs EXCLUDE REGEX ".*/plugins/.DS_Store") 56 | foreach(subdir ${subdirs}) 57 | add_subdirectory(${subdir}) 58 | endforeach() 59 | add_subdirectory("tests") 60 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 21, 6 | "patch": 0 7 | }, 8 | "configurePresets": [ 9 | { 10 | "name": "ninja", 11 | "displayName": "Ninja Configure Settings", 12 | "description": "Sets build and install directories", 13 | "binaryDir": "${sourceDir}/builds/${presetName}", 14 | "generator": "Ninja" 15 | }, 16 | { 17 | "name": "ninja-toolchain", 18 | "displayName": "Ninja Configure Settings with toolchain", 19 | "description": "Sets build and install directories", 20 | "binaryDir": "${sourceDir}/builds/${presetName}-toolchain", 21 | "generator": "Ninja", 22 | "toolchainFile": "$env{TOOLCHAINFILE}" 23 | } 24 | ], 25 | "buildPresets": [ 26 | { 27 | "name": "ninja", 28 | "configurePreset": "ninja", 29 | "displayName": "Build with Ninja", 30 | "description": "Build with Ninja" 31 | }, 32 | { 33 | "name": "ninja-toolchain", 34 | "configurePreset": "ninja-toolchain", 35 | "displayName": "Build ninja-toolchain", 36 | "description": "Build ninja with a toolchain" 37 | } 38 | ], 39 | "testPresets": [ 40 | { 41 | "name": "ninja", 42 | "configurePreset": "ninja" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SaBRe 2.0 2 | 3 | Copyright © 2019 Software Reliability Group (see AUTHORS file) 4 | 5 | SaBRe is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | SaBRe is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 | See LICENSE.GPL-3 for more details. 14 | 15 | The following files were adapted from Google's Native Client 16 | and originally distributed under the 3-clause BSD license (see LICENSE.BSD-3): 17 | includes/loader/ 18 | maps.h 19 | rewriter.h 20 | loader/ 21 | maps.c 22 | rewriter.c 23 | arch/x86_64/ 24 | rewriter.c 25 | x86_decoder.c 26 | x86_decoder.h 27 | 28 | The following files are taken from the Linux kernel 29 | and distributed under GNU General Public License version 2.0 (see LICENSE.GPL-2): 30 | includes/ 31 | hash.h 32 | hlist.h 33 | jhash.h 34 | kernel.h 35 | list.h 36 | rbtree_augmented.h 37 | rbtree.h 38 | -------------------------------------------------------------------------------- /LICENSE.BSD-3: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSE.MIT: -------------------------------------------------------------------------------- 1 | Copyright 2022 Software Reliability Group (see AUTHORS file) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SaBRe 2.0 2 | 3 | [![Build Status](https://app.travis-ci.com/srg-imperial/SaBRe.svg?branch=master)](https://app.travis-ci.com/srg-imperial/SaBRe) 4 | 5 | SaBRe is a modular selective binary rewriter. 6 | It is able to rewrite system calls, vDSO and named functions. 7 | We currently support two architectures: `x86_64` and `RISC-V`. 8 | We provide three plugins: 9 | 10 | * *sbr-id*: intercepts system calls but does not do any processing -- mainly aimed at testing 11 | * *sbr-trace*: a fast system-call tracer that mimics the original `strace` output 12 | * *sbr-scfuzzer*: a parametric fault injector to fuzz system calls 13 | 14 | SaBRe has two different system architectures. SaBRe 1.0 currently lives under [branch sabre_1.0](https://github.com/srg-imperial/SaBRe/tree/sabre_1.0) of this repo, while SaBRe 2.0 is the current main branch. For the differences between the two systems, look at section [SaBRe 1.0 vs 2.0](#sabre-10-vs-20). To learn more about the implementation details read our papers in [SaBRe research and papers](#sabre-research-and-papers). 15 | 16 | ## Building SaBRe 17 | 18 | --- 19 | 20 | ### Quick start and requirements 21 | 22 | SaBRe execution does not rely on any third-party library. 23 | However, SaBRe requires `cmake`, `make` and `gcc` for building. 24 | To quickly get started, run: 25 | 26 | ```bash 27 | git clone https://github.com/srg-imperial/SaBRe 28 | cd SaBRe 29 | mkdir build 30 | cd build 31 | cmake .. 32 | make 33 | ``` 34 | 35 | The executable will be located at `./sabre` assuming you are in the build 36 | directory you just created. 37 | The compiled plugins will lie in separate subfolders under `plugins/`. 38 | For instance, to run the `ls` command under the `sbr-trace` plugin: 39 | 40 | ```bash 41 | ./sabre plugins/sbr-trace/libsbr-trace.so -- /bin/ls 42 | ``` 43 | 44 | --- 45 | 46 | ### Compiling SaBRe executable 47 | 48 | `gcc` is recommended for compiling SaBRe. 49 | Also the build system uses `cmake` and `make`. 50 | So if you do not have them installed, use your package manager, e.g. for Debian/Ubuntu: 51 | 52 | ```bash 53 | sudo apt install cmake make gcc 54 | ``` 55 | 56 | You can [download a snapshot of the repository](https://github.com/srg-imperial/SaBRe/archive/master.zip) or clone it if you have `git` installed: 57 | 58 | ```bash 59 | git clone https://github.com/srg-imperial/SaBRe 60 | ``` 61 | 62 | The following build instructions assume that you are currently in the top level directory 63 | of your copy of the SaBRe repository: 64 | 65 | ```bash 66 | cd SaBRe 67 | mkdir build 68 | cd build 69 | cmake .. 70 | make 71 | ``` 72 | 73 | The sequel assumes the working directory is still `build/`. 74 | If everything goes well, the executable will be located at `./sabre`. 75 | 76 | --- 77 | 78 | ### Running SaBRe 79 | 80 | The general syntax to invoke SaBRe is: 81 | 82 | ```bash 83 | SaBRe [] -- [] 84 | ``` 85 | 86 | Both `PLUGIN` and `CLIENT` denote full paths to, respectively, the plugin library and the client program to be run under SaBRe. 87 | Once built, plugin libraries are located in separate subfolders under `plugins/`. 88 | For instance, the path to the `sbr-trace` library is: `plugins/sbr-trace/libsbr-trace.so`. 89 | As a full working example, if you want to execute the `ls` command under the `sbr-trace` plugin, just run: 90 | 91 | ```bash 92 | ./sabre plugins/sbr-trace/libsbr-trace.so -- /bin/ls 93 | ``` 94 | 95 | --- 96 | 97 | ## How to debug in SaBRe 98 | 99 | When using GDB with SaBRe you will notice that when the execution has reached the plugin's or the client's code, GDB is not able to show neither symbols nor source code. 100 | To fix this you will have to load `debug-tools/gdb-symbol-loader.py` in your GDB and then run the registered commands. 101 | SaBRe offers two helper commands: 102 | 103 | * `sbr-src`: Loads some paths for the source code of well known libraries like `libc` under Ubuntu 18.04. 104 | * `sbr-sym`: If provided with no arguments, it tries to load the symbols of some well know libraries that SaBRe is currently relocating (e.g. `libc`, `pthreads`, etc.). If strings are provided as arguments, we try to match those with the paths of libraries found in the maps of the running application and load their symbols. `sbr-sym` is using `add-symbol-file` under the hood and thus all restrictions and requirements apply. 105 | 106 | --- 107 | 108 | ## SaBRe 1.0 vs 2.0 109 | 110 | SaBRe is binary rewriter that loads a user provided plugin into the memory space of a client application. This plugin is called to handle the intercepted system calls or function calls of the client application. The main difference between SaBRe 1.0 and 2.0 is in *which* memory space the plugin lives and operates. 111 | 112 | Under SaBRe 1.0 the plugin lives in the memory space of SaBRe. That gives the maximum possible isolation between memory management and called libraries between SaBRe and the client. For example, if you use `malloc` inside the plugin, the memory will be allocated inside the memory arenas of SaBRe, while in 2.0 the plugin uses the same infrastructure as the client. The same difference applies for libraries too. If you choose some `libc` alternative or different version to be loaded with your plugin, SaBRe 1.0 will keep your plugin dependencies separate from the client. SaBRe 2.0 blends the plugin with the dependencies of the underlying client, and thus the same libraries will be used. 113 | 114 | SaBRe 1.0 comes with some technical limitations though. Keeping this isolation between client and plugin is not an easy task. For example a custom allocator needs to be properly and carefully used. There are also some other restrictions with respect to multithreading and the TLS. There is currently a long discussion [here](https://github.com/srg-imperial/SaBRe/pull/54) that highlights some of these technical limitations and what effort is required from the plugin developer to overcome them. 115 | 116 | If your priority is to maximise memory isolation and library interference, choose SaBRe 1.0. If you want to build complex application we recommend SaBRe 2.0. 117 | 118 | --- 119 | 120 | ## SaBRe research and papers 121 | 122 | * [The original paper on SaBRe 1.0](https://link.springer.com/content/pdf/10.1007/s10009-021-00644-w.pdf) 123 | * [SaBRe 1.0 limitation discussion](https://github.com/srg-imperial/SaBRe/pull/54) 124 | * [SaBRe 2.0 used in fuzzing](https://arxiv.org/abs/2201.04048) 125 | -------------------------------------------------------------------------------- /arch/riscv64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | list(APPEND SABRE_COMPONENT_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/includes/arch") 8 | 9 | sabre_add_component(backend 10 | clone_syscall.c 11 | handle_syscall.s 12 | handle_syscall_loader.s 13 | handle_vdso.s 14 | rewriter.c 15 | riscv_decoder.c 16 | riscv_utils.c 17 | syscall_stackframe.c 18 | ) 19 | 20 | sabre_add_component(realsyscall 21 | clone_syscall.c 22 | real_syscall.s) 23 | 24 | target_link_libraries(backend loader) 25 | 26 | sabre_add_executable(sabre main.s) 27 | set_target_properties(sabre PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) 28 | -------------------------------------------------------------------------------- /arch/riscv64/clone_syscall.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include "macros.h" 9 | 10 | #pragma GCC diagnostic ignored "-Wunused-parameter" 11 | 12 | long clone_syscall(unsigned long flags, void *child_stack, int *ptid, int *ctid, 13 | unsigned long newtls, void **args) { 14 | _nx_fatal_printf("clone_syscall() is not implemented on RISC-V arch\n"); 15 | } 16 | -------------------------------------------------------------------------------- /arch/riscv64/handle_syscall.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "handle_syscall.s" 9 | .text 10 | .globl handle_syscall 11 | .internal handle_syscall 12 | .type handle_syscall, @function 13 | 14 | handle_syscall: 15 | 16 | #addi sp, sp, -16 17 | # sd x8, 0(sp) 18 | # sd ra, 8(sp) 19 | # ecall 20 | # ld x8, 0(sp) 21 | # ld ra, 8(sp) 22 | # addi sp, sp, 16 23 | # ret 24 | 25 | addi sp, sp, -232 26 | 27 | sd x1, 0(sp) 28 | sd x3, 8(sp) 29 | sd x4, 16(sp) 30 | sd x5, 24(sp) 31 | sd x6, 32(sp) 32 | sd x7, 40(sp) 33 | sd x8, 48(sp) 34 | sd x9, 56(sp) 35 | sd x10, 64(sp) 36 | sd x11, 72(sp) 37 | sd x12, 80(sp) 38 | sd x13, 88(sp) 39 | sd x14, 96(sp) 40 | sd x15, 104(sp) 41 | sd x16, 112(sp) 42 | sd x17, 120(sp) 43 | sd x18, 128(sp) 44 | sd x19, 136(sp) 45 | sd x20, 144(sp) 46 | sd x21, 152(sp) 47 | sd x22, 160(sp) 48 | sd x23, 168(sp) 49 | sd x24, 176(sp) 50 | sd x25, 184(sp) 51 | sd x26, 192(sp) 52 | sd x27, 200(sp) 53 | sd x28, 208(sp) 54 | sd x29, 216(sp) 55 | sd x30, 224(sp) 56 | sd x31, 232(sp) 57 | 58 | addi sp, sp, -8 59 | sd x8, 0(sp) 60 | addi x8, sp, 0 61 | 62 | # adjust the arguments 63 | add t0, a7, x0 64 | add a7, a6, x0 65 | add a6, a5, x0 66 | add a5, a4, x0 67 | add a4, a3, x0 68 | add a3, a2, x0 69 | add a2, a1, x0 70 | add a1, a0, x0 71 | add a0, t0, x0 72 | 73 | # call plugin handler 74 | la t0, plugin_sc_handler 75 | ld t0, 0(t0) 76 | jalr t0 77 | # no need to adjust return value 78 | 79 | ld x8, 0(sp) 80 | addi sp, sp, 8 81 | 82 | ld x1, 0(sp) 83 | ld x3, 8(sp) 84 | ld x4, 16(sp) 85 | ld x5, 24(sp) 86 | ld x6, 32(sp) 87 | ld x7, 40(sp) 88 | ld x8, 48(sp) 89 | ld x9, 56(sp) 90 | #ld x10, 64(sp) 91 | # ld x11, 72(sp) 92 | ld x12, 80(sp) 93 | ld x13, 88(sp) 94 | ld x14, 96(sp) 95 | ld x15, 104(sp) 96 | ld x16, 112(sp) 97 | ld x17, 120(sp) 98 | ld x18, 128(sp) 99 | ld x19, 136(sp) 100 | ld x20, 144(sp) 101 | ld x21, 152(sp) 102 | ld x22, 160(sp) 103 | ld x23, 168(sp) 104 | ld x24, 176(sp) 105 | ld x25, 184(sp) 106 | ld x26, 192(sp) 107 | ld x27, 200(sp) 108 | ld x28, 208(sp) 109 | ld x29, 216(sp) 110 | ld x30, 224(sp) 111 | ld x31, 232(sp) 112 | 113 | addi sp, sp, 232 114 | ret 115 | 116 | .size handle_syscall, .-handle_syscall 117 | .section .note.GNU-stack,"",@progbits 118 | -------------------------------------------------------------------------------- /arch/riscv64/handle_syscall_loader.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "handle_syscall_loader.s" 9 | .text 10 | .globl handle_syscall_loader 11 | .internal handle_syscall_loader 12 | .type handle_syscall_loader, @function 13 | 14 | handle_syscall_loader: 15 | addi sp, sp, -232 16 | 17 | sd x1, 0(sp) 18 | sd x3, 8(sp) 19 | sd x4, 16(sp) 20 | sd x5, 24(sp) 21 | sd x6, 32(sp) 22 | sd x7, 40(sp) 23 | sd x8, 48(sp) 24 | sd x9, 56(sp) 25 | sd x10, 64(sp) 26 | sd x11, 72(sp) 27 | sd x12, 80(sp) 28 | sd x13, 88(sp) 29 | sd x14, 96(sp) 30 | sd x15, 104(sp) 31 | sd x16, 112(sp) 32 | sd x17, 120(sp) 33 | sd x18, 128(sp) 34 | sd x19, 136(sp) 35 | sd x20, 144(sp) 36 | sd x21, 152(sp) 37 | sd x22, 160(sp) 38 | sd x23, 168(sp) 39 | sd x24, 176(sp) 40 | sd x25, 184(sp) 41 | sd x26, 192(sp) 42 | sd x27, 200(sp) 43 | sd x28, 208(sp) 44 | sd x29, 216(sp) 45 | sd x30, 224(sp) 46 | sd x31, 232(sp) 47 | 48 | addi sp, sp, -8 49 | sd x8, 0(sp) 50 | addi x8, sp, 0 51 | 52 | 53 | # adjust the arguments 54 | add t0, a7, x0 55 | add a7, a6, x0 56 | add a6, a5, x0 57 | add a5, a4, x0 58 | add a4, a3, x0 59 | add a3, a2, x0 60 | add a2, a1, x0 61 | add a1, a0, x0 62 | add a0, t0, x0 63 | 64 | call ld_sc_handler 65 | 66 | # no need to adjust return value 67 | 68 | ld x8, 0(sp) 69 | addi sp, sp, 8 70 | 71 | ld x1, 0(sp) 72 | ld x3, 8(sp) 73 | ld x4, 16(sp) 74 | ld x5, 24(sp) 75 | ld x6, 32(sp) 76 | ld x7, 40(sp) 77 | ld x8, 48(sp) 78 | ld x9, 56(sp) 79 | #ld x10, 64(sp) 80 | # ld x11, 72(sp) 81 | ld x12, 80(sp) 82 | ld x13, 88(sp) 83 | ld x14, 96(sp) 84 | ld x15, 104(sp) 85 | ld x16, 112(sp) 86 | ld x17, 120(sp) 87 | ld x18, 128(sp) 88 | ld x19, 136(sp) 89 | ld x20, 144(sp) 90 | ld x21, 152(sp) 91 | ld x22, 160(sp) 92 | ld x23, 168(sp) 93 | ld x24, 176(sp) 94 | ld x25, 184(sp) 95 | ld x26, 192(sp) 96 | ld x27, 200(sp) 97 | ld x28, 208(sp) 98 | ld x29, 216(sp) 99 | ld x30, 224(sp) 100 | ld x31, 232(sp) 101 | 102 | addi sp, sp, 232 103 | ret 104 | 105 | .size handle_syscall_loader, .-handle_syscall_loader 106 | .section .note.GNU-stack,"",@progbits 107 | -------------------------------------------------------------------------------- /arch/riscv64/handle_vdso.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "handle_vdso.s" 9 | .text 10 | .globl handle_vdso 11 | .internal handle_vdso 12 | .type handle_vdso, @function 13 | 14 | handle_vdso: 15 | addi sp, sp, -232 16 | 17 | sd x1, 0(sp) 18 | sd x3, 8(sp) 19 | sd x4, 16(sp) 20 | sd x5, 24(sp) 21 | sd x6, 32(sp) 22 | sd x7, 40(sp) 23 | sd x8, 48(sp) 24 | sd x9, 56(sp) 25 | sd x10, 64(sp) 26 | sd x11, 72(sp) 27 | sd x12, 80(sp) 28 | sd x13, 88(sp) 29 | sd x14, 96(sp) 30 | sd x15, 104(sp) 31 | sd x16, 112(sp) 32 | sd x17, 120(sp) 33 | sd x18, 128(sp) 34 | sd x19, 136(sp) 35 | sd x20, 144(sp) 36 | sd x21, 152(sp) 37 | sd x22, 160(sp) 38 | sd x23, 168(sp) 39 | sd x24, 176(sp) 40 | sd x25, 184(sp) 41 | sd x26, 192(sp) 42 | sd x27, 200(sp) 43 | sd x28, 208(sp) 44 | sd x29, 216(sp) 45 | sd x30, 224(sp) 46 | sd x31, 232(sp) 47 | 48 | addi sp, sp, -8 49 | sd x8, 0(sp) 50 | addi x8, sp, 0 51 | 52 | bnez t1, vdso_handler_provided 53 | 54 | # adjust the arguments 55 | add t0, a7, x0 56 | add a7, a6, x0 57 | add a6, a5, x0 58 | add a5, a4, x0 59 | add a4, a3, x0 60 | add a3, a2, x0 61 | add a2, a1, x0 62 | add a1, a0, x0 63 | add a0, t2, x0 /* syscall number */ 64 | 65 | # call plugin handler 66 | la t0, plugin_sc_handler 67 | ld t0, 0(t0) 68 | jalr t0 69 | j end 70 | # no need to adjust return value 71 | 72 | 73 | vdso_handler_provided: 74 | call plugin_vdso_handler 75 | 76 | end: 77 | ld x8, 0(sp) 78 | addi sp, sp, 8 79 | 80 | ld x1, 0(sp) 81 | ld x3, 8(sp) 82 | ld x4, 16(sp) 83 | ld x5, 24(sp) 84 | ld x6, 32(sp) 85 | ld x7, 40(sp) 86 | ld x8, 48(sp) 87 | ld x9, 56(sp) 88 | #ld x10, 64(sp) 89 | # ld x11, 72(sp) 90 | ld x12, 80(sp) 91 | ld x13, 88(sp) 92 | ld x14, 96(sp) 93 | ld x15, 104(sp) 94 | ld x16, 112(sp) 95 | ld x17, 120(sp) 96 | ld x18, 128(sp) 97 | ld x19, 136(sp) 98 | ld x20, 144(sp) 99 | ld x21, 152(sp) 100 | ld x22, 160(sp) 101 | ld x23, 168(sp) 102 | ld x24, 176(sp) 103 | ld x25, 184(sp) 104 | ld x26, 192(sp) 105 | ld x27, 200(sp) 106 | ld x28, 208(sp) 107 | ld x29, 216(sp) 108 | ld x30, 224(sp) 109 | ld x31, 232(sp) 110 | 111 | addi sp, sp, 232 112 | ret 113 | 114 | .size handle_vdso, .-handle_vdso 115 | .section .note.GNU-stack,"",@progbits 116 | -------------------------------------------------------------------------------- /arch/riscv64/main.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "main.s" 9 | 10 | .data 11 | null_entry: 12 | .string "FATAL: entry point is null\n" 13 | null_new_stack: 14 | .string "FATAL: new stack top is null\n" 15 | 16 | .text 17 | .global main 18 | .type main, @function 19 | 20 | main: 21 | # Function prologue 22 | addi sp, sp, -8 23 | sd ra, 0(sp) #store return address 24 | 25 | addi sp, sp, -8 26 | sd s0, 0(sp) #save frame pointer 27 | addi s0, sp, 0 28 | 29 | 30 | # Push two NULL pointers onto stack and pass them to load 31 | addi sp, sp, -8 32 | sd x0, 0(sp) 33 | addi a2, sp, 0 # pass the location for new_entry to load 34 | addi sp, sp, -8 35 | sd x0, 0(sp) 36 | addi a3, sp, 0 # pass the location for new_stack_top to load 37 | 38 | 39 | # call the main loading function 40 | call load 41 | 42 | # TODO sanity check 43 | 44 | ld a0, 0(sp) # new_stack_top in a0 45 | ld a1, 8(sp) # new_entry in a1 46 | 47 | mv sp, a0 # new stack 48 | 49 | # Nothing at_exit() 50 | mv a0, zero 51 | 52 | # Call the entrypoint of the loader/static 53 | jr a1 54 | 55 | # if didn't end, force end 56 | addi x17, x0, 93 57 | ecall 58 | 59 | error_entrypoint: 60 | 61 | 62 | error_new_stack: 63 | 64 | 65 | .size main, .-main 66 | .section .note,"",@progbits 67 | -------------------------------------------------------------------------------- /arch/riscv64/real_syscall.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "real_syscall.s" 9 | .text 10 | .globl real_syscall 11 | .type real_syscall, @function 12 | 13 | real_syscall: 14 | addi sp, sp, -16 # function prologue 15 | sd ra, 8(sp) 16 | sd s0, 0(sp) 17 | addi s0, sp, 0 18 | 19 | addi t0, a0, 0 # store the syscall number 20 | addi a0, a1, 0 21 | addi a1, a2, 0 22 | addi a2, a3, 0 23 | addi a3, a4, 0 24 | addi a4, a5, 0 25 | addi a5, a6, 0 26 | addi a6, a7, 0 27 | 28 | addi a7, t0, 0 # place the syscall 29 | 30 | ecall 31 | 32 | ld s0, 0(sp) 33 | ld ra, 8(sp) 34 | addi sp, sp, 16 35 | 36 | ret 37 | 38 | .size real_syscall, .-real_syscall 39 | .section .note.GNU-stack,"",@progbits 40 | -------------------------------------------------------------------------------- /arch/riscv64/riscv_decoder.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include "riscv_decoder.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // move the ip to the start of the next inst 15 | // return current inst's opcode 16 | inline uint32_t next_inst_riscv(char **ip) { 17 | uint16_t first_half = *((uint16_t *)*ip); 18 | if ((__bswap_16(first_half) & 0x0300) == 0x0300) { 19 | uint32_t insn = *((uint32_t *)*ip); 20 | *ip += 4; 21 | return insn; 22 | } else { 23 | *ip += 2; 24 | return first_half; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /arch/riscv64/riscv_decoder.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef RISCV_DECODER_H 9 | #define RISCV_DECODER_H 10 | #include 11 | uint32_t next_inst_riscv(char **); 12 | #endif 13 | -------------------------------------------------------------------------------- /arch/riscv64/riscv_utils.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef RISCV_UTILS_H_ 9 | #define RISCV_UTILS_H_ 10 | #include 11 | #include 12 | 13 | #define RISCV_INST32_OP 0x7f 14 | #define RISCV_INST16_OP 0x03 15 | #define RD_32 0x0000f80 16 | #define RS1_32 0x00f8000 17 | #define RS2_32 0x1f00000 18 | 19 | #define LUI 0b0110111 20 | #define AUIPC 0b0010111 21 | #define JAL 0b1101111 22 | #define JALR 0b1100111 23 | #define BRANCH 0b1100011 24 | #define LOAD 0b0000011 25 | #define STORE 0b0100011 26 | #define COMPUTE1_32 0b0010011 27 | #define COMPUTE2_32 0b0110011 28 | #define COMPUTE1_64 0b0011011 29 | #define COMPUTE2_64 0b0111011 30 | 31 | #define rd_32(i) ((i & RD_32) >> 7) 32 | #define rs1_32(i) ((i & RS1_32) >> 15) 33 | #define rs2_32(i) ((i & RS2_32) >> 20) 34 | 35 | #define len(inst) ((inst & 0x3) == 0x3 ? 4 : 2) 36 | 37 | struct inst_param { 38 | uint8_t opcode; 39 | uint8_t func; 40 | uint8_t rd; 41 | uint8_t rs1; 42 | uint8_t rs2; 43 | int32_t imm; 44 | }; 45 | 46 | uint32_t get_patch_jal(int32_t, int); 47 | uint32_t get_patch_store(); 48 | 49 | uint32_t encode_jal32(struct inst_param *); 50 | uint32_t encode_addi32(struct inst_param *); 51 | uint32_t encode_auipc32(struct inst_param *); 52 | uint32_t encode_jalr32(struct inst_param *); 53 | uint32_t encode_ld32(struct inst_param *); 54 | int64_t decode_jal32_offset(uint32_t); 55 | int64_t decode_branch32_offset(uint32_t); 56 | uint64_t decode_jal16_offset(uint16_t); 57 | uint64_t decode_j16_offset(uint16_t); 58 | uint64_t decode_branch16_offset(uint16_t); 59 | 60 | bool is_jal32(uint32_t); 61 | bool is_branch32(uint32_t); 62 | bool is_jal16(uint16_t); 63 | bool is_j16(uint16_t); 64 | bool is_jr16(uint16_t); 65 | bool is_jalr16(uint16_t); 66 | bool is_beqz16(uint16_t); 67 | bool is_bnez16(uint16_t); 68 | bool is_store32(uint32_t); 69 | bool is_store16(uint16_t); 70 | bool is_control_flow_inst(uint32_t); 71 | uint64_t inst_offset64(uint32_t); 72 | 73 | uint32_t mask(int); 74 | int demask(uint32_t); 75 | int demask_ignore(uint32_t, int); 76 | uint32_t dependency_reg(uint32_t); 77 | uint32_t deprecated_reg(uint32_t); 78 | 79 | bool is_safe_insn(uint32_t); 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /arch/riscv64/syscall_stackframe.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include "syscall_stackframe.h" 9 | 10 | #include 11 | 12 | struct syscall_stackframe { 13 | void *rbp_stackalign; 14 | void *r15; 15 | void *r14; 16 | void *r13; 17 | void *r12; 18 | void *r11; 19 | void *r10; 20 | void *r8; 21 | void *rdi; 22 | void *rsi; 23 | void *rdx; 24 | void *rcx; 25 | void *rbx; 26 | void *rbp_prologue; 27 | // trampoline 28 | void *fake_ret; 29 | void *ret; 30 | } __packed; 31 | 32 | void *get_syscall_return_address(struct syscall_stackframe *stack_frame) { 33 | return stack_frame->ret; 34 | } 35 | 36 | size_t get_offsetof_syscall_return_address(void) { 37 | return offsetof(struct syscall_stackframe, ret); 38 | } 39 | -------------------------------------------------------------------------------- /arch/x86_64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | list(APPEND SABRE_COMPONENT_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/includes/arch") 8 | 9 | set(SRCS handle_syscall.S handle_syscall_loader.s handle_vdso.s rewriter.c 10 | syscall_stackframe.c x86_decoder.c) 11 | 12 | if(RDTSC) 13 | list(APPEND SRCS handle_rdtsc.s) 14 | endif(RDTSC) 15 | 16 | sabre_add_component(backend ${SRCS}) 17 | 18 | sabre_add_executable(sabre main.s) 19 | set_target_properties(sabre PROPERTIES RUNTIME_OUTPUT_DIRECTORY 20 | ${CMAKE_BINARY_DIR}) 21 | -------------------------------------------------------------------------------- /arch/x86_64/handle_rdtsc.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "handle_rdtsc.s" 9 | .text 10 | .globl rdtsc_entrypoint 11 | .internal rdtsc_entrypoint 12 | .type rdtsc_entrypoint, @function 13 | 14 | rdtsc_entrypoint: 15 | .cfi_startproc 16 | .cfi_def_cfa rsp, 0x88 17 | .cfi_offset rip, -0x88 18 | .cfi_remember_state 19 | 20 | # Prologue 21 | push %rbp 22 | .cfi_adjust_cfa_offset 8 23 | mov %rsp, %rbp 24 | .cfi_def_cfa_register rbp 25 | .cfi_remember_state 26 | 27 | # Save the registers 28 | pushq %rbx 29 | pushq %rcx 30 | pushq %rdx 31 | pushq %rsi 32 | pushq %rdi 33 | pushq %r8 34 | pushq %r9 35 | pushq %r10 36 | pushq %r11 37 | pushq %r12 38 | pushq %r13 39 | pushq %r14 40 | pushq %r15 41 | 42 | # Align the stack on a 16-byte boundary before the call 43 | push %rbp 44 | mov %rsp, %rbp 45 | .cfi_adjust_cfa_offset 0x70 46 | and $0xfffffffffffffff0, %rsp 47 | 48 | # Call the actual handler 49 | call *plugin_rdtsc_handler(%rip) 50 | 51 | # Move high part of rax to rdx 52 | mov %rax, %rdx 53 | mov $0x00000000FFFFFFFF, %r15 54 | and %r15, %rax 55 | shr $32, %rdx 56 | and %r15, %rdx 57 | mov %rdx, 88(%rsp) # Save rdx on right position on the stack 58 | 59 | # Restore the stack 60 | mov %rbp, %rsp 61 | pop %rbp 62 | .cfi_restore_state 63 | 64 | # Reload registers 65 | popq %r15 66 | popq %r14 67 | popq %r13 68 | popq %r12 69 | popq %r11 70 | popq %r10 71 | popq %r9 72 | popq %r8 73 | popq %rdi 74 | popq %rsi 75 | popq %rdx 76 | popq %rcx 77 | popq %rbx 78 | 79 | # Epilogue 80 | pop %rbp 81 | .cfi_restore_state 82 | addq $8, %rsp # drop fake return address 83 | .cfi_undefined rip 84 | ret 85 | .cfi_endproc 86 | .size rdtsc_entrypoint, .-rdtsc_entrypoint 87 | .section .note.GNU-stack,"",@progbits 88 | -------------------------------------------------------------------------------- /arch/x86_64/handle_syscall.S: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | .file "handle_syscall.S" 12 | .text 13 | .globl handle_syscall 14 | .internal handle_syscall 15 | .type handle_syscall, @function 16 | 17 | handle_syscall: 18 | .cfi_startproc 19 | .cfi_def_cfa rsp, 0x88 20 | .cfi_offset rip, -0x88 21 | .cfi_remember_state 22 | 23 | 24 | # Check for rt_sigreturn(). It needs to be handled specially. 25 | # 26 | # When a user registers a signal through rt_sigaction, glibc (or others) add 27 | # SA_RESTORER and a pointer to inform Linux how to finish a signal execution. 28 | # SA_RESTORER points to a function that should eventually call the 29 | # rt_sigreturn syscall (together with whatever teardown stuff). An important 30 | # point here is that rt_sigreturn doesn't return. SaBRe will replace the 31 | # syscall with a jump and because our trampoline messes with the stack layout 32 | # we need to manually handle it. So whenever we are about to call rt_sigreturn 33 | # we need to revert all custom stack manipulations we did before rt_sigreturn 34 | # is called. 35 | # 36 | # Replacing the SA_RESTORER pointer with a custom handler (e.g. exactly how we 37 | # do it for SIGSEGV in plugins/varan/signal/proxy.c:overwrite_handler_func) is 38 | # not an option as the original SA_RESTORER might have some teardown logic 39 | # that we shouldn't be messing with. On the other hand, we need to replace the 40 | # SA_RESTORER pointer for signals that SaBRe should be hanlding internally 41 | # (e.g. SIGSEGV). In this case when a user wants to define a custom SIGSEGV 42 | # with a custom SA_RESTORER we need to first execute the user's SA_RESTORER 43 | # and then our own one. In the current version of SaBRe, glibc is used which 44 | # can simplify various details related to SA_RESTORER. 45 | # 46 | # TODO(andronat): Implement SA_RESTORER overwritting. SIGSEGV by default 47 | # should be pointing to internal's glibc SA_RESTORER. When a user registers 48 | # a custom one, we need to properly redirect. Assert that our SA_RESTORER will 49 | # always be a simple one. 50 | cmp $15, %rax # NR_rt_sigreturn 51 | jnz 1f 52 | # It's 0x80 + 0x10 for 2 extra PUSH instructions 53 | add $0x90, %rsp # pop return addresses, red zone, and loader arg 54 | 0:syscall # rt_sigreturn() is unrestricted 55 | mov $66, %edi # rt_sigreturn() should never return 56 | mov $231, %eax # NR_exit_group 57 | jmp 0b 58 | 59 | 1: 60 | # Prologue 61 | push %rbp 62 | .cfi_adjust_cfa_offset 8 63 | mov %rsp, %rbp 64 | .cfi_def_cfa_register rbp 65 | .cfi_remember_state 66 | 67 | # Save the registers. 68 | # While the kernel clobbers %rcx and %r11, we play safe and we store them. 69 | # From: https://gitlab.com/x86-psABIs/x86-64-ABI/-/blob/master/x86-64-ABI/kernel.tex#L35-37 70 | pushq %rbx 71 | pushq %rcx 72 | pushq %rdx 73 | pushq %rsi 74 | pushq %rdi 75 | pushq %r8 76 | pushq %r9 77 | pushq %r10 78 | pushq %r11 79 | pushq %r12 80 | pushq %r13 81 | pushq %r14 82 | pushq %r15 83 | 84 | # Align the stack on a 16-byte boundary before the call 85 | push %rbp 86 | mov %rsp, %rbp 87 | .cfi_adjust_cfa_offset 0x68 88 | and $0xfffffffffffffff0, %rsp 89 | 90 | # Adjust the arguments 91 | pushq %rbp # wrapper_sp 92 | pushq %r9 # arg6 93 | movq %r8, %r9 # arg5 94 | movq %r10, %r8 # arg4 95 | movq %rdx, %rcx # arg3 96 | movq %rsi, %rdx # arg2 97 | movq %rdi, %rsi # arg1 98 | movq %rax, %rdi # sc_no 99 | 100 | call *runtime_syscall_router@GOTPCREL(%rip) 101 | 102 | # Pop arguments 103 | popq %r9 104 | popq %r15 # skip wrapper_sp 105 | 106 | # Restore the stack 107 | mov %rbp, %rsp 108 | pop %rbp 109 | .cfi_restore_state 110 | 111 | # Reload registers 112 | popq %r15 113 | popq %r14 114 | popq %r13 115 | popq %r12 116 | popq %r11 117 | popq %r10 118 | popq %r9 119 | popq %r8 120 | popq %rdi 121 | popq %rsi 122 | popq %rdx 123 | popq %rcx 124 | popq %rbx 125 | 126 | # Epilogue 127 | pop %rbp 128 | .cfi_restore_state 129 | addq $8, %rsp # drop fake return address 130 | .cfi_undefined rip 131 | ret 132 | .cfi_endproc 133 | .size handle_syscall, .-handle_syscall 134 | .section .note.GNU-stack,"",@progbits 135 | -------------------------------------------------------------------------------- /arch/x86_64/handle_syscall_loader.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "handle_syscall.s" 9 | .text 10 | .globl handle_syscall_loader 11 | .internal handle_syscall_loader 12 | .type handle_syscall_loader, @function 13 | 14 | handle_syscall_loader: 15 | .cfi_startproc 16 | .cfi_def_cfa rsp, 0x88 17 | .cfi_offset rip, -0x88 18 | .cfi_remember_state 19 | 20 | # Prologue 21 | push %rbp 22 | .cfi_adjust_cfa_offset 8 23 | mov %rsp, %rbp 24 | .cfi_def_cfa_register rbp 25 | .cfi_remember_state 26 | 27 | # Save the registers 28 | pushq %rbx 29 | pushq %rcx 30 | pushq %rdx 31 | pushq %rsi 32 | pushq %rdi 33 | pushq %r8 34 | pushq %r10 35 | pushq %r11 36 | pushq %r12 37 | pushq %r13 38 | pushq %r14 39 | pushq %r15 40 | 41 | # Align the stack on a 16-byte boundary before the call 42 | push %rbp 43 | mov %rsp, %rbp 44 | .cfi_adjust_cfa_offset 0x68 45 | and $0xfffffffffffffff0, %rsp 46 | 47 | # Adjust the arguments 48 | pushq %rsp # reserve space for wrapper_sp 49 | pushq %r9 # arg6 50 | movq %rsp, 8(%rsp) # wrapper_sp 51 | movq %r8, %r9 # arg5 52 | movq %r10, %r8 # arg4 53 | movq %rdx, %rcx # arg3 54 | movq %rsi, %rdx # arg2 55 | movq %rdi, %rsi # arg1 56 | movq %rax, %rdi # sc_no 57 | 58 | # Call the actual handler 59 | call *ld_sc_handler@GOTPCREL(%rip) 60 | 61 | # Pop arguments 62 | popq %r9 63 | popq %r15 # skip wrapper_sp 64 | 65 | # Restore the stack 66 | mov %rbp, %rsp 67 | pop %rbp 68 | .cfi_restore_state 69 | 70 | # Reload registers 71 | popq %r15 72 | popq %r14 73 | popq %r13 74 | popq %r12 75 | popq %r11 76 | popq %r10 77 | popq %r8 78 | popq %rdi 79 | popq %rsi 80 | popq %rdx 81 | popq %rcx 82 | popq %rbx 83 | 84 | # Epilogue 85 | pop %rbp 86 | .cfi_restore_state 87 | addq $8, %rsp # drop fake return address 88 | .cfi_undefined rip 89 | ret 90 | .cfi_endproc 91 | .size handle_syscall_loader, .-handle_syscall_loader 92 | .section .note.GNU-stack,"",@progbits 93 | -------------------------------------------------------------------------------- /arch/x86_64/handle_vdso.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "handle_vdso.s" 9 | .text 10 | .globl handle_vdso 11 | .internal handle_vdso 12 | .type handle_vdso, @function 13 | 14 | handle_vdso: 15 | .cfi_startproc 16 | .cfi_def_cfa rsp, 0x90 17 | .cfi_offset rip, -0x90 18 | .cfi_remember_state 19 | 20 | # Prologue 21 | push %rbp 22 | .cfi_adjust_cfa_offset 8 23 | mov %rsp, %rbp 24 | .cfi_def_cfa_register rbp 25 | .cfi_remember_state 26 | 27 | # Save the registers 28 | pushq %rbx 29 | pushq %rcx 30 | pushq %rdx 31 | pushq %rsi 32 | pushq %rdi 33 | pushq %r8 34 | pushq %r10 35 | pushq %r11 36 | pushq %r12 37 | pushq %r13 38 | pushq %r14 39 | pushq %r9 # arg6 40 | 41 | # Align the stack on a 16-byte boundary before the call 42 | push %rbp 43 | mov %rsp, %rbp 44 | .cfi_adjust_cfa_offset 0x68 45 | and $0xfffffffffffffff0, %rsp 46 | 47 | # Check if vDSO handler is provided 48 | test %r15, %r15 49 | jnz handler_provided 50 | 51 | # Adjust the arguments 52 | movq %r8, %r9 # arg5 53 | movq %r10, %r8 # arg4 54 | movq %rdx, %rcx # arg3 55 | movq %rsi, %rdx # arg2 56 | movq %rdi, %rsi # arg1 57 | movq %rax, %rdi # sc_no 58 | 59 | # Call the actual handler 60 | call *plugin_sc_handler(%rip) 61 | jmp end 62 | 63 | handler_provided: 64 | call *%r15 65 | 66 | # Reload the registers 67 | end: 68 | # Restore the stack 69 | mov %rbp, %rsp 70 | pop %rbp 71 | .cfi_restore_state 72 | 73 | popq %r9 74 | popq %r14 75 | popq %r13 76 | popq %r12 77 | popq %r11 78 | popq %r10 79 | popq %r8 80 | popq %rdi 81 | popq %rsi 82 | popq %rdx 83 | popq %rcx 84 | popq %rbx 85 | 86 | # Epilogue 87 | pop %rbp 88 | .cfi_restore_state 89 | addq $8, %rsp # drop fake return address 90 | .cfi_undefined rip 91 | ret 92 | .cfi_endproc 93 | .size handle_vdso, .-handle_vdso 94 | .section .note.GNU-stack,"",@progbits 95 | -------------------------------------------------------------------------------- /arch/x86_64/main.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | .file "main.s" 9 | 10 | .data 11 | null_entry: 12 | .string "FATAL: entry point is null\n" 13 | null_new_stack: 14 | .string "FATAL: new stack top is null\n" 15 | 16 | .text 17 | .globl main 18 | .type main, @function 19 | 20 | main: 21 | .cfi_startproc 22 | 23 | # Function prologue 24 | pushq %rbp 25 | .cfi_adjust_cfa_offset 8 26 | movq %rsp, %rbp 27 | .cfi_def_cfa_register rbp 28 | 29 | # Push two NULL pointers onto stack and pass them to load 30 | pushq $0 # The entrypoint initialized to 0 31 | movq %rsp, %rdx 32 | pushq $0 # The new stack top initialized to 0 33 | movq %rsp, %rcx 34 | 35 | # Call the main loading function 36 | callq *load@GOTPCREL(%rip) 37 | 38 | # Sanity checks 39 | movq -8(%rbp), %rax 40 | test %rax, %rax 41 | je error_entrypoint 42 | movq -16(%rbp), %r15 43 | test %r15, %r15 44 | je error_new_stack 45 | 46 | # Everything seems fine - nuke the stack! 47 | movq %r15, %rsp 48 | xorq %rbp, %rbp 49 | .cfi_undefined rip 50 | 51 | # Nothing at_exit() 52 | xorq %rdx, %rdx 53 | 54 | # Call the entrypoint of the loader/static ELF 55 | jmpq *%rax 56 | 57 | error_entrypoint: 58 | andq $~0xF, %rsp # Align the stack 59 | movq $2, %rdi # Write to stderr 60 | lea null_entry(%rip), %rsi # since this is a PIC 61 | callq *dprintf@GOTPCREL(%rip) # ditto 62 | movq $127, %rax # default bad return code 63 | movq %rbp, %rsp 64 | popq %rbp 65 | retq 66 | 67 | error_new_stack: 68 | andq $~0xF, %rsp 69 | movq $2, %rdi 70 | lea null_new_stack(%rip), %rsi 71 | callq *dprintf@GOTPCREL(%rip) 72 | movq $127, %rax 73 | movq %rbp, %rsp 74 | popq %rbp 75 | retq 76 | 77 | .cfi_endproc 78 | .size main, .-main 79 | .section .note.GNU-stack,"",@progbits 80 | -------------------------------------------------------------------------------- /arch/x86_64/syscall_stackframe.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #include "syscall_stackframe.h" 9 | 10 | #include 11 | 12 | struct syscall_stackframe { 13 | void *rbp_stackalign; 14 | void *r15; 15 | void *r14; 16 | void *r13; 17 | void *r12; 18 | void *r11; 19 | void *r10; 20 | void *r9; 21 | void *r8; 22 | void *rdi; 23 | void *rsi; 24 | void *rdx; 25 | void *rcx; 26 | void *rbx; 27 | void *rbp_prologue; 28 | // trampoline 29 | void *fake_ret; 30 | void *ret; 31 | } __packed; 32 | 33 | void *get_syscall_return_address(struct syscall_stackframe *stack_frame) { 34 | return stack_frame->ret; 35 | } 36 | 37 | size_t get_offsetof_syscall_return_address(void) { 38 | return offsetof(struct syscall_stackframe, ret); 39 | } 40 | -------------------------------------------------------------------------------- /arch/x86_64/x86_decoder.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2010 The Chromium Authors. All rights reserved. 2 | * Copyright © 2019 Software Reliability Group, Imperial College London 3 | * 4 | * This file is part of SaBRe. 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later AND BSD-3-Clause 7 | */ 8 | 9 | #ifndef X86_DECODER_H 10 | #define X86_DECODER_H 11 | 12 | #include 13 | 14 | #include "compiler.h" 15 | 16 | enum { REX_B = 0x01, REX_X = 0x02, REX_R = 0x04, REX_W = 0x08 }; 17 | 18 | unsigned short next_inst(const char **ip, bool is64bit, bool *has_prefix, 19 | char **rex_ptr, char **mod_rm_ptr, char **sib_ptr, 20 | bool *is_group) __internal; 21 | 22 | #endif // X86_DECODER_H 23 | -------------------------------------------------------------------------------- /cmake/c_flags_override.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_C_FLAGS_INIT "") 2 | set(CMAKE_C_FLAGS_DEBUG_INIT "-O0 -ggdb3") 3 | set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os") 4 | set(CMAKE_C_FLAGS_RELEASE_INIT "-O3") 5 | set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -ggdb3") 6 | set(CMAKE_C_STANDARD 11) 7 | -------------------------------------------------------------------------------- /cmake/sabre_add_component.cmake: -------------------------------------------------------------------------------- 1 | function(sabre_add_component target_name) 2 | add_library(${target_name} STATIC ${ARGN}) 3 | target_include_directories(${target_name} 4 | PUBLIC ${SABRE_COMPONENT_INCLUDE_DIRS}) 5 | target_compile_definitions(${target_name} PUBLIC ${SABRE_COMPONENT_C_DEFINES}) 6 | target_compile_options(${target_name} PRIVATE ${SABRE_COMPONENT_C_FLAGS}) 7 | endfunction() 8 | 9 | function(sabre_add_executable exe_name) 10 | add_executable(${exe_name} ${ARGN}) 11 | target_compile_definitions(${exe_name} PRIVATE ${SABRE_COMPONENT_C_DEFINES}) 12 | target_compile_options(${exe_name} PRIVATE ${SABRE_COMPONENT_C_FLAGS}) 13 | if(${CMAKE_VERSION} VERSION_LESS "3.13.0") 14 | string(REPLACE ";" " " SABRE_EXE_LINK_FLAGS_STR "${SABRE_EXE_LINK_FLAGS}") 15 | set_property( 16 | TARGET ${exe_name} 17 | APPEND 18 | PROPERTY LINK_FLAGS ${SABRE_EXE_LINK_FLAGS_STR}) 19 | else() 20 | target_link_options(${exe_name} PRIVATE ${SABRE_EXE_LINK_FLAGS}) 21 | endif() 22 | target_link_libraries(${exe_name} loader) 23 | endfunction() 24 | 25 | function(sabre_add_plugin plugin_name) 26 | add_library(${plugin_name} MODULE ${PROTECTOR} ${ARGN}) 27 | target_include_directories(${plugin_name} PUBLIC ${SABRE_PLUGIN_INCLUDE_DIRS}) 28 | target_compile_definitions(${plugin_name} PUBLIC ${SABRE_PLUGIN_C_DEFINES}) 29 | target_compile_options(${plugin_name} PUBLIC ${SABRE_PLUGIN_C_FLAGS}) 30 | target_link_libraries(${plugin_name} plugin_api backend) 31 | endfunction() 32 | -------------------------------------------------------------------------------- /debug-tools/gdb-symbol-loader.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | # Make a ~/.gdbinit file and add: 4 | # source ~/SaBRe/debug-tools/gdb-symbol-loader.py 5 | # Invoke from GDB as: sbr-sym and sbr-src 6 | 7 | # For adding debugging source files for Ubuntu 18.04 you can add the following 8 | # in your ~/.gdbinit: 9 | # dir /usr/src/glibc/glibc-2.27/nptl 10 | # dir /usr/src/glibc/glibc-2.27/elf 11 | # dir /usr/src/glibc/glibc-2.27/libio 12 | # dir /usr/src/gcc-7/src/libsanitizer/include/sanitizer 13 | 14 | # Useful gdb commands: info file, remove-symbol-file 15 | 16 | 17 | class AddSaBReSymbols(gdb.Command): 18 | @staticmethod 19 | def get_offsets(path): 20 | text_offset, bss_offset, rodata_offset = 0, 0, 0 21 | output = subprocess.check_output(["readelf", "-WS", path]) 22 | for line in output.splitlines(): 23 | line = str(line) 24 | if "] .text " in line: 25 | text_offset = "0x" + line.split()[5] 26 | if "] .bss " in line: 27 | bss_offset = "0x" + line.split()[5] 28 | if "] .rodata " in line: 29 | rodata_offset = "0x" + line.split()[5] 30 | return text_offset, bss_offset, rodata_offset 31 | 32 | @staticmethod 33 | def run_add_symbol_file(from_tty, lib, addr_start): 34 | text_offset, bss_offset, rodata_offset = AddSaBReSymbols.get_offsets(lib) 35 | 36 | gdb_cmd = ( 37 | f"add-symbol-file {lib}" 38 | f" -s .text {addr_start}+{text_offset}" 39 | f" -s .bss {addr_start}+{bss_offset}" 40 | ) 41 | if rodata_offset: 42 | gdb_cmd += f" -s .rodata {addr_start}+{rodata_offset}" 43 | print(gdb_cmd) 44 | gdb.execute(gdb_cmd, from_tty) 45 | 46 | def __init__(self): 47 | super(AddSaBReSymbols, self).__init__("sbr-sym", gdb.COMMAND_USER) 48 | self.dont_repeat() 49 | 50 | def invoke(self, args, from_tty): 51 | pagination = gdb.parameter("pagination") 52 | if pagination: 53 | gdb.execute("set pagination off") 54 | 55 | cmd = "info proc mappings" 56 | maplines = gdb.execute(cmd, from_tty, True).split("\n") 57 | 58 | argv = gdb.string_to_argv(args) 59 | if len(argv) > 0: 60 | for target in argv: 61 | print(f"Loading user provided target: {target}") 62 | for line in maplines: 63 | if target in line: 64 | line = line.strip().split() 65 | addr_start, lib = line[0], line[4] 66 | self.run_add_symbol_file(from_tty, lib, addr_start) 67 | # TODO: We just add the first occurrence of a lib for 68 | # now. 69 | break 70 | else: 71 | print("Load symbols of mremap-ed libraries") 72 | 73 | # Find all libs that have an offset of 0x1000 and an empty mapping 74 | # just before. 75 | mremap_libs = [] 76 | for i, line in enumerate(maplines[1:], start=1): 77 | prev_line = maplines[i - 1].strip().split() 78 | line = line.strip().split() 79 | 80 | if len(line) == 5 and line[3] == "0x1000" and len(prev_line) == 4: 81 | mremap_libs.append((f"{line[0]}-0x1000", line[4])) 82 | 83 | for addr_start, lib in mremap_libs: 84 | self.run_add_symbol_file(from_tty, lib, addr_start) 85 | 86 | if pagination: 87 | gdb.execute("set pagination on") 88 | 89 | 90 | AddSaBReSymbols() 91 | -------------------------------------------------------------------------------- /includes/arch/handle_rdtsc.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef HANDLE_RDTSC_H 9 | #define HANDLE_RDTSC_H 10 | 11 | #include "compiler.h" 12 | 13 | void rdtsc_entrypoint(void) __internal; 14 | 15 | #endif /* !HANDLE_RDTSC_H */ 16 | -------------------------------------------------------------------------------- /includes/arch/handle_syscall.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef HANDLE_SYSCALL_H 9 | #define HANDLE_SYSCALL_H 10 | 11 | #include "compiler.h" 12 | 13 | void handle_syscall() __internal; 14 | 15 | #endif /* !HANDLE_SYSCALL_H */ 16 | -------------------------------------------------------------------------------- /includes/arch/handle_syscall_loader.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef HANDLE_SYSCALL_LOADER_H 9 | #define HANDLE_SYSCALL_LOADER_H 10 | 11 | #include "compiler.h" 12 | 13 | void handle_syscall_loader() __internal; 14 | 15 | #endif /* !HANDLE_SYSCALL_LOADER_H */ 16 | -------------------------------------------------------------------------------- /includes/arch/handle_vdso.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef HANDLE_VDSO_H 9 | #define HANDLE_VDSO_H 10 | 11 | #include "compiler.h" 12 | 13 | void handle_vdso(void) __internal; 14 | 15 | #endif /* !HANDLE_VDSO_H */ 16 | -------------------------------------------------------------------------------- /includes/arch/rewriter_api.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef SABRE_INCLUDES_ARCH_REWRITER_API_H_ 9 | #define SABRE_INCLUDES_ARCH_REWRITER_API_H_ 10 | 11 | #include "loader/rewriter.h" 12 | #include "plugins/sbr_api_defs.h" 13 | #include 14 | 15 | extern const size_t JUMP_SIZE; 16 | 17 | void patch_syscalls_in_range(struct library *lib, char *start, char *stop, 18 | char **extra_space, int *extra_len, bool loader); 19 | void api_detour_func(struct library *lib, char *start, char *end, 20 | sbr_icept_callback_fn callback, char **extra_space, 21 | int *extra_len); 22 | void detour_func(struct library *lib, char *start, char *end, int syscall_no, 23 | char **extra_space, int *extra_len); 24 | 25 | #endif /* SABRE_INCLUDES_ARCH_REWRITER_API_H_ */ 26 | -------------------------------------------------------------------------------- /includes/arch/rewriter_tools.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef SABRE_INCLUDES_ARCH_REWRITER_TOOLS_H_ 9 | #define SABRE_INCLUDES_ARCH_REWRITER_TOOLS_H_ 10 | 11 | #include "macros.h" 12 | #include "rbtree.h" 13 | #include "rewriter_api.h" 14 | 15 | #include 16 | #include 17 | 18 | struct branch_target { 19 | char *addr; 20 | struct rb_node rb_target; 21 | }; 22 | 23 | #define rb_entry_target(node) rb_entry((node), struct branch_target, rb_target) 24 | 25 | /** 26 | * Returns a pointer pointing to the first target whose address does not compare 27 | * less than @p addr 28 | */ 29 | static inline struct branch_target *rb_lower_bound_target(struct rb_root *root, 30 | char *addr) { 31 | struct rb_node *n = root->rb_node; 32 | struct rb_node *parent = NULL; 33 | struct branch_target *target; 34 | 35 | while (n) { 36 | target = rb_entry_target(n); 37 | 38 | if (!(target->addr < addr)) { 39 | parent = n; 40 | n = n->rb_left; 41 | } else 42 | n = n->rb_right; 43 | } 44 | return parent ? rb_entry_target(parent) : NULL; 45 | } 46 | 47 | /** 48 | * Returns an iterator pointing to the first target whose address compares 49 | * greater than @p addr 50 | */ 51 | static inline struct branch_target *rb_upper_bound_target(struct rb_root *root, 52 | char *addr) { 53 | struct rb_node *n = root->rb_node; 54 | struct rb_node *parent = NULL; 55 | struct branch_target *target; 56 | 57 | while (n) { 58 | target = rb_entry_target(n); 59 | 60 | if (target->addr > addr) { 61 | parent = n; 62 | n = n->rb_left; 63 | } else 64 | n = n->rb_right; 65 | } 66 | return parent ? rb_entry_target(parent) : NULL; 67 | } 68 | 69 | static inline struct branch_target * 70 | __rb_insert_target(struct rb_root *root, char *addr, struct rb_node *node) { 71 | struct rb_node **p = &root->rb_node; 72 | struct rb_node *parent = NULL; 73 | struct branch_target *target; 74 | 75 | while (*p) { 76 | parent = *p; 77 | target = rb_entry(parent, struct branch_target, rb_target); 78 | 79 | if (addr < target->addr) 80 | p = &(*p)->rb_left; 81 | else if (addr > target->addr) 82 | p = &(*p)->rb_right; 83 | else 84 | return target; 85 | } 86 | 87 | rb_link_node(node, parent, p); 88 | 89 | return NULL; 90 | } 91 | 92 | static inline struct branch_target * 93 | rb_insert_target(struct rb_root *root, char *addr, struct rb_node *node) { 94 | struct branch_target *ret; 95 | if ((ret = __rb_insert_target(root, addr, node))) 96 | goto out; 97 | rb_insert_color(node, root); 98 | out: 99 | return ret; 100 | } 101 | 102 | static inline char *alloc_scratch_space(int fd, char *addr, int needed, 103 | char **extra_space, int *extra_len, 104 | bool near, uint64_t max_distance) { 105 | if (needed > *extra_len || 106 | (near && labs(*extra_space - (char *)(addr)) > (long)max_distance)) { 107 | // Start a new scratch page and mark any previous page as write-protected 108 | if (*extra_space) 109 | mprotect(*extra_space, 4096, PROT_READ | PROT_EXEC); 110 | // Our new scratch space is initially executable and writable. 111 | *extra_len = 4096; 112 | *extra_space = 113 | maps_alloc_near(fd, addr, *extra_len, 114 | PROT_READ | PROT_WRITE | PROT_EXEC, near, max_distance); 115 | _nx_debug_printf("alloc_scratch_space: mapped %x at %p (near %p)\n", 116 | *extra_len, *extra_space, addr); 117 | } 118 | if (*extra_space) { 119 | *extra_len -= needed; 120 | return *extra_space + *extra_len; 121 | } 122 | _nx_fatal_printf("No space left to allocate scratch space"); 123 | } 124 | 125 | /** 126 | * Compute the amount of space needed to accommodate relocated instructions 127 | * 128 | * @param[in] code relocatable instructions 129 | * @param[out] needed total amount of bytes to write 130 | * @param[out] postamble amount of bytes to relocate 131 | * @param[out] second first instruction not to be relocated 132 | * @param[in] detour_asm_size size of static ASM body 133 | * @param[in] jump_size size of the jump snippet 134 | */ 135 | static inline void needed_space(const struct s_code *code, int *needed, 136 | int *postamble, int *second, 137 | size_t detour_asm_size, size_t jump_size) { 138 | int additional_bytes_to_relocate = 139 | (__WORDSIZE == 32 ? 6 : jump_size) - code[0].len; 140 | *second = 0; 141 | while (additional_bytes_to_relocate > 0) { 142 | *second = (*second + 1) % jump_size; 143 | additional_bytes_to_relocate -= code[*second].len; 144 | } 145 | *postamble = (code[*second].addr + code[*second].len) - code[0].addr; 146 | 147 | // The following is all the code that construct the various bits of 148 | // assembly code. 149 | *needed = detour_asm_size + *postamble + jump_size; 150 | } 151 | 152 | #endif /* SABRE_INCLUDES_ARCH_REWRITER_TOOLS_H_ */ 153 | -------------------------------------------------------------------------------- /includes/arch/syscall_stackframe.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef SABRE_INCLUDES_ARCH_SYSCALL_STACKFRAME_H_ 9 | #define SABRE_INCLUDES_ARCH_SYSCALL_STACKFRAME_H_ 10 | 11 | #include 12 | 13 | // Stack frame built by handle_syscall and in the patching code in rewriter.c 14 | struct syscall_stackframe; 15 | 16 | void *get_syscall_return_address(struct syscall_stackframe *stack_frame); 17 | size_t get_offsetof_syscall_return_address(void); 18 | 19 | #endif /* SABRE_INCLUDES_ARCH_SYSCALL_STACKFRAME_H_ */ 20 | -------------------------------------------------------------------------------- /includes/compiler.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef COMPILER_H_ 9 | #define COMPILER_H_ 10 | 11 | #define __packed __attribute__((packed)) 12 | 13 | #define __unused __attribute__((unused)) 14 | 15 | #define attribute_hidden __attribute__((visibility("hidden"))) 16 | 17 | #define __hidden __attribute__((visibility("hidden"))) 18 | #define __internal __attribute__((visibility("internal"))) 19 | 20 | #define unreferenced_var(x) \ 21 | do { \ 22 | (void)x; \ 23 | } while (0) 24 | #define ignore_result(x) \ 25 | do { \ 26 | __typeof__(x) z = x; \ 27 | (void)sizeof z; \ 28 | } while (0) 29 | 30 | #ifndef __always_inline 31 | #define __always_inline inline __attribute__((always_inline)) 32 | #endif 33 | 34 | #define unreachable() __builtin_unreachable() 35 | 36 | #endif /* COMPILER_H_ */ 37 | -------------------------------------------------------------------------------- /includes/hash.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | 3 | #ifndef HASH_H_ 4 | #define HASH_H_ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __AVX2__ 11 | #include 12 | #endif 13 | 14 | /* 15 | * Knuth recommends primes in approximately golden ratio to the maximum 16 | * integer representable by a machine word for multiplicative _hashing. 17 | * Chuck Lever verified the effectiveness of this technique: 18 | * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf 19 | * 20 | * These primes are chosen to be bit-sparse, that is operations on them can 21 | * use shifts and additions instead of multiplications for machines where 22 | * multiplications are slow. 23 | */ 24 | 25 | /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ 26 | #define GOLDEN_RATIO_PRIME_32 0x9e370001UL 27 | /* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ 28 | #define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL 29 | 30 | #if __WORDSIZE == 32 31 | #define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32 32 | #define hash_long(val, bits) hash_32(val, bits) 33 | #elif __WORDSIZE == 64 34 | #define hash_long(val, bits) hash_64(val, bits) 35 | #define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64 36 | #endif 37 | 38 | static inline uint64_t hash_64(uint64_t val, unsigned int bits) { 39 | uint64_t hash = val; 40 | 41 | uint64_t n = hash; 42 | n <<= 18; 43 | hash -= n; 44 | n <<= 33; 45 | hash -= n; 46 | n <<= 3; 47 | hash += n; 48 | n <<= 3; 49 | hash -= n; 50 | n <<= 4; 51 | hash += n; 52 | n <<= 2; 53 | hash += n; 54 | 55 | // High bits are more random, so use them 56 | return hash >> (64 - bits); 57 | } 58 | 59 | static inline uint32_t hash_32(uint32_t val, unsigned int bits) { 60 | uint32_t hash = val * GOLDEN_RATIO_PRIME_32; 61 | 62 | // High bits are more random, so use them 63 | return hash >> (32 - bits); 64 | } 65 | 66 | static inline unsigned long hash_ptr(const void *ptr, unsigned int bits) { 67 | return hash_long((unsigned long)ptr, bits); 68 | } 69 | 70 | static inline unsigned long hash_internal(const void *data, unsigned int len) { 71 | unsigned char *p = (unsigned char *)data; 72 | unsigned char *e = p + len; 73 | uint64_t h = 0xfeedbeeffeedbeef; 74 | 75 | #ifdef __AVX2__ 76 | // Proceed in 8x32 bit steps 77 | 78 | __m256i pack_h = _mm256_set1_epi32(0xfeedbeef); 79 | __m256i pack_golden = _mm256_set1_epi32(0x9e3779b9); 80 | // 32 bit golden number 81 | // From http://burtleburtle.net/bob/hash/evahash.html 82 | 83 | while (true) { 84 | unsigned char *aux = p + sizeof(pack_h); 85 | if (aux > e) 86 | break; 87 | 88 | __m256i pack_p = _mm256_loadu_si256((void *)p); 89 | 90 | pack_h = _mm256_xor_si256(pack_h, pack_p); 91 | pack_h = _mm256_mullo_epi32(pack_h, pack_golden); 92 | 93 | p = aux; 94 | } 95 | 96 | uint64_t result[4]; 97 | _mm256_storeu_si256((void *)result, pack_h); 98 | 99 | h = result[0]; 100 | h ^= result[1]; 101 | h ^= result[2]; 102 | h ^= result[3]; 103 | 104 | #else 105 | // Proceed in 64 bit steps 106 | while (true) { 107 | unsigned char *aux = p + sizeof(h); 108 | if (aux > e) 109 | break; 110 | 111 | h ^= *(uint64_t *)(p); 112 | h *= 0x9e3779b97f4a7c13LL; 113 | // 64 bit golden number 114 | // From http://burtleburtle.net/bob/hash/evahash.html 115 | 116 | p = aux; 117 | } 118 | #endif 119 | 120 | // Finish 121 | while (p < e) { 122 | h ^= (uint64_t)(*p++); 123 | h *= 0x9e3779b97f4a7c13LL; 124 | } 125 | 126 | return h; 127 | } 128 | 129 | #endif /* HASH_H */ 130 | -------------------------------------------------------------------------------- /includes/hlist.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | 3 | #ifndef HLIST_H_ 4 | #define HLIST_H_ 5 | 6 | #include 7 | 8 | #include "kernel.h" 9 | 10 | /** Double linked lists with a single pointer list head */ 11 | struct hlist_head { 12 | struct hlist_node *first; 13 | }; 14 | 15 | /** Linked list node */ 16 | struct hlist_node { 17 | struct hlist_node *next, **pprev; 18 | }; 19 | 20 | #define HLIST_HEAD_INIT \ 21 | { .first = NULL } 22 | #define HLIST_HEAD(name) struct hlist_head name = {.first = NULL} 23 | #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) 24 | 25 | static inline void INIT_HLIST_NODE(struct hlist_node *h) { 26 | h->next = NULL; 27 | h->pprev = NULL; 28 | } 29 | 30 | static inline bool hlist_unhashed(const struct hlist_node *h) { 31 | return !h->pprev; 32 | } 33 | 34 | /** 35 | * Tests whether a list is empty. 36 | * 37 | * @param head list to test 38 | */ 39 | static inline bool hlist_empty(const struct hlist_head *h) { return !h->first; } 40 | 41 | /** 42 | * Delete a list entry. 43 | */ 44 | static inline void __hlist_del(struct hlist_node *n) { 45 | struct hlist_node *next = n->next; 46 | struct hlist_node **pprev = n->pprev; 47 | *pprev = next; 48 | if (next) 49 | next->pprev = pprev; 50 | } 51 | 52 | /** 53 | * Deletes entry from list. 54 | * 55 | * Note that empty list on entry does not return true after this, 56 | * the entry is in an undefined state. 57 | * 58 | * @param entry element to delete from the list 59 | */ 60 | static inline void hlist_del(struct hlist_node *n) { 61 | __hlist_del(n); 62 | n->next = (void *)0; 63 | n->pprev = (void *)0; 64 | } 65 | 66 | /** 67 | * Deletes entry from list and reinitialize it. 68 | * 69 | * @param entry element to delete from the list 70 | */ 71 | static inline void hlist_del_init(struct hlist_node *n) { 72 | if (!hlist_unhashed(n)) { 73 | __hlist_del(n); 74 | INIT_HLIST_NODE(n); 75 | } 76 | } 77 | 78 | /** 79 | * Add a new entry. 80 | * 81 | * Insert a new entry after the specified head. 82 | * 83 | * @param new new entry to be added 84 | * @param head list head to add it after 85 | */ 86 | static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { 87 | struct hlist_node *first = h->first; 88 | n->next = first; 89 | if (first) 90 | first->pprev = &n->next; 91 | h->first = n; 92 | n->pprev = &h->first; 93 | } 94 | 95 | /** 96 | * Add a new entry. 97 | * 98 | * Insert a new entry before the specified entry. 99 | * 100 | * @param new new entry to be added 101 | * @param head entry to add it before 102 | */ 103 | static inline void hlist_add_before(struct hlist_node *n, 104 | struct hlist_node *next) { 105 | n->pprev = next->pprev; 106 | n->next = next; 107 | next->pprev = &n->next; 108 | *(n->pprev) = n; 109 | } 110 | 111 | /** 112 | * Add a new entry. 113 | * 114 | * Insert a new entry after the specified entry. 115 | * 116 | * @param n new entry to be added 117 | * @param next entry to add it after 118 | */ 119 | static inline void hlist_add_after(struct hlist_node *n, 120 | struct hlist_node *next) { 121 | next->next = n->next; 122 | n->next = next; 123 | next->pprev = &n->next; 124 | 125 | if (next->next) 126 | next->next->pprev = &next->next; 127 | } 128 | 129 | /** 130 | * Move a list from one list head to another. 131 | * 132 | * @param list entry to move 133 | * @param head head that will precede our entry 134 | */ 135 | static inline void hlist_move_list(struct hlist_head *old, 136 | struct hlist_head *new) { 137 | new->first = old->first; 138 | if (new->first) 139 | new->first->pprev = &new->first; 140 | old->first = NULL; 141 | } 142 | 143 | /** 144 | * Get the struct for this entry. 145 | * 146 | * @param ptr struct list head pointer 147 | * @param type type of the struct this is embedded in 148 | * @param member name of the list struct within the struct 149 | */ 150 | #define hlist_entry(ptr, type, member) container_of(ptr, type, member) 151 | 152 | #define hlist_entry_safe(ptr, type, member) \ 153 | ({ \ 154 | typeof(ptr) ____ptr = (ptr); \ 155 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ 156 | }) 157 | 158 | /** 159 | * Get the first element from a list. 160 | * 161 | * @param ptr list head to take the element from 162 | * @param type type of the struct this is embedded in 163 | * @param member name of the list struct within the struct 164 | */ 165 | #define hlist_first_entry(head, type, member) \ 166 | list_entry((ptr)->first, type, member) 167 | 168 | /** 169 | * Get the first element from a list. 170 | * 171 | * @param ptr list head to take the element from 172 | * @param type type of the struct this is embedded in 173 | * @param member name of the list struct within the struct 174 | */ 175 | #define hlist_next_entry(node, type, member) \ 176 | list_entry((node)->member.next, type, member) 177 | 178 | /** 179 | * Iterate over a list. 180 | * 181 | * @param pos struct list head to use as a loop counter 182 | * @param head head for your list 183 | */ 184 | #define hlist_for_each(pos, head) \ 185 | for (pos = (head)->first; pos; pos = pos->next) 186 | 187 | /** 188 | * Iterate over a list safe against removal of list entry. 189 | * 190 | * @param pos struct list head to use as a loop counter 191 | * @param n another struct list head to use as temporary storage 192 | * @param head head for your list 193 | */ 194 | #define hlist_for_each_safe(pos, n, head) \ 195 | for (pos = (head)->first; pos && ({ \ 196 | n = pos->next; \ 197 | 1; \ 198 | }); \ 199 | pos = n) 200 | 201 | /** 202 | * Iterate over list of given type. 203 | * 204 | * @param tpos type pointer to use as a loop cursor 205 | * @param pos node pointer to use as a loop cursor 206 | * @param head head for your list 207 | * @param member name of the list structure within the struct 208 | */ 209 | #define hlist_for_each_entry(tpos, pos, head, member) \ 210 | for (pos = (head)->first; pos && ({ \ 211 | tpos = hlist_entry(pos, typeof(*tpos), member); \ 212 | 1; \ 213 | }); \ 214 | pos = pos->next) 215 | 216 | /** 217 | * Iterate over list of given type continuing after current point. 218 | * 219 | * @param tpos type pointer to use as a loop cursor 220 | * @param pos node pointer to use as a loop cursor 221 | * @param member name of the list structure within the struct 222 | */ 223 | #define hlist_for_each_entry_continue(tpos, pos, member) \ 224 | for (pos = (pos)->next; pos && ({ \ 225 | tpos = hlist_entry(pos, typeof(*tpos), member); \ 226 | 1; \ 227 | }); \ 228 | pos = pos->next) 229 | 230 | /** 231 | * Iterate over list of given type continuing from current point. 232 | * 233 | * @param tpos type pointer to use as a loop cursor 234 | * @param pos node pointer to use as a loop cursor 235 | * @param member name of the list structure within the struct 236 | */ 237 | #define hlist_for_each_entry_from(tpos, pos, member) \ 238 | for (; pos && ({ \ 239 | tpos = hlist_entry(pos, typeof(*tpos), member); \ 240 | 1; \ 241 | }); \ 242 | pos = pos->next) 243 | 244 | /** 245 | * Iterate over list of given type safe against removal of list entry. 246 | * 247 | * @param tpos type pointer to use as a loop cursor 248 | * @param pos node pointer to use as a loop cursor 249 | * @param n another type pointer to use as temporary storage 250 | * @param head head for your list 251 | * @param member name of the list structure within the struct 252 | */ 253 | #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ 254 | for (pos = (head)->first; pos && ({ \ 255 | n = pos->next; \ 256 | 1; \ 257 | }) && \ 258 | ({ \ 259 | tpos = hlist_entry(pos, typeof(*tpos), member); \ 260 | 1; \ 261 | }); \ 262 | pos = n) 263 | 264 | #endif /* HLIST_H_ */ 265 | -------------------------------------------------------------------------------- /includes/jhash.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | 3 | #ifndef JHASH_H_ 4 | #define JHASH_H_ 5 | 6 | #include 7 | 8 | /** 9 | * Rotate a 32-bit value left. 10 | * @param word value to rotate 11 | * @param shift bits to roll 12 | */ 13 | static inline uint32_t rol32(uint32_t word, unsigned int shift) { 14 | return (word << shift) | (word >> (32 - shift)); 15 | } 16 | 17 | /* Best hash sizes are of power of two */ 18 | #define jhash_size(n) ((uint32_t)1 << (n)) 19 | /* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */ 20 | #define jhash_mask(n) (jhash_size(n) - 1) 21 | 22 | /** Mix 3 32-bit values reversibly */ 23 | #define __jhash_mix(a, b, c) \ 24 | ({ \ 25 | a -= c; \ 26 | a ^= rol32(c, 4); \ 27 | c += b; \ 28 | b -= a; \ 29 | b ^= rol32(a, 6); \ 30 | a += c; \ 31 | c -= b; \ 32 | c ^= rol32(b, 8); \ 33 | b += a; \ 34 | a -= c; \ 35 | a ^= rol32(c, 16); \ 36 | c += b; \ 37 | b -= a; \ 38 | b ^= rol32(a, 19); \ 39 | a += c; \ 40 | c -= b; \ 41 | c ^= rol32(b, 4); \ 42 | b += a; \ 43 | }) 44 | 45 | /** Final mixing of 3 32-bit values (a,b,c) into c */ 46 | #define __jhash_final(a, b, c) \ 47 | ({ \ 48 | c ^= b; \ 49 | c -= rol32(b, 14); \ 50 | a ^= c; \ 51 | a -= rol32(c, 11); \ 52 | b ^= a; \ 53 | b -= rol32(a, 25); \ 54 | c ^= b; \ 55 | c -= rol32(b, 16); \ 56 | a ^= c; \ 57 | a -= rol32(c, 4); \ 58 | b ^= a; \ 59 | b -= rol32(a, 14); \ 60 | c ^= b; \ 61 | c -= rol32(b, 24); \ 62 | }) 63 | 64 | /* An arbitrary initial parameter */ 65 | #define JHASH_INITVAL 0xdeadbeef 66 | 67 | /** 68 | * Hash an arbitrary key 69 | * 70 | * The generic version, hashes an arbitrary sequence of bytes. 71 | * No alignment or length assumptions are made about the input key. 72 | * 73 | * @param k sequence of bytes as key 74 | * @param length the length of the key 75 | * @param initval the previous hash, or an arbitray value 76 | * @return the hash value of the key 77 | */ 78 | static inline uint32_t jhash(const void *key, uint32_t length, 79 | uint32_t initval) { 80 | uint32_t a, b, c; 81 | const uint8_t *k = key; 82 | 83 | /* Set up the internal state */ 84 | a = b = c = JHASH_INITVAL + length + initval; 85 | 86 | /* All but the last block: affect some 32 bits of (a,b,c) */ 87 | while (length > 12) { 88 | a += (k[0] + ((uint32_t)k[1] << 8) + ((uint32_t)k[2] << 16) + 89 | ((uint32_t)k[3] << 24)); 90 | b += (k[4] + ((uint32_t)k[5] << 8) + ((uint32_t)k[6] << 16) + 91 | ((uint32_t)k[7] << 24)); 92 | c += (k[8] + ((uint32_t)k[9] << 8) + ((uint32_t)k[10] << 16) + 93 | ((uint32_t)k[11] << 24)); 94 | __jhash_mix(a, b, c); 95 | length -= 12; 96 | k += 12; 97 | } 98 | /* Last block: affect all 32 bits of (c) */ 99 | /* All the case statements fall through */ 100 | switch (length) { 101 | case 12: 102 | c += (uint32_t)k[11] << 24; 103 | // fall through 104 | case 11: 105 | c += (uint32_t)k[10] << 16; 106 | // fall through 107 | case 10: 108 | c += (uint32_t)k[9] << 8; 109 | // fall through 110 | case 9: 111 | c += k[8]; 112 | // fall through 113 | case 8: 114 | b += (uint32_t)k[7] << 24; 115 | // fall through 116 | case 7: 117 | b += (uint32_t)k[6] << 16; 118 | // fall through 119 | case 6: 120 | b += (uint32_t)k[5] << 8; 121 | // fall through 122 | case 5: 123 | b += k[4]; 124 | // fall through 125 | case 4: 126 | a += (uint32_t)k[3] << 24; 127 | // fall through 128 | case 3: 129 | a += (uint32_t)k[2] << 16; 130 | // fall through 131 | case 2: 132 | a += (uint32_t)k[1] << 8; 133 | // fall through 134 | case 1: 135 | a += k[0]; 136 | __jhash_final(a, b, c); 137 | // fall through 138 | case 0: /* Nothing left to add */ 139 | break; 140 | } 141 | 142 | return c; 143 | } 144 | 145 | #endif /* JHASH_H_ */ 146 | -------------------------------------------------------------------------------- /includes/loader/debuginfo.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef DEBUGINFO_H 9 | #define DEBUGINFO_H 10 | 11 | // Lookup external debug info file for a given executable/library 12 | char *debuginfo_lookup_external(const char *absolute_path); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /includes/loader/elf_loading.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef ELF_LOADING_H 9 | #define ELF_LOADING_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int elfld_getehdr(int, ElfW(Ehdr) *); 17 | GElf_Sym find_elf_symbol(const char *, const char *, bool *); 18 | bool read_elf_note(const char *path, Elf64_Word note_type, const char *owner, 19 | void *notebuf, size_t *notesz); 20 | bool read_elf_section(const char *path, const char *section_name, void *scbuf, 21 | size_t *scsz); 22 | ElfW(Addr) addr_of_elf_symbol(const char *, const char *, bool *); 23 | ElfW(Addr) elfld_load_elf(int fd, ElfW(Ehdr) const *ehdr, size_t pagesize, 24 | ElfW(Addr) * out_phdr, ElfW(Addr) * out_phnum, 25 | const char **out_interp); 26 | 27 | #endif /* !ELF_LOADING_H */ 28 | -------------------------------------------------------------------------------- /includes/loader/global_vars.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef GLOBAL_VARS_H 9 | #define GLOBAL_VARS_H 10 | 11 | #include 12 | 13 | #include "plugins/sbr_api_defs.h" 14 | 15 | #define MAX_ICEPT_RECORDS 50 16 | #define MAX_ICEPT_STRLEN 80 17 | 18 | typedef struct { 19 | char lib_name[MAX_ICEPT_STRLEN]; 20 | char fn_name[MAX_ICEPT_STRLEN]; 21 | sbr_icept_callback_fn callback; 22 | } sbr_fn_icept_local_struct; 23 | 24 | extern int plugin_argc; 25 | extern char **plugin_argv; 26 | extern char abs_sabre_path[PATH_MAX]; 27 | extern char abs_plugin_path[PATH_MAX]; 28 | extern char abs_client_path[PATH_MAX]; 29 | 30 | extern int registered_icept_cnt; 31 | extern sbr_fn_icept_local_struct intercept_records[MAX_ICEPT_RECORDS]; 32 | extern sbr_icept_vdso_callback_fn vdso_callback; 33 | extern sbr_sc_handler_fn plugin_sc_handler; 34 | #ifdef __NX_INTERCEPT_RDTSC 35 | extern sbr_rdtsc_handler_fn plugin_rdtsc_handler; 36 | #endif 37 | extern calling_from_plugin_fn calling_from_plugin; 38 | extern enter_plugin_fn enter_plugin; 39 | extern exit_plugin_fn exit_plugin; 40 | extern is_vdso_ready_fn is_vdso_ready; 41 | 42 | extern const char *known_syscall_libs[]; 43 | 44 | void register_function_intercepts(const sbr_fn_icept_struct *); 45 | 46 | #endif /* !GLOBAL_VARS_H */ 47 | -------------------------------------------------------------------------------- /includes/loader/ld_sc_handler.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef LD_SC_HANDLER_H 9 | #define LD_SC_HANDLER_H 10 | 11 | void load_client_tls(); 12 | void load_sabre_tls(); 13 | 14 | long runtime_syscall_router(long, long, long, long, long, long, long, void *); 15 | void_void_fn ld_vdso_callback(long, void_void_fn); 16 | void setup_plugin_vdso(sbr_icept_vdso_callback_fn); 17 | 18 | #endif /* !LD_SC_HANDLER_H */ 19 | -------------------------------------------------------------------------------- /includes/loader/maps.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2010 The Chromium Authors. All rights reserved. 2 | * Copyright © 2019 Software Reliability Group, Imperial College London 3 | * 4 | * This file is part of SaBRe. 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later AND BSD-3-Clause 7 | */ 8 | 9 | #ifndef MAPS_H_ 10 | #define MAPS_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "compiler.h" 20 | #include "hlist.h" 21 | #include "jhash.h" 22 | #include "list.h" 23 | #include "rbtree.h" 24 | 25 | /** Process memory regions */ 26 | enum region_type { 27 | REGION_EXECUTABLE = 0x1, 28 | REGION_LIBRARY = 0x2, 29 | REGION_HEAP = 0x4, 30 | REGION_STACK = 0x8, 31 | REGION_BSS = 0x10, 32 | REGION_VDSO = 0x20, 33 | REGION_ALL = 0x7F, 34 | }; 35 | 36 | #define LIBS_HASHTABLE_SIZE 16 37 | #define library_hashfn(n) jhash(n, strlen(n), 0) & (LIBS_HASHTABLE_SIZE - 1) 38 | #define libraryhash_entry(node) \ 39 | hlist_entry_safe((node), struct library, library_hash) 40 | 41 | #define sectionhash_size 16 42 | #define symbolhash_size 16 43 | 44 | struct maps { 45 | int fd; 46 | 47 | struct library *lib_vdso; 48 | 49 | // This is a hash table: 50 | struct hlist_head libraries[LIBS_HASHTABLE_SIZE]; 51 | }; 52 | 53 | /** Region obtained via /proc//maps */ 54 | struct region { 55 | /** Region start address */ 56 | void *start; 57 | /** Region end address */ 58 | void *end; 59 | /** Region size */ 60 | size_t size; 61 | /** Access protection */ 62 | int perms; 63 | /** Region offset */ 64 | ElfW(Addr) offset; 65 | /** Device identifier */ 66 | dev_t dev; 67 | /** Device inode */ 68 | ino_t inode; 69 | /** Associated pathname */ 70 | const char *pathname; 71 | /** Region type */ 72 | enum region_type type; 73 | /** Regions tree */ 74 | struct rb_node rb_region; 75 | }; 76 | 77 | uintptr_t first_region(const char *); 78 | uintptr_t end_of_stack_region(); 79 | struct maps *maps_read(const char *libname) attribute_hidden; 80 | void *maps_alloc_near(int maps_fd, void *addr, size_t size, int prot, bool near, 81 | uint64_t max_distance) attribute_hidden; 82 | void maps_release(struct maps *maps) attribute_hidden; 83 | void binrw_rd_init_maps(void) attribute_hidden; 84 | 85 | /** 86 | * Iterate over hash table elements of given type. 87 | * 88 | * @param tpos type pointer to use as a loop cursor 89 | * @param pos entry pointer to use as a loop cursor 90 | * @param table your table 91 | * @param member the name of the enry within the struct 92 | */ 93 | #define for_each_library(lib, maps) \ 94 | for (int i = 0; i < LIBS_HASHTABLE_SIZE; ++i) \ 95 | for (lib = libraryhash_entry((maps)->libraries[i].first); lib; \ 96 | lib = libraryhash_entry(lib->library_hash.next)) 97 | 98 | #endif /* MAPS_H_ */ 99 | -------------------------------------------------------------------------------- /includes/loader/patchelf.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef PATHELF_H 9 | #define PATHELF_H 10 | 11 | #include 12 | 13 | void inject_needed_lib(const char *elfpath, const char *pluginpath, int fd, 14 | bool debug); 15 | 16 | #endif /* !PATHELF_H */ 17 | -------------------------------------------------------------------------------- /includes/loader/premain.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef PREMAIN_H 9 | #define PREMAIN_H 10 | 11 | #include "plugins/sbr_api_defs.h" 12 | 13 | // Copied from: 14 | // https://code.woboq.org/userspace/glibc/include/link.h.html#link_map 15 | #define DT_THISPROCNUM 0 16 | struct ld_link_map { 17 | ElfW(Addr) l_addr; 18 | char *l_name; 19 | ElfW(Dyn) * l_ld; 20 | struct link_map *l_next, *l_prev; 21 | struct link_map *l_real; 22 | Lmid_t l_ns; 23 | struct libname_list *l_libname; 24 | ElfW(Dyn) * l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + 25 | DT_VALNUM + DT_ADDRNUM]; 26 | }; 27 | 28 | void setup_sbr_premain(sbr_icept_reg_fn); 29 | 30 | #endif /* !PREMAIN_H */ 31 | -------------------------------------------------------------------------------- /includes/loader/rewriter.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2010 The Chromium Authors. All rights reserved. 2 | * Copyright © 2019 Software Reliability Group, Imperial College London 3 | * 4 | * This file is part of SaBRe. 5 | * 6 | * SPDX-License-Identifier: GPL-3.0-or-later AND BSD-3-Clause 7 | */ 8 | 9 | #ifndef LIBRARY_H_ 10 | #define LIBRARY_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "compiler.h" 18 | #include "loader/maps.h" 19 | 20 | struct symbol { 21 | const char *name; 22 | ElfW(Sym) sym; 23 | struct hlist_node symbol_hash; 24 | }; 25 | 26 | /* Internal data structure for sections. */ 27 | struct section { 28 | const char *name; /* section name */ 29 | ElfW(Shdr) shdr; /* section header */ 30 | struct hlist_node section_hash; 31 | }; 32 | 33 | struct library { 34 | char *pathname; 35 | bool valid; 36 | bool vdso; 37 | char *asr_offset; 38 | ElfW(Ehdr) ehdr; 39 | struct rb_root rb_region; 40 | struct hlist_head *section_hash; 41 | struct hlist_head *symbol_hash; 42 | char *image; 43 | size_t image_size; 44 | struct maps *maps; // TODO(andronat): do we really need this? 45 | struct hlist_node library_hash; 46 | }; 47 | 48 | struct s_code { 49 | char *addr; 50 | int len; 51 | unsigned short insn; 52 | bool is_ip_relative; 53 | }; 54 | 55 | int which_lib_name_interesting(const char *interesting_libs[], 56 | const char *pathname); 57 | void memorymaps_rewrite_all(const char *libs[], const char *bin, bool loader); 58 | void memorymaps_rewrite_lib(const char *libname); 59 | 60 | #endif /* LIBRARY_H_ */ 61 | -------------------------------------------------------------------------------- /includes/macros.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef MACROS_H 9 | #define MACROS_H 10 | 11 | #include 12 | #include 13 | 14 | #define _nx_fatal_printf(fmt, args...) \ 15 | do { \ 16 | dprintf(2, "Fatal error in %s:%u\n", __FILE__, __LINE__); \ 17 | dprintf(2, fmt, ##args); \ 18 | exit(127); \ 19 | } while (0) 20 | 21 | #if SBR_DEBUG 22 | #define _nx_debug_printf(fmt, args...) \ 23 | do { \ 24 | dprintf(2, "Debug in %s at %s:%u\n\t", __func__, __FILE__, __LINE__); \ 25 | dprintf(2, fmt, ##args); \ 26 | } while (0) 27 | #else 28 | #define _nx_debug_printf(fmt, args...) \ 29 | do { \ 30 | ; \ 31 | } while (0) 32 | #endif 33 | 34 | #define __round_mask(x, y) ((__typeof__(x))((y)-1)) 35 | #define round_up(x, y) ((((x)-1) | __round_mask(x, y)) + 1) 36 | #define round_down(x, y) ((x) & ~__round_mask(x, y)) 37 | 38 | // This works for syscalls made through libc which sets errno when fail. This 39 | // does not work for syscalls made directly to the kernel, which signals errors 40 | // by returning a negative value 41 | #define NOINTR(x) \ 42 | ({ \ 43 | typeof(x) __i; \ 44 | while ((__i = (x)) < 0 && errno == EINTR) \ 45 | ; \ 46 | __i; \ 47 | }) 48 | 49 | #endif /* !MACROS_H */ 50 | -------------------------------------------------------------------------------- /includes/plugins/real_syscall.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef REAL_SYSCALL_H 9 | #define REAL_SYSCALL_H 10 | 11 | #include 12 | 13 | #ifndef SYS_clone3 14 | #include 15 | #include 16 | 17 | #define SYS_clone3 435 18 | 19 | // Older compilers don't have this definition yet. 20 | struct clone_args { 21 | __aligned_u64 flags; 22 | __aligned_u64 pidfd; 23 | __aligned_u64 child_tid; 24 | __aligned_u64 parent_tid; 25 | __aligned_u64 exit_signal; 26 | __aligned_u64 stack; 27 | __aligned_u64 stack_size; 28 | __aligned_u64 tls; 29 | __aligned_u64 set_tid; 30 | __aligned_u64 set_tid_size; 31 | __aligned_u64 cgroup; 32 | }; 33 | #endif 34 | 35 | long real_syscall(long sc_no, long arg1, long arg2, long arg3, long arg4, 36 | long arg5, long arg6); 37 | 38 | long clone_syscall(unsigned long flags, void *child_stack, int *ptid, int *ctid, 39 | unsigned long newtls, void *ret_addr, void *ctx); 40 | 41 | long clone3_syscall(long arg1, long arg2, long arg3, int not_used, long arg5, 42 | void *ret_addr, void *ctx); 43 | 44 | long vfork_syscall(); 45 | long vfork_return_from_child(void *wrapper_sp); 46 | 47 | #endif /* !REAL_SYSCALL_H */ 48 | -------------------------------------------------------------------------------- /includes/plugins/sbr_api_defs.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef SBR_API_DEFS_H 9 | #define SBR_API_DEFS_H 10 | 11 | #include 12 | 13 | // Helper typedef to simplify definition of sbr_icept_callback_fn 14 | typedef void (*void_void_fn)(void); 15 | typedef void_void_fn (*sbr_icept_callback_fn)(void_void_fn); 16 | 17 | /* 18 | * Structure passed to the loader by SaBRe (or any other plugin) during 19 | * initialisation (in sbr_init). 20 | * 21 | * It contains two strings (library name as well as the name of the function 22 | * to be intercepted) and a callback function that loader calls while 23 | * intercepting the function. 24 | * 25 | * The callback function takes a function as an argument (which points to 26 | * relocated head of the function being intercepted) and returns a function 27 | * that is actually called instead of the function being intercepted. 28 | */ 29 | typedef struct sbr_fn_icept { 30 | const char *lib_name; 31 | const char *fn_name; 32 | /* 33 | * This is ugly - typedefs might help, but oh well. icept_callback is a 34 | * pointer to a function that takes a pointer to a function that takes 35 | * nothing ant returns nothing and returns a function that takes nothing and 36 | * returns nothing. Reason for that is intercepted functions will all have 37 | * different parameters anyway, so we might as well use ANY function pointer 38 | * to keep the compiler happy and cast them to whatever is required. 39 | */ 40 | // void (*(*icept_callback)(void (*)(void)))(void); 41 | sbr_icept_callback_fn icept_callback; 42 | } sbr_fn_icept_struct; 43 | 44 | // Signature for the syscall handler 45 | typedef long (*sbr_sc_handler_fn)(long, long, long, long, long, long, long, 46 | void *); 47 | 48 | #ifdef __NX_INTERCEPT_RDTSC 49 | // Signature for the RDTSC handler 50 | typedef long (*sbr_rdtsc_handler_fn)(); 51 | #endif 52 | 53 | // Signature for vDSO callback function 54 | typedef void_void_fn (*sbr_icept_vdso_callback_fn)(long, void_void_fn); 55 | 56 | // Signature for the callback registration function 57 | typedef void (*sbr_icept_reg_fn)(const sbr_fn_icept_struct *); 58 | 59 | typedef void (*sbr_post_load_fn)(bool); 60 | 61 | typedef void_void_fn sbr_premain_fn; 62 | 63 | // Signature for the sbr_init function 64 | typedef void (*sbr_init_fn)( 65 | int *, char ***, 66 | // sbr_segfault_handler_fn *segfault_handler, // - TBD 67 | sbr_icept_reg_fn, sbr_icept_vdso_callback_fn *, sbr_sc_handler_fn *, 68 | #ifdef __NX_INTERCEPT_RDTSC 69 | sbr_rdtsc_handler_fn *, 70 | #endif 71 | sbr_post_load_fn *, char *, char *); 72 | 73 | struct syscall_stackframe; 74 | void *get_syscall_return_address(struct syscall_stackframe *stack_frame); 75 | 76 | // SaBRe uses the recursion_protector shim to check if a syscall is made from 77 | // the SaBRe plugin or the client. 78 | typedef bool (*calling_from_plugin_fn)(void); 79 | typedef void (*enter_plugin_fn)(void); 80 | typedef void (*exit_plugin_fn)(void); 81 | typedef bool (*is_vdso_ready_fn)(void); 82 | 83 | #endif /* !SBR_API_DEFS_H */ 84 | -------------------------------------------------------------------------------- /includes/rbtree_augmented.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0 */ 2 | 3 | #ifndef _RBTREE_AUGMENTED_H 4 | #define _RBTREE_AUGMENTED_H 5 | 6 | #include "compiler.h" 7 | #include "rbtree.h" 8 | 9 | /* 10 | * Please note - only struct rb_augment_callbacks and the prototypes for 11 | * rb_insert_augmented() and rb_erase_augmented() are intended to be public. 12 | * The rest are implementation details you are not expected to depend on. 13 | * 14 | * See Documentation/rbtree.txt for documentation and samples. 15 | */ 16 | 17 | struct rb_augment_callbacks { 18 | void (*propagate)(struct rb_node *node, struct rb_node *stop); 19 | void (*copy)(struct rb_node *old, struct rb_node *new); 20 | void (*rotate)(struct rb_node *old, struct rb_node *new); 21 | }; 22 | 23 | static inline void __rb_insert_augmented( 24 | struct rb_node *node, struct rb_root *root, 25 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 26 | static inline void 27 | rb_insert_augmented(struct rb_node *node, struct rb_root *root, 28 | const struct rb_augment_callbacks *augment) { 29 | __rb_insert_augmented(node, root, augment->rotate); 30 | } 31 | 32 | #define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, rbtype, \ 33 | rbaugmented, rbcompute) \ 34 | static inline void rbname##_propagate(struct rb_node *rb, \ 35 | struct rb_node *stop) { \ 36 | while (rb != stop) { \ 37 | rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ 38 | rbtype augmented = rbcompute(node); \ 39 | if (node->rbaugmented == augmented) \ 40 | break; \ 41 | node->rbaugmented = augmented; \ 42 | rb = rb_parent(&node->rbfield); \ 43 | } \ 44 | } \ 45 | static inline void rbname##_copy(struct rb_node *rb_old, \ 46 | struct rb_node *rb_new) { \ 47 | rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 48 | rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 49 | new->rbaugmented = old->rbaugmented; \ 50 | } \ 51 | static void rbname##_rotate(struct rb_node *rb_old, \ 52 | struct rb_node *rb_new) { \ 53 | rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ 54 | rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ 55 | new->rbaugmented = old->rbaugmented; \ 56 | old->rbaugmented = rbcompute(old); \ 57 | } \ 58 | rbstatic const struct rb_augment_callbacks rbname = { \ 59 | rbname##_propagate, rbname##_copy, rbname##_rotate}; 60 | 61 | #define RB_RED 0 62 | #define RB_BLACK 1 63 | 64 | #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) 65 | 66 | #define __rb_color(pc) ((pc)&1) 67 | #define __rb_is_black(pc) __rb_color(pc) 68 | #define __rb_is_red(pc) (!__rb_color(pc)) 69 | #define rb_color(rb) __rb_color((rb)->__rb_parent_color) 70 | #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) 71 | #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) 72 | 73 | static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) { 74 | rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; 75 | } 76 | 77 | static inline void rb_set_parent_color(struct rb_node *rb, struct rb_node *p, 78 | int color) { 79 | rb->__rb_parent_color = (unsigned long)p | color; 80 | } 81 | 82 | static inline void __rb_change_child(struct rb_node *old, struct rb_node *new, 83 | struct rb_node *parent, 84 | struct rb_root *root) { 85 | if (parent) { 86 | if (parent->rb_left == old) 87 | parent->rb_left = new; 88 | else 89 | parent->rb_right = new; 90 | } else 91 | root->rb_node = new; 92 | } 93 | 94 | static inline void __rb_erase_color( 95 | struct rb_node *parent, struct rb_root *root, 96 | void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); 97 | 98 | static __always_inline struct rb_node * 99 | __rb_erase_augmented(struct rb_node *node, struct rb_root *root, 100 | const struct rb_augment_callbacks *augment) { 101 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; 102 | struct rb_node *parent, *rebalance; 103 | unsigned long pc; 104 | 105 | if (!tmp) { 106 | /* 107 | * Case 1: node to erase has no more than 1 child (easy!) 108 | * 109 | * Note that if there is one child it must be red due to 5) 110 | * and node must be black due to 4). We adjust colors locally 111 | * so as to bypass __rb_erase_color() later on. 112 | */ 113 | pc = node->__rb_parent_color; 114 | parent = __rb_parent(pc); 115 | __rb_change_child(node, child, parent, root); 116 | if (child) { 117 | child->__rb_parent_color = pc; 118 | rebalance = NULL; 119 | } else 120 | rebalance = __rb_is_black(pc) ? parent : NULL; 121 | tmp = parent; 122 | } else if (!child) { 123 | /* Still case 1, but this time the child is node->rb_left */ 124 | tmp->__rb_parent_color = pc = node->__rb_parent_color; 125 | parent = __rb_parent(pc); 126 | __rb_change_child(node, tmp, parent, root); 127 | rebalance = NULL; 128 | tmp = parent; 129 | } else { 130 | struct rb_node *successor = child, *child2; 131 | tmp = child->rb_left; 132 | if (!tmp) { 133 | /* 134 | * Case 2: node's successor is its right child 135 | * 136 | * (n) (s) 137 | * / \ / \ 138 | * (x) (s) -> (x) (c) 139 | * \ 140 | * (c) 141 | */ 142 | parent = successor; 143 | child2 = successor->rb_right; 144 | augment->copy(node, successor); 145 | } else { 146 | /* 147 | * Case 3: node's successor is leftmost under 148 | * node's right child subtree 149 | * 150 | * (n) (s) 151 | * / \ / \ 152 | * (x) (y) -> (x) (y) 153 | * / / 154 | * (p) (p) 155 | * / / 156 | * (s) (c) 157 | * \ 158 | * (c) 159 | */ 160 | do { 161 | parent = successor; 162 | successor = tmp; 163 | tmp = tmp->rb_left; 164 | } while (tmp); 165 | parent->rb_left = child2 = successor->rb_right; 166 | successor->rb_right = child; 167 | rb_set_parent(child, successor); 168 | augment->copy(node, successor); 169 | augment->propagate(parent, successor); 170 | } 171 | 172 | successor->rb_left = tmp = node->rb_left; 173 | rb_set_parent(tmp, successor); 174 | 175 | pc = node->__rb_parent_color; 176 | tmp = __rb_parent(pc); 177 | __rb_change_child(node, successor, tmp, root); 178 | if (child2) { 179 | successor->__rb_parent_color = pc; 180 | rb_set_parent_color(child2, parent, RB_BLACK); 181 | rebalance = NULL; 182 | } else { 183 | unsigned long pc2 = successor->__rb_parent_color; 184 | successor->__rb_parent_color = pc; 185 | rebalance = __rb_is_black(pc2) ? parent : NULL; 186 | } 187 | tmp = successor; 188 | } 189 | 190 | augment->propagate(tmp, NULL); 191 | return rebalance; 192 | } 193 | 194 | static __always_inline void 195 | rb_erase_augmented(struct rb_node *node, struct rb_root *root, 196 | const struct rb_augment_callbacks *augment) { 197 | struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); 198 | if (rebalance) 199 | __rb_erase_color(rebalance, root, augment->rotate); 200 | } 201 | 202 | #endif /* _RBTREE_AUGMENTED_H */ 203 | -------------------------------------------------------------------------------- /includes/stringutil.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef STRINGUTIL_H 9 | #define STRINGUTIL_H 10 | 11 | #include 12 | #include 13 | 14 | static inline char *copy_string(const char *str) { 15 | size_t len = strlen(str); 16 | char *result = malloc(len); 17 | if (result == NULL) { 18 | return NULL; 19 | } 20 | memcpy(result, str, len); 21 | result[len] = '\0'; 22 | return result; 23 | } 24 | 25 | static inline void hexdump(size_t bytes, const void *in, char *out) { 26 | const unsigned char *cin = in; 27 | for (size_t i = 0; i < bytes; ++i) { 28 | static const char digits[] = "0123456789abcdef"; 29 | out[2 * i] = digits[cin[i] / 16]; 30 | out[2 * i + 1] = digits[cin[i] % 16]; 31 | } 32 | } 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /loader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | list(APPEND SABRE_COMPONENT_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/includes/loader) 8 | 9 | # Build library 10 | sabre_add_component( 11 | loader 12 | elf_loading.c 13 | ld_sc_handler.c 14 | loader.c 15 | maps.c 16 | premain.c 17 | rewriter.c 18 | debuginfo.c) 19 | 20 | target_link_libraries(loader ${CMAKE_DL_LIBS} backend elf plugin_api) 21 | 22 | add_subdirectory(tools) 23 | -------------------------------------------------------------------------------- /loader/tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | sabre_add_executable(process-vdso process-vdso.c) 2 | sabre_add_executable(dump-vdso dump-vdso.c) 3 | 4 | target_include_directories(process-vdso PRIVATE ${CMAKE_SOURCE_DIR}/includes/arch) 5 | target_include_directories(dump-vdso PRIVATE ./includes) 6 | 7 | target_compile_options(dump-vdso PRIVATE ${SABRE_COMPONENT_C_FLAGS} "-Wno-unused-parameter") 8 | target_compile_options(process-vdso PRIVATE ${SABRE_COMPONENT_C_FLAGS} "-Wno-unused-parameter") 9 | 10 | set_target_properties(dump-vdso PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tools) 11 | set_target_properties(process-vdso PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tools) 12 | 13 | target_link_libraries(process-vdso loader) 14 | target_link_libraries(dump-vdso loader) 15 | -------------------------------------------------------------------------------- /loader/tools/dump-vdso.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef _GNU_SOURCE 9 | #define _GNU_SOURCE 1 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "compiler.h" 23 | #include "kernel.h" 24 | #include "loader/maps.h" 25 | 26 | int main(int argc, char **argv, char **envp) { 27 | int out_fd = open(argv[1], O_WRONLY | O_CREAT, 00600); 28 | struct maps *maps = maps_read(NULL); 29 | 30 | struct library *l; 31 | struct region *reg; 32 | struct region *n; 33 | 34 | for_each_library(l, maps) { 35 | if (l->vdso) { 36 | rbtree_postorder_for_each_entry_safe(reg, n, &l->rb_region, rb_region) { 37 | long written = 0; 38 | long size = reg->end - reg->start; 39 | 40 | while (written != size) 41 | written += write(out_fd, reg->start + written, size - written); 42 | 43 | break; 44 | } 45 | } 46 | } 47 | 48 | close(out_fd); 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /loader/tools/process-vdso.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef _GNU_SOURCE 9 | #define _GNU_SOURCE 1 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "../loader/rewriter.c" 23 | #include "../maps.c" 24 | #include "compiler.h" 25 | #include "kernel.h" 26 | 27 | // TODO(andronat): We should use this code as a unit test 28 | 29 | extern struct region *rb_insert_region(struct library *library, 30 | ElfW(Addr) offset, struct rb_node *node); 31 | 32 | int main(int argc, char **argv, char **envp) { 33 | // Take vdso elf file as first argument 34 | char *vdso = argv[1]; 35 | 36 | // Open vdso 37 | int vdso_fd = open(vdso, O_RDONLY, 00600); 38 | // Get file size 39 | struct stat vdso_stat; 40 | fstat(vdso_fd, &vdso_stat); 41 | 42 | // mmap it 43 | void *start_addr = (caddr_t)mmap( 44 | NULL, vdso_stat.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, vdso_fd, 0); 45 | 46 | // Close vdso 47 | close(vdso_fd); 48 | 49 | // Set up library with vdso 50 | void *start = start_addr; 51 | void *end = start_addr + vdso_stat.st_size; 52 | char *pathname = vdso; 53 | 54 | /* allocate a new region structure */ 55 | struct region *reg = (struct region *)malloc(sizeof(struct region)); 56 | assert(reg != NULL); 57 | 58 | reg->start = (void *)start; 59 | reg->end = (void *)end; 60 | reg->size = (size_t)(end - start); 61 | 62 | // Setup protection permissions 63 | int perms = PROT_NONE; 64 | perms |= PROT_READ; 65 | perms |= PROT_WRITE; 66 | perms |= PROT_EXEC; 67 | perms |= MAP_PRIVATE; 68 | reg->perms = perms; 69 | reg->type = REGION_VDSO; 70 | 71 | struct library lib = {0}; 72 | struct maps maps = {0}; 73 | 74 | // SaBRe needs this fd to find scratch space to mmap 75 | maps.fd = open("/proc/self/maps", O_RDONLY, 0); 76 | library_init(&lib, pathname, &maps); 77 | 78 | rb_insert_region(&lib, 0L, ®->rb_region); 79 | 80 | lib.vdso = true; 81 | parse_elf(&lib, NULL); 82 | 83 | // Call library_patch_syscalls 84 | patch_syscalls(&lib, false); 85 | 86 | // write the result to the second argument 87 | int result_fd = open(argv[2], O_WRONLY | O_CREAT, 00600); 88 | 89 | long size = vdso_stat.st_size; 90 | long written = 0; 91 | 92 | while (written != size) 93 | written += write(result_fd, start + written, size - written); 94 | 95 | close(result_fd); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /plugin_api/README.md: -------------------------------------------------------------------------------- 1 | # Using `recursion_protector.c` as part of your source files in your plugin and licensing considerations 2 | 3 | All plugins that run under SaBRe 2.0 are required to export the `from_plugin` and `vdso_ready` variables. Some languages, including Rust, currently cannot create such variables under the TLS model `initial-exec` which is a mandatory technical requirement. Thus, we provide the `recursion_protector.c` file so plugin authors can include it as part of their source code. The file is under the MIT license in order to avoid forcing plugin authors to opensource their plugins. 4 | -------------------------------------------------------------------------------- /plugin_api/arch/x86_64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: MIT 6 | 7 | sabre_add_component(plugin_api vfork_syscall.s vfork_return_from_child.s 8 | clone3_syscall.s clone_syscall.s real_syscall.s) 9 | -------------------------------------------------------------------------------- /plugin_api/arch/x86_64/clone3_syscall.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | .file "clone3_syscall.s" 9 | .text 10 | .globl clone3_syscall 11 | .type clone3_syscall, @function 12 | 13 | # - userland args: https://elixir.bootlin.com/glibc/glibc-2.35/source/sysdeps/unix/sysv/linux/x86_64/clone3.S#L25 14 | # long clone3 (long arg1, # %rdi - struct clone_args *cl_args 15 | # long arg1, # %rsi - size_t size 16 | # long arg2, # %rdx - int (*func)(void *arg) 17 | # not_used, # - %rcx - is clobbered by syscall so we don't use it. 18 | # long arg4, # %r8 - void *arg 19 | # void *ret_addr # %r9 20 | # void *ctx # +8(%rsp) 21 | # ); 22 | 23 | clone3_syscall: 24 | pushq %rbp 25 | movq %rsp, %rbp 26 | 27 | # Save xmm0 28 | subq $16, %rsp 29 | movdqu %xmm0, (%rsp) 30 | 31 | # Copy argument into xmm0 32 | movq 16(%rbp), %xmm0 33 | 34 | # Call clone3 35 | movq $435, %rax 36 | syscall 37 | 38 | # Both child and parent return here 39 | testq %rax, %rax 40 | jnz 1f 41 | 42 | # Child 43 | 44 | # TODO: Return to the plugin after a new child and not directly to client. 45 | 46 | pushq %rdi 47 | pushq %rsi 48 | pushq %rdx 49 | pushq %r8 50 | pushq %r9 51 | 52 | # Call post_clone_hook with xmm0 as first argument 53 | movq %xmm0, %rdi 54 | call *post_clone_hook@GOTPCREL(%rip) 55 | 56 | call *exit_plugin@GOTPCREL(%rip) 57 | 58 | # Set xmm0 to NaN to catch xmm0 corruptions 59 | pcmpeqd %xmm0, %xmm0 60 | 61 | popq %r9 62 | popq %r8 63 | popq %rdx 64 | popq %rsi 65 | popq %rdi 66 | 67 | # The child always returns 0. 68 | movq $0, %rax 69 | 70 | subq $0x80, %rsp # We need the -0x80 as we are jumping back to our trampoline that adds 0x80. 71 | 72 | # From: https://elixir.bootlin.com/glibc/glibc-2.35/source/sysdeps/unix/sysv/linux/x86_64/clone3.S#L52 73 | # glibc's clone3 expects %rdx to point to the user provide fn and it's arguments in %r8. 74 | # clone3 is significanlty different than clone where arguments are actually passed in the 75 | # child's stack. For more look here: https://elixir.bootlin.com/glibc/glibc-2.35/source/sysdeps/unix/sysv/linux/x86_64/clone.S#L98 76 | # It's safe to keep %rdx and %r8 unsaved as they are not clobbered from the kernel. For 77 | # more look here: https://gitlab.com/x86-psABIs/x86-64-ABI/-/blob/master/x86-64-ABI/kernel.tex#L35-37 78 | 79 | jmp *%r9 # ret_addr jumps back to our trampoline. 80 | 81 | 1: 82 | # Parent 83 | 84 | # Restore xmm0 value 85 | movdqu (%rsp), %xmm0 86 | addq $16, %rsp 87 | 88 | popq %rbp 89 | ret 90 | 91 | .size clone3_syscall, .-clone3_syscall 92 | .section .note.GNU-stack,"",@progbits 93 | -------------------------------------------------------------------------------- /plugin_api/arch/x86_64/clone_syscall.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | .file "clone_syscall.s" 9 | .text 10 | .globl clone_syscall 11 | .type clone_syscall, @function 12 | 13 | # long clone (unsigned long flags, # %rdi 14 | # void *child_stack, # %rsi 15 | # int *ptid, # %rdx 16 | # int *ctid, # %rcx 17 | # unsigned long newtls, # %r8 18 | # void* ret_addr # %r9 19 | # void* ctx # +8(%rsp) 20 | # ); 21 | 22 | clone_syscall: 23 | pushq %rbp 24 | movq %rsp, %rbp 25 | 26 | # Save xmm0 27 | subq $16, %rsp 28 | movdqu %xmm0, (%rsp) 29 | 30 | # Copy argument into xmm0 31 | movq 16(%rbp), %xmm0 32 | 33 | # Adjust the arguments 34 | movq $56, %rax 35 | movq %rcx, %r10 36 | syscall # syscall 37 | 38 | # Both child and parent return here 39 | testq %rax, %rax 40 | jnz 1f 41 | 42 | # Child 43 | 44 | # TODO: Return to the plugin after a new child and not directly to client. 45 | 46 | pushq %rdi 47 | pushq %rsi 48 | pushq %rdx 49 | pushq %r10 # %rcx 50 | pushq %r8 51 | pushq %r9 52 | 53 | # Call post_clone_hook with xmm0 as first argument 54 | movq %xmm0, %rdi 55 | call *post_clone_hook@GOTPCREL(%rip) 56 | 57 | call *exit_plugin@GOTPCREL(%rip) 58 | 59 | # Set xmm0 to NaN to catch xmm0 corruptions 60 | pcmpeqd %xmm0, %xmm0 61 | 62 | popq %r9 63 | popq %r8 64 | popq %r10 # %rcx 65 | popq %rdx 66 | popq %rsi 67 | popq %rdi 68 | 69 | # The child always returns 0. 70 | movq $0, %rax 71 | 72 | subq $0x80, %rsp 73 | jmp *%r9 74 | 75 | 1: 76 | # Parent 77 | 78 | # Restore xmm0 79 | movdqu (%rsp), %xmm0 80 | addq $16, %rsp 81 | 82 | popq %rbp 83 | ret 84 | 85 | .size clone_syscall, .-clone_syscall 86 | .section .note.GNU-stack,"",@progbits 87 | -------------------------------------------------------------------------------- /plugin_api/arch/x86_64/real_syscall.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | .file "real_syscall.s" 9 | .text 10 | .globl real_syscall 11 | .type real_syscall, @function 12 | 13 | # sc_no lives in %rdi 14 | # arg1 lives in %rsi 15 | # arg2 lives in %rdx 16 | # arg3 lives in %rcx 17 | # arg4 lives in %r8 18 | # arg5 lives in %r9 19 | # arg6 lives in 16(%rbp) 20 | 21 | real_syscall: 22 | pushq %rbp 23 | 24 | # Adjust the arguments 25 | movq %rsp, %rbp 26 | movq %rdi, %rax # sc_no 27 | movq %rsi, %rdi # arg1 28 | movq %rdx, %rsi # arg2 29 | movq %rcx, %rdx # arg3 30 | movq %r8, %r10 # arg4 31 | movq %r9, %r8 # arg5 32 | movq 16(%rbp), %r9 # arg6 33 | 34 | syscall # syscall 35 | 36 | popq %rbp 37 | ret 38 | .size real_syscall, .-real_syscall 39 | .section .note.GNU-stack,"",@progbits 40 | -------------------------------------------------------------------------------- /plugin_api/arch/x86_64/vfork_return_from_child.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | .file "vfork_return_from_child.s" 9 | .text 10 | .globl vfork_return_from_child 11 | .type vfork_return_from_child, @function 12 | 13 | # long vfork_return_from_child(void *wrapper_sp # %rdi 14 | # ); 15 | 16 | vfork_return_from_child: 17 | pushq %rbp 18 | movq %rsp, %rbp 19 | 20 | pushq %rdi 21 | call *exit_plugin@GOTPCREL(%rip) 22 | popq %rdi 23 | 24 | movq 0x8(%rdi), %r15 25 | movq 0x10(%rdi), %r14 26 | movq 0x18(%rdi), %r13 27 | movq 0x20(%rdi), %r12 28 | movq 0x28(%rdi), %r11 29 | movq 0x30(%rdi), %r10 30 | movq 0x38(%rdi), %r9 31 | movq 0x40(%rdi), %r8 32 | # Skip %rdi because we are reading it. 33 | movq 0x50(%rdi), %rsi 34 | movq 0x58(%rdi), %rdx 35 | movq 0x60(%rdi), %rcx 36 | movq 0x68(%rdi), %rbx 37 | movq 0x70(%rdi), %rbp 38 | 39 | # It's safe to clobber %r11 to load *ret. 40 | # *ret will jump back to the trampoline 41 | # and then in the first instruction after 42 | # the vfork syscall. 43 | movq 0x80(%rdi), %r11 44 | 45 | movq 0x48(%rdi), %rdi 46 | 47 | # The child always returns 0. 48 | movq $0, %rax 49 | 50 | subq $0x80, %rsp 51 | jmp *%r11 # We are going back to the client. 52 | 53 | .size vfork_return_from_child, .-vfork_return_from_child 54 | .section .note.GNU-stack,"",@progbits 55 | -------------------------------------------------------------------------------- /plugin_api/arch/x86_64/vfork_syscall.s: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | .file "vfork_syscall.s" 9 | .text 10 | .globl vfork_syscall 11 | .type vfork_syscall, @function 12 | 13 | # long vfork_syscall(); 14 | 15 | vfork_syscall: 16 | 17 | # The reason for this pair of `pop rdi` and `push rdi` is quite subtle. 18 | # It might seem strange to pop before the push, but there is a good 19 | # reason for this. Stay a while and listen! 20 | # 21 | # There are several important things to remember here. 22 | # 1. The vforked child shares the same stack with the parent process 23 | # and can modify the parent's stack. 24 | # 2. `%rdi` is not clobbered by the `syscall` instruction. (On x86-64, 25 | # only `%rcx` and `%r11` are clobbered.) 26 | # 3. This function has no arguments and the top of the stack contains 27 | # the return address. Thus, this `pop rdi` is storing the return 28 | # address in `rdi`. 29 | # 4. When vfork is called, the parent process is paused and the child 30 | # process continues on executing instructions. When the child 31 | # process exits, this syscall returns for the parent process. 32 | # 5. Registers are NOT shared with the child process. The kernel 33 | # simply saves/restores these whenever it does a context switch 34 | # between the parent and child. 35 | # 36 | # When the child gets to the bottom of this function, the `ret` 37 | # instruction pops the return address off the stack for both itself and 38 | # the parent. Note that proper usage of vfork says that you shouldn't 39 | # return from the function where it was called. That's not true for 40 | # *this* function, but it is true for the caller of this function and 41 | # so the stack shouldn't get popped any further. 42 | # 43 | # Thus, this `pop rdi` saves the return address in `%rdi` and the `push 44 | # rdi` puts it back on the stack. In the child process, it puts it back 45 | # on the stack so that `ret` can pop it off again. In the parent 46 | # process, it puts it back because the child added it back, but then 47 | # subsequently popped it with the `ret`. 48 | # 49 | # glibc also does this in `vfork(3)`, but doesn't explain it very well. 50 | 51 | popq %rdi 52 | 53 | # Adjust the arguments 54 | movq $58, %rax # sc_no 55 | syscall # syscall 56 | 57 | pushq %rdi 58 | 59 | # This is an idempotent operation for the child process 60 | # but it is mandatory for the parent. When the child exits, 61 | # we might be outside of the plugin guard. This might be 62 | # the case because child and parent share memory. Here we 63 | # make sure we re-enter. 64 | pushq %rax 65 | call *enter_plugin@GOTPCREL(%rip) 66 | popq %rax 67 | 68 | ret # We are going back to the plugin. 69 | 70 | .size vfork_syscall, .-vfork_syscall 71 | .section .note.GNU-stack,"",@progbits 72 | -------------------------------------------------------------------------------- /plugin_api/recursion_protector.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: MIT 6 | */ 7 | 8 | #include 9 | 10 | // Sanitizers intercept various function calls, look here: 11 | // https://github.com/llvm/llvm-project/blob/b3ca4f34311b87345cf87bfdd0343045eed22f5c/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc#L5185 12 | // In various TLS models _Thread_local variables calls __tls_get_addr to resolve 13 | // its value. Unfortunately these modes crash LLVM sanitizers in the above 14 | // function. The LLVM sanitizers themselves actually use initial-exec to avoid 15 | // this problem. initial-exec doesn't go through __tls_get_addr but rather uses 16 | // the %fs register directly. 17 | // In the current setup, we need "initial-exec" as runtime_syscall_router will 18 | // be called during pthread initialization which will happen before the 19 | // sanitizers initialization phase. 20 | // TODO(andronat): Will the following create any issues with other libraries? 21 | // e.g. overlapping offsets and thus writting/reading from wrong variables? 22 | static _Thread_local bool from_plugin 23 | __attribute__((tls_model("initial-exec"))) = false; 24 | 25 | bool calling_from_plugin() { return from_plugin; } 26 | void enter_plugin() { from_plugin = true; } 27 | void exit_plugin() { from_plugin = false; } 28 | 29 | // vDSO cannot be used in preinit: https://reviews.llvm.org/D40679. So when a 30 | // SaBRe plugin makes a vDSO call, it instantly crashes. 31 | // 32 | // vDSO are initialized in __vdso_platform_setup () at 33 | // ../sysdeps/unix/sysv/linux/x86_64/init-first.c:36 34 | // 35 | // Newer glibc 2.31 fixes this issue: 36 | // 1) https://sourceware.org/bugzilla/show_bug.cgi?id=24967 37 | // 2) 38 | // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=1bdda52fe92fd01b424cd6fbb63e3df96a95015c 39 | // 3) https://sourceware.org/pipermail/glibc-cvs/2020q1/068454.html 40 | // 41 | // Unfortunately, we can't rely on sanitizer interceptors either as the above 42 | // patch is not currently introduced in Ubuntu 18.04. 43 | // 44 | // Until them, we used a guard that will change value after glibc is 45 | // initialized. 46 | 47 | static _Thread_local bool vdso_ready 48 | __attribute__((tls_model("initial-exec"))) = false; 49 | 50 | void vdso_are_ready() __attribute__((constructor)); 51 | void vdso_are_ready() { vdso_ready = true; } 52 | 53 | bool is_vdso_ready() { return vdso_ready; } 54 | 55 | __attribute__((weak)) void post_clone_hook(void *ctx) { 56 | (void)ctx; // unused 57 | return; 58 | } 59 | -------------------------------------------------------------------------------- /plugins/sbr-id/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | list(APPEND SABRE_PLUGIN_C_FLAGS "-Wall" "-Werror" "-Wno-erro=unused-parameter") 8 | 9 | sabre_add_plugin(sbr-id 10 | identity.c) 11 | -------------------------------------------------------------------------------- /plugins/sbr-id/identity.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | This plugin simply intercepts all system calls and vDSO calls and 10 | reissues them. 11 | */ 12 | 13 | #include "real_syscall.h" 14 | #include "sbr_api_defs.h" 15 | 16 | #ifndef _GNU_SOURCE 17 | #define _GNU_SOURCE 18 | #endif 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | static char *sabre_path; 31 | static char *plugin_path; 32 | static char *client_path; 33 | 34 | bool is_vfork_through_clone3(long sc_no, long arg1) { 35 | struct clone_args *cl_args = (struct clone_args *)arg1; 36 | return sc_no == SYS_clone3 && 37 | ((cl_args->flags & (CLONE_VM | CLONE_VFORK | SIGCHLD)) == 38 | (CLONE_VM | CLONE_VFORK | SIGCHLD)); 39 | } 40 | 41 | bool is_vfork_through_clone(long sc_no, long arg1) { 42 | unsigned long flags = (unsigned long)arg1; 43 | return (sc_no == SYS_clone && (flags & (CLONE_VM | CLONE_VFORK | SIGCHLD)) == 44 | (CLONE_VM | CLONE_VFORK | SIGCHLD)); 45 | } 46 | 47 | long handle_syscall(long sc_no, long arg1, long arg2, long arg3, long arg4, 48 | long arg5, long arg6, void *wrapper_sp) { 49 | if (sc_no == SYS_clone && arg2 != 0) { // clone 50 | void *ret_addr = get_syscall_return_address(wrapper_sp); 51 | return clone_syscall(arg1, (void *)arg2, (void *)arg3, (void *)arg4, arg5, 52 | ret_addr, NULL); 53 | } else if (sc_no == SYS_clone3 && 54 | ((struct clone_args *)arg1)->stack != 0) { // clone3 55 | void *ret_addr = get_syscall_return_address(wrapper_sp); 56 | return clone3_syscall(arg1, arg2, arg3, 0, arg5, ret_addr, NULL); 57 | } else if (sc_no == SYS_execve) { 58 | if (access((char *)arg1, F_OK) != 0) { 59 | // TODO: Double check this is the correct way to return errors. 60 | return -ENOENT; 61 | } 62 | 63 | char **old_argv = (char **)arg2; // Just make our life easier. 64 | 65 | size_t old_argv_size = 0; 66 | for (int i = 0; old_argv[i] != NULL; i++) { 67 | old_argv_size++; 68 | } 69 | // argv is NULL terminated, and we should copy the NULL too. 70 | old_argv_size += 1; 71 | 72 | // We will be adding the minimum 3 args. 73 | // TODO: Support addition of plugin and sabre flags. 74 | char **n_argv = malloc((old_argv_size + 3) * sizeof(char *)); 75 | assert(n_argv != NULL); 76 | // argv should always start with the path to the binary. 77 | // old_argv now has the old binary path by default so 78 | // we just append it. 79 | memcpy(n_argv + 3, old_argv, old_argv_size * sizeof(char *)); 80 | 81 | n_argv[0] = sabre_path; 82 | n_argv[1] = plugin_path; 83 | n_argv[2] = "--"; 84 | // Overwrite first argument of old_argv as sometimes this is not a valid 85 | // path. 86 | n_argv[3] = (char *)arg1; 87 | 88 | return real_syscall(SYS_execve, (long)sabre_path, (long)n_argv, arg3, arg4, 89 | arg5, arg6); 90 | } else if (sc_no == SYS_readlink) { 91 | const char *pathname = (const char *)arg1; 92 | char *buf = (char *)arg2; 93 | size_t bufsize = (size_t)arg3; 94 | 95 | if (strcmp(pathname, "/proc/self/exe") == 0) { 96 | if (buf == NULL) { 97 | return -EFAULT; 98 | } 99 | 100 | // strncpy doesn't tell us how many bytes it copied, so we have to 101 | // calculate that ourselves. Plus, readlink should not append a NUL byte 102 | // to the end. Best to use memcpy here to mimic the kernel. 103 | size_t len = strlen(client_path); 104 | if (len > bufsize) { 105 | len = bufsize; 106 | } 107 | 108 | memcpy(buf, client_path, len); 109 | 110 | return len; 111 | } 112 | } else if (sc_no == SYS_vfork || is_vfork_through_clone(sc_no, arg1) || 113 | is_vfork_through_clone3(sc_no, arg1)) { 114 | long pid = vfork_syscall(); 115 | if (pid == 0) { // Child 116 | return vfork_return_from_child(wrapper_sp); 117 | } 118 | // Parent 119 | return pid; 120 | } 121 | 122 | return real_syscall(sc_no, arg1, arg2, arg3, arg4, arg5, arg6); 123 | } 124 | 125 | void_void_fn actual_clock_gettime = NULL; 126 | void_void_fn actual_getcpu = NULL; 127 | void_void_fn actual_gettimeofday = NULL; 128 | void_void_fn actual_time = NULL; 129 | 130 | typedef int clock_gettime_fn(clockid_t, struct timespec *); 131 | int handle_vdso_clock_gettime(clockid_t arg1, struct timespec *arg2) { 132 | return ((clock_gettime_fn *)actual_clock_gettime)(arg1, arg2); 133 | } 134 | 135 | // arg3 has type: struct getcpu_cache * 136 | typedef int getcpu_fn(unsigned *, unsigned *, void *); 137 | int handle_vdso_getcpu(unsigned *arg1, unsigned *arg2, void *arg3) { 138 | return ((getcpu_fn *)actual_getcpu)(arg1, arg2, arg3); 139 | } 140 | 141 | typedef int gettimeofday_fn(struct timeval *, struct timezone *); 142 | int handle_vdso_gettimeofday(struct timeval *arg1, struct timezone *arg2) { 143 | return ((gettimeofday_fn *)actual_gettimeofday)(arg1, arg2); 144 | } 145 | 146 | #ifdef __x86_64__ 147 | typedef int time_fn(time_t *); 148 | int handle_vdso_time(time_t *arg1) { return ((time_fn *)actual_time)(arg1); } 149 | #endif // __x86_64__ 150 | 151 | void_void_fn handle_vdso(long sc_no, void_void_fn actual_fn) { 152 | (void)actual_fn; 153 | switch (sc_no) { 154 | case SYS_clock_gettime: 155 | actual_clock_gettime = actual_fn; 156 | return (void_void_fn)handle_vdso_clock_gettime; 157 | case SYS_getcpu: 158 | actual_getcpu = actual_fn; 159 | return (void_void_fn)handle_vdso_getcpu; 160 | case SYS_gettimeofday: 161 | actual_gettimeofday = actual_fn; 162 | return (void_void_fn)handle_vdso_gettimeofday; 163 | #ifdef __x86_64__ 164 | case SYS_time: 165 | actual_time = actual_fn; 166 | return (void_void_fn)handle_vdso_time; 167 | #endif // __x86_64__ 168 | default: 169 | return (void_void_fn)NULL; 170 | } 171 | } 172 | 173 | #ifdef __NX_INTERCEPT_RDTSC 174 | long handle_rdtsc() { 175 | long high, low; 176 | 177 | asm volatile("rdtsc;" : "=a"(low), "=d"(high) : :); 178 | 179 | long ret = high; 180 | ret <<= 32; 181 | ret |= low; 182 | 183 | return ret; 184 | } 185 | #endif // __NX_INTERCEPT_RDTSC 186 | 187 | void post_clone_hook(void *ctx) { 188 | assert(ctx == NULL); 189 | return; 190 | } 191 | 192 | void sbr_init(int *argc, char **argv[], sbr_icept_reg_fn fn_icept_reg, 193 | sbr_icept_vdso_callback_fn *vdso_callback, 194 | sbr_sc_handler_fn *syscall_handler, 195 | #ifdef __NX_INTERCEPT_RDTSC 196 | sbr_rdtsc_handler_fn *rdtsc_handler, 197 | #endif 198 | sbr_post_load_fn *post_load, char *sp, char *cp) { 199 | (void)fn_icept_reg; // unused 200 | (void)post_load; // unused 201 | 202 | sabre_path = sp; 203 | plugin_path = (*argv)[0]; 204 | client_path = cp; 205 | 206 | *syscall_handler = handle_syscall; 207 | *vdso_callback = handle_vdso; 208 | 209 | #ifdef __NX_INTERCEPT_RDTSC 210 | *rdtsc_handler = handle_rdtsc; 211 | #endif 212 | 213 | (*argc)--; 214 | (*argv)++; 215 | } 216 | -------------------------------------------------------------------------------- /plugins/sbr-scfuzzer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | list(APPEND SABRE_PLUGIN_C_FLAGS "-Wall" "-Werror" "-Wno-erro=unused-parameter") 8 | 9 | sabre_add_plugin(sbr-scfuzzer 10 | sc-fuzzer.c) 11 | -------------------------------------------------------------------------------- /plugins/sbr-trace/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | list(APPEND SABRE_PLUGIN_C_FLAGS "-Wall" "-Werror" "-Wno-erro=unused-parameter") 8 | 9 | sabre_add_plugin(sbr-trace 10 | strace.c) 11 | -------------------------------------------------------------------------------- /plugins/sbr-trace/sbr_api.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * This is a proposed API for Loader <-> Plugin interaction. 10 | * This header file should be imported by the plugin implementation. 11 | * TBD: 12 | * - What handles the errors - loader or plugin? i.e. do we use void return 13 | * types in the plugin or do we use int or something similar? 14 | * - Segfault handler 15 | */ 16 | #ifndef SBR_API_H 17 | #define SBR_API_H 18 | 19 | // Includes 20 | #include "sbr_api_defs.h" 21 | 22 | /* 23 | * Protocol of plugin registration and startup: 24 | * 1. Loader is passed the path of the plugin (which is ELF Shared Object) 25 | * 2. Loader uses dlopen() to open the ELF and dlsym() to find sbr_init() 26 | * 3. Loader calls the sbr_init(), providing following arguments: 27 | * a) pointers to argc and argv - both of them will be modified by the 28 | * plugin 29 | * b) pointer to segfault handler to be populated by the plugin 30 | * c) pointer to interception callback registration function to be called by 31 | * the plugin 32 | * d) pointer to vDSO callback function to be populated by the plugin 33 | * e) pointer to syscall handler function to be populated by the plugin 34 | * 35 | * Plugin side (in sbr_init()): 36 | * 4. the plugin parses arguments and leaves them in a state such that when 37 | * sbr_init returns, argv[0] is the path of the ELF to be executed and 38 | * consecutive arguments are standard arguments passed to the ELF 39 | * 5. the plugin populates segfault handler with appropriate function (optional) 40 | * 6. the plugin calls fn_icept_reg for each of the functions that need to be 41 | * intercepted 42 | * 7. the plugin populates vdso_callback with appropriate function (optional) 43 | * 8. the plugin populates syscall_handler with appropriate function (required) 44 | * 45 | * Loader side: 46 | * 9. the loader loads the ELF file 47 | * 10. the loader performs the interception of the functions registered: 48 | * a) function is located and first few instructions are relocated to make 49 | * room for unconditional jump - pointer to the first function is saved 50 | * and an unconditional jump is injected at the end to connect these 51 | * instructions to the rest of the function 52 | * b) static code is injected that would divert the flow of control through 53 | * a pointer returned by the callback (that has to be called with the 54 | * pointer of the start of the original function - the first relocated 55 | * instruction) 56 | * c) the unconditional jump mentioned in a) now jumps to code in b) 57 | * 11. the loader performs the interception of vDSO if vdso_callback was 58 | * populated in a similar way to 10. 59 | * 12. the loader transfers control to the entry point of the ELF 60 | */ 61 | void sbr_init(int *argc, char **argv[], 62 | // sbr_segfault_handler_fn *segfault_handler, // - TBD 63 | sbr_icept_reg_fn fn_icept_reg, 64 | sbr_icept_vdso_callback_fn *vdso_callback, 65 | sbr_sc_handler_fn *syscall_handler, sbr_post_load_fn *post_load); 66 | 67 | // If the init above is used, nothing else is required from the API - loader 68 | // knows what it needs to overwrite and what to overwrite it with. 69 | 70 | #endif /* !SBR_API_H */ 71 | -------------------------------------------------------------------------------- /plugins/sbr-trace/sysent.h: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | #ifndef SYSENT_H 9 | #define SYSENT_H 10 | 11 | typedef struct sysent { 12 | int nargs; 13 | const char *sys_name; 14 | } struct_sysent; 15 | 16 | #endif /* !SYSENT_H */ 17 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | set (LIT_AUTOGENERATED_WARNING "This file is autogenerated, do not edit!") 8 | 9 | set(SABRE_AVAILABLE_TEST_FEATURES "") 10 | macro(ADD_TEST_FEATURE feature) 11 | list(APPEND SABRE_AVAILABLE_TEST_FEATURES "\"${feature}\"") 12 | endmacro(ADD_TEST_FEATURE) 13 | 14 | if(RDTSC) 15 | ADD_TEST_FEATURE(rdtsc) 16 | endif() 17 | 18 | macro(FIND_TEST_FEATURE prog) 19 | string(TOUPPER "${prog}" p) 20 | cmake_parse_arguments("TEST_FEATURE_${p}" "REQUIRED" "" "" ${ARGN}) 21 | find_program("TEST_${p}_PATH" ${prog}) 22 | if(NOT TEST_${p}_PATH) 23 | if(TEST_FEATURE_${p}_REQUIRED) 24 | message(FATAL_ERROR "Required test dependency \"${prog}\" not found") 25 | else() 26 | message(AUTHOR_WARNING "Optional test dependency \"${prog}\" not found") 27 | endif() 28 | else() 29 | if (NOT TEST_FEATURE_${p}_REQUIRED) 30 | ADD_TEST_FEATURE(${prog}) 31 | endif() 32 | endif() 33 | 34 | # Hide programs from cmake cache 35 | mark_as_advanced("TEST_${p}_PATH") 36 | endmacro(FIND_TEST_FEATURE) 37 | 38 | include(CheckCCompilerFlag) 39 | include(CMakePushCheckState) 40 | CMAKE_PUSH_CHECK_STATE(RESET) 41 | SET(CMAKE_REQUIRED_FLAGS "-fsanitize=thread") # Also needs to be a link flag for test to pass 42 | CHECK_C_COMPILER_FLAG("-fsanitize=thread" tsan_avail) 43 | CMAKE_POP_CHECK_STATE() 44 | if(NOT tsan_avail) 45 | message(AUTHOR_WARNING "ThreadSanitizer is not supported by the system compiler") 46 | else() 47 | ADD_TEST_FEATURE(tsan) 48 | endif() 49 | 50 | check_c_compiler_flag("-no-pie" no_pie) 51 | 52 | FIND_TEST_FEATURE(bash REQUIRED) 53 | FIND_TEST_FEATURE(timeout REQUIRED) 54 | FIND_TEST_FEATURE(gcc REQUIRED) 55 | 56 | FIND_TEST_FEATURE(clang) 57 | 58 | FIND_TEST_FEATURE(bunzip2) 59 | FIND_TEST_FEATURE(bzip2) 60 | FIND_TEST_FEATURE(cat) 61 | FIND_TEST_FEATURE(chacl) 62 | FIND_TEST_FEATURE(chgrp) 63 | FIND_TEST_FEATURE(chmod) 64 | FIND_TEST_FEATURE(cp) 65 | FIND_TEST_FEATURE(date) 66 | FIND_TEST_FEATURE(dbus-uuidgen) 67 | FIND_TEST_FEATURE(dd) 68 | FIND_TEST_FEATURE(dmesg) 69 | FIND_TEST_FEATURE(dumpkeys) 70 | FIND_TEST_FEATURE(ed) 71 | FIND_TEST_FEATURE(efibootmgr) 72 | FIND_TEST_FEATURE(fgconsole) 73 | FIND_TEST_FEATURE(fuser) 74 | FIND_TEST_FEATURE(grep) 75 | FIND_TEST_FEATURE(gzip) 76 | FIND_TEST_FEATURE(ip) 77 | FIND_TEST_FEATURE(kill) 78 | FIND_TEST_FEATURE(kmod) 79 | FIND_TEST_FEATURE(lessecho) 80 | FIND_TEST_FEATURE(ln) 81 | FIND_TEST_FEATURE(loginctl) 82 | FIND_TEST_FEATURE(ls) 83 | FIND_TEST_FEATURE(lsmod) 84 | FIND_TEST_FEATURE(mktemp) 85 | FIND_TEST_FEATURE(mount) 86 | FIND_TEST_FEATURE(nano) 87 | FIND_TEST_FEATURE(nc) 88 | FIND_TEST_FEATURE(ntfs-3g) 89 | FIND_TEST_FEATURE(openvt) 90 | FIND_TEST_FEATURE(ping) 91 | FIND_TEST_FEATURE(ps) 92 | FIND_TEST_FEATURE(sed) 93 | FIND_TEST_FEATURE(setfacl) 94 | FIND_TEST_FEATURE(su) 95 | FIND_TEST_FEATURE(tar) 96 | 97 | string(REPLACE ";" "," SABRE_AVAILABLE_TEST_FEATURES_STR 98 | "${SABRE_AVAILABLE_TEST_FEATURES}") 99 | configure_file("lit.cfg.in" "${CMAKE_CURRENT_BINARY_DIR}/lit.cfg" @ONLY) 100 | 101 | 102 | if(no_pie) 103 | # foreach(link "" "-static") # SaBRe 2.0 doesn't support static ELFs 104 | foreach(link "") 105 | foreach(pie "-no-pie" "-pie") 106 | configure_file("ld/test.c.in" "${CMAKE_CURRENT_BINARY_DIR}/ld/test_${link}_${pie}.c" @ONLY) 107 | endforeach(pie) 108 | endforeach(link) 109 | 110 | configure_file("ld/lit.cfg.in" "${CMAKE_CURRENT_BINARY_DIR}/ld/lit.cfg" @ONLY) 111 | endif(no_pie) 112 | 113 | file(GLOB_RECURSE smoketests CONFIGURE_DEPENDS "smoke/*.in") 114 | # We don't want to configure lit.cfg.in as a test, but just as a 115 | # config so exclude it now and deal with more simply later 116 | list(REMOVE_ITEM smoketests "${CMAKE_CURRENT_SOURCE_DIR}/smoke/lit.cfg.in") 117 | foreach(test ${smoketests}) 118 | get_filename_component(test_name ${test} NAME_WE) 119 | foreach(tool "id" "sbrtrace" "fault-injector") 120 | configure_file(${test} 121 | "${CMAKE_CURRENT_BINARY_DIR}/smoke/test_${tool}_${test_name}.c" 122 | @ONLY) 123 | endforeach(tool) 124 | endforeach(test) 125 | 126 | configure_file("smoke/lit.cfg.in" "${CMAKE_CURRENT_BINARY_DIR}/smoke/lit.cfg" @ONLY) 127 | 128 | add_custom_target(smoketests lit -v --timeout 30 "${CMAKE_CURRENT_BINARY_DIR}/smoke") 129 | add_dependencies(smoketests sabre sbr-id sbr-trace sbr-scfuzzer) 130 | 131 | add_custom_target(tests lit -v --timeout 30 "${CMAKE_CURRENT_BINARY_DIR}") 132 | add_dependencies(tests sabre sbr-id sbr-trace sbr-scfuzzer process-vdso) 133 | -------------------------------------------------------------------------------- /tests/Simple/test_execve.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -D_EXEC_NAME=%t1 -o %t1 10 | * RUN: echo "Hello, world!" > %t1.expected 11 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 1 12 | * RUN: sleep 2 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define xstr(a) str(a) 23 | #define str(a) #a 24 | 25 | #ifndef _EXEC_NAME 26 | #define _EXEC_NAME a.out 27 | #endif 28 | 29 | int main(int argc, char **argv) { 30 | if (argc == 1) { 31 | printf("Hello, world!\n"); 32 | fflush(NULL); 33 | return 0; 34 | } 35 | 36 | int pid = fork(); 37 | if (pid == 0) { 38 | char *const args[] = {xstr(_EXEC_NAME), NULL}; 39 | char *const envp[] = {NULL}; 40 | execve(xstr(_EXEC_NAME), args, envp); 41 | assert(0); 42 | } else 43 | wait(NULL); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /tests/Simple/test_fork.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: echo "abc" > %t1.expected 11 | * RUN: echo "def" >> %t1.expected 12 | * RUN: timeout 5 %{sbr} %{sbr-id} -- %t1 &> %t1.actual 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) { 23 | int pid = fork(); 24 | if (pid == 0) { 25 | printf("abc\n"); 26 | } else { 27 | wait(NULL); 28 | printf("def\n"); 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /tests/Simple/test_hello.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 11 | * RUN: echo "Hello, world!" > %t1.expected 12 | * RUN: diff %t1.actual %t1.expected 13 | */ 14 | 15 | #include 16 | #include 17 | 18 | int main(int argc, char **argv) { 19 | printf("Hello, world!\n"); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /tests/Simple/test_name.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: rm -rf %t1 10 | * RUN: echo > %t5 11 | * RUN: %{cc} %s -o %t2 12 | * RUN: %{sbr} %{sbr-id} -- %t2 %t1 %t5 %t6 &> %t2.actual 13 | * RUN: echo -n > %t2.expected 14 | * RUN: diff %t2.actual %t2.expected 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | /* Utility functions */ 27 | 28 | /* Tests */ 29 | static void test_mkdir(char *dirname) { assert(mkdir(dirname, 0777) == 0); } 30 | 31 | static void test_rename(char *from, char *to) { assert(rename(from, to) == 0); } 32 | 33 | static void test_unlink(char *filename) { assert(unlink(filename) == 0); } 34 | 35 | int main(int argc, char **argv) { 36 | /* Set-up */ 37 | 38 | /* Test */ 39 | test_mkdir(argv[1]); 40 | test_rename(argv[2], argv[3]); 41 | test_unlink(argv[3]); 42 | 43 | /* Tear-down */ 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /tests/Simple/test_read_write.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: echo "This is a test file" > %t2 10 | * RUN: %{cc} %s -o %t1 11 | * RUN: %{sbr} %{sbr-id} -- %t1 %t2 &> %t1.actual 12 | * RUN: echo -n > %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | /* Utility functions */ 27 | 28 | /* Tests */ 29 | static void test_lseek(int fd) { assert(lseek(fd, 1, SEEK_SET) != -1); } 30 | 31 | int main(int argc, char **argv) { 32 | /* Set-up */ 33 | int fd = open(argv[1], O_RDWR); 34 | 35 | /* Test */ 36 | test_lseek(fd); 37 | 38 | /* Tear-down */ 39 | close(fd); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /tests/Simple/test_sanitizers.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* REQUIRES: clang,tsan 9 | * RUN: ulimit -s 32768 10 | * RUN: %{gcc} -fsanitize=thread %s -o %t1 11 | * RUN: %{clang} -fsanitize=thread %s -o %t2 12 | * RUN: %{gcc} -fsanitize=address %s -o %t3 13 | * RUN: %{clang} -fsanitize=address %s -o %t4 14 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 15 | * RUN: %{sbr} %{sbr-id} -- %t2 &> %t2.actual 16 | * RUN: %{sbr} %{sbr-id} -- %t3 &> %t3.actual 17 | * RUN: %{sbr} %{sbr-id} -- %t4 &> %t4.actual 18 | * RUN: echo "Hello, world!" > %t1.expected 19 | * RUN: diff %t1.actual %t1.expected 20 | * RUN: diff %t2.actual %t1.expected 21 | * RUN: diff %t3.actual %t1.expected 22 | * RUN: diff %t4.actual %t1.expected 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | int main(int argc, char **argv) { 29 | printf("Hello, world!\n"); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /tests/Simple/test_stat.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: echo > %t1 10 | * RUN: ln -s -f %t1 %t1.link 11 | * RUN: %{cc} %s -o %t2 12 | * RUN: %{sbr} %{sbr-id} -- %t2 %t1 %t1.link &> %t2.actual 13 | * RUN: echo -n > %t2.expected 14 | * RUN: diff %t2.actual %t2.expected 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | /* Utility functions */ 30 | 31 | /* Tests */ 32 | 33 | static void test_stat(char *filename) { 34 | struct stat s; 35 | assert(stat(filename, &s) != -1); 36 | } 37 | 38 | static void test_fstat(int fd) { 39 | struct stat s; 40 | assert(fstat(fd, &s) != -1); 41 | } 42 | 43 | static void test_lstat_readlink(char *filename) { 44 | struct stat s; 45 | char *linkname; 46 | ssize_t r; 47 | 48 | assert(lstat(filename, &s) != -1); 49 | 50 | linkname = malloc(s.st_size + 1); 51 | 52 | r = readlink(filename, linkname, s.st_size + 1); 53 | 54 | free(linkname); 55 | } 56 | 57 | static void test_statfs(char *filename) { 58 | struct statfs s; 59 | 60 | assert(statfs(filename, &s) != -1); 61 | } 62 | 63 | static void test_fstatfs(int fd) { 64 | struct statfs s; 65 | 66 | assert(fstatfs(fd, &s) != -1); 67 | } 68 | 69 | int main(int argc, char **argv) { 70 | /* Set-up */ 71 | int fd = open(argv[1], O_RDONLY); 72 | 73 | /* Test */ 74 | test_stat(argv[1]); 75 | test_lstat_readlink(argv[2]); 76 | test_statfs(argv[1]); 77 | test_fstatfs(fd); 78 | 79 | /* Tear-down */ 80 | close(fd); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /tests/Simple/test_sys.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: echo "This is a test file" > %t2 10 | * RUN: %{cc} -std=c99 %s -o %t1 11 | * RUN: %{sbr} %{sbr-id} -- %t1 %t2 &> %t1.actual 12 | * RUN: echo -n > %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | /* Utility functions */ 32 | 33 | /* Tests */ 34 | static void test_getgid() { 35 | getgid(); 36 | getegid(); 37 | } 38 | 39 | static void test_getuid() { 40 | getuid(); 41 | geteuid(); 42 | } 43 | 44 | static void test_getpid() { getpid(); } 45 | 46 | static void test_getrlimit() { 47 | struct rlimit rl; 48 | 49 | assert(getrlimit(RLIMIT_STACK, &rl) == 0); 50 | } 51 | 52 | static void test_prctl() { 53 | char buf[16]; 54 | 55 | assert(prctl(PR_GET_NAME, buf, NULL, NULL, NULL) == 0); 56 | } 57 | 58 | static void test_times() { 59 | struct tms tms; 60 | 61 | assert(times(&tms) != -1); 62 | } 63 | 64 | static void test_uname() { 65 | struct utsname uts; 66 | 67 | assert(uname(&uts) == 0); 68 | } 69 | 70 | static void test_mmap(int fd) { 71 | assert(mmap(NULL, 16, PROT_READ, MAP_PRIVATE, fd, 0) != MAP_FAILED); 72 | } 73 | 74 | int main(int argc, char **argv) { 75 | assert(argc == 2); 76 | /* Set-up */ 77 | int fd = open(argv[1], O_RDONLY); 78 | 79 | /* Test */ 80 | test_prctl(); 81 | test_getgid(); 82 | test_getpid(); 83 | test_getuid(); 84 | test_getrlimit(); 85 | test_times(); 86 | test_uname(); 87 | 88 | test_mmap(fd); 89 | 90 | /* Tear-down */ 91 | close(fd); 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /tests/Simple/test_time.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t2 10 | * RUN: %{sbr} %{sbr-id} -- %t2 2>&1 > %t2.actual 11 | * RUN: echo "Success" > %t2.expected 12 | * RUN: diff %t2.actual %t2.expected 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | /* Utility functions */ 25 | 26 | /* Tests */ 27 | static void test_time() { assert(time(NULL) != -1); } 28 | 29 | static void test_gettimeofday() { 30 | struct timeval tv; 31 | struct timezone tz; 32 | 33 | assert(gettimeofday(&tv, &tz) == 0); 34 | } 35 | 36 | static void test_clock_gettime() { 37 | struct timespec tp; 38 | 39 | assert(clock_gettime(CLOCK_REALTIME, &tp) == 0); 40 | } 41 | 42 | int main(int argc, char **argv) { 43 | /* Set-up */ 44 | 45 | /* Test */ 46 | test_time(); 47 | test_gettimeofday(); 48 | test_clock_gettime(); 49 | 50 | /* Tear-down */ 51 | printf("Success\n"); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /tests/Simple/test_tsan.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * XFAIL: * 10 | * REQUIRES: clang,tsan 11 | * RUN: ulimit -s 32768 12 | * RUN: %{gcc} -fsanitize=thread -fPIE -pie -g -O1 %s -o %t1 13 | * RUN: %{clang} -fsanitize=thread -fPIE -pie -g -O1 %s -o %t2 14 | * RUN: ! %{sbr} %{sbr-id} -- %t1 &> %t1.actual 15 | * RUN: ! %{sbr} %{sbr-id} -- %t2 &> %t2.actual 16 | * RUN: grep "WARNING: ThreadSanitizer: data race" %t1.actual 17 | * RUN: grep "WARNING: ThreadSanitizer: data race" %t2.actual 18 | * RUN: grep "Location is global 'Global' of size" %t1.actual 19 | * RUN: grep "Location is global 'Global' of size" %t2.actual 20 | */ 21 | 22 | // Currently this fails because TSan can't properly resolve symbols due to 23 | // SaBRe. 24 | 25 | #include 26 | 27 | int Global; 28 | 29 | void *Thread1(void *x) { 30 | Global++; 31 | return NULL; 32 | } 33 | 34 | void *Thread2(void *x) { 35 | Global--; 36 | return NULL; 37 | } 38 | 39 | int main() { 40 | pthread_t t[2]; 41 | pthread_create(&t[0], NULL, Thread1, NULL); 42 | pthread_create(&t[1], NULL, Thread2, NULL); 43 | pthread_join(t[0], NULL); 44 | pthread_join(t[1], NULL); 45 | } 46 | -------------------------------------------------------------------------------- /tests/Utils/help/bash.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # RUN: %{sbr} %{sbr-id} -- %{bash} --help &>%t1 8 | # RUN: grep "bash" %t1 9 | -------------------------------------------------------------------------------- /tests/Utils/help/bunzip2.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: bunzip2 8 | # RUN: %{sbr} %{sbr-id} -- %{bunzip2} --help &>%t1 9 | # RUN: grep "bunzip2" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/bzip2.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: bzip2 8 | # RUN: %{sbr} %{sbr-id} -- %{bzip2} --help &>%t1 9 | # RUN: grep "bzip2" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/cat.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: cat 8 | # RUN: %{sbr} %{sbr-id} -- %{cat} --help &>%t1 9 | # RUN: grep "cat" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/chacl.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: chacl 8 | # RUN: %{sbr} %{sbr-id} -- %{chacl} &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 1 10 | # RUN: grep "chacl" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/chgrp.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: chgrp 8 | # RUN: %{sbr} %{sbr-id} -- %{chgrp} --help &>%t1 9 | # RUN: grep "chgrp" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/chmod: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: chmod 8 | # RUN: %{sbr} %{sbr-id} -- %{chmod} --help &>%t1 9 | # RUN: grep "chmod" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/cp.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: cp 8 | # RUN: %{sbr} %{sbr-id} -- %{cp} --help &>%t1 9 | # RUN: grep "cp" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/date.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: date 8 | # RUN: %{sbr} %{sbr-id} -- %{date} --help &>%t1 9 | # RUN: grep "date" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/dbus-uuidgen.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: dbus-uuidgen 8 | # RUN: %{sbr} %{sbr-id} -- %{dbus-uuidgen} --help &>%t1 9 | # RUN: grep "dbus-uuidgen" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/dd.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: dd 8 | # RUN: %{sbr} %{sbr-id} -- %{dd} --help &>%t1 9 | # RUN: grep "dd" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/dmesg.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: dmesg 8 | # RUN: %{sbr} %{sbr-id} -- %{dmesg} --help &>%t1 9 | # RUN: grep "dmesg" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/dumpkeys.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: dumpkeys 8 | # RUN: %{sbr} %{sbr-id} -- %{dumpkeys} --help &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 1 10 | # RUN: grep "dumpkeys" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/ed.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ed 8 | # RUN: %{sbr} %{sbr-id} -- %{ed} --help &>%t1 9 | # RUN: grep "ed" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/efibootmgr.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: efibootmgr 8 | # RUN: %{sbr} %{sbr-id} -- %{efibootmgr} --help &>%t1 9 | # RUN: grep "efibootmgr" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/fgconsole.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: fgconsole 8 | # RUN: %{sbr} %{sbr-id} -- %{fgconsole} --help &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 1 10 | # RUN: grep "fgconsole" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/fuser.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: fuser 8 | # RUN: %{sbr} %{sbr-id} -- %{fuser} --help &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 1 10 | # RUN: grep "fuser" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/gcc.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # RUN: %{sbr} %{sbr-id} -- %{gcc} --help &>%t1 8 | # RUN: grep "gcc" %t1 9 | -------------------------------------------------------------------------------- /tests/Utils/help/grep.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: grep 8 | # RUN: %{sbr} %{sbr-id} -- %{grep} --help &>%t1 9 | # RUN: grep "grep" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/gzip.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: gzip 8 | # RUN: %{sbr} %{sbr-id} -- %{gzip} --help &>%t1 9 | # RUN: grep "gzip" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/ip.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ip 8 | # RUN: %{sbr} %{sbr-id} -- %{ip} --help &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 255 10 | # RUN: grep "ip" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/kill.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: kill 8 | # RUN: %{sbr} %{sbr-id} -- %{kill} --help &>%t1 9 | # RUN: grep "kill" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/kmod.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: kmod 8 | # RUN: %{sbr} %{sbr-id} -- %{kmod} --help &>%t1 9 | # RUN: grep "kmod" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/lessecho.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: lessecho 8 | # RUN: %{sbr} %{sbr-id} -- %{lessecho} --help &>%t1 9 | # RUN: grep "lessecho" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/ln.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ln 8 | # RUN: %{sbr} %{sbr-id} -- %{ln} --help &>%t1 9 | # RUN: grep "ln" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/loginctl.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: loginctl 8 | # RUN: %{sbr} %{sbr-id} -- %{loginctl} --help &>%t1 9 | # RUN: grep "loginctl" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/ls.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ls 8 | # RUN: %{sbr} %{sbr-id} -- %{ls} --help &>%t1 9 | # RUN: grep "ls" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/lsmod.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: lsmod 8 | # RUN: %{sbr} %{sbr-id} -- %{lsmod} --help &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 1 10 | # RUN: grep "lsmod" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/mktemp.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: mktemp 8 | # RUN: %{sbr} %{sbr-id} -- %{mktemp} --help &>%t1 9 | # RUN: grep "mktemp" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/mount.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: mount 8 | # RUN: %{sbr} %{sbr-id} -- %{mount} --help &>%t1 9 | # RUN: grep "mount" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/nano.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: nano 8 | # RUN: %{sbr} %{sbr-id} -- %{nano} --help &>%t1 9 | # RUN: grep "nano" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/nc.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: nc 8 | # RUN: %{sbr} %{sbr-id} -- %{nc} -h &>%t1 9 | # RUN: grep "nc" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/ntfs-3g.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ntfs-3g 8 | # RUN: %{sbr} %{sbr-id} -- %{ntfs-3g} --help &>%t1 || RC=$(echo $?) 9 | # RUN: test ${RC} -eq 9 10 | # RUN: grep "Usage: ntfs-3g" %t1 11 | -------------------------------------------------------------------------------- /tests/Utils/help/openvt.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: openvt 8 | # RUN: %{sbr} %{sbr-id} -- %{openvt} --help &>%t1 9 | # RUN: grep "openvt" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/ping.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ping 8 | # RUN: %{ping} || RC_ORIG=$(echo $?) 9 | # RUN: %{sbr} %{sbr-id} -- %{ping} &>%t1 || RC_SABRE=$(echo $?) 10 | # RUN: test ${RC_ORIG} -eq ${RC_SABRE} 11 | # RUN: grep "ping" %t1 12 | -------------------------------------------------------------------------------- /tests/Utils/help/ps.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: ps 8 | # RUN: %{sbr} %{sbr-id} -- %{ps} --help s &>%t1 9 | # RUN: grep "ps" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/sed.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: sed 8 | # RUN: %{sbr} %{sbr-id} -- %{sed} --help &>%t1 9 | # RUN: grep "sed" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/setfacl.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: setfacl 8 | # RUN: %{sbr} %{sbr-id} -- %{setfacl} --help &>%t1 9 | # RUN: grep "setfacl" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/help/tar.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # REQUIRES: tar 8 | # RUN: %{sbr} %{sbr-id} -- %{tar} --help &>%t1 9 | # RUN: grep "tar" %t1 10 | -------------------------------------------------------------------------------- /tests/Utils/test_rm.sh: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # These tests are for testing the existence of: unlinkat, faccessat and 8 | # newfstatat system call. 9 | # 10 | # RUN: echo > %t1.file 11 | # RUN: echo > %t2.file 12 | # RUN: mkdir -p %t3.dir 13 | # RUN: %{sbr} %{sbr-id} -- /bin/rm %t1.file 14 | # RUN: %{sbr} %{sbr-id} -- /bin/rm -f %t2.file 15 | # RUN: %{sbr} %{sbr-id} -- /bin/rm -rf %t3.dir 16 | -------------------------------------------------------------------------------- /tests/Utils/test_shebang.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright © 2019 Software Reliability Group, Imperial College London 4 | # 5 | # This file is part of SaBRe. 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | 9 | # RUN: %{sbr} %{sbr-id} -- %s &>%t1.actual 10 | # RUN: echo "Hello World!" >%t1.expected 11 | # RUN: diff %t1.actual %t1.expected 12 | 13 | echo "Hello World!" 14 | -------------------------------------------------------------------------------- /tests/Utils/test_shebang2.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright © 2019 Software Reliability Group, Imperial College London 4 | # 5 | # This file is part of SaBRe. 6 | # 7 | # SPDX-License-Identifier: GPL-3.0-or-later 8 | 9 | # RUN: %{sbr} %{sbr-id} -- %s &>%t1.actual 10 | # RUN: echo "Hello World!" >%t1.expected 11 | # RUN: diff %t1.actual %t1.expected 12 | 13 | echo "Hello World!" 14 | -------------------------------------------------------------------------------- /tests/ld/lit.cfg.in: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # -*- Python -*- 8 | 9 | import os 10 | import sys 11 | 12 | import lit.formats 13 | 14 | ################################################################################# 15 | # @LIT_AUTOGENERATED_WARNING@ 16 | ################################################################################# 17 | 18 | # Configuration file for the 'lit' test runner. 19 | 20 | # name: The name of this test suite. 21 | config.name = 'sabre-tests-ld' 22 | 23 | # testFormat: The test format to use to interpret tests. 24 | config.test_format = lit.formats.ShTest(execute_external=True) 25 | 26 | # suffixes: A list of file extensions to treat as test files. 27 | config.suffixes = ['.c', '.sh'] 28 | 29 | # test_source_root: The root path where tests are located. 30 | config.test_source_root = '@CMAKE_BINARY_DIR@/tests/ld' 31 | config.test_exec_root = '@CMAKE_BINARY_DIR@/tests' 32 | 33 | config.target_triple = '(unused)' 34 | 35 | config.substitutions.append(('%{sbr}', '@CMAKE_BINARY_DIR@/sabre @CMAKE_BINARY_DIR@/plugins/sbr-id/libsbr-id.so --')) 36 | config.substitutions.append(('%{cc}', '@GCC_PATH@')) 37 | config.substitutions.append(('%{clang}', '@CLANG_PATH@')) 38 | config.substitutions.append(('%{gcc}', '@GCC_PATH@')) 39 | -------------------------------------------------------------------------------- /tests/ld/test.c.in: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 -fPIE @link@ @pie@ 10 | * RUN: %{sbr} %t1 &> %t1.actual 11 | * %t1 &> %t1.actual 12 | * RUN: echo "Hello, world!" > %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | // ############################################################################# 17 | // # @LIT_AUTOGENERATED_WARNING@ 18 | // ############################################################################# 19 | 20 | #include 21 | #include 22 | 23 | int main(int argc, char **argv) { 24 | printf("Hello, world!\n"); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tests/lit.cfg.in: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # -*- Python -*- 8 | 9 | ################################################################################ 10 | # 11 | # @LIT_AUTOGENERATED_WARNING@ 12 | # 13 | ################################################################################ 14 | 15 | import os 16 | import sys 17 | 18 | import lit.formats 19 | 20 | 21 | 22 | # Configuration file for the 'lit' test runner. 23 | 24 | # name: The name of this test suite. 25 | config.name = 'sabre-tests' 26 | 27 | # testFormat: The test format to use to interpret tests. 28 | config.test_format = lit.formats.ShTest(execute_external=True) 29 | 30 | # suffixes: A list of file extensions to treat as test files. 31 | config.suffixes = ['.c', '.S', '.sh'] 32 | 33 | # excludes: A list of individual files to exclude. 34 | config.excludes = [] 35 | 36 | # test_source_root: The root path where tests are located. 37 | config.test_source_root = '@PROJECT_SOURCE_DIR@/tests' 38 | config.test_exec_root = '@CMAKE_BINARY_DIR@/tests' 39 | 40 | config.target_triple = '(unused)' 41 | 42 | config.substitutions.append(('%{bash}', '@TEST_BASH_PATH@')) 43 | config.substitutions.append(('%{timeout}', '@TEST_TIMEOUT_PATH@')) 44 | config.substitutions.append(('%{cc}', '@TEST_GCC_PATH@')) 45 | config.substitutions.append(('%{clang}', '@TEST_CLANG_PATH@')) 46 | config.substitutions.append(('%{gcc}', '@TEST_GCC_PATH@')) 47 | 48 | config.substitutions.append(('%{sbr}', '@CMAKE_BINARY_DIR@/sabre')) 49 | config.substitutions.append(('%{sbr-id}', '@CMAKE_BINARY_DIR@/plugins/sbr-id/libsbr-id.so')) 50 | config.substitutions.append(('%{sbr-trc}', '@CMAKE_BINARY_DIR@/plugins/sbr-trace/libsbr-trace.so')) 51 | config.substitutions.append(('%{process-vdso}', '@CMAKE_BINARY_DIR@/tools/process-vdso')) 52 | 53 | # Programs for utils tests 54 | config.substitutions.append(('%{bunzip2}' , '@TEST_BUNZIP2_PATH@')) 55 | config.substitutions.append(('%{bzip2}' , '@TEST_BZIP2_PATH@')) 56 | config.substitutions.append(('%{cat}' , '@TEST_CAT_PATH@')) 57 | config.substitutions.append(('%{chacl}' , '@TEST_CHACL_PATH@')) 58 | config.substitutions.append(('%{chgrp}' , '@TEST_CHGRP_PATH@')) 59 | config.substitutions.append(('%{chmod}' , '@TEST_CHMOD_PATH@')) 60 | config.substitutions.append(('%{cp}' , '@TEST_CP_PATH@')) 61 | config.substitutions.append(('%{date}' , '@TEST_DATE_PATH@')) 62 | config.substitutions.append(('%{dbus-uuidgen}' , '@TEST_DBUS-UUIDGEN_PATH@')) 63 | config.substitutions.append(('%{dd}' , '@TEST_DD_PATH@')) 64 | config.substitutions.append(('%{dmesg}' , '@TEST_DMESG_PATH@')) 65 | config.substitutions.append(('%{dumpkeys}' , '@TEST_DUMPKEYS_PATH@')) 66 | config.substitutions.append(('%{ed}' , '@TEST_ED_PATH@')) 67 | config.substitutions.append(('%{efibootmgr}' , '@TEST_EFIBOOTMGR_PATH@')) 68 | config.substitutions.append(('%{fgconsole}' , '@TEST_FGCONSOLE_PATH@')) 69 | config.substitutions.append(('%{fgrep}' , '@TEST_FGREP_PATH@')) 70 | config.substitutions.append(('%{fuser}' , '@TEST_FUSER_PATH@')) 71 | config.substitutions.append(('%{grep}' , '@TEST_GREP_PATH@')) 72 | config.substitutions.append(('%{gzip}' , '@TEST_GZIP_PATH@')) 73 | config.substitutions.append(('%{ip}' , '@TEST_IP_PATH@')) 74 | config.substitutions.append(('%{kill}' , '@TEST_KILL_PATH@')) 75 | config.substitutions.append(('%{kmod}' , '@TEST_KMOD_PATH@')) 76 | config.substitutions.append(('%{lessecho}' , '@TEST_LESSECHO_PATH@')) 77 | config.substitutions.append(('%{ln}' , '@TEST_LN_PATH@')) 78 | config.substitutions.append(('%{loginctl}' , '@TEST_LOGINCTL_PATH@')) 79 | config.substitutions.append(('%{lsmod}' , '@TEST_LSMOD_PATH@')) 80 | config.substitutions.append(('%{ls}' , '@TEST_LS_PATH@')) 81 | config.substitutions.append(('%{mktemp}' , '@TEST_MKTEMP_PATH@')) 82 | config.substitutions.append(('%{mount}' , '@TEST_MOUNT_PATH@')) 83 | config.substitutions.append(('%{nano}' , '@TEST_NANO_PATH@')) 84 | config.substitutions.append(('%{nc}' , '@TEST_NC_PATH@')) 85 | config.substitutions.append(('%{ntfs-3g}' , '@TEST_NTFS-3G_PATH@')) 86 | config.substitutions.append(('%{openvt}' , '@TEST_OPENVT_PATH@')) 87 | config.substitutions.append(('%{ping}' , '@TEST_PING_PATH@')) 88 | config.substitutions.append(('%{ps}' , '@TEST_PS_PATH@')) 89 | config.substitutions.append(('%{sed}' , '@TEST_SED_PATH@')) 90 | config.substitutions.append(('%{setfacl}' , '@TEST_SETFACL_PATH@')) 91 | config.substitutions.append(('%{su}' , '@TEST_SU_PATH@')) 92 | config.substitutions.append(('%{tar}' , '@TEST_TAR_PATH@')) 93 | 94 | config.available_features = [@SABRE_AVAILABLE_TEST_FEATURES_STR@] 95 | -------------------------------------------------------------------------------- /tests/regression/test_ancillary.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: echo "Test contents" > %t1.expected 11 | * RUN: %{sbr} %{sbr-id} -- %t1 %t1.expected &> %t1.actual 12 | * RUN: diff %t1.actual %t1.expected 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static void test_send(int socket, int fd) // send fd by socket 25 | { 26 | struct msghdr msg = {0}; 27 | char buf[CMSG_SPACE(sizeof(fd))]; 28 | memset(buf, '\0', sizeof(buf)); 29 | struct iovec io = {.iov_base = "ABC", .iov_len = 3}; 30 | 31 | msg.msg_iov = &io; 32 | msg.msg_iovlen = 1; 33 | msg.msg_control = buf; 34 | msg.msg_controllen = sizeof(buf); 35 | 36 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 37 | cmsg->cmsg_level = SOL_SOCKET; 38 | cmsg->cmsg_type = SCM_RIGHTS; 39 | cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 40 | 41 | *((int *)CMSG_DATA(cmsg)) = fd; 42 | 43 | msg.msg_controllen = cmsg->cmsg_len; 44 | 45 | if (sendmsg(socket, &msg, 0) < 0) { 46 | printf("Failed to send message\n"); 47 | exit(-1); 48 | } 49 | } 50 | 51 | static int test_receive(int socket) // receive fd from socket 52 | { 53 | struct msghdr msg = {0}; 54 | 55 | char m_buffer[256]; 56 | struct iovec io = {.iov_base = m_buffer, .iov_len = sizeof(m_buffer)}; 57 | msg.msg_iov = &io; 58 | msg.msg_iovlen = 1; 59 | msg.msg_flags = INT_MAX; 60 | 61 | union { 62 | struct cmsghdr cm; 63 | char space[CMSG_SPACE(sizeof(int))]; 64 | } cmsg; 65 | msg.msg_control = cmsg.space; 66 | msg.msg_controllen = sizeof(cmsg); 67 | 68 | if (recvmsg(socket, &msg, 0) < 0) { 69 | printf("Failed to receive message\n"); 70 | exit(-1); 71 | } 72 | 73 | if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { 74 | printf("Truncated data"); 75 | exit(-1); 76 | } 77 | 78 | unsigned char *data = CMSG_DATA((&cmsg.cm)); 79 | 80 | int fd = *((int *)data); 81 | return fd; 82 | } 83 | 84 | int main(int argc, char **argv) { 85 | const char *filename = argv[1]; 86 | 87 | int sv[2]; 88 | if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) != 0) { 89 | printf("Failed to create Unix-domain socket pair\n"); 90 | exit(-1); 91 | } 92 | 93 | int pid = fork(); 94 | if (pid > 0) // in parent 95 | { 96 | close(sv[1]); 97 | int sock = sv[0]; 98 | 99 | int fd = open(filename, O_RDONLY); 100 | if (fd < 0) { 101 | printf("Failed to open file %s for reading\n", filename); 102 | exit(-1); 103 | } 104 | 105 | test_send(sock, fd); 106 | 107 | close(fd); 108 | nanosleep(&(struct timespec){.tv_sec = 1, .tv_nsec = 500000000}, 0); 109 | } else // in child 110 | { 111 | close(sv[0]); 112 | int sock = sv[1]; 113 | 114 | nanosleep(&(struct timespec){.tv_sec = 0, .tv_nsec = 500000000}, 0); 115 | 116 | int fd = test_receive(sock); 117 | char buffer[256]; 118 | ssize_t nbytes; 119 | while ((nbytes = read(fd, buffer, sizeof(buffer))) > 0) 120 | write(1, buffer, nbytes); 121 | close(fd); 122 | } 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /tests/regression/test_dlopen.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | // RUN: %{cc} %s -o %t1 -ldl 9 | // RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 10 | // %t1 &> %t1.actual 11 | // RUN: echo "-0.416147" > %t1.expected 12 | // RUN: diff %t1.actual %t1.expected 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int main(void) { 20 | void *handle; 21 | double (*cosine)(double); 22 | char *error; 23 | 24 | handle = dlopen(LIBM_SO, RTLD_LAZY); 25 | if (!handle) { 26 | fprintf(stderr, "%s\n", dlerror()); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | dlerror(); 31 | 32 | cosine = (double (*)(double))dlsym(handle, "cos"); 33 | 34 | error = dlerror(); 35 | if (error != NULL) { 36 | fprintf(stderr, "%s\n", error); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | printf("%f\n", (*cosine)(2.0)); 41 | dlclose(handle); 42 | exit(EXIT_SUCCESS); 43 | } 44 | -------------------------------------------------------------------------------- /tests/regression/test_execve_sigchld.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -D_EXEC_NAME=%t1 -o %t1 10 | * RUN: echo "Hello, world!" > %t1.expected 11 | * RUN: echo "1" >> %t1.expected 12 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 1 13 | * RUN: sleep 2 14 | * RUN: diff %t1.actual %t1.expected 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define xstr(a) str(a) 29 | #define str(a) #a 30 | 31 | #ifndef _EXEC_NAME 32 | #define _EXEC_NAME a.out 33 | #endif 34 | 35 | #define ISSET(t, f) ((t) & (f)) 36 | 37 | int signal_pipe[2]; 38 | 39 | static void handler(int s, siginfo_t *info, void *context) { 40 | unsigned char signo = (unsigned char)s; 41 | 42 | while (write(signal_pipe[1], &signo, sizeof(signo)) == -1) { 43 | if (errno != EINTR) 44 | break; 45 | } 46 | } 47 | 48 | int main(int argc, char **argv) { 49 | if (argc == 1) { 50 | printf("Hello, world!\n"); 51 | fflush(NULL); 52 | return 0; 53 | } 54 | 55 | // Set up pipe and make it non-blocking 56 | int rval = pipe(signal_pipe); 57 | if (rval == -1) 58 | return -1; 59 | 60 | int flags = fcntl(signal_pipe[0], F_GETFL, 0); 61 | if (flags != -1 && !ISSET(flags, O_NONBLOCK)) 62 | rval = fcntl(signal_pipe[0], F_SETFL, flags | O_NONBLOCK); 63 | if (rval != -1) { 64 | flags = fcntl(signal_pipe[1], F_GETFL, 0); 65 | if (flags != -1 && !ISSET(flags, O_NONBLOCK)) 66 | rval = fcntl(signal_pipe[1], F_SETFL, flags | O_NONBLOCK); 67 | } 68 | 69 | // Set up signal handler 70 | struct sigaction sa; 71 | memset(&sa, 0, sizeof(sa)); 72 | sigfillset(&sa.sa_mask); 73 | sa.sa_flags = SA_INTERRUPT; 74 | sa.sa_flags |= SA_SIGINFO; 75 | sa.sa_sigaction = handler; 76 | 77 | sigaction(SIGCHLD, &sa, NULL); 78 | 79 | // Fork 80 | int pid = fork(); 81 | 82 | if (pid == 0) { 83 | // Child - execve 84 | char *const args[] = {xstr(_EXEC_NAME), NULL}; 85 | char *const envp[] = {NULL}; 86 | sleep(1); 87 | execve(xstr(_EXEC_NAME), args, envp); 88 | assert(0); 89 | } 90 | 91 | // Parent - poll on pipe 92 | struct pollfd fd; 93 | fd.fd = signal_pipe[0]; 94 | fd.events = (POLLIN | POLLHUP); 95 | 96 | for (;;) { 97 | int ret = poll(&fd, 1, -1); 98 | if (ret > 0) 99 | break; 100 | else if (ret == -1 && errno != EINVAL) 101 | // Try again 102 | continue; 103 | else 104 | return -1; 105 | } 106 | 107 | unsigned char signo; 108 | 109 | if (fd.revents & POLLIN) 110 | read(signal_pipe[0], &signo, sizeof(signo)); 111 | else { 112 | printf("Unexpected poll revents: %d\n", fd.revents); 113 | return -1; 114 | } 115 | 116 | printf("%d\n", signo == SIGCHLD); 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /tests/regression/test_mktemp.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * REQUIRES: rdtsc 10 | * RUN: %{cc} %s -o %t1 11 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 12 | * RUN: echo "Success" > %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int main() { 24 | char template[] = "tmpXXXXXX"; 25 | 26 | mktemp(template); 27 | 28 | assert(strlen(template) > 0); 29 | 30 | struct stat buf; 31 | assert(stat(template, &buf) == -1); 32 | 33 | printf("Success\n"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /tests/regression/test_pthread.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -pthread -o %t1 10 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 11 | * RUN: echo "Hello from thread" > %t1.expected 12 | * RUN: echo "Hello from main" >> %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | /* this function is run by the second thread */ 20 | void *thread_f(void *ignored) { 21 | printf("Hello from thread\n"); 22 | return NULL; 23 | } 24 | 25 | int main() { 26 | 27 | /* this variable is our reference to the second thread */ 28 | pthread_t thread; 29 | 30 | /* create a second thread which executes inc_x(&x) */ 31 | if (pthread_create(&thread, NULL, thread_f, NULL)) { 32 | printf("Error creating thread\n"); 33 | return 1; 34 | } 35 | 36 | /* wait for the second thread to finish */ 37 | if (pthread_join(thread, NULL)) { 38 | printf("Error joining thread\n"); 39 | return 2; 40 | } 41 | 42 | printf("Hello from main\n"); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /tests/regression/test_return_value.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: ! %{sbr} %{sbr-id} -- %t1 11 | */ 12 | 13 | int main() { return 1; } 14 | -------------------------------------------------------------------------------- /tests/regression/test_select.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: echo -n "Test contents" > %t1.expected 11 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 12 | * RUN: diff %t1.actual %t1.expected 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define TO_SEND "Test contents" 26 | 27 | struct metadata { 28 | int fd; 29 | }; 30 | 31 | #define MAXEVENTS 64 32 | 33 | int main(int argc, char **argv) { 34 | int sv[2]; 35 | if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) != 0) { 36 | printf("Failed to create Unix-domain socket pair\n"); 37 | exit(-1); 38 | } 39 | 40 | int pid = fork(); 41 | if (pid > 0) { // in parent 42 | close(sv[1]); 43 | int sock = sv[0]; 44 | 45 | const char *to_send = TO_SEND; 46 | 47 | fd_set active_fd_set, ready_fd_set; 48 | 49 | FD_ZERO(&active_fd_set); 50 | FD_SET(sock, &active_fd_set); 51 | 52 | while (1) { 53 | ready_fd_set = active_fd_set; 54 | if (select(sock + 1, NULL, &ready_fd_set, NULL, NULL) < 0) { 55 | printf("Error\n"); 56 | return 1; 57 | } 58 | 59 | if (FD_ISSET(sock, &ready_fd_set)) { 60 | write(sock, to_send, strlen(to_send)); 61 | close(sock); 62 | 63 | return 0; 64 | } 65 | } 66 | } else { // in child 67 | close(sv[0]); 68 | int sock = sv[1]; 69 | 70 | fd_set active_fd_set, ready_fd_set; 71 | 72 | FD_ZERO(&active_fd_set); 73 | FD_SET(sock, &active_fd_set); 74 | 75 | while (1) { 76 | char buffer[256]; 77 | 78 | ready_fd_set = active_fd_set; 79 | if (select(sock + 1, &ready_fd_set, NULL, NULL, NULL) < 0) { 80 | printf("Error\n"); 81 | return 1; 82 | } 83 | 84 | if (FD_ISSET(sock, &ready_fd_set)) { 85 | ssize_t nbytes = read(sock, buffer, strlen("Test contents")); 86 | write(1, buffer, nbytes); 87 | close(sock); 88 | 89 | return 0; 90 | } 91 | } 92 | } 93 | 94 | // Dead code 95 | assert(0); 96 | return 1; 97 | } 98 | -------------------------------------------------------------------------------- /tests/smoke/hello.c.in: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{gcc} %s -o %t1 10 | * RUN: echo "Hello World!" > %t2 11 | * RUN: %{@tool@} %t1 &> %t3 12 | * RUN: diff %t2 %t3 13 | */ 14 | 15 | // ############################################################################# 16 | // # @LIT_AUTOGENERATED_WARNING@ 17 | // ############################################################################# 18 | 19 | #include 20 | 21 | int main(int argc, char *argv[]) { 22 | printf("Hello World!\n"); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/smoke/lit.cfg.in: -------------------------------------------------------------------------------- 1 | # Copyright © 2019 Software Reliability Group, Imperial College London 2 | # 3 | # This file is part of SaBRe. 4 | # 5 | # SPDX-License-Identifier: GPL-3.0-or-later 6 | 7 | # -*- Python -*- 8 | 9 | ################################################################################ 10 | # 11 | # @LIT_AUTOGENERATED_WARNING@ 12 | # 13 | ################################################################################ 14 | 15 | import os 16 | import sys 17 | 18 | import lit.formats 19 | 20 | # Configuration file for the 'lit' test runner. 21 | 22 | # name: The name of this test suite. 23 | config.name = 'sabre-smoketests' 24 | 25 | # testFormat: The test format to use to interpret tests. 26 | config.test_format = lit.formats.ShTest(execute_external=True) 27 | 28 | # suffixes: A list of file extensions to treat as test files. 29 | config.suffixes = ['.c', '.S', '.sh'] 30 | 31 | # excludes: A list of individual files to exclude. 32 | config.excludes = [] 33 | 34 | # test_source_root: The root path where tests are located. 35 | config.test_source_root = '@CMAKE_BINARY_DIR@/tests/smoke' 36 | config.test_exec_root = '@CMAKE_BINARY_DIR@/tests' 37 | 38 | config.target_triple = '(unused)' 39 | 40 | config.substitutions.append(('%{gcc}', '@TEST_GCC_PATH@')) 41 | 42 | config.substitutions.append(('%{id}', '@CMAKE_BINARY_DIR@/sabre @CMAKE_BINARY_DIR@/plugins/sbr-id/libsbr-id.so --')) 43 | config.substitutions.append(('%{sbrtrace}', '@CMAKE_BINARY_DIR@/sabre @CMAKE_BINARY_DIR@/plugins/sbr-trace/libsbr-trace.so --output=/dev/null --')) 44 | config.substitutions.append(('%{fault-injector}', '@CMAKE_BINARY_DIR@/sabre @CMAKE_BINARY_DIR@/plugins/sbr-scfuzzer/libsbr-scfuzzer.so -u 0 -d 0 -f 0 -n 0 -p 0 -m 0 -o /dev/null --')) 45 | -------------------------------------------------------------------------------- /tests/syscalls/test_chmod.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | // RUN: %{cc} %s -o %t1 9 | // RUN: touch %t3 10 | // RUN: %{sbr} %{sbr-id} -- %t1 %t3 2>&1 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | int main(int argc, char **argv) { 19 | 20 | if (chmod(argv[1], 00755) < 0) 21 | return 1; 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/syscalls/test_chown.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | // RUN: %{cc} %s -o %t1 9 | // RUN: touch %t3 10 | // RUN: %{sbr} %{sbr-id} -- %t1 %t3 2>&1 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | int main(int argc, char **argv) { 19 | 20 | int fd = open(argv[1], O_RDONLY); 21 | if (fd < 0) 22 | return 1; 23 | 24 | if (fchown(fd, getuid(), getgid()) < 0) 25 | return 2; 26 | 27 | close(fd); 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/syscalls/test_clone.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 -lpthread 10 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 11 | * RUN: echo "Hello from parent" > %t1.expected 12 | * RUN: echo "Hello from child" >> %t1.expected 13 | * RUN: echo "Goodbye from parent" >> %t1.expected 14 | * RUN: diff %t1.actual %t1.expected 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include //Header file for sleep(). man 3 sleep for details. 21 | 22 | // A normal C function that is executed as a thread 23 | // when its name is specified in pthread_create() 24 | void *myThreadFun(void *msg) { 25 | printf("Hello from %s\n", (char *)msg); 26 | return NULL; 27 | } 28 | 29 | int main() { 30 | pthread_t thread_id; 31 | char *msg = "child"; 32 | 33 | printf("Hello from parent\n"); 34 | 35 | pthread_create(&thread_id, NULL, myThreadFun, msg); 36 | pthread_join(thread_id, NULL); 37 | 38 | printf("Goodbye from parent\n"); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /tests/syscalls/test_fork.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 11 | * RUN: echo "Hello from child" > %t1.expected 12 | * RUN: echo "Hello from parent" >> %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | 19 | long __syscall(int syscallno, long arg1, long arg2, long arg3, long arg4, 20 | long arg5, long arg6); 21 | 22 | int main(int argc, char *argv[]) { 23 | 24 | int ret = __syscall(__NR_fork, 0L, 0L, 0L, 0L, 0L, 0L); 25 | 26 | if (ret != 0) { 27 | // Parent 28 | char string[] = "Hello from parent\n"; 29 | int status; 30 | wait(&status); 31 | __syscall(__NR_write, 1, (long)string, 18, 0L, 0L, 0L); 32 | } else { 33 | // Child 34 | char string[] = "Hello from child\n"; 35 | __syscall(__NR_write, 1, (long)string, 17, 0L, 0L, 0L); 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | asm(".pushsection .text, \"ax\", @progbits\n" 42 | 43 | "__syscall:" 44 | ".internal __syscall\n" 45 | ".globl __syscall\n" 46 | ".type __syscall, @function\n" 47 | #if defined(__x86_64__) 48 | "movq %rdi, %rax\n" /* place syscall number into %rax */ 49 | "movq %rsi, %rdi\n" /* shift arg1 - arg5 */ 50 | "movq %rdx, %rsi\n" 51 | "movq %rcx, %rdx\n" 52 | "movq %r8, %r10\n" 53 | "movq %r9, %r8\n" 54 | "movq 8(%rsp),%r9\n" /* arg6 is on the stack */ 55 | "syscall\n" /* do the system call */ 56 | "ret\n" /* return to caller */ 57 | #else 58 | #error Unsupported target platform 59 | #endif 60 | ".size __syscall, .-__syscall\n" 61 | ".popsection\n"); 62 | -------------------------------------------------------------------------------- /tests/syscalls/test_fork_simple.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 11 | * RUN: echo "Hello from child" > %t1.expected 12 | * RUN: echo "Hello from parent" >> %t1.expected 13 | * RUN: diff %t1.actual %t1.expected 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | int main() { 21 | if (fork() == 0) { 22 | printf("Hello from child\n"); 23 | } else { 24 | int status; 25 | wait(&status); 26 | printf("Hello from parent\n"); 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/syscalls/test_prlimit.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | // RUN: %{cc} %s -o %t1 9 | // RUN: %{sbr} %{sbr-id} -- %t1 2>&1 10 | 11 | #ifndef _GNU_SOURCE 12 | #define _GNU_SOURCE 13 | #endif 14 | #include 15 | #include 16 | #include 17 | 18 | int main(void) { 19 | struct rlimit limit; 20 | 21 | if (prlimit(0, RLIMIT_STACK, NULL, &limit) != 0) 22 | return 1; 23 | 24 | limit.rlim_cur = limit.rlim_cur * 8 <= limit.rlim_max ? limit.rlim_cur * 8 25 | : limit.rlim_cur / 8; 26 | 27 | if (prlimit(0, RLIMIT_STACK, &limit, NULL) != 0) 28 | return 2; 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /tests/syscalls/test_utime.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | // RUN: %{cc} %s -o %t1 9 | // RUN: touch %t3 10 | // RUN: %{sbr} %{sbr-id} -- %t1 %t3 2>&1 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | int main(int argc, char **argv) { 20 | char buf[1024]; 21 | 22 | struct utimbuf t; 23 | t.actime = 10; 24 | t.modtime = 0; 25 | 26 | if (utime(argv[1], &t) < 0) 27 | return 1; 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/syscalls/test_vfork.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} %s -o %t1 10 | * RUN: %{sbr} %{sbr-id} -- %t1 &> %t1.actual 11 | * RUN: echo "Child process started" > %t1.expected 12 | * RUN: echo "Now i am coming back to parent process" >> %t1.expected 13 | * RUN: echo "Value of n: 10" >> %t1.expected 14 | * RUN: diff %t1.actual %t1.expected 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | int main() { 22 | int n = 10; 23 | pid_t pid = vfork(); //creating the child process 24 | if (pid == 0) //if this is a chile process 25 | { 26 | printf("Child process started\n"); 27 | _exit(0); 28 | } else //parent process execution 29 | { 30 | printf("Now i am coming back to parent process\n"); 31 | } 32 | printf("Value of n: %d\n", n); //sample printing to check "n" value 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /tests/syscalls/test_xattr.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | // RUN: %{cc} %s -o %t1 9 | // RUN: touch %t3 10 | // RUN: ln -sf %t3 %t3.link 11 | // RUN: %t1 %t3 %t3.link || RC_ORIG=$(echo $?) 12 | // RUN: %{sbr} %{sbr-id} -- %t1 %t3 %t3.link 2>&1 || RC_SABRE=$(echo $?) 13 | // RUN: test ${RC_ORIG} -eq ${RC_SABRE} 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | // TODO(andronat): By default ext4 doesn't mount with user_xattr and thus 25 | // most of the bellow code fails due to ENOTSUP. We just invoke the 26 | // below syscalls to test if Varan can intercept them, and not that 27 | // they properly work. Ideally a new mount should be created with 28 | // user_xattr enabled and this code should be tested inside it. 29 | 30 | int main(int argc, char **argv) { 31 | const char test_key[] = "user.test-key"; 32 | const char test_val[] = "test val"; 33 | char buf[1024]; 34 | size_t s; 35 | 36 | setxattr(argv[1], test_key, test_val, sizeof(test_val), XATTR_CREATE); 37 | // if (setxattr(argv[1], test_key, test_val, sizeof(test_val), XATTR_CREATE) < 0) 38 | // return 1; 39 | 40 | if ((s = getxattr(argv[1], test_key, buf, sizeof(test_val))) < 0) 41 | return 2; 42 | // if (s != sizeof(test_val) || strcmp(buf, test_val)) 43 | // return 3; 44 | 45 | if ((s = listxattr(argv[1], buf, sizeof buf)) == -1) 46 | return 4; 47 | // if (s != sizeof(test_key) || strcmp(buf, test_key)) 48 | // return 5; 49 | 50 | removexattr(argv[1], test_key); 51 | // if (removexattr(argv[1], test_key) == -1) 52 | // return 6; 53 | 54 | /* link variants */ 55 | 56 | // this should fail as user extended attributes are not allowed on non-regular files 57 | if (lsetxattr(argv[2], test_key, test_val, sizeof(test_val), XATTR_CREATE) != 58 | -1) 59 | return 7; 60 | 61 | // hence the attribute list should be empty 62 | if (lgetxattr(argv[2], test_key, buf, sizeof(test_val)) != -1) 63 | return 8; 64 | 65 | if (llistxattr(argv[2], buf, sizeof buf) != 0) 66 | return 10; 67 | 68 | if (lremovexattr(argv[2], test_key) != -1) 69 | return 12; 70 | 71 | /* file descriptor variants */ 72 | 73 | int fd = open(argv[1], O_RDWR); 74 | 75 | fsetxattr(fd, test_key, test_val, sizeof(test_val), XATTR_CREATE); 76 | // if (fsetxattr(fd, test_key, test_val, sizeof(test_val), XATTR_CREATE) < 0) 77 | // return 13; 78 | 79 | if ((s = fgetxattr(fd, test_key, buf, sizeof(test_val))) < 0) 80 | return 14; 81 | // if (s != sizeof(test_val) || strcmp(buf, test_val)) 82 | // return 15; 83 | 84 | if ((s = flistxattr(fd, buf, sizeof buf)) == -1) 85 | return 16; 86 | // if (s != sizeof(test_key) || strcmp(buf, test_key)) 87 | // return 17; 88 | 89 | fremovexattr(fd, test_key); 90 | // if (fremovexattr(fd, test_key) == -1) 91 | // return 18; 92 | 93 | close(fd); 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /tests/test_sigill.S: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} -nostdlib -nostartfiles %s -o %t1 10 | * RUN: %{sbr} %{sbr-id} -- %t1 11 | */ 12 | 13 | /* The purpose of this test is to ensure that when Varan encounters a non-relocatable instruction 14 | it inserts an illegal instruction that will trigger a SIGILL */ 15 | 16 | .global _start 17 | _start: 18 | mov $39, %rax /* __NR_getpid */ 19 | jmp 1f /* source of jump 1 */ 20 | nop 21 | nop 22 | nop 23 | 1: 24 | not %edi /* destination of jump 1 => non relocatable*/ 25 | syscall /* syscall instruction cannot be rewritten with jump*/ 26 | lea 0(%rip), %rax /* PC-relative addressing => non relocatable */ 27 | jmp 2f /* source of jump 2 */ 28 | nop 29 | nop 30 | nop 31 | 2: 32 | nop /* destination of jump 2 */ 33 | rdtsc /* RDTSC instruction cannot be rewritten with jump*/ 34 | lea 0(%rip), %rax /* PC-relative addressing => non relocatable */ 35 | nop 36 | nop 37 | mov $0, %rdi 38 | mov $60, %rax /* __NR_exit */ 39 | syscall 40 | -------------------------------------------------------------------------------- /tests/vdso/test_rip.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} -masm=intel -fPIC -pie -Wl,--export-dynamic %s -o %t1 10 | * RUN: %{process-vdso} %t1 %t1.processed 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | void *__vdso_time() { 17 | void *ret; 18 | asm volatile("cmp DWORD PTR [rip+0x2],0x42 \n" 19 | "jmp end_time \n" 20 | ".quad 0x1 \n" 21 | "nop \n" 22 | "nop \n" 23 | "nop \n" 24 | "nop \n" 25 | "end_time: nop" 26 | : "=g"(ret)::); 27 | return ret; 28 | } 29 | 30 | void *__vdso_clock_gettime() { 31 | void *ret; 32 | asm volatile("movq %0,[rip+0x2] \n" 33 | "jmp end \n" 34 | ".quad 42 \n" 35 | "nop \n" 36 | "nop \n" 37 | "nop \n" 38 | "nop \n" 39 | "end: nop" 40 | : "=g"(ret)::); 41 | return ret; 42 | } 43 | 44 | int main(int argc, char **argv) { 45 | printf("%ld\n", (const long)__vdso_clock_gettime()); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /tests/vdso/test_vdso_calls.c: -------------------------------------------------------------------------------- 1 | /* Copyright © 2019 Software Reliability Group, Imperial College London 2 | * 3 | * This file is part of SaBRe. 4 | * 5 | * SPDX-License-Identifier: GPL-3.0-or-later 6 | */ 7 | 8 | /* 9 | * RUN: %{cc} -g %s -o %t1 10 | * RUN: %{sbr} %{sbr-trc} --handle-vdso=special -- %t1 &> %t1.actual 11 | * RUN: [ $(grep "(vDSO)" %t1.actual | wc -l) -eq 4 ] 12 | * RUN: [ $(grep "time(0X0)" %t1.actual | wc -l) -eq 2 ] 13 | * RUN: [ $(grep "gettimeofday" %t1.actual | wc -l) -eq 2 ] 14 | * RUN: [ $(grep "clock_gettime" %t1.actual | wc -l) -eq 2 ] 15 | * RUN: [ $(grep "getcpu" %t1.actual | wc -l) -eq 2 ] 16 | */ 17 | 18 | #ifndef _GNU_SOURCE 19 | #define _GNU_SOURCE 20 | #endif 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* Utility functions */ 31 | 32 | /* Tests */ 33 | 34 | static void test_all_vdso() { 35 | struct timespec ts; 36 | assert(clock_gettime(CLOCK_REALTIME, &ts) != -1); 37 | 38 | assert(sched_getcpu() != -1); 39 | 40 | struct timeval tv; 41 | assert(gettimeofday(&tv, NULL) == 0); 42 | 43 | assert(time(NULL) != -1); 44 | } 45 | 46 | static void test_clock_gettime() { 47 | struct timespec t; 48 | assert(syscall(SYS_clock_gettime, CLOCK_REALTIME, &t, NULL) == 0); 49 | } 50 | 51 | static void test_gettimeofday() { 52 | struct timeval t; 53 | assert(syscall(SYS_gettimeofday, &t, NULL, NULL) == 0); 54 | } 55 | 56 | static void test_time() { assert(syscall(SYS_time, NULL, NULL, NULL) != -1); } 57 | 58 | static void test_getcpu() { 59 | int cpu, node; 60 | assert(syscall(SYS_getcpu, &cpu, &node, NULL) == 0); 61 | } 62 | 63 | int main(int argc, char **argv) { 64 | /* Set-up */ 65 | 66 | /* Test */ 67 | test_time(); 68 | test_getcpu(); 69 | test_gettimeofday(); 70 | test_clock_gettime(); 71 | test_all_vdso(); 72 | 73 | /* Tear-down */ 74 | 75 | printf("Success\n"); 76 | 77 | return 0; 78 | } 79 | --------------------------------------------------------------------------------