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

Add getrandom impl using ctru_sys bindings #8

Merged
merged 3 commits into from
Feb 1, 2022

Conversation

ian-h-chamberlain
Copy link
Member

@ian-h-chamberlain ian-h-chamberlain commented Jan 30, 2022

Ref Meziu/rust-horizon#6

Add a getrandom call that libc can link against. This will also require a change to libc to declare an extern "C" fn getrandom and then finally update std to utilize that call when target_os = "horizon".

Two main questions:

  • Is this the right place to put this impl? we could put it in ctru-sys instead if we wanted, but putting it here feels like a "linker-fix" to me. It does require adding the dependency on ctru-sys, though.
  • How do we want to handle conversion errors? try_into().unwrap() feels a bit heavy-handed, maybe if the conversion fails we should set errno or something? Does ctru-sys have an API for something like errno for us to set in case of non-zero return values from the PS_ syscall?

@Meziu @AzureMarker

@Meziu
Copy link
Member

Meziu commented Jan 30, 2022

Make a PR to libc too.

@Meziu
Copy link
Member

Meziu commented Jan 30, 2022

Is this the right place to put this impl?

Yes, this is a standard Newlib function, and it's a linker fix for it since it's not normally available.

@AzureMarker
Copy link
Member

At some point we should consider renaming the linker fix lib to something like ctru-libc-polyfill.

