Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion lib/Test/Smoke/Policy.pm
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ sub default_Policy {
my $self = shift;
my @ccflags = @_ ? @_ : qw( -DDEBUGGING );

my @escaped = map { _shell_escape_sq($_) } @ccflags;
local $" = " ";
return <<__EOPOLICY__;
#!/bin/sh
Expand All @@ -205,10 +206,23 @@ sub default_Policy {
# Be sure to define -DDEBUGGING by default, it's easier to remove
# it from Policy.sh than it is to add it in on the correct places

ccflags='@ccflags'
ccflags='@escaped'
__EOPOLICY__
}

=head2 _shell_escape_sq( $string )

Escape a string for use inside a single-quoted shell context.
Replaces each C<'> with C<'\''> (end quote, escaped quote, reopen quote).

=cut

sub _shell_escape_sq {
my ($str) = @_;
$str =~ s/'/'\\''/g;
return $str;
}

1;

=head1 COPYRIGHT
Expand Down
23 changes: 22 additions & 1 deletion t/policy.t
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use lib $findbin;
use TestLib;
use Test::Smoke::Util qw( get_config );
use Data::Dumper;
use Test::More tests => 3 + 8 + 24 + 2;
use Test::More tests => 3 + 8 + 24 + 2 + 4;

use_ok( 'Test::Smoke::Policy' );

Expand Down Expand Up @@ -119,3 +119,24 @@ sub run_tests {
like $p->{_policy}, "/ccflags='@ccflags'/",
"Default policy created with '@ccflags'";
}

{ # Test shell injection prevention in default_Policy

# _shell_escape_sq should escape single quotes
is( Test::Smoke::Policy::_shell_escape_sq("no quotes"),
"no quotes", "No-op when no single quotes" );

is( Test::Smoke::Policy::_shell_escape_sq("-DPATH='/usr/local'"),
"-DPATH='\\''\/usr\/local'\\''",
"Single quotes escaped with shell-safe sequence" );

# Verify the generated policy escapes quotes rather than passing them raw
my $p = Test::Smoke::Policy->new( undef, 0, "-DPATH='/usr'" );
like $p->{_policy}, qr/ccflags=.*\\'/,
"Single quotes in ccflags are escaped (contain backslash-quote sequence)";

# Shell metacharacters without quotes pass through (safe inside single quotes)
$p = Test::Smoke::Policy->new( undef, 0, '-DFOO=`whoami`' );
like $p->{_policy}, qr/ccflags=.*`whoami`/,
"Backticks pass through (harmless inside single quotes)";
}