All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Pedro Tôrres" <t0rr3sp3dr0@gmail.com>
Subject: [PULL 04/12] hw/misc: applesmc: use host osk as default on macs
Date: Tue,  5 Oct 2021 18:44:00 +0200	[thread overview]
Message-ID: <20211005164408.288128-5-pbonzini@redhat.com> (raw)
In-Reply-To: <20211005164408.288128-1-pbonzini@redhat.com>

From: Pedro Tôrres <t0rr3sp3dr0@gmail.com>

When running on a Mac, QEMU is able to get the host OSK and use it as
the default value for the AppleSMC device. The OSK query operation
doesn't require administrator privileges and can be executed by any user
on the system. This patch is based on open-source code from Apple, just
like the implementation from VirtualBox.

Apple:
https://opensource.apple.com/source/IOKitUser/IOKitUser-647.6.13/pwr_mgt.subproj/IOPMLibPrivate.c
https://opensource.apple.com/source/PowerManagement/PowerManagement-637.60.1/pmconfigd/PrivateLib.c

VirtualBox:
https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/EFI/DevSmc.cpp#L516

Signed-off-by: Pedro Tôrres <t0rr3sp3dr0@gmail.com>
---
 hw/misc/applesmc.c | 192 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 191 insertions(+), 1 deletion(-)

diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 1b9acaf1d3..cec247b5ee 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -38,6 +38,171 @@
 #include "qemu/timer.h"
 #include "qom/object.h"
 
+#if defined(__APPLE__) && defined(__MACH__)
+#include <IOKit/IOKitLib.h>
+
+enum {
+    kSMCSuccess     = 0x00,
+    kSMCKeyNotFound = 0x84
+};
+
+enum {
+    kSMCUserClientOpen  = 0x00,
+    kSMCUserClientClose = 0x01,
+    kSMCHandleYPCEvent  = 0x02,
+    kSMCReadKey         = 0x05,
+    kSMCGetKeyInfo      = 0x09
+};
+
+typedef struct SMCVersion {
+    uint8_t  major;
+    uint8_t  minor;
+    uint8_t  build;
+    uint8_t  reserved;
+    uint16_t release;
+} SMCVersion;
+
+typedef struct SMCPLimitData {
+    uint16_t version;
+    uint16_t length;
+    uint32_t cpuPLimit;
+    uint32_t gpuPLimit;
+    uint32_t memPLimit;
+} SMCPLimitData;
+
+typedef struct SMCKeyInfoData {
+    IOByteCount dataSize;
+    uint32_t    dataType;
+    uint8_t     dataAttributes;
+} SMCKeyInfoData;
+
+typedef struct {
+    uint32_t       key;
+    SMCVersion     vers;
+    SMCPLimitData  pLimitData;
+    SMCKeyInfoData keyInfo;
+    uint8_t        result;
+    uint8_t        status;
+    uint8_t        data8;
+    uint32_t       data32;
+    uint8_t        bytes[32];
+} SMCParamStruct;
+
+static IOReturn smc_call_struct_method(uint32_t selector,
+                                       SMCParamStruct *inputStruct,
+                                       SMCParamStruct *outputStruct)
+{
+    IOReturn ret;
+
+    size_t inputStructCnt = sizeof(SMCParamStruct);
+    size_t outputStructCnt = sizeof(SMCParamStruct);
+
+    io_service_t smcService = IO_OBJECT_NULL;
+    io_connect_t smcConnect = IO_OBJECT_NULL;
+
+    smcService = IOServiceGetMatchingService(kIOMasterPortDefault,
+                                             IOServiceMatching("AppleSMC"));
+    if (smcService == IO_OBJECT_NULL) {
+        ret = kIOReturnNotFound;
+        goto exit;
+    }
+
+    ret = IOServiceOpen(smcService, mach_task_self(), 1, &smcConnect);
+    if (ret != kIOReturnSuccess) {
+        smcConnect = IO_OBJECT_NULL;
+        goto exit;
+    }
+    if (smcConnect == IO_OBJECT_NULL) {
+        ret = kIOReturnError;
+        goto exit;
+    }
+
+    ret = IOConnectCallMethod(smcConnect, kSMCUserClientOpen,
+                              NULL, 0, NULL, 0,
+                              NULL, NULL, NULL, NULL);
+    if (ret != kIOReturnSuccess) {
+        goto exit;
+    }
+
+    ret = IOConnectCallStructMethod(smcConnect, selector,
+                                    inputStruct, inputStructCnt,
+                                    outputStruct, &outputStructCnt);
+
+exit:
+    if (smcConnect != IO_OBJECT_NULL) {
+        IOConnectCallMethod(smcConnect, kSMCUserClientClose,
+                            NULL, 0, NULL, 0, NULL,
+                            NULL, NULL, NULL);
+        IOServiceClose(smcConnect);
+    }
+
+    return ret;
+}
+
+static IOReturn smc_read_key(uint32_t key,
+                             uint8_t *bytes,
+                             IOByteCount *dataSize)
+{
+    IOReturn ret;
+
+    SMCParamStruct inputStruct;
+    SMCParamStruct outputStruct;
+
+    if (key == 0 || bytes == NULL) {
+        ret = kIOReturnCannotWire;
+        goto exit;
+    }
+
+    /* determine key's data size */
+    memset(&inputStruct, 0, sizeof(SMCParamStruct));
+    inputStruct.data8 = kSMCGetKeyInfo;
+    inputStruct.key = key;
+
+    memset(&outputStruct, 0, sizeof(SMCParamStruct));
+    ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct);
+    if (ret != kIOReturnSuccess) {
+        goto exit;
+    }
+    if (outputStruct.result == kSMCKeyNotFound) {
+        ret = kIOReturnNotFound;
+        goto exit;
+    }
+    if (outputStruct.result != kSMCSuccess) {
+        ret = kIOReturnInternalError;
+        goto exit;
+    }
+
+    /* get key value */
+    memset(&inputStruct, 0, sizeof(SMCParamStruct));
+    inputStruct.data8 = kSMCReadKey;
+    inputStruct.key = key;
+    inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize;
+
+    memset(&outputStruct, 0, sizeof(SMCParamStruct));
+    ret = smc_call_struct_method(kSMCHandleYPCEvent, &inputStruct, &outputStruct);
+    if (ret != kIOReturnSuccess) {
+        goto exit;
+    }
+    if (outputStruct.result == kSMCKeyNotFound) {
+        ret = kIOReturnNotFound;
+        goto exit;
+    }
+    if (outputStruct.result != kSMCSuccess) {
+        ret = kIOReturnInternalError;
+        goto exit;
+    }
+
+    memset(bytes, 0, *dataSize);
+    if (*dataSize > inputStruct.keyInfo.dataSize) {
+        *dataSize = inputStruct.keyInfo.dataSize;
+    }
+    memcpy(bytes, outputStruct.bytes, *dataSize);
+
+exit:
+    return ret;
+}
+#endif
+
 /* #define DEBUG_SMC */
 
 #define APPLESMC_DEFAULT_IOBASE        0x300
