From 7b1e63189ed5815d7fe030d2016d855e5af50458 Mon Sep 17 00:00:00 2001 From: Zach Wasserman Date: Mon, 20 Feb 2023 16:29:49 -0600 Subject: [PATCH] Fix macOS pkg file permission warnings (#9940) Fixes warnings reported by Suspicious Package about the declared permissions not matching the actual permissions. This was tested on macOS and Linux (in the `fleetdm/fleetctl` Docker container) with the "native tooling" option. #7852 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Changes file added for user-visible changes in `changes/` or `orbit/changes/`. See [Changes files](https://fleetdm.com/docs/contributing/committing-changes#changes-files) for more information. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --- changes/fix-bom | 1 + orbit/pkg/packaging/macos.go | 49 +++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 changes/fix-bom diff --git a/changes/fix-bom b/changes/fix-bom new file mode 100644 index 0000000000..c23b020ae0 --- /dev/null +++ b/changes/fix-bom @@ -0,0 +1 @@ +* Fix permissions warnings reported by Suspicious Package in macos pkg installers. These warnings appeared to be purely cosmetic. diff --git a/orbit/pkg/packaging/macos.go b/orbit/pkg/packaging/macos.go index 2b4a16e2f6..eb6fc51b39 100644 --- a/orbit/pkg/packaging/macos.go +++ b/orbit/pkg/packaging/macos.go @@ -8,6 +8,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" "github.com/Masterminds/semver" @@ -18,6 +19,8 @@ import ( "github.com/rs/zerolog/log" ) +var bomRegexp = regexp.MustCompile(`(.+)\t([0-9]+/[0-9]+)`) + // See helful docs in http://bomutils.dyndns.org/tutorial.html // BuildPkg builds a macOS .pkg. @@ -284,21 +287,50 @@ func xarBom(opt Options, rootPath string) error { return fmt.Errorf("cpio Scripts: %w", err) } - // Make bom + // Make Bill of materials (bom) var cmdMkbom *exec.Cmd - var isDarwin = runtime.GOOS == "darwin" - var isLinuxNative = runtime.GOOS == "linux" && opt.NativeTooling + isDarwin := runtime.GOOS == "darwin" + isLinuxNative := runtime.GOOS == "linux" && opt.NativeTooling switch { - case isDarwin, isLinuxNative: - cmdMkbom = exec.Command("mkbom", filepath.Join(rootPath, "root"), filepath.Join("flat", "base.pkg", "Bom")) + case isDarwin: + // Using mkbom directly results in permissions listed for the current user and group. We + // transform the output in order to explicitly set root (0) and admin (80). + inBomPath := filepath.Join(rootPath, "inBom") + cmd := exec.Command("mkbom", filepath.Join(rootPath, "root"), inBomPath) + if err := cmd.Run(); err != nil { + return fmt.Errorf("initial mkbom: %w", err) + } + bomContents, err := exec.Command("lsbom", inBomPath).Output() + if err != nil { + return fmt.Errorf("lsbom inBom: %w", err) + } + bomContents = bomReplace(bomContents) + if err := ioutil.WriteFile(inBomPath, bomContents, 0); err != nil { + return fmt.Errorf("write inBom: %w", err) + } + + // Use the file list (with transformed permissions) via -i flag + cmdMkbom = exec.Command("mkbom", "-i", "inBom", filepath.Join("flat", "base.pkg", "Bom")) + cmdMkbom.Dir = rootPath + + // No need for transformation when using the Linux mkbom because of the -u and -g flags + // available in that command. + case isLinuxNative: + cmdMkbom = exec.Command( + "mkbom", "-u", "0", "-g", "80", + filepath.Join(rootPath, "root"), filepath.Join("flat", "base.pkg", "Bom"), + ) cmdMkbom.Dir = rootPath default: + // Same as linux native, but modified for running in Docker. This should + // be either Windows, or Linux without the --native-tooling flag. cmdMkbom = exec.Command( "docker", "run", "--rm", "-v", rootPath+":/root", "fleetdm/bomutils", "mkbom", "-u", "0", "-g", "80", // Use / instead of filepath.Join because these will always be paths within the Docker - // container (so Linux file paths) + // container (so Linux file paths) -- if we use filepath.Join we'll get invalid paths on + // Windows due to use of backslashes. "/root/root", "/root/flat/base.pkg/Bom", ) } @@ -347,6 +379,11 @@ func xarBom(opt Options, rootPath string) error { return nil } +// bomReplace replaces the permission strings (typically "501/20") with the appropriate string ("0/80") +func bomReplace(inBom []byte) []byte { + return bomRegexp.ReplaceAll(inBom, []byte("$1\t0/80")) +} + func cpio(srcPath, dstPath string) error { // This is the compression routine that is expected for pkg files. dst, err := secure.OpenFile(dstPath, os.O_RDWR|os.O_CREATE, 0o755)