mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
Merge branch 'net-convert-rawv6-ieee802154-phonet-and-tls-getsockopt-to-sockopt_t'
Breno Leitao says: ==================== net: convert rawv6, ieee802154, phonet and tls getsockopt to sockopt_t Now that sockopt_init_user() was already merged, builds a user-backed sockopt_t from the __user pair. A getsockopt leaf can then take a sockopt_t behind a thin __user wrapper: the wrapper builds it, calls the leaf, and writes the length back to optlen. The leaf copies with copy_to_iter() instead of copy_to_user(). Convert four more leaves the way udp and raw already were: ipv6 raw (do_rawv6_getsockopt), ieee802154 dgram, phonet pep, and tls (do_tls_getsockopt and its per-option helpers). Converting phonet surfaced a pre-existing bug: pep_getsockopt() clamps the length it reports but writes a full int with put_user(), overrunning an optval buffer shorter than sizeof(int). It is fixed in its own patch, with a Fixes: tag, before the phonet conversion, so it can be backported alone. The last patch adds getsockopt_iter selftest fixtures for rawv6, ieee802154, phonet and tls, checking the returned length and errno across exact, oversized and short buffers, an unknown optname and a bad level. For full motivation about these changes, please check the initial thread at link https://lore.kernel.org/all/20260401-getsockopt-v2-0-611df6771aff@debian.org/#t ==================== Link: https://patch.msgid.link/20260729-getsockopt_phase4-v4-0-c44576757c17@debian.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
958f2f4b1d
|
|
@ -831,20 +831,12 @@ static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int dgram_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
static int do_dgram_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
|
||||
{
|
||||
struct dgram_sock *ro = dgram_sk(sk);
|
||||
|
||||
int val, len;
|
||||
|
||||
if (level != SOL_IEEE802154)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
len = min_t(unsigned int, len, sizeof(int));
|
||||
len = umin(sizeof(int), opt->optlen);
|
||||
|
||||
switch (optname) {
|
||||
case WPAN_WANTACK:
|
||||
|
|
@ -871,10 +863,32 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname,
|
|||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
||||
if (put_user(len, optlen))
|
||||
opt->optlen = len;
|
||||
if (copy_to_iter(&val, len, &opt->iter_out) != len)
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dgram_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
sockopt_t opt;
|
||||
int err;
|
||||
|
||||
if (level != SOL_IEEE802154)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = sockopt_init_user(&opt, optval, optlen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = do_dgram_getsockopt(sk, optname, &opt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (put_user(opt.optlen, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1051,14 +1051,12 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname,
|
|||
return do_rawv6_setsockopt(sk, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
static int do_rawv6_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
|
||||
{
|
||||
struct raw6_sock *rp = raw6_sk(sk);
|
||||
int val, len;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
len = opt->optlen;
|
||||
|
||||
switch (optname) {
|
||||
case IPV6_HDRINCL:
|
||||
|
|
@ -1080,11 +1078,10 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
|
|||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
||||
len = min_t(unsigned int, sizeof(int), len);
|
||||
len = umin(sizeof(int), len);
|
||||
|
||||
if (put_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &val, len))
|
||||
opt->optlen = len;
|
||||
if (copy_to_iter(&val, len, &opt->iter_out) != len)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1092,6 +1089,9 @@ static int do_rawv6_getsockopt(struct sock *sk, int level, int optname,
|
|||
static int rawv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
sockopt_t opt;
|
||||
int err;
|
||||
|
||||
switch (level) {
|
||||
case SOL_RAW:
|
||||
break;
|
||||
|
|
@ -1109,7 +1109,18 @@ static int rawv6_getsockopt(struct sock *sk, int level, int optname,
|
|||
return ipv6_getsockopt(sk, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
return do_rawv6_getsockopt(sk, level, optname, optval, optlen);
|
||||
err = sockopt_init_user(&opt, optval, optlen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = do_rawv6_getsockopt(sk, optname, &opt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (put_user(opt.optlen, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rawv6_ioctl(struct sock *sk, int cmd, int *karg)
|
||||
|
|
|
|||
|
|
@ -1080,17 +1080,11 @@ static int pep_setsockopt(struct sock *sk, int level, int optname,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int pep_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
static int do_pep_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
|
||||
{
|
||||
struct pep_sock *pn = pep_sk(sk);
|
||||
int len, val;
|
||||
|
||||
if (level != SOL_PNPIPE)
|
||||
return -ENOPROTOOPT;
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
switch (optname) {
|
||||
case PNPIPE_ENCAP:
|
||||
val = pn->ifindex ? PNPIPE_ENCAP_IP : PNPIPE_ENCAP_NONE;
|
||||
|
|
@ -1114,11 +1108,33 @@ static int pep_getsockopt(struct sock *sk, int level, int optname,
|
|||
return -ENOPROTOOPT;
|
||||
}
|
||||
|
||||
len = min_t(unsigned int, sizeof(int), len);
|
||||
if (put_user(len, optlen))
|
||||
len = umin(sizeof(int), opt->optlen);
|
||||
opt->optlen = len;
|
||||
if (copy_to_iter(&val, len, &opt->iter_out) != len)
|
||||
return -EFAULT;
|
||||
if (put_user(val, (int __user *) optval))
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pep_getsockopt(struct sock *sk, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
sockopt_t opt;
|
||||
int err;
|
||||
|
||||
if (level != SOL_PNPIPE)
|
||||
return -ENOPROTOOPT;
|
||||
|
||||
err = sockopt_init_user(&opt, optval, optlen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = do_pep_getsockopt(sk, optname, &opt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (put_user(opt.optlen, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -424,20 +424,16 @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock,
|
|||
return mask;
|
||||
}
|
||||
|
||||
static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
|
||||
int __user *optlen, int tx)
|
||||
static int do_tls_getsockopt_conf(struct sock *sk, sockopt_t *opt, int tx)
|
||||
{
|
||||
int rc = 0;
|
||||
const struct tls_cipher_desc *cipher_desc;
|
||||
struct tls_context *ctx = tls_get_ctx(sk);
|
||||
struct tls_crypto_info *crypto_info;
|
||||
struct cipher_context *cctx;
|
||||
int len;
|
||||
int len = opt->optlen;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
if (!optval || (len < sizeof(*crypto_info))) {
|
||||
if (!opt->iter_out.ubuf || len < sizeof(*crypto_info)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -462,7 +458,8 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
|
|||
}
|
||||
|
||||
if (len == sizeof(*crypto_info)) {
|
||||
if (copy_to_user(optval, crypto_info, sizeof(*crypto_info)))
|
||||
if (copy_to_iter(crypto_info, sizeof(*crypto_info),
|
||||
&opt->iter_out) != sizeof(*crypto_info))
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -478,44 +475,38 @@ static int do_tls_getsockopt_conf(struct sock *sk, char __user *optval,
|
|||
memcpy(crypto_info_rec_seq(crypto_info, cipher_desc),
|
||||
cctx->rec_seq, cipher_desc->rec_seq);
|
||||
|
||||
if (copy_to_user(optval, crypto_info, cipher_desc->crypto_info))
|
||||
if (copy_to_iter(crypto_info, cipher_desc->crypto_info,
|
||||
&opt->iter_out) != cipher_desc->crypto_info)
|
||||
rc = -EFAULT;
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int do_tls_getsockopt_tx_zc(struct sock *sk, char __user *optval,
|
||||
int __user *optlen)
|
||||
static int do_tls_getsockopt_tx_zc(struct sock *sk, sockopt_t *opt)
|
||||
{
|
||||
struct tls_context *ctx = tls_get_ctx(sk);
|
||||
unsigned int value;
|
||||
int len;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
int len = opt->optlen;
|
||||
|
||||
if (len != sizeof(value))
|
||||
return -EINVAL;
|
||||
|
||||
value = ctx->zerocopy_sendfile;
|
||||
if (copy_to_user(optval, &value, sizeof(value)))
|
||||
if (copy_to_iter(&value, sizeof(value), &opt->iter_out) != sizeof(value))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_tls_getsockopt_no_pad(struct sock *sk, char __user *optval,
|
||||
int __user *optlen)
|
||||
static int do_tls_getsockopt_no_pad(struct sock *sk, sockopt_t *opt)
|
||||
{
|
||||
struct tls_context *ctx = tls_get_ctx(sk);
|
||||
int value, len;
|
||||
int value, len = opt->optlen;
|
||||
|
||||
if (ctx->prot_info.version != TLS_1_3_VERSION)
|
||||
return -EINVAL;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
if (len < sizeof(value))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -525,38 +516,31 @@ static int do_tls_getsockopt_no_pad(struct sock *sk, char __user *optval,
|
|||
if (value < 0)
|
||||
return value;
|
||||
|
||||
if (put_user(sizeof(value), optlen))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(optval, &value, sizeof(value)))
|
||||
opt->optlen = sizeof(value);
|
||||
if (copy_to_iter(&value, sizeof(value), &opt->iter_out) != sizeof(value))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_tls_getsockopt_tx_payload_len(struct sock *sk, char __user *optval,
|
||||
int __user *optlen)
|
||||
static int do_tls_getsockopt_tx_payload_len(struct sock *sk, sockopt_t *opt)
|
||||
{
|
||||
struct tls_context *ctx = tls_get_ctx(sk);
|
||||
u16 payload_len = ctx->tx_max_payload_len;
|
||||
int len;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
return -EFAULT;
|
||||
int len = opt->optlen;
|
||||
|
||||
if (len < sizeof(payload_len))
|
||||
return -EINVAL;
|
||||
|
||||
if (put_user(sizeof(payload_len), optlen))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_to_user(optval, &payload_len, sizeof(payload_len)))
|
||||
opt->optlen = sizeof(payload_len);
|
||||
if (copy_to_iter(&payload_len, sizeof(payload_len),
|
||||
&opt->iter_out) != sizeof(payload_len))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_tls_getsockopt(struct sock *sk, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
static int do_tls_getsockopt(struct sock *sk, int optname, sockopt_t *opt)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
|
|
@ -565,17 +549,16 @@ static int do_tls_getsockopt(struct sock *sk, int optname,
|
|||
switch (optname) {
|
||||
case TLS_TX:
|
||||
case TLS_RX:
|
||||
rc = do_tls_getsockopt_conf(sk, optval, optlen,
|
||||
optname == TLS_TX);
|
||||
rc = do_tls_getsockopt_conf(sk, opt, optname == TLS_TX);
|
||||
break;
|
||||
case TLS_TX_ZEROCOPY_RO:
|
||||
rc = do_tls_getsockopt_tx_zc(sk, optval, optlen);
|
||||
rc = do_tls_getsockopt_tx_zc(sk, opt);
|
||||
break;
|
||||
case TLS_RX_EXPECT_NO_PAD:
|
||||
rc = do_tls_getsockopt_no_pad(sk, optval, optlen);
|
||||
rc = do_tls_getsockopt_no_pad(sk, opt);
|
||||
break;
|
||||
case TLS_TX_MAX_PAYLOAD_LEN:
|
||||
rc = do_tls_getsockopt_tx_payload_len(sk, optval, optlen);
|
||||
rc = do_tls_getsockopt_tx_payload_len(sk, opt);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOPROTOOPT;
|
||||
|
|
@ -591,12 +574,25 @@ static int tls_getsockopt(struct sock *sk, int level, int optname,
|
|||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct tls_context *ctx = tls_get_ctx(sk);
|
||||
sockopt_t opt;
|
||||
int err;
|
||||
|
||||
if (level != SOL_TLS)
|
||||
return ctx->sk_proto->getsockopt(sk, level,
|
||||
optname, optval, optlen);
|
||||
|
||||
return do_tls_getsockopt(sk, optname, optval, optlen);
|
||||
err = sockopt_init_user(&opt, optval, optlen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = do_tls_getsockopt(sk, optname, &opt);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (put_user(opt.optlen, optlen))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int validate_crypto_info(const struct tls_crypto_info *crypto_info,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@
|
|||
#include <linux/vm_sockets.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/tls.h>
|
||||
#include "kselftest_harness.h"
|
||||
|
||||
#ifndef AF_VSOCK
|
||||
|
|
@ -40,6 +43,18 @@
|
|||
#ifndef ICMP_FILTER
|
||||
#define ICMP_FILTER 1
|
||||
#endif
|
||||
#ifndef IPV6_HDRINCL
|
||||
#define IPV6_HDRINCL 36
|
||||
#endif
|
||||
#ifndef IPV6_CHECKSUM
|
||||
#define IPV6_CHECKSUM 7
|
||||
#endif
|
||||
#ifndef SOL_TLS
|
||||
#define SOL_TLS 282
|
||||
#endif
|
||||
#ifndef TCP_ULP
|
||||
#define TCP_ULP 31
|
||||
#endif
|
||||
|
||||
/* ---------- netlink ---------- */
|
||||
|
||||
|
|
@ -394,4 +409,228 @@ TEST_F(raw, bad_optname)
|
|||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
/* ---------- raw (ipv6) ---------- */
|
||||
|
||||
FIXTURE(rawv6)
|
||||
{
|
||||
int fd;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(rawv6)
|
||||
{
|
||||
self->fd = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
|
||||
if (self->fd < 0)
|
||||
SKIP(return, "SOCK_RAW/IPv6 socket: %s", strerror(errno));
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(rawv6)
|
||||
{
|
||||
if (self->fd >= 0)
|
||||
close(self->fd);
|
||||
}
|
||||
|
||||
TEST_F(rawv6, hdrincl_exact)
|
||||
{
|
||||
socklen_t optlen;
|
||||
int val = -1;
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(sizeof(int), optlen);
|
||||
ASSERT_TRUE(val == 0 || val == 1);
|
||||
}
|
||||
|
||||
TEST_F(rawv6, hdrincl_oversize_clamped)
|
||||
{
|
||||
char buf[16] = {};
|
||||
socklen_t optlen = sizeof(buf);
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
|
||||
buf, &optlen));
|
||||
ASSERT_EQ(sizeof(int), optlen);
|
||||
}
|
||||
|
||||
/* Raw int options clamp the reported length down to the user buffer
|
||||
* instead of returning EINVAL on a short buffer.
|
||||
*/
|
||||
TEST_F(rawv6, hdrincl_undersize_clamped)
|
||||
{
|
||||
socklen_t optlen = 2;
|
||||
int val = 0;
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(2, optlen);
|
||||
}
|
||||
|
||||
TEST_F(rawv6, checksum_default)
|
||||
{
|
||||
socklen_t optlen;
|
||||
int val = 0;
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
/* A non-ICMPv6 raw socket has the checksum disabled, reported as -1. */
|
||||
ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_CHECKSUM,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(sizeof(int), optlen);
|
||||
ASSERT_EQ(-1, val);
|
||||
}
|
||||
|
||||
TEST_F(rawv6, bad_optname)
|
||||
{
|
||||
socklen_t optlen;
|
||||
int val;
|
||||
|
||||
optlen = sizeof(val);
|
||||
|
||||
/* SOL_RAW reaches do_rawv6_getsockopt() directly. */
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, 0x7fff, &val, &optlen));
|
||||
ASSERT_EQ(ENOPROTOOPT, errno);
|
||||
ASSERT_EQ(sizeof(val), optlen);
|
||||
}
|
||||
|
||||
/* ---------- tls ---------- */
|
||||
|
||||
FIXTURE(tls)
|
||||
{
|
||||
int fd;
|
||||
int sfd;
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(tls)
|
||||
{
|
||||
struct sockaddr_in a = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
|
||||
};
|
||||
socklen_t alen = sizeof(a);
|
||||
int lfd;
|
||||
|
||||
self->fd = -1;
|
||||
self->sfd = -1;
|
||||
|
||||
lfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (lfd < 0)
|
||||
SKIP(return, "TCP socket: %s", strerror(errno));
|
||||
if (bind(lfd, (struct sockaddr *)&a, sizeof(a)) || listen(lfd, 1) ||
|
||||
getsockname(lfd, (struct sockaddr *)&a, &alen)) {
|
||||
close(lfd);
|
||||
SKIP(return, "listener setup: %s", strerror(errno));
|
||||
}
|
||||
self->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (self->fd < 0) {
|
||||
close(lfd);
|
||||
SKIP(return, "TCP socket: %s", strerror(errno));
|
||||
}
|
||||
if (connect(self->fd, (struct sockaddr *)&a, sizeof(a))) {
|
||||
close(lfd);
|
||||
SKIP(return, "connect: %s", strerror(errno));
|
||||
}
|
||||
self->sfd = accept(lfd, NULL, NULL);
|
||||
close(lfd);
|
||||
if (setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")))
|
||||
SKIP(return, "TCP_ULP=tls: %s (built without TLS?)",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(tls)
|
||||
{
|
||||
if (self->fd >= 0)
|
||||
close(self->fd);
|
||||
if (self->sfd >= 0)
|
||||
close(self->sfd);
|
||||
}
|
||||
|
||||
/* do_tls_getsockopt_tx_zc(): fixed-size int, exact length required. */
|
||||
TEST_F(tls, tx_zerocopy_exact)
|
||||
{
|
||||
socklen_t optlen = sizeof(int);
|
||||
int val = -1;
|
||||
|
||||
ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(sizeof(int), optlen);
|
||||
ASSERT_TRUE(val == 0 || val == 1);
|
||||
}
|
||||
|
||||
TEST_F(tls, tx_zerocopy_wrong_len)
|
||||
{
|
||||
socklen_t optlen = 2;
|
||||
int val;
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
|
||||
&val, &optlen));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
}
|
||||
|
||||
/* do_tls_getsockopt_conf(): NULL optval still yields EINVAL -- the
|
||||
* converted code tests opt->iter_out.ubuf in place of optval.
|
||||
*/
|
||||
TEST_F(tls, conf_null_optval)
|
||||
{
|
||||
socklen_t optlen = 64;
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, NULL, &optlen));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
}
|
||||
|
||||
TEST_F(tls, conf_short)
|
||||
{
|
||||
socklen_t optlen = 2;
|
||||
char buf[2];
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, buf, &optlen));
|
||||
ASSERT_EQ(EINVAL, errno);
|
||||
}
|
||||
|
||||
/* TLS_TX before crypto is set reports not-ready. */
|
||||
TEST_F(tls, conf_not_ready)
|
||||
{
|
||||
struct tls_crypto_info info;
|
||||
socklen_t optlen = sizeof(info);
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, &info, &optlen));
|
||||
ASSERT_EQ(EBUSY, errno);
|
||||
}
|
||||
|
||||
/* Set TX crypto, then read it back at the base and full sizes, exercising
|
||||
* both copy_to_iter() branches. SKIP if AES-GCM is unavailable.
|
||||
*/
|
||||
TEST_F(tls, conf_crypto_roundtrip)
|
||||
{
|
||||
struct tls12_crypto_info_aes_gcm_128 tx = {
|
||||
.info.version = TLS_1_2_VERSION,
|
||||
.info.cipher_type = TLS_CIPHER_AES_GCM_128,
|
||||
};
|
||||
struct tls12_crypto_info_aes_gcm_128 full;
|
||||
struct tls_crypto_info base;
|
||||
socklen_t optlen;
|
||||
|
||||
if (setsockopt(self->fd, SOL_TLS, TLS_TX, &tx, sizeof(tx)))
|
||||
SKIP(return, "set TLS_TX aes_gcm_128: %s", strerror(errno));
|
||||
|
||||
optlen = sizeof(base);
|
||||
ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX, &base, &optlen));
|
||||
ASSERT_EQ(sizeof(base), optlen);
|
||||
ASSERT_EQ(TLS_1_2_VERSION, base.version);
|
||||
ASSERT_EQ(TLS_CIPHER_AES_GCM_128, base.cipher_type);
|
||||
|
||||
optlen = sizeof(full);
|
||||
ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX, &full, &optlen));
|
||||
ASSERT_EQ(sizeof(full), optlen);
|
||||
ASSERT_EQ(TLS_CIPHER_AES_GCM_128, full.info.cipher_type);
|
||||
}
|
||||
|
||||
TEST_F(tls, bad_optname)
|
||||
{
|
||||
socklen_t optlen = sizeof(int);
|
||||
int val;
|
||||
|
||||
ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, 0x7fff, &val, &optlen));
|
||||
ASSERT_EQ(ENOPROTOOPT, errno);
|
||||
}
|
||||
|
||||
TEST_HARNESS_MAIN
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user