src/lib.rs Outdated
buflen: libc::size_t,
_flags: libc::c_uint,
) -> libc::ssize_t {
let ret = ctru_sys::psInit();
Copy link
Member

Choose a reason for hiding this comment

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

Does this need to happen every time, or can we lazily initialize it with something like core::sync::Once?

Also, do we need to call psExit or not worry about it?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question re: psExit. The docs are pretty sparse on what these functions actually do, but I would assume that it is more correct to call it before the program ends. I'm not really sure how we could handle something like that in this crate... maybe this impl should only call PS_GenerateRandomBytes and it's up to the user to initialize / exit PS itself?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, also – as far as I can tell there's no problem calling it more than once, but it could be done with Once if we wanted to avoid the potential overhead

Copy link
Member

@AzureMarker AzureMarker Jan 31, 2022

Choose a reason for hiding this comment

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

If it's OK with not calling psExit then I'd go with the Once route.

Copy link
Member Author

@ian-h-chamberlain ian-h-chamberlain Jan 31, 2022

Choose a reason for hiding this comment

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

I opted to remove psInit entirely, as I think it makes more sense to treat Ps the way e.g. Gfx and Apt are in ctru-rs already (and I have a local changeset to do so). With the new implementation I pushed, failing to initialize the Ps causes a runtime panic (from std) if the user tries to e.g. construct a HashMap, but everything works if they do initialize it.

src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
@ian-h-chamberlain
Copy link
Member Author

Trying it out with a real application (HashMap), and I think there is some additional work to make it work as expected, e.g. https://man7.org/linux/man-pages/man2/getrandom.2.html#RETURN_VALUE

src/lib.rs Outdated
mut buflen: libc::size_t,
flags: libc::c_uint,
) -> libc::ssize_t {
// TODO: is this needed? Maybe just `buflen = buflen.min(libc::ssize_t::MAX)` ?
Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

@Meziu Meziu Jan 31, 2022

Choose a reason for hiding this comment

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

There is the GRND_RANDOM flag for using random instead of urandom(under linux). Maybe we could check those to change the maximum buffer length(for urandom it's 33554431, while for random it's 512), so it would more closely resemble the original.

GRND_NONBLOCK instead looks like it can just be ignored, as it doesn't change how our code behaves.

We don't need to return errors when those flags are set.

Copy link
Member Author

Choose a reason for hiding this comment

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

Interesting... as it turns out, getrandom, getentropy, GRND_NONBLOCK, and GRND_RANDOM seem to only be defined in newlib for Cygwin, and not on 3DS (or any other platform).

So, I guess I will just add them to horizon/mod.rs in libc, and anyone using it will just have to live with the fact that GRND_NONBLOCK doesn't work at all.

src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated
let ret = ctru_sys::PS_GenerateRandomBytes(buf, buflen as libc::c_uint) as libc::ssize_t;
if ret < 0 {
// this is kind of a hack, but at least gives some visibility to the
// error code returned by PS_GenerateRandomBytes I guess? Another option
Copy link
Member

Choose a reason for hiding this comment

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

Based on this header file, these error codes aren't compatible:
https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/result.h

We would probably want to parse the 3ds result and return the appropriate error code.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, std implementation seems to just report them as "unexpected error code XYZ" if I set it in errno here. I have some local changes to sort of "parse" those error codes based on https://www.3dbrew.org/wiki/Error_codes but seeing that header, I wonder if we can just leverage ports of those macros instead. Let me see if I can put something in ctru-sys for this...

Copy link
Member

Choose a reason for hiding this comment

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

Looks nice! 👍

@ian-h-chamberlain
Copy link
Member Author

Okay, I've updated all relevant PRs for getrandom with what I think makes sense and based on your comments. Let me know if any further changes are necessary, in particular I think the ctru_sys::Result -> errno code is not perfect, but I'm not sure what else we can do since there is not a 1-to-1 translation.

Copy link
Member

@Meziu Meziu left a comment

Choose a reason for hiding this comment

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

Looks good! Will merge once rust3ds/ctru-rs#35 is finalized.

@Meziu Meziu merged commit f6c3cde into rust3ds:master Feb 1, 2022
@rust3ds rust3ds locked and limited conversation to collaborators Feb 1, 2022
@rust3ds rust3ds unlocked this conversation Feb 1, 2022
@Meziu
Copy link
Member

Meziu commented Feb 1, 2022

OH, having linker-fix depend on ctru-sys creates a dependency duplication error in cargo. @ian-h-chamberlain

@ian-h-chamberlain
Copy link
Member Author

OH, having linker-fix depend kn ctru-sys creates a dependency duplication error in cargo. @ian-h-chamberlain

Ah yeah, I think I didn't notice because I had so many [patch]es going during testing. I think it's easy enough to result by adding one, let me see...

@Meziu
Copy link
Member

Meziu commented Feb 1, 2022

Fixed in rust3ds/ctru-rs@c59de27 @ian-h-chamberlain

It is cool to have that link field, but ultimately useless, since the library is linked by cargo-3ds at the top level.

@ian-h-chamberlain
Copy link
Member Author

Fixed in Meziu/ctru-rs@c59de27 @ian-h-chamberlain

It is cool to have that link field, but ultimately useless, since the library is linked by cargo-3ds at the top level.

That's true, I think technically we could remove it from cargo-3ds if we left it in the ctru-sys Cargo.toml. We may still want the [patch], since otherwise there could be confusing issues in the dependency resolution:

$ cargo tree 
ctru-rs v0.7.1 (/Users/ianchamberlain/Documents/Development/3ds/ctru-rs/ctru-rs)
├── bitflags v1.3.2
├── cfg-if v1.0.0
├── const-zero v0.1.0
├── ctru-sys v0.4.0 (/Users/ianchamberlain/Documents/Development/3ds/ctru-rs/ctru-sys)
│   └── libc v0.2.116 (https://github.com/Meziu/libc.git#ab957c0c)
├── libc v0.2.116 (https://github.com/Meziu/libc.git#ab957c0c)
├── linker-fix-3ds v0.1.0 (https://github.com/Meziu/rust-linker-fix-3ds.git#f6c3cde6)
│   ├── ctru-sys v0.4.0 (https://github.com/Meziu/ctru-rs.git#c59de27f)
│   │   └── libc v0.2.116 (https://github.com/Meziu/libc.git#ab957c0c)
│   └── libc v0.2.116 (https://github.com/Meziu/libc.git#ab957c0c)
...

See how there are two different versions of ctru-sys?

@Meziu
Copy link
Member

Meziu commented Feb 1, 2022

Yes, absolutely, dependency duplicates aren't cool but link = ctru can't stay anyways. ctru wouldn't link to the standard otherwise.

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.

3 participants