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

Fix struct msghdr types on non-Linux platforms. #648

Merged
merged 1 commit into from
Dec 20, 2017

Conversation

kinetiknz
Copy link
Contributor

@kinetiknz kinetiknz commented Jul 5, 2017

Type struct msghdr and struct cmsghdr types defined in sys/socket/ffi.rs match the Linux headers, but differ from the standard header (and other OSes): http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html

This PR fixes a memory corruption/unsafety issue on non-Linux machines when using recvmsg with certain parameters.

While fixing this, I wondered what the reason was for nix not using libc's definition of these structures.

Closes #748.

@Susurrus
Copy link
Contributor

Susurrus commented Jul 6, 2017

I'd like to take the policy that we never fix FFI stuff directly within nix, instead only fixing in libc and switching our types to use those. All the types defined in socket::ffi actually already exist in libc. Can you just remove that module and use the libc types directly instead?

@Susurrus
Copy link
Contributor

Susurrus commented Jul 6, 2017

Whoops, should have read your entire post. The goal is for nix to exclusively use libc datatypes for all platforms, the only reason not to would be if they aren't fixing their end.

@kinetiknz kinetiknz force-pushed the msghdr_size branch 6 times, most recently from a39e409 to ed75b24 Compare July 10, 2017 04:29
@kinetiknz
Copy link
Contributor Author

Can you just remove that module and use the libc types directly instead?

Will do. Updated PR coming soon.

