From a55900c84feff144c9aa3832118edd9209f79a4a Mon Sep 17 00:00:00 2001 From: David Dick Date: Thu, 2 Jan 2025 09:19:35 +1100 Subject: [PATCH] Improving code coverage for getrandom XS --- MANIFEST | 1 + t/getrandom.t | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 t/getrandom.t diff --git a/MANIFEST b/MANIFEST index 4e8d37a..4a1d7ea 100644 --- a/MANIFEST +++ b/MANIFEST @@ -7,6 +7,7 @@ README.md lib/Crypt/URandom.pm t/00.load.t t/boilerplate.t +t/getrandom.t t/pod.t t/pp.t t/rand.t diff --git a/t/getrandom.t b/t/getrandom.t new file mode 100644 index 0000000..1c72562 --- /dev/null +++ b/t/getrandom.t @@ -0,0 +1,65 @@ +use Test::More; +use FileHandle(); +use Config; +use strict; +use warnings; + +SKIP: { + if ($^O eq 'linux') { # LD_PRELOAD trick works here + my %optional; + eval `cat ./check_random.pl`; + if (($optional{DEFINE}) && ($optional{DEFINE} eq '-DHAVE_CRYPT_URANDOM_NATIVE_GETRANDOM')) { + + my $failed_number_of_bytes = 13; + my $error_number = POSIX::EINTR() + 0; + my $c_path = 'getrandom.c'; + unlink $c_path or ($! == POSIX::ENOENT()) or die "Failed to unlink $c_path:$!"; + my $c_handle = FileHandle->new($c_path, Fcntl::O_CREAT() | Fcntl::O_WRONLY() | Fcntl::O_EXCL()) or die "Failed to open $c_path for writing:$!"; + print $c_handle <<"_OUT_"; +#include +#include +#include + +ssize_t getrandom(void *buf, size_t buflen, unsigned int flags) { + errno = $error_number; + return $failed_number_of_bytes; +} +_OUT_ + my $binary_path = './getrandom.so'; + my $result = system { $Config{cc} } $Config{cc}, $Config{cccdlflags}, '-shared', '-o', $binary_path, $c_path; + ok($result == 0, "Compiled a LD_PRELOAD binary at $binary_path:$!"); + my $handle = FileHandle->new(); + + if (my $pid = $handle->open(q[-|])) { + my $line = <$handle>; + chomp $line; + my ($actual_error, $entire_message) = split /\t/smx, $line; + $! = POSIX::EINTR(); + my $correct_error = "$!"; + ok($actual_error eq $correct_error, "Correct error caught:'$actual_error' vs '$correct_error'"); + my $correct_message = "Only read $failed_number_of_bytes bytes from getrandom:$actual_error"; + my $quoted_correct_message = quotemeta $correct_message; + ok($entire_message =~ /^$quoted_correct_message/smx, "Error message is correct:$entire_message"); + waitpid $pid, 0; + ok($? == 0, "Successfully caught exception for broken getrandom"); + } elsif (defined $pid) { + local $ENV{LD_PRELOAD} = $binary_path; + eval { + exec { $^X } $^X, (map { "-I$_" } @INC), '-MCrypt::URandom', '-e', 'eval { Crypt::URandom::getrandom(28); } or do { print "$!\t$@\n"; exit 0 }; exit 1;' or die "Failed to exec $^X:$!"; + } or do { + warn "$@"; + }; + exit 1; + } else { + die "Failed to fork:$!"; + } + unlink $c_path or die "Failed to unlink $c_path:$!"; + unlink $binary_path or die "Failed to unlink $binary_path:$!";; + } else { + skip("Not sure about alternative function signatures for $optional{DEFINE}", 1); + } + } else { + skip("Not sure about LD_PRELOAD support in $^O", 1); + } +} +done_testing();