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

Use libc::getrandom on Solaris and update docs. #420

Merged
merged 1 commit into from May 6, 2024
Merged

Conversation

josephlr
Copy link
Member

@josephlr josephlr commented May 6, 2024

#417 used getentropy(2) on Solaris, but after looking at the blog post introducing getrandom() and getentropy(), it seems like we should prefer using getrandom based on this quote:

On Solaris the output of getentropy(2) is entropy and should not be used where randomness is needed, in particular it must not be used where an IV or nonce is needed when calling a cryptographic operation. It is intended only for seeding a user space RBG (Random Bit Generator) system. More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG applied to it.

I also updated some of the documentation explaining:

  • Why we ever use getentropy(2)
  • Why we set GRND_RANDOM on Solaris
  • Why we don't ever set GRND_RANDOM on other platforms.

@newpavlov
Copy link
Member

Left comment here just before this PR was created.

@josephlr
Copy link
Member Author

josephlr commented May 6, 2024

Left comment here just before this PR was created.

Sounds good! I'll put Solaris in its own file.

@newpavlov newpavlov mentioned this pull request May 6, 2024
@josephlr josephlr force-pushed the solaris2 branch 3 times, most recently from 8c3cf8d to 43b98f9 Compare May 6, 2024 11:20
@josephlr
Copy link
Member Author

josephlr commented May 6, 2024

@newpavlov I moved Solaris stuff to its own file. I also changed the implementation to always set GRND_RANDOM.

Looking over the man pages, I think your comment in #417 (comment) (noting that all "correct" examples use GRND_RANDOM) is a good point. I don't think it hugely matters one way or another, and if we are doing a special implementation for Solaris, we might as well just mimic what they recommend in their man pages.

Let me know if you want me to change it back to using flags = 0 for consistency with the other uses of getrandom(2).

Copy link
Member

@newpavlov newpavlov left a comment

Choose a reason for hiding this comment

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

I am fine with using GRND_RANDOM to be extra safe. We can change it later, if someone more familiar with the OS will confirm that using zero flag performs like we want.

let ret = unsafe { libc::getrandom(ptr, chunk.len(), libc::GRND_RANDOM) };
if ret != (chunk.len() as isize) {
return Err(last_os_error());
}
Copy link
Member

@newpavlov newpavlov May 6, 2024

Choose a reason for hiding this comment

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

I think it's better to write the ret check like this:

// Upon successful completion, the `getrandom()` function returns the number of
// bytes written to `buf`. Otherwise, it returns 0 and sets `errno` to indicate the error.
if ret == 0 {
    return Err(last_os_error());
}
if ret as usize != chunk.len() {
    return Err(Error::UNEXPECTED);
}

Copy link
Member

@newpavlov newpavlov May 6, 2024

Choose a reason for hiding this comment

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

It also may be worth to add a note that getrandom_inner never receives an empty buffer because of the check in lib.rs.

Copy link
Member Author

@josephlr josephlr May 6, 2024

Choose a reason for hiding this comment

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

Fixed, but I made the error check ret < 0, as it's negative values which indicates errors for getrandom. Then we also don't have to think about zero-length buffer handling here. (though i agree it's fine).

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 weird it seems like the docs contradict themselves:

"Upon successful completion, the getrandom() function returns the number of bytes written to buf. Otherwise, it returns 0 and sets errno to indicate the error."

"the function returns -1 and errno is set to EAGAIN."

Copy link
Member

@newpavlov newpavlov May 6, 2024

Choose a reason for hiding this comment

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

No, the check should be ret == 0 as per the cited man quote (yeah, I was surprised as well...).

UPD: Maybe we should check both 0 and -1 to be extra safe? :)

Copy link
Member Author

@josephlr josephlr May 6, 2024

Choose a reason for hiding this comment

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

Updated to check for negative and zero values and to document the weirdness with the error return value.

Copy link
Member

@newpavlov newpavlov May 6, 2024

Choose a reason for hiding this comment

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

It could be worth to slightly modify the check to have only one branch in the happy path:

if ret as usize != chunk.len() {
    return if ret <= 0 {
        last_os_error()
    } else {
        Err(Error::UNEXPECTED)
    };
}

Copy link
Member Author

Choose a reason for hiding this comment

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

I think that is harder to read (and will probably get compiled to the same thing regardless).

Copy link
Member

Choose a reason for hiding this comment

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

You can tweak formatting to your liking.

will probably get compiled to the same thing regardless

It does not: https://rust.godbolt.org/z/G6d1zq4hs But it's a small enough difference, so I do not insist on this change.

Copy link
Member Author

@josephlr josephlr May 6, 2024

Choose a reason for hiding this comment

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

Oh interesting. I'll leave it as-is, but that's good to know.

I think only casting ret (which is ssize_t) to usize once we know it's not negative is more consistent with how we handle those sorts of values elsewhere.

#417 used `getentropy(2)`
on Solaris, but after looking at
[the blog post introducing `getrandom()` and `getentropy()`](https://blogs.oracle.com/solaris/post/solaris-new-system-calls-getentropy2-and-getrandom2),
it seems like we should prefer using `getrandom` based on this quote:

> On Solaris the output of getentropy(2) is entropy and should not be used where randomness is needed, in particular it must not be used where an IV or nonce is needed when calling a cryptographic operation.  It is intended only for seeding a user space RBG (Random Bit Generator) system. More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG applied to it.

I also updated some of the documentation explaining:
  - Why we use `getentropy(2)`
  - Why we only set `GRND_RANDOM` on Solaris

Signed-off-by: Joe Richey <joerichey@google.com>
@josephlr josephlr merged commit 229d870 into master May 6, 2024
51 checks passed
@josephlr josephlr deleted the solaris2 branch May 6, 2024 12:10
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.

None yet

2 participants