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

initialize msg_name with null pointer when msg_name is empty #2530

Merged
merged 2 commits into from
Nov 3, 2024

Conversation

pacak
Copy link
Contributor

@pacak pacak commented Oct 30, 2024

The msg_name field points to a caller-allocated buffer that is used to return the source address if the socket is unconnected. The caller should set msg_namelen to the size of this buffer before this call; upon return from a successful call, msg_namelen will contain the length of the returned address. If the application does not need to know the source address, msg_name can be specified as NULL.

In case we use () msgname_len gets initialized with 0, but pointer to the array with msg_name. This works for the first iteration somehow, but after that kernel sets msgname_len to a non-zero and second invocation with the same MultiHeader fails

What does this PR do

Fixes #2506

Checklist:

  • I have read CONTRIBUTING.md
  • I have written necessary tests and rustdoc comments
  • A change log has been added if this PR modifies nix's API

@@ -2002,7 +2002,7 @@ unsafe fn pack_mhdr_to_receive<S>(
let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
let p = mhdr.as_mut_ptr();
unsafe {
(*p).msg_name = address as *mut c_void;
(*p).msg_name = if S::size() == 0 { ptr::null_mut() } else { (*address).as_mut_ptr() as *mut c_void };
Copy link
Member

Choose a reason for hiding this comment

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

(*address).as_mut_ptr() as *mut c_void

Any idea why it would work after reverting the change made in #2041?

Copy link
Member

@SteveLauC SteveLauC Oct 31, 2024

Choose a reason for hiding this comment

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

not sure if things fixed by https://github.com/nix-rust/nix/pull/2041 are still working after that.

Considering this, gentle ping on @JarredAllen, the author of #2041, could you please take a look at this PR?

Context

@pacak is trying to solve #2506, after digging into the previous Nix versions(Thank you for this!), he figured out that the issue is possibly introduced by #2041:

Screenshot 2024-10-31 at 8 33 28 AM

If we can have you, I hope we can solve the following questions:

  1. The reason behind above change made in Set the length of a socket address when calling recvmsg on Linux #2041, and possibly why reverting it would fix Re-use MultiHeader<()> in subsequent recvmmsg() calls #2506.
  2. The things that Set the length of a socket address when calling recvmsg on Linux #2041 tried to fix would still work after this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any idea why it would work after reverting the change made in #2041?

As far as I understand .as_mut_ptr() gives a null pointer in case of (), address as *mut c_void gives a dangling pointer through magic of rustc optimizations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess just using .as_mut_ptr() would be enough as long as all the instances return the right pointer. Explicit checking for size makes it so it works even if there's a bogus instance.

Copy link
Member

Choose a reason for hiding this comment

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

As far as I understand .as_mut_ptr() gives a null pointer in case of (), address as *mut c_void gives a dangling pointer through magic of rustc optimizations.

If so

I guess just using .as_mut_ptr() would be enough as long as all the instances return the right pointer.

then yes


not sure if things fixed by #2041 are still working after that.

I think this PR won't break the fix done by #2041 as there is a unit test guarding it.

BTW, let's document why we should use .as_mut_tr() rather than address as *mut c_void because it is so easy to revert the fix if one is not aware of such a subtle different behavior . 😮‍💨

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry I wasn't around, but thanks for fixing my mistake! I concur with the assessment that this shouldn't break my fix.

Copy link
Member

Choose a reason for hiding this comment

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

No need to be sorry. 😆

The msg_name field points to a caller-allocated buffer that is used to
return the source address if the socket is unconnected. The caller
should set msg_namelen to the size of this buffer before this call; upon
return from a successful call, msg_namelen will contain the length of
the returned address. If the application does not need to know the
source address, msg_name can be specified as NULL.

In case we use () msgname_len gets initialized with 0, but a dangling
pointer to the array with msg_name. This works for the first iteration
somehow, but after that kernel sets msgname_len to a non-zero and second
invocation with the same MultiHeader fails

Fixes nix-rust#2506
Copy link
Member

@SteveLauC SteveLauC left a comment

Choose a reason for hiding this comment

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

Thanks! Appreciate the patience when you struggle with the format.

@SteveLauC SteveLauC added this pull request to the merge queue Nov 3, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 3, 2024
@SteveLauC SteveLauC added this pull request to the merge queue Nov 3, 2024
Merged via the queue into nix-rust:master with commit 5fe8266 Nov 3, 2024
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Re-use MultiHeader<()> in subsequent recvmmsg() calls
3 participants