├── procmon.gif ├── gnu └── stubs.h ├── dist ├── changelog ├── DEBIAN.in │ └── control.in └── SPECS.in │ └── spec.in ├── .github ├── compliance │ └── inventory.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── scorecard.yml ├── tools └── pullsqlite3.sh ├── .devcontainer ├── Dockerfile_Rocky ├── Dockerfile_Ubuntu ├── devcontainer.json ├── install-rocky-dependencies.sh └── install-ubuntu-dependencies.sh ├── CODE_OF_CONDUCT.md ├── .gitignore ├── procmon_template.1 ├── getsyscalls ├── getsyscalls.sh └── getsyscalls.cpp ├── src ├── tracer │ ├── ebpf │ │ ├── kern │ │ │ ├── procmonEBPFkern5.3-5.5.c │ │ │ ├── procmonEBPFkern5.6-.c │ │ │ ├── procmonEBPFkern5.2.c │ │ │ ├── procmonEBPFkern4.17-5.1.c │ │ │ ├── procmonEBPF_maps.h │ │ │ ├── procmonGenericExit_rawtp.c │ │ │ ├── procmonEBPF_common.h │ │ │ └── procmonGenericEntry_rawtp.c │ │ ├── raw_ebpf_event.h │ │ ├── syscall_schema.cpp │ │ ├── ebpf_tracer_engine.h │ │ └── syscall_schema.h │ ├── mock_tracer_engine.h │ ├── mock_tracer_engine.cpp │ └── tracer_engine.h ├── sym │ ├── bcc_perf_map.h │ ├── common.h │ ├── file_desc.h │ ├── bcc_proc.h │ ├── bcc_zip.h │ ├── bcc_perf_map.cpp │ ├── bcc_elf.h │ ├── bcc_syms.h │ └── syms.h ├── storage │ ├── storage_proxy.cpp │ ├── mock_storage_engine.cpp │ ├── storage_proxy.h │ ├── mock_storage_engine.h │ ├── sqlite3_storage_engine.h │ └── storage_engine.h ├── common │ ├── printable.cpp │ ├── printable.h │ ├── cli_utils.h │ ├── telemetry.h │ ├── stack_trace.h │ ├── cli_utils.cpp │ ├── event.h │ └── cancellable_message_queue.h ├── display │ ├── headless.h │ ├── kill_event_formatter.cpp │ ├── screen_configuration.h │ ├── event_formatter.h │ ├── kill_event_formatter.h │ ├── column.h │ ├── headless.cpp │ ├── column.cpp │ ├── event_formatter.cpp │ └── screen.h ├── version.h.in ├── installer.h ├── configuration │ ├── procmon_configuration.h │ └── procmon_configuration.cpp ├── procmon.cpp └── installer.cpp ├── templates └── build.yaml ├── LICENSE ├── cgmanifest.json ├── azure-pipelines.yaml ├── INSTALL.md ├── CONTRIBUTING.md ├── BUILD.md ├── SECURITY.md ├── README.md └── makePackages.sh /procmon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/ProcMon-for-Linux/HEAD/procmon.gif -------------------------------------------------------------------------------- /gnu/stubs.h: -------------------------------------------------------------------------------- 1 | /* dummy .h to trick /usr/include/features.h to work with 'clang --target=bpf' */ -------------------------------------------------------------------------------- /dist/changelog: -------------------------------------------------------------------------------- 1 | * Tue Jul 23 2024 Mario Hewardt - 2.0.0 2 | - Adds new distribution support. -------------------------------------------------------------------------------- /.github/compliance/inventory.yml: -------------------------------------------------------------------------------- 1 | inventory: 2 | - source: DirectOwners 3 | isProduction: false 4 | items: 5 | - id: marioh@microsoft.com 6 | -------------------------------------------------------------------------------- /tools/pullsqlite3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | wget https://www.sqlite.org/2019/sqlite-amalgamation-3270200.zip 4 | unzip sqlite-amalgamation-3270200.zip 5 | mv sqlite-amalgamation-3270200 sqlite3 6 | rm sqlite-amalgamation-3270200.zip 7 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile_Rocky: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/mirror/docker/library/rockylinux:8 2 | 3 | # Install dependencies 4 | COPY install-rocky-dependencies.sh /usr/local/bin/install_dependencies.sh 5 | RUN chmod +x /usr/local/bin/install_dependencies.sh && \ 6 | /usr/local/bin/install_dependencies.sh -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile_Ubuntu: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/mirror/docker/library/ubuntu:20.04 2 | 3 | # To make it easier for build and release pipelines to run apt-get, 4 | # configure apt to not require confirmation (assume the -y argument by default) 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Install dependencies 8 | COPY install-ubuntu-dependencies.sh /usr/local/bin/install_dependencies.sh 9 | RUN chmod +x /usr/local/bin/install_dependencies.sh && \ 10 | /usr/local/bin/install_dependencies.sh -------------------------------------------------------------------------------- /dist/DEBIAN.in/control.in: -------------------------------------------------------------------------------- 1 | Package: procmon 2 | Version: @PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@ 3 | Architecture: amd64 4 | Maintainer: Sysinternals 5 | Description: Sysinternals process monitor utility 6 | Process Monitor (Procmon) is part of the Sysinternals suite of tools. Procmon provides a convenient and efficient way for Linux developers to trace the syscall 7 | activity on the system. 8 | Depends: sysinternalsebpf (>= 1.5.0), libelf1 (>= 0.0) 9 | License: MIT 10 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu 3 | { 4 | "name": "Procmon for Linux Development Container", 5 | "build": { 6 | // If you want to use a different docker file (such as Dockerfile_Rocky) you can specify it here 7 | "dockerfile": "Dockerfile_Ubuntu" 8 | }, 9 | "customizations": { 10 | "vscode": { 11 | "extensions": [ 12 | "ms-vscode.cpptools", 13 | "ms-vscode.cpptools-extension-pack", 14 | "ms-vscode.makefile-tools" 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Logs 35 | *.log 36 | *.db 37 | 38 | # CMake 39 | CMakeLists.txt.user 40 | CMakeCache.txt 41 | CMakeFiles 42 | CMakeScripts 43 | Testing 44 | Makefile 45 | cmake_install.cmake 46 | install_manifest.txt 47 | compile_commands.json 48 | CTestTestfile.cmake 49 | 50 | # build artifacts 51 | bin/ 52 | build/ 53 | obj/ 54 | pkgbuild/ 55 | 56 | # dev env 57 | .vscode/ 58 | -------------------------------------------------------------------------------- /.devcontainer/install-rocky-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # install all needed packges to build .rpm packages 4 | echo "assumeyes=1" >> /etc/yum.conf 5 | 6 | # install endpoint for git > 2.0 7 | yum install http://opensource.wandisco.com/rhel/8/git/x86_64/wandisco-git-release-8-1.noarch.rpm 8 | 9 | # Enable powertools and extra repos 10 | dnf install dnf-plugins-core && dnf install epel-release && dnf config-manager --set-enabled powertools && dnf update 11 | 12 | yum update \ 13 | && yum install \ 14 | gcc \ 15 | gcc-c++ \ 16 | make \ 17 | cmake \ 18 | llvm \ 19 | clang \ 20 | elfutils-libelf-devel \ 21 | rpm-build \ 22 | json-glib-devel \ 23 | python3 \ 24 | libxml2-devel \ 25 | glibc-devel.i686 \ 26 | openssl-devel \ 27 | ncurses-devel 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | --- 11 | name: Bug report 12 | about: Create a report to help us improve 13 | title: '' 14 | labels: '' 15 | assignees: MarioHewardt 16 | 17 | --- 18 | 19 | **Describe the bug** 20 | A clear and concise description of what the bug is. 21 | 22 | **To Reproduce** 23 | Steps to reproduce the behavior. 24 | 25 | **Sysmon version** 26 | Version of Procmon or if built from source. 27 | 28 | **Distro/kernel version** 29 | The distribution and kernel version. 30 | 31 | **Logs** 32 | Output of log with enough log entries to cover the timespan of the issue. 33 | 34 | **Expected behavior** 35 | A clear and concise description of what you expected to happen. 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /procmon_template.1: -------------------------------------------------------------------------------- 1 | .\" Manpage for procmon. 2 | .TH man 8 "@BUILD_DATE@" "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" "procmon manpage" 3 | .SH NAME 4 | procmon \- syscall tracing diagnostics tool 5 | .SH SYNOPSIS 6 | procmon [OPTIONS...] 7 | -h Prints this help screen 8 | -p/--pids Comma separated list of process ids to monitor 9 | -e/--events Comma separated list of system calls to monitor 10 | -c/--collect [FILEPATH] Option to start Procmon in a headless mode 11 | -f/--file FILEPATH Open a Procmon trace file 12 | -l/--log FILEPATH Log debug traces to file 13 | .SH DESCRIPTION 14 | Procmon is a Linux reimagining of the classic Procmon tool from the Sysinternals suite of tools for Windows. Procmon provides a convenient and efficient way for Linux developers to trace the syscall activity on the system. -------------------------------------------------------------------------------- /getsyscalls/getsyscalls.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | VERSION=$1 9 | URL="https://raw.githubusercontent.com/torvalds/linux/v${VERSION}/arch/x86/entry/syscalls/syscall_64.tbl" 10 | INPUT_FILE="syscall_${VERSION}.tbl" 11 | OUTPUT_FILE="../src/tracer/ebpf/syscalls.h" 12 | 13 | # Fetch the file 14 | echo "Fetching syscall table from $URL ..." 15 | wget -q "$URL" -O "$INPUT_FILE" 16 | 17 | # Check if download was successful 18 | if [ $? -ne 0 ]; then 19 | echo "Failed to download file from $URL" 20 | exit 1 21 | fi 22 | 23 | # Run getsyscalls program 24 | echo "Running getsyscalls on $INPUT_FILE and storing output in $OUTPUT_FILE ..." 25 | ./getsyscalls "$INPUT_FILE" "$OUTPUT_FILE" 26 | 27 | # Check if parse_syscalls ran successfully 28 | if [ $? -ne 0 ]; then 29 | echo "Failed to run getsyscalls on $INPUT_FILE" 30 | exit 1 31 | fi 32 | -------------------------------------------------------------------------------- /dist/SPECS.in/spec.in: -------------------------------------------------------------------------------- 1 | Name: procmon 2 | Version: @PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@ 3 | Release: @PROJECT_VERSION_TWEAK@%{?dist} 4 | Summary: Sysinternals process monitor utility 5 | 6 | License: MIT 7 | URL: https://github.com/Sysinternals/Procmon-for-Linux 8 | 9 | %description 10 | Sysinternals process monitor utility 11 | 12 | # Dependencies 13 | Requires: sysinternalsebpf >= 1.5.0 14 | Requires: elfutils-libelf > 0.0 15 | 16 | %install 17 | rm -rf $RPM_BUILD_ROOT 18 | mkdir -p $RPM_BUILD_ROOT/%{_bindir} 19 | cp procmon $RPM_BUILD_ROOT/%{_bindir} 20 | mkdir -p $RPM_BUILD_ROOT/usr/share/man/man1 21 | cp procmon.1.gz $RPM_BUILD_ROOT/usr/share/man/man1 22 | 23 | %clean 24 | rm -rf $RPM_BUILD_ROOT 25 | 26 | %files 27 | %{_bindir}/procmon 28 | /usr/share/man/man1/procmon.1.gz 29 | 30 | %changelog 31 | @CHANGE_LOG@ 32 | 33 | %description 34 | Process Monitor (Procmon) is part of the Sysinternals suite of tools. Procmon provides a convenient and efficient way for Linux developers to trace the syscall 35 | activity on the system. 36 | -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonEBPFkern5.3-5.5.c: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #define FILEPATH_NUMDIRS 32 24 | 25 | #include "procmonGenericEntry_rawtp.c" 26 | #include "procmonGenericExit_rawtp.c" 27 | 28 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonEBPFkern5.6-.c: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #define FILEPATH_NUMDIRS 16 24 | 25 | #include "procmonGenericEntry_rawtp.c" 26 | #include "procmonGenericExit_rawtp.c" 27 | 28 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /templates/build.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: srcPath 3 | type: string 4 | default: '.' 5 | - name: runStaticAnalysis 6 | type: boolean 7 | default: False 8 | - name: builddir 9 | type: string 10 | default: 'build' 11 | 12 | steps: 13 | - script: | 14 | mkdir -p ${{ parameters.srcPath }}/${{ parameters.builddir }} && cd ${{ parameters.srcPath }}/${{ parameters.builddir }} 15 | cmake .. 16 | make 17 | displayName: "Build Procmon binaries" 18 | 19 | - script: | 20 | if [ ${{ parameters.runStaticAnalysis }} == True ]; then 21 | rm -rf ${{ parameters.srcPath }}/${{ parameters.builddir }} && mkdir -p ${{ parameters.srcPath }}/${{ parameters.builddir }} && cd ${{ parameters.srcPath }}/${{ parameters.builddir }} 22 | scan-build cmake .. 23 | scan-build -v --status-bugs -o verifier_result --exclude ../src/logging --exclude ../src/tracer/ebpf --exclude ../src/sym --exclude ../vendor -disable-checker cplusplus.NewDelete,cplusplus.NewDeleteLeaks make 24 | else 25 | echo "Skipping static code analysis." 26 | fi 27 | displayName: "Static analysis of Procmon source code" -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonEBPFkern5.2.c: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #define NOLOOPS 1 24 | 25 | #define FILEPATH_NUMDIRS 13 26 | 27 | #include "procmonGenericEntry_rawtp.c" 28 | #include "procmonGenericExit_rawtp.c" 29 | 30 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonEBPFkern4.17-5.1.c: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #define SUB4096 1 24 | #define NOLOOPS 1 25 | 26 | #define FILEPATH_NUMDIRS 5 27 | 28 | #include "procmonGenericEntry_rawtp.c" 29 | #include "procmonGenericExit_rawtp.c" 30 | 31 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /cgmanifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "Registrations":[ 3 | { 4 | "Component": { 5 | "Type": "git", 6 | "git": { 7 | "RepositoryUrl": "https://github.com/iovisor/bcc.git", 8 | "CommitHash": "ebf0e4b2fd7190e747638f68a4421a8b653bc0a2" 9 | } 10 | }, 11 | "DevelopmentDependency" : true 12 | }, 13 | 14 | { 15 | "Component": { 16 | "Type": "git", 17 | "git": { 18 | "RepositoryUrl": "https://github.com/amrayn/easyloggingpp", 19 | "CommitHash": "163a8e538e4f9878f86d1b4c8887f5135d119d30" 20 | } 21 | }, 22 | "DevelopmentDependency" : true 23 | }, 24 | 25 | { 26 | "Component": { 27 | "Type": "other", 28 | "Other": { 29 | "Name": "sqlite", 30 | "Version": "3.27.2", 31 | "DownloadUrl": "https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gz" 32 | } 33 | }, 34 | "DevelopmentDependency" : true 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /src/sym/bcc_perf_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef LIBBCC_PERF_MAP_H 17 | #define LIBBCC_PERF_MAP_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | // Symbol name, start address, length, payload 28 | typedef int (*bcc_perf_map_symcb)(const char *, uint64_t, uint64_t, void *); 29 | 30 | bool bcc_is_perf_map(const char *path); 31 | bool bcc_is_valid_perf_map(const char *path); 32 | 33 | int bcc_perf_map_nstgid(int pid); 34 | bool bcc_perf_map_path(char *map_path, size_t map_len, int pid); 35 | int bcc_perf_map_foreach_sym(const char *path, bcc_perf_map_symcb callback, 36 | void* payload); 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | #endif 42 | -------------------------------------------------------------------------------- /.devcontainer/install-ubuntu-dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # To make it easier for build and release pipelines to run apt-get, 4 | # configure apt to not require confirmation (assume the -y argument by default) 5 | DEBIAN_FRONTEND=noninteractive 6 | echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes 7 | 8 | sudo apt-get update 9 | sudo apt -y install software-properties-common 10 | sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main" 11 | sudo apt-get update 12 | 13 | sudo apt upgrade -y \ 14 | && sudo apt-get install -y --no-install-recommends \ 15 | build-essential \ 16 | gcc \ 17 | g++ \ 18 | make \ 19 | cmake \ 20 | libelf-dev \ 21 | llvm \ 22 | clang \ 23 | libxml2 \ 24 | libxml2-dev \ 25 | libzstd1 \ 26 | git \ 27 | libgtest-dev \ 28 | apt-transport-https \ 29 | dirmngr \ 30 | libjson-glib-dev \ 31 | libc6-dev-i386 \ 32 | libssl-dev \ 33 | gettext \ 34 | libbpf-dev \ 35 | clang-tools 36 | 37 | sudo wget https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/openat2.h -O /usr/include/linux/openat2.h 38 | 39 | # install debbuild 40 | wget https://github.com/debbuild/debbuild/releases/download/19.5.0/debbuild_19.5.0-ascherer.ubuntu18.04_all.deb \ 41 | && sudo dpkg -i debbuild_19.5.0-ascherer.ubuntu18.04_all.deb 42 | -------------------------------------------------------------------------------- /src/storage/storage_proxy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "storage_proxy.h" 18 | 19 | const std::map StorageProxy::storageEngineTypeMap = 20 | { 21 | { "mock", StorageProxy::StorageEngineType::Mock }, 22 | { "sql", StorageProxy::StorageEngineType::Sql } 23 | }; -------------------------------------------------------------------------------- /src/common/printable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "printable.h" 18 | 19 | const std::string IPrintable::Print() const 20 | { 21 | return typeid(this).name(); 22 | } 23 | 24 | std::ostream& operator<<(std::ostream& stream, const IPrintable& printable) 25 | { 26 | stream << printable.Print(); 27 | return stream; 28 | }; -------------------------------------------------------------------------------- /src/common/printable.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | struct IPrintable 24 | { 25 | public: 26 | virtual const std::string Print() const; 27 | friend std::ostream& operator<<(std::ostream& stream, const IPrintable& printable); 28 | }; -------------------------------------------------------------------------------- /src/sym/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 PLUMgrid, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace ebpf { 25 | 26 | #ifdef __cpp_lib_make_unique 27 | using std::make_unique; 28 | #else 29 | template 30 | typename std::enable_if::value, std::unique_ptr>::type 31 | make_unique(Args &&... args) { 32 | return std::unique_ptr(new T(std::forward(args)...)); 33 | } 34 | #endif 35 | 36 | std::vector get_online_cpus(); 37 | 38 | std::vector get_possible_cpus(); 39 | 40 | std::string get_pid_exe(pid_t pid); 41 | 42 | std::string tracefs_path(); 43 | 44 | std::string tracepoint_format_file(std::string const& category, 45 | std::string const& event); 46 | 47 | std::string parse_tracepoint(std::istream &input, std::string const& category, 48 | std::string const& event); 49 | } // namespace ebpf 50 | -------------------------------------------------------------------------------- /src/tracer/ebpf/raw_ebpf_event.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #define MAX_BUFFER 128 20 | #define MAX_STACK_FRAMES 32 21 | 22 | struct SyscallEvent 23 | { 24 | pid_t pid; 25 | uint32_t sysnum; 26 | uint64_t timestamp; 27 | uint64_t duration_ns; 28 | uint64_t userStack[MAX_STACK_FRAMES]; 29 | uint64_t userStackCount; 30 | uint64_t ret; 31 | char comm[16]; 32 | unsigned char buffer [MAX_BUFFER]; 33 | }; -------------------------------------------------------------------------------- /src/display/headless.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef HEADLESS_H 18 | #define HEADLESS_H 19 | 20 | #include "../configuration/procmon_configuration.h" 21 | 22 | class Headless 23 | { 24 | public: 25 | Headless() { }; 26 | 27 | bool initialize(std::shared_ptr configPtr); 28 | void run(); 29 | void shutdown(); 30 | 31 | private: 32 | // procmon configuration 33 | std::shared_ptr config; 34 | }; 35 | 36 | #endif // HEADLESS_H -------------------------------------------------------------------------------- /src/tracer/mock_tracer_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef MOCK_TRACER_ENGINE_H 18 | #define MOCK_TRACER_ENGINE_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "tracer_engine.h" 26 | #include "../storage/mock_storage_engine.h" 27 | 28 | class MockTracerEngine : public ITracerEngine 29 | { 30 | public: 31 | MockTracerEngine(std::shared_ptr storageEngine, std::vector targetEvents); 32 | }; 33 | 34 | #endif // MOCK_TRACER_ENGINE_H -------------------------------------------------------------------------------- /src/common/cli_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | namespace CLIUtils 23 | { 24 | // An immediate exit with no cleanup/wind-down 25 | void FastExit(); 26 | 27 | // Prints usage string to terminal 28 | void DisplayUsage(bool shouldExit); 29 | 30 | template 31 | void ProtectArgNotNull(T& arg, std::string argName) 32 | { 33 | if (arg == NULL) 34 | { 35 | std::cerr << "ERROR: The argument '" << argName << "' cannot be null." << std::endl << std::endl; 36 | DisplayUsage(true); 37 | } 38 | }; 39 | }; -------------------------------------------------------------------------------- /src/version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon for Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | //==================================================================== 18 | // 19 | // ProcmonVersion.h.in 20 | // 21 | // Version information 22 | // 23 | //==================================================================== 24 | 25 | // 26 | // Version information 27 | // 28 | #define STRFILEVER "@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@" 29 | 30 | // 31 | // File information 32 | // 33 | #define VER_COMPANY "Sysinternals - www.sysinternals.com" 34 | 35 | #define VER_COPYRIGHT "Copyright (C) 2009-2024 Microsoft Corporation. All rights reserved. Licensed under the MIT license.\nMark Russinovich, Mario Hewardt, John Salem, Javid Habibi." -------------------------------------------------------------------------------- /src/sym/file_desc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | namespace ebpf { 22 | 23 | /// FileDesc is a helper class for managing open file descriptors. Copy is 24 | /// disallowed (call dup instead), and cleanup happens automatically. 25 | class FileDesc { 26 | public: 27 | explicit FileDesc(int fd = -1) : fd_(fd) {} 28 | FileDesc(FileDesc &&that) : fd_(-1) { *this = std::move(that); } 29 | FileDesc(const FileDesc &that) = delete; 30 | 31 | ~FileDesc() { 32 | if (fd_ >= 0) 33 | ::close(fd_); 34 | } 35 | 36 | FileDesc &operator=(int fd) { 37 | if (fd_ >= 0) 38 | ::close(fd_); 39 | fd_ = fd; 40 | return *this; 41 | } 42 | FileDesc &operator=(FileDesc &&that) { 43 | if (fd_ >= 0) 44 | ::close(fd_); 45 | fd_ = that.fd_; 46 | that.fd_ = -1; 47 | return *this; 48 | } 49 | FileDesc &operator=(const FileDesc &that) = delete; 50 | 51 | FileDesc dup() const { 52 | if (fd_ >= 0) { 53 | int dup_fd = ::dup(fd_); 54 | return FileDesc(dup_fd); 55 | } else { 56 | return FileDesc(-1); 57 | } 58 | } 59 | 60 | operator int() { return fd_; } 61 | operator int() const { return fd_; } 62 | 63 | private: 64 | int fd_; 65 | }; 66 | 67 | } // namespace ebpf 68 | -------------------------------------------------------------------------------- /azure-pipelines.yaml: -------------------------------------------------------------------------------- 1 | # Azure build pipelines for Procmon-for-Linux 2 | resources: 3 | repositories: 4 | - repository: ProcMon 5 | type: github 6 | endpoint: sysinternals 7 | name: microsoft/ProcMon-for-Linux 8 | 9 | - repository: SysinternalsEBPF 10 | type: github 11 | endpoint: sysinternals 12 | name: microsoft/SysinternalsEBPF 13 | 14 | trigger: 15 | branches: 16 | include: 17 | - release/* 18 | - main 19 | exclude: 20 | - dev/* 21 | - test/* 22 | 23 | pr: 24 | - main 25 | 26 | stages: 27 | - stage: "Build" 28 | jobs: 29 | - job: "Build_Procmon" 30 | pool: 31 | vmImage: "ubuntu-22.04" 32 | timeoutInMinutes: 240 33 | steps: 34 | - checkout: self 35 | - checkout: SysinternalsEBPF 36 | - script: | 37 | clang --version 38 | clang++ --version 39 | gcc --version 40 | displayName: 'List compiler versions' 41 | 42 | - script: | 43 | export LLVM_LIBRARY_DIRS=/usr/lib/llvm-6.0/lib 44 | ls 45 | chmod +x ProcMon-for-Linux/.devcontainer/install-ubuntu-dependencies.sh 46 | ProcMon-for-Linux/.devcontainer/install-ubuntu-dependencies.sh 47 | displayName: "Install pre-reqs for Ubuntu" 48 | 49 | - template: templates/build.yaml@SysinternalsEBPF 50 | parameters: 51 | srcPath: 'SysinternalsEBPF' 52 | runStaticAnalysis: false 53 | builddir: 'sysinternalsEBPF_build' 54 | 55 | - script: | 56 | cd $(Build.SourcesDirectory)/SysinternalsEBPF/sysinternalsEBPF_build 57 | sudo make install 58 | sudo ldconfig 59 | displayName: "Install SysinternalsEBPF" 60 | 61 | - template: templates/build.yaml 62 | parameters: 63 | srcPath: 'ProcMon-for-Linux' 64 | runStaticAnalysis: true 65 | builddir: 'procmon_build' 66 | -------------------------------------------------------------------------------- /src/display/kill_event_formatter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "kill_event_formatter.h" 18 | #include "../logging/easylogging++.h" 19 | 20 | 21 | std::string KillEventFormatter::GetDetails(ITelemetry event) 22 | { 23 | std::string details; 24 | long pid = 0; 25 | long signal = 0; 26 | 27 | // First get the PID 28 | int size = sizeof(long); 29 | memcpy(&pid, event.arguments, size); 30 | 31 | // Next, the signal # 32 | memcpy(&signal, event.arguments+sizeof(long), size); 33 | 34 | if(signal Utils::ArgTypeStringToArgTag = { 21 | {"fd", ProcmonArgTag::FD}, 22 | {"int", ProcmonArgTag::INT}, 23 | {"unsigned int", ProcmonArgTag::UNSIGNED_INT}, 24 | {"size_t", ProcmonArgTag::SIZE_T}, 25 | {"pid_t", ProcmonArgTag::PID_T}, 26 | {"long", ProcmonArgTag::LONG}, 27 | {"unsigned long", ProcmonArgTag::UNSIGNED_LONG}, 28 | {"char *", ProcmonArgTag::CHAR_PTR}, 29 | {"const char *", ProcmonArgTag::CONST_CHAR_PTR}, 30 | {"u32", ProcmonArgTag::UINT32}, 31 | {"unsigned", ProcmonArgTag::UNSIGNED_INT}, 32 | {"umode_t", ProcmonArgTag::INT} 33 | }; 34 | 35 | std::vector Utils::Linux64PointerSycalls = { 36 | "mmap", 37 | "mremap", 38 | "shmat", 39 | "getcwd" 40 | }; 41 | -------------------------------------------------------------------------------- /src/tracer/mock_tracer_engine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "mock_tracer_engine.h" 22 | 23 | MockTracerEngine::MockTracerEngine(std::shared_ptr storageEngine, std::vector targetEvents) : ITracerEngine(storageEngine, targetEvents) 24 | { 25 | std::default_random_engine generator; 26 | std::uniform_real_distribution distribution(100, 9999); 27 | auto dice = std::bind(distribution, generator); 28 | for (size_t i = 0; i < 1000; ++i) 29 | { 30 | int foo = (int)std::ceil(dice()); 31 | std::stringstream ss; 32 | ss << "tel " << foo; 33 | MockTelemetry tel { .pid = foo, .stackTrace = {}, .comm = ss.str(), .processName = ss.str() }; 34 | _storageEngine->Store(tel); 35 | } 36 | 37 | _storageEngine->Store({ .pid = 101, .stackTrace = {}, .comm = "/usr/bin/local/my.exe", .processName = "my.exe" }); 38 | } 39 | -------------------------------------------------------------------------------- /src/installer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | #ifndef PROCMON_INSTALLER_H 17 | #define PROCMON_INSTALLER_H 18 | 19 | #include 20 | #include 21 | 22 | #define PROCMON_EBPF_INSTALL_DIR "/tmp" 23 | 24 | #define KERN_4_16_OBJ "procmonEBPFkern4.16.o" 25 | #define KERN_4_17_5_1_OBJ "procmonEBPFkern4.17-5.1.o" 26 | #define KERN_5_2_OBJ "procmonEBPFkern5.2.o" 27 | #define KERN_5_3_5_5_OBJ "procmonEBPFkern5.3-5.5.o" 28 | #define KERN_5_6__OBJ "procmonEBPFkern5.6-.o" 29 | #define KERN_4_15_CORE_OBJ "procmonEBPFkern4.15_core.o" 30 | #define KERN_4_16_CORE_OBJ "procmonEBPFkern4.16_core.o" 31 | #define KERN_4_17_5_1_CORE_OBJ "procmonEBPFkern4.17-5.1_core.o" 32 | #define KERN_5_2_CORE_OBJ "procmonEBPFkern5.2_core.o" 33 | #define KERN_5_3_5_5_CORE_OBJ "procmonEBPFkern5.3-5.5_core.o" 34 | #define KERN_5_6__CORE_OBJ "procmonEBPFkern5.6-_core.o" 35 | 36 | bool ExtractEBPFPrograms(); 37 | bool DeleteEBPFPrograms(); 38 | 39 | #endif -------------------------------------------------------------------------------- /src/storage/mock_storage_engine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "mock_storage_engine.h" 18 | 19 | 20 | std::vector MockStorageEngine::QueryByPid(pid_t pid, const std::vector& syscalls) 21 | { 22 | std::lock_guard guard(_mapLock); 23 | auto search = _dataStore.find(pid); 24 | return (search != _dataStore.end()) ? search->second : std::vector {}; 25 | } 26 | 27 | bool MockStorageEngine::Store(MockTelemetry data) 28 | { 29 | std::lock_guard guard(_mapLock); 30 | _dataStore[data.pid].push_back(data); 31 | return true; 32 | } 33 | 34 | bool MockStorageEngine::StoreMany(std::vector data) 35 | { 36 | for (auto& datum : data) 37 | { 38 | Store(datum); 39 | } 40 | return true; 41 | } 42 | 43 | std::vector MockStorageEngine::QueryIdsBySearch( 44 | std::string search, std::vector pids, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls) 45 | { 46 | return std::vector(); 47 | } -------------------------------------------------------------------------------- /src/common/telemetry.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef TELEMETRY_BASE_H 18 | #define TELEMETRY_BASE_H 19 | 20 | #include "stack_trace.h" 21 | #include "string.h" 22 | 23 | #define MAX_BUFFER 128 24 | 25 | struct ITelemetry 26 | { 27 | pid_t pid; 28 | StackTrace stackTrace; 29 | std::string comm; 30 | std::string processName; 31 | std::string syscall; 32 | int64_t result; 33 | uint64_t duration; 34 | unsigned char *arguments; 35 | uint64_t timestamp; 36 | 37 | friend bool operator != (ITelemetry a, ITelemetry b) 38 | { 39 | if(a.pid != b.pid) return true; 40 | if(a.stackTrace.Serialize() != b.stackTrace.Serialize()) return true; 41 | if(a.comm != b.comm) return true; 42 | if(a.syscall != b.syscall) return true; 43 | if(a.result != b.result) return true; 44 | if(a.duration != b.duration) return true; 45 | if(strcmp((const char *)a.arguments, (const char *)b.arguments) != 0) return true; 46 | if(a.timestamp != b.timestamp) return true; 47 | 48 | return false; 49 | } 50 | }; 51 | 52 | #endif // TELEMETRY_BASE_H -------------------------------------------------------------------------------- /src/display/screen_configuration.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef SCREEN_CONFIGURATION_H 18 | #define SCREEN_CONFIGURATION_H 19 | 20 | #define MAX_COLUMNS 5 21 | 22 | #include 23 | 24 | #undef OK 25 | #define NCURSES_OK 0 26 | 27 | #include 28 | 29 | class ScreenConfiguration 30 | { 31 | public: 32 | enum sort {time, pid, process, operation, result, duration}; 33 | 34 | ScreenConfiguration() 35 | { 36 | // set default view for UI 37 | columnSort = ScreenConfiguration::time; 38 | columnAscending = true; 39 | } 40 | 41 | void setColumnSort(ScreenConfiguration::sort sort) { columnSort = sort; } 42 | ScreenConfiguration::sort getColumnSort() { return columnSort; } 43 | void toggleColumnAscending() { columnAscending = !columnAscending; } 44 | void setColumnAscending(bool asc) { columnAscending = asc; } 45 | bool getColumnAscending() { return columnAscending; } 46 | 47 | private: 48 | // UI Control Variables 49 | sort columnSort; 50 | bool columnAscending; 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/common/stack_trace.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef STACK_TRACE_H 18 | #define STACK_TRACE_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | struct StackTrace 26 | { 27 | std::vector kernelIPs; 28 | std::vector kernelSymbols; 29 | std::vector userIPs; 30 | std::vector userSymbols; 31 | 32 | StackTrace() {} 33 | 34 | std::string Serialize() 35 | { 36 | std::string ret; 37 | 38 | if(userIPs.size() == 0) 39 | { 40 | return ""; 41 | } 42 | 43 | ret += std::to_string(userIPs[0]); 44 | 45 | for(int i = 1; i < userIPs.size(); i++) 46 | { 47 | ret += ";" + std::to_string(userIPs[i]); 48 | } 49 | return ret; 50 | } 51 | 52 | void Inflate(std::string blob) 53 | { 54 | std::string token; 55 | std::stringstream stream(blob); 56 | 57 | while(std::getline(stream, token, ';')) 58 | { 59 | userIPs.push_back(std::stoull(token)); 60 | } 61 | } 62 | 63 | }; 64 | 65 | #endif // STACK_TRACE_H 66 | -------------------------------------------------------------------------------- /src/tracer/tracer_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef TRACER_ENGINE_H 18 | #define TRACER_ENGINE_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../common/event.h" 25 | #include "../storage/storage_engine.h" 26 | 27 | class ITracerEngine 28 | { 29 | protected: 30 | std::shared_ptr _storageEngine; 31 | std::vector _targetEvents; 32 | int RunState; 33 | 34 | public: 35 | ITracerEngine() {}; 36 | ITracerEngine(std::shared_ptr storageEngine, std::vector targetEvents) : _storageEngine(storageEngine) { _targetEvents = targetEvents; }; 37 | virtual ~ITracerEngine() {}; 38 | 39 | virtual void Initialize() {}; 40 | 41 | virtual void AddEvent(Event eventToTrace) {}; 42 | virtual void AddEvent(std::vector eventsToTrace) {}; 43 | 44 | virtual void AddPids(std::vector pidsToTrace) {}; 45 | 46 | virtual void RemoveEvent(Event eventToRemove) {}; 47 | virtual void RemoveEvent(std::vector eventsToRemove) {}; 48 | virtual void SetRunState(int runState) { RunState = runState; } 49 | virtual int GetRunState() { return RunState; } 50 | virtual void Cancel() {} 51 | }; 52 | 53 | #endif // TRACER_ENGINE_H -------------------------------------------------------------------------------- /src/common/cli_utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "cli_utils.h" 18 | 19 | namespace CLIUtils 20 | { 21 | // An immediate exit with no cleanup/wind-down 22 | void FastExit() 23 | { 24 | // re-enable cursor before exiting Procmon 25 | system("setterm -cursor on"); 26 | 27 | exit(-1); 28 | } 29 | 30 | // Prints usage string to terminal 31 | void DisplayUsage(bool shouldExit) 32 | { 33 | std::cout << "procmon [OPTIONS...]" << std::endl; 34 | std::cout << " OPTIONS" << std::endl; 35 | std::cout << " -h/--help Prints this help screen" << std::endl; 36 | std::cout << " -p/--pids Comma separated list of process ids to monitor" << std::endl; 37 | std::cout << " -e/--events Comma separated list of system calls to monitor" << std::endl; 38 | std::cout << " -c/--collect [FILEPATH] Option to start Procmon in a headless mode" << std::endl; 39 | std::cout << " -f/--file FILEPATH Open a Procmon trace file" << std::endl; 40 | std::cout << " -l/--log FILEPATH Log debug traces to file" << std::endl; 41 | 42 | if (shouldExit) 43 | FastExit(); 44 | } 45 | } -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Install Procmon 2 | 3 | ## Azure Linux 3 4 | ```sh 5 | sudo dnf install procmon 6 | ``` 7 | ## Ubuntu 8 | #### 1. Register Microsoft key and feed 9 | ```sh 10 | wget -q https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 11 | sudo dpkg -i packages-microsoft-prod.deb 12 | ``` 13 | 14 | #### 2. Install Procmon 15 | ```sh 16 | sudo apt-get update 17 | sudo apt-get install procmon 18 | ``` 19 | 20 | ## Debian 21 | #### 1. Register Microsoft key and feed 22 | ```sh 23 | wget -q https://packages.microsoft.com/config/debian/$(. /etc/os-release && echo ${VERSION_ID%%.*})/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 24 | sudo dpkg -i packages-microsoft-prod.deb 25 | ``` 26 | 27 | #### 2. Install Procmon 28 | ```sh 29 | sudo apt-get update 30 | sudo apt-get install procmon 31 | ``` 32 | ## Fedora 33 | #### 1. Register Microsoft key and feed 34 | ```sh 35 | sudo rpm -Uvh https://packages.microsoft.com/config/fedora/$(rpm -E %fedora)/packages-microsoft-prod.rpm 36 | ``` 37 | 38 | #### 2. Install Procmon 39 | ```sh 40 | sudo apt-get update 41 | sudo apt-get install procmon 42 | ``` 43 | 44 | ## RHEL 45 | #### 1. Register Microsoft key and feed 46 | ```sh 47 | sudo rpm -Uvh https://packages.microsoft.com/config/rhel/$(. /etc/os-release && echo ${VERSION_ID%%.*})/packages-microsoft-prod.rpm 48 | ``` 49 | 50 | #### 2. Install Procmon 51 | ```sh 52 | sudo yum install procmon 53 | ``` 54 | 55 | ## openSUSE 15 56 | #### 1. Register Microsoft key and feed 57 | ```sh 58 | sudo zypper install libicu 59 | sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc 60 | wget -q https://packages.microsoft.com/config/opensuse/15/prod.repo 61 | sudo mv prod.repo /etc/zypp/repos.d/microsoft-prod.repo 62 | sudo chown root:root /etc/zypp/repos.d/microsoft-prod.repo 63 | ``` 64 | 65 | #### 2. Install Procmon 66 | ```sh 67 | sudo zypper install procmon 68 | ``` 69 | 70 | ## SLES 12 71 | #### 1. Register Microsoft key and feed 72 | ```sh 73 | sudo rpm -Uvh https://packages.microsoft.com/config/sles/12/packages-microsoft-prod.rpm 74 | ``` 75 | 76 | #### 2. Install Procmon 77 | ```sh 78 | sudo zypper install procmon 79 | ``` 80 | 81 | ## SLES 15 82 | #### 1. Register Microsoft key and feed 83 | ```sh 84 | sudo rpm -Uvh https://packages.microsoft.com/config/sles/15/packages-microsoft-prod.rpm 85 | ``` 86 | 87 | #### 2. Install Procmon 88 | ```sh 89 | sudo zypper install procmon 90 | ``` 91 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Before we can accept a pull request from you, you'll need to sign a [Contributor License Agreement (CLA)](https://cla.microsoft.com). It is an automated process and you only need to do it once. 4 | To enable us to quickly review and accept your pull requests, always create one pull request per issue and link the issue in the pull request. Never merge multiple requests in one unless they have the same root cause. Be sure to follow our Coding Guidelines and keep code changes as small as possible. Avoid pure formatting changes to code that has not been modified otherwise. Pull requests should contain tests whenever possible. 5 | 6 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 7 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 8 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 9 | 10 | # Branching 11 | The main branch contains current development. While CI should ensure that main always builds, it is still considered pre-release code. Release checkpoints will be put into stable branches for maintenance. 12 | 13 | To contribute, fork the repository and create a branch in your fork for your work. Please keep branch names short and descriptive. Please direct PRs into the upstream main branch. 14 | 15 | ## Build and run from source 16 | ### Environment 17 | * `Linux` OS (dev team is using Ubuntu 18.04) 18 | * Development can be done on Windows Subsystem for Linux, but Procmon cannot be executed in that environment 19 | * `git` 20 | * `cmake` >= 3.14 21 | * `libsqlite3-dev` >= 3.22 22 | 23 | ```bash 24 | sudo apt-get -y install bison build-essential flex git libedit-dev \ 25 | libllvm6.0 llvm-6.0-dev libclang-6.0-dev python zlib1g-dev libelf-dev 26 | ``` 27 | 28 | ##### 1. Build BCC 29 | ```bash 30 | git clone --branch tag_v0.10.0 https://github.com/iovisor/bcc.git 31 | mkdir bcc/build 32 | cd bcc/build 33 | cmake .. -DCMAKE_INSTALL_PREFIX=/usr 34 | make 35 | sudo make install 36 | ``` 37 | 38 | ##### 2. Build Procmon 39 | ```bash 40 | git clone https://github.com/microsoft/Procmon-for-Linux 41 | cd procmon-for-linux 42 | mkdir build 43 | cd build 44 | cmake .. 45 | make 46 | ``` 47 | 48 | ## Pull Requests 49 | * Always tag a work item or issue with a pull request. 50 | * Limit pull requests to as few issues as possible, preferably 1 per PR 51 | 52 | -------------------------------------------------------------------------------- /src/common/event.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | #include "printable.h" 23 | #include "cli_utils.h" 24 | 25 | class Event : public IPrintable 26 | { 27 | public: 28 | Event(std::string eventName) 29 | { 30 | if (!IsValid(eventName)) 31 | { 32 | // TODO error handling 33 | std::cerr << "Event::\"" << eventName << "\" is an invalid trace event" << std::endl; 34 | 35 | // re-enable cursor before exiting Procmon 36 | system("setterm -cursor on"); 37 | 38 | // TODO: something better? 39 | exit(-1); 40 | } 41 | _name = eventName; 42 | } 43 | 44 | const std::string Name() const { return _name; } 45 | 46 | static bool IsValid(std::string event) 47 | { 48 | // TODO 49 | return true; 50 | } 51 | 52 | static bool IsValid(Event event) 53 | { 54 | // TODO 55 | return IsValid(event.Name()); 56 | } 57 | 58 | const std::string Print() const override { return _name; } 59 | 60 | bool operator <(const Event& e) 61 | { 62 | if(_name < e.Name()) 63 | return true; 64 | 65 | return false; 66 | } 67 | 68 | private: 69 | std::string _name; 70 | }; -------------------------------------------------------------------------------- /src/sym/bcc_proc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 GitHub, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef LIBBCC_PROC_H 17 | #define LIBBCC_PROC_H 18 | 19 | #include "bcc_syms.h" 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | 30 | typedef struct mod_info { 31 | char *name; 32 | uint64_t start_addr; 33 | uint64_t end_addr; 34 | long long unsigned int file_offset; 35 | uint64_t dev_major; 36 | uint64_t dev_minor; 37 | uint64_t inode; 38 | } mod_info; 39 | 40 | // Module info, whether to check mount namespace, payload 41 | // Callback returning a negative value indicates to stop the iteration 42 | typedef int (*bcc_procutils_modulecb)(mod_info *, int, void *); 43 | 44 | // Symbol name, address, payload 45 | typedef void (*bcc_procutils_ksymcb)(const char *, const char *, uint64_t, void *); 46 | 47 | char *bcc_procutils_which_so(const char *libname, int pid); 48 | char *bcc_procutils_which(const char *binpath); 49 | int bcc_mapping_is_file_backed(const char *mapname); 50 | // Iterate over all executable memory mapping sections of a Process. 51 | // All anonymous and non-file-backed mapping sections, namely those 52 | // listed in bcc_mapping_is_file_backed, will be ignored. 53 | // Returns -1 on error, and 0 on success 54 | int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback, 55 | void *payload); 56 | 57 | int _procfs_maps_each_module(FILE *procmaps, int pid, 58 | bcc_procutils_modulecb callback, void *payload); 59 | // Iterate over all non-data Kernel symbols. 60 | // Returns -1 on error, and 0 on success 61 | int bcc_procutils_each_ksym(bcc_procutils_ksymcb callback, void *payload); 62 | void bcc_procutils_free(const char *ptr); 63 | const char *bcc_procutils_language(int pid); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | #endif 69 | -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonEBPF_maps.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef PROCMON_EBPF_MAPS_H 24 | #define PROCMON_EBPF_MAPS_H 25 | 26 | #include "procmonEBPF_common.h" 27 | 28 | // create a map to hold the event as we build it - too big for stack 29 | // one entry per cpu 30 | struct { 31 | __uint(type, BPF_MAP_TYPE_ARRAY); 32 | __type(key, uint32_t); 33 | __type(value, struct SyscallEvent); 34 | __uint(max_entries, MAX_PROC); 35 | } eventStorageMap SEC(".maps"); 36 | 37 | // create a map to hold the syscall information 38 | struct { 39 | __uint(type, BPF_MAP_TYPE_HASH); 40 | __uint(max_entries, 10240); 41 | __type(key, uint64_t); 42 | __type(value, struct SyscallEvent); 43 | } syscallsMap SEC(".maps"); 44 | 45 | // Procmon config 46 | struct { 47 | __uint(type, BPF_MAP_TYPE_ARRAY); 48 | __type(key, uint32_t); 49 | __type(value, uint64_t); 50 | __uint(max_entries, CONFIG_ITEMS); 51 | } configuration SEC(".maps"); 52 | 53 | // Procmon PIDS 54 | struct { 55 | __uint(type, BPF_MAP_TYPE_ARRAY); 56 | __type(key, uint32_t); 57 | __type(value, int); 58 | __uint(max_entries, MAX_PIDS); 59 | } pids SEC(".maps"); 60 | 61 | // Procmon runstate 62 | struct { 63 | __uint(type, BPF_MAP_TYPE_ARRAY); 64 | __type(key, uint32_t); 65 | __type(value, uint64_t); 66 | __uint(max_entries, 1); 67 | } runstate SEC(".maps"); 68 | 69 | // Procmon syscalls 70 | struct { 71 | __uint(type, BPF_MAP_TYPE_HASH); 72 | __type(key, uint32_t); 73 | __type(value, struct SyscallSchema); 74 | __uint(max_entries, 1000); 75 | } syscalls SEC(".maps"); 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/display/event_formatter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef EVENT_FORMATTER_H 18 | #define EVENT_FORMATTER_H 19 | 20 | #include 21 | 22 | #include "../common/telemetry.h" 23 | #include "../common/event.h" 24 | #include "../display/screen_configuration.h" 25 | #include "../configuration/procmon_configuration.h" 26 | 27 | class EventFormatter 28 | { 29 | 30 | protected: 31 | std::string syscall; 32 | ProcmonConfiguration* config; 33 | 34 | std::string CalculateDeltaTimestamp(uint64_t ebpfEventTimestamp); 35 | int FindSyscall(std::string& syscallName); 36 | std::string DecodeArguments(ITelemetry &event); 37 | 38 | public: 39 | EventFormatter(){}; 40 | virtual ~EventFormatter(){}; 41 | 42 | void Initialize(const std::string &syscall, ProcmonConfiguration* config) { this->syscall = syscall; this->config = config; } 43 | 44 | std::string& GetSyscall() { return syscall; } 45 | 46 | virtual std::string GetTimestamp(ITelemetry &event); 47 | virtual std::string GetPID(ITelemetry &event); 48 | virtual std::string GetProcess(ITelemetry &event); 49 | virtual std::string GetOperation(ITelemetry &event); 50 | virtual std::string GetResult(ITelemetry &event); 51 | virtual std::string GetDuration(ITelemetry &event); 52 | virtual std::string GetDetails(ITelemetry &event); 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonGenericExit_rawtp.c: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "procmonEBPF_common.h" 24 | #include 25 | #include "procmonEBPF_maps.h" 26 | 27 | // ------------------------------------------------------------------------------------------ 28 | // genericRawExit 29 | // 30 | // Called during a syscall exit 31 | // ------------------------------------------------------------------------------------------ 32 | SEC("raw_tracepoint/sys_exit") 33 | __attribute__((flatten)) 34 | int genericRawExit(struct bpf_our_raw_tracepoint_args *ctx) 35 | { 36 | uint64_t pidTid = bpf_get_current_pid_tgid(); 37 | const struct pt_regs *regs = (const struct pt_regs *)ctx->args[0]; 38 | int pid = pidTid >> 32; 39 | 40 | // 41 | // Check all filters 42 | // 43 | if(CheckFilters(pid) == 0) 44 | { 45 | return EBPF_RET_UNUSED; 46 | } 47 | 48 | 49 | // 50 | // Look up the corresponding event 51 | // 52 | struct SyscallEvent* event = (struct SyscallEvent*) bpf_map_lookup_elem(&syscallsMap, &pidTid); 53 | if (event == NULL) 54 | { 55 | return EBPF_RET_UNUSED; 56 | } 57 | 58 | // 59 | // Update event fields 60 | // 61 | event->duration_ns = bpf_ktime_get_ns() - event->timestamp; 62 | 63 | if (bpf_probe_read(&event->ret, sizeof(int64_t), (void *)&SYSCALL_PT_REGS_RC(regs)) != 0) 64 | { 65 | BPF_PRINTK("[genericRawExit] Failed to get return code\n"); 66 | return EBPF_RET_UNUSED; 67 | } 68 | 69 | // 70 | // Send event 71 | // 72 | eventOutput((void*)ctx, &eventMap, BPF_F_CURRENT_CPU, event, sizeof(struct SyscallEvent)); 73 | 74 | bpf_map_delete_elem(&syscallsMap, &pidTid); 75 | 76 | return EBPF_RET_UNUSED; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/display/kill_event_formatter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef KILL_EVENT_FORMATTER_H 18 | #define KILL_EVENT_FORMATTER_H 19 | 20 | #include 21 | 22 | #include "../common/telemetry.h" 23 | #include "../common/event.h" 24 | #include "event_formatter.h" 25 | 26 | class KillEventFormatter : public EventFormatter 27 | { 28 | 29 | protected: 30 | std::map signalmap = { 31 | {0, "CHECKPERM"}, 32 | {1, "SIGHUP"}, 33 | {2, "SIGINT"}, 34 | {3, "SIGQUIT"}, 35 | {4, "SIGILL"}, 36 | {5, "SIGTRAP"}, 37 | {6, "SIGABRT"}, 38 | {7, "SIGBUS"}, 39 | {8, "SIGFPE"}, 40 | {9, "SIGKILL"}, 41 | {10, "SIGUSR1"}, 42 | {11, "SIGSEGV"}, 43 | {12, "SIGUSR2"}, 44 | {13, "SIGPIPE"}, 45 | {14, "SIGALRM"}, 46 | {15, "SIGTERM"}, 47 | {16, "SIGSTKFLT"}, 48 | {17, "SIGCHLD"}, 49 | {18, "SIGCONT"}, 50 | {19, "SIGSTOP"}, 51 | {20, "SIGTSTP"}, 52 | {21, "SIGTTIN"}, 53 | {22, "SIGTTOU"}, 54 | {23, "SIGURG"}, 55 | {24, "SIGXCPU"}, 56 | {25, "SIGXFSZ"}, 57 | {26, "SIGVTALRM"}, 58 | {27, "SIGPROF"}, 59 | {28, "SIGWINCH"}, 60 | {29, "SIGIO"}, 61 | {30, "SIGPWR"}, 62 | {31, "SIGSYS"} 63 | }; 64 | 65 | public: 66 | KillEventFormatter() {}; 67 | ~KillEventFormatter(){}; 68 | 69 | std::string GetDetails(ITelemetry event); 70 | void Initialize(const std::string syscall, ProcmonConfiguration* config) { EventFormatter::Initialize(syscall, config); } 71 | }; 72 | 73 | #endif -------------------------------------------------------------------------------- /src/sym/bcc_zip.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef LIBBCC_ZIP_H 18 | #define LIBBCC_ZIP_H 19 | 20 | #include 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | // Represents an opened zip archive. 27 | // Only basic ZIP files are supported, in particular the following are not 28 | // supported: 29 | // - encryption 30 | // - streaming 31 | // - multi-part ZIP files 32 | // - ZIP64 33 | struct bcc_zip_archive; 34 | 35 | // Carries information on name, compression method and data corresponding to 36 | // a file in a zip archive. 37 | struct bcc_zip_entry { 38 | // Compression method as defined in pkzip spec. 0 means data is uncompressed. 39 | uint16_t compression; 40 | 41 | // Non-null terminated name of the file. 42 | const char* name; 43 | // Length of the file name. 44 | uint16_t name_length; 45 | 46 | // Pointer to the file data. 47 | const void* data; 48 | // Length of the file data. 49 | uint32_t data_length; 50 | // Offset of the file data within the archive. 51 | uint32_t data_offset; 52 | }; 53 | 54 | // Opens a zip archive. Returns NULL in case of an error. 55 | struct bcc_zip_archive* bcc_zip_archive_open(const char* path); 56 | 57 | // Closes a zip archive and releases resources. 58 | void bcc_zip_archive_close(struct bcc_zip_archive* archive); 59 | 60 | // Looks up data corresponding to a file in given zip archive. 61 | int bcc_zip_archive_find_entry(struct bcc_zip_archive* archive, 62 | const char* name, struct bcc_zip_entry* out); 63 | 64 | int bcc_zip_archive_find_entry_at_offset(struct bcc_zip_archive* archive, 65 | uint32_t offset, 66 | struct bcc_zip_entry* out); 67 | 68 | // Opens a zip archives and looks up entry within the archive. 69 | // Provided path is interpreted as archive path followed by "!/" 70 | // characters and name of the zip entry. This convention is used 71 | // by Android tools. 72 | struct bcc_zip_archive* bcc_zip_archive_open_and_find( 73 | const char* path, struct bcc_zip_entry* out); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | #endif 79 | -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonEBPF_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifndef PROCMON_EBPF_COMMON_H 24 | #define PROCMON_EBPF_COMMON_H 25 | 26 | #define PROCMON_EBPF 27 | 28 | #define PACKET_SIZE 128 29 | #define UDP_HASH_SIZE (128 * 1024) 30 | 31 | 32 | #define LINUX_MAX_EVENT_SIZE (65536 - 24) 33 | 34 | #define MAX_BUFFER 128 35 | #define MAX_STACK_FRAMES 32 36 | #define MAX_PROC 512 37 | 38 | #define CONFIG_ITEMS 1 39 | #define MAX_PIDS 10 40 | 41 | #define TRACER_RUNNING 0 42 | #define TRACER_SUSPENDED 1 43 | #define TRACER_STOP 2 44 | 45 | #define RUNSTATE_KEY 0 46 | #define CONFIG_PID_KEY 0 47 | 48 | #define CONFIG_INDEX 0 49 | #define PIDS_INDEX 1 50 | #define RUNSTATE_INDEX 2 51 | #define SYSCALL_INDEX 3 52 | 53 | #define EBPF_RET_UNUSED 0 54 | 55 | struct SyscallEvent 56 | { 57 | pid_t pid; 58 | uint32_t sysnum; 59 | uint64_t timestamp; 60 | uint64_t duration_ns; 61 | uint64_t userStack[MAX_STACK_FRAMES]; 62 | uint64_t userStackCount; 63 | uint64_t ret; 64 | char comm[16]; 65 | unsigned char buffer [MAX_BUFFER]; 66 | }; 67 | 68 | enum ProcmonArgTag 69 | { 70 | NOTKNOWN, // Catch all for cases where arg type isn't known yet. 71 | INT, 72 | UNSIGNED_INT, 73 | SIZE_T, 74 | PID_T, 75 | LONG, 76 | UNSIGNED_LONG, 77 | CHAR_PTR, 78 | CONST_CHAR_PTR, 79 | FD, 80 | PTR, 81 | UINT32 82 | }; 83 | 84 | struct SyscallSchema 85 | { 86 | // We should probably just be passing the syscall number back and forth instead. 87 | char syscallName[100]; 88 | // It's probably not necessary to pass this info to kernel land and we can just store 89 | // it in an userland only map to be used by the UI. 90 | char argNames[6][100]; 91 | // The key data structure necessary to infer what needs to be done. 92 | enum ProcmonArgTag types[6]; 93 | int usedArgCount; 94 | }; 95 | #endif 96 | -------------------------------------------------------------------------------- /BUILD.md: -------------------------------------------------------------------------------- 1 | # Build 2 | Please see the history of this file for instructions for older, unsupported versions. 3 | 4 | ## Prerequisites 5 | - SysinternalsEBPF being installed: 6 | library `libsysinternalsEBPF.so`, header `libsysinternalsEBPF.h`, plus 7 | resource files in `/opt/sysinternalsEBPF`. These can be installed from 8 | the 9 | [SysinternalsEBPF](https://github.com/Sysinternals/SysinternalsEBPF) 10 | project or via the `sysinternalsebpf` DEB package from the 11 | _packages.microsoft.com_ repository (see [INSTALL.md](INSTALL.md)). 12 | If you installed SysinternalsEBPF via make install, you may need to add /usr/local/lib to the loader library path (LD_LIBRARY_PATH). 13 | 14 | - clang/llvm v10+ 15 | 16 | ### Azure Linux 17 | ``` 18 | sudo dnf update 19 | sudo dnf install gcc gcc-c++ make cmake llvm clang elfutils-libelf-devel rpm-build json-glib-devel python3 libxml2-devel openssl-devel ncurses-devel 20 | ``` 21 | 22 | ### Ubuntu 20.04+ 23 | ``` 24 | sudo apt update 25 | sudo apt -y install build-essential gcc g++ make cmake libelf-dev llvm clang libxml2 libxml2-dev libzstd1 git libgtest-dev apt-transport-https dirmngr libjson-glib-dev libssl-dev 26 | ``` 27 | 28 | ### Rocky 9 29 | ``` 30 | sudo dnf install dnf-plugins-core 31 | sudo dnf config-manager --set-enabled crb 32 | sudo dnf install epel-release 33 | 34 | sudo dnf update 35 | sudo yum install gcc gcc-c++ make cmake llvm clang elfutils-libelf-devel rpm-build json-glib-devel python3 libxml2-devel openssl-devel ncurses-devel 36 | ``` 37 | 38 | ### Rocky 8 39 | ``` 40 | sudo dnf install dnf-plugins-core 41 | sudo dnf install epel-release 42 | sudo dnf config-manager --set-enabled powertools 43 | 44 | sudo dnf update 45 | sudo yum install gcc gcc-c++ make cmake llvm clang elfutils-libelf-devel rpm-build json-glib-devel python3 libxml2-devel openssl-devel ncurses-devel 46 | ``` 47 | 48 | ### Debian 11 49 | ``` 50 | wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 51 | sudo dpkg -i packages-microsoft-prod.deb 52 | rm packages-microsoft-prod.deb 53 | sudo apt update 54 | sudo apt -y install build-essential gcc g++ make cmake libelf-dev llvm clang libzstd1 git libjson-glib-dev libxml2 libxml2-dev libssl-dev 55 | ``` 56 | 57 | ## Build 58 | ``` 59 | cd 60 | git clone https://github.com/Sysinternals/ProcMon-for-Linux.git 61 | cd ProcMon-for-Linux 62 | mkdir build 63 | cd build 64 | cmake .. 65 | make 66 | ``` 67 | 68 | ## Run 69 | ``` 70 | sudo ./procmon 71 | ``` 72 | 73 | ## Make Packages 74 | Packages can be generated with: 75 | ``` 76 | make deb 77 | ``` 78 | or 79 | ``` 80 | make rpm 81 | ``` 82 | 83 | The directories build/deb and build/rpm will be populated with the required 84 | files. If dpkg-deb is available, the build/deb directory will be used to create 85 | a deb package. Similarly if rpmbuild is available, the build/rpm directory will 86 | be used to create an rpm package. 87 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /src/display/column.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef COLUMN_H 18 | #define COLUMN_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "../logging/easylogging++.h" 26 | 27 | #define COLUMN_PADDING 2 28 | 29 | class Column { 30 | public: 31 | Column(int height, int width, int y, int x, std::string columnName); 32 | ~Column(); 33 | 34 | // column property access functions 35 | int getX() { return x; } 36 | int getY() { return y; } 37 | int getWidth() { return width; } 38 | int getHeight() { return height; } 39 | std::string getColumnName() { return columnName; } 40 | std::vector getColumnData() { return columnData; } 41 | 42 | // helper functions 43 | void addLine(std::string value); 44 | int resize(int height, int width, int x); 45 | void setLineColor(int y, int cursesColorPair); 46 | void toggleHeaderHighlight(); 47 | void moveColumn(int x); 48 | 49 | // screen column functions 50 | void setBackground(int cursesColor); 51 | void refreshColumn(); 52 | void resetColumn(); 53 | void clearColumn(); 54 | void redrawColumn(); 55 | void hideColumn(); 56 | void showColumn(); 57 | 58 | private: 59 | int height; 60 | int width; 61 | int x; 62 | int y; 63 | int currentLine; 64 | bool highlight; 65 | WINDOW* win; 66 | PANEL* panel; 67 | 68 | std::string columnName; 69 | std::vector columnData; 70 | 71 | void columnPrintFill(int colorPair, int x, int y, const char * fmt, ...); 72 | }; 73 | 74 | #endif // SCREEN_H -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Process Monitor for Linux (Preview) [![Build Status](https://dev.azure.com/sysinternals/Tools/_apis/build/status/Sysinternals.ProcMon-for-Linux?repoName=Sysinternals%2FProcMon-for-Linux&branchName=main)](https://dev.azure.com/sysinternals/Tools/_build/latest?definitionId=342&repoName=Sysinternals%2FProcMon-for-Linux&branchName=main) 2 | Process Monitor (Procmon) is a Linux reimagining of the classic Procmon tool from the Sysinternals suite of tools for Windows. Procmon provides a convenient and efficient way for Linux developers to trace the syscall activity on the system. 3 | 4 | ![Procmon in use](procmon.gif "Procmon in use") 5 | 6 | # Installation & Usage 7 | 8 | ## Requirements 9 | 10 | * OS: Ubuntu 18.04 lts 11 | * `cmake` >= 3.14 (build-time only) 12 | * `libsqlite3-dev` >= 3.22 (build-time only) 13 | 14 | ## Install Procmon 15 | 16 | Please see installation instructions [here](INSTALL.md). 17 | 18 | ## Build Procmon 19 | Please see build instructions [here](BUILD.md). 20 | 21 | ## Usage 22 | ```txt 23 | Usage: procmon [OPTIONS] 24 | OPTIONS 25 | -h/--help Prints this help screen 26 | -p/--pids Comma separated list of process IDs to monitor 27 | -e/--events Comma separated list of system calls to monitor 28 | -c/--collect [FILEPATH] Option to start Procmon in a headless mode 29 | -f/--file FILEPATH Open a Procmon trace file 30 | -l/--log FILEPATH Log debug traces to file 31 | ``` 32 | 33 | ### Examples 34 | 35 | The following traces all processes and syscalls on the system: 36 | 37 | ```sh 38 | sudo procmon 39 | ``` 40 | 41 | The following traces processes with process id 10 and 20: 42 | 43 | ```sh 44 | sudo procmon -p 10,20 45 | ``` 46 | 47 | The following traces process 20 only syscalls read, write and open at: 48 | 49 | ```sh 50 | sudo procmon -p 20 -e read,write,openat 51 | ``` 52 | 53 | The following traces process 35 and opens Procmon in headless mode to output all captured events to file `procmon.db`: 54 | 55 | ```sh 56 | sudo procmon -p 35 -c procmon.db 57 | ``` 58 | 59 | The following opens a Procmon `tracefile`, `procmon.db`, within the Procmon TUI: 60 | 61 | ```sh 62 | sudo procmon -f procmon.db 63 | ``` 64 | 65 | # Feedback 66 | 67 | * Ask a question on Stack Overflow (tag with ProcmonForLinux) 68 | * Request a new feature on GitHub 69 | * Vote for popular feature requests 70 | * File a bug in GitHub Issues 71 | 72 | # Contributing 73 | 74 | If you are interested in fixing issues and contributing directly to the code base, please see the [document How to Contribute](CONTRIBUTING.md), which covers the following: 75 | 76 | * How to build and run from the source 77 | * The development workflow, including debugging and running tests 78 | * Coding Guidelines 79 | * Submitting pull requests 80 | 81 | Please see also our [Code of Conduct](CODE_OF_CONDUCT.md). 82 | 83 | # License 84 | 85 | Copyright (c) Microsoft Corporation. All rights reserved. 86 | 87 | Licensed under the MIT License. 88 | -------------------------------------------------------------------------------- /src/storage/storage_proxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "storage_engine.h" 24 | #include "mock_storage_engine.h" 25 | #include "sqlite3_storage_engine.h" 26 | 27 | class StorageProxy 28 | { 29 | public: 30 | // Add new storage types here 31 | enum StorageEngineType 32 | { 33 | Mock, 34 | Sql 35 | }; 36 | 37 | static const std::map storageEngineTypeMap; 38 | 39 | static bool IsValidStorageEngineType(std::string type) 40 | { 41 | std::transform(type.begin(), type.end(), type.begin(), [](unsigned char c) { return std::tolower(c); }); 42 | auto foundType = storageEngineTypeMap.find(type); 43 | return foundType != storageEngineTypeMap.end(); 44 | }; 45 | 46 | static IStorageEngine *StorageFactory(StorageEngineType type) 47 | { 48 | switch (type) 49 | { 50 | case StorageEngineType::Mock: 51 | return new MockStorageEngine(); 52 | 53 | case StorageEngineType::Sql: 54 | return new Sqlite3StorageEngine(); 55 | default: 56 | return new MockStorageEngine(); 57 | } 58 | }; 59 | 60 | static IStorageEngine *StorageFactory(std::string type) 61 | { 62 | StorageEngineType foundType = GetStorageTypeForString(type); 63 | return StorageFactory(foundType); 64 | }; 65 | 66 | static StorageEngineType GetStorageTypeForString(std::string type) 67 | { 68 | std::transform(type.begin(), type.end(), type.begin(), [](unsigned char c) { return std::tolower(c); }); 69 | auto foundType = storageEngineTypeMap.find(type); 70 | if (foundType == storageEngineTypeMap.end()) return StorageEngineType::Mock; 71 | 72 | return foundType->second; 73 | }; 74 | }; -------------------------------------------------------------------------------- /getsyscalls/getsyscalls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Define a structure to hold the syscall information 7 | struct SyscallInfo { 8 | int number; 9 | std::string category; 10 | std::string name; 11 | std::string entrypoint; 12 | }; 13 | 14 | // Function to parse a line and fill a SyscallInfo structure 15 | bool parseLine(const std::string& line, SyscallInfo& info) 16 | { 17 | // Ignore lines starting with # 18 | if (line.empty() || line[0] == '#') 19 | { 20 | return false; 21 | } 22 | 23 | std::istringstream stream(line); 24 | if (!(stream >> info.number >> info.category >> info.name >> info.entrypoint)) 25 | { 26 | return false; // Parsing failed 27 | } 28 | 29 | // Check if any number is between 512 and 547 30 | if (info.number >= 512 && info.number <= 547) 31 | { 32 | return false; // Skip this line 33 | } 34 | 35 | return true; // Parsing succeeded 36 | } 37 | 38 | // Function to read syscalls from a file and store them in a vector 39 | std::vector readSyscalls(const std::string& filename) 40 | { 41 | std::vector syscalls; 42 | std::ifstream infile(filename); 43 | std::string line; 44 | 45 | while (std::getline(infile, line)) 46 | { 47 | SyscallInfo info; 48 | if (parseLine(line, info)) 49 | { 50 | syscalls.push_back(info); 51 | } 52 | } 53 | 54 | return syscalls; 55 | } 56 | 57 | // Function to write syscalls to a header file 58 | void writeSyscalls(const std::string& filename, const std::vector& syscalls) 59 | { 60 | std::ofstream outfile(filename); 61 | 62 | outfile << "// AUTO GENERATED BY getsyscalls\n"; 63 | outfile << "#ifndef SYSCALL_H\n"; 64 | outfile << "#define SYSCALL_H\n\n"; 65 | outfile << "struct SyscallInfo {\n"; 66 | outfile << " int number;\n"; 67 | outfile << " std::string category;\n"; 68 | outfile << " std::string name;\n"; 69 | outfile << " std::string entrypoint;\n"; 70 | outfile << "};\n\n"; 71 | 72 | outfile << "const std::vector syscalls = {\n"; 73 | for (const auto& info : syscalls) 74 | { 75 | outfile << " {" << info.number << ", \"" << info.category << "\", \"" << info.name << "\", \"" << info.entrypoint << "\"},\n"; 76 | } 77 | outfile << "};\n\n"; 78 | 79 | outfile << "#endif // SYSCALL_H\n"; 80 | } 81 | 82 | int main(int argc, char* argv[]) 83 | { 84 | if (argc != 3) 85 | { 86 | std::cerr << "Usage: " << argv[0] << " \n"; 87 | return 1; 88 | } 89 | 90 | const std::string inputFilename = argv[1]; 91 | const std::string outputFilename = argv[2]; 92 | 93 | // Read syscalls from input file 94 | std::vector syscalls = readSyscalls(inputFilename); 95 | 96 | // Write syscalls to output header file 97 | writeSyscalls(outputFilename, syscalls); 98 | 99 | std::cout << "Syscalls have been parsed and written to " << outputFilename << std::endl; 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | - cron: '40 8 * * 0' 14 | push: 15 | branches: [ "main" ] 16 | 17 | # Declare default permissions as read only. 18 | permissions: read-all 19 | 20 | jobs: 21 | analysis: 22 | name: Scorecard analysis 23 | runs-on: ubuntu-latest 24 | permissions: 25 | # Needed to upload the results to code-scanning dashboard. 26 | security-events: write 27 | # Needed to publish results and get a badge (see publish_results below). 28 | id-token: write 29 | # Uncomment the permissions below if installing in a private repository. 30 | # contents: read 31 | # actions: read 32 | 33 | steps: 34 | - name: "Checkout code" 35 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 36 | with: 37 | persist-credentials: false 38 | 39 | - name: "Run analysis" 40 | uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 41 | with: 42 | results_file: results.sarif 43 | results_format: sarif 44 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 45 | # - you want to enable the Branch-Protection check on a *public* repository, or 46 | # - you are installing Scorecard on a *private* repository 47 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional. 48 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 49 | 50 | # Public repositories: 51 | # - Publish results to OpenSSF REST API for easy access by consumers 52 | # - Allows the repository to include the Scorecard badge. 53 | # - See https://github.com/ossf/scorecard-action#publishing-results. 54 | # For private repositories: 55 | # - `publish_results` will always be set to `false`, regardless 56 | # of the value entered here. 57 | publish_results: true 58 | 59 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 60 | # format to the repository Actions tab. 61 | - name: "Upload artifact" 62 | uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20 63 | with: 64 | name: SARIF file 65 | path: results.sarif 66 | retention-days: 5 67 | 68 | # Upload the results to GitHub's code scanning dashboard (optional). 69 | # Commenting out will disable upload of results to your repo's Code Scanning dashboard 70 | - name: "Upload to code-scanning" 71 | uses: github/codeql-action/upload-sarif@v3 72 | with: 73 | sarif_file: results.sarif 74 | -------------------------------------------------------------------------------- /src/sym/bcc_perf_map.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Facebook, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "bcc_perf_map.h" 24 | 25 | bool bcc_is_perf_map(const char *path) { 26 | char* pos = strstr(const_cast(path), ".map"); 27 | // Path ends with ".map" 28 | return (pos != NULL) && (*(pos + 4)== 0); 29 | } 30 | 31 | bool bcc_is_valid_perf_map(const char *path) { 32 | return bcc_is_perf_map(path) && (access(path, R_OK) == 0); 33 | } 34 | 35 | int bcc_perf_map_nstgid(int pid) { 36 | char status_path[64]; 37 | FILE *status; 38 | 39 | snprintf(status_path, sizeof(status_path), "/proc/%d/status", pid); 40 | status = fopen(status_path, "r"); 41 | 42 | if (!status) 43 | return -1; 44 | 45 | // return the original PID if we fail to work out the TGID 46 | int nstgid = pid; 47 | 48 | size_t size = 0; 49 | char *line = NULL; 50 | while (getline(&line, &size, status) != -1) { 51 | // check Tgid line first in case CONFIG_PID_NS is off 52 | if (strstr(line, "Tgid:") != NULL) 53 | nstgid = (int)strtol(strrchr(line, '\t'), NULL, 10); 54 | if (strstr(line, "NStgid:") != NULL) 55 | // PID namespaces can be nested -- last number is innermost PID 56 | nstgid = (int)strtol(strrchr(line, '\t'), NULL, 10); 57 | } 58 | free(line); 59 | fclose(status); 60 | 61 | return nstgid; 62 | } 63 | 64 | bool bcc_perf_map_path(char *map_path, size_t map_len, int pid) { 65 | char source[64]; 66 | snprintf(source, sizeof(source), "/proc/%d/root", pid); 67 | 68 | char target[4096]; 69 | ssize_t target_len = readlink(source, target, sizeof(target) - 1); 70 | if (target_len == -1) 71 | return false; 72 | 73 | target[target_len] = '\0'; 74 | if (strcmp(target, "/") == 0) 75 | target[0] = '\0'; 76 | 77 | int nstgid = bcc_perf_map_nstgid(pid); 78 | 79 | snprintf(map_path, map_len, "%s/tmp/perf-%d.map", target, nstgid); 80 | return true; 81 | } 82 | 83 | int bcc_perf_map_foreach_sym(const char *path, bcc_perf_map_symcb callback, 84 | void* payload) { 85 | FILE* file = fopen(path, "r"); 86 | if (!file) 87 | return -1; 88 | 89 | char *line = NULL; 90 | size_t size = 0; 91 | long long begin, len; 92 | while (getline(&line, &size, file) != -1) { 93 | char *cursor = line; 94 | char *newline, *sep; 95 | 96 | begin = strtoull(cursor, &sep, 16); 97 | if (begin == 0 || *sep != ' ' || (begin == ULLONG_MAX && errno == ERANGE)) 98 | continue; 99 | cursor = sep; 100 | while (*cursor && isspace(*cursor)) cursor++; 101 | 102 | len = strtoull(cursor, &sep, 16); 103 | if (*sep != ' ' || 104 | (sep == cursor && len == 0) || 105 | (len == ULLONG_MAX && errno == ERANGE)) 106 | continue; 107 | cursor = sep; 108 | while (*cursor && isspace(*cursor)) cursor++; 109 | 110 | newline = strchr(cursor, '\n'); 111 | if (newline) 112 | newline[0] = '\0'; 113 | 114 | callback(cursor, begin, len, payload); 115 | } 116 | 117 | free(line); 118 | fclose(file); 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /src/common/cancellable_message_queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | /// A single-reader, single-writer, single-ended queue 28 | /// capable of being cancelled externally 29 | /// for getting out of a blocking wait. 30 | template 31 | class CancellableMessageQueue 32 | { 33 | private: 34 | std::mutex writeLock; 35 | std::mutex readLock; 36 | std::condition_variable readCondition; 37 | std::atomic cancelled = false; 38 | 39 | std::queue leftQueue; 40 | std::queue rightQueue; 41 | 42 | std::queue *currentWriteQueue = &leftQueue; 43 | std::queue *currentReadQueue = &rightQueue; 44 | 45 | void swapQueues() 46 | { 47 | std::unique_lock lock(writeLock); 48 | std::swap(currentReadQueue, currentWriteQueue); 49 | }; 50 | 51 | public: 52 | CancellableMessageQueue() {}; 53 | ~CancellableMessageQueue() {}; 54 | 55 | std::optional pop() 56 | { 57 | std::unique_lock lock(readLock); 58 | readCondition.wait(lock, [&]{ 59 | return !currentReadQueue->empty() || 60 | !currentWriteQueue->empty() || 61 | cancelled; 62 | }); 63 | // currently own the lock 64 | 65 | // if we're cancelled, return an empty optional 66 | if (cancelled) return std::nullopt; 67 | 68 | // otherwise, determine which queue to read from 69 | if (currentReadQueue->empty() && !currentWriteQueue->empty()) 70 | { 71 | // swap the queues! 72 | swapQueues(); 73 | } 74 | 75 | T retVal = currentReadQueue->front(); 76 | currentReadQueue->pop(); 77 | return retVal; 78 | }; 79 | 80 | void push(T value) 81 | { 82 | std::unique_lock lock(writeLock); 83 | // got lock! 84 | currentWriteQueue->push(std::move(value)); 85 | readCondition.notify_all(); 86 | }; 87 | 88 | void push(std::vector values) 89 | { 90 | std::unique_lock lock(writeLock); 91 | // got lock! 92 | for (auto& el : values) 93 | { 94 | currentWriteQueue->push(std::move(el)); 95 | } 96 | readCondition.notify_all(); 97 | } 98 | 99 | const bool isCancelled() const { return cancelled; }; 100 | 101 | void cancel() 102 | { 103 | cancelled = true; 104 | readCondition.notify_all(); 105 | }; 106 | }; -------------------------------------------------------------------------------- /src/tracer/ebpf/ebpf_tracer_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "syscall_schema.h" 26 | #include "kern/procmonEBPF_common.h" 27 | #include "../../common/cancellable_message_queue.h" 28 | #include "../tracer_engine.h" 29 | #include "../../common/event.h" 30 | #include "../../storage/storage_engine.h" 31 | 32 | #include 33 | 34 | extern "C" 35 | { 36 | #include 37 | #include 38 | } 39 | 40 | #define KERN_4_17_5_1_OBJ "procmonEBPFkern4.17-5.1.o" 41 | #define KERN_5_2_OBJ "procmonEBPFkern5.2.o" 42 | #define KERN_5_3_5_5_OBJ "procmonEBPFkern5.3-5.5.o" 43 | #define KERN_5_6__OBJ "procmonEBPFkern5.6-.o" 44 | #define KERN_4_17_5_1_CORE_OBJ "procmonEBPFkern4.17-5.1_core.o" 45 | #define KERN_5_2_CORE_OBJ "procmonEBPFkern5.2_core.o" 46 | #define KERN_5_3_5_5_CORE_OBJ "procmonEBPFkern5.3-5.5_core.o" 47 | #define KERN_5_6__CORE_OBJ "procmonEBPFkern5.6-_core.o" 48 | 49 | class EbpfTracerEngine : public ITracerEngine 50 | { 51 | private: 52 | ~EbpfTracerEngine(); 53 | 54 | // The thread for polling the perf buffer 55 | // This thread will also be calling the 56 | // callback for every event 57 | std::thread PollingThread; 58 | 59 | // The thread for consuming the raw events 60 | std::thread ConsumerThread; 61 | 62 | // The queue for containing raw events 63 | // from eBPF to be processed into telemetry 64 | CancellableMessageQueue EventQueue; 65 | 66 | std::map SymbolCacheMap; 67 | 68 | void Poll(); 69 | void Consume(); 70 | 71 | StackTrace GetStackTraceForIPs(int pid, uint64_t *userIPs, uint64_t userCount); 72 | 73 | // Instance level callback 74 | void PerfCallback(void *rawMessage, int rawMessageSize); 75 | // static callback that passes the instance pointer in cbCookie 76 | static void PerfCallbackWrapper(void *cbCookie, int cpu, void *rawMessage, uint32_t rawMessageSize); 77 | 78 | // Instance level callback 79 | void PerfLostCallback(uint64_t lost); 80 | // static callback that passes the instance pointer in cbCookie 81 | static void PerfLostCallbackWrapper(void *cbCookie, int cpu, uint64_t lost); 82 | public: 83 | std::vector Schemas; 84 | 85 | EbpfTracerEngine(std::shared_ptr storageEngine, std::vector targetEvents, std::vector pids); 86 | void Initialize() override; 87 | 88 | void AddPids(std::vector pidsToTrace) override; 89 | 90 | void SetRunState(int runState) override; 91 | void Cancel() { EventQueue.cancel(); } 92 | }; -------------------------------------------------------------------------------- /src/storage/mock_storage_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef MOCK_STORAGE_ENGINE_H 18 | #define MOCK_STORAGE_ENGINE_H 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "storage_engine.h" 26 | #include "../common/telemetry.h" 27 | #include "../common/event.h" 28 | #include "../display/screen_configuration.h" 29 | 30 | typedef ITelemetry MockTelemetry; 31 | 32 | class MockStorageEngine : public IStorageEngine 33 | { 34 | private: 35 | std::mutex _mapLock; 36 | std::map> _dataStore; 37 | public: 38 | bool Initialize(const std::vector& syscalls) override {return true;}; 39 | 40 | std::vector QueryByPid(pid_t pid, const std::vector& syscalls = {}) override; 41 | 42 | virtual std::vector QueryByPidInTimespan( 43 | pid_t pid, double start_time = 0.0, double end_time = 0.0, const std::vector& syscalls = {}) override {return std::vector();}; 44 | 45 | virtual std::vector QueryByPids(std::vector pids, const std::vector& syscalls = {}) override {return std::vector();}; 46 | 47 | virtual std::vector QueryByPidsInTimespan( 48 | std::vector pids, double start_time = 0.0, double end_time = 0.0, const std::vector& syscalls = {}) override {return std::vector();}; 49 | 50 | virtual std::vector QueryByEventsinPage( 51 | std::vector pids, uint pageNumber, uint eventsPerPage, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) override {return std::vector();}; 52 | 53 | virtual std::vector QueryByResultCodeInTimespan( 54 | int resultCode, double start_time = 0.0, double end_time = 0.0, const std::vector &syscalls = {}) override {return std::vector();}; 55 | 56 | virtual std::vector QueryByFilteredEventsinPage( 57 | std::string filter, std::vector pids, uint pageNumber, uint eventsPerPage, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) override {return std::vector();}; 58 | 59 | virtual std::vector QueryIdsBySearch( 60 | std::string search, std::vector pids, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) override; 61 | 62 | // Store API 63 | bool Store(MockTelemetry data) override; 64 | bool StoreMany(std::vector data) override; 65 | int Size() override { return 0; }; 66 | 67 | // Load API 68 | std::tuple Load(std::string filepath) { return std::make_tuple(0, ""); }; 69 | }; 70 | 71 | #endif // MOCK_STORAGE_ENGINE_H -------------------------------------------------------------------------------- /src/sym/bcc_elf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 GitHub, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef LIBBCC_ELF_H 17 | #define LIBBCC_ELF_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | #include 25 | 26 | struct bcc_elf_usdt { 27 | uint64_t pc; 28 | uint64_t base_addr; 29 | // Virtual address semaphore is found at 30 | uint64_t semaphore; 31 | 32 | const char *provider; 33 | const char *name; 34 | const char *arg_fmt; 35 | 36 | // Offset from start of file where the semaphore is at 37 | uint64_t semaphore_offset; 38 | }; 39 | 40 | // Binary module path, bcc_elf_usdt struct, payload 41 | typedef void (*bcc_elf_probecb)(const char *, const struct bcc_elf_usdt *, 42 | void *); 43 | // Symbol name, start address, length, payload 44 | // Callback returning a negative value indicates to stop the iteration 45 | typedef int (*bcc_elf_symcb)(const char *, uint64_t, uint64_t, void *); 46 | // Section idx, str table idx, str length, start address, length, payload 47 | typedef int (*bcc_elf_symcb_lazy)(size_t, size_t, size_t, uint64_t, uint64_t, 48 | int, void *); 49 | // Segment virtual address, memory size, file offset, payload 50 | // Callback returning a negative value indicates to stop the iteration 51 | typedef int (*bcc_elf_load_sectioncb)(uint64_t, uint64_t, uint64_t, void *); 52 | 53 | // Iterate over all USDT probes noted in a binary module 54 | // Returns -1 on error, and 0 on success 55 | int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback, 56 | void *payload); 57 | // Iterate over all executable load sections of an ELF 58 | // Returns -1 on error, 1 if stopped by callback, and 0 on success 59 | int bcc_elf_foreach_load_section(const char *path, 60 | bcc_elf_load_sectioncb callback, 61 | void *payload); 62 | // Iterate over symbol table of a binary module 63 | // Parameter "option" points to a bcc_symbol_option struct to indicate whether 64 | // and how to use debuginfo file, and what types of symbols to load. 65 | // Returns -1 on error, and 0 on success or stopped by callback 66 | int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback, void *option, 67 | void *payload); 68 | // Similar to bcc_elf_foreach_sym, but pass reference to symbolized string along 69 | // with symbolized string length 70 | int bcc_elf_foreach_sym_lazy(const char *path, bcc_elf_symcb_lazy callback, 71 | void *option, void *payload); 72 | // Iterate over all symbols from current system's vDSO 73 | // Returns -1 on error, and 0 on success or stopped by callback 74 | int bcc_elf_foreach_vdso_sym(bcc_elf_symcb callback, void *payload); 75 | 76 | int bcc_elf_get_text_scn_info(const char *path, uint64_t *addr, 77 | uint64_t *offset); 78 | 79 | int bcc_elf_get_type(const char *path); 80 | int bcc_elf_is_shared_obj(const char *path); 81 | int bcc_elf_is_exe(const char *path); 82 | int bcc_elf_is_vdso(const char *name); 83 | int bcc_free_memory(); 84 | int bcc_elf_get_buildid(const char *path, char *buildid); 85 | int bcc_elf_symbol_str(const char *path, size_t section_idx, 86 | size_t str_table_idx, char *out, size_t len, 87 | int debugfile); 88 | 89 | #ifdef __cplusplus 90 | } 91 | #endif 92 | #endif 93 | -------------------------------------------------------------------------------- /src/configuration/procmon_configuration.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include "../storage/mock_storage_engine.h" 30 | #include "../storage/storage_engine.h" 31 | #include "../storage/storage_proxy.h" 32 | #include "../tracer/tracer_engine.h" 33 | #include "../tracer/mock_tracer_engine.h" 34 | #include "../tracer/ebpf/ebpf_tracer_engine.h" 35 | #include "../common/event.h" 36 | #include "../common/cli_utils.h" 37 | #include "../logging/easylogging++.h" 38 | 39 | #define DEFAULT_TIMESTAMP_LENGTH 25 40 | #define DEFAULT_DATESTAMP_LENGTH 11 41 | 42 | struct ProcmonArgs 43 | { 44 | std::vector pids; 45 | std::vector events; 46 | StorageProxy::StorageEngineType storageEngineType; 47 | }; 48 | 49 | // Should only be created once. Pass around using 50 | // a std::shared_ptr. 51 | class ProcmonConfiguration : public ProcmonArgs 52 | { 53 | private: 54 | std::shared_ptr _storageEngine; 55 | std::unique_ptr _tracerEngine; 56 | std::vector syscallSchema; 57 | std::vector pointerSyscalls; 58 | struct timespec startTime; 59 | std::string epocStartTime; 60 | std::string date; 61 | bool headless = false; 62 | std::string traceFilePath = ""; 63 | std::string debugTraceFilePath = ""; 64 | std::string outputTraceFilePath = ""; 65 | 66 | void HandlePidArgs(char *pidArgs); 67 | 68 | void HandleStorageArgs(char *storageArgs); 69 | 70 | void HandleEventArgs(char *eventArgs); 71 | 72 | void HandleFileArg(char * filepath); 73 | void HandleLogArg(char * filepath); 74 | 75 | std::string ConvertEpocTime(time_t time); 76 | 77 | public: 78 | // Initializes the configuration handling args and creating necessary resources. 79 | ProcmonConfiguration(int argc, char *argv[]); 80 | 81 | // Getters & Setters 82 | const std::unique_ptr& GetTracer() { return _tracerEngine; }; 83 | std::shared_ptr GetStorage() { return _storageEngine; }; 84 | std::vector& GetSchema() { return syscallSchema; } 85 | std::vector getPointerSyscalls() { return pointerSyscalls; } 86 | uint64_t GetStartTime(); 87 | void SetStartTime(uint64_t start); 88 | void SetEpocStartTime(std::string startTime) { epocStartTime = startTime; } 89 | std::string GetEpocStartTime() { return epocStartTime; } 90 | std::string GetStartDate() { return date; } 91 | bool GetHeadlessMode() { return headless; } 92 | std::string GetTraceFilePath() { return traceFilePath; } 93 | std::string GetDebugTraceFilePath() { return debugTraceFilePath; } 94 | std::string GetOutputTraceFilePath() { return outputTraceFilePath; } 95 | }; -------------------------------------------------------------------------------- /src/display/headless.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "headless.h" 18 | #include "../logging/easylogging++.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace 26 | { 27 | volatile std::sig_atomic_t signalStatus; 28 | } 29 | 30 | void sigintHandler(int sig) 31 | { 32 | signalStatus = sig; 33 | } 34 | 35 | bool Headless::initialize(std::shared_ptr configPtr) 36 | { 37 | config = configPtr; 38 | 39 | std::cout << "Procmon " << STRFILEVER; 40 | std::cout << VER_COPYRIGHT; 41 | 42 | std::cout << "Press Ctrl-C to end monitoring without terminating the process." << std::endl << std::endl; 43 | 44 | std::cout << "PID Filter: "; 45 | if(config->pids.size() == 0) 46 | { 47 | std::cout << "All Pids" << std::endl; 48 | } 49 | else 50 | { 51 | std::cout << config->pids[0]; 52 | 53 | for(int i = 1; i < config->pids.size(); i++) 54 | { 55 | std::cout << ", " << config->pids[i]; 56 | } 57 | std::cout << std::endl; 58 | } 59 | 60 | std::cout << "Syscall Filter: "; 61 | if(config->events.size() == syscalls.size()) 62 | { 63 | std::cout << "All Syscalls" << std::endl; 64 | } 65 | else 66 | { 67 | std::cout << config->events[0].Name(); 68 | 69 | for(int i = 1; i < config->events.size(); i++) 70 | { 71 | std::cout << ", " << config->events[i].Name(); 72 | } 73 | std::cout << std::endl; 74 | } 75 | 76 | return true; 77 | } 78 | 79 | void Headless::run() 80 | { 81 | bool running = true; 82 | std::string size; 83 | 84 | // setup signal handler 85 | signal(SIGINT, sigintHandler); 86 | 87 | std::cout << "Events captured: "; 88 | 89 | while(running) 90 | { 91 | // check to see if user has hit ctrl + c 92 | if(signalStatus == SIGINT) 93 | { 94 | config->GetTracer()->SetRunState(TRACER_SUSPENDED); 95 | break; 96 | } 97 | 98 | // update terminal with events captured 99 | size = std::to_string(config->GetStorage()->Size()); 100 | std::cout << size << std::flush; 101 | std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 102 | 103 | // print overwrite pervious value printed to screen 104 | std::cout << std::string(size.length(),'\b'); 105 | } 106 | std::cout << std::endl << std::endl; 107 | } 108 | 109 | void Headless::shutdown() 110 | { 111 | std::cout << "Writing events to " << config->GetOutputTraceFilePath() << std::endl; 112 | 113 | try 114 | { 115 | config->GetStorage()->Export(std::make_tuple(config->GetStartTime(), config->GetEpocStartTime()), config->GetOutputTraceFilePath()); 116 | } 117 | catch(const std::runtime_error& e) 118 | { 119 | LOG(ERROR) << e.what(); 120 | std::cerr << "Failed to write to tracefile " << config->GetOutputTraceFilePath() << std::endl; 121 | CLIUtils::FastExit(); 122 | } 123 | 124 | 125 | std::cout << "Total events captured: " << config->GetStorage()->Size() << std::endl; 126 | 127 | } -------------------------------------------------------------------------------- /src/procmon.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include "configuration/procmon_configuration.h" 22 | #include "display/screen.h" 23 | #include "display/headless.h" 24 | #include "logging/easylogging++.h" 25 | #include "installer.h" 26 | 27 | INITIALIZE_EASYLOGGINGPP 28 | 29 | //-------------------------------------------------------------------- 30 | // 31 | // main 32 | // 33 | // Main entry point 34 | // 35 | //-------------------------------------------------------------------- 36 | int main(int argc, char *argv[]) 37 | { 38 | // Make sure user is running elevated 39 | if(geteuid() != 0) 40 | { 41 | std::cout << "Procmon requires elevated credentials. Please run with sudo.\n"; 42 | exit(-1); 43 | } 44 | 45 | /* 46 | * Turn off cursor for shell. Note this has to be done before EBPF spins up. 47 | * This is due to a conflict that leads to the consumer thread dieing when the system 48 | * function is executed. 49 | */ 50 | curs_set(0); 51 | 52 | // Extrace eBPF programs 53 | ExtractEBPFPrograms(); 54 | 55 | // Program initialization: create global config from args 56 | auto config = std::make_shared(argc, argv); 57 | 58 | LOG(DEBUG) << "Tracing " << config->events.size() << " system calls"; 59 | 60 | // Configure logging 61 | if(config->GetDebugTraceFilePath().size() != 0) 62 | { 63 | el::Configurations defaultConf; 64 | defaultConf.setToDefault(); 65 | 66 | defaultConf.set(el::Level::Debug, el::ConfigurationType::Format, "%datetime [%level] %msg"); 67 | defaultConf.set(el::Level::Global, el::ConfigurationType::MaxLogFileSize, "5242880"); 68 | 69 | defaultConf.set(el::Level::Info, el::ConfigurationType::Filename, config->GetDebugTraceFilePath()); 70 | defaultConf.set(el::Level::Error, el::ConfigurationType::Filename, config->GetDebugTraceFilePath()); 71 | defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, config->GetDebugTraceFilePath()); 72 | 73 | el::Loggers::reconfigureAllLoggers(defaultConf); 74 | } 75 | 76 | if(config->GetHeadlessMode()) 77 | { 78 | if(config->GetTraceFilePath().compare("") != 0) 79 | { 80 | std::cerr << "Cannot open trace file in headless mode"; 81 | CLIUtils::DisplayUsage(true); 82 | } 83 | 84 | Headless headlessDisplay; 85 | 86 | // init headless interface 87 | headlessDisplay.initialize(config); 88 | 89 | // run in headless mode 90 | headlessDisplay.run(); 91 | 92 | // cleanup run 93 | headlessDisplay.shutdown(); 94 | } 95 | else 96 | { 97 | Screen display; 98 | 99 | // initialize curses UI 100 | display.initScreen(config); 101 | 102 | // run display 103 | display.run(); 104 | 105 | // shutdown curses UI 106 | display.shutdownScreen(); 107 | } 108 | 109 | // re-enable cursor before exiting Procmon 110 | curs_set(1); 111 | 112 | config->GetTracer()->Cancel(); 113 | DeleteEBPFPrograms(); 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /makePackages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Procmon for Linux 4 | # 5 | # Copyright (c) Microsoft Corporation 6 | # 7 | # All rights reserved. 8 | # 9 | # MIT License 10 | # 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 16 | # 17 | 18 | ################################################################################# 19 | # 20 | # makePackages.sh 21 | # 22 | # Builds the directory trees for DEB and RPM packages and, if suitable tools are 23 | # available, builds the actual packages too. 24 | # 25 | ################################################################################# 26 | 27 | if [ "$5" = "" ]; then 28 | echo "Usage: $0 " 29 | exit 1 30 | fi 31 | 32 | # copy cmake vars 33 | CMAKE_SOURCE_DIR=$1 34 | PROJECT_BINARY_DIR=$2 35 | PACKAGE_NAME=$3 36 | PACKAGE_VER=$4 37 | PACKAGE_REL=$5 38 | PACKAGE_TYPE=$6 39 | 40 | DEB_PACKAGE_NAME="${PACKAGE_NAME}_${PACKAGE_VER}_amd64" 41 | RPM_PACKAGE_NAME="${PACKAGE_NAME}-${PACKAGE_VER}-${PACKAGE_REL}" 42 | 43 | if [ "$PACKAGE_TYPE" = "deb" ]; then 44 | DPKGDEB=`which dpkg-deb` 45 | 46 | if [ -d "${PROJECT_BINARY_DIR}/deb" ]; then 47 | rm -rf "${PROJECT_BINARY_DIR}/deb" 48 | fi 49 | 50 | # copy deb files 51 | mkdir -p "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}" 52 | #cp -a "${CMAKE_SOURCE_DIR}/dist/DEBIAN" "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/" 53 | mkdir -p "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/DEBIAN" 54 | cp "${PROJECT_BINARY_DIR}/DEBIANcontrol" "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/DEBIAN/control" 55 | mkdir -p "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/usr/share/doc/procmon" 56 | cp "${PROJECT_BINARY_DIR}/changelog.gz" "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/usr/share/doc/procmon" 57 | mkdir -p "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/usr/share/man/man1" 58 | cp -a "${PROJECT_BINARY_DIR}/procmon.1.gz" "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/usr/share/man/man1" 59 | mkdir -p "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/usr/bin" 60 | cp "${PROJECT_BINARY_DIR}/procmon" "${PROJECT_BINARY_DIR}/deb/${DEB_PACKAGE_NAME}/usr/bin/" 61 | 62 | # make the deb 63 | if [ "$DPKGDEB" != "" ]; then 64 | cd "${PROJECT_BINARY_DIR}/deb" 65 | "$DPKGDEB" -Zxz --build --root-owner-group "${DEB_PACKAGE_NAME}" 66 | RET=$? 67 | else 68 | echo "No dpkg-deb found" 69 | RET=1 70 | fi 71 | 72 | exit 0 73 | fi 74 | 75 | if [ "$PACKAGE_TYPE" = "rpm" ]; then 76 | RPMBUILD=`which rpmbuild` 77 | 78 | if [ -d "${PROJECT_BINARY_DIR}/rpm" ]; then 79 | rm -rf "${PROJECT_BINARY_DIR}/rpm" 80 | fi 81 | 82 | # copy rpm files 83 | mkdir -p "${PROJECT_BINARY_DIR}/rpm/${RPM_PACKAGE_NAME}/SPECS" 84 | cp -a "${PROJECT_BINARY_DIR}/SPECS.spec" "${PROJECT_BINARY_DIR}/rpm/${RPM_PACKAGE_NAME}/SPECS/${RPM_PACKAGE_NAME}.spec" 85 | mkdir "${PROJECT_BINARY_DIR}/rpm/${RPM_PACKAGE_NAME}/BUILD/" 86 | cp "${PROJECT_BINARY_DIR}/procmon.1.gz" "${PROJECT_BINARY_DIR}/changelog" "${PROJECT_BINARY_DIR}/procmon" "${PROJECT_BINARY_DIR}/rpm/${RPM_PACKAGE_NAME}/BUILD/" 87 | 88 | # make the rpm 89 | if [ "$RPMBUILD" != "" ]; then 90 | cd "${PROJECT_BINARY_DIR}/rpm/${RPM_PACKAGE_NAME}" 91 | "$RPMBUILD" --define "_topdir `pwd`" -v -bb "SPECS/${RPM_PACKAGE_NAME}.spec" 92 | RET=$? 93 | cp RPMS/x86_64/*.rpm .. 94 | else 95 | echo "No rpmbuild found" 96 | RET=1 97 | fi 98 | fi 99 | 100 | exit $RET 101 | -------------------------------------------------------------------------------- /src/storage/sqlite3_storage_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "storage_engine.h" 25 | #include "../common/telemetry.h" 26 | #include "../display/screen_configuration.h" 27 | 28 | class Sqlite3StorageEngine : public IStorageEngine 29 | { 30 | private: 31 | bool ready; 32 | 33 | // Since we are only expecting only one writer to access the storage engine at a time, 34 | // this is okay for now. However once more writers are introduced, telemetryCount should 35 | // declared as an atomic. 36 | uint telemetryCount; 37 | 38 | std::vector syscallList; 39 | 40 | sqlite3* dbConnection; 41 | 42 | std::string addPidFilterToSQLQuery(const std::string initialQuery, std::vector pids, const bool first); 43 | 44 | std::string addSyscallFilterToSQLQuery(const std::string initialQuery, std::vector events, const bool first); 45 | 46 | void prepareAndGetFromSqlite3(const std::string raw_sql_statement, std::vector& results); 47 | void prepareAndGetIdsFromSqlite3(const std::string raw_sql_statement, std::vector& results); 48 | 49 | ITelemetry parseSqlite3Row(sqlite3_stmt *preppedSqlStmt); 50 | 51 | std::vector getFromSqlite3(sqlite3_stmt* preppedSqlStmt); 52 | std::vector getIdsFromSqlite3(sqlite3_stmt* preppedSqlStmt); 53 | 54 | public: 55 | Sqlite3StorageEngine(): ready(false) {}; 56 | ~Sqlite3StorageEngine(); 57 | 58 | bool Initialize(const std::vector& syscalls) override; 59 | 60 | // Query API 61 | 62 | std::vector QueryByPid(pid_t pid, const std::vector& syscalls = {}) override; 63 | 64 | std::vector QueryByPids(std::vector pids, const std::vector& syscalls = {}) override; 65 | 66 | std::vector QueryByPidInTimespan( 67 | pid_t pid, double start_time = 0.0, double end_time = 0.0, const std::vector& syscalls = {}) override; 68 | 69 | std::vector QueryByPidsInTimespan( 70 | std::vector pids, double start_time = 0.0, double end_time = 0.0, const std::vector& syscalls = {}) override; 71 | 72 | std::vector QueryByResultCodeInTimespan( 73 | int resultCode, double start_time = 0.0, double end_time = 0.0, const std::vector& syscalls = {}) override; 74 | 75 | std::vector QueryByEventsinPage( 76 | std::vector pids, uint pageNumber, uint eventsPerPage, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) override; 77 | 78 | std::vector QueryByFilteredEventsinPage( 79 | std::string filter, std::vector pids, uint pageNumber, uint eventsPerPage, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) override; 80 | 81 | std::vector QueryIdsBySearch( 82 | std::string search, std::vector pids, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) override; 83 | 84 | // Store API 85 | bool Store(ITelemetry data) override; 86 | bool StoreMany(std::vector data) override; 87 | bool Clear() override; 88 | 89 | // Load API 90 | std::tuple Load(std::string filePath) override; 91 | 92 | // Debug API 93 | int Size() override; 94 | bool Export(std::tuple startTime, std::string filePath) override; 95 | }; -------------------------------------------------------------------------------- /src/storage/storage_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef STORAGE_ENGINE_H 18 | #define STORAGE_ENGINE_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "../common/telemetry.h" 25 | #include "../common/event.h" 26 | #include "../display/screen_configuration.h" 27 | 28 | class IStorageEngine 29 | { 30 | protected: 31 | std::map> _syscallHitMap; 32 | 33 | public: 34 | IStorageEngine() {} 35 | virtual ~IStorageEngine(){}; 36 | 37 | // Initialize the storage engine with expected syscalls to be stored. 38 | virtual bool Initialize(const std::vector &syscalls) = 0; 39 | 40 | // Query API 41 | 42 | // Get all telemetry data for given pid 43 | // optionally filter by syscalls. 44 | virtual std::vector QueryByPid(pid_t pid, const std::vector &syscalls = {}) = 0; 45 | 46 | // Get all telemetry data for a given pid in a timespan 47 | // optionally filter by syscalls. 48 | // notes: - specify only start_time to get everything _after_ 49 | // - specify only end_time to get everything _before_ 50 | virtual std::vector QueryByPidInTimespan( 51 | pid_t pid, double start_time = 0.0, double end_time = 0.0, const std::vector &syscalls = {}) = 0; 52 | 53 | // Get all telemetry data for given pids 54 | // optionally filter by syscalls. 55 | virtual std::vector QueryByPids(std::vector pids, const std::vector &syscalls = {}) = 0; 56 | 57 | // Get all telemetry data for a given pids in a timespan 58 | // optionally filter by syscalls. 59 | // notes: - specify only start_time to get everything _after_ 60 | // - specify only end_time to get everything _before_ 61 | virtual std::vector QueryByPidsInTimespan( 62 | std::vector pids, double start_time = 0.0, double end_time = 0.0, const std::vector &syscalls = {}) = 0; 63 | 64 | // Get a specified page of telemetry data for a given pids 65 | // optionally filter by syscalls. 66 | virtual std::vector QueryByEventsinPage( 67 | std::vector pids, uint pageNumber, uint eventsPerPage, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) = 0; 68 | 69 | virtual std::vector QueryByResultCodeInTimespan( 70 | int resultCode, double start_time = 0.0, double end_time = 0.0, const std::vector &syscalls = {}) = 0; 71 | 72 | virtual std::vector QueryByFilteredEventsinPage( 73 | std::string filter, std::vector pids, uint pageNumber, uint eventsPerPage, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) = 0; 74 | 75 | virtual std::vector QueryIdsBySearch( 76 | std::string search, std::vector pids, ScreenConfiguration::sort orderBy, bool asc, const std::vector& syscalls = {}) = 0; 77 | 78 | // Store API 79 | virtual bool Store(ITelemetry data) = 0; 80 | virtual bool StoreMany(std::vector data) = 0; 81 | virtual int Size() { return 0; }; 82 | virtual bool Export(std::tuple startTime, std::string filePath) { return false; }; 83 | virtual bool Clear() { return false; }; 84 | 85 | // Load API 86 | virtual std::tuple Load(std::string filePath) = 0; 87 | 88 | // Hitmap API 89 | virtual std::map> GetHitmap () { return _syscallHitMap; } 90 | }; 91 | 92 | #endif -------------------------------------------------------------------------------- /src/installer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "installer.h" 7 | 8 | extern "C" 9 | { 10 | #include "libsysinternalsEBPF.h" 11 | } 12 | 13 | mode_t fileMode = S_IRUSR | S_IWUSR; 14 | 15 | extern char _binary_procmonEBPFkern4_17_5_1_o_start[]; 16 | extern char _binary_procmonEBPFkern4_17_5_1_o_end[]; 17 | extern char _binary_procmonEBPFkern5_2_o_start[]; 18 | extern char _binary_procmonEBPFkern5_2_o_end[]; 19 | extern char _binary_procmonEBPFkern5_3_5_5_o_start[]; 20 | extern char _binary_procmonEBPFkern5_3_5_5_o_end[]; 21 | extern char _binary_procmonEBPFkern5_6__o_start[]; 22 | extern char _binary_procmonEBPFkern5_6__o_end[]; 23 | extern char _binary_procmonEBPFkern4_17_5_1_core_o_start[]; 24 | extern char _binary_procmonEBPFkern4_17_5_1_core_o_end[]; 25 | extern char _binary_procmonEBPFkern5_2_core_o_start[]; 26 | extern char _binary_procmonEBPFkern5_2_core_o_end[]; 27 | extern char _binary_procmonEBPFkern5_3_5_5_core_o_start[]; 28 | extern char _binary_procmonEBPFkern5_3_5_5_core_o_end[]; 29 | extern char _binary_procmonEBPFkern5_6__core_o_start[]; 30 | extern char _binary_procmonEBPFkern5_6__core_o_end[]; 31 | 32 | //-------------------------------------------------------------------- 33 | // 34 | // ExtractEBPFPrograms 35 | // 36 | // Extracts the EBPF programs from the procmon binary and places them 37 | // in /tmp 38 | // 39 | //-------------------------------------------------------------------- 40 | bool ExtractEBPFPrograms() 41 | { 42 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_4_17_5_1_OBJ, 43 | _binary_procmonEBPFkern4_17_5_1_o_start, 44 | _binary_procmonEBPFkern4_17_5_1_o_end, 45 | true, 46 | fileMode)) 47 | { 48 | return false; 49 | } 50 | 51 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_5_2_OBJ, 52 | _binary_procmonEBPFkern5_2_o_start, 53 | _binary_procmonEBPFkern5_2_o_end, 54 | true, 55 | fileMode)) 56 | { 57 | return false; 58 | } 59 | 60 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_5_3_5_5_OBJ, 61 | _binary_procmonEBPFkern5_3_5_5_o_start, 62 | _binary_procmonEBPFkern5_3_5_5_o_end, 63 | true, 64 | fileMode)) 65 | { 66 | return false; 67 | } 68 | 69 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_5_6__OBJ, 70 | _binary_procmonEBPFkern5_6__o_start, 71 | _binary_procmonEBPFkern5_6__o_end, 72 | true, 73 | fileMode)) 74 | { 75 | return false; 76 | } 77 | 78 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_4_17_5_1_CORE_OBJ, 79 | _binary_procmonEBPFkern4_17_5_1_core_o_start, 80 | _binary_procmonEBPFkern4_17_5_1_core_o_end, 81 | true, 82 | fileMode)) 83 | { 84 | return false; 85 | } 86 | 87 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_5_2_CORE_OBJ, 88 | _binary_procmonEBPFkern5_2_core_o_start, 89 | _binary_procmonEBPFkern5_2_core_o_end, 90 | true, 91 | fileMode)) 92 | { 93 | return false; 94 | } 95 | 96 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_5_3_5_5_CORE_OBJ, 97 | _binary_procmonEBPFkern5_3_5_5_core_o_start, 98 | _binary_procmonEBPFkern5_3_5_5_core_o_end, 99 | true, 100 | fileMode)) 101 | { 102 | return false; 103 | } 104 | 105 | if (!dropFile(PROCMON_EBPF_INSTALL_DIR "/" KERN_5_6__CORE_OBJ, 106 | _binary_procmonEBPFkern5_6__core_o_start, 107 | _binary_procmonEBPFkern5_6__core_o_end, 108 | true, 109 | fileMode)) 110 | { 111 | return false; 112 | } 113 | 114 | return true; 115 | } 116 | 117 | //-------------------------------------------------------------------- 118 | // 119 | // DeleteEBPFPrograms 120 | // 121 | // Deletes the temporary eBPF programs from /tmp 122 | // 123 | //-------------------------------------------------------------------- 124 | bool DeleteEBPFPrograms() 125 | { 126 | DIR* dir = opendir(PROCMON_EBPF_INSTALL_DIR); 127 | if (dir == nullptr) 128 | { 129 | return false; 130 | } 131 | 132 | struct dirent* entry; 133 | while ((entry = readdir(dir)) != nullptr) 134 | { 135 | std::string filename(entry->d_name); 136 | if (filename.find("procmon") == 0) 137 | { 138 | std::string filepath = PROCMON_EBPF_INSTALL_DIR "/" + filename; 139 | struct stat fileStat; 140 | if (stat(filepath.c_str(), &fileStat) == 0 && S_ISREG(fileStat.st_mode)) 141 | { 142 | unlink(filepath.c_str()); 143 | } 144 | } 145 | } 146 | 147 | closedir(dir); 148 | 149 | return true; 150 | } -------------------------------------------------------------------------------- /src/sym/bcc_syms.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 GitHub, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #ifndef LIBBCC_SYMS_H 17 | #define LIBBCC_SYMS_H 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #include 24 | #include "linux/bpf.h" 25 | #include "bcc_proc.h" 26 | 27 | struct bcc_symbol { 28 | const char *name; 29 | const char *demangle_name; 30 | const char *module; 31 | uint64_t offset; 32 | }; 33 | 34 | typedef int (*SYM_CB)(const char *symname, uint64_t addr); 35 | struct mod_info; 36 | 37 | #ifndef STT_GNU_IFUNC 38 | #define STT_GNU_IFUNC 10 39 | #endif 40 | 41 | #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2 42 | // Indicate if the Local Entry Point (LEP) should be used as a symbol's 43 | // start address 44 | #define STT_PPC64_ELFV2_SYM_LEP 31 45 | #endif 46 | 47 | static const uint32_t BCC_SYM_ALL_TYPES = 65535; 48 | struct bcc_symbol_option { 49 | int use_debug_file; 50 | int check_debug_file_crc; 51 | // Symbolize on-demand or symbolize everything ahead of time 52 | int lazy_symbolize; 53 | // Bitmask flags indicating what types of ELF symbols to use 54 | uint32_t use_symbol_type; 55 | }; 56 | 57 | void *bcc_symcache_new(int pid, struct bcc_symbol_option *option); 58 | void bcc_free_symcache(void *symcache, int pid); 59 | 60 | // The demangle_name pointer in bcc_symbol struct is returned from the 61 | // __cxa_demangle function call, which is supposed to be freed by caller. Call 62 | // this function after done using returned result of bcc_symcache_resolve. 63 | void bcc_symbol_free_demangle_name(struct bcc_symbol *sym); 64 | int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym); 65 | int bcc_symcache_resolve_no_demangle(void *symcache, uint64_t addr, 66 | struct bcc_symbol *sym); 67 | 68 | int bcc_symcache_resolve_name(void *resolver, const char *module, 69 | const char *name, uint64_t *addr); 70 | void bcc_symcache_refresh(void *resolver); 71 | 72 | int _bcc_syms_find_module(struct mod_info *info, int enter_ns, void *p); 73 | int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address, 74 | uint8_t inode_match_only, uint64_t *global); 75 | 76 | /*bcc APIs for build_id stackmap support*/ 77 | void *bcc_buildsymcache_new(void); 78 | void bcc_free_buildsymcache(void *symcache); 79 | int bcc_buildsymcache_add_module(void *resolver, const char *module_name); 80 | int bcc_buildsymcache_resolve(void *resolver, 81 | struct bpf_stack_build_id *trace, 82 | struct bcc_symbol *sym); 83 | // Call cb on every function symbol in the specified module. Uses simpler 84 | // SYM_CB callback mainly for easier to use in Python API. 85 | // Will prefer use debug file and check debug file CRC when reading the module. 86 | int bcc_foreach_function_symbol(const char *module, SYM_CB cb); 87 | 88 | // Find the offset of a symbol in a module binary. If addr is not zero, will 89 | // calculate the offset using the provided addr and the module's load address. 90 | // 91 | // If pid is provided, will use it to help lookup the module in the Process and 92 | // enter the Process's mount Namespace. 93 | // 94 | // If option is not NULL, will respect the specified options for lookup. 95 | // Otherwise default option will apply, which is to use debug file, verify 96 | // checksum, and try all types of symbols. 97 | // 98 | // Return 0 on success and -1 on failure. Output will be write to sym. After 99 | // use, sym->module need to be freed if it's not empty. 100 | int bcc_resolve_symname(const char *module, const char *symname, 101 | const uint64_t addr, int pid, 102 | struct bcc_symbol_option* option, 103 | struct bcc_symbol *sym); 104 | 105 | /* Calculate the global address for 'offset' in a shared object loaded into 106 | * a process 107 | * 108 | * Need to know (start_addr, file_offset) pairs for the /proc/PID/maps module 109 | * entry containing the offset and the elf section containing the module's 110 | * .text 111 | */ 112 | uint64_t __so_calc_global_addr(uint64_t mod_start_addr, 113 | uint64_t mod_file_offset, 114 | uint64_t elf_sec_start_addr, 115 | uint64_t elf_sec_file_offset, uint64_t offset); 116 | 117 | /* Given a global address which falls within a shared object's mapping in a 118 | * process, calculate the corresponding 'offset' in the .so 119 | * 120 | * Need to know (start_addr, file_offset) pairs for the /proc/PID/maps module 121 | * entry containing the offset and the elf section containing the module's 122 | * .text 123 | */ 124 | uint64_t __so_calc_mod_offset(uint64_t mod_start_addr, uint64_t mod_file_offset, 125 | uint64_t elf_sec_start_addr, 126 | uint64_t elf_sec_file_offset, 127 | uint64_t global_addr); 128 | 129 | #ifdef __cplusplus 130 | } 131 | #endif 132 | #endif 133 | -------------------------------------------------------------------------------- /src/display/column.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "column.h" 18 | #include "screen.h" 19 | 20 | Column::Column(int height, int width, int y, int x, std::string columnName) 21 | { 22 | this->height = height; 23 | this->width = width; 24 | this->y = y; 25 | this->x = x; 26 | this->columnName = columnName; 27 | 28 | // init ncurses objects 29 | this->win = newwin(height, width, y, x); 30 | this->panel = new_panel(this->win); 31 | 32 | // init local column datastore 33 | this->columnData.clear(); 34 | 35 | // Add Header to window 36 | columnPrintFill(COLUMN_HEADER_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 37 | 38 | this->currentLine = 1; // init to 1 to account for column header 39 | this->highlight = false; // init header highlight to off 40 | refreshColumn(); 41 | } 42 | 43 | Column::~Column() 44 | { 45 | // clean up column data 46 | this->columnData.clear(); 47 | 48 | // free up ncurses objects 49 | del_panel(this->panel); 50 | delwin(this->win); 51 | } 52 | 53 | void Column::addLine(std::string value) 54 | { 55 | // add data to local storage 56 | columnData.push_back(value); 57 | 58 | // write string to screen 59 | columnPrintFill(LINE_COLOR, 0, this->currentLine, "%s", value.c_str()); 60 | this->currentLine++; 61 | } 62 | 63 | int Column::resize(int height, int width, int x) 64 | { 65 | this->height = height; 66 | this->width = width; 67 | this->x = x; 68 | 69 | return wresize(this->win, height, width); 70 | } 71 | 72 | void Column::setLineColor(int y, int color) 73 | { 74 | if(y - 1 < columnData.size()) 75 | { 76 | columnPrintFill(color, 0, y, "%s", columnData[y - 1].c_str()); 77 | } 78 | } 79 | 80 | void Column::toggleHeaderHighlight() 81 | { 82 | if(highlight) 83 | { 84 | highlight = false; 85 | columnPrintFill(COLUMN_HEADER_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 86 | } 87 | else 88 | { 89 | highlight = true; 90 | columnPrintFill(HIGHLIGHT_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 91 | } 92 | } 93 | 94 | void Column::redrawColumn() 95 | { 96 | int line = 0; 97 | 98 | // clear column 99 | clearColumn(); 100 | 101 | // redraw header 102 | if(highlight) columnPrintFill(HIGHLIGHT_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 103 | else columnPrintFill(COLUMN_HEADER_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 104 | 105 | // redraw column data 106 | for(line = 0; line < this->height - 1 && line < columnData.size(); line++){ 107 | columnPrintFill(LINE_COLOR, 0, line + 1, "%s", columnData[line].c_str()); 108 | } 109 | } 110 | 111 | void Column::moveColumn(int x) 112 | { 113 | this->x = x; 114 | } 115 | 116 | void Column::resetColumn() 117 | { 118 | // reset line in column to 1 119 | currentLine = 1; 120 | 121 | // clear local column datastore 122 | this->columnData.clear(); 123 | } 124 | 125 | void Column::clearColumn() 126 | { 127 | // clear window 128 | werase(this->win); 129 | 130 | // redraw header 131 | if(highlight) columnPrintFill(HIGHLIGHT_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 132 | else columnPrintFill(COLUMN_HEADER_COLOR, 0, 0, "%s", (columnName + ":").c_str()); 133 | } 134 | 135 | void Column::refreshColumn() 136 | { 137 | wnoutrefresh(this->win); 138 | } 139 | 140 | void Column::hideColumn() 141 | { 142 | hide_panel(this->panel); 143 | } 144 | 145 | void Column::showColumn() 146 | { 147 | panel_above(this->panel); 148 | } 149 | 150 | void Column::columnPrintFill(int colorPair, int x, int y, const char * fmt, ...) 151 | { 152 | int cursorX; 153 | 154 | // set background color 155 | wattron(this->win, COLOR_PAIR(colorPair)); 156 | 157 | // move cursor to correct position 158 | wmove(win, y, x); 159 | 160 | // print to screen 161 | va_list args; 162 | va_start(args, fmt); 163 | std::string result; 164 | int len = vsnprintf(nullptr, 0, fmt, args)+1; 165 | va_end(args); 166 | 167 | if(len > 0) 168 | { 169 | result.resize(len); 170 | va_start(args, fmt); 171 | vsnprintf(&result.front(), len, fmt, args); 172 | va_end(args); 173 | } 174 | 175 | waddnstr(win, result.c_str(), this->width-COLUMN_PADDING); 176 | 177 | // get current cursor position 178 | cursorX = getcurx(win); 179 | 180 | if(cursorX <= this->width) 181 | { 182 | // fill the rest of the line for screen 183 | for (int i = cursorX; i < this->width; i++) 184 | { 185 | wprintw(win, " "); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/tracer/ebpf/syscall_schema.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "kern/procmonEBPF_common.h" 29 | #include "syscalls.h" 30 | 31 | class Utils 32 | { 33 | public: 34 | static std::map ArgTypeStringToArgTag; 35 | static std::vector Linux64PointerSycalls; 36 | 37 | static int GetSyscallNumberForName(const std::string& name) 38 | { 39 | for(const auto& syscall : syscalls) 40 | { 41 | if (syscall.name == name) 42 | { 43 | return syscall.number; 44 | } 45 | } 46 | 47 | return -1; 48 | } 49 | 50 | static ProcmonArgTag GetArgTagForArg(const std::string &argumentName, const std::string &argumentType) 51 | { 52 | auto maybeTag = ArgTypeStringToArgTag.find(argumentType); 53 | if (maybeTag != ArgTypeStringToArgTag.end()) 54 | return maybeTag->second; 55 | else if (argumentName == "fd") 56 | return ProcmonArgTag::FD; 57 | else if (argumentType.find("*") != std::string::npos) 58 | { 59 | return ProcmonArgTag::PTR; 60 | } 61 | else 62 | return ProcmonArgTag::NOTKNOWN; 63 | } 64 | 65 | static std::vector CollectSyscallSchema() 66 | { 67 | std::vector schemas; 68 | schemas.reserve(350); 69 | 70 | std::regex filenameRegex("(.*)/sys_enter_([a-z0-9_]+)"); 71 | // The line that contains this substring is up to where we skip to. 72 | std::regex syscall_nrRegex("__syscall_nr"); 73 | // Regex to parse argument info. 74 | std::regex argFieldTypeName("(field:)([a-zA-Z0-9_\\s\\*]+)(;)"); 75 | // Regex to parse arg and name 76 | std::regex argTypeAndName("([a-z\\* _]+)+ ([a-z_]+)$"); 77 | 78 | for(const auto& syscall : syscalls) 79 | { 80 | SyscallSchema schema; 81 | std::smatch match; 82 | 83 | if (syscall.entrypoint.compare(0, 4, "sys_") == 0) 84 | { 85 | std::string sysDir = "sys_enter_" + syscall.entrypoint.substr(4); 86 | int syscallNameLen = sizeof(schema.syscallName) / sizeof(schema.syscallName[0]); 87 | strncpy(schema.syscallName, syscall.name.c_str(), syscallNameLen -1); 88 | schema.syscallName[syscallNameLen - 1] = '\0'; 89 | 90 | std::string filePath = "/sys/kernel/debug/tracing/events/syscalls/" + sysDir + "/format"; 91 | std::ifstream file(filePath); 92 | 93 | // Skip all that we don't care about. 94 | std::string line; 95 | while (std::getline(file, line)) 96 | if (std::regex_search(line, match, syscall_nrRegex)) 97 | break; 98 | 99 | // Start interpreting lines since everything but the last line is what we are about. 100 | int argCount = 0; 101 | while (std::getline(file, line)) 102 | { 103 | if (std::regex_search(line, match, argFieldTypeName)) 104 | { 105 | int i1 = line.find(":"); 106 | int i2 = line.find(";"); 107 | std::string res = line.substr(i1+1, i2-i1-1); 108 | int lastPos = res.find_last_of(" "); 109 | 110 | std::string argName = res.substr(lastPos+1, res.length()-lastPos-1); 111 | std::string argType = res.substr(0, lastPos); 112 | int argLen = sizeof(schema.argNames[argCount]) / sizeof(schema.argNames[argCount][0]); 113 | strncpy(schema.argNames[argCount], argName.c_str(), argLen -1); 114 | schema.argNames[argCount][argLen -1] = '\0'; 115 | schema.types[argCount] = GetArgTagForArg(argName, argType); 116 | argCount++; 117 | } 118 | } 119 | // Make sure to record how many arguments we actually have for this syscall. 120 | schema.usedArgCount = argCount; 121 | schemas.push_back(schema); 122 | } 123 | } 124 | 125 | return schemas; 126 | } 127 | private: 128 | Utils(); 129 | }; 130 | -------------------------------------------------------------------------------- /src/display/event_formatter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "event_formatter.h" 18 | #include "../logging/easylogging++.h" 19 | #include "errno.h" 20 | #include 21 | 22 | 23 | std::string EventFormatter::GetTimestamp(ITelemetry &event) 24 | { 25 | return CalculateDeltaTimestamp(event.timestamp); 26 | } 27 | 28 | std::string EventFormatter::GetPID(ITelemetry &event) 29 | { 30 | return std::to_string(event.pid); 31 | } 32 | 33 | std::string EventFormatter::GetProcess(ITelemetry &event) 34 | { 35 | return event.processName; 36 | } 37 | 38 | std::string EventFormatter::GetOperation(ITelemetry &event) 39 | { 40 | return event.syscall; 41 | } 42 | 43 | std::string EventFormatter::GetDuration(ITelemetry &event) 44 | { 45 | std::ostringstream oss; 46 | oss << std::fixed << std::setprecision(3) << (double) event.duration/1000000; 47 | return oss.str(); 48 | } 49 | 50 | std::string EventFormatter::GetResult(ITelemetry &event) 51 | { 52 | std::vector pointerSycalls = config->getPointerSyscalls(); 53 | if(event.result >= 0) 54 | { 55 | for(int i = 0; i < pointerSycalls.size(); i++) 56 | { 57 | if(event.syscall == pointerSycalls[i]) 58 | { 59 | std::stringstream stream; 60 | stream << std::setfill('0') << std::setw(sizeof(uint64_t)*2) << std::hex << event.result; 61 | return "0x" + stream.str(); 62 | } 63 | } 64 | return std::to_string(event.result); 65 | } 66 | else 67 | { 68 | return std::to_string(event.result) + " (" + strerror(-1 * event.result) + ")"; 69 | } 70 | } 71 | 72 | std::string EventFormatter::GetDetails(ITelemetry &event) 73 | { 74 | return DecodeArguments(event); 75 | } 76 | 77 | 78 | std::string EventFormatter::CalculateDeltaTimestamp(uint64_t ebpfEventTimestamp) 79 | { 80 | std::string deltaTimestamp; 81 | 82 | // calculate delta from beginning of procmon for timestamp column 83 | uint64_t delta = ebpfEventTimestamp - (config->GetStartTime()); 84 | 85 | 86 | unsigned hour = delta / 3600000000000; 87 | delta = delta % 3600000000000; 88 | unsigned min = delta / 60000000000; 89 | delta = delta % 60000000000; 90 | unsigned sec = delta / 1000000000; 91 | delta = delta % 1000000000; 92 | unsigned millisec = delta / 1000000; 93 | 94 | deltaTimestamp += " +" + std::to_string(hour) + ":" + 95 | std::to_string(min) + ":" + 96 | std::to_string(sec) + "." + 97 | std::to_string(millisec); 98 | 99 | return deltaTimestamp; 100 | } 101 | 102 | std::string EventFormatter::DecodeArguments(ITelemetry &event) 103 | { 104 | std::string args = ""; 105 | 106 | std::vector& schema = config->GetSchema(); 107 | 108 | // Find the schema item 109 | int index = FindSyscall(event.syscall); 110 | SyscallSchema item = schema[index]; 111 | 112 | int readOffset = 0; 113 | for(int i=0; i event.result) 155 | { 156 | size = event.result; 157 | } 158 | 159 | uint8_t buff[size]; 160 | memcpy(buff, event.arguments + readOffset, size); 161 | readOffset += size; 162 | 163 | for(int i = 0; i < size; i++) 164 | { 165 | ss << std::setfill('0') << std::setw(2) << std::hex << (uint32_t)buff[i] << " "; 166 | } 167 | 168 | args += ss.str(); 169 | } 170 | else 171 | { 172 | int size = MAX_BUFFER / 6; 173 | uint8_t buff[size]; 174 | std::stringstream ss; 175 | 176 | 177 | memcpy(buff, event.arguments + readOffset, size); 178 | readOffset += size; 179 | 180 | for(int i = 0; i < size; i++) 181 | { 182 | ss << std::hex << (uint32_t)buff[i] << " "; 183 | } 184 | args += ss.str(); 185 | } 186 | } 187 | else if (item.types[i] == ProcmonArgTag::FD) 188 | { 189 | int size=MAX_BUFFER/6; 190 | char buff[size]; 191 | memcpy(buff, event.arguments+readOffset, size); 192 | readOffset+=size; 193 | args+=buff; 194 | } 195 | else if (item.types[i] == ProcmonArgTag::PTR) 196 | { 197 | unsigned long val = 0; 198 | int size = sizeof(unsigned long); 199 | memcpy(&val, event.arguments+readOffset, size); 200 | if(val==0) 201 | { 202 | args+="NULL"; 203 | } 204 | else 205 | { 206 | args+="0x"; 207 | std::stringstream ss; 208 | ss << std::hex << val; 209 | args+=ss.str(); 210 | } 211 | readOffset+=size; 212 | 213 | } 214 | else 215 | { 216 | args+="{}"; 217 | } 218 | 219 | args+=" "; 220 | } 221 | 222 | return args; 223 | } 224 | 225 | int EventFormatter::FindSyscall(std::string& syscallName) 226 | { 227 | std::vector& schema = config->GetSchema(); 228 | 229 | int i = 0; 230 | for(auto& syscall : schema) 231 | { 232 | if(syscallName.compare(syscall.syscallName)==0) 233 | { 234 | return i; 235 | } 236 | i++; 237 | } 238 | 239 | return -1; 240 | } 241 | -------------------------------------------------------------------------------- /src/sym/syms.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 GitHub, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #pragma once 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "bcc_proc.h" 27 | #include "bcc_syms.h" 28 | #include "file_desc.h" 29 | 30 | class ProcStat { 31 | std::string procfs_; 32 | std::string root_symlink_; 33 | std::string mount_ns_symlink_; 34 | // file descriptor of /proc//root open with O_PATH used to get into root 35 | // of process after it exits; unlike a dereferenced root symlink, *at calls 36 | // to this use the process's mount namespace 37 | int root_fd_ = -1; 38 | // store also root path and mount namespace pair to detect its changes 39 | std::string root_, mount_ns_; 40 | ino_t inode_; 41 | bool getinode_(ino_t &inode); 42 | 43 | public: 44 | ProcStat(int pid); 45 | ~ProcStat() { 46 | if (root_fd_ > 0) 47 | close(root_fd_); 48 | } 49 | bool refresh_root(); 50 | int get_root_fd() { return root_fd_; } 51 | bool is_stale(); 52 | void reset() { getinode_(inode_); } 53 | }; 54 | 55 | class SymbolCache { 56 | public: 57 | virtual ~SymbolCache() = default; 58 | 59 | virtual void refresh() = 0; 60 | virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle = true) = 0; 61 | virtual bool resolve_name(const char *module, const char *name, 62 | uint64_t *addr) = 0; 63 | }; 64 | 65 | class KSyms : SymbolCache { 66 | struct Symbol { 67 | Symbol(const char *name, const char *mod, uint64_t addr) : name(name), mod(mod), addr(addr) {} 68 | std::string name; 69 | std::string mod; 70 | uint64_t addr; 71 | 72 | bool operator<(const Symbol &rhs) const { return addr < rhs.addr; } 73 | }; 74 | 75 | std::vector syms_; 76 | std::unordered_map symnames_; 77 | static void _add_symbol(const char *, const char *, uint64_t, void *); 78 | 79 | public: 80 | virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle = true) override; 81 | virtual bool resolve_name(const char *unused, const char *name, 82 | uint64_t *addr) override; 83 | virtual void refresh() override; 84 | }; 85 | 86 | class ProcSyms : SymbolCache { 87 | struct NameIdx { 88 | size_t section_idx; 89 | size_t str_table_idx; 90 | size_t str_len; 91 | bool debugfile; 92 | }; 93 | 94 | struct Symbol { 95 | Symbol(const std::string *name, uint64_t start, uint64_t size) 96 | : is_name_resolved(true), start(start), size(size) { 97 | data.name = name; 98 | } 99 | Symbol(size_t section_idx, size_t str_table_idx, size_t str_len, uint64_t start, 100 | uint64_t size, bool debugfile) 101 | : is_name_resolved(false), start(start), size(size) { 102 | data.name_idx.section_idx = section_idx; 103 | data.name_idx.str_table_idx = str_table_idx; 104 | data.name_idx.str_len = str_len; 105 | data.name_idx.debugfile = debugfile; 106 | } 107 | bool is_name_resolved; 108 | union { 109 | struct NameIdx name_idx; 110 | const std::string *name{nullptr}; 111 | } data; 112 | uint64_t start; 113 | uint64_t size; 114 | 115 | bool operator<(const struct Symbol& rhs) const { 116 | return start < rhs.start; 117 | } 118 | }; 119 | 120 | enum class ModuleType { 121 | UNKNOWN, 122 | EXEC, 123 | SO, 124 | PERF_MAP, 125 | VDSO 126 | }; 127 | 128 | class ModulePath { 129 | // helper class to get a usable module path independent of the running 130 | // process by storing a file descriptor created from openat(2) if possible 131 | // if openat fails, falls back to process-dependent path with /proc/.../root 132 | private: 133 | int fd_; 134 | std::string proc_root_path_; 135 | std::string path_; 136 | 137 | public: 138 | ModulePath(const std::string &ns_path, int root_fd, int pid, bool enter_ns); 139 | const char *alt_path() { return proc_root_path_.c_str(); } 140 | const char *path() { 141 | if (path_ == proc_root_path_ || access(proc_root_path_.c_str(), F_OK) < 0) 142 | // cannot stat /proc/.../root/, pid might not exist anymore; use /proc/self/fd/... 143 | return path_.c_str(); 144 | return proc_root_path_.c_str(); 145 | } 146 | ~ModulePath() { 147 | if (fd_ > 0) 148 | close(fd_); 149 | } 150 | }; 151 | 152 | struct Module { 153 | struct Range { 154 | uint64_t start; 155 | uint64_t end; 156 | uint64_t file_offset; 157 | Range(uint64_t s, uint64_t e, uint64_t f) 158 | : start(s), end(e), file_offset(f) {} 159 | }; 160 | 161 | Module(const char *name, std::shared_ptr path, 162 | struct bcc_symbol_option *option); 163 | 164 | std::string name_; 165 | std::shared_ptr path_; 166 | std::vector ranges_; 167 | bool loaded_; 168 | bcc_symbol_option *symbol_option_; 169 | ModuleType type_; 170 | 171 | // The file offset within the ELF of the SO's first text section. 172 | uint64_t elf_so_offset_; 173 | uint64_t elf_so_addr_; 174 | 175 | std::unordered_set symnames_; 176 | std::vector syms_; 177 | 178 | void load_sym_table(); 179 | 180 | bool contains(uint64_t addr, uint64_t &offset) const; 181 | uint64_t start() const { return ranges_.begin()->start; } 182 | 183 | bool find_addr(uint64_t offset, struct bcc_symbol *sym); 184 | bool find_name(const char *symname, uint64_t *addr); 185 | 186 | static int _add_symbol(const char *symname, uint64_t start, uint64_t size, 187 | void *p); 188 | static int _add_symbol_lazy(size_t section_idx, size_t str_table_idx, 189 | size_t str_len, uint64_t start, uint64_t size, 190 | int debugfile, void *p); 191 | }; 192 | 193 | int pid_; 194 | std::vector modules_; 195 | ProcStat procstat_; 196 | bcc_symbol_option symbol_option_; 197 | 198 | static int _add_module(mod_info *, int, void *); 199 | void load_modules(); 200 | 201 | public: 202 | ProcSyms(int pid, struct bcc_symbol_option *option = nullptr); 203 | virtual void refresh() override; 204 | virtual bool resolve_addr(uint64_t addr, struct bcc_symbol *sym, bool demangle = true) override; 205 | virtual bool resolve_name(const char *module, const char *name, 206 | uint64_t *addr) override; 207 | }; 208 | 209 | class BuildSyms { 210 | struct Symbol { 211 | Symbol(const std::string *name, uint64_t start, uint64_t size) 212 | :name(name), start(start), size(size) {} 213 | const std::string *name; 214 | uint64_t start; 215 | uint64_t size; 216 | 217 | bool operator<(const struct Symbol &rhs) const { 218 | return start < rhs.start; 219 | } 220 | }; 221 | 222 | struct Module { 223 | Module(const char *module_name): 224 | module_name_(module_name), 225 | loaded_(false) {} 226 | const std::string module_name_; 227 | const std::string build_id_; 228 | bool loaded_; 229 | std::unordered_set symnames_; 230 | std::vector syms_; 231 | bcc_symbol_option symbol_option_; 232 | 233 | bool load_sym_table(); 234 | static int _add_symbol(const char *symname, uint64_t start, uint64_t size, 235 | void *p); 236 | bool resolve_addr(uint64_t offset, struct bcc_symbol*, bool demangle=true); 237 | }; 238 | 239 | std::unordered_map > buildmap_; 240 | 241 | public: 242 | BuildSyms() {} 243 | virtual ~BuildSyms() = default; 244 | virtual bool add_module(const std::string module_name); 245 | virtual bool resolve_addr(std::string build_id, uint64_t offset, struct bcc_symbol *sym, bool demangle = true); 246 | }; 247 | -------------------------------------------------------------------------------- /src/configuration/procmon_configuration.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "procmon_configuration.h" 18 | 19 | extern std::string debugTraceFile; 20 | extern bool debugTrace; 21 | 22 | void ProcmonConfiguration::HandlePidArgs(char *pidArgs) 23 | { 24 | std::stringstream pidStream(pidArgs); 25 | std::string pidString; 26 | while (getline(pidStream, pidString, ',')) 27 | { 28 | pid_t pid; 29 | try 30 | { 31 | pid = std::stoi(pidString, nullptr, 10); 32 | pids.push_back(pid); 33 | if(pids.size()>MAX_PIDS) 34 | { 35 | std::cerr << "Max number of pids (" << MAX_PIDS << ")" << " exceeded" << '\n'; 36 | CLIUtils::FastExit(); 37 | } 38 | } 39 | catch(const std::exception& e) 40 | { 41 | std::cerr << "ProcmonConfiguration::Invalid pid specified - " << e.what() << '\n'; 42 | CLIUtils::FastExit(); 43 | } 44 | } 45 | } 46 | 47 | void ProcmonConfiguration::HandleStorageArgs(char *storageArgs) 48 | { 49 | if (StorageProxy::IsValidStorageEngineType(storageArgs)) 50 | { 51 | storageEngineType = StorageProxy::GetStorageTypeForString(storageArgs); 52 | _storageEngine = std::shared_ptr(StorageProxy::StorageFactory(storageEngineType)); 53 | } 54 | else 55 | { 56 | std::cerr << "ProcmonConfiguration::\"" << storageArgs << "\" is not a valid storage engine" << std::endl; 57 | CLIUtils::FastExit(); 58 | } 59 | } 60 | 61 | void ProcmonConfiguration::HandleEventArgs(char *eventArgs) 62 | { 63 | std::stringstream eventStream(eventArgs); 64 | std::string eventString; 65 | while (getline(eventStream, eventString, ',')) 66 | { 67 | events.emplace_back(eventString); 68 | } 69 | } 70 | 71 | void ProcmonConfiguration::HandleLogArg(char * filepath) 72 | { 73 | if(filepath) 74 | { 75 | debugTraceFilePath = std::string(filepath); 76 | debugTrace = true; 77 | } 78 | } 79 | 80 | void ProcmonConfiguration::HandleFileArg(char * filepath) 81 | { 82 | std::ifstream testFilePath(filepath); 83 | if (!testFilePath) 84 | { 85 | std::cerr << "The specified promcon trace file doesn't exist" << std::endl; 86 | CLIUtils::FastExit(); 87 | } 88 | 89 | traceFilePath = std::string(filepath); 90 | } 91 | 92 | ProcmonConfiguration::ProcmonConfiguration(int argc, char *argv[]) 93 | { 94 | // get start time since EPOC for header 95 | epocStartTime = ConvertEpocTime(time(nullptr)); 96 | 97 | // get start time of procmon 98 | if(clock_gettime(CLOCK_MONOTONIC, &startTime) == -1) 99 | { 100 | LOG(ERROR) << "Failed to get start time"; 101 | exit(1); 102 | } 103 | 104 | LOG(DEBUG) << "Tv_sec " << startTime.tv_sec << " Tv_nsec " << startTime.tv_nsec; 105 | 106 | // setup default output trace file 107 | outputTraceFilePath = "procmon_" + date + "_" + epocStartTime + ".db"; 108 | 109 | static struct option long_options[] = 110 | { 111 | { "pids", required_argument, NULL, 'p' }, 112 | { "storageEngine", required_argument, NULL, 's' }, 113 | { "events", required_argument, NULL, 'e' }, 114 | { "collect", optional_argument, NULL, 'c' }, 115 | { "file", required_argument, NULL, 'f' }, 116 | { "log", required_argument, NULL, 'l' }, 117 | { "help", no_argument, NULL, 'h' }, 118 | { NULL, 0, NULL, 0 } 119 | }; 120 | 121 | int c = 0; 122 | int option_index = 0; 123 | while (true) 124 | { 125 | if ((c = getopt_long(argc, argv, "hc:p:s:e:f:l:", long_options, &option_index)) == -1) 126 | break; 127 | 128 | switch (c) 129 | { 130 | case 0: 131 | // We've encountered an unknown long arg!! 132 | CLIUtils::DisplayUsage(true); 133 | break; 134 | case 'p': 135 | HandlePidArgs(optarg); 136 | break; 137 | 138 | case 's': 139 | HandleStorageArgs(optarg); 140 | break; 141 | 142 | case 'e': 143 | HandleEventArgs(optarg); 144 | break; 145 | 146 | case 'c': 147 | { 148 | if(strlen(optarg) > 0) 149 | { 150 | outputTraceFilePath = std::string(optarg); 151 | } 152 | 153 | headless = true; 154 | break; 155 | } 156 | 157 | case 'f': 158 | HandleFileArg(optarg); 159 | break; 160 | 161 | case 'l': 162 | HandleLogArg(optarg); 163 | break; 164 | 165 | default: 166 | // Invalid argument 167 | CLIUtils::DisplayUsage(true); 168 | } 169 | } 170 | 171 | LOG(DEBUG) << "Output trace file:" << outputTraceFilePath; 172 | 173 | // Get schema of all syscalls on system 174 | syscallSchema = Utils::CollectSyscallSchema(); 175 | 176 | // if user has not specified any syscalls trace all events 177 | if(events.size() == 0) 178 | { 179 | for (auto i : syscalls) 180 | { 181 | events.push_back({i.name}); 182 | } 183 | } 184 | else 185 | { 186 | for (auto event : events) 187 | { 188 | auto search = std::find_if(syscallSchema.begin(), syscallSchema.end(), [event](auto s) -> bool {return event.Name().compare(s.syscallName) == 0; }); 189 | 190 | if (search == syscallSchema.end()) 191 | { 192 | // Invalid syscall passed to procmon 193 | std::cerr << "ERROR: Invalid syscall " << event.Name() << std::endl << std::endl; 194 | 195 | CLIUtils::DisplayUsage(true); 196 | } 197 | } 198 | } 199 | 200 | if (_storageEngine == nullptr) 201 | { 202 | // Use default storage engine 203 | _storageEngine = std::shared_ptr(StorageProxy::StorageFactory(StorageProxy::StorageEngineType::Sql)); 204 | } 205 | 206 | // Initialize Storage Engine 207 | _storageEngine->Initialize(events); 208 | 209 | // Initialize Tracer 210 | _tracerEngine = std::unique_ptr(new EbpfTracerEngine(_storageEngine, events, pids)); 211 | _tracerEngine->Initialize(); 212 | _tracerEngine->AddEvent(events); 213 | 214 | // List of all syscalls that contain pointer params 215 | pointerSyscalls = Utils::Linux64PointerSycalls; 216 | 217 | // Set initial state to running 218 | _tracerEngine->SetRunState(TRACER_RUNNING); 219 | } 220 | 221 | uint64_t ProcmonConfiguration::GetStartTime() 222 | { 223 | return startTime.tv_sec * 1000000000 + startTime.tv_nsec; 224 | } 225 | 226 | void ProcmonConfiguration::SetStartTime(uint64_t start) 227 | { 228 | startTime.tv_sec = start / 1000000000; 229 | startTime.tv_nsec = start % 1000000000; 230 | } 231 | 232 | std::string ProcmonConfiguration::ConvertEpocTime(time_t time) 233 | { 234 | char _buf[DEFAULT_TIMESTAMP_LENGTH]; 235 | char _date_buf[DEFAULT_DATESTAMP_LENGTH]; 236 | struct tm* _time; 237 | 238 | _time = localtime(&time); 239 | // prep datestamp 240 | strftime(_date_buf, DEFAULT_DATESTAMP_LENGTH, "%Y-%m-%d", _time); 241 | date = std::string(_date_buf); 242 | 243 | // prep timestamp 244 | strftime(_buf, DEFAULT_TIMESTAMP_LENGTH, "%T", _time); 245 | 246 | return std::string(_buf); 247 | } -------------------------------------------------------------------------------- /src/display/screen.h: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | MIT License 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #ifndef SCREEN_H 18 | #define SCREEN_H 19 | 20 | #include 21 | 22 | /* 23 | * Due to a conflict with ncurses OK macro and ebpf::StatusTuple::OK() 24 | * we have to undef OK and define a NCURSES_OK which is equivalent to 25 | * ncurses OK. 26 | */ 27 | #undef OK 28 | #define NCURSES_OK 0 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | #include "column.h" 35 | #include "screen_configuration.h" 36 | #include "event_formatter.h" 37 | #include "../configuration/procmon_configuration.h" 38 | 39 | // Symbol resolution code 40 | #include "bcc_elf.h" 41 | #include "bcc_perf_map.h" 42 | #include "bcc_proc.h" 43 | #include "bcc_syms.h" 44 | 45 | // default screen dimensions 46 | #define MINIMUM_HEIGHT 15 47 | #define MINIMUM_WIDTH 100 48 | #define HEADER_HEIGHT 2 49 | #define FOOTER_HEIGHT 1 50 | #define ROW_HEIGHT 1 51 | #define DEFAULT_COLUMN_VIEW_HEIGHT 10 52 | #define DEFAULT_STAT_VIEW_HEIGHT 15 53 | #define DEFAULT_HELP_VIEW_HEIGHT 15 54 | 55 | // default column sizes 56 | #define DEFAULT_TIME_COL_WIDTH 15 57 | #define DEFAULT_PID_COL_WIDTH 10 58 | #define DEFAULT_PROCESS_COL_WIDTH 25 59 | #define DEFAULT_OPERATION_COL_WIDTH 20 60 | #define DEFAULT_DURATION_COL_WIDTH 20 61 | #define DEFAULT_RESULT_COL_WIDTH 32 62 | 63 | // default column X positions 64 | #define DEFAULT_PID_COL_X (int)DEFAULT_TIME_COL_WIDTH 65 | #define DEFAULT_PROCESS_COL_X (int)(DEFAULT_PID_COL_X + DEFAULT_PID_COL_WIDTH) 66 | #define DEFAULT_OPERATION_COL_X (int)(DEFAULT_PROCESS_COL_X + DEFAULT_PROCESS_COL_WIDTH) 67 | #define DEFAULT_RESULT_COL_X (int)(DEFAULT_OPERATION_COL_X + DEFAULT_OPERATION_COL_WIDTH) 68 | #define DEFAULT_DURATION_COL_X (int)(DEFAULT_RESULT_COL_X + DEFAULT_RESULT_COL_WIDTH) 69 | #define DEFAULT_DETAIL_COL_X (int)(DEFAULT_DURATION_COL_X + DEFAULT_DURATION_COL_WIDTH) 70 | 71 | // default window positions 72 | #define HEADER_X 0 73 | #define HEADER_Y 0 74 | 75 | // default color scheme 76 | #define HEADER_COLOR 1 77 | #define MENU_COLOR 2 78 | #define COLUMN_HEADER_COLOR 3 79 | #define LINE_COLOR 4 80 | #define HIGHLIGHT_COLOR 5 81 | #define DETAIL_VIEW_BACKGROUND_COLOR 6 82 | #define SEARCH_HIGHLIGHT_COLOR 7 83 | #define MENU_COLOR_ERROR 8 84 | 85 | // default colors 86 | #define LIGHT_BLUE 33 87 | #define BLUE 35 88 | 89 | #define FOOTER_X 0 90 | 91 | #define MAX_CONTINUOUS_SCROLL 10 92 | #define MAX_REFRESH_ATTEMPTS 5 93 | 94 | // column view constants 95 | #define COLUMN_VIEW_Y_OFFSET 2 96 | 97 | class Screen { 98 | public: 99 | Screen(); 100 | ~Screen(); 101 | 102 | // public ncurses screen functions 103 | void initScreen(std::shared_ptr); 104 | void run(); 105 | void shutdownScreen(); 106 | void refreshScreen(); 107 | 108 | private: 109 | // procmon configuration 110 | std::shared_ptr configPtr; 111 | 112 | // screen configuration 113 | ScreenConfiguration screenConfig; 114 | 115 | // screen variables 116 | int screenH; 117 | int screenW; 118 | int columnHeight; 119 | int totalLines; 120 | int currentLine; 121 | int currentPage; 122 | int eventRefreshThreshold; 123 | 124 | // event variables 125 | int totalEvents; 126 | 127 | // detail view dimensions 128 | int detailViewHeight; 129 | int detailViewWidth; 130 | 131 | // Stat view dimensions 132 | int statViewHeight; 133 | int statViewWidth; 134 | 135 | // Help view dimensions 136 | int helpViewHeight; 137 | int helpViewWidth; 138 | 139 | // control variables for various views 140 | bool detailViewActive; 141 | bool filterPromptActive; 142 | bool searchPromptActive; 143 | int searchCount; 144 | std::string filter; 145 | bool columnSortViewActive; 146 | int columnSortLineSelection; 147 | bool statViewActive; 148 | bool helpViewActive; 149 | 150 | // ncurses windows 151 | WINDOW* root; 152 | WINDOW* headerWin; 153 | WINDOW* footerWin; 154 | WINDOW* detailWin; 155 | WINDOW* columnWin; 156 | WINDOW* statWin; 157 | WINDOW* helpWin; 158 | 159 | // columns 160 | Column* timeStampColumn; 161 | Column* pidColumn; 162 | Column* processColumn; 163 | Column* operationColumn; 164 | Column* resultColumn; 165 | Column* durationColumn; 166 | Column* detailColumn; 167 | 168 | // column map 169 | std::map columnMap; 170 | 171 | // ncurses panels 172 | PANEL* headerPanel; 173 | PANEL* footerPanel; 174 | PANEL* detailPanel; 175 | PANEL* columnPanel; 176 | PANEL* statPanel; 177 | PANEL* helpPanel; 178 | 179 | // screen data 180 | std::vector eventList; 181 | std::vector idList; 182 | 183 | // Symbol resolution 184 | std::unordered_map symEnginePidMap; 185 | bcc_symbol_option SymbolOption = {.use_debug_file = 1, 186 | .check_debug_file_crc = 1, 187 | .lazy_symbolize = 1, 188 | .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)}; 189 | 190 | 191 | // A list of formatters used to special case the output formatting on a per sys call basis 192 | // NOTE: The first element in the vector is always our default formatter with a syscall name of "". 193 | // When inserting formatters into this vector always push_back(). 194 | std::vector formatters; 195 | EventFormatter* GetFormatter(ITelemetry lineData); 196 | 197 | void InitializeFormatters(); 198 | 199 | // Core Initializers 200 | void initColors(); 201 | 202 | // Header Functions 203 | void initHeader(); 204 | void drawHeader(); 205 | void resizeHeader(); 206 | 207 | // Footer Functions 208 | void initFooter(); 209 | void drawFooterFkeys(); 210 | void resizeFooter(); 211 | 212 | // Footer View Functions 213 | void drawFilterPrompt(std::string filter); 214 | void drawSearchPrompt(std::string search, bool error); 215 | 216 | // View Initializers 217 | void initDetailView(); 218 | void initColumnView(); 219 | void initStatView(); 220 | void initHelpView(); 221 | 222 | // Column Initializers 223 | void initTimestampColumn(); 224 | void initPidColumn(); 225 | void initProcessColumn(); 226 | void initOperationColumn(); 227 | void initResultColumn(); 228 | void initDurationColumn(); 229 | void initDetailColumn(); 230 | 231 | // Column visibility Control 232 | void hideColumns(); 233 | void showColumns(); 234 | 235 | // Terminal management helpers 236 | int getUserInput(); 237 | void resize(); 238 | 239 | // Display event helpers 240 | void addLine(ITelemetry lineData); 241 | void displayEvents(std::vector screenData); 242 | void displaySearchEvents(std::vector idList, int searchCount); 243 | void toggleColumnSort(ScreenConfiguration::sort selectedColumn); 244 | int getTotalEventsOnScreen(); 245 | int getTotalLines(); 246 | int getCurrentPage(); 247 | 248 | // Scrolling Helpers 249 | void scrollUp(); 250 | void scrollDown(); 251 | void pageUp(); 252 | void pageDown(); 253 | void columnScrollUp(); 254 | void columnScrollDown(); 255 | 256 | // View Controls 257 | void showDetailView(); 258 | void closeDetailView(); 259 | void showHelpView(); 260 | void closeHelpView(); 261 | void showColumnView(); 262 | void closeColumnView(); 263 | void showStatView(); 264 | void closeStatView(); 265 | 266 | // Mouse Helper Functions 267 | void handleMouseEvent(MEVENT* event); 268 | 269 | // Helper Functions 270 | void toggleColumnHighlight(ScreenConfiguration::sort selectedColumn); 271 | void windowPrintFill(WINDOW * win, int colorPair, int x, int y, const char * fmt, ...); 272 | void windowPrintFillRight(WINDOW * win, int colorPair, int x, int y, const char * fmt, ...); 273 | std::string calculateDeltaTimestamp(uint64_t ebpfEventTimestamp); 274 | bool compareEventList(std::vector newEventList, std::vector oldEventList); 275 | 276 | // Screen Control Functions 277 | void resetScreen(); 278 | void clearScreen(); 279 | void redrawScreen(); 280 | void setLineColor(int y, int colorPair); 281 | 282 | std::string DecodeArguments(ITelemetry event); 283 | int FindSyscall(std::string& syscallName); 284 | bool ResolveSymbols(StackTrace* stack, pid_t pid); 285 | }; 286 | 287 | #endif // SCREEN_H 288 | -------------------------------------------------------------------------------- /src/tracer/ebpf/kern/procmonGenericEntry_rawtp.c: -------------------------------------------------------------------------------- 1 | /* 2 | Procmon-for-Linux 3 | 4 | Copyright (c) Microsoft Corporation 5 | 6 | All rights reserved. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #ifdef EBPF_CO_RE 24 | #include "vmlinux.h" 25 | #else 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #endif 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | #include "procmonEBPF_common.h" 45 | #include 46 | #include "procmonEBPF_maps.h" 47 | 48 | 49 | #define bpf_probe(dsc, size, src, str) \ 50 | if (str) \ 51 | bpf_probe_read_str((void*)dsc, size, (const void*)src); \ 52 | else \ 53 | bpf_probe_read((void*)dsc, size, src); 54 | 55 | 56 | // ------------------------------------------------------------------------------------------ 57 | // PopulateArguments 58 | // 59 | // Populates the event with the arguments for the syscall. 60 | // ------------------------------------------------------------------------------------------ 61 | __attribute__((always_inline)) 62 | static inline int PopulateArguments(enum ProcmonArgTag type, unsigned long arg, struct SyscallEvent * event, unsigned int* offset_ptr) 63 | { 64 | unsigned int len = 0; 65 | unsigned int str = 0; 66 | unsigned long src = arg; 67 | 68 | if (type == INT || type == LONG) 69 | { 70 | len = sizeof(long); 71 | src = (unsigned long)&arg; 72 | } 73 | else if (type == UNSIGNED_INT || type == UNSIGNED_LONG || type == SIZE_T || type == PID_T || type == PTR) 74 | { 75 | len = sizeof(unsigned long); 76 | src = (unsigned long)&arg; 77 | } 78 | else if (type == CHAR_PTR || type == CONST_CHAR_PTR) 79 | { 80 | len = MAX_BUFFER / 6; 81 | str = 1; 82 | } 83 | else if (type == FD) 84 | { 85 | len = MAX_BUFFER / 6; 86 | str = 1; 87 | char buff[len]; 88 | } 89 | else if (type == UINT32) 90 | { 91 | len = sizeof(uint32_t); 92 | src = (unsigned long)&arg; 93 | } 94 | else 95 | { 96 | // Do nothing here.... 97 | } 98 | 99 | if (*offset_ptr + len >= MAX_BUFFER) 100 | return -1; 101 | 102 | if (!src) 103 | return -1; 104 | 105 | bpf_probe(event->buffer + *offset_ptr, len, (void *)src, str) 106 | *offset_ptr += len; 107 | 108 | return 0; 109 | } 110 | 111 | // ------------------------------------------------------------------------------------------ 112 | // set_eventArgs 113 | // 114 | // Populates the event with the arguments for the syscall. 115 | // ------------------------------------------------------------------------------------------ 116 | __attribute__((always_inline)) 117 | static inline bool set_eventArgs(unsigned long *a, const struct pt_regs *regs) 118 | { 119 | int ret = 0; 120 | ret |= bpf_probe_read(&a[0], sizeof(a[0]), &SYSCALL_PT_REGS_PARM1(regs)); 121 | ret |= bpf_probe_read(&a[1], sizeof(a[1]), &SYSCALL_PT_REGS_PARM2(regs)); 122 | ret |= bpf_probe_read(&a[2], sizeof(a[2]), &SYSCALL_PT_REGS_PARM3(regs)); 123 | ret |= bpf_probe_read(&a[3], sizeof(a[3]), &SYSCALL_PT_REGS_PARM4(regs)); 124 | ret |= bpf_probe_read(&a[4], sizeof(a[4]), &SYSCALL_PT_REGS_PARM5(regs)); 125 | ret |= bpf_probe_read(&a[5], sizeof(a[5]), &SYSCALL_PT_REGS_PARM6(regs)); 126 | if (!ret) 127 | return true; 128 | else 129 | return false; 130 | } 131 | 132 | // ------------------------------------------------------------------------------------------ 133 | // GetRunningState 134 | // 135 | // Returns the running state 136 | // ------------------------------------------------------------------------------------------ 137 | __attribute__((always_inline)) 138 | static inline uint64_t GetRunningState() 139 | { 140 | uint64_t *state = NULL; 141 | int rkey = RUNSTATE_KEY; 142 | 143 | state = (uint64_t*)bpf_map_lookup_elem(&runstate, &rkey); 144 | if(state == NULL) 145 | { 146 | return -1; 147 | } 148 | 149 | return *state; 150 | } 151 | 152 | 153 | // ------------------------------------------------------------------------------------------ 154 | // MatchPidFilter 155 | // 156 | // Checks if the specified pid matches the pid filter 157 | // ------------------------------------------------------------------------------------------ 158 | __attribute__((always_inline)) 159 | static inline int IsProcmon() 160 | { 161 | char comm[16] = {0}; 162 | bpf_get_current_comm(comm, sizeof(comm)); 163 | 164 | if (comm[0] == 'p' && comm[1] == 'r' && comm[2] == 'o' && comm[3] == 'c' && comm[4] == 'm' && comm[5] == 'o' && comm[6] == 'n') 165 | { 166 | return 1; 167 | } 168 | 169 | return 0; 170 | } 171 | 172 | // ------------------------------------------------------------------------------------------ 173 | // MatchPidFilter 174 | // 175 | // Checks if the specified pid matches the pid filter 176 | // ------------------------------------------------------------------------------------------ 177 | __attribute__((always_inline)) 178 | static inline int MatchPidFilter(int pid) 179 | { 180 | for(int i=0; iargs[1]; 262 | uint32_t cpuId = bpf_get_smp_processor_id(); 263 | uint64_t pidTid = bpf_get_current_pid_tgid(); 264 | int pid = pidTid >> 32; 265 | struct pt_regs* regs = NULL; 266 | 267 | // 268 | // Check all filters 269 | // 270 | if(CheckFilters(pid) == 0) 271 | { 272 | return EBPF_RET_UNUSED; 273 | } 274 | 275 | // 276 | // Get the syscall details 277 | // 278 | struct SyscallSchema* schema = bpf_map_lookup_elem(&syscalls, &syscall); 279 | if(schema == NULL) 280 | { 281 | BPF_PRINTK("[genericRawEnter] Failed to get syscall schema %d.", syscall); 282 | return EBPF_RET_UNUSED; 283 | } 284 | 285 | // 286 | // Get temp storage to build up the event 287 | // 288 | struct SyscallEvent* sysEntry = bpf_map_lookup_elem(&eventStorageMap, &cpuId); 289 | if (!sysEntry) 290 | { 291 | BPF_PRINTK("[genericRawEnter] Failed to get storage for syscall event."); 292 | return EBPF_RET_UNUSED; 293 | } 294 | 295 | // 296 | // Populate the event 297 | // 298 | sysEntry->pid = pid; 299 | sysEntry->sysnum = ctx->args[1]; 300 | bpf_get_current_comm(&sysEntry->comm, sizeof(sysEntry->comm)); 301 | sysEntry->userStackCount = bpf_get_stack(ctx, &sysEntry->userStack, MAX_STACK_FRAMES * sizeof(uint64_t), BPF_F_USER_STACK) / sizeof(uint64_t); 302 | sysEntry->timestamp = bpf_ktime_get_ns(); 303 | 304 | regs = (struct pt_regs *)ctx->args[0]; 305 | unsigned long a[8]; 306 | if (!set_eventArgs(a, regs)) 307 | { 308 | BPF_PRINTK("[genericRawEnter] Failed to set_eventArgs\n"); 309 | return EBPF_RET_UNUSED; 310 | } 311 | 312 | unsigned int offset = 0; 313 | for (int i = 0; i < 6; i++) 314 | { 315 | if(PopulateArguments(schema->types[i], a[i], sysEntry, &offset) || i >= schema->usedArgCount) 316 | { 317 | break; 318 | } 319 | } 320 | 321 | // 322 | // Store the event to be retrieved and updated on exit 323 | // 324 | if (bpf_map_update_elem(&syscallsMap, &pidTid, sysEntry, BPF_ANY) != UPDATE_OKAY) 325 | { 326 | BPF_PRINTK("[genericRawEnter] Failed to update syscalls map\n"); 327 | return EBPF_RET_UNUSED; 328 | } 329 | 330 | return EBPF_RET_UNUSED; 331 | } --------------------------------------------------------------------------------