include: ssp: fortify <sys/socket.h>
The entire recv*() implementation set is ripe for opportunities to validate, so do what we can with what we have. Reviewed by: markj Sponsored by: Klara, Inc. Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D45686
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
INCS= poll.h random.h ssp.h stdio.h stdlib.h string.h strings.h uio.h unistd.h
|
||||
INCS+= wchar.h
|
||||
INCS= poll.h random.h socket.h ssp.h stdio.h stdlib.h string.h strings.h
|
||||
INCS+= uio.h unistd.h wchar.h
|
||||
INCSDIR= ${INCLUDEDIR}/ssp
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Copyright (c) 2024, Klara, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``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 FOUNDATION OR CONTRIBUTORS
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _SSP_SOCKET_H_
|
||||
#define _SSP_SOCKET_H_
|
||||
|
||||
#include <ssp/ssp.h>
|
||||
|
||||
#if __SSP_FORTIFY_LEVEL > 0
|
||||
|
||||
#include <sys/_null.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
__ssp_inline void
|
||||
__ssp_check_msghdr(struct msghdr *hdr)
|
||||
{
|
||||
if (__ssp_bos(hdr->msg_name) < hdr->msg_namelen)
|
||||
__chk_fail();
|
||||
|
||||
__ssp_check_iovec(hdr->msg_iov, hdr->msg_iovlen);
|
||||
|
||||
if (__ssp_bos(hdr->msg_control) < hdr->msg_controllen)
|
||||
__chk_fail();
|
||||
}
|
||||
|
||||
__ssp_redirect_raw_impl(int, getpeername, getpeername,
|
||||
(int fdes, struct sockaddr *__restrict name, socklen_t *__restrict namelen))
|
||||
{
|
||||
size_t namesz = __ssp_bos(name);
|
||||
|
||||
if (namesz != (size_t)-1 && namesz < *namelen)
|
||||
__chk_fail();
|
||||
|
||||
return (__ssp_real(getpeername)(fdes, name, namelen));
|
||||
}
|
||||
|
||||
__ssp_redirect_raw_impl(int, getsockname, getsockname,
|
||||
(int fdes, struct sockaddr *__restrict name,
|
||||
socklen_t *__restrict namelen))
|
||||
{
|
||||
size_t namesz = __ssp_bos(name);
|
||||
|
||||
if (namesz != (size_t)-1 && namesz < *namelen)
|
||||
__chk_fail();
|
||||
|
||||
return (__ssp_real(getsockname)(fdes, name, namelen));
|
||||
}
|
||||
|
||||
__ssp_redirect(ssize_t, recv, (int __sock, void *__buf, size_t __len,
|
||||
int __flags), (__sock, __buf, __len, __flags));
|
||||
|
||||
__ssp_redirect_raw_impl(ssize_t, recvfrom, recvfrom,
|
||||
(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr *__restrict from,
|
||||
socklen_t *__restrict fromlen))
|
||||
{
|
||||
if (__ssp_bos(buf) < len)
|
||||
__chk_fail();
|
||||
if (from != NULL && __ssp_bos(from) < *fromlen)
|
||||
__chk_fail();
|
||||
|
||||
return (__ssp_real(recvfrom)(s, buf, len, flags, from, fromlen));
|
||||
}
|
||||
|
||||
__ssp_redirect_raw_impl(ssize_t, recvmsg, recvmsg,
|
||||
(int s, struct msghdr *hdr, int flags))
|
||||
{
|
||||
__ssp_check_msghdr(hdr);
|
||||
return (__ssp_real(recvmsg)(s, hdr, flags));
|
||||
}
|
||||
|
||||
#if __BSD_VISIBLE
|
||||
struct timespec;
|
||||
|
||||
__ssp_redirect_raw_impl(ssize_t, recvmmsg, recvmmsg,
|
||||
(int s, struct mmsghdr *__restrict hdrvec, size_t vlen, int flags,
|
||||
const struct timespec *__restrict timeout))
|
||||
{
|
||||
const size_t vecsz = __ssp_bos(hdrvec);
|
||||
|
||||
if (vecsz != (size_t)-1 && vecsz / sizeof(*hdrvec) < vlen)
|
||||
__chk_fail();
|
||||
|
||||
for (size_t i = 0; i < vlen; i++) {
|
||||
__ssp_check_msghdr(&hdrvec[i].msg_hdr);
|
||||
}
|
||||
|
||||
return (__ssp_real(recvmmsg)(s, hdrvec, vlen, flags, timeout));
|
||||
}
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* __SSP_FORTIFY_LEVEL > 0 */
|
||||
#endif /* _SSP_SOCKET_H_ */
|
||||
+2
-1
@@ -31,12 +31,13 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ssp/ssp.h>
|
||||
#include "libc_private.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
ssize_t
|
||||
recv(int s, void *buf, size_t len, int flags)
|
||||
__ssp_real(recv)(int s, void *buf, size_t len, int flags)
|
||||
{
|
||||
/*
|
||||
* POSIX says recv() shall be a cancellation point, so call the
|
||||
|
||||
@@ -32,13 +32,14 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ssp/ssp.h>
|
||||
#include "libc_private.h"
|
||||
|
||||
__weak_reference(__sys_recvfrom, __recvfrom);
|
||||
|
||||
#pragma weak recvfrom
|
||||
ssize_t
|
||||
recvfrom(int s, void *buf, size_t len, int flags,
|
||||
__ssp_real(recvfrom)(int s, void *buf, size_t len, int flags,
|
||||
struct sockaddr * __restrict from, socklen_t * __restrict fromlen)
|
||||
{
|
||||
return (INTERPOS_SYS(recvfrom, s, buf, len, flags, from, fromlen));
|
||||
|
||||
@@ -32,13 +32,14 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/socket.h>
|
||||
#include <ssp/ssp.h>
|
||||
#include "libc_private.h"
|
||||
|
||||
__weak_reference(__sys_recvmsg, __recvmsg);
|
||||
|
||||
#pragma weak recvmsg
|
||||
ssize_t
|
||||
recvmsg(int s, struct msghdr *msg, int flags)
|
||||
__ssp_real(recvmsg)(int s, struct msghdr *msg, int flags)
|
||||
{
|
||||
return (INTERPOS_SYS(recvmsg, s, msg, flags));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
|
||||
# sys/ headers
|
||||
FORTIFY_TCATS+= random
|
||||
FORTIFY_TCATS+= select
|
||||
FORTIFY_TCATS+= socket
|
||||
FORTIFY_TCATS+= uio
|
||||
|
||||
# non-sys/ headers
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/random.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -66,6 +67,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -65,6 +65,7 @@ local includes = {
|
||||
"sys/random.h",
|
||||
"sys/resource.h",
|
||||
"sys/select.h",
|
||||
"sys/socket.h",
|
||||
"sys/time.h",
|
||||
"sys/uio.h",
|
||||
"sys/wait.h",
|
||||
@@ -115,6 +116,19 @@ local readv_init = [[
|
||||
replace_stdin();
|
||||
]]
|
||||
|
||||
local socket_stackvars = "\tint sock[2] = { -1, -1 };\n"
|
||||
local recvfrom_sockaddr_stackvars = socket_stackvars .. [[
|
||||
char data[16];
|
||||
socklen_t socklen;
|
||||
]]
|
||||
local recvmsg_stackvars = socket_stackvars .. "\tstruct msghdr msg;\n"
|
||||
local socket_init = [[
|
||||
new_socket(sock);
|
||||
]]
|
||||
local socket_socklen_init = socket_init .. [[
|
||||
socklen = __len;
|
||||
]]
|
||||
|
||||
local stdio_init = [[
|
||||
replace_stdin();
|
||||
]]
|
||||
@@ -200,6 +214,187 @@ local all_tests = {
|
||||
},
|
||||
},
|
||||
},
|
||||
socket = {
|
||||
-- <sys/socket.h>
|
||||
{
|
||||
func = "getpeername",
|
||||
buftype = "struct sockaddr",
|
||||
bufsize = "sizeof(struct sockaddr)",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"__buf",
|
||||
"&socklen",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = socket_stackvars .. "\tsocklen_t socklen;",
|
||||
init = socket_socklen_init,
|
||||
uses_len = true,
|
||||
},
|
||||
{
|
||||
func = "getsockname",
|
||||
buftype = "struct sockaddr",
|
||||
bufsize = "sizeof(struct sockaddr)",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"__buf",
|
||||
"&socklen",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = socket_stackvars .. "\tsocklen_t socklen;",
|
||||
init = socket_socklen_init,
|
||||
uses_len = true,
|
||||
},
|
||||
{
|
||||
func = "recv",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"__buf",
|
||||
"__len",
|
||||
"0",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = socket_stackvars,
|
||||
init = socket_init,
|
||||
},
|
||||
{
|
||||
func = "recvfrom",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"__buf",
|
||||
"__len",
|
||||
"0",
|
||||
"NULL",
|
||||
"NULL",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = socket_stackvars,
|
||||
init = socket_init,
|
||||
},
|
||||
{
|
||||
func = "recvfrom",
|
||||
variant = "sockaddr",
|
||||
buftype = "struct sockaddr",
|
||||
bufsize = "sizeof(struct sockaddr)",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"data",
|
||||
"sizeof(data)",
|
||||
"0",
|
||||
"__buf",
|
||||
"&socklen",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = recvfrom_sockaddr_stackvars,
|
||||
init = socket_socklen_init,
|
||||
uses_len = true,
|
||||
},
|
||||
{
|
||||
func = "recvmsg",
|
||||
variant = "msg_name",
|
||||
buftype = "struct sockaddr",
|
||||
bufsize = "sizeof(struct sockaddr)",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"&msg",
|
||||
"0",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = recvmsg_stackvars,
|
||||
init = [[
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_name = BUF;
|
||||
msg.msg_namelen = __len;
|
||||
]],
|
||||
uses_len = true,
|
||||
},
|
||||
{
|
||||
func = "recvmsg",
|
||||
variant = "msg_iov",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"&msg",
|
||||
"0",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = recvmsg_stackvars .. "\tstruct iovec iov[2];\n",
|
||||
init = [[
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&iov[0], 0, sizeof(iov));
|
||||
|
||||
/*
|
||||
* We position the buffer second just so that we can confirm that the
|
||||
* fortification bits are traversing the iovec correctly.
|
||||
*/
|
||||
iov[1].iov_base = BUF;
|
||||
iov[1].iov_len = __len;
|
||||
|
||||
msg.msg_iov = &iov[0];
|
||||
msg.msg_iovlen = nitems(iov);
|
||||
]],
|
||||
uses_len = true,
|
||||
},
|
||||
{
|
||||
func = "recvmsg",
|
||||
variant = "msg_control",
|
||||
bufsize = "CMSG_SPACE(sizeof(int))",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"&msg",
|
||||
"0",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = recvmsg_stackvars,
|
||||
init = [[
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_control = BUF;
|
||||
msg.msg_controllen = __len;
|
||||
]],
|
||||
uses_len = true,
|
||||
},
|
||||
{
|
||||
func = "recvmmsg",
|
||||
variant = "msgvec",
|
||||
buftype = "struct mmsghdr[]",
|
||||
bufsize = "2",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"__buf",
|
||||
"__len",
|
||||
"0",
|
||||
"NULL",
|
||||
},
|
||||
stackvars = socket_stackvars,
|
||||
},
|
||||
{
|
||||
-- We'll assume that recvmsg is covering msghdr
|
||||
-- validation thoroughly enough, we'll just try tossing
|
||||
-- an error in the second element of a msgvec to try and
|
||||
-- make sure that each one is being validated.
|
||||
func = "recvmmsg",
|
||||
variant = "msghdr",
|
||||
arguments = {
|
||||
"sock[0]",
|
||||
"&msgvec[0]",
|
||||
"nitems(msgvec)",
|
||||
"0",
|
||||
"NULL",
|
||||
},
|
||||
exclude = excludes_stack_overflow,
|
||||
stackvars = socket_stackvars .. "\tstruct mmsghdr msgvec[2];\n",
|
||||
init = [[
|
||||
memset(&msgvec[0], 0, sizeof(msgvec));
|
||||
|
||||
/*
|
||||
* Same as above, make sure fortification isn't ignoring n > 1 elements
|
||||
* of the msgvec.
|
||||
*/
|
||||
msgvec[1].msg_hdr.msg_control = BUF;
|
||||
msgvec[1].msg_hdr.msg_controllen = __len;
|
||||
]],
|
||||
uses_len = true,
|
||||
},
|
||||
},
|
||||
uio = {
|
||||
-- <sys/uio.h>
|
||||
{
|
||||
@@ -1207,6 +1402,50 @@ new_symlink(size_t __len)
|
||||
return (linkname);
|
||||
}
|
||||
|
||||
/*
|
||||
* For our purposes, first descriptor will be the reader; we'll send both
|
||||
* raw data and a control message over it so that the result can be used for
|
||||
* any of our recv*() tests.
|
||||
*/
|
||||
static void __unused
|
||||
new_socket(int sock[2])
|
||||
{
|
||||
unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
|
||||
static char sockbuf[256];
|
||||
ssize_t rv;
|
||||
size_t total = 0;
|
||||
struct msghdr hdr = { 0 };
|
||||
struct cmsghdr *cmsg;
|
||||
int error, fd;
|
||||
|
||||
error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
|
||||
ATF_REQUIRE(error == 0);
|
||||
|
||||
while (total != sizeof(sockbuf)) {
|
||||
rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
|
||||
|
||||
ATF_REQUIRE_MSG(rv > 0,
|
||||
"expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
|
||||
rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
|
||||
ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
|
||||
"%zd exceeds total %zu", rv, sizeof(sockbuf));
|
||||
total += rv;
|
||||
}
|
||||
|
||||
hdr.msg_control = ctrl;
|
||||
hdr.msg_controllen = sizeof(ctrl);
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&hdr);
|
||||
cmsg->cmsg_level = SOL_SOCKET;
|
||||
cmsg->cmsg_type = SCM_RIGHTS;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
|
||||
fd = STDIN_FILENO;
|
||||
memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
|
||||
|
||||
error = sendmsg(sock[1], &hdr, 0);
|
||||
ATF_REQUIRE(error != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constructs a tmpfile that we can use for testing read(2) and friends.
|
||||
*/
|
||||
|
||||
@@ -32,11 +32,12 @@
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <ssp/ssp.h>
|
||||
#include "libc_private.h"
|
||||
|
||||
ssize_t
|
||||
recvmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags,
|
||||
const struct timespec *__restrict timeout)
|
||||
__ssp_real(recvmmsg)(int s, struct mmsghdr *__restrict msgvec, size_t vlen,
|
||||
int flags, const struct timespec *__restrict timeout)
|
||||
{
|
||||
struct pollfd pfd[1];
|
||||
size_t i, rcvd;
|
||||
|
||||
@@ -670,6 +670,10 @@ struct mmsghdr {
|
||||
};
|
||||
#endif /* __BSD_VISIBLE */
|
||||
|
||||
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
|
||||
#include <ssp/socket.h>
|
||||
#endif
|
||||
|
||||
#ifndef _KERNEL
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
Reference in New Issue
Block a user