Refuse a bundle whose output directory leads out of the module through a link, so a repository cannot make the build write into or pack files it does not hold (issue 1609)
mesh/merge-gate head 0caa8c6844d9 merged into trunk 0205b8f7080a — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head 0caa8c6844d9 merged into trunk 0205b8f7080a — pass: its merge-check.sh passed
mesh/delivery delivered
mesh/merge-gate head 0caa8c6844d9 merged into trunk 0205b8f7080a — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head 0caa8c6844d9 merged into trunk 0205b8f7080a — pass: its merge-check.sh passed
mesh/delivery delivered
This commit is contained in:
@@ -1295,6 +1295,9 @@ func one(ctx context.Context, run Runner, publish Publisher,
|
||||
}
|
||||
}
|
||||
say("bundle", "compiled, packing")
|
||||
if err := outsideTheModule(tree, compiled); err != nil {
|
||||
return catalogue.Built{}, fmt.Errorf("%s: packing %s failed: %w", module, a.Name, err)
|
||||
}
|
||||
body, err := pack(compiled)
|
||||
if err != nil {
|
||||
return catalogue.Built{}, fmt.Errorf("%s: packing %s failed: %w", module, a.Name, err)
|
||||
@@ -1384,6 +1387,36 @@ func archiveRoot(tree string, a catalogue.Artifact) (string, error) {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
// outsideTheModule refuses a path that, once every link in it is followed, is not inside the module's
|
||||
// directory, naming where it really is and where the module is. For a path not there yet (an output
|
||||
// directory about to be made) the deepest part that exists is the one followed. A repository commits
|
||||
// its own links, so `.mesh-build` as a link would otherwise have a bundle's build write into, and pack,
|
||||
// any directory the build account can read (issue 1609).
|
||||
func outsideTheModule(tree, path string) error {
|
||||
realTree, err := filepath.EvalSymlinks(tree)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
real, rest := path, ""
|
||||
for {
|
||||
resolved, err := filepath.EvalSymlinks(real)
|
||||
if err == nil {
|
||||
real = filepath.Join(resolved, rest)
|
||||
break
|
||||
}
|
||||
if !errors.Is(err, os.ErrNotExist) || filepath.Dir(real) == real {
|
||||
return err
|
||||
}
|
||||
rest = filepath.Join(filepath.Base(real), rest)
|
||||
real = filepath.Dir(real)
|
||||
}
|
||||
if rel, err := filepath.Rel(realTree, real); err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
|
||||
return fmt.Errorf("%s leads out of the module through a link: it resolves to %s, and the module is %s",
|
||||
path, real, realTree)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// pack tars and gzips a directory.
|
||||
//
|
||||
// **Deterministically**: entries sorted, and no timestamps, uid, gid or original names carried
|
||||
@@ -1687,6 +1720,9 @@ func compile(ctx context.Context, run Runner, tree string, chain Toolchain,
|
||||
// a package in a third (ADR 0040). Compiling them all into one place would have them overwrite
|
||||
// each other and then be packed together, so each bundle compiles and packs alone.
|
||||
out := Out(a.Name)
|
||||
if err := outsideTheModule(tree, filepath.Join(tree, out)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// **The output directory exists before the compiler is told about it.** `tsc --outDir` makes
|
||||
// one; `go build -o` writes a file into a directory and does not create it, failing with a
|
||||
@@ -2013,6 +2049,9 @@ func bundled(ctx context.Context, run Runner, tree string, chain Toolchain, base
|
||||
a catalogue.Artifact, launchers map[string]string) (string, error) {
|
||||
const within = "/app/modules/module"
|
||||
out, final := Out(a.Name), Out(a.Name)+bundledSuffix
|
||||
if err := outsideTheModule(tree, filepath.Join(tree, final)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.RemoveAll(filepath.Join(tree, final)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user