@@ -23,6 +23,7 @@ import (
2323 "testing"
2424 "time"
2525
26+ "github.com/google/go-cmp/cmp"
2627 "github.com/hashicorp/terraform/internal/communicator/remote"
2728 "github.com/zclconf/go-cty/cty"
2829 "golang.org/x/crypto/ssh"
@@ -660,7 +661,7 @@ func TestAccHugeUploadFile(t *testing.T) {
660661 return scpUploadFile (targetFile , source , w , stdoutR , size )
661662 }
662663
663- cmd , err := quoteShell ([]string {"scp" , "-vt" , targetDir }, c .connInfo .TargetPlatform )
664+ cmd , err := quoteScpCommand ([]string {"scp" , "-vt" , targetDir }, c .connInfo .TargetPlatform )
664665 if err != nil {
665666 t .Fatal (err )
666667 }
@@ -680,6 +681,146 @@ func TestAccHugeUploadFile(t *testing.T) {
680681 }
681682}
682683
684+ func TestQuoteScpCommand (t * testing.T ) {
685+ testCases := []struct {
686+ inputArgs []string
687+ platform string
688+ expectedCmd string
689+ }{
690+ // valid Unix command
691+ {
692+ []string {"scp" , "-vt" , "/var/path" },
693+ TargetPlatformUnix ,
694+ "'scp' -vt /var/path" ,
695+ },
696+
697+ // command injection attempt in Unix
698+ {
699+ []string {"scp" , "-vt" , "/var/path;rm" },
700+ TargetPlatformUnix ,
701+ "'scp' -vt /var/path\\ ;rm" ,
702+ },
703+ {
704+ []string {"scp" , "-vt" , "/var/path&&rm" },
705+ TargetPlatformUnix ,
706+ "'scp' -vt /var/path\\ &\\ &rm" ,
707+ },
708+ {
709+ []string {"scp" , "-vt" , "/var/path|rm" },
710+ TargetPlatformUnix ,
711+ "'scp' -vt /var/path\\ |rm" ,
712+ },
713+ {
714+ []string {"scp" , "-vt" , "/var/path||rm" },
715+ TargetPlatformUnix ,
716+ "'scp' -vt /var/path\\ |\\ |rm" ,
717+ },
718+ {
719+ []string {"scp" , "-vt" , "/var/path; rm" },
720+ TargetPlatformUnix ,
721+ "'scp' -vt '/var/path; rm'" ,
722+ },
723+ {
724+ []string {"scp" , "-vt" , "/var/path`rm`" },
725+ TargetPlatformUnix ,
726+ "'scp' -vt /var/path\\ `rm\\ `" ,
727+ },
728+ {
729+ []string {"scp" , "-vt" , "/var/path$(rm)" },
730+ TargetPlatformUnix ,
731+ "'scp' -vt /var/path\\ $\\ (rm\\ )" ,
732+ },
733+
734+ // valid Windows commands
735+ {
736+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp" },
737+ TargetPlatformWindows ,
738+ "scp -vt C:\\ Windows\\ Temp" ,
739+ },
740+ {
741+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp With Space" },
742+ TargetPlatformWindows ,
743+ "scp -vt \" C:\\ Windows\\ Temp With Space\" " ,
744+ },
745+
746+ // command injection attempt in Windows
747+ {
748+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp ;rmdir" },
749+ TargetPlatformWindows ,
750+ "scp -vt \" C:\\ Windows\\ Temp ;rmdir\" " ,
751+ },
752+ {
753+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp\" ;rmdir" },
754+ TargetPlatformWindows ,
755+ "scp -vt \" C:\\ Windows\\ Temp\\ \" ;rmdir\" " ,
756+ },
757+ {
758+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp\n rmdir" },
759+ TargetPlatformWindows ,
760+ "scp -vt \" C:\\ Windows\\ Temp\n rmdir\" " ,
761+ },
762+ {
763+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp\t rmdir" },
764+ TargetPlatformWindows ,
765+ "scp -vt \" C:\\ Windows\\ Temp\t rmdir\" " ,
766+ },
767+ {
768+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp\v rmdir" },
769+ TargetPlatformWindows ,
770+ "scp -vt \" C:\\ Windows\\ Temp\v rmdir\" " ,
771+ },
772+ {
773+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp\u0020 rmdir" },
774+ TargetPlatformWindows ,
775+ "scp -vt \" C:\\ Windows\\ Temp rmdir\" " ,
776+ },
777+
778+ // There is no special handling of the injection attempts below
779+ // but we include them anyway to demonstrate this
780+ // and to avoid any regressions due to upstream changes.
781+ {
782+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp;rmdir" },
783+ TargetPlatformWindows ,
784+ "scp -vt C:\\ Windows\\ Temp;rmdir" ,
785+ },
786+ {
787+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp&rmdir" },
788+ TargetPlatformWindows ,
789+ "scp -vt C:\\ Windows\\ Temp&rmdir" ,
790+ },
791+ {
792+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp&&rmdir" },
793+ TargetPlatformWindows ,
794+ "scp -vt C:\\ Windows\\ Temp&&rmdir" ,
795+ },
796+ {
797+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp|rmdir" },
798+ TargetPlatformWindows ,
799+ "scp -vt C:\\ Windows\\ Temp|rmdir" ,
800+ },
801+ {
802+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp||rmdir" },
803+ TargetPlatformWindows ,
804+ "scp -vt C:\\ Windows\\ Temp||rmdir" ,
805+ },
806+ {
807+ []string {"scp" , "-vt" , "C:\\ Windows\\ Temp$(rmdir)" },
808+ TargetPlatformWindows ,
809+ "scp -vt C:\\ Windows\\ Temp$(rmdir)" ,
810+ },
811+ }
812+
813+ for _ , tc := range testCases {
814+ cmd , err := quoteScpCommand (tc .inputArgs , tc .platform )
815+ if err != nil {
816+ t .Fatal (err )
817+ }
818+ if diff := cmp .Diff (tc .expectedCmd , cmd ); diff != "" {
819+ t .Fatalf ("unexpected command for %q: %s" , tc .inputArgs , diff )
820+ }
821+ }
822+ }
823+
683824func TestScriptPath (t * testing.T ) {
684825 cases := []struct {
685826 Input string
0 commit comments