incusd/instance/lxc: Confine credentials write to credentials directory

systemd credentials name could be abused to escape the credentials
folder and allow for arbitrary writes to the host filesystem allowing
for privilege escalation and denial of service attacks.

We now use Go's OpenRoot (openat2) to restrict all file interactions to
the "credentials" directory, avoiding such attacks.

This addresses CVE-2026-33945

Reported-by: https://7asecurity.com
Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
This commit is contained in:
Stéphane Graber 2026-03-24 21:19:28 -04:00
parent 15a5344774
commit d0f2c86fcb
No known key found for this signature in database
GPG Key ID: C638974D64792D67

View File

@ -9236,16 +9236,22 @@ func (d *lxc) setupCredentials(update bool) error {
} }
} }
credsRoot, err := os.OpenRoot(credentialsDir)
if err != nil {
return fmt.Errorf("Failed to open the credentials directory: %w", err)
}
defer func() { _ = credsRoot.Close() }()
for k, v := range credentials { for k, v := range credentials {
credentialPath := filepath.Join(credentialsDir, k) err := credsRoot.WriteFile(k, v, 0o400)
err := os.WriteFile(credentialPath, v, 0o400)
if err != nil { if err != nil {
return fmt.Errorf("Failed to write credential %q: %w", k, err) return fmt.Errorf("Failed to write credential %q: %w", k, err)
} }
err = os.Chown(credentialPath, int(rootUID), int(rootGID)) err = credsRoot.Chown(k, int(rootUID), int(rootGID))
if err != nil { if err != nil {
return fmt.Errorf("Failed setting permissions for file %q: %w", credentialPath, err) return fmt.Errorf("Failed setting permissions for file %q: %w", k, err)
} }
delete(oldCredentials, k) delete(oldCredentials, k)