From d740266afd89f654b16e94dcf3912be00185f43e Mon Sep 17 00:00:00 2001 From: Michael McGee Date: Fri, 18 Aug 2023 18:56:25 +0000 Subject: [PATCH] fddev: add debugging wrapper --- .vscode/launch.json | 37 ++++++++++++++ src/app/fddbg/Local.mk | 3 ++ src/app/fddbg/main.c | 113 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 src/app/fddbg/Local.mk create mode 100644 src/app/fddbg/main.c diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..5a3262759d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,37 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "fddev", + "type": "cppdbg", + "request": "launch", + "cwd": "${workspaceFolder}/build/native/gcc/bin", + "program": "${workspaceFolder}/build/native/gcc/bin/fddev", + "args": ["--no-sandbox"], + "miDebuggerPath": "${workspaceFolder}/build/native/gcc/bin/fddbg", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + }, + { + "description": "Don't detach on fork", + "text": "-gdb-set detach-on-fork off", + "ignoreFailures": false + }, + { + "description": "Stay parent after fork", + "text": "-gdb-set follow-fork-mode parent", + "ignoreFailures": false + } + ] + } + ] +} diff --git a/src/app/fddbg/Local.mk b/src/app/fddbg/Local.mk new file mode 100644 index 0000000000..4f5efd6914 --- /dev/null +++ b/src/app/fddbg/Local.mk @@ -0,0 +1,3 @@ +ifdef FD_HAS_HOSTED +$(call make-bin,fddbg,main,fd_util) +endif diff --git a/src/app/fddbg/main.c b/src/app/fddbg/main.c new file mode 100644 index 0000000000..dd36a28fdb --- /dev/null +++ b/src/app/fddbg/main.c @@ -0,0 +1,113 @@ +#define _GNU_SOURCE + +#include "../../util/fd_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +has_all_capabilities( void ) { + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; + + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; + FD_TEST( syscall( SYS_capget, &capheader, &capdata ) >= 0 ); + return + capdata[0].permitted == 0xFFFFFFFF && + ( capdata[1].permitted & 0x000001FF ) == 0x000001FF; +} + +static void +raise_all_capabilities( void ) { + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; + + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; + FD_TEST( syscall( SYS_capget, &capheader, &capdata ) >= 0 ); + + capdata[0].effective = 0xFFFFFFFF; + capdata[0].inheritable = 0xFFFFFFFF; + capdata[1].effective = 0xFFFFFFFF; + capdata[1].inheritable = 0xFFFFFFFF; + FD_TEST( syscall(SYS_capset, &capheader, &capdata) >= 0 ); + + for ( int cap = 0; cap <= CAP_LAST_CAP; cap++ ) + FD_TEST( !prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) ); +} + +static void +self_exe( char * path ) { + long count = readlink( "/proc/self/exe", path, PATH_MAX ); + FD_TEST( count >= 0 && count < PATH_MAX ); + path[ count ] = '\0'; +} + +int +main( int argc, + char ** argv ) { + fd_boot( &argc, &argv ); + + for( int i=0; i 1 && !strcmp( argv[1], "--setcap" ) ) ) { + struct vfs_cap_data { + __le32 magic_etc; // Always set to VFS_CAP_REVISION_2 + struct { + __le32 permitted; // Mask of permitted capabilities + __le32 inheritable; // Mask of inheritable capabilities + } data[2]; + } cap_data; + + cap_data.magic_etc = VFS_CAP_REVISION_2; + cap_data.data[0].permitted = 0xFFFFFFFF; + cap_data.data[0].inheritable = 0xFFFFFFFF; + cap_data.data[1].permitted = 0xFFFFFFFF; + cap_data.data[1].inheritable = 0xFFFFFFFF; + + char self_path[ PATH_MAX ]; + self_exe( self_path ); + FD_TEST( !setxattr( self_path, "security.capability", &cap_data, sizeof(cap_data), 0) ); + } else { + if( FD_UNLIKELY( !has_all_capabilities() ) ) { + if ( FD_UNLIKELY( argc > 1 && !strcmp( argv[1], "--withcap" ) ) ) FD_LOG_ERR(( "missing capabilities" )); + + char self_path[ PATH_MAX ]; + self_exe( self_path ); + + pid_t child = fork(); + FD_TEST( child >= 0 ); + if( child == 0 ) execv( "/bin/sudo", (char *[]){ "sudo", self_path, "--setcap", NULL } ); + else { + int wstatus; + FD_TEST( waitpid( child, &wstatus, 0 ) >= 0 ); + FD_TEST( WIFEXITED( wstatus ) && !WEXITSTATUS( wstatus ) ); + char self_path[ PATH_MAX ]; + self_exe( self_path ); + FD_TEST( execv( self_path, (char *[]){ "fddbg", "--withcap", NULL } ) >= 0 ); + } + } else { + raise_all_capabilities(); + + char * args[ 32 ]; + int start = argc > 1 && !strcmp( argv[1], "--withcap" ) ? 2 : 1; + args[0] = "/bin/gdb"; + for( int i=start; i= 0 ); + } + } +}