From: Dmitry V. Levin Date: Sun, 3 Jul 2016 22:15:45 +0000 (+0000) Subject: msghdr.c: limit output when printing excessively large messages X-Git-Tag: v4.13~72 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bf2698a6b8fa9e78e82ec2acaeef39273e95ab17;p=strace msghdr.c: limit output when printing excessively large messages Limit output of struct msghdr.msg_control when struct msghdr.msg_controllen is greater than the maximum ancillary buffer size specified in /proc/sys/net/core/optmem_max file. * configure.ac (AC_CHECK_FUNCS): Add open64. * defs.h (read_int_from_file): New prototype. * util.c (read_int_from_file): New function. * msghdr.c (get_optmem_max): New function based on read_int_from_file. (decode_msg_control): Use it to check control_len argument. * tests/msg_control.c (test_big_len): New function. (main): Use it to test printing of excessively large messages. --- diff --git a/configure.ac b/configure.ac index 74288d83..97b75be7 100644 --- a/configure.ac +++ b/configure.ac @@ -290,6 +290,7 @@ AC_CHECK_FUNCS(m4_normalize([ ftruncate futimens if_indextoname + open64 pipe2 prctl preadv diff --git a/defs.h b/defs.h index 114b98e5..bda74a34 100644 --- a/defs.h +++ b/defs.h @@ -511,6 +511,8 @@ int strace_vfprintf(FILE *fp, const char *fmt, va_list args); # define strace_vfprintf vfprintf #endif +extern int read_int_from_file(const char *, int *); + extern void set_sortby(const char *); extern void set_overhead(int); extern void qualify(const char *); diff --git a/msghdr.c b/msghdr.c index dd203260..3db95fa7 100644 --- a/msghdr.c +++ b/msghdr.c @@ -229,10 +229,33 @@ print_cmsg_type_data(struct tcb *tcp, const int cmsg_level, const int cmsg_type, } } +#ifndef UIO_MAXIOV +# define UIO_MAXIOV 1024 +#endif + +static unsigned int +get_optmem_max(void) +{ + static int optmem_max; + + if (!optmem_max) { + if (read_int_from_file("/proc/sys/net/core/optmem_max", + &optmem_max) || optmem_max <= 0) { + optmem_max = sizeof(long long) * (2 * UIO_MAXIOV + 512); + } else { + optmem_max = (optmem_max + sizeof(long long) - 1) + & ~(sizeof(long long) - 1); + } + } + + return optmem_max; +} + static void -decode_msg_control(struct tcb *tcp, unsigned long addr, const size_t control_len) +decode_msg_control(struct tcb *tcp, unsigned long addr, + const size_t in_control_len) { - if (!control_len) + if (!in_control_len) return; tprints(", msg_control="); @@ -242,6 +265,9 @@ decode_msg_control(struct tcb *tcp, unsigned long addr, const size_t control_len #endif sizeof(struct cmsghdr); + size_t control_len = + in_control_len > get_optmem_max() + ? get_optmem_max() : in_control_len; size_t buf_len = control_len; char *buf = buf_len < cmsg_size ? NULL : malloc(buf_len); if (!buf || umoven(tcp, addr, buf_len, buf) < 0) { @@ -299,6 +325,8 @@ decode_msg_control(struct tcb *tcp, unsigned long addr, const size_t control_len if (buf_len) { tprints(", "); printaddr(addr + (control_len - buf_len)); + } else if (control_len < in_control_len) { + tprints(", ..."); } tprints("]"); free(buf); diff --git a/tests/msg_control.c b/tests/msg_control.c index 8d288834..d5ed278d 100644 --- a/tests/msg_control.c +++ b/tests/msg_control.c @@ -49,6 +49,10 @@ # define SCM_SECURITY 3 #endif +#ifndef UIO_MAXIOV +# define UIO_MAXIOV 1024 +#endif + #define MIN_SIZE_OF(type, member) \ (offsetof(type, member) + sizeof(((type *) 0)->member)) @@ -652,6 +656,39 @@ test_unknown_level(struct msghdr *const mh, void *const page) (unsigned) mh->msg_controllen, rc, errno2name()); } +static void +test_big_len(struct msghdr *const mh) +{ + int optmem_max; + + if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max) + || optmem_max <= 0 || optmem_max > 0x100000) + optmem_max = sizeof(long long) * (2 * UIO_MAXIOV + 512); + optmem_max = (optmem_max + sizeof(long long) - 1) + & ~(sizeof(long long) - 1); + + const size_t len = optmem_max * 2; + struct cmsghdr *const cmsg = tail_alloc(len); + cmsg->cmsg_len = len; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + mh->msg_control = cmsg; + mh->msg_controllen = len; + + int rc = sendmsg(-1, mh, 0); + if (EBADF != errno) + perror_msg_and_skip("sendmsg"); + + printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" + ", msg_iovlen=0, msg_control=[{cmsg_len=%u" + ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", + (unsigned) cmsg->cmsg_len); + print_fds(cmsg, optmem_max); + printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", + (unsigned long) len, rc, errno2name()); +} + int main(int ac, const char **av) { int rc = sendmsg(-1, 0, 0); @@ -659,6 +696,7 @@ int main(int ac, const char **av) struct msghdr *mh = tail_alloc(sizeof(*mh)); memset(mh, 0, sizeof(*mh)); + test_big_len(mh); rc = sendmsg(-1, mh + 1, 0); printf("sendmsg(-1, %p, 0) = %d %s (%m)\n", diff --git a/util.c b/util.c index 31227554..c99136d2 100644 --- a/util.c +++ b/util.c @@ -1436,3 +1436,45 @@ printargs_d(struct tcb *tcp) (int) tcp->u_arg[i]); return RVAL_DECODED; } + +#if defined _LARGEFILE64_SOURCE && defined HAVE_OPEN64 +# define open_file open64 +#else +# define open_file open +#endif + +int +read_int_from_file(const char *const fname, int *const pvalue) +{ + const int fd = open_file(fname, O_RDONLY); + if (fd < 0) + return -1; + + long lval; + char buf[sizeof(lval) * 3]; + int n = read(fd, buf, sizeof(buf) - 1); + int saved_errno = errno; + close(fd); + + if (n < 0) { + errno = saved_errno; + return -1; + } + + buf[n] = '\0'; + char *endptr = 0; + errno = 0; + lval = strtol(buf, &endptr, 10); + if (!endptr || (*endptr && '\n' != *endptr) +#if INT_MAX < LONG_MAX + || lval > INT_MAX || lval < INT_MIN +#endif + || ERANGE == errno) { + if (!errno) + errno = EINVAL; + return -1; + } + + *pvalue = (int) lval; + return 0; +}