diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 3cd0e3e..23e101e 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: perl -V - name: install dependencies uses: perl-actions/install-with-cpm@v1 @@ -46,26 +46,21 @@ jobs: matrix: perl-version: [ + "5.40", + "5.38", + "5.36", + "5.34", "5.32", "5.30", "5.28", "5.26", - "5.24", - "5.22", - "5.20", - "5.18", - "5.16", - "5.14", - "5.12", - "5.10", - "5.8", ] container: image: perl:${{ matrix.perl-version }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: perl -V - name: install dependencies uses: perl-actions/install-with-cpm@v1 @@ -77,6 +72,37 @@ jobs: - name: make test run: make test + windows: + needs: [ubuntu] + env: + PERL_USE_UNSAFE_INC: 0 + AUTHOR_TESTING: 1 + AUTOMATED_TESTING: 1 + RELEASE_TESTING: 1 + + runs-on: windows-latest + + strategy: + fail-fast: false + matrix: + perl-version: [latest] + + steps: + - uses: actions/checkout@v4 + - name: Set up Perl + uses: shogo82148/actions-setup-perl@v1 + with: + perl-version: ${{ matrix.perl-version }} + - run: perl -V + - name: install dependencies + uses: perl-actions/install-with-cpm@v1 + with: + cpanfile: "cpanfile" + - name: Makefile.PL + run: perl Makefile.PL + - name: make test + run: gmake test + macOS: needs: [ubuntu] env: @@ -93,7 +119,7 @@ jobs: perl-version: [latest] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - run: perl -V - name: install dependencies uses: perl-actions/install-with-cpm@v1 diff --git a/digest-bench b/digest-bench index f828b2b..e9828b1 100755 --- a/digest-bench +++ b/digest-bench @@ -5,10 +5,11 @@ die unless @ARGV; my ( $mod, @args ) = @ARGV; -eval "require $mod"; -die $@ if $@; +my $pm_file = $mod . ".pm"; +$pm_file =~ s{::}{/}g; +require $pm_file; -$a = substr( join( "", "a" .. "z", ) x 800, 0, 8 * 1024 ); +my $a = substr( join( "", "a" .. "z", ) x 800, 0, 8 * 1024 ); my $count = 4 * 1024; use Time::HiRes qw(time); diff --git a/t/security.t b/t/security.t index 5cba122..c2439e0 100644 --- a/t/security.t +++ b/t/security.t @@ -1,14 +1,29 @@ #!/usr/bin/env perl -# Digest->new() had an exploitable eval +# Security tests: eval-based require patterns are exploitable use strict; use warnings; -use Test::More tests => 1; +use Test::More tests => 2; use Digest; +# Test 1: Digest->new() had an exploitable eval $LOL::PWNED = 0; eval { Digest->new(q[MD;5;$LOL::PWNED = 42]) }; -is $LOL::PWNED, 0; +is $LOL::PWNED, 0, 'Digest->new does not eval-inject via module name'; + +# Test 2: digest-bench must not allow code injection via module name +# With eval "require $mod", an attacker can append arbitrary Perl after a +# valid module name. The payload executes inside the eval and can create +# files, open sockets, etc. A safe bare require prevents this entirely. +{ + use File::Temp qw(tmpnam); + my $canary = tmpnam(); + # Payload: require a real module, then create a canary file as proof of execution + my $payload = qq{Digest::MD5; open my \\\$fh, '>', '$canary'}; + `$^X digest-bench "$payload" 2>&1`; + ok(! -e $canary, 'digest-bench does not execute injected code in module name'); + unlink $canary if -e $canary; # cleanup if test fails +}