Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/driver/qemu/entitlementutil/entitlementutil.go
2649 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
// Package entitlementutil provides a workaround for https://github.com/lima-vm/lima/issues/1742
5
package entitlementutil
6
7
import (
8
"context"
9
"fmt"
10
"os"
11
"os/exec"
12
"strings"
13
14
"github.com/mattn/go-isatty"
15
"github.com/sirupsen/logrus"
16
17
"github.com/lima-vm/lima/v2/pkg/uiutil"
18
)
19
20
// IsSigned returns an error if the binary is not signed, or the sign is invalid,
21
// or not associated with the "com.apple.security.hypervisor" entitlement.
22
func IsSigned(ctx context.Context, qExe string) error {
23
cmd := exec.CommandContext(ctx, "codesign", "--verify", qExe)
24
out, err := cmd.CombinedOutput()
25
logrus.WithError(err).Debugf("Executed %v: out=%q", cmd.Args, string(out))
26
if err != nil {
27
return fmt.Errorf("failed to run %v: %w (out=%q)", cmd.Args, err, string(out))
28
}
29
30
cmd = exec.CommandContext(ctx, "codesign", "--display", "--entitlements", "-", "--xml", qExe)
31
out, err = cmd.CombinedOutput()
32
logrus.WithError(err).Debugf("Executed %v: out=%q", cmd.Args, string(out))
33
if err != nil {
34
return fmt.Errorf("failed to run %v: %w (out=%q)", cmd.Args, err, string(out))
35
}
36
if !strings.Contains(string(out), "com.apple.security.hypervisor") {
37
return fmt.Errorf("binary %q seems signed but lacking the \"com.apple.security.hypervisor\" entitlement", qExe)
38
}
39
return nil
40
}
41
42
func Sign(ctx context.Context, qExe string) error {
43
ent, err := os.CreateTemp("", "lima-qemu-entitlements-*.xml")
44
if err != nil {
45
return fmt.Errorf("failed to create a temporary file for signing QEMU binary: %w", err)
46
}
47
entName := ent.Name()
48
defer os.RemoveAll(entName)
49
const entXML = `<?xml version="1.0" encoding="UTF-8"?>
50
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
51
<plist version="1.0">
52
<dict>
53
<key>com.apple.security.hypervisor</key>
54
<true/>
55
</dict>
56
</plist>`
57
if _, err = ent.WriteString(entXML); err != nil {
58
ent.Close()
59
return fmt.Errorf("failed to write to a temporary file %q for signing QEMU binary: %w", entName, err)
60
}
61
ent.Close()
62
signCmd := exec.CommandContext(ctx, "codesign", "--sign", "-", "--entitlements", entName, "--force", qExe)
63
out, err := signCmd.CombinedOutput()
64
logrus.WithError(err).Debugf("Executed %v: out=%q", signCmd.Args, string(out))
65
if err != nil {
66
return fmt.Errorf("failed to run %v: %w (out=%q)", signCmd.Args, err, string(out))
67
}
68
return nil
69
}
70
71
// isColimaWrapper__useThisFunctionOnlyForPrintingHints returns true
72
// if qExe is like "/Users/<USER>/.colima/_wrapper/4e1b408f843d1c63afbbdcf80c40e4c88d33509f/bin/qemu-system-x86_64".
73
//
74
// The result can be used *ONLY* for controlling hint messages.
75
// DO NOT change the behavior of Lima depending on this result.
76
//
77
//nolint:revive,staticcheck // underscores in this function name intentionally added
78
func isColimaWrapper__useThisFunctionOnlyForPrintingHints__(qExe string) bool {
79
return strings.Contains(qExe, "/.colima/_wrapper/")
80
}
81
82
// AskToSignIfNotSignedProperly asks to sign the QEMU binary with the "com.apple.security.hypervisor" entitlement.
83
//
84
// On Homebrew, QEMU binaries are usually already signed, but Homebrew's signing infrastructure is broken for Intel as of August 2023.
85
// https://github.com/lima-vm/lima/issues/1742
86
func AskToSignIfNotSignedProperly(ctx context.Context, qExe string) {
87
if isSignedErr := IsSigned(ctx, qExe); isSignedErr != nil {
88
logrus.WithError(isSignedErr).Warnf("QEMU binary %q does not seem properly signed with the \"com.apple.security.hypervisor\" entitlement", qExe)
89
if isColimaWrapper__useThisFunctionOnlyForPrintingHints__(qExe) {
90
logrus.Info("Hint: the warning above is usually negligible for colima ( Printed due to https://github.com/abiosoft/colima/issues/796 )")
91
}
92
var ans bool
93
if isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) {
94
message := fmt.Sprintf("Try to sign %q with the \"com.apple.security.hypervisor\" entitlement?", qExe)
95
var askErr error
96
ans, askErr = uiutil.Confirm(message, true)
97
if askErr != nil {
98
logrus.WithError(askErr).Warn("No answer was given")
99
}
100
}
101
if ans {
102
if signErr := Sign(ctx, qExe); signErr != nil {
103
logrus.WithError(signErr).Warnf("Failed to sign %q", qExe)
104
} else {
105
logrus.Infof("Successfully signed %q with the \"com.apple.security.hypervisor\" entitlement", qExe)
106
}
107
} else {
108
logrus.Warn("If QEMU does not start up, you may have to sign the QEMU binary with the \"com.apple.security.hypervisor\" entitlement manually. See https://github.com/lima-vm/lima/issues/1742 .")
109
}
110
}
111
}
112
113