2016-07-18 10:20:06 +00:00
/*
* Check decoding of msg_name * fields of struct msghdr array argument
* of sendmmsg and recvmmsg syscalls .
*
* Copyright ( c ) 2016 Dmitry V . Levin < ldv @ altlinux . org >
* 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 "tests.h"
2016-07-18 17:48:44 +00:00
# include <errno.h>
2016-07-18 10:20:06 +00:00
# include <limits.h>
# include <stddef.h>
# include <stdio.h>
# include <string.h>
# include <unistd.h>
# include <sys/un.h>
# include "msghdr.h"
# define DEFAULT_STRLEN 32
# define IOV_MAX1 (IOV_MAX + 1)
# ifndef TEST_NAME
# define TEST_NAME "mmsg_name"
# endif
static void
print_msghdr ( const struct msghdr * const msg , const int user_msg_namelen )
{
const struct sockaddr_un * const un = msg - > msg_name ;
const int offsetof_sun_path = offsetof ( struct sockaddr_un , sun_path ) ;
printf ( " {msg_name= " ) ;
2016-07-18 17:48:44 +00:00
if ( ! un )
printf ( " NULL " ) ;
else if ( user_msg_namelen < offsetof_sun_path ) {
2016-07-18 10:20:06 +00:00
printf ( " %p " , un ) ;
} else {
printf ( " {sa_family=AF_UNIX " ) ;
if ( user_msg_namelen > offsetof_sun_path ) {
int len = user_msg_namelen < ( int ) msg - > msg_namelen ?
user_msg_namelen : ( int ) msg - > msg_namelen ;
2016-07-18 17:48:44 +00:00
len - = offsetof_sun_path ;
if ( len > ( int ) sizeof ( un - > sun_path ) )
len = sizeof ( un - > sun_path ) ;
printf ( " , sun_path= \" %.*s \" " , len , un - > sun_path ) ;
2016-07-18 10:20:06 +00:00
}
printf ( " } " ) ;
}
printf ( " , msg_namelen= " ) ;
if ( user_msg_namelen ! = ( int ) msg - > msg_namelen ) {
printf ( " %d-> " , user_msg_namelen ) ;
}
printf ( " %d, msg_iov=[{iov_base= \" %c \" , iov_len=1}] "
" , msg_iovlen=1, msg_controllen=0, msg_flags=0} " ,
( int ) msg - > msg_namelen , * ( char * ) msg - > msg_iov [ 0 ] . iov_base ) ;
}
static void
test_mmsg_name ( const int send_fd , const int recv_fd )
{
2016-07-18 17:48:44 +00:00
struct sockaddr_un * const send_addr =
tail_alloc ( sizeof ( * send_addr ) * IOV_MAX1 ) ;
2016-07-18 10:20:06 +00:00
char * const send_buf = tail_alloc ( sizeof ( * send_buf ) * IOV_MAX1 ) ;
struct iovec * const send_iov = tail_alloc ( sizeof ( * send_iov ) * IOV_MAX1 ) ;
struct mmsghdr * const send_mh = tail_alloc ( sizeof ( * send_mh ) * IOV_MAX1 ) ;
int i , rc ;
for ( i = 0 ; i < IOV_MAX1 ; + + i ) {
2016-07-18 17:48:44 +00:00
int sun_len = i + 1 > ( int ) sizeof ( send_addr [ i ] . sun_path )
? ( int ) sizeof ( send_addr [ i ] . sun_path )
: i + 1 ;
send_addr [ i ] . sun_family = AF_UNIX ;
memset ( send_addr [ i ] . sun_path , ' a ' + i % 26 , sun_len ) ;
2016-07-18 10:20:06 +00:00
send_buf [ i ] = ' 0 ' + i % 10 ;
send_iov [ i ] . iov_base = & send_buf [ i ] ;
send_iov [ i ] . iov_len = sizeof ( * send_buf ) ;
send_mh [ i ] . msg_hdr . msg_iov = & send_iov [ i ] ;
send_mh [ i ] . msg_hdr . msg_iovlen = 1 ;
2016-07-18 17:48:44 +00:00
send_mh [ i ] . msg_hdr . msg_name = & send_addr [ i ] ;
send_mh [ i ] . msg_hdr . msg_namelen = i + 1 ;
2016-07-18 10:20:06 +00:00
send_mh [ i ] . msg_hdr . msg_control = 0 ;
send_mh [ i ] . msg_hdr . msg_controllen = 0 ;
send_mh [ i ] . msg_hdr . msg_flags = 0 ;
}
2016-07-18 17:48:44 +00:00
rc = send_mmsg ( send_fd , send_mh , IOV_MAX1 , MSG_DONTWAIT ) ;
int saved_errno = errno ;
printf ( " sendmmsg(%d, [ " , send_fd ) ;
for ( i = 0 ; i < IOV_MAX1 ; + + i ) {
if ( i )
printf ( " , " ) ;
if ( i > = IOV_MAX
2016-09-26 15:16:50 +00:00
# if !VERBOSE
2016-07-18 17:48:44 +00:00
| | i > = DEFAULT_STRLEN
# endif
) {
printf ( " ... " ) ;
break ;
}
printf ( " {msg_hdr= " ) ;
print_msghdr ( & send_mh [ i ] . msg_hdr , i + 1 ) ;
printf ( " } " ) ;
}
errno = saved_errno ;
printf ( " ], %u, MSG_DONTWAIT) = %d %s (%m) \n " ,
IOV_MAX1 , rc , errno2name ( ) ) ;
for ( i = 0 ; i < IOV_MAX1 ; + + i ) {
send_mh [ i ] . msg_hdr . msg_name = 0 ;
send_mh [ i ] . msg_hdr . msg_namelen = 0 ;
}
/*
* When recvmmsg is called with a valid descriptor
* but inaccessible memory , it causes segfaults on some architectures .
* As in these cases we test decoding of failed recvmmsg calls ,
* it ' s ok to fail recvmmsg with any reason as long as
* it doesn ' t read that inaccessible memory .
*/
rc = send_mmsg ( - 1 , & send_mh [ IOV_MAX ] , 2 , MSG_DONTWAIT ) ;
saved_errno = errno ;
printf ( " sendmmsg(-1, [{msg_hdr= " ) ;
print_msghdr ( & send_mh [ IOV_MAX ] . msg_hdr , 0 ) ;
errno = saved_errno ;
printf ( " }, %p], %u, MSG_DONTWAIT) = %d %s (%m) \n " ,
& send_mh [ IOV_MAX1 ] , 2 , rc , errno2name ( ) ) ;
2016-07-18 10:20:06 +00:00
rc = send_mmsg ( send_fd , send_mh , IOV_MAX1 , MSG_DONTWAIT ) ;
if ( rc < 0 )
perror_msg_and_skip ( " sendmmsg " ) ;
printf ( " sendmmsg(%d, [ " , send_fd ) ;
2016-07-18 16:25:25 +00:00
for ( i = 0 ; i < IOV_MAX1 ; + + i ) {
2016-07-18 10:20:06 +00:00
if ( i )
printf ( " , " ) ;
2016-07-18 16:25:25 +00:00
if ( i > = IOV_MAX
2016-09-26 15:16:50 +00:00
# if !VERBOSE
2016-07-18 16:25:25 +00:00
| | i > = DEFAULT_STRLEN
# endif
) {
2016-07-18 10:20:06 +00:00
printf ( " ... " ) ;
break ;
}
2016-07-18 17:48:44 +00:00
printf ( " {msg_hdr= " ) ;
print_msghdr ( & send_mh [ i ] . msg_hdr , 0 ) ;
printf ( " %s} " , i < rc ? " , msg_len=1 " : " " ) ;
2016-07-18 10:20:06 +00:00
}
printf ( " ], %u, MSG_DONTWAIT) = %d \n " , IOV_MAX1 , rc ) ;
struct sockaddr_un * const recv_addr =
tail_alloc ( sizeof ( * recv_addr ) * IOV_MAX1 ) ;
char * const recv_buf = tail_alloc ( sizeof ( * recv_buf ) * IOV_MAX1 ) ;
struct iovec * const recv_iov = tail_alloc ( sizeof ( * recv_iov ) * IOV_MAX1 ) ;
struct mmsghdr * const recv_mh = tail_alloc ( sizeof ( * recv_mh ) * IOV_MAX1 ) ;
for ( i = 0 ; i < IOV_MAX1 ; + + i ) {
recv_iov [ i ] . iov_base = & recv_buf [ i ] ;
recv_iov [ i ] . iov_len = sizeof ( * recv_buf ) ;
recv_mh [ i ] . msg_hdr . msg_name = & recv_addr [ i ] ;
recv_mh [ i ] . msg_hdr . msg_namelen = i ;
recv_mh [ i ] . msg_hdr . msg_iov = & recv_iov [ i ] ;
recv_mh [ i ] . msg_hdr . msg_iovlen = 1 ;
recv_mh [ i ] . msg_hdr . msg_control = 0 ;
recv_mh [ i ] . msg_hdr . msg_controllen = 0 ;
recv_mh [ i ] . msg_hdr . msg_flags = 0 ;
}
rc = recv_mmsg ( recv_fd , recv_mh , IOV_MAX1 , MSG_DONTWAIT , 0 ) ;
if ( rc < 0 )
perror_msg_and_skip ( " recvmmsg " ) ;
printf ( " recvmmsg(%d, [ " , recv_fd ) ;
for ( i = 0 ; i < rc ; + + i ) {
if ( i )
printf ( " , " ) ;
2016-09-26 15:16:50 +00:00
# if !VERBOSE
2016-07-18 10:20:06 +00:00
if ( i > = DEFAULT_STRLEN ) {
printf ( " ... " ) ;
break ;
}
# endif
printf ( " {msg_hdr= " ) ;
print_msghdr ( & recv_mh [ i ] . msg_hdr , i ) ;
printf ( " , msg_len=1} " ) ;
}
printf ( " ], %u, MSG_DONTWAIT, NULL) = %d \n " , IOV_MAX1 , rc ) ;
}
int
main ( void )
{
int fds [ 2 ] ;
if ( socketpair ( AF_UNIX , SOCK_STREAM , 0 , fds ) )
perror_msg_and_skip ( " socketpair " ) ;
const struct sockaddr_un un = {
. sun_family = AF_UNIX ,
. sun_path = TEST_NAME " -recvmmsg.test.send.socket "
} ;
( void ) unlink ( un . sun_path ) ;
if ( bind ( fds [ 1 ] , ( const void * ) & un , sizeof ( un ) ) )
perror_msg_and_skip ( " bind " ) ;
( void ) unlink ( un . sun_path ) ;
test_mmsg_name ( fds [ 1 ] , fds [ 0 ] ) ;
puts ( " +++ exited with 0 +++ " ) ;
return 0 ;
}