Affix
view release on metacpan or search on metacpan
t/070_security_fixes.t view on Meta::CPAN
use v5.40;
use blib;
use Test2::V0 -no_srand => 1;
use Config;
use Path::Tiny qw[path];
$|++;
#
subtest 'H6: BSD find_library regex uses \Q quoting' => sub {
use Affix::Platform::BSD;
# We can't easily test the regex directly since \Q is consumed by qr//,
# but we CAN test that malicious library names don't produce false matches.
# Verify the regex is compiled (won't die when constructed with evil name)
my $evil_name = q[m; rm -rf /];
my $regex = qr[-l\Q$evil_name\E\.[^\s]+.+\s*=>\s*(.+)$];
# The escaped name should NOT match a legitimate ldconfig output line
unlike '-lm.1 => /lib/libm.so.1', $regex, 'Evil name does not match legitimate ldconfig line';
# A safe name should match ldconfig-style output
my $safe_name = 'm';
my $safe_regex = qr[-l\Q$safe_name\E\.[^\s]+.+\s*=>\s*(.+)$];
like '-lm.1 => /lib/libm.so.1', $safe_regex, 'Safe name matches ldconfig output format';
};
#
subtest 'H7/H8: Macro name validation prevents symbol table injection' => sub {
use Affix::Wrap;
# Valid macro
my $valid = Affix::Wrap::Macro->new( name => 'SAFE_CONST', value => '42' );
my $result = $valid->affix( undef, 'Test::H7Valid' );
ok defined $result, 'affix() returns for valid name';
# The generated constant should work via use constant
my $code = $valid->affix_type;
ok eval "package Test::H7Valid; $code; 1", 'Generated constant compiles' or diag "eval error: $@";
# Evil macro name â should NOT install into symbol table
my $evil = Affix::Wrap::Macro->new( name => 'EVIL; system("echo PWNED")', value => '1', );
$result = $evil->affix( undef, 'Test::H7Evil' );
ok defined $result, 'affix() returns for evil name (no crash)';
# The evil name must NOT be accessible as a subroutine in the target package
ok !defined $Test::H7Evil::{'EVIL; system("echo PWNED")'}, 'Evil name NOT installed in symbol table';
};
#
subtest 'H7/H8: Enum constant name validation' => sub {
use Affix qw[Enum];
my $type = Enum [ [ RED => 0 ], [ GREEN => 1 ], [ BLUE => 2 ], ];
ok defined $type, 'Enum type created';
my ( $const_map, $val_map ) = $type->resolve();
is ref $const_map, 'HASH', 'const_map is a hash';
ok exists $const_map->{RED}, 'RED in const_map';
ok exists $const_map->{GREEN}, 'GREEN in const_map';
ok exists $const_map->{BLUE}, 'BLUE in const_map';
};
#
subtest 'M4: Double-quote C string literal stripping in affix_type' => sub {
use Affix::Wrap;
my $macro = Affix::Wrap::Macro->new( name => 'GREETING', value => '"Hello World"', );
my $code = $macro->affix_type;
like $code, qr/use constant GREETING => 'Hello World'/, 'Double-quoted string stripped of outer quotes';
unlike $code, qr/"Hello World"/, 'No remaining double quotes in generated code';
ok eval "package Test::M4; $code; 1", 'Generated constant compiles' or diag "eval error: $@";
};
#
subtest 'M5: Path traversal prevention in Affix::Build output name' => sub {
skip_all 'No CC' unless $Config{cc};
use Affix::Build;
my $TMP_DIR = Path::Tiny->tempdir( CLEANUP => 1 );
my $c = Affix::Build->new( build_dir => $TMP_DIR, name => '../../etc/passwd' );
$c->add( \<<~'', lang => 'c' );
#include <stdio.h>
int traversal_test(void) { return 42; }
ok eval { $c->compile_and_link() }, 'Compiled despite malicious name';
my $lib = $c->link;
unlike "$lib", qr/\.\.[\/\\]/, 'Output path contains no path traversal';
};
#
subtest 'M13: Division by zero in _calculate_expr' => sub {
use Affix qw[Enum];
# _calculate_expr is in Affix::Type::Enum, accessible via resolve
# We can test indirectly by defining enums with division expressions
my $type = Enum [ [ HALF => '10 / 2' ], [ ZERO => '10 / 0' ], [ REM => '10 % 3' ], [ REMZ => '10 % 0' ], ];
ok defined $type, 'Enum with division expressions created';
my ( $const_map, $val_map ) = $type->resolve();
is $const_map->{HALF}, 5, '10 / 2 = 5';
is $const_map->{ZERO}, 0, '10 / 0 = 0 (not crash)';
is $const_map->{REM}, 1, '10 % 3 = 1';
is $const_map->{REMZ}, 0, '10 % 0 = 0 (not crash)';
};
#
subtest 'M14/L12: DynaLoader typo fix' => sub {
is $DynaLoader::dl_debug, 0, '$DynaLoader::dl_debug is set to 0 (not 1, no noisy bootstrap)';
};
done_testing;
( run in 0.601 second using v1.01-cache-2.11-cpan-14f38c9f855 )