Explorar o código

helper: added NSTask launch mode for macOS 11.3

macOS 11.3 beta 2 fixed a bug (FB8921623) which prevented Hypervisor from
working in an inherited sandbox.
osy %!s(int64=4) %!d(string=hai) anos
pai
achega
40c04d3d33

+ 12 - 1
QEMUHelper/Bootstrap.c

@@ -77,7 +77,7 @@ static void __attribute__((noreturn)) runQemu(qemu_main_t *funcs, int argc, cons
     exit(0);
 }
 
-pid_t startQemu(const char *dylibPath, int argc, const char **argv, int newStdout, int newStderr) {
+pid_t startQemuFork(const char *dylibPath, int argc, const char **argv, int newStdout, int newStderr) {
     qemu_main_t funcs = {};
     int res = loadQemu(dylibPath, &funcs);
     if (res < 0) {
@@ -97,3 +97,14 @@ pid_t startQemu(const char *dylibPath, int argc, const char **argv, int newStdou
     // launch qemu
     runQemu(&funcs, argc, argv);
 }
+
+int startQemuProcess(const char *dylibPath, int argc, const char **argv) {
+    qemu_main_t funcs = {};
+    int res = loadQemu(dylibPath, &funcs);
+    if (res < 0) {
+        return res;
+    }
+    // launch qemu
+    runQemu(&funcs, argc, argv);
+    return 0;
+}

+ 2 - 1
QEMUHelper/Bootstrap.h

@@ -19,6 +19,7 @@
 
 #include <unistd.h>
 
-pid_t startQemu(const char *dylibPath, int argc, const char **argv, int newStdout, int newStderr);
+pid_t startQemuFork(const char *dylibPath, int argc, const char **argv, int newStdout, int newStderr);
+int startQemuProcess(const char *dylibPath, int argc, const char **argv);
 
 #endif /* Bootstrap_h */

+ 20 - 6
QEMUHelper/QEMUHelper.m

@@ -100,23 +100,37 @@
         return;
     }
     
-#if 0 // old NSTask code does not work with inherited sandbox
+    if (@available(macOS 11.3, *)) { // macOS 11.3 fixed sandbox bug for hypervisor to work
+        [self startQemuTask:binName standardOutput:standardOutput standardError:standardError libraryPath:libraryPath argv:argv onExit:onExit];
+    } else { // old deprecated fork() method
+        [self startQemuFork:binName standardOutput:standardOutput standardError:standardError libraryPath:libraryPath argv:argv onExit:onExit];
+    }
+}
+
+- (void)startQemuTask:(NSString *)binName standardOutput:(NSFileHandle *)standardOutput standardError:(NSFileHandle *)standardError libraryPath:(NSURL *)libraryPath argv:(NSArray<NSString *> *)argv onExit:(void(^)(BOOL,NSString *))onExit {
+    NSError *err;
     NSTask *task = [NSTask new];
-    task.executableURL = qemuURL;
-    task.arguments = argv;
+    NSMutableArray<NSString *> *newArgv = [argv mutableCopy];
+    NSString *path = [libraryPath URLByAppendingPathComponent:binName].path;
+    [newArgv insertObject:path atIndex:0];
+    task.executableURL = [[NSBundle mainBundle] URLForAuxiliaryExecutable:@"QEMULauncher"];
+    task.arguments = newArgv;
     task.standardOutput = standardOutput;
     task.standardError = standardError;
     //task.environment = @{@"DYLD_LIBRARY_PATH": libraryPath.path};
     task.qualityOfService = NSQualityOfServiceUserInitiated;
     task.terminationHandler = ^(NSTask *task) {
         BOOL normalExit = task.terminationReason == NSTaskTerminationReasonExit && task.terminationStatus == 0;
-        onExit(normalExit, nil); // TODO: get last error line
+        onExit(normalExit, nil);
     };
     if (![task launchAndReturnError:&err]) {
         NSLog(@"Error starting QEMU: %@", err);
         onExit(NO, NSLocalizedString(@"Error starting QEMU.", @"QEMUHelper"));
     }
-#endif
+}
+
+
+- (void)startQemuFork:(NSString *)binName standardOutput:(NSFileHandle *)standardOutput standardError:(NSFileHandle *)standardError libraryPath:(NSURL *)libraryPath argv:(NSArray<NSString *> *)argv onExit:(void(^)(BOOL,NSString *))onExit {
     // convert all the Objective-C strings to C strings as we should not use objects in this context after fork()
     NSString *path = [libraryPath URLByAppendingPathComponent:binName].path;
     char *cpath = strdup(path.UTF8String);
@@ -128,7 +142,7 @@
     }
     int newStdOut = standardOutput.fileDescriptor;
     int newStdErr = standardError.fileDescriptor;
-    pid_t pid = startQemu(cpath, argc, (const char **)cargv, newStdOut, newStdErr);
+    pid_t pid = startQemuFork(cpath, argc, (const char **)cargv, newStdOut, newStdErr);
     // free all resources regardless of error because on success, child has a copy
     [standardOutput closeFile];
     [standardError closeFile];

+ 14 - 0
QEMULauncher/QEMULauncher.entitlements

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.security.app-sandbox</key>
+	<true/>
+	<key>com.apple.security.cs.allow-jit</key>
+	<true/>
+	<key>com.apple.security.inherit</key>
+	<true/>
+	<key>com.apple.security.hypervisor</key>
+	<true/>
+</dict>
+</plist>

+ 26 - 0
QEMULauncher/main.c

@@ -0,0 +1,26 @@
+//
+// Copyright © 2021 osy. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <stdio.h>
+#include "Bootstrap.h"
+
+int main(int argc, const char * argv[]) {
+    if (argc < 2) {
+        fprintf(stderr, "usage: QEMULauncher dylibPath qemuArguments...\n");
+        return 1;
+    }
+    return startQemuProcess(argv[1], argc - 1, &argv[1]);
+}

+ 132 - 0
UTM.xcodeproj/project.pbxproj

@@ -643,6 +643,9 @@
 		CE4EF2722506DD7900E9D33B /* VMRemovableDrivesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE4EF2712506DD7900E9D33B /* VMRemovableDrivesView.xib */; };
 		CE5076DB250AB55D00C26C19 /* VMDisplayMetalViewController+Pencil.m in Sources */ = {isa = PBXBuildFile; fileRef = CE5076DA250AB55D00C26C19 /* VMDisplayMetalViewController+Pencil.m */; };
 		CE612AC624D3B50700FA6300 /* VMDisplayWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE612AC524D3B50700FA6300 /* VMDisplayWindowController.swift */; };
