diff --git a/lib/libradius/radius.h b/lib/libradius/radius.h index ac19d2b78..f49613368 100644 --- a/lib/libradius/radius.h +++ b/lib/libradius/radius.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radius.h,v 1.4 2024/02/25 06:22:45 yasuoka Exp $ */ +/* $OpenBSD: radius.h,v 1.6 2024/06/29 07:19:18 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -31,6 +31,7 @@ #define RADIUS_DEFAULT_PORT 1812 #define RADIUS_ACCT_DEFAULT_PORT 1813 +#define RADIUS_DAE_DEFAULT_PORT 3799 /* RADIUS codes */ #define RADIUS_CODE_ACCESS_REQUEST 1 @@ -42,6 +43,12 @@ #define RADIUS_CODE_STATUS_SERVER 12 #define RADIUS_CODE_STATUS_CLIENT 13 +#define RADIUS_CODE_DISCONNECT_REQUEST 40 +#define RADIUS_CODE_DISCONNECT_ACK 41 +#define RADIUS_CODE_DISCONNECT_NACK 42 +#define RADIUS_CODE_COA_REQUEST 43 +#define RADIUS_CODE_COA_ACK 44 +#define RADIUS_CODE_COA_NACK 45 /* RADIUS attributes */ #define RADIUS_TYPE_USER_NAME 1 @@ -143,6 +150,9 @@ #define RADIUS_TYPE_FRAMED_IPV6_ROUTE 99 #define RADIUS_TYPE_FRAMED_IPV6_POOL 100 +/* RFC 5176 3.5. Error-Cause */ +#define RADIUS_TYPE_ERROR_CAUSE 101 + /* RFC 6911 3. Attributes */ #define RADIUS_TYPE_FRAMED_IPV6_ADDRESS 168 #define RADIUS_TYPE_DNS_SERVER_IPV6_ADDRESS 169 @@ -320,6 +330,42 @@ #define RADIUS_TUNNEL_MEDIUM_TYPE_E163 7 /* E.163 (POTS) */ #define RADIUS_TUNNEL_MEDIUM_TYPE_E164 8 /* E.164 (SMDS, Frame * Relay, ATM) */ +/* RFC 5167 3.5. Error-Cause */ +/* Residual Session Context Removed */ +#define RADIUS_ERROR_CAUSE_RESIDUAL_SESSION_REMOVED 201 +/* Invalid EAP Packet (Ignored) */ +#define RADIUS_ERROR_CAUSE_INVALID_EAP_PACKET 202 +/* Unsupported Attribute */ +#define RADIUS_ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE 401 +/* Missing Attribute */ +#define RADIUS_ERROR_CAUSE_MISSING_ATTRIBUTE 402 +/* NAS Identification Mismatch */ +#define RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH 403 +/* Invalid Request */ +#define RADIUS_ERROR_CAUSE_INVALID_REQUEST 404 +/* Unsupported Service */ +#define RADIUS_ERROR_CAUSE_UNSUPPORTED_SERVICE 405 +/* Unsupported Extension */ +#define RADIUS_ERROR_CAUSE_UNSUPPORTED_EXTENSION 406 +/* Invalid Attribute Valu */ +#define RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE 407 +/* Administratively Prohibited */ +#define RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED 501 +/* Request Not Routable (Proxy) */ +#define RADIUS_ERROR_CAUSE_REQUEST_NOT_ROUTABLE 502 +/* Session Context Not Found */ +#define RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND 503 +/* Session Context Not Removable */ +#define RADIUS_ERROR_CAUSE_SESSION_NOT_REMOVABLE 504 +/* Other Proxy Processing Error */ +#define RADIUS_ERROR_CAUSE_OTHER_PROXY_PROCESSING_ERROR 505 +/* Resources Unavailable */ +#define RADIUS_ERROR_CAUSE_RESOURCES_UNAVAILABLE 506 +/* Request Initiated */ +#define RADIUS_ERROR_CAUSE_REQUEST_INITIATED 507 +/* Multiple Session Selection Unsupported */ +#define RADIUS_ERROR_CAUSE_MULTI_SELECTION_UNSUPPORTED 508 + #include #include diff --git a/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 b/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 index 683b6696e..5f8da325b 100644 --- a/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 +++ b/lib/libssl/man/SSL_CTX_set_alpn_select_cb.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: SSL_CTX_set_alpn_select_cb.3,v 1.8 2021/09/10 09:25:29 tb Exp $ +.\" $OpenBSD: SSL_CTX_set_alpn_select_cb.3,v 1.9 2024/06/28 14:48:43 tb Exp $ .\" OpenSSL 87b81496 Apr 19 12:38:27 2017 -0400 .\" OpenSSL b97fdb57 Nov 11 09:33:09 2016 +0100 .\" @@ -49,7 +49,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED .\" OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: September 10 2021 $ +.Dd $Mdocdate: June 28 2024 $ .Dt SSL_CTX_SET_ALPN_SELECT_CB 3 .Os .Sh NAME @@ -153,6 +153,15 @@ It implements the standard protocol selection. It is expected that this function is called from the application callback .Fa cb . +If +.Fn SSL_select_next_proto +returns +.Dv OPENSSL_NPN_NO_OVERLAP , +.Fa cb +should ignore +.Fa out +and fail by returning +.Dv SSL_TLSEXT_ERR_ALERT_FATAL . The protocol data in .Fa server , .Fa server_len @@ -175,7 +184,8 @@ value will point into either .Fa server or .Fa client , -so it should be copied immediately. +so it must not be modified and +should be copied immediately. If no match is found, the first item in .Fa client , .Fa client_len diff --git a/lib/libssl/ssl_lib.c b/lib/libssl/ssl_lib.c index d1b552d94..f5d477e86 100644 --- a/lib/libssl/ssl_lib.c +++ b/lib/libssl/ssl_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_lib.c,v 1.323 2024/04/15 16:00:05 tb Exp $ */ +/* $OpenBSD: ssl_lib.c,v 1.325 2024/06/29 07:34:12 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1785,45 +1785,70 @@ LSSL_ALIAS(SSL_get_servername_type); * It returns either: * OPENSSL_NPN_NEGOTIATED if a common protocol was found, or * OPENSSL_NPN_NO_OVERLAP if the fallback case was reached. + * + * XXX - the out argument points into server_list or client_list and should + * therefore really be const. We can't fix that without breaking the callers. */ int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, - const unsigned char *server, unsigned int server_len, - const unsigned char *client, unsigned int client_len) + const unsigned char *server_list, unsigned int server_list_len, + const unsigned char *client_list, unsigned int client_list_len) { - unsigned int i, j; - const unsigned char *result; - int status = OPENSSL_NPN_UNSUPPORTED; + CBS client, client_proto, server, server_proto; + + *out = NULL; + *outlen = 0; + + /* First check that the client list is well-formed. */ + CBS_init(&client, client_list, client_list_len); + if (!tlsext_alpn_check_format(&client)) + goto err; /* - * For each protocol in server preference order, - * see if we support it. + * Use first client protocol as fallback. This is one way of doing NPN's + * "opportunistic" protocol selection (see security considerations in + * draft-agl-tls-nextprotoneg-04), and it is the documented behavior of + * this API. For ALPN it's the callback's responsibility to fail on + * OPENSSL_NPN_NO_OVERLAP. */ - for (i = 0; i < server_len; ) { - for (j = 0; j < client_len; ) { - if (server[i] == client[j] && - memcmp(&server[i + 1], - &client[j + 1], server[i]) == 0) { - /* We found a match */ - result = &server[i]; - status = OPENSSL_NPN_NEGOTIATED; - goto found; + + if (!CBS_get_u8_length_prefixed(&client, &client_proto)) + goto err; + + *out = (unsigned char *)CBS_data(&client_proto); + *outlen = CBS_len(&client_proto); + + /* Now check that the server list is well-formed. */ + CBS_init(&server, server_list, server_list_len); + if (!tlsext_alpn_check_format(&server)) + goto err; + + /* + * Walk the server list and select the first protocol that appears in + * the client list. + */ + while (CBS_len(&server) > 0) { + if (!CBS_get_u8_length_prefixed(&server, &server_proto)) + goto err; + + CBS_init(&client, client_list, client_list_len); + + while (CBS_len(&client) > 0) { + if (!CBS_get_u8_length_prefixed(&client, &client_proto)) + goto err; + + if (CBS_mem_equal(&client_proto, + CBS_data(&server_proto), CBS_len(&server_proto))) { + *out = (unsigned char *)CBS_data(&server_proto); + *outlen = CBS_len(&server_proto); + + return OPENSSL_NPN_NEGOTIATED; } - j += client[j]; - j++; } - i += server[i]; - i++; } - /* There's no overlap between our protocols and the server's list. */ - result = client; - status = OPENSSL_NPN_NO_OVERLAP; - - found: - *out = (unsigned char *) result + 1; - *outlen = result[0]; - return (status); + err: + return OPENSSL_NPN_NO_OVERLAP; } LSSL_ALIAS(SSL_select_next_proto); diff --git a/lib/libssl/ssl_packet.c b/lib/libssl/ssl_packet.c index 70017b466..32d6cceb7 100644 --- a/lib/libssl/ssl_packet.c +++ b/lib/libssl/ssl_packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_packet.c,v 1.15 2022/11/26 16:08:56 tb Exp $ */ +/* $OpenBSD: ssl_packet.c,v 1.16 2024/06/28 13:37:49 jsing Exp $ */ /* * Copyright (c) 2016, 2017 Joel Sing * @@ -18,34 +18,6 @@ #include "bytestring.h" #include "ssl_local.h" -static int -ssl_is_sslv2_client_hello(CBS *header) -{ - uint16_t record_length; - uint8_t message_type; - CBS cbs; - - CBS_dup(header, &cbs); - - if (!CBS_get_u16(&cbs, &record_length) || - !CBS_get_u8(&cbs, &message_type)) - return 0; - - /* - * The SSLv2 record length field uses variable length (2 or 3 byte) - * encoding. Given the size of a client hello, we expect/require the - * 2-byte form which is indicated by a one in the most significant bit. - */ - if ((record_length & 0x8000) == 0) - return 0; - if ((record_length & ~0x8000) < 3) - return 0; - if (message_type != SSL2_MT_CLIENT_HELLO) - return 0; - - return 1; -} - static int ssl_is_sslv3_handshake(CBS *header) { @@ -67,164 +39,6 @@ ssl_is_sslv3_handshake(CBS *header) return 1; } -static int -ssl_convert_sslv2_client_hello(SSL *s) -{ - CBB cbb, handshake, client_hello, cipher_suites, compression, session_id; - CBS cbs, challenge, cipher_specs, session; - uint16_t record_length, client_version, cipher_specs_length; - uint16_t session_id_length, challenge_length; - unsigned char *client_random = NULL, *data = NULL; - size_t data_len, pad_len, len; - uint32_t cipher_spec; - uint8_t message_type; - unsigned char *pad; - int ret = -1; - int n; - - memset(&cbb, 0, sizeof(cbb)); - - CBS_init(&cbs, s->packet, SSL3_RT_HEADER_LENGTH); - - if (!CBS_get_u16(&cbs, &record_length) || - !CBS_get_u8(&cbs, &message_type) || - !CBS_get_u16(&cbs, &client_version)) - return -1; - - /* - * The SSLv2 record length field uses variable length (2 or 3 byte) - * encoding. Given the size of a client hello, we expect/require the - * 2-byte form which is indicated by a one in the most significant bit. - * Also note that the record length value does not include the bytes - * used for the record length field. - */ - if ((record_length & 0x8000) == 0) - return -1; - record_length &= ~0x8000; - if (record_length < SSL3_RT_HEADER_LENGTH - 2) - return -1; - if (message_type != SSL2_MT_CLIENT_HELLO) - return -1; - - if (record_length < 9) { - SSLerror(s, SSL_R_RECORD_LENGTH_MISMATCH); - return -1; - } - if (record_length > 4096) { - SSLerror(s, SSL_R_RECORD_TOO_LARGE); - return -1; - } - - n = ssl3_packet_extend(s, record_length + 2); - if (n != record_length + 2) - return n; - - tls1_transcript_record(s, s->packet + 2, - s->packet_length - 2); - s->mac_packet = 0; - - if (s->msg_callback) - s->msg_callback(0, SSL2_VERSION, 0, - s->packet + 2, s->packet_length - 2, s, - s->msg_callback_arg); - - /* Decode the SSLv2 record containing the client hello. */ - CBS_init(&cbs, s->packet, s->packet_length); - - if (!CBS_get_u16(&cbs, &record_length)) - return -1; - if (!CBS_get_u8(&cbs, &message_type)) - return -1; - if (!CBS_get_u16(&cbs, &client_version)) - return -1; - if (!CBS_get_u16(&cbs, &cipher_specs_length)) - return -1; - if (!CBS_get_u16(&cbs, &session_id_length)) - return -1; - if (!CBS_get_u16(&cbs, &challenge_length)) - return -1; - if (!CBS_get_bytes(&cbs, &cipher_specs, cipher_specs_length)) - return -1; - if (!CBS_get_bytes(&cbs, &session, session_id_length)) - return -1; - if (!CBS_get_bytes(&cbs, &challenge, challenge_length)) - return -1; - if (CBS_len(&cbs) != 0) { - SSLerror(s, SSL_R_RECORD_LENGTH_MISMATCH); - return -1; - } - - /* - * Convert SSLv2 challenge to SSLv3/TLS client random, by truncating or - * left-padding with zero bytes. - */ - if ((client_random = malloc(SSL3_RANDOM_SIZE)) == NULL) - goto err; - if (!CBB_init_fixed(&cbb, client_random, SSL3_RANDOM_SIZE)) - goto err; - if ((len = CBS_len(&challenge)) > SSL3_RANDOM_SIZE) - len = SSL3_RANDOM_SIZE; - pad_len = SSL3_RANDOM_SIZE - len; - if (!CBB_add_space(&cbb, &pad, pad_len)) - goto err; - memset(pad, 0, pad_len); - if (!CBB_add_bytes(&cbb, CBS_data(&challenge), len)) - goto err; - if (!CBB_finish(&cbb, NULL, NULL)) - goto err; - - /* Build SSLv3/TLS record with client hello. */ - if (!CBB_init(&cbb, SSL3_RT_MAX_PLAIN_LENGTH)) - goto err; - if (!CBB_add_u8(&cbb, SSL3_RT_HANDSHAKE)) - goto err; - if (!CBB_add_u16(&cbb, 0x0301)) - goto err; - if (!CBB_add_u16_length_prefixed(&cbb, &handshake)) - goto err; - if (!CBB_add_u8(&handshake, SSL3_MT_CLIENT_HELLO)) - goto err; - if (!CBB_add_u24_length_prefixed(&handshake, &client_hello)) - goto err; - if (!CBB_add_u16(&client_hello, client_version)) - goto err; - if (!CBB_add_bytes(&client_hello, client_random, SSL3_RANDOM_SIZE)) - goto err; - if (!CBB_add_u8_length_prefixed(&client_hello, &session_id)) - goto err; - if (!CBB_add_u16_length_prefixed(&client_hello, &cipher_suites)) - goto err; - while (CBS_len(&cipher_specs) > 0) { - if (!CBS_get_u24(&cipher_specs, &cipher_spec)) - goto err; - if ((cipher_spec & 0xff0000) != 0) - continue; - if (!CBB_add_u16(&cipher_suites, cipher_spec & 0xffff)) - goto err; - } - if (!CBB_add_u8_length_prefixed(&client_hello, &compression)) - goto err; - if (!CBB_add_u8(&compression, 0)) - goto err; - if (!CBB_finish(&cbb, &data, &data_len)) - goto err; - - if (data_len > s->s3->rbuf.len) - goto err; - - s->packet = s->s3->rbuf.buf; - s->packet_length = data_len; - memcpy(s->packet, data, data_len); - ret = 1; - - err: - CBB_cleanup(&cbb); - free(client_random); - free(data); - - return (ret); -} - /* * Potentially do legacy processing on the first packet received by a TLS * server. We return 1 if we want SSLv3/TLS record processing to continue @@ -233,7 +47,6 @@ ssl_convert_sslv2_client_hello(SSL *s) int ssl_server_legacy_first_packet(SSL *s) { - uint16_t min_version; const char *data; CBS header; @@ -249,23 +62,6 @@ ssl_server_legacy_first_packet(SSL *s) if (s->method->min_tls_version == s->method->max_tls_version) return 1; - if (ssl_is_sslv2_client_hello(&header) == 1) { - /* Only permit SSLv2 client hellos if TLSv1.0 is enabled. */ - if (ssl_enabled_tls_version_range(s, &min_version, NULL) != 1) { - SSLerror(s, SSL_R_NO_PROTOCOLS_AVAILABLE); - return -1; - } - if (min_version > TLS1_VERSION) - return 1; - - if (ssl_convert_sslv2_client_hello(s) != 1) { - SSLerror(s, SSL_R_BAD_PACKET_LENGTH); - return -1; - } - - return 1; - } - /* Ensure that we have SSL3_RT_HEADER_LENGTH (5 bytes) of the packet. */ if (CBS_len(&header) != SSL3_RT_HEADER_LENGTH) { SSLerror(s, ERR_R_INTERNAL_ERROR); diff --git a/regress/lib/libssl/unit/ssl_set_alpn_protos.c b/regress/lib/libssl/unit/ssl_set_alpn_protos.c index 87dd4d9e5..6f3fcfbc2 100644 --- a/regress/lib/libssl/unit/ssl_set_alpn_protos.c +++ b/regress/lib/libssl/unit/ssl_set_alpn_protos.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_set_alpn_protos.c,v 1.2 2022/07/21 03:59:04 tb Exp $ */ +/* $OpenBSD: ssl_set_alpn_protos.c,v 1.3 2024/06/28 14:50:37 tb Exp $ */ /* * Copyright (c) 2022 Theo Buehler * @@ -20,6 +20,21 @@ #include +static void +hexdump(const unsigned char *buf, size_t len) +{ + size_t i; + + if (buf == NULL) { + fprintf(stderr, "(null), len %zu\n", len); + return; + } + for (i = 1; i <= len; i++) + fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); + if (len % 8) + fprintf(stderr, "\n"); +} + struct alpn_test { const char *description; const uint8_t protocols[24]; @@ -186,6 +201,279 @@ test_ssl_set_alpn_protos_edge_cases(void) return failed; } +static const struct select_next_proto_test { + const unsigned char *server_list; + size_t server_list_len; + const unsigned char *client_list; + size_t client_list_len; + int want_ret; + const unsigned char *want_out; + unsigned char want_out_len; /* yes, unsigned char */ +} select_next_proto_tests[] = { + { + .server_list = "\x01" "a" "\x01" "b" "\x01" "c", + .server_list_len = 6, + .client_list = "\x01" "a", + .client_list_len = 2, + .want_ret = OPENSSL_NPN_NEGOTIATED, + .want_out = "a", + .want_out_len = 1, + }, + { + .server_list = "\x01" "a" "\x01" "b" "\x01" "c", + .server_list_len = 6, + .client_list = "\x02" "aa" "\x01" "b" "\x01" "c", + .client_list_len = 7, + .want_ret = OPENSSL_NPN_NEGOTIATED, + .want_out = "b", + .want_out_len = 1, + }, + { + /* Use server preference. */ + .server_list = "\x01" "a" "\x01" "b" "\x01" "c", + .server_list_len = 6, + .client_list = "\x01" "c" "\x01" "b" "\x01" "a", + .client_list_len = 6, + .want_ret = OPENSSL_NPN_NEGOTIATED, + .want_out = "a", + .want_out_len = 1, + }, + { + /* Again server preference wins. */ + .server_list = "\x01" "a" "\x03" "bbb" "\x02" "cc", + .server_list_len = 9, + .client_list = "\x01" "z" "\x02" "cc" "\x03" "bbb", + .client_list_len = 9, + .want_ret = OPENSSL_NPN_NEGOTIATED, + .want_out = "bbb", + .want_out_len = 3, + }, + { + /* No overlap fails with first client protocol. */ + .server_list = "\x01" "a" "\x01" "b" "\x01" "c", + .server_list_len = 6, + .client_list = "\x01" "z" "\x01" "y", + .client_list_len = 4, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + .want_out = "z", + .want_out_len = 1, + }, + { + /* + * No server protocols is a misconfiguration, but should fail + * cleanly. + */ + .server_list = "", + .server_list_len = 0, + .client_list = "\x01" "a" "\x01" "b" "\x01" "c", + .client_list_len = 6, + .want_out = "a", + .want_out_len = 1, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * NULL server protocols is a programming error that fails + * cleanly. + */ + .server_list = NULL, + .server_list_len = 0, + .client_list = "\x01" "a" "\x01" "b" "\x01" "c", + .client_list_len = 6, + .want_out = "a", + .want_out_len = 1, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * Malformed server protocols is a misconfiguration, but it + * should fail cleanly. + */ + .server_list = "\x00", + .server_list_len = 1, + .client_list = "\x01" "a" "\x01" "b" "\x01" "c", + .client_list_len = 6, + .want_out = "a", + .want_out_len = 1, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * Malformed server protocols is a misconfiguration, but it + * should fail cleanly. + */ + .server_list = "\x01" "a" "\x03" "bb", + .server_list_len = 5, + .client_list = "\x01" "a" "\x01" "b" "\x01" "c", + .client_list_len = 6, + .want_out = "a", + .want_out_len = 1, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * Empty client protocols is not reachable from the ALPN + * callback. It fails cleanly with NULL protocol and 0 length. + */ + .server_list = "\x01" "a", + .server_list_len = 2, + .client_list = "", + .client_list_len = 0, + .want_out = NULL, + .want_out_len = 0, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * NULL client protocols is not reachable from the ALPN + * callback. It fails cleanly with NULL protocol and 0 length. + */ + .server_list = "\x01" "a", + .server_list_len = 2, + .client_list = NULL, + .client_list_len = 0, + .want_out = NULL, + .want_out_len = 0, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * Malformed client list fails cleanly with NULL protocol and + * 0 length. + */ + .server_list = "\x01" "a", + .server_list_len = 2, + .client_list = "\x01" "a" "\x02" "bb" "\x03" "cc" "\x04" "ddd", + .client_list_len = 12, + .want_out = NULL, + .want_out_len = 0, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* + * Malformed client list fails cleanly with NULL protocol and + * 0 length. + */ + .server_list = "\x01" "a", + .server_list_len = 2, + .client_list = "\x01" "a" "\x02" "bb" "\x00" "\x03" "ddd", + .client_list_len = 10, + .want_out = NULL, + .want_out_len = 0, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + + /* + * Some non-toy examples. + */ + + { + .server_list = "\x08" "http/1.1" "\x06" "spdy/1", + .server_list_len = 16, + .client_list = "\x08" "http/2.0" "\x08" "http/1.1", + .client_list_len = 18, + .want_out = "http/1.1", + .want_out_len = 8, + .want_ret = OPENSSL_NPN_NEGOTIATED, + }, + { + .server_list = "\x08" "http/2.0" "\x06" "spdy/1", + .server_list_len = 16, + .client_list = "\x08" "http/1.0" "\x08" "http/1.1", + .client_list_len = 18, + .want_out = "http/1.0", + .want_out_len = 8, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + .server_list = "\x08" "http/1.1" "\x08" "http/1.0", + .server_list_len = 18, + .client_list = "\x08" "http/1.0" "\x08" "http/1.1", + .client_list_len = 18, + .want_out = "http/1.1", + .want_out_len = 8, + .want_ret = OPENSSL_NPN_NEGOTIATED, + }, + { + /* Server malformed. */ + .server_list = "\x08" "http/1.1" "\x07" "http/1.0", + .server_list_len = 18, + .client_list = "\x08" "http/1.0" "\x08" "http/1.1", + .client_list_len = 18, + .want_out = "http/1.0", + .want_out_len = 8, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* Server malformed. */ + .server_list = "\x07" "http/1.1" "\x08" "http/1.0", + .server_list_len = 18, + .client_list = "\x08" "http/1.0" "\x08" "http/1.1", + .client_list_len = 18, + .want_out = "http/1.0", + .want_out_len = 8, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, + { + /* Client has trailing bytes. */ + .server_list = "\x08" "http/1.1" "\x08" "http/1.0", + .server_list_len = 18, + .client_list = "\x08" "http/1.0" "\x07" "http/1.1", + .client_list_len = 18, + .want_out = NULL, + .want_out_len = 0, + .want_ret = OPENSSL_NPN_NO_OVERLAP, + }, +}; + +#define N_SELECT_NEXT_PROTO_TESTS \ + (sizeof(select_next_proto_tests) / sizeof(select_next_proto_tests[0])) + +static int +select_next_proto_testcase(const struct select_next_proto_test *test) +{ + unsigned char *out; + unsigned char out_len; + int ret; + int failed = 0; + + ret = SSL_select_next_proto(&out, &out_len, test->server_list, + test->server_list_len, test->client_list, test->client_list_len); + + if (ret != test->want_ret || out_len != test->want_out_len || + (out == NULL && test->want_out != NULL) || + (out != NULL && test->want_out == NULL) || + (out != NULL && test->want_out != NULL && + memcmp(out, test->want_out, out_len) != 0)) { + fprintf(stderr, "FAIL: ret: %u (want %u), out_len: %u (want %u)\n", + ret, test->want_ret, out_len, test->want_out_len); + fprintf(stderr, "\ngot:\n"); + hexdump(out, out_len); + fprintf(stderr, "\nwant:\n"); + hexdump(test->want_out, test->want_out_len); + fprintf(stderr, "\nserver:\n"); + hexdump(test->server_list, test->server_list_len); + fprintf(stderr, "\nclient:\n"); + hexdump(test->client_list, test->client_list_len); + fprintf(stderr, "\n"); + failed = 1; + } + + return failed; +} + +static int +test_ssl_select_next_proto(void) +{ + size_t i; + int failed = 0; + + for (i = 0; i < N_SELECT_NEXT_PROTO_TESTS; i++) + failed |= select_next_proto_testcase(&select_next_proto_tests[i]); + + return failed; +} + int main(void) { @@ -197,6 +485,8 @@ main(void) failed |= test_ssl_set_alpn_protos_edge_cases(); + failed |= test_ssl_select_next_proto(); + if (!failed) printf("PASS %s\n", __FILE__); diff --git a/regress/sys/kern/Makefile b/regress/sys/kern/Makefile index f2f4ddc67..a75bf1e46 100644 --- a/regress/sys/kern/Makefile +++ b/regress/sys/kern/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.105 2023/07/06 07:45:56 deraadt Exp $ +# $OpenBSD: Makefile,v 1.106 2024/06/28 21:36:05 bluhm Exp $ SUBDIR+= accept access SUBDIR+= bind @@ -22,7 +22,7 @@ SUBDIR+= setuid .endif SUBDIR+= signal sosplice stackjmp stackpivot syscall_segment SUBDIR+= sysvmsg sysvsem sysvshm -SUBDIR+= unalign unfdpass unixsockets unveil unveil-unmount +SUBDIR+= unalign unfdpass unixsockets unp-write-closed unveil unveil-unmount SUBDIR+= wait SUBDIR+= xonly diff --git a/regress/sys/kern/unp-write-closed/Makefile b/regress/sys/kern/unp-write-closed/Makefile new file mode 100644 index 000000000..832994174 --- /dev/null +++ b/regress/sys/kern/unp-write-closed/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1.1.1 2024/06/28 21:07:27 bluhm Exp $ + +PROG= unp-write-closed + +.include diff --git a/regress/sys/kern/unp-write-closed/unp-write-closed.c b/regress/sys/kern/unp-write-closed/unp-write-closed.c new file mode 100644 index 000000000..51e84ec7c --- /dev/null +++ b/regress/sys/kern/unp-write-closed/unp-write-closed.c @@ -0,0 +1,83 @@ +/* $OpenBSD: unp-write-closed.c,v 1.1.1.1 2024/06/28 21:07:27 bluhm Exp $ */ +/* + * Copyright (c) 2024 Vitaliy Makkoveev + * Copyright (c) 2024 Alenander Bluhm + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include + +sig_atomic_t done = 0; + +void +handler(int sigraised) +{ + done = 1; +} + +int +main(int argc, char *argv[]) +{ + int i, s[2], status; + pid_t pid; + + if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) + err(1, "signal pipe"); + if (signal(SIGALRM, handler) == SIG_ERR) + err(1, "signal alrm"); + alarm(30); + + while (!done) { + if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) < 0) + err(1, "socketpair"); + + switch ((pid = fork())) { + case -1: + err(1, "fork"); + case 0: + if (close(s[0]) < 0) + err(1, "child close 0"); + if (close(s[1]) < 0) + err(1, "child close 1"); + return 0; + default: + if (close(s[1]) < 0) + err(1, "parent close 1"); + for (i = 1000000; i > 0; i--) { + if (write(s[0], "1", 1) < 0) + break; + } + if (i <= 0) + errx(1, "write did not fail"); + if (errno != EPIPE) + err(1, "write"); + if (close(s[0]) < 0) + err(1, "parent close 1"); + if (waitpid(pid, &status, 0) < 0) + err(1, "waitpid"); + if (status != 0) + errx(1, "child status %d", status); + break; + } + } + + return 0; +} diff --git a/sys/dev/pci/drm/amd/pm/legacy-dpm/amdgpu_kv_dpm.c b/sys/dev/pci/drm/amd/pm/legacy-dpm/amdgpu_kv_dpm.c index 5cb4725c7..c8586cb7d 100644 --- a/sys/dev/pci/drm/amd/pm/legacy-dpm/amdgpu_kv_dpm.c +++ b/sys/dev/pci/drm/amd/pm/legacy-dpm/amdgpu_kv_dpm.c @@ -164,6 +164,8 @@ static void sumo_construct_vid_mapping_table(struct amdgpu_device *adev, for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { if (table[i].ulSupportedSCLK != 0) { + if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES) + continue; vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit = table[i].usVoltageID; vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit = diff --git a/sys/dev/pci/drm/i915/display/intel_dp.c b/sys/dev/pci/drm/i915/display/intel_dp.c index f32ec5ca3..f80bd9f03 100644 --- a/sys/dev/pci/drm/i915/display/intel_dp.c +++ b/sys/dev/pci/drm/i915/display/intel_dp.c @@ -393,6 +393,10 @@ bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) struct intel_encoder *encoder = &intel_dig_port->base; struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + /* eDP MSO is not compatible with joiner */ + if (intel_dp->mso_link_count) + return false; + return DISPLAY_VER(dev_priv) >= 12 || (DISPLAY_VER(dev_priv) == 11 && encoder->port != PORT_A); diff --git a/sys/dev/pci/drm/radeon/sumo_dpm.c b/sys/dev/pci/drm/radeon/sumo_dpm.c index d49c145db..f7f1ddc6c 100644 --- a/sys/dev/pci/drm/radeon/sumo_dpm.c +++ b/sys/dev/pci/drm/radeon/sumo_dpm.c @@ -1621,6 +1621,8 @@ void sumo_construct_vid_mapping_table(struct radeon_device *rdev, for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) { if (table[i].ulSupportedSCLK != 0) { + if (table[i].usVoltageIndex >= SUMO_MAX_NUMBER_VOLTAGES) + continue; vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit = table[i].usVoltageID; vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit = diff --git a/sys/dev/pv/if_vio.c b/sys/dev/pv/if_vio.c index f216b83cd..5ff0ccac6 100644 --- a/sys/dev/pv/if_vio.c +++ b/sys/dev/pv/if_vio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vio.c,v 1.41 2024/06/26 01:40:49 jsg Exp $ */ +/* $OpenBSD: if_vio.c,v 1.42 2024/06/28 14:46:31 jan Exp $ */ /* * Copyright (c) 2012 Stefan Fritsch, Alexander Fiveg. @@ -419,7 +419,7 @@ vio_alloc_mem(struct vio_softc *sc) */ allocsize = sizeof(struct virtio_net_hdr) * txqsize; - if (vsc->sc_nvqs == 3) { + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) { allocsize += sizeof(struct virtio_net_ctrl_cmd) * 1; allocsize += sizeof(struct virtio_net_ctrl_status) * 1; allocsize += sizeof(struct virtio_net_ctrl_rx) * 1; @@ -436,7 +436,7 @@ vio_alloc_mem(struct vio_softc *sc) kva = sc->sc_dma_kva; sc->sc_tx_hdrs = (struct virtio_net_hdr*)(kva + offset); offset += sizeof(struct virtio_net_hdr) * txqsize; - if (vsc->sc_nvqs == 3) { + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) { sc->sc_ctrl_cmd = (void*)(kva + offset); offset += sizeof(*sc->sc_ctrl_cmd); sc->sc_ctrl_status = (void*)(kva + offset); @@ -529,7 +529,7 @@ vio_needs_reset(struct vio_softc *sc) { if (virtio_get_status(sc->sc_virtio) & VIRTIO_CONFIG_DEVICE_STATUS_DEVICE_NEEDS_RESET) { - printf("%s: device needs reset", sc->sc_dev.dv_xname); + printf("%s: device needs reset\n", sc->sc_dev.dv_xname); vio_ctrl_wakeup(sc, RESET); return 1; } @@ -604,8 +604,7 @@ vio_attach(struct device *parent, struct device *self, void *aux) virtio_postpone_intr_far(&sc->sc_vq[VQTX]); else virtio_stop_vq_intr(vsc, &sc->sc_vq[VQTX]); - if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ) && - virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_RX)) { + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) { if (virtio_alloc_vq(vsc, &sc->sc_vq[VQCTL], 2, NBPG, 1, "control") == 0) { sc->sc_vq[VQCTL].vq_done = vio_ctrleof; @@ -760,7 +759,7 @@ vio_stop(struct ifnet *ifp, int disable) /* only way to stop I/O and DMA is resetting... */ virtio_reset(vsc); vio_rxeof(sc); - if (vsc->sc_nvqs >= 3) + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) vio_ctrl_wakeup(sc, RESET); vio_tx_drain(sc); if (disable) @@ -769,10 +768,10 @@ vio_stop(struct ifnet *ifp, int disable) virtio_reinit_start(vsc); virtio_start_vq_intr(vsc, &sc->sc_vq[VQRX]); virtio_stop_vq_intr(vsc, &sc->sc_vq[VQTX]); - if (vsc->sc_nvqs >= 3) + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) virtio_start_vq_intr(vsc, &sc->sc_vq[VQCTL]); virtio_reinit_end(vsc); - if (vsc->sc_nvqs >= 3) + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) vio_ctrl_wakeup(sc, FREE); } @@ -959,7 +958,7 @@ vio_dump(struct vio_softc *sc) printf("rx tick active: %d\n", !timeout_triggered(&sc->sc_rxtick)); printf("RX virtqueue:\n"); virtio_vq_dump(&vsc->sc_vqs[VQRX]); - if (vsc->sc_nvqs == 3) { + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ)) { printf("CTL virtqueue:\n"); virtio_vq_dump(&vsc->sc_vqs[VQCTL]); printf("ctrl_inuse: %d\n", sc->sc_ctrl_inuse); @@ -1530,7 +1529,7 @@ vio_wait_ctrl_done(struct vio_softc *sc) r = tsleep_nsec(&sc->sc_ctrl_inuse, PRIBIO, "viodone", VIRTIO_NET_CTRL_TIMEOUT); if (r == EWOULDBLOCK) { - printf("%s: ctrl queue timeout", sc->sc_dev.dv_xname); + printf("%s: ctrl queue timeout\n", sc->sc_dev.dv_xname); vio_ctrl_wakeup(sc, RESET); return ENXIO; } @@ -1648,7 +1647,7 @@ vio_iff(struct vio_softc *sc) ifp->if_flags &= ~IFF_ALLMULTI; - if (vsc->sc_nvqs < 3) { + if (!virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_RX)) { /* no ctrl vq; always promisc */ ifp->if_flags |= IFF_ALLMULTI | IFF_PROMISC; return; @@ -1682,9 +1681,6 @@ vio_iff(struct vio_softc *sc) sc->sc_ctrl_mac_tbl_mc->nentries = rxfilter ? nentries : 0; - if (vsc->sc_nvqs < 3) - return; - r = vio_set_rx_filter(sc); if (r == EIO) allmulti = 1; /* fallback */ diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index df5086c86..27edd54af 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket2.c,v 1.155 2024/05/17 19:11:14 mvs Exp $ */ +/* $OpenBSD: uipc_socket2.c,v 1.156 2024/06/28 21:30:24 mvs Exp $ */ /* $NetBSD: uipc_socket2.c,v 1.11 1996/02/04 02:17:55 christos Exp $ */ /* @@ -160,8 +160,6 @@ void soisdisconnected(struct socket *so) { soassertlocked(so); - so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); - so->so_state |= SS_ISDISCONNECTED; mtx_enter(&so->so_rcv.sb_mtx); so->so_rcv.sb_state |= SS_CANTRCVMORE; @@ -171,6 +169,9 @@ soisdisconnected(struct socket *so) so->so_snd.sb_state |= SS_CANTSENDMORE; mtx_leave(&so->so_snd.sb_mtx); + so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING); + so->so_state |= SS_ISDISCONNECTED; + wakeup(&so->so_timeo); sowwakeup(so); sorwakeup(so); diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index fee5d29ab..580698ca8 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_usrreq.c,v 1.207 2024/06/26 12:23:36 mvs Exp $ */ +/* $OpenBSD: uipc_usrreq.c,v 1.208 2024/06/28 21:30:24 mvs Exp $ */ /* $NetBSD: uipc_usrreq.c,v 1.18 1996/02/09 19:00:50 christos Exp $ */ /* @@ -513,6 +513,14 @@ uipc_send(struct socket *so, struct mbuf *m, struct mbuf *nam, goto out; } + /* + * We hold both solock() and `sb_mtx' mutex while modifying + * SS_CANTSENDMORE flag. solock() is enough to check it. + */ + if (so->so_snd.sb_state & SS_CANTSENDMORE) { + error = EPIPE; + goto dispose; + } if (unp->unp_conn == NULL) { error = ENOTCONN; goto dispose; @@ -531,12 +539,6 @@ uipc_send(struct socket *so, struct mbuf *m, struct mbuf *nam, */ mtx_enter(&so2->so_rcv.sb_mtx); mtx_enter(&so->so_snd.sb_mtx); - if (so->so_snd.sb_state & SS_CANTSENDMORE) { - mtx_leave(&so->so_snd.sb_mtx); - mtx_leave(&so2->so_rcv.sb_mtx); - error = EPIPE; - goto dispose; - } if (control) { if (sbappendcontrol(so2, &so2->so_rcv, m, control)) { control = NULL; diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c index 97b14c1bf..aa04381db 100644 --- a/sys/miscfs/fifofs/fifo_vnops.c +++ b/sys/miscfs/fifofs/fifo_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fifo_vnops.c,v 1.105 2024/05/03 17:43:09 mvs Exp $ */ +/* $OpenBSD: fifo_vnops.c,v 1.106 2024/06/28 21:30:24 mvs Exp $ */ /* $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */ /* @@ -174,10 +174,16 @@ fifo_open(void *v) return (error); } fip->fi_readers = fip->fi_writers = 0; + /* + * Should take both solock() and `sb_mtx' mutex for + * SS_CANTSENDMORE flag modifications. + */ + solock(wso); mtx_enter(&wso->so_snd.sb_mtx); wso->so_snd.sb_state |= SS_CANTSENDMORE; wso->so_snd.sb_lowat = PIPE_BUF; mtx_leave(&wso->so_snd.sb_mtx); + sounlock(wso); } else { rso = fip->fi_readsock; wso = fip->fi_writesock; @@ -185,9 +191,11 @@ fifo_open(void *v) if (ap->a_mode & FREAD) { fip->fi_readers++; if (fip->fi_readers == 1) { + solock(wso); mtx_enter(&wso->so_snd.sb_mtx); wso->so_snd.sb_state &= ~SS_CANTSENDMORE; mtx_leave(&wso->so_snd.sb_mtx); + sounlock(wso); if (fip->fi_writers > 0) wakeup(&fip->fi_writers); }