2020-01-18 08:38:21 +00:00
/*
* Copyright ( c ) 2018 - 2020 , Andreas Kling < kling @ serenityos . org >
2022-01-25 02:02:39 +00:00
* Copyright ( c ) 2022 , Alex Major
2020-01-18 08:38:21 +00:00
*
2021-04-22 08:24:48 +00:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-01-18 08:38:21 +00:00
*/
2021-05-15 10:34:40 +00:00
# include <AK/Assertions.h>
2021-02-11 21:43:18 +00:00
# include <AK/Debug.h>
2021-02-11 21:01:49 +00:00
# include <AK/Iterator.h>
# include <AK/Vector.h>
2022-05-01 20:57:24 +00:00
# include <Kernel/API/SyscallString.h>
2021-02-11 20:08:46 +00:00
# include <LibCore/ArgsParser.h>
2022-01-25 02:02:39 +00:00
# include <LibMain/Main.h>
2021-09-12 11:29:28 +00:00
# include <errno_codes.h>
2019-09-12 14:26:54 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2021-05-14 15:38:33 +00:00
# include <sys/mman.h>
2021-02-05 11:16:30 +00:00
# include <syscall.h>
2019-09-12 14:26:54 +00:00
# define SC_NARG 4
2020-03-08 09:36:51 +00:00
FlatPtr arg [ SC_NARG ] ;
2021-02-11 21:01:49 +00:00
char outbuf [ BUFSIZ ] ;
2019-09-12 14:26:54 +00:00
2023-02-28 21:01:46 +00:00
using Arguments = Vector < DeprecatedString > ;
2021-02-11 21:01:49 +00:00
using ArgIter = Arguments : : Iterator ;
static FlatPtr parse_from ( ArgIter & ) ;
2019-09-12 14:26:54 +00:00
2021-04-23 09:11:09 +00:00
template < >
struct AK : : Formatter < Syscall : : Function > : Formatter < StringView > {
2021-11-16 00:15:21 +00:00
ErrorOr < void > format ( FormatBuilder & builder , Syscall : : Function function )
2021-04-23 09:11:09 +00:00
{
return Formatter < StringView > : : format ( builder , to_string ( function ) ) ;
}
} ;
2022-01-25 02:02:39 +00:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2019-09-12 14:26:54 +00:00
{
2021-02-11 20:08:46 +00:00
bool output_buffer = false ;
bool list_syscalls = false ;
2023-02-28 21:01:46 +00:00
Arguments syscall_arguments ;
2021-02-11 20:08:46 +00:00
Core : : ArgsParser args_parser ;
2021-02-11 21:43:18 +00:00
args_parser . set_general_help (
" Enables you to do a direct syscall, even those that use a 'SC_*_params' buffer. \n "
" Arguments can be literal strings, numbers, the output buffer, or parameter buffers: \n "
" - Arguments that begin with a comma are stripped of the comma and treated as string arguments, for example ',0x0' or ',['. \n "
" - 'buf' is replaced by a pointer to the output buffer. \n "
" - Numbers can be written like 1234 or 0xDEADC0DE. \n "
" - Parameter buffer (e.g. SC_realpath_params) can be passed by wrapping them in '[' and ']'. Note that '[' and ']' must be separate arguments to syscall(1). Buffers can be used recursively. \n "
" - The first argument may also be any syscall function name. Run 'syscall -l' to see the list. \n "
" - Arguments that cannot be interpreted are treated as string arguments, for example 'Hello, friends!'. \n "
" \n "
" Full example: syscall -o realpath [ /usr/share/man/man2/getgid.md 1024 buf 1024 ] " ) ;
2021-04-23 09:11:09 +00:00
args_parser . add_option ( list_syscalls , " List all existing syscalls, and exit " , " list-syscalls " , ' l ' ) ;
2021-02-11 20:08:46 +00:00
args_parser . add_option ( output_buffer , " Output the contents of the buffer (beware of stray zero bytes!) " , " output-buffer " , ' o ' ) ;
2022-01-25 02:02:39 +00:00
args_parser . add_positional_argument ( syscall_arguments , " Syscall arguments; see general help. " , " syscall-arguments " , Core : : ArgsParser : : Required : : No ) ;
args_parser . parse ( arguments ) ;
2021-02-11 20:08:46 +00:00
2021-04-23 09:11:09 +00:00
if ( list_syscalls ) {
outln ( " syscall list: " ) ;
for ( int sc = 0 ; sc < Syscall : : Function : : __Count ; + + sc ) {
outln ( " \033 [33;1m{} \033 [0m - {} " , sc , static_cast < Syscall : : Function > ( sc ) ) ;
}
exit ( 0 ) ;
}
2022-01-25 02:02:39 +00:00
if ( syscall_arguments . is_empty ( ) ) {
2023-02-21 11:44:41 +00:00
args_parser . print_usage ( stderr , arguments . strings [ 0 ] ) ;
2021-04-23 09:11:09 +00:00
exit ( 1 ) ;
}
2022-01-25 02:02:39 +00:00
ArgIter iter = syscall_arguments . begin ( ) ;
2021-02-11 21:01:49 +00:00
for ( size_t i = 0 ; i < SC_NARG & & ! iter . is_end ( ) ; i + + ) {
arg [ i ] = parse_from ( iter ) ;
}
if ( ! iter . is_end ( ) ) {
2021-02-11 21:43:18 +00:00
warnln ( " Too many arguments (did you want to use '[ parameter buffers ]'?) " ) ;
2021-02-11 21:01:49 +00:00
return - 1 ;
2019-09-12 14:26:54 +00:00
}
2021-02-11 21:01:49 +00:00
if ( arg [ 0 ] > Syscall : : Function : : __Count ) {
for ( int sc = 0 ; sc < Syscall : : Function : : __Count ; + + sc ) {
2021-08-05 18:41:44 +00:00
if ( Syscall : : to_string ( ( Syscall : : Function ) sc ) = = ( char const * ) arg [ 0 ] ) {
2021-02-11 21:01:49 +00:00
arg [ 0 ] = sc ;
break ;
2019-09-12 14:26:54 +00:00
}
2021-02-11 21:01:49 +00:00
}
if ( arg [ 0 ] > Syscall : : Function : : __Count ) {
2021-02-11 21:43:18 +00:00
warnln ( " Invalid syscall entry {} " , ( char * ) arg [ 0 ] ) ;
2021-02-11 21:01:49 +00:00
return - 1 ;
2019-09-12 14:26:54 +00:00
}
}
2021-02-11 21:43:18 +00:00
dbgln_if ( SYSCALL_1_DEBUG , " Calling {} {:p} {:p} {:p} \n " , arg [ 0 ] , arg [ 1 ] , arg [ 2 ] , arg [ 3 ] ) ;
2021-02-11 21:01:49 +00:00
int rc = syscall ( arg [ 0 ] , arg [ 1 ] , arg [ 2 ] , arg [ 3 ] ) ;
if ( output_buffer )
fwrite ( outbuf , 1 , sizeof ( outbuf ) , stdout ) ;
2021-11-06 22:25:25 +00:00
if ( - rc > = 0 & & - rc < EMAXERRNO ) {
warnln ( " Syscall return: {} ({}) " , rc , strerror ( - rc ) ) ;
} else {
warnln ( " Syscall return: {} (?) " , rc ) ;
}
2021-02-11 21:01:49 +00:00
return 0 ;
}
static FlatPtr as_buf ( Vector < FlatPtr > params_vec )
{
size_t params_size = sizeof ( FlatPtr ) * params_vec . size ( ) ;
size_t buf_size = round_up_to_power_of_two ( params_size + 1 , PAGE_SIZE ) ;
void * buf = mmap ( nullptr , buf_size , PROT_READ | PROT_WRITE , MAP_ANON | MAP_PRIVATE , 0 , 0 ) ;
if ( buf = = MAP_FAILED ) {
fprintf ( stderr , " Warning: Could not allocate buffer of size %zu (low memory?) \n " , buf_size ) ;
exit ( 1 ) ;
}
// It's probably good to ensure zero-initialization.
memset ( buf , 0 , buf_size ) ;
memcpy ( buf , params_vec . data ( ) , params_size ) ;
2021-02-11 21:43:18 +00:00
if constexpr ( SYSCALL_1_DEBUG ) {
StringBuilder builder ;
2022-07-11 17:32:29 +00:00
builder . append ( " Prepared [ " sv ) ;
2021-02-11 21:43:18 +00:00
for ( size_t i = 0 ; i < params_vec . size ( ) ; + + i ) {
builder . appendff ( " {:p} " , params_vec [ i ] ) ;
}
builder . appendff ( " ] at {:p} " , ( FlatPtr ) buf ) ;
2022-12-06 01:12:49 +00:00
dbgln ( " {} " , builder . to_deprecated_string ( ) ) ;
2021-02-11 21:43:18 +00:00
}
2021-02-11 21:01:49 +00:00
// Leak the buffer here. We need to keep it until the special syscall happens,
// and we terminate immediately afterwards anyway.
return ( FlatPtr ) buf ;
2019-09-12 14:26:54 +00:00
}
2021-02-11 21:01:49 +00:00
static FlatPtr parse_parameter_buffer ( ArgIter & iter )
2019-09-12 14:26:54 +00:00
{
2021-02-11 21:01:49 +00:00
Vector < FlatPtr > params_vec ;
while ( ! iter . is_end ( ) ) {
2023-02-28 21:01:46 +00:00
if ( * iter = = " ] " sv ) {
2021-02-11 21:01:49 +00:00
+ + iter ;
return as_buf ( params_vec ) ;
}
2019-09-12 14:26:54 +00:00
2021-02-11 21:01:49 +00:00
params_vec . append ( parse_from ( iter ) ) ;
2019-09-12 14:26:54 +00:00
}
2021-02-13 09:55:51 +00:00
fprintf ( stderr , " Error: Unmatched '['?! \n " ) ;
2021-02-11 21:01:49 +00:00
exit ( 1 ) ;
2021-02-23 19:42:32 +00:00
VERIFY_NOT_REACHED ( ) ;
2021-02-11 21:01:49 +00:00
}
static FlatPtr parse_from ( ArgIter & iter )
{
2023-02-28 21:01:46 +00:00
auto const & this_arg_string = * iter ;
auto * this_arg = this_arg_string . characters ( ) ;
2021-02-11 21:01:49 +00:00
+ + iter ;
// Is it a forced literal?
2021-02-11 21:43:18 +00:00
if ( this_arg [ 0 ] = = ' , ' ) {
this_arg + = 1 ;
2023-02-28 21:01:46 +00:00
dbgln_if ( SYSCALL_1_DEBUG , " Using (forced) string >>{}<< at {:p} " , this_arg_string , ( FlatPtr ) this_arg ) ;
2021-02-11 21:43:18 +00:00
return ( FlatPtr ) this_arg ;
}
2021-02-11 21:01:49 +00:00
// Is it the output buffer?
2023-02-28 21:01:46 +00:00
if ( this_arg_string = = " buf " sv )
2021-02-11 21:01:49 +00:00
return ( FlatPtr ) outbuf ;
// Is it a parameter buffer?
2023-02-28 21:01:46 +00:00
if ( this_arg_string = = " [ " sv )
2021-02-11 21:01:49 +00:00
return parse_parameter_buffer ( iter ) ;
// Is it a number?
2023-02-28 21:01:46 +00:00
if ( auto l = this_arg_string . to_uint ( ) ; l . has_value ( ) )
return * l ;
2019-09-12 14:26:54 +00:00
2021-02-11 21:01:49 +00:00
// Then it must be a string:
2023-02-28 21:01:46 +00:00
if ( this_arg_string = = " ] " sv )
2021-02-11 21:01:49 +00:00
fprintf ( stderr , " Warning: Treating unmatched ']' as literal string \n " ) ;
2023-02-28 21:01:46 +00:00
dbgln_if ( SYSCALL_1_DEBUG , " Using (detected) string >>{}<< at {:p} " , this_arg_string , ( FlatPtr ) this_arg ) ;
2021-02-11 21:43:18 +00:00
2021-02-11 21:01:49 +00:00
return ( FlatPtr ) this_arg ;
2019-09-12 14:26:54 +00:00
}