+		CE6B240B25F1F3CE0020D43E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = CE6B240A25F1F3CE0020D43E /* main.c */; };
+		CE6B241125F1F53E0020D43E /* Bootstrap.c in Sources */ = {isa = PBXBuildFile; fileRef = CE0DF17125A80B6300A51894 /* Bootstrap.c */; };
+		CE6B241525F1F5780020D43E /* QEMULauncher in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE6B240825F1F3CE0020D43E /* QEMULauncher */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
 		CE6D21DC2553A6ED001D29C5 /* VMConfirmActionModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6D21DB2553A6ED001D29C5 /* VMConfirmActionModifier.swift */; };
 		CE6D21DD2553A6ED001D29C5 /* VMConfirmActionModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE6D21DB2553A6ED001D29C5 /* VMConfirmActionModifier.swift */; };
 		CE772AAC25C8B0F600E4E379 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE772AAB25C8B0F600E4E379 /* ContentView.swift */; };
@@ -743,6 +746,13 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
+		CE6B241225F1F55C0020D43E /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = CE550BC1225947990063E575 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = CE6B240725F1F3CE0020D43E;
+			remoteInfo = QEMULauncher;
+		};
 		CEBDA1E324D8BDDB0010B5EC /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = CE550BC1225947990063E575 /* Project object */;
@@ -903,6 +913,16 @@
 			name = "Embed Libraries";
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		CE6B241425F1F5630020D43E /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 6;
+			files = (
+				CE6B241525F1F5780020D43E /* QEMULauncher in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		CEBDA1E924D8BDDB0010B5EC /* Embed XPC Services */ = {
 			isa = PBXCopyFilesBuildPhase;
 			buildActionMask = 2147483647;
@@ -1382,6 +1402,10 @@
 		CE66450E2269355F00B0849A /* CocoaSpice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CocoaSpice.h; sourceTree = "<group>"; };
 		CE66450F226935F000B0849A /* CSInput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CSInput.h; sourceTree = "<group>"; };
 		CE664510226935F000B0849A /* CSInput.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CSInput.m; sourceTree = "<group>"; };
+		CE6B240825F1F3CE0020D43E /* QEMULauncher */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QEMULauncher; sourceTree = BUILT_PRODUCTS_DIR; };
+		CE6B240A25F1F3CE0020D43E /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+		CE6B240F25F1F43A0020D43E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		CE6B241025F1F4B30020D43E /* QEMULauncher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QEMULauncher.entitlements; sourceTree = "<group>"; };
 		CE6D21DB2553A6ED001D29C5 /* VMConfirmActionModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VMConfirmActionModifier.swift; sourceTree = "<group>"; };
 		CE6EDCDD241C4A6800A719DC /* UTMViewState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UTMViewState.h; sourceTree = "<group>"; };
 		CE6EDCDE241C4A6800A719DC /* UTMViewState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UTMViewState.m; sourceTree = "<group>"; };
@@ -2166,6 +2190,7 @@
 				CE2D63CE2265150F00FC7E63 /* Renderer */,
 				CEBDA1DB24D8BDDA0010B5EC /* QEMUHelper */,
 				CE9D18F72265410E00355E14 /* qemu */,
+				CE6B240925F1F3CE0020D43E /* QEMULauncher */,
 				CE4698F824C8FBD9008C1BD6 /* Icons */,
 				CE550BCA225947990063E575 /* Products */,
 				CE2D63D622653C7300FC7E63 /* Frameworks */,
@@ -2179,6 +2204,7 @@
 				CE2D93BE24AD46670059923A /* UTM.app */,
 				CE2D951C24AD48BE0059923A /* UTM.app */,
 				CEBDA1DA24D8BDDA0010B5EC /* QEMUHelper.xpc */,
+				CE6B240825F1F3CE0020D43E /* QEMULauncher */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -2281,6 +2307,16 @@
 			path = Managers;
 			sourceTree = "<group>";
 		};
