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:
Kyle Evans
2024-07-13 00:16:12 -05:00
parent 2aba0eea3f
commit 1f155d48f8
20 changed files with 2641 additions and 7 deletions
+2 -2
View File
@@ -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>
+119
View File
@@ -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
View File
@@ -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
+2 -1
View File
@@ -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));
+2 -1
View File
@@ -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));
}
+1
View File
@@ -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
+45
View File
@@ -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.
*/
+45
View File
@@ -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.
*/
+3 -2
View File
@@ -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;
+4
View File
@@ -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>