Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenSSL 3.2.0, QUIC, macOS, error 56 on connected UDP socket #23396

Closed
wants to merge 3 commits into from

Conversation

Sashan
Copy link
Contributor

@Sashan Sashan commented Jan 26, 2024

current translate_msg() function attempts to set ->msg_name (and ->msg_namelen) with BIO's peer name (connection destination) regardless if underlying socket is connected or not. Such implementation uncovers differences in socket implementation between various OSes.

As we have learned hard way sendmsg() and sendmmsg() on OpenBSD and (MacOS too) fail to send messages with ->msg_name being set on connected socket. In such case the caller receives EISCON errro.

I think translate_msg() caller should provide a hint to indicate whether we deal with connected (or un-connected) socket. For connected sockets the peer's name should not be set/filled by translate_msg(). On the other hand if socket is un-connected, then translate_msg() must populate ->msg_name and ->msg_namelen members.

The caller can use getpeername(2) to see if socket is connected. If getpeername() succeeds then we must be dealing with connected socket and translate_msg() must not set ->msg_name and ->msg_namelen members. If getpeername(2) fails, then translate_msg() must provide peer's name (destination address) in ->msg_name and set ->msg_namelen accordingly.

The propposed fix introduces is_connected() function, which applies getpeername() to socket bound to BIO instance. The dgram_sendmmsg() uses is_connected() as a hint for translate_msg() function, so msghdr gets initialized with respect to socket state.

The change also modifies existing test/quic_client_test.c so it also covers the case of connected socket. To keep things simple we can introduce optional argument connect_first to ./quic_client_test function. Without connect_first the test run as usual. With connect_first the test creates and connects socket first. Then it passes such socket to BIO sub-system to perform QUIC connect test as usual.

Fixes #23251

Checklist
  • documentation is added or updated
  • tests are added or updated

@Sashan Sashan requested review from t8m and hlandau January 26, 2024 13:01
@Sashan Sashan added triaged: bug The issue/pr is/fixes a bug tests: present The PR has suitable tests present labels Jan 26, 2024
struct sockaddr_storage ss;
socklen_t ss_len = sizeof(ss);

return (getpeername(b->num, (struct sockaddr *)&ss, &ss_len) == 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think we want to add a syscall to every BIO_sendmmsg invocation.

Whether a socket is connected is supposed to be tracked by BIO_CTRL_DGRAM_SET_CONNECTED (data->connected).

@Sashan
Copy link
Contributor Author

Sashan commented Jan 29, 2024 via email

@Sashan Sashan force-pushed the issue.23251 branch 2 times, most recently from f86585c to f274cef Compare January 29, 2024 12:21
@Sashan Sashan requested a review from hlandau January 29, 2024 13:34
crypto/bio/bss_dgram.c Outdated Show resolved Hide resolved
test/quic_client_test.c Outdated Show resolved Hide resolved
@t8m t8m added branch: master Merge to master branch approval: review pending This pull request needs review by a committer approval: otc review pending This pull request needs review by an OTC member branch: 3.2 Merge to openssl-3.2 labels Jan 29, 2024
@Sashan
Copy link
Contributor Author

Sashan commented Jan 29, 2024 via email

@Sashan Sashan force-pushed the issue.23251 branch 2 times, most recently from 6e44fcd to 664e8d9 Compare January 29, 2024 17:15
test/quic_client_test.c Outdated Show resolved Hide resolved
test/quic_client_test.c Outdated Show resolved Hide resolved
Copy link
Member

@t8m t8m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving with or without the unresolved nit fixed.

Also please use git commit -a --fixup <commitid> instead of force pushes to make the incremental review easier.

crypto/bio/bss_dgram.c Outdated Show resolved Hide resolved
@t8m t8m removed the approval: otc review pending This pull request needs review by an OTC member label Jan 30, 2024
@@ -573,6 +575,10 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
b->shutdown = (int)num;
b->init = 1;
dgram_update_local_addr(b);
if (getpeername(b->num, (struct sockaddr *)&ss, &ss_len) == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation needs fixing in this file

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, @Sashan it seems your editor needs to be configured to replace tabs with spaces.

data = (bio_dgram_data *)b->ptr;
if (data->connected == 0) {
/* macOS requires msg_namelen be 0 if msg_name is NULL */
mh->msg_name = msg->peer != NULL ? &msg->peer->sa : NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

else
mh->msg_namelen = 0;
} else {
mh->msg_name = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

htons(port))))
goto err;
} else {
c_fd = fd_arg;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation also in this file

@Sashan Sashan requested a review from hlandau February 15, 2024 11:50
@openssl-machine
Copy link
Collaborator

This PR is in a state where it requires action by @openssl/committers but the last update was 30 days ago

Sashan and others added 3 commits April 15, 2024 01:08
current `translate_msg()` function attempts to set `->msg_name`
(and `->msg_namelen`) with `BIO`'s peer name (connection destination)
regardless if underlying socket is connected or not. Such implementation
uncovers differences in socket implementation between various OSes.

As we have learned hard way `sendmsg()` and `sendmmsg()` on `OpenBSD`
and (`MacOS` too) fail to send messages with `->msg_name` being
set on connected socket. In such case the caller receives
`EISCON` errro.

I think `translate_msg()` caller should provide a hint to indicate
whether we deal with connected (or un-connected) socket. For
connected sockets the peer's name should not be set/filled
by `translate_msg()`. On the other hand if socket is un-connected,
then `translate_msg()` must populate `->msg_name` and `->msg_namelen`
members.

The caller can use `getpeername(2)` to see if socket is
connected. If `getpeername()` succeeds then we must be dealing
with connected socket and `translate_msg()` must not set
`->msg_name` and `->msg_namelen` members. If `getpeername(2)`
fails, then `translate_msg()` must provide peer's name (destination
address) in `->msg_name` and set `->msg_namelen` accordingly.

