Compare commits

...

4 Commits

Author SHA1 Message Date
Keeley Hammond
86d839a881 build: correct CHECK syntax (#48106) 2025-08-18 17:41:48 -07:00
Keeley Hammond
5be0be7f04 fix: ensure snapshot is valid (#48105)
* feat: add support for embedder snapshot validation

* chore: e patches all

---------

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-08-18 14:46:40 -07:00
trop[bot]
df232d1269 ci: cleanup use new arc cluster (#48007)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-08-09 09:46:41 +02:00
John Kleinschmidt
ab51554bdf ci: fixup mac runner hang (#47992) 2025-08-08 12:54:44 +02:00
10 changed files with 149 additions and 15 deletions

View File

@@ -47,11 +47,6 @@ runs:
- name: Add Clang problem matcher
shell: bash
run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json"
- name: Enable long paths for Windows
shell: powershell
if: ${{ inputs.target-platform == 'win' }}
run: |
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -Type DWord
- name: Build Electron ${{ inputs.step-suffix }}
shell: bash
run: |

View File

@@ -6,6 +6,8 @@ runs:
- name: Free Space on MacOS
shell: bash
run: |
echo "Disk usage before cleanup:"
df -h
sudo mkdir -p $TMPDIR/del-target
tmpify() {
@@ -62,4 +64,5 @@ runs:
# lipo off some huge binaries arm64 versions to save space
strip_universal_deep $(xcode-select -p)/../SharedFrameworks
# strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr
# strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr
sudo mdutil -a -i off

View File

@@ -36,12 +36,8 @@ runs:
echo "SAS Token not found; exiting src cache download early..."
exit 1
else
echo "const fs = require('fs');" > gettoken.js
echo "const fileContents = fs.readFileSync('sas-token', 'utf8');" >> gettoken.js
echo "const token = JSON.parse(fileContents);" >> gettoken.js
echo "console.log(token[process.argv[2]])" >> gettoken.js
sas_token=$(node ./gettoken.js sasToken)
account_name=$(node ./gettoken.js accountName)
sas_token=$(jq -r '.sasToken' sas-token)
account_name=$(jq -r '.accountName' sas-token)
if [ "${{ inputs.target-platform }}" = "win" ]; then
azcopy copy --log-level=ERROR \
"https://$account_name.file.core.windows.net/${{ env.AZURE_AKS_WIN_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar

View File

@@ -103,6 +103,9 @@ jobs:
"'kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceCamera','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceBluetoothAlways','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceAppleEvents','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceCamera','/opt/hca/hosted-compute-agent',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceBluetoothAlways','/opt/hca/hosted-compute-agent',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
)
for values in "${userValuesArray[@]}"; do
# Sonoma and higher have a few extra values

View File

@@ -518,6 +518,10 @@ source_set("electron_lib") {
"//v8:v8_libplatform",
]
if (v8_use_external_startup_data && use_v8_context_snapshot) {
deps += [ ":mksnapshot_checksum_gen" ]
}
public_deps = [
"//base",
"//base:i18n",
@@ -772,6 +776,14 @@ source_set("electron_lib") {
}
}
action("mksnapshot_checksum_gen") {
script = "build/checksum_header.py"
outputs = [ "$target_gen_dir/snapshot_checksum.h" ]
inputs = [ "$root_out_dir/$v8_context_snapshot_filename" ]
args = rebase_path(inputs) + rebase_path(outputs)
deps = [ "//tools/v8_context_snapshot" ]
}
electron_paks("packed_resources") {
if (is_mac) {
output_dir = "$root_gen_dir/electron_repack"

37
build/checksum_header.py Normal file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python3
import os
import sys
import hashlib
dir_path = os.path.dirname(os.path.realpath(__file__))
TEMPLATE_H = """
#ifndef ELECTRON_SNAPSHOT_CHECKSUM_H_
#define ELECTRON_SNAPSHOT_CHECKSUM_H_
namespace electron::snapshot_checksum {
const std::string kChecksum = "{checksum}";
} // namespace electron::snapshot_checksum
#endif // ELECTRON_SNAPSHOT_CHECKSUM_H_
"""
def calculate_sha256(filepath):
sha256_hash = hashlib.sha256()
with open(filepath, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
input_file = sys.argv[1]
output_file = sys.argv[2]
checksum = calculate_sha256(input_file)
checksum_h = TEMPLATE_H.replace("{checksum}", checksum)
with open(output_file, 'w') as f:
f.write(checksum_h)

View File

@@ -154,3 +154,4 @@ make_focus_methods_in_webcontentsviewchildframe_notimplemented.patch
cherry-pick-295a4a1b14b8.patch
cherry-pick-c3568ceda9d8.patch
cherry-pick-f1e6422a355c.patch
feat_add_support_for_embedder_snapshot_validation.patch

View File

@@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <sattard@anthropic.com>
Date: Fri, 15 Aug 2025 14:58:12 -0700
Subject: feat: add support for embedder snapshot validation
IsValid is not exposed despite being commented as for embedders, this exposes something that works for us.
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index 9b80a6f0cd185e6a9ccdaf3977040a241a25e568..f3f9c6d4d3b7d32243de9d091277fc1a361880cb 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -75,11 +75,23 @@ bool GenerateEntropy(unsigned char* buffer, size_t amount) {
return true;
}
+static base::RepeatingCallback<void(v8::StartupData*)>& SnapshotValidator() {
+ static base::NoDestructor<base::RepeatingCallback<void(v8::StartupData*)>>
+ validator(
+ base::BindRepeating([](v8::StartupData* data) -> void { /* empty */ }));
+ return *validator;
+}
+
+void SetV8SnapshotValidatorInner(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
+ SnapshotValidator() = std::move(callback);
+}
+
void GetMappedFileData(base::MemoryMappedFile* mapped_file,
v8::StartupData* data) {
if (mapped_file) {
data->data = reinterpret_cast<const char*>(mapped_file->data());
data->raw_size = static_cast<int>(mapped_file->length());
+ SnapshotValidator().Run(data);
} else {
data->data = nullptr;
data->raw_size = 0;
@@ -223,6 +235,10 @@ constexpr std::string_view kV8FlagFeaturePrefix = "V8Flag_";
} // namespace
+void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback) {
+ SetV8SnapshotValidatorInner(std::move(callback));
+}
+
class V8FeatureVisitor : public base::FeatureVisitor {
public:
void Visit(const std::string& feature_name,
diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h
index 6f7382cd600cd34916d9382878aee4b469dae5d0..61ed0f46437d2e1abbcebcfb64df06d17c8d9139 100644
--- a/gin/v8_initializer.h
+++ b/gin/v8_initializer.h
@@ -11,6 +11,7 @@
#include "base/files/file.h"
#include "base/files/memory_mapped_file.h"
+#include "base/functional/callback.h"
#include "build/build_config.h"
#include "gin/array_buffer.h"
#include "gin/gin_export.h"
@@ -28,6 +29,8 @@ class StartupData;
namespace gin {
+void SetV8SnapshotValidator(const base::RepeatingCallback<void(v8::StartupData*)>& callback);
+
class GIN_EXPORT V8Initializer {
public:
// This should be called by IsolateHolder::Initialize().

View File

@@ -23,10 +23,13 @@
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "content/public/app/initialize_mojo_core.h"
#include "content/public/common/content_switches.h"
#include "crypto/hash.h"
#include "electron/buildflags/buildflags.h"
#include "electron/fuses.h"
#include "electron/mas.h"
#include "electron/snapshot_checksum.h"
#include "extensions/common/constants.h"
#include "gin/v8_initializer.h"
#include "ipc/ipc_buildflags.h"
#include "sandbox/policy/switches.h"
#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
@@ -49,6 +52,7 @@
#include "third_party/abseil-cpp/absl/types/variant.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"
#include "v8/include/v8-snapshot.h"
#if BUILDFLAG(IS_MAC)
#include "shell/app/electron_main_delegate_mac.h"
@@ -206,6 +210,20 @@ void RegisterPathProvider() {
PATH_END);
}
void ValidateV8Snapshot(v8::StartupData* data) {
if (data->data &&
electron::fuses::IsEmbeddedAsarIntegrityValidationEnabled()) {
CHECK_GT(data->raw_size, 0);
UNSAFE_BUFFERS({
base::span<const char> span_data(
data->data, static_cast<unsigned long>(data->raw_size));
CHECK(base::ToLowerASCII(base::HexEncode(
crypto::hash::Sha256(base::as_bytes(span_data)))) ==
electron::snapshot_checksum::kChecksum);
})
}
}
} // namespace
std::string LoadResourceBundle(const std::string& locale) {
@@ -229,7 +247,9 @@ std::string LoadResourceBundle(const std::string& locale) {
return loaded_locale;
}
ElectronMainDelegate::ElectronMainDelegate() = default;
ElectronMainDelegate::ElectronMainDelegate() {
gin::SetV8SnapshotValidator(base::BindRepeating(&ValidateV8Snapshot));
}
ElectronMainDelegate::~ElectronMainDelegate() = default;

View File

@@ -3089,7 +3089,7 @@ describe('iframe using HTML fullscreen API while window is OS-fullscreened', ()
});
});
ifdescribe(process.platform !== 'darwin' || process.arch !== 'arm64')('navigator.serial', () => {
describe('navigator.serial', () => {
let w: BrowserWindow;
before(async () => {
w = new BrowserWindow({
@@ -3621,7 +3621,7 @@ ifdescribe((process.platform !== 'linux' || app.isUnityRunning()))('navigator.se
});
});
ifdescribe(process.platform !== 'darwin' || process.arch !== 'arm64')('navigator.bluetooth', () => {
describe('navigator.bluetooth', () => {
let w: BrowserWindow;
before(async () => {
w = new BrowserWindow({