2017-07-19 10:07:34 +00:00
/*
* Copyright ( c ) 2016 Fabien Siron < fabien . siron @ epita . fr >
* Copyright ( c ) 2017 JingPiao Chen < chenjingpiao @ gmail . com >
2018-02-13 22:00:00 +00:00
* Copyright ( c ) 2017 - 2018 The strace developers .
2017-07-19 10:07:34 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "defs.h"
# include "netlink.h"
# include "netlink_sock_diag.h"
# include "nlattr.h"
# include "print_fields.h"
# include <arpa/inet.h>
# include <linux/sock_diag.h>
# include <linux/inet_diag.h>
# include "xlat/inet_diag_attrs.h"
# include "xlat/inet_diag_bytecodes.h"
# include "xlat/inet_diag_extended_flags.h"
# include "xlat/inet_diag_req_attrs.h"
# include "xlat/tcp_states.h"
# include "xlat/tcp_state_flags.h"
void
print_inet_diag_sockid ( const struct inet_diag_sockid * id , const uint8_t family )
{
PRINT_FIELD_NET_PORT ( " { " , * id , idiag_sport ) ;
PRINT_FIELD_NET_PORT ( " , " , * id , idiag_dport ) ;
PRINT_FIELD_INET_ADDR ( " , " , * id , idiag_src , family ) ;
PRINT_FIELD_INET_ADDR ( " , " , * id , idiag_dst , family ) ;
PRINT_FIELD_IFINDEX ( " , " , * id , idiag_if ) ;
PRINT_FIELD_COOKIE ( " , " , * id , idiag_cookie ) ;
tprints ( " } " ) ;
}
static void
decode_inet_diag_hostcond ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len )
{
struct inet_diag_hostcond cond ;
if ( len < sizeof ( cond ) ) {
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
return ;
}
if ( umove_or_printaddr ( tcp , addr , & cond ) )
return ;
PRINT_FIELD_XVAL ( " { " , cond , family , addrfams , " AF_??? " ) ;
PRINT_FIELD_U ( " , " , cond , prefix_len ) ;
PRINT_FIELD_U ( " , " , cond , port ) ;
if ( len > sizeof ( cond ) ) {
tprints ( " , " ) ;
decode_inet_addr ( tcp , addr + sizeof ( cond ) ,
2017-08-21 11:30:47 +00:00
len - sizeof ( cond ) , cond . family , " addr " ) ;
2017-07-19 10:07:34 +00:00
}
tprints ( " } " ) ;
}
static void
print_inet_diag_bc_op ( const struct inet_diag_bc_op * const op )
{
PRINT_FIELD_XVAL ( " { " , * op , code , inet_diag_bytecodes ,
" INET_DIAG_BC_??? " ) ;
PRINT_FIELD_U ( " , " , * op , yes ) ;
PRINT_FIELD_U ( " , " , * op , no ) ;
tprints ( " } " ) ;
}
static void
decode_inet_diag_markcond ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len )
{
struct inet_diag_markcond markcond ;
if ( len < sizeof ( markcond ) )
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
else if ( ! umove_or_printaddr ( tcp , addr , & markcond ) ) {
PRINT_FIELD_U ( " { " , markcond , mark ) ;
PRINT_FIELD_U ( " , " , markcond , mask ) ;
tprints ( " } " ) ;
}
}
static void
decode_bytecode_data ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const unsigned char code )
{
switch ( code ) {
case INET_DIAG_BC_S_COND :
case INET_DIAG_BC_D_COND :
decode_inet_diag_hostcond ( tcp , addr , len ) ;
break ;
case INET_DIAG_BC_DEV_COND : {
uint32_t ifindex ;
if ( len < sizeof ( ifindex ) )
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
else if ( ! umove_or_printaddr ( tcp , addr , & ifindex ) )
print_ifindex ( ifindex ) ;
break ;
}
case INET_DIAG_BC_S_GE :
case INET_DIAG_BC_S_LE :
case INET_DIAG_BC_D_GE :
case INET_DIAG_BC_D_LE : {
struct inet_diag_bc_op op ;
if ( len < sizeof ( op ) )
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
else if ( ! umove_or_printaddr ( tcp , addr , & op ) )
print_inet_diag_bc_op ( & op ) ;
break ;
}
case INET_DIAG_BC_MARK_COND :
decode_inet_diag_markcond ( tcp , addr , len ) ;
break ;
case INET_DIAG_BC_AUTO :
case INET_DIAG_BC_JMP :
case INET_DIAG_BC_NOP :
default :
printstr_ex ( tcp , addr , len , QUOTE_FORCE_HEX ) ;
break ;
}
}
static bool
decode_inet_diag_bc_op ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct inet_diag_bc_op op ;
if ( len < sizeof ( op ) )
return false ;
if ( umove_or_printaddr ( tcp , addr , & op ) )
return true ;
if ( len > sizeof ( op ) )
tprints ( " { " ) ;
print_inet_diag_bc_op ( & op ) ;
if ( len > sizeof ( op ) ) {
tprints ( " , " ) ;
decode_bytecode_data ( tcp , addr + sizeof ( op ) ,
len - sizeof ( op ) , op . code ) ;
tprints ( " } " ) ;
}
return true ;
}
static const nla_decoder_t inet_diag_req_nla_decoders [ ] = {
[ INET_DIAG_REQ_BYTECODE ] = decode_inet_diag_bc_op
} ;
static void
decode_inet_diag_req_compat ( struct tcb * const tcp ,
const struct nlmsghdr * const nlmsghdr ,
const uint8_t family ,
const kernel_ulong_t addr ,
const unsigned int len )
{
struct inet_diag_req req = { . idiag_family = family } ;
size_t offset = sizeof ( req . idiag_family ) ;
bool decode_nla = false ;
PRINT_FIELD_XVAL ( " { " , req , idiag_family , addrfams , " AF_??? " ) ;
tprints ( " , " ) ;
if ( len > = sizeof ( req ) ) {
if ( ! umoven_or_printaddr ( tcp , addr + offset ,
sizeof ( req ) - offset ,
2018-01-22 13:24:40 +01:00
( char * ) & req + offset ) ) {
2017-07-19 10:07:34 +00:00
PRINT_FIELD_U ( " " , req , idiag_src_len ) ;
PRINT_FIELD_U ( " , " , req , idiag_dst_len ) ;
PRINT_FIELD_FLAGS ( " , " , req , idiag_ext ,
inet_diag_extended_flags ,
" 1<<INET_DIAG_ \ ? \ ? \ ?-1 " ) ;
PRINT_FIELD_INET_DIAG_SOCKID ( " , " , req , id ,
req . idiag_family ) ;
PRINT_FIELD_FLAGS ( " , " , req , idiag_states ,
tcp_state_flags , " 1<<TCP_??? " ) ;
PRINT_FIELD_U ( " , " , req , idiag_dbs ) ;
decode_nla = true ;
}
} else
tprints ( " ... " ) ;
tprints ( " } " ) ;
2017-07-19 22:55:53 +08:00
offset = NLMSG_ALIGN ( sizeof ( req ) ) ;
2017-07-19 10:07:34 +00:00
if ( decode_nla & & len > offset ) {
tprints ( " , " ) ;
decode_nlattr ( tcp , addr + offset , len - offset ,
inet_diag_req_attrs , " INET_DIAG_REQ_??? " ,
inet_diag_req_nla_decoders ,
ARRAY_SIZE ( inet_diag_req_nla_decoders ) , NULL ) ;
}
}
static void
decode_inet_diag_req_v2 ( struct tcb * const tcp ,
const struct nlmsghdr * const nlmsghdr ,
const uint8_t family ,
const kernel_ulong_t addr ,
const unsigned int len )
{
struct inet_diag_req_v2 req = { . sdiag_family = family } ;
size_t offset = sizeof ( req . sdiag_family ) ;
bool decode_nla = false ;
PRINT_FIELD_XVAL ( " { " , req , sdiag_family , addrfams , " AF_??? " ) ;
tprints ( " , " ) ;
if ( len > = sizeof ( req ) ) {
if ( ! umoven_or_printaddr ( tcp , addr + offset ,
sizeof ( req ) - offset ,
2018-01-22 13:24:40 +01:00
( char * ) & req + offset ) ) {
2017-07-19 10:07:34 +00:00
PRINT_FIELD_XVAL ( " " , req , sdiag_protocol ,
inet_protocols , " IPPROTO_??? " ) ;
PRINT_FIELD_FLAGS ( " , " , req , idiag_ext ,
inet_diag_extended_flags ,
" 1<<INET_DIAG_ \ ? \ ? \ ?-1 " ) ;
PRINT_FIELD_FLAGS ( " , " , req , idiag_states ,
tcp_state_flags , " 1<<TCP_??? " ) ;
PRINT_FIELD_INET_DIAG_SOCKID ( " , " , req , id ,
req . sdiag_family ) ;
decode_nla = true ;
}
} else
tprints ( " ... " ) ;
tprints ( " } " ) ;
2017-07-19 22:55:53 +08:00
offset = NLMSG_ALIGN ( sizeof ( req ) ) ;
2017-07-19 10:07:34 +00:00
if ( decode_nla & & len > offset ) {
tprints ( " , " ) ;
decode_nlattr ( tcp , addr + offset , len - offset ,
inet_diag_req_attrs , " INET_DIAG_REQ_??? " ,
inet_diag_req_nla_decoders ,
ARRAY_SIZE ( inet_diag_req_nla_decoders ) , NULL ) ;
}
}
DECL_NETLINK_DIAG_DECODER ( decode_inet_diag_req )
{
if ( nlmsghdr - > nlmsg_type = = TCPDIAG_GETSOCK
| | nlmsghdr - > nlmsg_type = = DCCPDIAG_GETSOCK )
2018-01-22 13:22:17 +01:00
decode_inet_diag_req_compat ( tcp , nlmsghdr , family , addr , len ) ;
2017-07-19 10:07:34 +00:00
else
2018-01-22 13:22:17 +01:00
decode_inet_diag_req_v2 ( tcp , nlmsghdr , family , addr , len ) ;
2017-07-19 10:07:34 +00:00
}
static bool
decode_inet_diag_meminfo ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct inet_diag_meminfo minfo ;
if ( len < sizeof ( minfo ) )
return false ;
if ( umove_or_printaddr ( tcp , addr , & minfo ) )
return true ;
PRINT_FIELD_U ( " { " , minfo , idiag_rmem ) ;
PRINT_FIELD_U ( " , " , minfo , idiag_wmem ) ;
PRINT_FIELD_U ( " , " , minfo , idiag_fmem ) ;
PRINT_FIELD_U ( " , " , minfo , idiag_tmem ) ;
tprints ( " } " ) ;
return true ;
}
static bool
decode_tcpvegas_info ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct tcpvegas_info vegas ;
if ( len < sizeof ( vegas ) )
return false ;
if ( umove_or_printaddr ( tcp , addr , & vegas ) )
return true ;
PRINT_FIELD_U ( " { " , vegas , tcpv_enabled ) ;
PRINT_FIELD_U ( " , " , vegas , tcpv_rttcnt ) ;
PRINT_FIELD_U ( " , " , vegas , tcpv_rtt ) ;
PRINT_FIELD_U ( " , " , vegas , tcpv_minrtt ) ;
tprints ( " } " ) ;
return true ;
}
static bool
decode_tcp_dctcp_info ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct tcp_dctcp_info dctcp ;
if ( len < sizeof ( dctcp ) )
return false ;
if ( umove_or_printaddr ( tcp , addr , & dctcp ) )
return true ;
PRINT_FIELD_U ( " { " , dctcp , dctcp_enabled ) ;
PRINT_FIELD_U ( " , " , dctcp , dctcp_ce_state ) ;
PRINT_FIELD_U ( " , " , dctcp , dctcp_alpha ) ;
PRINT_FIELD_U ( " , " , dctcp , dctcp_ab_ecn ) ;
PRINT_FIELD_U ( " , " , dctcp , dctcp_ab_tot ) ;
tprints ( " } " ) ;
return true ;
}
static bool
decode_tcp_bbr_info ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct tcp_bbr_info bbr ;
if ( len < sizeof ( bbr ) )
return false ;
if ( umove_or_printaddr ( tcp , addr , & bbr ) )
return true ;
PRINT_FIELD_X ( " { " , bbr , bbr_bw_lo ) ;
PRINT_FIELD_X ( " , " , bbr , bbr_bw_hi ) ;
PRINT_FIELD_U ( " , " , bbr , bbr_min_rtt ) ;
PRINT_FIELD_U ( " , " , bbr , bbr_pacing_gain ) ;
PRINT_FIELD_U ( " , " , bbr , bbr_cwnd_gain ) ;
tprints ( " } " ) ;
return true ;
}
2018-10-26 01:42:34 +02:00
static bool
decode_tcp_md5sig ( struct tcb * const tcp ,
const kernel_ulong_t addr ,
const unsigned int len ,
const void * const opaque_data )
{
struct tcp_diag_md5sig sig ;
if ( len < sizeof ( sig ) )
return false ;
kernel_ulong_t l = len ;
kernel_ulong_t a = addr ;
for ( ; len > = sizeof ( sig ) ; l - = sizeof ( sig ) , a + = sizeof ( sig ) ) {
if ( a ! = addr )
tprints ( " , " ) ;
if ( umove ( tcp , a , & sig ) ) {
tprints ( " /* " ) ;
printaddr ( a ) ;
tprints ( " */ " ) ;
return true ;
}
PRINT_FIELD_XVAL ( " { " , sig , tcpm_family , addrfams , " AF_??? " ) ;
PRINT_FIELD_U ( " , " , sig , tcpm_prefixlen ) ;
PRINT_FIELD_U ( " , " , sig , tcpm_keylen ) ;
PRINT_FIELD_INET_ADDR ( " , " , sig , tcpm_addr , sig . tcpm_family ) ;
tprints ( " , " ) ;
print_quoted_string ( ( char * ) sig . tcpm_key ,
MIN ( sizeof ( sig . tcpm_key ) , sig . tcpm_keylen ) ,
QUOTE_FORCE_HEX ) ;
tprints ( " } " ) ;
}
if ( l ) {
tprints ( " , " ) ;
tprintf_comment ( " % " PRI_klu " bytes of unexpected data " , l ) ;
}
return true ;
}
2017-07-19 10:07:34 +00:00
static const nla_decoder_t inet_diag_msg_nla_decoders [ ] = {
[ INET_DIAG_MEMINFO ] = decode_inet_diag_meminfo ,
[ INET_DIAG_INFO ] = NULL , /* unimplemented */
[ INET_DIAG_VEGASINFO ] = decode_tcpvegas_info ,
[ INET_DIAG_CONG ] = decode_nla_str ,
[ INET_DIAG_TOS ] = decode_nla_u8 ,
[ INET_DIAG_TCLASS ] = decode_nla_u8 ,
[ INET_DIAG_SKMEMINFO ] = decode_nla_meminfo ,
[ INET_DIAG_SHUTDOWN ] = decode_nla_u8 ,
[ INET_DIAG_DCTCPINFO ] = decode_tcp_dctcp_info ,
[ INET_DIAG_PROTOCOL ] = decode_nla_u8 ,
[ INET_DIAG_SKV6ONLY ] = decode_nla_u8 ,
[ INET_DIAG_LOCALS ] = NULL , /* unimplemented */
[ INET_DIAG_PEERS ] = NULL , /* unimplemented */
[ INET_DIAG_PAD ] = NULL ,
[ INET_DIAG_MARK ] = decode_nla_u32 ,
2017-09-16 17:44:29 +00:00
[ INET_DIAG_BBRINFO ] = decode_tcp_bbr_info ,
2018-10-26 01:42:34 +02:00
[ INET_DIAG_CLASS_ID ] = decode_nla_u32 ,
[ INET_DIAG_MD5SIG ] = decode_tcp_md5sig ,
2017-07-19 10:07:34 +00:00
} ;
DECL_NETLINK_DIAG_DECODER ( decode_inet_diag_msg )
{
struct inet_diag_msg msg = { . idiag_family = family } ;
size_t offset = sizeof ( msg . idiag_family ) ;
bool decode_nla = false ;
PRINT_FIELD_XVAL ( " { " , msg , idiag_family , addrfams , " AF_??? " ) ;
tprints ( " , " ) ;
if ( len > = sizeof ( msg ) ) {
if ( ! umoven_or_printaddr ( tcp , addr + offset ,
sizeof ( msg ) - offset ,
2018-01-22 13:24:40 +01:00
( char * ) & msg + offset ) ) {
2017-07-19 10:07:34 +00:00
PRINT_FIELD_XVAL ( " " , msg , idiag_state ,
tcp_states , " TCP_??? " ) ;
PRINT_FIELD_U ( " , " , msg , idiag_timer ) ;
PRINT_FIELD_U ( " , " , msg , idiag_retrans ) ;
PRINT_FIELD_INET_DIAG_SOCKID ( " , " , msg , id ,
msg . idiag_family ) ;
PRINT_FIELD_U ( " , " , msg , idiag_expires ) ;
PRINT_FIELD_U ( " , " , msg , idiag_rqueue ) ;
PRINT_FIELD_U ( " , " , msg , idiag_wqueue ) ;
Decode UID/GID in -y mode
* defs.h (RVAL_UID, RVAL_GID): New macro constants.
(printgid): New function declaration.
* ipc_msgctl.c (print_msqid_ds, print_msqid_ds): Use printgid for
printing GID.
* ipc_shmctl.c (print_shmid_ds, print_shmid_ds): Likewise.
* keyctl.c (keyctl_chown_key): Likewise.
* nlattr.c (decode_nla_gid): Likewise.
* linux/dummy.h (sys_getgid, sys_getgid16, sys_getresgid,
sys_getresgid16, sys_setfsgid, sys_setfsgid16, sys_setgid, sys_setgid16,
sys_setregid, sys_setregid16, sys_setresgid, sys_setresgid16): Remove
macros.
(sys_getegid): Define to sys_getgid instead of sys_getuid.
(sys_getegid16): Define to sys_getgid16 instead of sys_geteuid16.
* linux/syscall.h (getresgid16, getgid16, setfsgid16, setresgid16,
setregid16, setgid16): New external SYS_FUNC declarations.
* msghdr.c (print_scm_creds); Use PRINT_FIELD_GID for printing GID.
* net.c (print_get_ucred): Likewise.
* netlink_inet_diag.c (decode_inet_diag_msg): Likewise.
* netlink_smc_diag.c (decode_smc_diag_msg): Likewise.
* print_fields.h (PRINT_FIELD_UID); Use printuid for printing UID.
(PRINT_FIELD_GID): New macro.
* print_struct_stat.c (print_struct_stat): Use printuid for printing
UID, printgid for printing GID.
* printsiginfo.c (printsigsource): Use printuid for printing UID.
* resource.c (print_priority_who): New function.
(SYS_FUNC(getpriority), SYS_FUNC(setpriority)): Use print_priority_who
for printing the second argument.
* statx.c (SYS_FUNC(statx)): Use PRINT_FIELD_UID for printing UID,
PRINT_FIELD_GID for printing GID.
* syscall.c (syscall_exiting_trace): Handle RVAL_UID and RVAL_GID.
* tests/overflowuid.c: Include stdio.h.
(printuid): New function.
* tests/setfsugid.c (printugid): Rename from printuid, update call
sites.
* tests/setgroups.c: Likewise.
* tests/setugid.c: Likewise.
* tests/tests.h (printuid): New declaration.
* uid.c (printgid, sys_getresgid, sys_getgid, sys_setfsgid,
sys_setresgid, sys_setregid, sys_setgid): Add SIZEIFY wrappers.
(gid_t, gid_t_, gid_t__): Define similarly to uid_t, uid_t_, uid_t__.
Include grp.h, pwd.h, sys/types.h.
(enum id_type): New enumeration.
(SYS_FUNC(getuid), SYS_FUNC(setfsuid), ): Return RVAL_UID flag.
(SYS_FUNC(getgid), SYS_FUNC(setfsgid), SYS_FUNC(setgid),
SYS_FUNC(getresgid), SYS_FUNC(setregid), SYS_FUNC(setresgid)): New
functions.
(get_print_id): Rename from get_print_uid, add idt argument, call
printuid or printgid depending on it. Update call sites.
(SYS_FUNC(chown), SYS_FUNC(fchown), print_gid): Use printgid
for printing GID.
(ID_CACHE_SIZE): New macro constant.
(print_id): New function.
(printuid): Implement using print_id.
(printgid): New function.
* xlat/priorities.in: Provide fallback values.
2018-10-26 02:18:41 +02:00
PRINT_FIELD_UID ( " , " , msg , idiag_uid ) ;
2017-07-19 10:07:34 +00:00
PRINT_FIELD_U ( " , " , msg , idiag_inode ) ;
decode_nla = true ;
}
} else
tprints ( " ... " ) ;
tprints ( " } " ) ;
2017-07-19 22:55:53 +08:00
offset = NLMSG_ALIGN ( sizeof ( msg ) ) ;
2017-07-19 10:07:34 +00:00
if ( decode_nla & & len > offset ) {
tprints ( " , " ) ;
decode_nlattr ( tcp , addr + offset , len - offset ,
inet_diag_attrs , " INET_DIAG_??? " ,
inet_diag_msg_nla_decoders ,
ARRAY_SIZE ( inet_diag_msg_nla_decoders ) , NULL ) ;
}
}