1
0
mirror of https://github.com/dart-lang/sdk synced 2024-07-03 00:08:46 +00:00

[gn] Support producing signed builds on Mac

This can be controlled via  codesigning_identity GN arg.

For example, setting codesigning_identity="-"
would produce ad-hoc signed binaries.

This CL also includes changes in vm/cc tests which are needed
for tests to be green when running with hardened runtime.

Issue https://github.com/dart-lang/sdk/issues/53928

Tested: enabled ad-hoc signing and tested on bots.
Cq-Include-Trybots: luci.dart.try:vm-mac-debug-arm64-try,vm-mac-release-arm64-try,vm-mac-release-x64-try,vm-mac-debug-x64-try
Change-Id: I3c3a6265c62b2904e43a326b7d8223bcfd393577
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333401
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
This commit is contained in:
Vyacheslav Egorov 2023-11-03 07:36:25 +00:00 committed by Commit Queue
parent ad2708d071
commit 4ce23629eb
13 changed files with 191 additions and 8 deletions

View File

@ -14,6 +14,7 @@ assert(host_os == "mac")
import("//build/config/sysroot.gni")
import("//build/toolchain/goma.gni")
import("//build/toolchain/rbe.gni")
import("//build/toolchain/signing.gni")
if (use_goma) {
assembler_prefix = "$goma_dir/gomacc "
@ -189,20 +190,44 @@ template("mac_toolchain") {
stripped_outfile = "{{root_out_dir}}/exe.stripped/$exename"
}
command = "$ld $sysroot_flags $toolchain_flags {{ldflags}} -Xlinker -rpath -Xlinker @executable_path/Frameworks -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}} {{frameworks}}"
commands = [ "$ld $sysroot_flags $toolchain_flags {{ldflags}} -Xlinker -rpath -Xlinker @executable_path/Frameworks -o $outfile -Wl,-filelist,$rspfile {{solibs}} {{libs}} {{frameworks}}" ]
symbolizer_script =
rebase_path("//runtime/tools/dart_profiler_symbols.py")
symbolize_command =
"$symbolizer_script --nm $nm --output $symfile --binary $outfile"
command += " && $symbolize_command"
commands +=
[ "$symbolizer_script --nm $nm --output $symfile --binary $outfile" ]
if (defined(invoker.strip)) {
strip = invoker.strip
strip_command = "${strip} -x -o $stripped_outfile $outfile"
command += " && " + strip_command
commands += [ "${strip} -x -o $stripped_outfile $outfile" ]
}
if (codesigning_identity != "") {
# codesign tool performs signing in-place. This does not fit very well
# into the overall build: we would have to produce unsigned binary with
# some suffix (e.g. dart_unsigned), then copy it to the final location
# and sign. To avoid this dance we choose to perform signing here
# at the link step. Unfortunately this also comes with some limitations:
# executable target can't push arbitrary configuration variables down
# to the link step. Which means we can't specify per target
# entitlement files - and instead rely on dart_codesign.py script to
# match binaries to their entitlement files by name.
signing_script = rebase_path("//runtime/tools/dart_codesign.py")
binaries_to_sign = [
"--binary",
outfile,
]
if (defined(stripped_outfile)) {
binaries_to_sign += [
"--binary",
stripped_outfile,
]
}
commands += [ "$signing_script --identity $codesigning_identity " +
string_join(" ", binaries_to_sign) ]
}
command = string_join(" && ", commands)
description = "LINK $outfile"
rspfile_content = "{{inputs_newline}}"
outputs = [

View File

@ -0,0 +1,16 @@
# Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Defines code signing configuration for Mac builds.
declare_args() {
# If codesigning_identity is not empty then all executables will be
# signed using the specified identity and using corresponding entitlements
# from runtime/tools/entitlements/${binary_name}.plist.
#
# You can specify codesigning_identity = "-" to use ad-hoc codesigning.
#
# See also runtime/tools/dart_codesigning.py script.
codesigning_identity = ""
}

63
runtime/tools/dart_codesign.py Executable file
View File

@ -0,0 +1,63 @@
#!/usr/bin/env python3
#
# Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
#
# Sign given binaries with using the specified signing identity and
# using entitlements from runtime/tools/entitlement/${binary_name}.plist
# if any.
#
import optparse
import os
import subprocess
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
def SignBinary(identity, binary):
codesign_args = [
"--deep", "--force", "--verify", "--verbose", "--timestamp",
"--options", "runtime", "--sign", identity
]
name = os.path.basename(binary)
# Check if we have a matching entitlements file and apply it.
# It would be simpler if we could specify it from outside but
# GN does not give us tools for doing that: executable target can't
# push arbitrary configuration down to the link tool where
# we would like to perform code signing.
entitlements_file = os.path.join(SCRIPT_DIR, "entitlements",
name + ".plist")
if os.path.exists(entitlements_file):
codesign_args += ["--entitlements", entitlements_file]
cmd = ["codesign"] + codesign_args + [binary]
result = subprocess.run(cmd, capture_output=True, encoding="utf8")
if result.returncode != 0:
print("failed to run: " + " ".join(cmd))
print(f"exit code: {result.returncode}")
print("stdout:")
print(result.stdout)
print("stdout:")
print(result.stderr)
raise Exception("failed to codesign")
parser = optparse.OptionParser()
parser.add_option("--identity", type="string", help="Code signing identity")
parser.add_option("--binary",
type="string",
action="append",
help="Binary to sign")
options = parser.parse_args()[0]
if not options.identity:
raise Exception("Missing code signing identity (--identity)")
if not options.binary:
raise Exception("Missing binaries to sign (--binary)")
for binary in options.binary:
SignBinary(options.identity, binary)

View File

@ -0,0 +1,6 @@
These entitlement configurations are used when GN arg codesigning_identity
is set to non-empty string.
They must be kept in sync with [entitlements][1] used for codesigning releases:
[1]: https://dart.googlesource.com/recipes/+/refs/heads/main/recipes/release/sign-mac.resources/Entitlements_dart.plist

View File

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

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>

View File

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

View File

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

View File

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

View File

@ -199,7 +199,7 @@ static void TestRegress38528(intptr_t header_overlap) {
const uword page = VirtualMemory::PageSize();
std::unique_ptr<VirtualMemory> blob(VirtualMemory::Allocate(
2 * page,
/*is_executable=*/false, /*is_compressed*/ false, "test"));
/*is_executable=*/true, /*is_compressed=*/false, "test"));
const intptr_t remainder_size = page / 2;
const intptr_t alloc_size = page - header_overlap * kObjectAlignment;
void* const other_code =

View File

@ -109,8 +109,18 @@ VM_UNIT_TEST_CASE(DuplicateRXVirtualMemory) {
reinterpret_cast<void*>(page_start), 2 * page_size);
EXPECT_NE(nullptr, vm);
#if defined(DART_HOST_OS_MACOS) && !defined(DART_PRECOMPILED_RUNTIME)
// If we are not going to use vm_remap then we need to pass
// is_executable=true so that pages get allocated with MAP_JIT flag if
// necessary. Otherwise OS will kill us with a codesigning violation if
// hardened runtime is enabled.
const bool is_executable = true;
#else
const bool is_executable = false;
#endif
VirtualMemory* vm2 = VirtualMemory::AllocateAligned(
vm->size(), kPageSize, /*is_executable=*/false,
vm->size(), kPageSize, is_executable,
/*is_compressed=*/false, "FfiCallbackMetadata::TrampolinePage");
bool ok = vm->DuplicateRX(vm2);
EXPECT_EQ(true, ok);

View File

@ -330,6 +330,9 @@ def ToGnArgs(args, mode, arch, target_os, sanitizer, verify_sdk_hash):
gn_args['verify_sdk_hash'] = verify_sdk_hash
if args.codesigning_identity != '':
gn_args['codesigning_identity'] = args.codesigning_identity
return gn_args
@ -518,6 +521,10 @@ def AddCommonGnOptionArgs(parser):
default=False,
dest='use_mallinfo2',
action='store_true')
parser.add_argument('--codesigning-identity',
help='Sign executables using the given identity.',
default='',
type=str)
def AddCommonConfigurationArgs(parser):