Skip to content

Commit ef331d0

Browse files
committed
Don't use securejoin(templateDir, templateName)
The final template path may be a symlink that points somewhere outside the templateDir (e.g. when installed by Homebrew). Also use `path` instead of `filepath` functions to join host and path of template:// URLs; they are not native filepaths and always uses slashes as path delimiters. Signed-off-by: Jan Dubois <[email protected]>
1 parent 353be89 commit ef331d0

File tree

5 files changed

+18
-12
lines changed

5 files changed

+18
-12
lines changed

cmd/limactl/start.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"os"
10+
"path"
1011
"path/filepath"
1112
"runtime"
1213
"strings"
@@ -118,8 +119,7 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string, createOnly bool) (*
118119
return nil, err
119120
}
120121
if isTemplateURL, templateURL := limatmpl.SeemsTemplateURL(arg); isTemplateURL {
121-
// No need to use SecureJoin here. https://github.com/lima-vm/lima/pull/805#discussion_r853411702
122-
templateName := filepath.Join(templateURL.Host, templateURL.Path)
122+
templateName := path.Join(templateURL.Host, templateURL.Path)
123123
switch templateName {
124124
case "experimental/vz":
125125
logrus.Warn("template://experimental/vz was merged into the default template in Lima v1.0. See also <https://lima-vm.io/docs/config/vmtype/>.")

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ require (
1616
github.com/containers/gvisor-tap-vsock v0.8.6 // gomodjail:unconfined
1717
github.com/coreos/go-semver v0.3.1
1818
github.com/cpuguy83/go-md2man/v2 v2.0.7
19-
github.com/cyphar/filepath-securejoin v0.4.1
2019
github.com/digitalocean/go-qemu v0.0.0-20221209210016-f035778c97f7
2120
github.com/diskfs/go-diskfs v1.6.0 // gomodjail:unconfined
2221
github.com/docker/go-units v0.5.0

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3
5151
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
5252
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
5353
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
54-
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
55-
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
5654
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5755
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5856
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=

pkg/limatmpl/locator.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ func Read(ctx context.Context, name, locator string) (*Template, error) {
4040
isTemplateURL, templateURL := SeemsTemplateURL(locator)
4141
switch {
4242
case isTemplateURL:
43-
// No need to use SecureJoin here. https://github.com/lima-vm/lima/pull/805#discussion_r853411702
44-
templateName := filepath.Join(templateURL.Host, templateURL.Path)
43+
templateName := path.Join(templateURL.Host, templateURL.Path)
4544
logrus.Debugf("interpreting argument %q as a template name %q", locator, templateName)
4645
if tmpl.Name == "" {
4746
// e.g., templateName = "deprecated/centos-7.yaml" , tmpl.Name = "centos-7"

pkg/templatestore/templatestore.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"strings"
1515
"unicode"
1616

17-
securejoin "github.com/cyphar/filepath-securejoin"
1817
"github.com/lima-vm/lima/pkg/store/dirnames"
1918
"github.com/lima-vm/lima/pkg/usrlocalsharelima"
2019
)
@@ -42,7 +41,16 @@ func templatesPaths() ([]string, error) {
4241
}, nil
4342
}
4443

44+
// Read searches for template `name` in all template directories and returns the
45+
// contents of the first one found. Template names cannot contain the substring ".."
46+
// to make sure they don't reference files outside the template directories. We are
47+
// not using securejoin.SecureJoin because the actual template may be a symlink to a
48+
// directory elsewhere (e.g. when installed by Homebrew).
4549
func Read(name string) ([]byte, error) {
50+
doubleDot := ".."
51+
if strings.Contains(name, doubleDot) {
52+
return nil, fmt.Errorf("template name %q must not contain %q", name, doubleDot)
53+
}
4654
paths, err := templatesPaths()
4755
if err != nil {
4856
return nil, err
@@ -54,10 +62,8 @@ func Read(name string) ([]byte, error) {
5462
name += ".yaml"
5563
}
5664
for _, templatesDir := range paths {
57-
filePath, err := securejoin.SecureJoin(templatesDir, name)
58-
if err != nil {
59-
return nil, err
60-
}
65+
// Normalize filePath for error messages because template names always use forward slashes
66+
filePath := filepath.Clean(filepath.Join(templatesDir, name))
6167
if b, err := os.ReadFile(filePath); !errors.Is(err, os.ErrNotExist) {
6268
return b, err
6369
}
@@ -67,6 +73,10 @@ func Read(name string) ([]byte, error) {
6773

6874
const Default = "default"
6975

76+
// Templates returns a list of Template structures containing the Name and Location for each template.
77+
// It searches all template directories, but only the first template of a given name is recorded.
78+
// Only non-hidden files with a ".yaml" file extension are considered templates.
79+
// The final result is sorted alphabetically by template name.
7080
func Templates() ([]Template, error) {
7181
paths, err := templatesPaths()
7282
if err != nil {

0 commit comments

Comments
 (0)