The propposed fix introduces `is_connected()` function,
which applies `getpeername()` to socket bound to `BIO` instance.
The `dgram_sendmmsg()` uses `is_connected()` as a hint
for `translate_msg()` function, so msghdr gets initialized
with respect to socket state.

The change also modifies existing `test/quic_client_test.c`
so it also covers the case of connected socket. To keep
things simple we can introduce optional argument `connect_first`
to `./quic_client_test` function. Without `connect_first`
the test run as usual. With `connect_first` the test creates
and connects socket first. Then it passes such socket to
`BIO` sub-system to perform `QUIC` connect test as usual.

Fixes openssl#23251
@t8m t8m added approval: done This pull request has the required number of approvals branch: 3.3 Merge to openssl-3.3 and removed approval: review pending This pull request needs review by a committer labels Apr 15, 2024
@openssl-machine openssl-machine added approval: ready to merge The 24 hour grace period has passed, ready to merge and removed approval: done This pull request has the required number of approvals labels Apr 16, 2024
@openssl-machine
Copy link
Collaborator

This pull request is ready to merge

@t8m
Copy link
Member

t8m commented Apr 16, 2024

Merged to the master, 3.3 and 3.2 branches. Thank you.

@t8m t8m closed this Apr 16, 2024
openssl-machine pushed a commit that referenced this pull request Apr 16, 2024
current `translate_msg()` function attempts to set `->msg_name`
(and `->msg_namelen`) with `BIO`'s peer name (connection destination)
regardless if underlying socket is connected or not. Such implementation
uncovers differences in socket implementation between various OSes.

As we have learned hard way `sendmsg()` and `sendmmsg()` on `OpenBSD`
and (`MacOS` too) fail to send messages with `->msg_name` being
set on connected socket. In such case the caller receives
`EISCON` errro.

I think `translate_msg()` caller should provide a hint to indicate
whether we deal with connected (or un-connected) socket. For
connected sockets the peer's name should not be set/filled
by `translate_msg()`. On the other hand if socket is un-connected,
then `translate_msg()` must populate `->msg_name` and `->msg_namelen`
members.

The caller can use `getpeername(2)` to see if socket is
connected. If `getpeername()` succeeds then we must be dealing
with connected socket and `translate_msg()` must not set
`->msg_name` and `->msg_namelen` members. If `getpeername(2)`
fails, then `translate_msg()` must provide peer's name (destination
address) in `->msg_name` and set `->msg_namelen` accordingly.

The propposed fix introduces `is_connected()` function,
which applies `getpeername()` to socket bound to `BIO` instance.
The `dgram_sendmmsg()` uses `is_connected()` as a hint
for `translate_msg()` function, so msghdr gets initialized
with respect to socket state.