CHANGELOG.md Outdated
@@ -66,6 +66,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#623](https://github.com/nix-rust/nix/pull/623))
- Multiple constants related to the termios API have now been properly defined for
all supported platforms. ([#527](https://github.com/nix-rust/nix/pull/527))
- Fixed field types of `sys::socket::ffi::{msghdr, cmsghdr}` on
non-Linux platforms. ([#](https://...))
Copy link
Contributor

Choose a reason for hiding this comment

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

You can fill this in at this point. It won't change between now and when it's committed.

@@ -33,9 +48,9 @@ pub struct msghdr<'a> {
pub msg_name: *const c_void,
Copy link
Contributor

Choose a reason for hiding this comment

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

Both msghdr and cmsghdr here should be removed in favor of the declarations in libc.

@kinetiknz
Copy link
Contributor Author

Apologies for the delay, I've been busy with other stuff. I'll try to get the PR updated this week with the removal of socket/ffi.rs and various fixes for this area of the code. Most of the work is already complete, it just needs tidying up.

@Susurrus
Copy link
Contributor

@kinetiknz I actually did some work in this area (see #748). Would you be willing to push this through? This is the last remaining FFI declarations in nix.

@kinetiknz
Copy link
Contributor Author

Sure thing, apologies for letting this sit so long!

Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

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

Just a few minor comments, but I don't understand this code very well. I'd like to do a deeper dive on this, but before I do could you add some comments to help me out? You seem to have a good sense of this API, so it'd be really helpful getting more of that knowledge written down.

Additionally, do we have tests for this? If not, can some be written or is this a hard API for that?

@@ -198,8 +203,10 @@ use self::ffi::{cmsghdr, msghdr, type_of_cmsg_data, type_of_msg_iovlen, type_of_
/// To make room for multiple messages, nest the type parameter with
/// tuples, e.g.
/// `let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();`
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should make this a doccomment so it can be compile & run tested.

@@ -380,7 +388,7 @@ pub enum ControlMessage<'a> {
pub struct UnknownCmsg<'a>(&'a cmsghdr, &'a [u8]);

fn cmsg_align(len: usize) -> usize {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest we add an #[inline] here as it's a small convenience function.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you also add a comment here summarizing this function? I'm having trouble following this code and having a comment for this helper function would be nice.

@Susurrus
Copy link
Contributor

@kinetiknz Just pinging you again on this as it's the last nugget before we have all FFI types upstreamed.

@kinetiknz
Copy link
Contributor Author

@kinetiknz Just pinging you again on this as it's the last nugget before we have all FFI types upstreamed.

Sorry! I'll push my changes tomorrow.

Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

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

This all looks pretty correct to me, unfortunately I'm not too familiar with all of this. @asomers Could you take a look over this as well?

@@ -187,8 +188,12 @@ unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
mem::swap(dst, &mut remainder);
}

// OSX always aligns struct cmsghdr as if it were a 32-bit OS
#[cfg(target_os = "macos")]
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this apply to ios as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like it, thanks.

@@ -187,8 +188,12 @@ unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
mem::swap(dst, &mut remainder);
}

// OSX always aligns struct cmsghdr as if it were a 32-bit OS
#[cfg(target_os = "macos")]
type align_of_cmsg_data = libc::c_uint;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be u32 instead of c_uint? Even if they are the same I'd think u32 is more clear.

@@ -197,9 +202,16 @@ use self::ffi::{cmsghdr, msghdr, type_of_cmsg_data, type_of_msg_iovlen, type_of_
///
/// To make room for multiple messages, nest the type parameter with
/// tuples, e.g.
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove the ", e.g." and add ":"

cmsg_type: libc::SCM_RIGHTS,
cmsg_data: [],
let cmsg = {
let mut cmsg: cmsghdr = mem::uninitialized();
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be more clear if rewritten to use struct update syntax:

    let mut cmsg = cmsghdr {
        cmsg_len: self.len() as _,
        cmsg_level: libc::SOL_SOCKET,
        cmsg_type: libc::SCM_RIGHTS,
        ..unsafe { mem::uninitialized() }
    };

Copy link
Contributor Author

@kinetiknz kinetiknz Dec 20, 2017

Choose a reason for hiding this comment

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

I agree that's nicer, but it looks like the musl target prevents this due to private fields. 😞

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's only a problem for msghdr, so I'll keep the cmsghdr changes and revert the rest.

@Susurrus
Copy link
Contributor

Also, could you rebase and squash all the commits into one since this is really a single big change?

@kinetiknz
Copy link
Contributor Author

Also, could you rebase and squash all the commits into one since this is really a single big change?

Will do, but I figured it'd be easier to review as a series of small commits.

@Susurrus
Copy link
Contributor

Susurrus commented Dec 4, 2017

@kinetiknz I think there are just a few small things to finish to wrap this up in a nice pretty bow. You have some time soon to finish this off?

@kinetiknz
Copy link
Contributor Author

Sure, I should have time early next week.

@Susurrus
Copy link
Contributor

@kinetiknz Will you have time to do some work on this this week? This is the last piece of nix that still relies on its own C types rather than libcs.

@kinetiknz kinetiknz force-pushed the msghdr_size branch 3 times, most recently from a950024 to a7ac04f Compare December 20, 2017 03:04
@kinetiknz
Copy link
Contributor Author

@kinetiknz Will you have time to do some work on this this week? This is the last piece of nix that still relies on its own C types rather than libcs.

Sorry about the delay, rebased and squashed with the last set of comments addressed. Also adjusted the definition of align_of_cmsg_data for DragonFly BSD based on 709cbdf.

@nix-rust nix-rust deleted a comment from kinetiknz Dec 20, 2017
@nix-rust nix-rust deleted a comment from kinetiknz Dec 20, 2017
Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

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

Yeah, I think we should basically go and merge this. I'd just ask for a simple alphetizing of a #cfg and the struct initializing could be more clear using struct update syntax. Hopefully that's not too much to ask for this PR, cause after that let's merge!

cmsg_type: libc::SCM_RIGHTS,
cmsg_data: [],
let cmsg = {
let mut cmsg: cmsghdr = mem::uninitialized();
Copy link
Contributor

Choose a reason for hiding this comment

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

This would be more clear if rewritten to use struct update syntax:

    let mut cmsg = cmsghdr {
        cmsg_len: self.len() as _,
        cmsg_level: libc::SOL_SOCKET,
        cmsg_type: libc::SCM_RIGHTS,
        ..unsafe { mem::uninitialized() }
    };

cmsg_level: libc::SOL_SOCKET,
cmsg_type: libc::SCM_TIMESTAMP,
cmsg_data: [],
let cmsg = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

@@ -295,19 +296,30 @@ unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
mem::swap(dst, &mut remainder);
}

// Darwin and DragonFly BSD always aligns struct cmsghdr as if it were a 32-bit OS
#[cfg(any(target_os = "ios", target_os = "macos", target_os = "dragonfly"))]
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you alphabetize this list?

@kinetiknz
Copy link
Contributor Author

No problem, let me know if there's anything else!

@kinetiknz
Copy link
Contributor Author

Repushed with musl and iOS target fixes.

@nix-rust nix-rust deleted a comment from kinetiknz Dec 20, 2017
@nix-rust nix-rust deleted a comment from kinetiknz Dec 20, 2017
Copy link
Contributor

@Susurrus Susurrus left a comment

Choose a reason for hiding this comment

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

One last tiny nitpick, then I think we're definite RTM!

cmsg_level: libc::SOL_SOCKET,
cmsg_type: libc::SCM_RIGHTS,
cmsg_data: [],
cmsg_len: self.len() as _,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this indentation is messed up.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what happened there, but fixed version pushed.

@Susurrus
Copy link
Contributor

Just realized this is more than fixing the FFI stuff, it actually fixes things on non-Linux platforms, so it's a bug fix. Can you add a CHANGELOG entry under the Fixed section for this?

@kinetiknz
Copy link
Contributor Author

Just realized this is more than fixing the FFI stuff, it actually fixes things on non-Linux platforms, so it's a bug fix. Can you add a CHANGELOG entry under the Fixed section for this?

Added something, suggestions welcome if that's not clear enough.

@Susurrus
Copy link
Contributor

bors r+

bors bot added a commit that referenced this pull request Dec 20, 2017
648:  Fix `struct msghdr` types on non-Linux platforms. r=Susurrus a=kinetiknz

Type `struct msghdr` and `struct cmsghdr` types defined in `sys/socket/ffi.rs` match the Linux headers, but differ from the standard header (and other OSes): http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html

This PR fixes a memory corruption/unsafety issue on non-Linux machines when using `recvmsg` with certain parameters.

While fixing this, I wondered what the reason was for nix not using libc's definition of these structures.

Closes #748.
@bors
Copy link
Contributor

bors bot commented Dec 20, 2017

@bors bors bot merged commit 19ef148 into nix-rust:master Dec 20, 2017
@Susurrus
Copy link
Contributor

Awesome, thanks for following through on this, @kinetiknz. And when/if you have time any additional tests and refinements are always appreciated!

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.

Migrate all FFI declarations to libc
2 participants