2016-04-12 00:05:43 +00:00
/*
* Check verbose decoding of seccomp SECCOMP_SET_MODE_FILTER .
*
* Copyright ( c ) 2015 - 2016 Dmitry V . Levin < ldv @ altlinux . org >
2018-06-14 11:00:00 +00:00
* Copyright ( c ) 2016 - 2018 The strace developers .
2016-04-12 00:05:43 +00:00
* All rights reserved .
*
2018-12-10 00:00:00 +00:00
* SPDX - License - Identifier : GPL - 2.0 - or - later
2016-04-12 00:05:43 +00:00
*/
# include "tests.h"
# include <errno.h>
# include <stddef.h>
# include <stdio.h>
2016-08-09 14:38:29 +00:00
# include <asm/unistd.h>
2016-04-12 00:05:43 +00:00
# include <unistd.h>
# ifdef HAVE_PRCTL
# include <sys / prctl.h>
# endif
# ifdef HAVE_LINUX_SECCOMP_H
# include <linux / seccomp.h>
# endif
2017-07-08 01:49:00 +00:00
# include <linux/filter.h>
2016-04-12 00:05:43 +00:00
# if defined __NR_seccomp \
& & defined PR_SET_NO_NEW_PRIVS \
& & defined SECCOMP_SET_MODE_FILTER \
& & defined SECCOMP_RET_ERRNO \
& & defined BPF_JUMP \
& & defined BPF_STMT
2018-12-30 15:35:21 +00:00
# define SOCK_FILTER_ALLOW_SYSCALL(nr) \
2016-04-12 00:05:43 +00:00
BPF_JUMP ( BPF_JMP | BPF_K | BPF_JEQ , __NR_ # # nr , 0 , 1 ) , \
BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_ALLOW )
2018-12-30 15:35:21 +00:00
# define SOCK_FILTER_DENY_SYSCALL(nr, err) \
2016-04-12 00:05:43 +00:00
BPF_JUMP ( BPF_JMP | BPF_K | BPF_JEQ , __NR_ # # nr , 0 , 1 ) , \
BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_ERRNO | ( SECCOMP_RET_DATA & ( err ) ) )
2018-12-30 15:35:21 +00:00
# define SOCK_FILTER_KILL_PROCESS \
2016-04-12 00:05:43 +00:00
BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_KILL )
2018-12-30 15:35:21 +00:00
# define PRINT_ALLOW_SYSCALL(nr) \
2016-04-12 00:05:43 +00:00
tprintf ( " BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#x, 0, 0x1), " \
" BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), " , \
__NR_ # # nr )
2018-12-30 15:35:21 +00:00
# define PRINT_DENY_SYSCALL(nr, err) \
2016-04-12 00:05:43 +00:00
tprintf ( " BPF_JUMP(BPF_JMP|BPF_K|BPF_JEQ, %#x, 0, 0x1), " \
" BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|%#x), " , \
__NR_ # # nr , err )
static const struct sock_filter filter_c [ ] = {
/* load syscall number */
BPF_STMT ( BPF_LD | BPF_W | BPF_ABS , offsetof ( struct seccomp_data , nr ) ) ,
/* allow syscalls */
SOCK_FILTER_ALLOW_SYSCALL ( close ) ,
SOCK_FILTER_ALLOW_SYSCALL ( exit ) ,
SOCK_FILTER_ALLOW_SYSCALL ( exit_group ) ,
/* deny syscalls */
SOCK_FILTER_DENY_SYSCALL ( sync , EBUSY ) ,
SOCK_FILTER_DENY_SYSCALL ( setsid , EPERM ) ,
/* kill process */
SOCK_FILTER_KILL_PROCESS
} ;
int
main ( void )
{
tprintf ( " %s " , " " ) ;
static const char kill_stmt_txt [ ] =
2017-11-01 02:02:21 +00:00
" BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL_THREAD) " ;
2016-04-12 00:05:43 +00:00
struct sock_filter * const filter =
tail_memdup ( filter_c , sizeof ( filter_c ) ) ;
struct sock_filter * const big_filter =
tail_alloc ( sizeof ( * big_filter ) * ( BPF_MAXINSNS + 1 ) ) ;
2017-03-16 13:46:36 +00:00
TAIL_ALLOC_OBJECT_CONST_PTR ( struct sock_fprog , prog ) ;
2016-04-12 00:05:43 +00:00
int fds [ 2 ] ;
if ( pipe ( fds ) )
perror_msg_and_fail ( " pipe " ) ;
if ( prctl ( PR_SET_NO_NEW_PRIVS , 1 , 0 , 0 , 0 ) )
perror_msg_and_skip ( " PR_SET_NO_NEW_PRIVS " ) ;
prog - > filter = filter + ARRAY_SIZE ( filter_c ) ;
prog - > len = 1 ;
syscall ( __NR_seccomp , SECCOMP_SET_MODE_FILTER , 0 , prog ) ;
tprintf ( " seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=1, filter=%p}) "
" = -1 EFAULT (%m) \n " , prog - > filter ) ;
prog - > filter = filter + ARRAY_SIZE ( filter_c ) - 1 ;
prog - > len = 3 ;
syscall ( __NR_seccomp , SECCOMP_SET_MODE_FILTER , 0 , prog ) ;
tprintf ( " seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=%u "
print_array: enhance printing of unfetchable object addresses
When umoven_func invocation fails to fetch data, it prints the faulty
address. If this happens to a subsequent umoven_func invocation,
the printed address may be undistinguishable from a valid data printed
by print_func, e.g. when the data is printed in a numeric form like
[0x1, 0x2, 0x3, 0xdefaced].
Fix this source of confusion by moving the printing of the faulty
address from umoven_func to print_array itself. This change renames
umoven_func to tfetch_mem_func and changes its semantics, so that
- tfetch_mem_func never prints anything;
- tfetch_mem_func returns true if the fetch succeeded,
and false otherwise.
* defs.h (print_array): Replace umoven_func argument with
tfetch_mem_func.
* util.c (print_array): Replace umoven_func argument with
tfetch_mem_func, document expected tfetch_mem_func return value
semantics. When tfetch_mem_func returns false, print either addr
or "... /* addr */" depending on the context (inside the array or not).
* bpf.c (print_ebpf_prog, print_bpf_prog_info,
BEGIN_BPF_CMD_DECODER(BPF_PROG_QUERY)): Replace umoven_or_printaddr
argument of print_array with tfetch_mem.
* bpf_filter.c (print_bpf_fprog): Likewise.
* btrfs.c (btrfs_print_logical_ino_container,
btrfs_print_ino_path_container, btrfs_print_qgroup_inherit,
btrfs_ioctl): Likewise.
* dm.c (dm_decode_dm_target_deps): Likewise.
* epoll.c (epoll_wait_common): Likewise.
* file_ioctl.c (file_ioctl): Likewise.
* ipc_sem.c (tprint_sembuf_array): Likewise.
* kexec.c (print_kexec_segments): Likewise.
* mem.c (SYS_FUNC(subpage_prot)): Likewise.
* net.c (print_getsockopt): Likewise.
* netlink.c (decode_nlmsgerr_attr_cookie): Likewise.
* netlink_netlink_diag.c (decode_netlink_diag_groups): Likewise.
* netlink_packet_diag.c (decode_packet_diag_mclist): Likewise.
* netlink_unix_diag.c (decode_unix_diag_inode): Likewise.
* nlattr.c (decode_nla_meminfo): Likewise.
* numa.c (print_nodemask, SYS_FUNC(move_pages),
* perf_ioctl.c (perf_ioctl_query_bpf): Likewise.
* poll.c (decode_poll_entering): Likewise.
* printsiginfo.c (print_siginfo_array): Likewise.
* rtnl_tc.c (decode_tca_stab_data): Likewise.
* sock.c (decode_ifconf): Likewise.
* uid.c (print_groups): Likewise.
* io.c (SYS_FUNC(io_submit), SYS_FUNC(io_getevents)): Replace
umoven_or_printaddr argument of print_array with tfetch_mem.
(tprint_iov_upto): Replace umoven_or_printaddr_ignore_syserror
with tfetch_mem_ignore_syserror.
* v4l2.c (print_v4l2_format_fmt): Replace umoven_or_printaddr argument
of print_array with tfetch_mem.
(print_v4l2_ext_controls): Replace umoven_or_printaddr_ignore_syserror
with tfetch_mem_ignore_syserror.
* mmsghdr.c (fetch_struct_mmsghdr_or_printaddr): Rename
to fetch_struct_mmsghdr_for_print, do not print address, return bool.
(decode_mmsgvec): Replace fetch_struct_mmsghdr_or_printaddr
with fetch_struct_mmsghdr_for_print.
* tests/aio.c (main): Update expected output.
* tests/bpf.c (print_BPF_PROG_QUERY_attr5): Likewise.
* tests/ioctl_perf-success.c (main): Likewise.
* tests/ioctl_v4l2.c (main): Update expected output.
* tests/kexec_load.c (main): Likewise.
* tests/mmsg_name.c (test_mmsg_name): Update expected output.
* tests/move_pages.c (print_page_array, print_node_array): Likewise.
* tests/poll.c (print_pollfd_array_entering): Likewise.
* tests/preadv-pwritev.c (main): Likewise.
* tests/preadv2-pwritev2.c (dumpio): Likewise.
* tests/process_vm_readv_writev.c (print_iov): Likewise.
* tests/pwritev.c (print_iovec): Likewise.
* tests/readv.c (main): Likewise.
* tests/seccomp-filter-v.c
* tests/semop.c (main): Likewise.
* tests/set_mempolicy.c (print_nodes): Likewise.
* tests/setgroups.c (main): Likewise.
* tests/test_nlattr.h (print_nlattr) Likewise.
Co-Authored-by: Eugene Syromyatnikov <evgsyr@gmail.com>
2018-05-29 01:15:19 +00:00
" , filter=[%s, ... /* %p */]}) = -1 EFAULT (%m) \n " ,
2016-04-12 00:05:43 +00:00
prog - > len , kill_stmt_txt , filter + ARRAY_SIZE ( filter_c ) ) ;
prog - > len = 0 ;
syscall ( __NR_seccomp , SECCOMP_SET_MODE_FILTER , 0 , prog ) ;
2016-05-07 23:11:52 +00:00
tprintf ( " seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=0, filter=[]}) "
" = -1 EINVAL (%m) \n " ) ;
2016-04-12 00:05:43 +00:00
unsigned int i ;
for ( i = 0 ; i < = BPF_MAXINSNS ; + + i ) {
const struct sock_filter stmt =
BPF_STMT ( BPF_CLASS ( i ) , i < < 16 ) ;
big_filter [ i ] = stmt ;
}
prog - > filter = big_filter ;
prog - > len = BPF_MAXINSNS + 1 ;
tprintf ( " seccomp(SECCOMP_SET_MODE_FILTER, %s, {len=%u, filter=[ " ,
2018-05-23 12:24:05 +02:00
" SECCOMP_FILTER_FLAG_TSYNC|SECCOMP_FILTER_FLAG_LOG| "
2019-01-05 21:14:42 +00:00
" SECCOMP_FILTER_FLAG_SPEC_ALLOW| "
" SECCOMP_FILTER_FLAG_NEW_LISTENER|0xfffffff0 " ,
2017-11-01 01:50:59 +00:00
prog - > len ) ;
2016-04-12 00:05:43 +00:00
for ( i = 0 ; i < BPF_MAXINSNS ; + + i ) {
if ( i )
tprintf ( " , " ) ;
2017-06-17 22:23:09 +00:00
switch ( BPF_CLASS ( i ) ) {
2016-04-12 00:05:43 +00:00
case BPF_LD :
tprintf ( " BPF_STMT(BPF_LD|BPF_W|BPF_IMM, %#x) " , i < < 16 ) ;
break ;
case BPF_LDX :
tprintf ( " BPF_STMT(BPF_LDX|BPF_W|BPF_IMM, %#x) " , i < < 16 ) ;
break ;
case BPF_ST :
tprintf ( " BPF_STMT(BPF_ST, %#x) " , i < < 16 ) ;
break ;
case BPF_STX :
tprintf ( " BPF_STMT(BPF_STX, %#x) " , i < < 16 ) ;
break ;
case BPF_ALU :
tprintf ( " BPF_STMT(BPF_ALU|BPF_K|BPF_ADD, %#x) " , i < < 16 ) ;
break ;
case BPF_JMP :
tprintf ( " BPF_STMT(BPF_JMP|BPF_K|BPF_JA, %#x) " , i < < 16 ) ;
break ;
case BPF_RET :
tprintf ( " BPF_STMT(BPF_RET|BPF_K, %#x "
" /* SECCOMP_RET_??? */) " , i < < 16 ) ;
break ;
case BPF_MISC :
tprintf ( " BPF_STMT(BPF_MISC|BPF_TAX, %#x) " , i < < 16 ) ;
break ;
}
}
tprintf ( " , ...]}) " ) ;
syscall ( __NR_seccomp , SECCOMP_SET_MODE_FILTER , - 1 , prog ) ;
tprintf ( " = -1 EINVAL (%m) \n " ) ;
prog - > filter = filter ;
prog - > len = ARRAY_SIZE ( filter_c ) ;
tprintf ( " seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=%u, filter=[ " ,
prog - > len ) ;
tprintf ( " BPF_STMT(BPF_LD|BPF_W|BPF_ABS, %#x), " ,
( unsigned ) offsetof ( struct seccomp_data , nr ) ) ;
PRINT_ALLOW_SYSCALL ( close ) ;
PRINT_ALLOW_SYSCALL ( exit ) ;
PRINT_ALLOW_SYSCALL ( exit_group ) ;
PRINT_DENY_SYSCALL ( sync , EBUSY ) ,
PRINT_DENY_SYSCALL ( setsid , EPERM ) ,
tprintf ( " %s]}) = 0 \n +++ exited with 0 +++ \n " , kill_stmt_txt ) ;
if ( syscall ( __NR_seccomp , SECCOMP_SET_MODE_FILTER , 0 , prog ) )
perror_msg_and_skip ( " SECCOMP_SET_MODE_FILTER " ) ;
if ( close ( 0 ) | | close ( 1 ) )
_exit ( 77 ) ;
_exit ( 0 ) ;
}
# else
SKIP_MAIN_UNDEFINED ( " __NR_seccomp && PR_SET_NO_NEW_PRIVS "
" && SECCOMP_SET_MODE_FILTER && SECCOMP_RET_ERRNO "
" && BPF_JUMP && BPF_STMT " )
# endif