+		CE6B240925F1F3CE0020D43E /* QEMULauncher */ = {
+			isa = PBXGroup;
+			children = (
+				CE6B241025F1F4B30020D43E /* QEMULauncher.entitlements */,
+				CE6B240A25F1F3CE0020D43E /* main.c */,
+				CE6B240F25F1F43A0020D43E /* Info.plist */,
+			);
+			path = QEMULauncher;
+			sourceTree = "<group>";
+		};
 		CE7BED4D22600F5000A1E1B6 /* Display */ = {
 			isa = PBXGroup;
 			children = (
@@ -2494,6 +2530,21 @@
 			productReference = CE2D951C24AD48BE0059923A /* UTM.app */;
 			productType = "com.apple.product-type.application";
 		};
+		CE6B240725F1F3CE0020D43E /* QEMULauncher */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = CE6B240E25F1F3CE0020D43E /* Build configuration list for PBXNativeTarget "QEMULauncher" */;
+			buildPhases = (
+				CE6B240425F1F3CE0020D43E /* Sources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = QEMULauncher;
+			productName = QEMULauncher;
+			productReference = CE6B240825F1F3CE0020D43E /* QEMULauncher */;
+			productType = "com.apple.product-type.tool";
+		};
 		CEBDA1D924D8BDDA0010B5EC /* QEMUHelper */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = CEBDA1E624D8BDDB0010B5EC /* Build configuration list for PBXNativeTarget "QEMUHelper" */;
@@ -2501,10 +2552,12 @@
 				CEBDA1D624D8BDDA0010B5EC /* Sources */,
 				CEBDA1D724D8BDDA0010B5EC /* Frameworks */,
 				CEBDA1D824D8BDDA0010B5EC /* Resources */,
+				CE6B241425F1F5630020D43E /* CopyFiles */,
 			);
 			buildRules = (
 			);
 			dependencies = (
+				CE6B241325F1F55C0020D43E /* PBXTargetDependency */,
 			);
 			name = QEMUHelper;
 			productName = QEMUHelper;
@@ -2528,6 +2581,9 @@
 						CreatedOnToolsVersion = 12.0;
 						LastSwiftMigration = 1200;
 					};
+					CE6B240725F1F3CE0020D43E = {
+						CreatedOnToolsVersion = 12.5;
+					};
 					CEBDA1D924D8BDDA0010B5EC = {
 						CreatedOnToolsVersion = 12.0;
 					};
@@ -2556,6 +2612,7 @@
 				CE2D926824AD46670059923A /* iOS */,
 				CE2D951B24AD48BE0059923A /* macOS */,
 				CEBDA1D924D8BDDA0010B5EC /* QEMUHelper */,
+				CE6B240725F1F3CE0020D43E /* QEMULauncher */,
 			);
 		};
 /* End PBXProject section */
@@ -3124,6 +3181,15 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		CE6B240425F1F3CE0020D43E /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				CE6B241125F1F53E0020D43E /* Bootstrap.c in Sources */,
+				CE6B240B25F1F3CE0020D43E /* main.c in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		CEBDA1D624D8BDDA0010B5EC /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -3137,6 +3203,11 @@
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+		CE6B241325F1F55C0020D43E /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = CE6B240725F1F3CE0020D43E /* QEMULauncher */;
+			targetProxy = CE6B241225F1F55C0020D43E /* PBXContainerItemProxy */;
+		};
 		CEBDA1E424D8BDDB0010B5EC /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = CEBDA1D924D8BDDA0010B5EC /* QEMUHelper */;