@@ -315,6 +480,7 @@ static const MemoryRegionOps applesmc_err_io_ops = {
 static void applesmc_isa_realize(DeviceState *dev, Error **errp)
 {
     AppleSMCState *s = APPLE_SMC(dev);
+    bool valid_key = false;
 
     memory_region_init_io(&s->io_data, OBJECT(s), &applesmc_data_io_ops, s,
                           "applesmc-data", 1);
@@ -331,7 +497,31 @@ static void applesmc_isa_realize(DeviceState *dev, Error **errp)
     isa_register_ioport(&s->parent_obj, &s->io_err,
                         s->iobase + APPLESMC_ERR_PORT);
 
-    if (!s->osk || (strlen(s->osk) != 64)) {
+    if (s->osk) {
+        valid_key = strlen(s->osk) == 64;
+    } else {
+#if defined(__APPLE__) && defined(__MACH__)
+        IOReturn ret;
+        IOByteCount size = 32;
+
+        ret = smc_read_key('OSK0', (uint8_t *) default_osk, &size);
+        if (ret != kIOReturnSuccess) {
+            goto failure;
+        }
+
+        ret = smc_read_key('OSK1', (uint8_t *) default_osk + size, &size);
+        if (ret != kIOReturnSuccess) {
+            goto failure;
+        }
+
+        warn_report("Using AppleSMC with host key");
+        valid_key = true;
+        s->osk = default_osk;
+failure:;
+#endif
+    }
+
+    if (!valid_key) {
         warn_report("Using AppleSMC with invalid key");
         s->osk = default_osk;
     }
-- 
2.31.1




  parent reply	other threads:[~2021-10-05 17:24 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-05 16:43 [PULL 00/12] Misc changes for 2021-10-05 Paolo Bonzini
2021-10-05 16:43 ` [PULL 01/12] i386: docs: Briefly describe KVM PV features Paolo Bonzini
2021-10-05 16:43 ` [PULL 02/12] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Paolo Bonzini
2021-10-05 16:43 ` [PULL 03/12] x86/sev: generate SEV kernel loader hashes in x86_load_linux Paolo Bonzini
2021-10-05 16:44 ` Paolo Bonzini [this message]
2021-10-05 16:44 ` [PULL 05/12] configure, meson: move CPU_CFLAGS out of QEMU_CFLAGS Paolo Bonzini
2021-10-05 16:44 ` [PULL 06/12] migration: block-dirty-bitmap: add missing qemu_mutex_lock_iothread Paolo Bonzini
2021-10-05 16:44 ` [PULL 07/12] migration: add missing qemu_mutex_lock_iothread in migration_completion Paolo Bonzini
2021-10-05 16:44 ` [PULL 08/12] meson: bump submodule to 0.59.2 Paolo Bonzini
2021-10-05 16:44 ` [PULL 09/12] meson: switch minimum meson version to 0.58.2, minimum recommended " Paolo Bonzini
2021-10-05 16:44 ` [PULL 10/12] hexagon: use env keyword argument to pass PYTHONPATH Paolo Bonzini
2021-10-05 16:44 ` [PULL 11/12] target/xtensa: list cores in a text file Paolo Bonzini
2021-10-05 16:44 ` [PULL 12/12] meson: show library versions in the summary Paolo Bonzini
2021-10-06 16:22   ` Philippe Mathieu-Daudé
2021-10-06 16:52     ` Richard Henderson
2021-10-06 16:55       ` Philippe Mathieu-Daudé
2021-10-06 17:16         ` Paolo Bonzini
2021-10-06 17:56           ` Philippe Mathieu-Daudé
2021-10-07  9:42             ` Paolo Bonzini
2021-10-05 21:34 ` [PULL 00/12] Misc changes for 2021-10-05 Richard Henderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211005164408.288128-5-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=t0rr3sp3dr0@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.