mirror of
https://github.com/lxc/incus
synced 2026-08-02 05:26:46 +00:00
incusd/instance: Confine OCI network writes to instance root
Also rejects line breaks in the oci.dns.domain and oci.dns.search values which are written to the generated resolv.conf. This addresses GHSA-7fj9-65v4-rp7h (CVE pending) Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
This commit is contained in:
parent
4d64535046
commit
e46720cb6d
@ -27,6 +27,15 @@ func isNvidiaConfigValue(value string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// isResolvConfValue rejects line breaks that would allow injecting arbitrary lines into the generated resolv.conf.
|
||||
func isResolvConfValue(value string) error {
|
||||
if strings.ContainsAny(value, "\r\n") {
|
||||
return errors.New("Value cannot contain line breaks")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConfigVolatilePrefix indicates the prefix used for volatile config keys.
|
||||
const ConfigVolatilePrefix = "volatile."
|
||||
|
||||
@ -836,7 +845,7 @@ var InstanceConfigKeysContainer = map[string]func(value string) error{
|
||||
// liveupdate: no
|
||||
// condition: OCI container
|
||||
// shortdesc: DNS domain
|
||||
"oci.dns.domain": validate.IsAny,
|
||||
"oci.dns.domain": validate.Optional(isResolvConfValue),
|
||||
|
||||
// gendoc:generate(entity=instance, group=oci, key=oci.dns.search)
|
||||
// Comma-separated list of search domains for the initial `resolv.conf`.
|
||||
@ -845,7 +854,7 @@ var InstanceConfigKeysContainer = map[string]func(value string) error{
|
||||
// liveupdate: no
|
||||
// condition: OCI container
|
||||
// shortdesc: DNS search domains
|
||||
"oci.dns.search": validate.IsAny,
|
||||
"oci.dns.search": validate.Optional(validate.IsListOf(isResolvConfValue)),
|
||||
|
||||
// Caller is responsible for full validation of any raw.* value.
|
||||
|
||||
|
||||
@ -2617,17 +2617,25 @@ func (d *lxc) startCommon() (string, []func() error, error) {
|
||||
}
|
||||
|
||||
// Configure network handling.
|
||||
err = os.MkdirAll(filepath.Join(d.Path(), "network"), 0o711)
|
||||
// Confine all writes to the instance directory to avoid following image-planted symlinks.
|
||||
instRoot, err := os.OpenRoot(d.Path())
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
defer logger.WarnOnError(instRoot.Close, "Failed to close instance root")
|
||||
|
||||
err = instRoot.Mkdir("network", 0o711)
|
||||
if err != nil && !errors.Is(err, fs.ErrExist) {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(filepath.Join(d.RootfsPath(), "etc"), 0o755)
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(d.Path(), "network", "hosts"), fmt.Appendf(nil, `127.0.0.1 localhost
|
||||
err = instRoot.WriteFile("network/hosts", fmt.Appendf(nil, `127.0.0.1 localhost
|
||||
127.0.1.1 %s
|
||||
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
@ -2645,7 +2653,7 @@ ff02::2 ip6-allrouters
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(d.Path(), "network", "hostname"), fmt.Appendf(nil, "%s\n", d.name), 0o644)
|
||||
err = instRoot.WriteFile("network/hostname", fmt.Appendf(nil, "%s\n", d.name), 0o644)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -2669,7 +2677,7 @@ ff02::2 ip6-allrouters
|
||||
fmt.Fprintf(&resolvConf, "domain %s\n", d.expandedConfig["oci.dns.domain"])
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(d.Path(), "network", "resolv.conf"), []byte(resolvConf.String()), 0o644)
|
||||
err = instRoot.WriteFile("network/resolv.conf", []byte(resolvConf.String()), 0o644)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@ -2699,7 +2707,7 @@ ff02::2 ip6-allrouters
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
err = os.WriteFile(filepath.Join(d.Path(), "network", "interfaces.json"), ifacesData, 0o644)
|
||||
err = instRoot.WriteFile("network/interfaces.json", ifacesData, 0o644)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user