The change also modifies existing `test/quic_client_test.c`
so it also covers the case of connected socket. To keep
things simple we can introduce optional argument `connect_first`
to `./quic_client_test` function. Without `connect_first`
the test run as usual. With `connect_first` the test creates
and connects socket first. Then it passes such socket to
`BIO` sub-system to perform `QUIC` connect test as usual.

Fixes #23251

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #23396)

(cherry picked from commit c062403)
openssl-machine pushed a commit that referenced this pull request Apr 16, 2024
current `translate_msg()` function attempts to set `->msg_name`
(and `->msg_namelen`) with `BIO`'s peer name (connection destination)
regardless if underlying socket is connected or not. Such implementation
uncovers differences in socket implementation between various OSes.

As we have learned hard way `sendmsg()` and `sendmmsg()` on `OpenBSD`
and (`MacOS` too) fail to send messages with `->msg_name` being
set on connected socket. In such case the caller receives
`EISCON` errro.

I think `translate_msg()` caller should provide a hint to indicate
whether we deal with connected (or un-connected) socket. For
connected sockets the peer's name should not be set/filled
by `translate_msg()`. On the other hand if socket is un-connected,
then `translate_msg()` must populate `->msg_name` and `->msg_namelen`
members.

The caller can use `getpeername(2)` to see if socket is
connected. If `getpeername()` succeeds then we must be dealing
with connected socket and `translate_msg()` must not set
`->msg_name` and `->msg_namelen` members. If `getpeername(2)`
fails, then `translate_msg()` must provide peer's name (destination
address) in `->msg_name` and set `->msg_namelen` accordingly.

The propposed fix introduces `is_connected()` function,
which applies `getpeername()` to socket bound to `BIO` instance.
The `dgram_sendmmsg()` uses `is_connected()` as a hint
for `translate_msg()` function, so msghdr gets initialized
with respect to socket state.

The change also modifies existing `test/quic_client_test.c`
so it also covers the case of connected socket. To keep
things simple we can introduce optional argument `connect_first`
to `./quic_client_test` function. Without `connect_first`
the test run as usual. With `connect_first` the test creates
and connects socket first. Then it passes such socket to
`BIO` sub-system to perform `QUIC` connect test as usual.

Fixes #23251

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #23396)

(cherry picked from commit c062403)
openssl-machine pushed a commit that referenced this pull request Apr 16, 2024
current `translate_msg()` function attempts to set `->msg_name`
(and `->msg_namelen`) with `BIO`'s peer name (connection destination)
regardless if underlying socket is connected or not. Such implementation
uncovers differences in socket implementation between various OSes.

As we have learned hard way `sendmsg()` and `sendmmsg()` on `OpenBSD`
and (`MacOS` too) fail to send messages with `->msg_name` being
set on connected socket. In such case the caller receives
`EISCON` errro.

I think `translate_msg()` caller should provide a hint to indicate
whether we deal with connected (or un-connected) socket. For
connected sockets the peer's name should not be set/filled
by `translate_msg()`. On the other hand if socket is un-connected,
then `translate_msg()` must populate `->msg_name` and `->msg_namelen`
members.

The caller can use `getpeername(2)` to see if socket is
connected. If `getpeername()` succeeds then we must be dealing
with connected socket and `translate_msg()` must not set
`->msg_name` and `->msg_namelen` members. If `getpeername(2)`
fails, then `translate_msg()` must provide peer's name (destination
address) in `->msg_name` and set `->msg_namelen` accordingly.

The propposed fix introduces `is_connected()` function,
which applies `getpeername()` to socket bound to `BIO` instance.
The `dgram_sendmmsg()` uses `is_connected()` as a hint
for `translate_msg()` function, so msghdr gets initialized
with respect to socket state.

The change also modifies existing `test/quic_client_test.c`
so it also covers the case of connected socket. To keep
things simple we can introduce optional argument `connect_first`
to `./quic_client_test` function. Without `connect_first`
the test run as usual. With `connect_first` the test creates
and connects socket first. Then it passes such socket to
`BIO` sub-system to perform `QUIC` connect test as usual.

Fixes #23251

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #23396)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approval: ready to merge The 24 hour grace period has passed, ready to merge branch: master Merge to master branch branch: 3.2 Merge to openssl-3.2 branch: 3.3 Merge to openssl-3.3 tests: present The PR has suitable tests present triaged: bug The issue/pr is/fixes a bug
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

OpenSSL 3.2.0, QUIC, macOS, error 56 on connected UDP socket
5 participants