From c537c6905f171ed28eb867d17f89ba7c04419d1f Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 26 Dec 2023 16:01:32 +0800 Subject: [PATCH 01/14] initial commits Signed-off-by: Patrick Zheng --- cmd/notation/internal/plugin/plugin.go | 5 ++- cmd/notation/plugin/install.go | 27 +++++++----- internal/osutil/file.go | 4 +- specs/commandline/plugin.md | 2 +- test/e2e/internal/notation/init.go | 41 ++++++++++-------- test/e2e/run.sh | 3 +- test/e2e/suite/plugin/install.go | 21 ++++++--- .../malicious-plugin/largeFileZip.zip | Bin 0 -> 332387 bytes 8 files changed, 59 insertions(+), 44 deletions(-) create mode 100644 test/e2e/testdata/malicious-plugin/largeFileZip.zip diff --git a/cmd/notation/internal/plugin/plugin.go b/cmd/notation/internal/plugin/plugin.go index e06f57c18..65f0f2b34 100644 --- a/cmd/notation/internal/plugin/plugin.go +++ b/cmd/notation/internal/plugin/plugin.go @@ -52,7 +52,8 @@ const ( // URL const DownloadPluginFromURLTimeout = 10 * time.Minute -// DownloadPluginFromURL downloads plugin file from url to a tmp directory +// DownloadPluginFromURL downloads plugin source from url to a tmp file on file +// system func DownloadPluginFromURL(ctx context.Context, pluginURL string, tmpFile io.Writer) error { // Get the data client := httputil.NewAuthClient(ctx, &http.Client{Timeout: DownloadPluginFromURLTimeout}) @@ -79,7 +80,7 @@ func DownloadPluginFromURL(ctx context.Context, pluginURL string, tmpFile io.Wri return err } if lr.N == 0 { - return fmt.Errorf("%s %q: https response reaches the %d MiB size limit", resp.Request.Method, resp.Request.URL, MaxPluginSourceBytes) + return fmt.Errorf("%s %q: plugin size reached the %d MiB size limit", resp.Request.Method, resp.Request.URL, MaxPluginSourceBytes) } return nil } diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index 2dfed9093..297a27d99 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -73,6 +73,9 @@ Example - Install plugin from file system regardless if it's already installed: Example - Install plugin from file system with .tar.gz: notation plugin install --file wabbit-plugin-v1.0.tar.gz +Example - Install plugin from file system with a single plugin executable file: + notation plugin install --file notation-wabbit-plugin + Example - Install plugin from URL, SHA256 checksum is required: notation plugin install --url https://wabbit-networks.com/intaller/linux/amd64/wabbit-plugin-v1.0.tar.gz --sha256sum f8a75d9234db90069d9eb5660e5374820edf36d710bd063f4ef81e7063d3810b `, @@ -84,10 +87,10 @@ Example - Install plugin from URL, SHA256 checksum is required: case opts.isURL: return errors.New("missing plugin URL") } - return errors.New("missing plugin source") + return errors.New("missing plugin source location") } if len(args) > 1 { - return fmt.Errorf("can only insall one plugin at a time, but got %v", args) + return fmt.Errorf("can only install one plugin at a time, but got %v", args) } opts.pluginSource = args[0] return nil @@ -103,8 +106,8 @@ Example - Install plugin from URL, SHA256 checksum is required: }, } opts.LoggingFlagOpts.ApplyFlags(command.Flags()) - command.Flags().BoolVar(&opts.isFile, "file", false, "install plugin from a file in file system") - command.Flags().BoolVar(&opts.isURL, "url", false, "install plugin from an HTTPS URL. The timeout of the download HTTPS request is set to 10 minutes") + command.Flags().BoolVar(&opts.isFile, "file", false, "install plugin from a file on file system") + command.Flags().BoolVar(&opts.isURL, "url", false, "install plugin from an HTTPS URL. The default plugin download timeout is 10 minutes") command.Flags().StringVar(&opts.inputChecksum, "sha256sum", "", "must match SHA256 of the plugin source, required when \"--url\" flag is set") command.Flags().BoolVar(&opts.force, "force", false, "force the installation of the plugin") command.MarkFlagsMutuallyExclusive("file", "url") @@ -135,7 +138,7 @@ func install(command *cobra.Command, opts *pluginInstallOpts) error { } tmpFile, err := os.CreateTemp("", notationPluginDownloadTmpFile) if err != nil { - return fmt.Errorf("failed to create notationPluginDownloadTmpFile: %w", err) + return fmt.Errorf("failed to create temporary file required for downloading plugin: %w", err) } defer os.Remove(tmpFile.Name()) defer tmpFile.Close() @@ -200,17 +203,17 @@ func installPlugin(ctx context.Context, inputPath string, inputChecksum string, // from a fs.FS // // Note: zip.ReadCloser implments fs.FS -func installPluginFromFS(ctx context.Context, pluginFs fs.FS, force bool) error { +func installPluginFromFS(ctx context.Context, pluginFS fs.FS, force bool) error { // set up logger logger := log.GetLogger(ctx) root := "." // extracting all regular files from root into tmpDir tmpDir, err := os.MkdirTemp("", notationPluginTmpDir) if err != nil { - return fmt.Errorf("failed to create notationPluginTmpDir: %w", err) + return fmt.Errorf("failed to create temporary directory: %w", err) } defer os.RemoveAll(tmpDir) - if err := fs.WalkDir(pluginFs, root, func(path string, d fs.DirEntry, err error) error { + if err := fs.WalkDir(pluginFS, root, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } @@ -228,7 +231,7 @@ func installPluginFromFS(ctx context.Context, pluginFs fs.FS, force bool) error return nil } logger.Debugf("Extracting file %s...", fName) - rc, err := pluginFs.Open(path) + rc, err := pluginFS.Open(path) if err != nil { return err } @@ -264,7 +267,7 @@ func installPluginFromTarGz(ctx context.Context, tarGzPath string, force bool) e // extracting all regular files into tmpDir tmpDir, err := os.MkdirTemp("", notationPluginTmpDir) if err != nil { - return fmt.Errorf("failed to create notationPluginTmpDir: %w", err) + return fmt.Errorf("failed to create temporary directory: %w", err) } defer os.RemoveAll(tmpDir) for { @@ -307,9 +310,9 @@ func installPluginWithOptions(ctx context.Context, opts plugin.CLIInstallOptions return err } if existingPluginMetadata != nil { - fmt.Printf("Succussefully installed plugin %s, updated the version from %s to %s\n", newPluginMetadata.Name, existingPluginMetadata.Version, newPluginMetadata.Version) + fmt.Printf("Successfully updated plugin %s from version %s to %s\n", newPluginMetadata.Name, existingPluginMetadata.Version, newPluginMetadata.Version) } else { - fmt.Printf("Succussefully installed plugin %s, version %s\n", newPluginMetadata.Name, newPluginMetadata.Version) + fmt.Printf("Successfully installed plugin %s, version %s\n", newPluginMetadata.Name, newPluginMetadata.Version) } return nil } diff --git a/internal/osutil/file.go b/internal/osutil/file.go index d2de17ce5..37eb42292 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -119,7 +119,7 @@ func CopyFromReaderToDir(src io.Reader, dst string, perm fs.FileMode) error { if err != nil { return err } - return fmt.Errorf("file reaches the %d MiB size limit", MaxFileBytes) + return fmt.Errorf("file reached the %d MiB size limit", MaxFileBytes) } if err := dstFile.Chmod(perm); err != nil { _ = dstFile.Close() @@ -157,7 +157,7 @@ func ValidateSHA256Sum(path string, checksum string) error { sha256sum := sha256Hash.Sum(nil) enc := hex.EncodeToString(sha256sum[:]) if !strings.EqualFold(enc, checksum) { - return fmt.Errorf("plugin checksum does not match user input. Expecting %s", checksum) + return fmt.Errorf("plugin sha256sum does not match user input. Expecting %s", checksum) } return nil } diff --git a/specs/commandline/plugin.md b/specs/commandline/plugin.md index 8ab20e54f..4781c06db 100644 --- a/specs/commandline/plugin.md +++ b/specs/commandline/plugin.md @@ -48,7 +48,7 @@ Usage: Flags: -d, --debug debug mode - --file install plugin from a file in file system + --file install plugin from a file on file system --force force the installation of a plugin -h, --help help for install --sha256sum string must match SHA256 of the plugin source diff --git a/test/e2e/internal/notation/init.go b/test/e2e/internal/notation/init.go index 2e1659917..110a7dde1 100644 --- a/test/e2e/internal/notation/init.go +++ b/test/e2e/internal/notation/init.go @@ -33,18 +33,19 @@ const ( ) const ( - envKeyRegistryHost = "NOTATION_E2E_REGISTRY_HOST" - envKeyRegistryUsername = "NOTATION_E2E_REGISTRY_USERNAME" - envKeyRegistryPassword = "NOTATION_E2E_REGISTRY_PASSWORD" - envKeyDomainRegistryHost = "NOTATION_E2E_DOMAIN_REGISTRY_HOST" - envKeyNotationBinPath = "NOTATION_E2E_BINARY_PATH" - envKeyNotationOldBinPath = "NOTATION_E2E_OLD_BINARY_PATH" - envKeyNotationPluginPath = "NOTATION_E2E_PLUGIN_PATH" - envKeyNotationPluginTarGzPath = "NOTATION_E2E_PLUGIN_TAR_GZ_PATH" - envKeyNotationConfigPath = "NOTATION_E2E_CONFIG_PATH" - envKeyOCILayoutPath = "NOTATION_E2E_OCI_LAYOUT_PATH" - envKeyTestRepo = "NOTATION_E2E_TEST_REPO" - envKeyTestTag = "NOTATION_E2E_TEST_TAG" + envKeyRegistryHost = "NOTATION_E2E_REGISTRY_HOST" + envKeyRegistryUsername = "NOTATION_E2E_REGISTRY_USERNAME" + envKeyRegistryPassword = "NOTATION_E2E_REGISTRY_PASSWORD" + envKeyDomainRegistryHost = "NOTATION_E2E_DOMAIN_REGISTRY_HOST" + envKeyNotationBinPath = "NOTATION_E2E_BINARY_PATH" + envKeyNotationOldBinPath = "NOTATION_E2E_OLD_BINARY_PATH" + envKeyNotationPluginPath = "NOTATION_E2E_PLUGIN_PATH" + envKeyNotationPluginTarGzPath = "NOTATION_E2E_PLUGIN_TAR_GZ_PATH" + envKeyNotationMaliciouPluginArchivePath = "NOTATION_E2E_MALICIOUS_PLUGIN_ARCHIVE_PATH" + envKeyNotationConfigPath = "NOTATION_E2E_CONFIG_PATH" + envKeyOCILayoutPath = "NOTATION_E2E_OCI_LAYOUT_PATH" + envKeyTestRepo = "NOTATION_E2E_TEST_REPO" + envKeyTestTag = "NOTATION_E2E_TEST_TAG" ) var ( @@ -52,13 +53,14 @@ var ( NotationBinPath string // NotationOldBinPath is the path of an old version notation binary for // testing forward compatibility. - NotationOldBinPath string - NotationE2EPluginPath string - NotationE2EPluginTarGzPath string - NotationE2EConfigPath string - NotationE2ELocalKeysDir string - NotationE2ETrustPolicyDir string - NotationE2EConfigJsonDir string + NotationOldBinPath string + NotationE2EPluginPath string + NotationE2EPluginTarGzPath string + NotationE2EMaliciousPluginArchivePath string + NotationE2EConfigPath string + NotationE2ELocalKeysDir string + NotationE2ETrustPolicyDir string + NotationE2EConfigJsonDir string ) var ( @@ -93,6 +95,7 @@ func setUpNotationValues() { // set Notation e2e-plugin path setPathValue(envKeyNotationPluginPath, &NotationE2EPluginPath) setPathValue(envKeyNotationPluginTarGzPath, &NotationE2EPluginTarGzPath) + setPathValue(envKeyNotationMaliciouPluginArchivePath, &NotationE2EMaliciousPluginArchivePath) // set Notation configuration paths setPathValue(envKeyNotationConfigPath, &NotationE2EConfigPath) diff --git a/test/e2e/run.sh b/test/e2e/run.sh index a3ce61864..7da050cb4 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -73,7 +73,7 @@ go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo@v2.9.5 # build e2e plugin and tar.gz PLUGIN_NAME=notation-e2e-plugin -( cd $CWD/plugin && go build -o ./bin/$PLUGIN_NAME . && echo "e2e plugin built." && tar -czvf ./bin/$PLUGIN_NAME.tar.gz -C ./bin/ $PLUGIN_NAME) +( cd $CWD/plugin && go build -o ./bin/$PLUGIN_NAME . && echo "e2e plugin built." && tar -czvf ./bin/$PLUGIN_NAME.tar.gz -C ./bin/ $PLUGIN_NAME ) # setup registry case $REGISTRY_NAME in @@ -108,6 +108,7 @@ export NOTATION_E2E_TEST_REPO=e2e export NOTATION_E2E_TEST_TAG=v1 export NOTATION_E2E_PLUGIN_PATH=$CWD/plugin/bin/$PLUGIN_NAME export NOTATION_E2E_PLUGIN_TAR_GZ_PATH=$CWD/plugin/bin/$PLUGIN_NAME.tar.gz +export NOTATION_E2E_MALICIOUS_PLUGIN_ARCHIVE_PATH=$CWD/testdata/malicious-plugin # run tests ginkgo -r -p -v \ No newline at end of file diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index bd85d0389..c85dc97c0 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -42,7 +42,7 @@ var _ = Describe("notation plugin install", func() { It("with missing plugin source", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install"). - MatchErrContent("Error: missing plugin source\n") + MatchErrContent("Error: missing plugin source location\n") }) }) @@ -60,24 +60,31 @@ var _ = Describe("notation plugin install", func() { }) }) + It("with zip file too large", func() { + Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { + notation.Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileZip.zip", "-v"). + MatchContent("Successfully installed plugin e2e-plugin, version 1.0.0\n") + }) + }) + It("with valid plugin file path", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.Exec("plugin", "install", "--file", NotationE2EPluginTarGzPath, "-v"). - MatchContent("Succussefully installed plugin e2e-plugin, version 1.0.0\n") + MatchContent("Successfully installed plugin e2e-plugin, version 1.0.0\n") }) }) It("with plugin executable file path", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.Exec("plugin", "install", "--file", NotationE2EPluginPath). - MatchContent("Succussefully installed plugin e2e-plugin, version 1.0.0\n") + MatchContent("Successfully installed plugin e2e-plugin, version 1.0.0\n") }) }) It("with plugin already installed", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.Exec("plugin", "install", "--file", NotationE2EPluginTarGzPath). - MatchContent("Succussefully installed plugin e2e-plugin, version 1.0.0\n") + MatchContent("Successfully installed plugin e2e-plugin, version 1.0.0\n") notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EPluginTarGzPath). MatchErrContent("Error: plugin installation failed: plugin e2e-plugin with version 1.0.0 already exists\n") @@ -87,17 +94,17 @@ var _ = Describe("notation plugin install", func() { It("with plugin already installed but force install", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.Exec("plugin", "install", "--file", NotationE2EPluginTarGzPath, "-v"). - MatchContent("Succussefully installed plugin e2e-plugin, version 1.0.0\n") + MatchContent("Successfully installed plugin e2e-plugin, version 1.0.0\n") notation.Exec("plugin", "install", "--file", NotationE2EPluginTarGzPath, "--force"). - MatchContent("Succussefully installed plugin e2e-plugin, updated the version from 1.0.0 to 1.0.0\n") + MatchContent("Successfully updated plugin e2e-plugin from version 1.0.0 to 1.0.0\n") }) }) It("with valid plugin URL", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.Exec("plugin", "install", "--url", PluginURL, "--sha256sum", PluginChecksum). - MatchKeyWords("Succussefully installed plugin e2e-test-plugin, version 0.1.0\n") + MatchKeyWords("Successfully installed plugin e2e-test-plugin, version 0.1.0\n") }) }) diff --git a/test/e2e/testdata/malicious-plugin/largeFileZip.zip b/test/e2e/testdata/malicious-plugin/largeFileZip.zip new file mode 100644 index 0000000000000000000000000000000000000000..f67bee3fe02816f8eb3c873eb1f54c3005153cc4 GIT binary patch literal 332387 zcmeIwv1^of0LS6?Oj1HYy?|n&OOVd4W(lo}2w5^T=#~bIL5K*F!6`;c$NU3ME)Ms_5Bxj-`+XA z|7K}nd_I|89N%}hp6qNtc(}WLWAEwS@4q}BzZwo+{`30U>kG5n^IhNlb@I*GKaWm- zT>5t7+}97QE7P-c{(Sam{@kZ*Y;0Y=G(S7%;P1^ZZ~cdJe*J!KGCODa^!WDr`Omo; zkMQD=&PF`(P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0 zvGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl} z7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q% zfU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L z1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{ zP=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx7 z4+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U z@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt z6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGT zJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb z))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0 zY(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~ z#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU` zU~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv45 z0mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~ z6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(& zLjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdT zJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)o zPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V z^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL# zTTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0 zvGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl} z7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q% zfU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L z1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{ zP=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx7 z4+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U z@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt z6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGT zJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb z))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0 zY(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~ z#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU` zU~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv45 z0mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~ z6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(& zLjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdT zJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)o zPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V z^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL# zTTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0 zvGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl} z7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q% zfU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L z1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{ zP=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx7 z4+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U z@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt z6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGT zJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb z))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0 zY(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~ z#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU` zU~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv45 z0mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~ z6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(& zLjlIt6AuL#TTeU`U~E0{P=N9OTF|d%*XH>7$Jx;z0SUB*7XSbN literal 0 HcmV?d00001 From 4c715f39657c6e13039c737a928bc1183a0625ff Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 26 Dec 2023 16:05:18 +0800 Subject: [PATCH 02/14] fix unit test Signed-off-by: Patrick Zheng --- internal/osutil/file_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/osutil/file_test.go b/internal/osutil/file_test.go index fdf9dd331..f1fcaf9cd 100644 --- a/internal/osutil/file_test.go +++ b/internal/osutil/file_test.go @@ -261,11 +261,11 @@ func TestCopyToDir(t *testing.T) { } func TestValidateChecksum(t *testing.T) { - expectedErrorMsg := "plugin checksum does not match user input. Expecting abcd123" + expectedErrorMsg := "plugin sha256sum does not match user input. Expecting abcd123" if err := ValidateSHA256Sum("./testdata/test", "abcd123"); err == nil || err.Error() != expectedErrorMsg { - t.Fatalf("expected err %s, got %v", expectedErrorMsg, err) + t.Fatalf("expected err %s, but got %v", expectedErrorMsg, err) } if err := ValidateSHA256Sum("./testdata/test", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); err != nil { - t.Fatalf("expected nil err, got %v", err) + t.Fatalf("expected nil err, but got %v", err) } } From a8f13c11dc3e4e6093d3128e996d1c52c4a4ff0b Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 26 Dec 2023 16:53:01 +0800 Subject: [PATCH 03/14] fix e2e tests Signed-off-by: Patrick Zheng --- cmd/notation/internal/plugin/plugin.go | 2 +- cmd/notation/plugin/install.go | 4 ++-- internal/osutil/file.go | 3 ++- test/e2e/suite/plugin/install.go | 13 ++++++++++--- .../malicious-plugin/largeFileTarGzip.tar.gz | Bin 0 -> 274883 bytes 5 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 test/e2e/testdata/malicious-plugin/largeFileTarGzip.tar.gz diff --git a/cmd/notation/internal/plugin/plugin.go b/cmd/notation/internal/plugin/plugin.go index 65f0f2b34..2d1b8b910 100644 --- a/cmd/notation/internal/plugin/plugin.go +++ b/cmd/notation/internal/plugin/plugin.go @@ -80,7 +80,7 @@ func DownloadPluginFromURL(ctx context.Context, pluginURL string, tmpFile io.Wri return err } if lr.N == 0 { - return fmt.Errorf("%s %q: plugin size reached the %d MiB size limit", resp.Request.Method, resp.Request.URL, MaxPluginSourceBytes) + return fmt.Errorf("%s %q: https response reached the 256 MiB size limit", resp.Request.Method, resp.Request.URL) } return nil } diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index 297a27d99..332af827a 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -226,7 +226,7 @@ func installPluginFromFS(ctx context.Context, pluginFS fs.FS, force bool) error return err } // only accept regular files. - // it is required by github-advanced-security to check for `..` in fName + // check for `..` in fName to avoid zip slip vulnerability if !info.Mode().IsRegular() || strings.Contains(fName, "..") { return nil } @@ -279,7 +279,7 @@ func installPluginFromTarGz(ctx context.Context, tarGzPath string, force bool) e return err } // only accept regular files. - // it is required by github-advanced-security to check for `..` in fName + // check for `..` in fName to avoid zip slip vulnerability if !header.FileInfo().Mode().IsRegular() || strings.Contains(header.Name, "..") { continue } diff --git a/internal/osutil/file.go b/internal/osutil/file.go index 37eb42292..0b539ee3b 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -16,6 +16,7 @@ package osutil import ( "crypto/sha256" "encoding/hex" + "errors" "fmt" "io" "io/fs" @@ -119,7 +120,7 @@ func CopyFromReaderToDir(src io.Reader, dst string, perm fs.FileMode) error { if err != nil { return err } - return fmt.Errorf("file reached the %d MiB size limit", MaxFileBytes) + return errors.New("file reached the 256 MiB size limit") } if err := dstFile.Chmod(perm); err != nil { _ = dstFile.Close() diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index c85dc97c0..4918b35e6 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -60,10 +60,17 @@ var _ = Describe("notation plugin install", func() { }) }) - It("with zip file too large", func() { + It("with content inside zip archive is too large", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileZip.zip", "-v"). - MatchContent("Successfully installed plugin e2e-plugin, version 1.0.0\n") + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileZip.zip", "-v"). + MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") + }) + }) + + It("with content inside tar.gz archive is too large", func() { + Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileTarGzip.tar.gz", "-v"). + MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") }) }) diff --git a/test/e2e/testdata/malicious-plugin/largeFileTarGzip.tar.gz b/test/e2e/testdata/malicious-plugin/largeFileTarGzip.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..a716973375f5fdfa6f5f1fa0c3efb06a14d31ac6 GIT binary patch literal 274883 zcmeI*zsp-y0LS4QbCK$h+#p%Z;B^xRrMToBqDc!uUJ!!h9orBW7b7~Vg#<2H)KzeD zeCbxjMi=o%r5G$YDM__M9E+VYM5NIx=lV~0;5oxt@A*FS2kuiJTu7=@fAG`A$8YtM z^xOANuV&BxaAp5Ve(}-b)Wq?^n-$|M|w9o4tF7@83Rt z@$i@We_wMGAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0+9&ZyIa(2;jMYO z8IH~z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyKp=L3X|s`r7GQClbOy1H z@qPjX2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkL{Y}xB(p#@0x^I6J+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5Qtu&ec1J@7GPbjTI1;F7(jpk0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5(bi+U}@0C~9?j&KklK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk(F;tQjWo0Xi{qp-h<=R$1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfWWfX%|Z*1?B}x-2LS>E2oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5Fik}K>M)kS1rK0T(!p0&oO`i0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&U*cSC#hyn6)GaTU{K!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1fmz1HXCVZ0T#zeXAu1w0|*cxK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=DI zubYJyAlc7nDGmYz2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkJxdV%&~*RNWD zb-8Mdqn~2{0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAh0d!wGad3(Vo0PAwq8b?3J00IOE5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV6SS)N3II$ji-ego6M90t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBm_USQg6q@e{^94DPY^lJ( z*+@eRusBXSgXq^7K!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PCm9-7K^K z$$madaS$LtfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009Eg3$zcre$@i3%T;R} z{Tu@b5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7csfo)N*g%}_&H^UJQ0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyKp=X7X|s`r7GQClbOzC{F@OL80t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBmV_PSYU0h0ZEmf|2lfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C7q8Df%cKxaaSeL8TIQlsT5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0Rr2iUJEfmUT%gX90UjuAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!8B>0@G$A4K2XpIOz Date: Tue, 26 Dec 2023 17:07:43 +0800 Subject: [PATCH 04/14] improve error msg and updated spec Signed-off-by: Patrick Zheng --- cmd/notation/plugin/install.go | 2 +- cmd/notation/plugin/uninstall.go | 2 +- specs/commandline/plugin.md | 20 +++++++++++--------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index 332af827a..b8db8f22e 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -58,7 +58,7 @@ func installCommand(opts *pluginInstallOpts) *cobra.Command { command := &cobra.Command{ Use: "install [flags] <--file|--url> ", Aliases: []string{"add"}, - Short: "Install plugin", + Short: "Install a plugin", Long: `Install a plugin Example - Install plugin from file system: diff --git a/cmd/notation/plugin/uninstall.go b/cmd/notation/plugin/uninstall.go index d60b77e9f..6c20c1106 100644 --- a/cmd/notation/plugin/uninstall.go +++ b/cmd/notation/plugin/uninstall.go @@ -87,7 +87,7 @@ func uninstallPlugin(command *cobra.Command, opts *pluginUninstallOpts) error { } mgr := plugin.NewCLIManager(dir.PluginFS()) if err := mgr.Uninstall(ctx, pluginName); err != nil { - return fmt.Errorf("failed to uninstall %s: %w", pluginName, err) + return fmt.Errorf("failed to uninstall plugin %s: %w", pluginName, err) } fmt.Printf("Successfully uninstalled plugin %s\n", pluginName) return nil diff --git a/specs/commandline/plugin.md b/specs/commandline/plugin.md index 4781c06db..62033a6ae 100644 --- a/specs/commandline/plugin.md +++ b/specs/commandline/plugin.md @@ -49,10 +49,10 @@ Usage: Flags: -d, --debug debug mode --file install plugin from a file on file system - --force force the installation of a plugin + --force force the installation of the plugin -h, --help help for install - --sha256sum string must match SHA256 of the plugin source - --url install plugin from an HTTPS URL + --sha256sum string must match SHA256 of the plugin source, required when "--url" flag is set + --url install plugin from an HTTPS URL. The default plugin download timeout is 10 minutes -v, --verbose verbose mode Aliases: @@ -68,7 +68,9 @@ Usage: notation plugin uninstall [flags] Flags: + -d, --debug debug mode -h, --help help for remove + -v, --verbose verbose mode -y, --yes do not prompt for confirmation Aliases: uninstall, remove, rm @@ -80,7 +82,7 @@ Aliases: ### Install a plugin from file system -Install a Notation plugin from file system. Plugin file supports `.zip` and `.tar.gz` format. The checksum validation is optional for this case. +Install a Notation plugin from file system. Plugin file supports `.zip`, `.tar.gz`, and single plugin executable file format. The checksum validation is optional for this case. ```shell $ notation plugin install --file @@ -95,13 +97,13 @@ Successfully installed plugin , version If the entered plugin checksum digest doesn't match the published checksum, Notation will return an error message and will not start installation. ```console -Error: plugin installation failed: plugin checksum does not match user input. Expecting +Error: plugin installation failed: plugin sha256sum does not match user input. Expecting ``` If the plugin version is higher than the existing plugin, Notation will start installation and overwrite the existing plugin. ```console -Successfully installed plugin , updated the version from to +Successfully updated plugin from version to ``` If the plugin version is equal to the existing plugin, Notation will not start installation and return the following message. Users can use a flag `--force` to skip plugin version check and force the installation. @@ -113,7 +115,7 @@ Error: plugin installation failed: plugin with version alr If the plugin version is lower than the existing plugin, Notation will return an error message and will not start installation. Users can use a flag `--force` to skip plugin version check and force the installation. ```console -Error: failed to install plugin: . The installing plugin version is lower than the existing plugin version . +Error: plugin installation failed: failed to install plugin . The installing plugin version is lower than the existing plugin version . It is not recommended to install an older version. To force the installation, use the "--force" option. ``` ### Install a plugin from URL @@ -134,7 +136,7 @@ Upon successful execution, the plugin is uninstalled from the plugin directory. ```shell Are you sure you want to uninstall plugin ""? [y/n] y -Successfully uninstalled +Successfully uninstalled plugin ``` Uninstall the plugin without prompt for confirmation. @@ -147,7 +149,7 @@ If the plugin is not found, an error is returned showing the syntax for the plug ```shell Error: unable to find plugin . -To view a list of installed plugins, use "notation plugin list" +To view a list of installed plugins, use `notation plugin list` ``` ### List installed plugins From 5e8387f438ecec742fd60834e580331b2ac70475 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 27 Dec 2023 08:34:18 +0800 Subject: [PATCH 05/14] update Signed-off-by: Patrick Zheng --- test/e2e/suite/plugin/install.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index 4918b35e6..33b2a3511 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -60,14 +60,14 @@ var _ = Describe("notation plugin install", func() { }) }) - It("with content inside zip archive is too large", func() { + It("with content inside zip archive exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileZip.zip", "-v"). MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") }) }) - It("with content inside tar.gz archive is too large", func() { + It("with content inside tar.gz archive exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileTarGzip.tar.gz", "-v"). MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") From f1901d14d02608cd7c76680ca45c9f4ed033bf72 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 28 Dec 2023 17:18:18 +0800 Subject: [PATCH 06/14] updated per code review Signed-off-by: Patrick Zheng --- cmd/notation/internal/plugin/plugin.go | 2 +- cmd/notation/plugin/install.go | 2 +- internal/osutil/file.go | 5 ++--- specs/commandline/plugin.md | 2 +- test/e2e/suite/plugin/install.go | 7 +++++++ 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/cmd/notation/internal/plugin/plugin.go b/cmd/notation/internal/plugin/plugin.go index 2d1b8b910..078f66ea3 100644 --- a/cmd/notation/internal/plugin/plugin.go +++ b/cmd/notation/internal/plugin/plugin.go @@ -80,7 +80,7 @@ func DownloadPluginFromURL(ctx context.Context, pluginURL string, tmpFile io.Wri return err } if lr.N == 0 { - return fmt.Errorf("%s %q: https response reached the 256 MiB size limit", resp.Request.Method, resp.Request.URL) + return fmt.Errorf("%s %q: https response reached the %d MiB size limit", resp.Request.Method, resp.Request.URL, MaxPluginSourceBytes/1024/1024) } return nil } diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index b8db8f22e..6df2aba33 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -107,7 +107,7 @@ Example - Install plugin from URL, SHA256 checksum is required: } opts.LoggingFlagOpts.ApplyFlags(command.Flags()) command.Flags().BoolVar(&opts.isFile, "file", false, "install plugin from a file on file system") - command.Flags().BoolVar(&opts.isURL, "url", false, "install plugin from an HTTPS URL. The default plugin download timeout is 10 minutes") + command.Flags().BoolVar(&opts.isURL, "url", false, fmt.Sprintf("install plugin from an HTTPS URL. The default plugin download timeout is %s", notationplugin.DownloadPluginFromURLTimeout)) command.Flags().StringVar(&opts.inputChecksum, "sha256sum", "", "must match SHA256 of the plugin source, required when \"--url\" flag is set") command.Flags().BoolVar(&opts.force, "force", false, "force the installation of the plugin") command.MarkFlagsMutuallyExclusive("file", "url") diff --git a/internal/osutil/file.go b/internal/osutil/file.go index 0b539ee3b..26816eba3 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -16,7 +16,6 @@ package osutil import ( "crypto/sha256" "encoding/hex" - "errors" "fmt" "io" "io/fs" @@ -120,7 +119,7 @@ func CopyFromReaderToDir(src io.Reader, dst string, perm fs.FileMode) error { if err != nil { return err } - return errors.New("file reached the 256 MiB size limit") + return fmt.Errorf("file reached the %d MiB size limit", MaxFileBytes/1024/1024) } if err := dstFile.Chmod(perm); err != nil { _ = dstFile.Close() @@ -158,7 +157,7 @@ func ValidateSHA256Sum(path string, checksum string) error { sha256sum := sha256Hash.Sum(nil) enc := hex.EncodeToString(sha256sum[:]) if !strings.EqualFold(enc, checksum) { - return fmt.Errorf("plugin sha256sum does not match user input. Expecting %s", checksum) + return fmt.Errorf("plugin SHA-256 checksum does not match user input. Expecting %s", checksum) } return nil } diff --git a/specs/commandline/plugin.md b/specs/commandline/plugin.md index 62033a6ae..a12f47671 100644 --- a/specs/commandline/plugin.md +++ b/specs/commandline/plugin.md @@ -52,7 +52,7 @@ Flags: --force force the installation of the plugin -h, --help help for install --sha256sum string must match SHA256 of the plugin source, required when "--url" flag is set - --url install plugin from an HTTPS URL. The default plugin download timeout is 10 minutes + --url install plugin from an HTTPS URL. The default plugin download timeout is 10m0s -v, --verbose verbose mode Aliases: diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index 33b2a3511..bd9674fbf 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -122,6 +122,13 @@ var _ = Describe("notation plugin install", func() { }) }) + It("with valid plugin URL but mismatched SHA-256 checksum", func() { + Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("plugin", "install", "--url", PluginURL, "--sha256sum", "abcd"). + MatchErrContent("Error: plugin installation failed: plugin SHA-256 checksum does not match user input. Expecting abcd\n") + }) + }) + It("with invalid plugin URL scheme", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--url", "http://invalid", "--sha256sum", "abcd"). From 1afce6b49fcebb09fee1c052b5dd8a39a60ea602 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 28 Dec 2023 17:20:58 +0800 Subject: [PATCH 07/14] fix unit test Signed-off-by: Patrick Zheng --- internal/osutil/file_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/osutil/file_test.go b/internal/osutil/file_test.go index f1fcaf9cd..59226f9b1 100644 --- a/internal/osutil/file_test.go +++ b/internal/osutil/file_test.go @@ -261,7 +261,7 @@ func TestCopyToDir(t *testing.T) { } func TestValidateChecksum(t *testing.T) { - expectedErrorMsg := "plugin sha256sum does not match user input. Expecting abcd123" + expectedErrorMsg := "plugin SHA-256 checksum does not match user input. Expecting abcd123" if err := ValidateSHA256Sum("./testdata/test", "abcd123"); err == nil || err.Error() != expectedErrorMsg { t.Fatalf("expected err %s, but got %v", expectedErrorMsg, err) } From 5d9c18e6b3c04d425b451311330b6926fd967d8f Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 2 Jan 2024 12:48:05 +0800 Subject: [PATCH 08/14] update Signed-off-by: Patrick Zheng --- .../malicious-plugin/largeFileZip.zip | Bin 332387 -> 0 bytes ...TarGzip.tar.gz => large_file_tarGz.tar.gz} | Bin 274883 -> 264717 bytes .../malicious-plugin/large_file_zip.zip | Bin 0 -> 265120 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 test/e2e/testdata/malicious-plugin/largeFileZip.zip rename test/e2e/testdata/malicious-plugin/{largeFileTarGzip.tar.gz => large_file_tarGz.tar.gz} (95%) create mode 100644 test/e2e/testdata/malicious-plugin/large_file_zip.zip diff --git a/test/e2e/testdata/malicious-plugin/largeFileZip.zip b/test/e2e/testdata/malicious-plugin/largeFileZip.zip deleted file mode 100644 index f67bee3fe02816f8eb3c873eb1f54c3005153cc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 332387 zcmeIwv1^of0LS6?Oj1HYy?|n&OOVd4W(lo}2w5^T=#~bIL5K*F!6`;c$NU3ME)Ms_5Bxj-`+XA z|7K}nd_I|89N%}hp6qNtc(}WLWAEwS@4q}BzZwo+{`30U>kG5n^IhNlb@I*GKaWm- zT>5t7+}97QE7P-c{(Sam{@kZ*Y;0Y=G(S7%;P1^ZZ~cdJe*J!KGCODa^!WDr`Omo; zkMQD=&PF`(P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0 zvGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl} z7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q% zfU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L z1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{ zP=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx7 z4+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U z@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt z6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGT zJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb z))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0 zY(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~ z#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU` zU~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv45 z0mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~ z6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(& zLjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdT zJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)o zPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V z^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL# zTTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0 zvGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl} z7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q% zfU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L z1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{ zP=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx7 z4+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U z@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt z6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGT zJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb z))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0 zY(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~ z#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU` zU~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv45 z0mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~ z6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(& zLjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdT zJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)o zPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V z^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL# zTTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0 zvGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl} z7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q% zfU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L z1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{ zP=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx7 z4+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U z@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt z6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGT zJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb z))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0 zY(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~ z#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU` zU~E0{P=K-Z#6tnb))Nl}7+X&~6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv45 z0mjx74+R)oPdpT0Y(4Q%fU)(&LjlIt6AuL#TTeU`U~E0{P=K-Z#6tnb))Nl}7+X&~ z6ku#U@lb%V^~6H~#?})L1sGdTJQQGTJ@HV0vGv450mjx74+R)oPdpT0Y(4Q%fU)(& zLjlIt6AuL#TTeU`U~E0{P=N9OTF|d%*XH>7$Jx;z0SUB*7XSbN diff --git a/test/e2e/testdata/malicious-plugin/largeFileTarGzip.tar.gz b/test/e2e/testdata/malicious-plugin/large_file_tarGz.tar.gz similarity index 95% rename from test/e2e/testdata/malicious-plugin/largeFileTarGzip.tar.gz rename to test/e2e/testdata/malicious-plugin/large_file_tarGz.tar.gz index a716973375f5fdfa6f5f1fa0c3efb06a14d31ac6..da3db5cbb8016b45462f01898e532aa47c941975 100644 GIT binary patch literal 264717 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 C6_3gQ literal 274883 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 W{;0q5@X`1|tNeOV{(OD+d;bC91G^>w literal 0 HcmV?d00001 From f82907921fc3240b20dce3023bc9da1402653dd2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 2 Jan 2024 12:52:32 +0800 Subject: [PATCH 09/14] fix e2e tests Signed-off-by: Patrick Zheng --- test/e2e/suite/plugin/install.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index bd9674fbf..94de68556 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -62,14 +62,14 @@ var _ = Describe("notation plugin install", func() { It("with content inside zip archive exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileZip.zip", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_zip.zip", "-v"). MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") }) }) It("with content inside tar.gz archive exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/largeFileTarGzip.tar.gz", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_tarGz.tar.gz", "-v"). MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") }) }) From f40e7a96d6f991fe880e26954d30994f971d52c1 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jan 2024 14:29:42 +0800 Subject: [PATCH 10/14] updated per code review Signed-off-by: Patrick Zheng --- cmd/notation/plugin/install.go | 41 ++++++++++++++---- internal/osutil/file.go | 19 +++----- specs/commandline/plugin.md | 6 +-- test/e2e/suite/plugin/install.go | 22 ++++++++-- .../testdata/malicious-plugin/zip_bomb.zip | Bin 0 -> 42374 bytes .../testdata/malicious-plugin/zip_slip.zip | Bin 0 -> 220 bytes 6 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 test/e2e/testdata/malicious-plugin/zip_bomb.zip create mode 100644 test/e2e/testdata/malicious-plugin/zip_slip.zip diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index 6df2aba33..6f32c7b0f 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -107,7 +107,7 @@ Example - Install plugin from URL, SHA256 checksum is required: } opts.LoggingFlagOpts.ApplyFlags(command.Flags()) command.Flags().BoolVar(&opts.isFile, "file", false, "install plugin from a file on file system") - command.Flags().BoolVar(&opts.isURL, "url", false, fmt.Sprintf("install plugin from an HTTPS URL. The default plugin download timeout is %s", notationplugin.DownloadPluginFromURLTimeout)) + command.Flags().BoolVar(&opts.isURL, "url", false, fmt.Sprintf("install plugin from an HTTPS URL. The plugin download timeout is %s", notationplugin.DownloadPluginFromURLTimeout)) command.Flags().StringVar(&opts.inputChecksum, "sha256sum", "", "must match SHA256 of the plugin source, required when \"--url\" flag is set") command.Flags().BoolVar(&opts.force, "force", false, "force the installation of the plugin") command.MarkFlagsMutuallyExclusive("file", "url") @@ -160,11 +160,11 @@ func install(command *cobra.Command, opts *pluginInstallOpts) error { // installPlugin installs the plugin given plugin source path func installPlugin(ctx context.Context, inputPath string, inputChecksum string, force bool) error { // sanity check - inputFileStat, err := os.Stat(inputPath) + inputFileInfo, err := os.Stat(inputPath) if err != nil { return err } - if !inputFileStat.Mode().IsRegular() { + if !inputFileInfo.Mode().IsRegular() { return fmt.Errorf("%s is not a valid file", inputPath) } // checksum check @@ -185,12 +185,21 @@ func installPlugin(ctx context.Context, inputPath string, inputChecksum string, return err } defer rc.Close() + // check for '..' in file name to avoid zip slip vulnerability + for _, f := range rc.File { + if strings.Contains(f.Name, "..") { + return fmt.Errorf("file name in zip cannot contain '..', but found %q", f.Name) + } + } return installPluginFromFS(ctx, rc, force) case notationplugin.MediaTypeGzip: // when file is gzip, required to be tar return installPluginFromTarGz(ctx, inputPath, force) default: // input file is not in zip or gzip, try install directly + if inputFileInfo.Size() >= osutil.MaxFileBytes { + return fmt.Errorf("file size reached the %d MiB size limit", osutil.MaxFileBytes/1024/1024) + } installOpts := plugin.CLIInstallOptions{ PluginPath: inputPath, Overwrite: force, @@ -213,6 +222,7 @@ func installPluginFromFS(ctx context.Context, pluginFS fs.FS, force bool) error return fmt.Errorf("failed to create temporary directory: %w", err) } defer os.RemoveAll(tmpDir) + var pluginFileSize int64 if err := fs.WalkDir(pluginFS, root, func(path string, d fs.DirEntry, err error) error { if err != nil { return err @@ -225,11 +235,15 @@ func installPluginFromFS(ctx context.Context, pluginFS fs.FS, force bool) error if err != nil { return err } - // only accept regular files. - // check for `..` in fName to avoid zip slip vulnerability - if !info.Mode().IsRegular() || strings.Contains(fName, "..") { + // only accept regular files + if !info.Mode().IsRegular() { return nil } + // check for plugin file size to avoid zip bomb vulnerability + pluginFileSize += info.Size() + if pluginFileSize >= osutil.MaxFileBytes { + return fmt.Errorf("total file size reached the %d MiB size limit", osutil.MaxFileBytes/1024/1024) + } logger.Debugf("Extracting file %s...", fName) rc, err := pluginFS.Open(path) if err != nil { @@ -270,6 +284,7 @@ func installPluginFromTarGz(ctx context.Context, tarGzPath string, force bool) e return fmt.Errorf("failed to create temporary directory: %w", err) } defer os.RemoveAll(tmpDir) + var pluginFileSize int64 for { header, err := tarReader.Next() if err != nil { @@ -278,11 +293,19 @@ func installPluginFromTarGz(ctx context.Context, tarGzPath string, force bool) e } return err } - // only accept regular files. - // check for `..` in fName to avoid zip slip vulnerability - if !header.FileInfo().Mode().IsRegular() || strings.Contains(header.Name, "..") { + // check for '..' in file name to avoid zip slip vulnerability + if strings.Contains(header.Name, "..") { + return fmt.Errorf("file name in tar.gz cannot contain '..', but found %q", header.Name) + } + // only accept regular files + if !header.FileInfo().Mode().IsRegular() { continue } + // check for plugin file size to avoid zip bomb vulnerability + pluginFileSize += header.FileInfo().Size() + if pluginFileSize >= osutil.MaxFileBytes { + return fmt.Errorf("total file size reached the %d MiB size limit", osutil.MaxFileBytes/1024/1024) + } fName := filepath.Base(header.Name) logger.Debugf("Extracting file %s...", fName) tmpFilePath := filepath.Join(tmpDir, fName) diff --git a/internal/osutil/file.go b/internal/osutil/file.go index 26816eba3..06f69792a 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -26,7 +26,7 @@ import ( ) // MaxFileBytes is the maximum file bytes. -// When used, the value should strictly less than this number. +// When used, the value should be strictly less than this number. var MaxFileBytes int64 = 256 * 1024 * 1024 // 256 MiB // WriteFile writes to a path with all parent directories created. @@ -104,25 +104,18 @@ func IsRegularFile(path string) (bool, error) { } // CopyFromReaderToDir copies file from src to dst where dst is the destination -// file path. The file size must be less than 256 MiB. +// file path. func CopyFromReaderToDir(src io.Reader, dst string, perm fs.FileMode) error { dstFile, err := os.Create(dst) if err != nil { return err } - lr := &io.LimitedReader{ - R: src, - N: MaxFileBytes, - } - if _, err := io.Copy(dstFile, lr); err != nil || lr.N == 0 { - _ = dstFile.Close() - if err != nil { - return err - } - return fmt.Errorf("file reached the %d MiB size limit", MaxFileBytes/1024/1024) + if _, err := io.Copy(dstFile, src); err != nil { + dstFile.Close() + return err } if err := dstFile.Chmod(perm); err != nil { - _ = dstFile.Close() + dstFile.Close() return err } return dstFile.Close() diff --git a/specs/commandline/plugin.md b/specs/commandline/plugin.md index a12f47671..c0460ab50 100644 --- a/specs/commandline/plugin.md +++ b/specs/commandline/plugin.md @@ -52,7 +52,7 @@ Flags: --force force the installation of the plugin -h, --help help for install --sha256sum string must match SHA256 of the plugin source, required when "--url" flag is set - --url install plugin from an HTTPS URL. The default plugin download timeout is 10m0s + --url install plugin from an HTTPS URL. The plugin download timeout is 10m0s -v, --verbose verbose mode Aliases: @@ -82,7 +82,7 @@ Aliases: ### Install a plugin from file system -Install a Notation plugin from file system. Plugin file supports `.zip`, `.tar.gz`, and single plugin executable file format. The checksum validation is optional for this case. +Install a Notation plugin from the host file system. `.zip`, `.tar.gz`, and `single plugin executable file` formats are supported. In this scenario, SHA-256 checksum validation is optional. ```shell $ notation plugin install --file @@ -120,7 +120,7 @@ It is not recommended to install an older version. To force the installation, us ``` ### Install a plugin from URL -Install a Notation plugin from a remote location and verify the plugin checksum. Notation only supports installing plugins from an HTTPS URL, which means that the URL must start with "https://". +Install a Notation plugin from a URL. Notation only supports HTTPS URL, which means that the URL must start with "https://". The URL MUST point to a resource in `.zip`, `.tar.gz`, or `single plugin executable file` format. In this scenario, the SHA-256 checksum of the resource MUST be provided. ```shell $ notation plugin install --sha256sum --url diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index 94de68556..6e35647fa 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -60,17 +60,31 @@ var _ = Describe("notation plugin install", func() { }) }) - It("with content inside zip archive exceeds 256 MiB size limit", func() { + It("with zip bomb single file exceeds 256 MiB size limit in zip format", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_zip.zip", "-v"). - MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") + MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") }) }) - It("with content inside tar.gz archive exceeds 256 MiB size limit", func() { + It("with zip bomb single file exceeds 256 MiB size limit in tar.gz format", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_tarGz.tar.gz", "-v"). - MatchErrContent("Error: plugin installation failed: file reached the 256 MiB size limit\n") + MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") + }) + }) + + It("with zip slip", func() { + Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_tarGz.tar.gz", "-v"). + MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") + }) + }) + + It("with zip bomb total file size exceeds 256 MiB size limit", func() { + Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/zip_slip.zip", "-v"). + MatchErrContent("Error: plugin installation failed: file name in zip cannot contain '..', but found \"../../../../../../../../tmp/evil.sh\"\n") }) }) diff --git a/test/e2e/testdata/malicious-plugin/zip_bomb.zip b/test/e2e/testdata/malicious-plugin/zip_bomb.zip new file mode 100644 index 0000000000000000000000000000000000000000..b4d00682f287342d9afab1d70c03075d9a48eed1 GIT binary patch literal 42374 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 DBG6lk literal 0 HcmV?d00001 diff --git a/test/e2e/testdata/malicious-plugin/zip_slip.zip b/test/e2e/testdata/malicious-plugin/zip_slip.zip new file mode 100644 index 0000000000000000000000000000000000000000..96c173ed6a8551ede36c3523315eaf1bc6efbdfa GIT binary patch literal 220 zcmWIWW@h1H00E^$hPFzD&&V?`yo1^TIFnK^pJ8KEJZ49xfMPDusf(h6<{ zMwS=M3=Ci*z?+dtjv1Hn5^&p=G=i8|Z2}6SSjGym48tN;HjojFK$r=nV?i7S0Gwtf A)Bpeg literal 0 HcmV?d00001 From 9c303bb0910eaa0a5caebf3723b6a3e6e740dfe7 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jan 2024 14:38:39 +0800 Subject: [PATCH 11/14] update Signed-off-by: Patrick Zheng --- test/e2e/testdata/malicious-plugin/zip_slip.zip | Bin 220 -> 226 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/e2e/testdata/malicious-plugin/zip_slip.zip b/test/e2e/testdata/malicious-plugin/zip_slip.zip index 96c173ed6a8551ede36c3523315eaf1bc6efbdfa..c0fd13b0ceb5266d16198a5a65c697512afa5d61 100644 GIT binary patch literal 226 zcmWIWW@h1H0D-I$<%l4|-@PnAHVCUQ$S~;X>0?DDxdr;EWtlm8B^4#1A)E}%>I_p; zLAbPnn}Lz#1vAhH5CKvX;LXS+$BfGk36Rwcj6l4k5yZl39Z(R}MplT8Xto7-v$BEA OUhPFzD&&V?`yo1^TIFnK^pJ8KEJZ49xfMPDusf(h6<{ zMwS=M3=Ci*z?+dtjv1Hn5^&p=G=i8|Z2}6SSjGym48tN;HjojFK$r=nV?i7S0Gwtf A)Bpeg From 424e7e32337f1c2e000be21ff7bda88c7a347b8f Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jan 2024 14:42:22 +0800 Subject: [PATCH 12/14] fix tests Signed-off-by: Patrick Zheng --- test/e2e/suite/plugin/install.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index 6e35647fa..f34798e94 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -84,7 +84,7 @@ var _ = Describe("notation plugin install", func() { It("with zip bomb total file size exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/zip_slip.zip", "-v"). - MatchErrContent("Error: plugin installation failed: file name in zip cannot contain '..', but found \"../../../../../../../../tmp/evil.sh\"\n") + MatchErrContent("Error: plugin installation failed: file name in zip cannot contain '..', but found \"../../../../../../../../tmp/evil.txt\"\n") }) }) From efc1fbd64d911220c67ff16140865af32820a9fe Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jan 2024 14:51:32 +0800 Subject: [PATCH 13/14] fix tests Signed-off-by: Patrick Zheng --- test/e2e/suite/plugin/install.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index f34798e94..fde010296 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -74,14 +74,14 @@ var _ = Describe("notation plugin install", func() { }) }) - It("with zip slip", func() { + It("with zip bomb total file size exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_tarGz.tar.gz", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/zip_bomb.zip", "-v"). MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") }) }) - It("with zip bomb total file size exceeds 256 MiB size limit", func() { + It("with zip slip", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/zip_slip.zip", "-v"). MatchErrContent("Error: plugin installation failed: file name in zip cannot contain '..', but found \"../../../../../../../../tmp/evil.txt\"\n") From 4fa9ba20b9441c3e29e94840a9cb0b95af6ec2b2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jan 2024 16:51:02 +0800 Subject: [PATCH 14/14] updated tests Signed-off-by: Patrick Zheng --- test/e2e/suite/plugin/install.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index fde010296..363801d44 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -14,6 +14,8 @@ package plugin import ( + "path/filepath" + . "github.com/notaryproject/notation/test/e2e/internal/notation" "github.com/notaryproject/notation/test/e2e/internal/utils" . "github.com/onsi/ginkgo/v2" @@ -62,28 +64,28 @@ var _ = Describe("notation plugin install", func() { It("with zip bomb single file exceeds 256 MiB size limit in zip format", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_zip.zip", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", filepath.Join(NotationE2EMaliciousPluginArchivePath, "large_file_zip.zip"), "-v"). MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") }) }) It("with zip bomb single file exceeds 256 MiB size limit in tar.gz format", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/large_file_tarGz.tar.gz", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", filepath.Join(NotationE2EMaliciousPluginArchivePath, "large_file_tarGz.tar.gz"), "-v"). MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") }) }) It("with zip bomb total file size exceeds 256 MiB size limit", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/zip_bomb.zip", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", filepath.Join(NotationE2EMaliciousPluginArchivePath, "zip_bomb.zip"), "-v"). MatchErrContent("Error: plugin installation failed: total file size reached the 256 MiB size limit\n") }) }) It("with zip slip", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--file", NotationE2EMaliciousPluginArchivePath+"/zip_slip.zip", "-v"). + notation.ExpectFailure().Exec("plugin", "install", "--file", filepath.Join(NotationE2EMaliciousPluginArchivePath, "zip_slip.zip"), "-v"). MatchErrContent("Error: plugin installation failed: file name in zip cannot contain '..', but found \"../../../../../../../../tmp/evil.txt\"\n") }) })