@@ -3274,6 +3345,7 @@
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
 				CURRENT_PROJECT_VERSION = 23;
+				DEVELOPMENT_TEAM = "";
 				ENABLE_HARDENED_RUNTIME = YES;
 				ENABLE_PREVIEWS = YES;
 				HEADER_SEARCH_PATHS = (
@@ -3297,6 +3369,7 @@
 				MARKETING_VERSION = 2.0.23;
 				PRODUCT_BUNDLE_IDENTIFIER = com.utmapp.UTM;
 				PRODUCT_NAME = "$(PROJECT_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
 				SDKROOT = macosx;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
 				SWIFT_OBJC_BRIDGING_HEADER = "Platform/Swift-Bridging-Header.h";
@@ -3317,6 +3390,7 @@
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
 				CURRENT_PROJECT_VERSION = 23;
+				DEVELOPMENT_TEAM = "";
 				ENABLE_HARDENED_RUNTIME = YES;
 				ENABLE_PREVIEWS = YES;
 				HEADER_SEARCH_PATHS = (
@@ -3340,6 +3414,7 @@
 				MARKETING_VERSION = 2.0.23;
 				PRODUCT_BUNDLE_IDENTIFIER = com.utmapp.UTM;
 				PRODUCT_NAME = "$(PROJECT_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
 				SDKROOT = macosx;
 				SWIFT_COMPILATION_MODE = wholemodule;
 				SWIFT_OBJC_BRIDGING_HEADER = "Platform/Swift-Bridging-Header.h";
@@ -3466,6 +3541,50 @@
 			};
 			name = Release;
 		};
+		CE6B240C25F1F3CE0020D43E /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CODE_SIGN_ENTITLEMENTS = QEMULauncher/QEMULauncher.entitlements;
+				CODE_SIGN_IDENTITY = "-";
+				CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
+				CODE_SIGN_STYLE = Automatic;
+				CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
+				DEVELOPMENT_TEAM = "";
+				ENABLE_HARDENED_RUNTIME = YES;
+				INFOPLIST_FILE = QEMULauncher/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../../../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 11.0;
+				MARKETING_VERSION = 2.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.utmapp.QEMULauncher;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		CE6B240D25F1F3CE0020D43E /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+				CODE_SIGN_ENTITLEMENTS = QEMULauncher/QEMULauncher.entitlements;
+				CODE_SIGN_IDENTITY = "-";
+				CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
+				CODE_SIGN_STYLE = Automatic;
+				CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
+				DEVELOPMENT_TEAM = "";
+				ENABLE_HARDENED_RUNTIME = YES;
+				INFOPLIST_FILE = QEMULauncher/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = "@executable_path/../../../../Frameworks";
+				MACOSX_DEPLOYMENT_TARGET = 11.0;
+				MARKETING_VERSION = 2.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.utmapp.QEMULauncher;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
 		CEBDA1E724D8BDDB0010B5EC /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -3474,6 +3593,7 @@
 				CODE_SIGN_IDENTITY = "-";
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
+				DEVELOPMENT_TEAM = "";
 				ENABLE_HARDENED_RUNTIME = YES;
 				INFOPLIST_FILE = QEMUHelper/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = (
@@ -3484,6 +3604,7 @@
 				MARKETING_VERSION = 2.0;
 				PRODUCT_BUNDLE_IDENTIFIER = com.utmapp.QEMUHelper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
 				SDKROOT = macosx;
 				SKIP_INSTALL = YES;
 			};
@@ -3497,6 +3618,7 @@
 				CODE_SIGN_IDENTITY = "-";
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
+				DEVELOPMENT_TEAM = "";
 				ENABLE_HARDENED_RUNTIME = YES;
 				INFOPLIST_FILE = QEMUHelper/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = (
@@ -3507,6 +3629,7 @@
 				MARKETING_VERSION = 2.0;
 				PRODUCT_BUNDLE_IDENTIFIER = com.utmapp.QEMUHelper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				PROVISIONING_PROFILE_SPECIFIER = "";
 				SDKROOT = macosx;
 				SKIP_INSTALL = YES;
 			};
@@ -3542,6 +3665,15 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		CE6B240E25F1F3CE0020D43E /* Build configuration list for PBXNativeTarget "QEMULauncher" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				CE6B240C25F1F3CE0020D43E /* Debug */,
+				CE6B240D25F1F3CE0020D43E /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		CEBDA1E624D8BDDB0010B5EC /* Build configuration list for PBXNativeTarget "QEMUHelper" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (