From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- toolkit/mozapps/update/updater/Makefile.in | 3 + toolkit/mozapps/update/updater/launchchild_osx.mm | 56 +++++++--- .../UpdateSettings-WrongChannel/moz.build | 18 +++ .../UpdateSettings-xpcshell/moz.build | 18 +++ .../macos-frameworks/UpdateSettings/Info.plist | 24 ++++ .../macos-frameworks/UpdateSettings/README.md | 77 +++++++++++++ .../UpdateSettings/UpdateSettings.h | 17 +++ .../UpdateSettings/UpdateSettings.mm | 13 +++ .../macos-frameworks/UpdateSettings/moz.build | 24 ++++ .../updater/macos-frameworks/UpdateSettingsUtil.h | 17 +++ .../updater/macos-frameworks/UpdateSettingsUtil.mm | 21 ++++ .../update/updater/macos-frameworks/moz.build | 18 +++ toolkit/mozapps/update/updater/moz.build | 3 + .../mozapps/update/updater/updater-common.build | 13 ++- .../update/updater/updater-xpcshell/Makefile.in | 4 + toolkit/mozapps/update/updater/updater.cpp | 121 +++++++++++++++------ 16 files changed, 396 insertions(+), 51 deletions(-) create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm create mode 100644 toolkit/mozapps/update/updater/macos-frameworks/moz.build (limited to 'toolkit/mozapps/update/updater') diff --git a/toolkit/mozapps/update/updater/Makefile.in b/toolkit/mozapps/update/updater/Makefile.in index 70cf32378a..ec3ad9773a 100644 --- a/toolkit/mozapps/update/updater/Makefile.in +++ b/toolkit/mozapps/update/updater/Makefile.in @@ -25,4 +25,7 @@ libs:: $(call py_action,preprocessor updater.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings) $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS $(NSINSTALL) $(DIST)/bin/org.mozilla.updater $(DIST)/bin/updater.app/Contents/MacOS + $(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/Frameworks + $(NSINSTALL) $(DIST)/bin/UpdateSettings $(DIST)/bin/updater.app/Contents/Frameworks/UpdateSettings.framework + $(NSINSTALL) $(srcdir)/macos-frameworks/UpdateSettings/Info.plist $(DIST)/bin/updater.app/Contents/Frameworks/UpdateSettings.framework/Resources endif diff --git a/toolkit/mozapps/update/updater/launchchild_osx.mm b/toolkit/mozapps/update/updater/launchchild_osx.mm index 917f282d9f..b64e85980c 100644 --- a/toolkit/mozapps/update/updater/launchchild_osx.mm +++ b/toolkit/mozapps/update/updater/launchchild_osx.mm @@ -280,8 +280,9 @@ void CleanupElevatedMacUpdate(bool aFailureOccurred) { LaunchChild(3, launchctlArgs); } -// Note: Caller is responsible for freeing argv. -bool ObtainUpdaterArguments(int* argc, char*** argv) { +// Note: Caller is responsible for freeing aArgv. +bool ObtainUpdaterArguments(int* aArgc, char*** aArgv, + MARChannelStringTable* aMARStrings) { MacAutoreleasePool pool; id updateServer = ConnectToUpdateServer(); @@ -294,15 +295,22 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { @try { NSArray* updaterArguments = [updateServer performSelector:@selector(getArguments)]; - *argc = [updaterArguments count]; - char** tempArgv = (char**)malloc(sizeof(char*) * (*argc)); - for (int i = 0; i < *argc; i++) { + *aArgc = [updaterArguments count]; + char** tempArgv = (char**)malloc(sizeof(char*) * (*aArgc)); + for (int i = 0; i < *aArgc; i++) { int argLen = [[updaterArguments objectAtIndex:i] length] + 1; tempArgv[i] = (char*)malloc(argLen); strncpy(tempArgv[i], [[updaterArguments objectAtIndex:i] UTF8String], argLen); } - *argv = tempArgv; + *aArgv = tempArgv; + + NSString* channelID = + [updateServer performSelector:@selector(getMARChannelID)]; + const char* channelIDStr = [channelID UTF8String]; + aMARStrings->MARChannelID = + mozilla::MakeUnique(strlen(channelIDStr) + 1); + strcpy(aMARStrings->MARChannelID.get(), channelIDStr); } @catch (NSException* e) { // Let's try our best and clean up. CleanupElevatedMacUpdate(true); @@ -321,10 +329,12 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { NSArray* mUpdaterArguments; BOOL mShouldKeepRunning; BOOL mAborted; + NSString* mMARChannelID; } -- (id)initWithArgs:(NSArray*)args; +- (id)initWithArgs:(NSArray*)aArgs marChannelID:(NSString*)aMARChannelID; - (BOOL)runServer; - (NSArray*)getArguments; +- (NSString*)getMARChannelID; - (void)abort; - (BOOL)wasAborted; - (void)shutdown; @@ -333,12 +343,13 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { @implementation ElevatedUpdateServer -- (id)initWithArgs:(NSArray*)args { +- (id)initWithArgs:(NSArray*)aArgs marChannelID:(NSString*)aMARChannelID { self = [super init]; if (!self) { return nil; } - mUpdaterArguments = args; + mUpdaterArguments = aArgs; + mMARChannelID = aMARChannelID; mShouldKeepRunning = YES; mAborted = NO; return self; @@ -367,6 +378,20 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { return mUpdaterArguments; } +/** + * The MAR channel ID(s) are stored in the UpdateSettings.framework that ships + * with the updater.app bundle. When an elevated update is occurring, the + * org.mozilla.updater binary is extracted and installed individually as a + * Privileged Helper Tool. This Privileged Helper Tool does not have access to + * the UpdateSettings.framework and we therefore rely on the unelevated updater + * process to pass this information to the elevated updater process in the same + * fashion that the command line arguments are passed to the elevated updater + * process by `getArguments`. + */ +- (NSString*)getMARChannelID { + return mMARChannelID; +} + - (void)abort { mAborted = YES; [self shutdown]; @@ -386,16 +411,19 @@ bool ObtainUpdaterArguments(int* argc, char*** argv) { @end -bool ServeElevatedUpdate(int argc, const char** argv) { +bool ServeElevatedUpdate(int aArgc, const char** aArgv, + const char* aMARChannelID) { MacAutoreleasePool pool; - NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:argc]; - for (int i = 0; i < argc; i++) { - [updaterArguments addObject:[NSString stringWithUTF8String:argv[i]]]; + NSMutableArray* updaterArguments = [NSMutableArray arrayWithCapacity:aArgc]; + for (int i = 0; i < aArgc; i++) { + [updaterArguments addObject:[NSString stringWithUTF8String:aArgv[i]]]; } + NSString* channelID = [NSString stringWithUTF8String:aMARChannelID]; ElevatedUpdateServer* updater = - [[ElevatedUpdateServer alloc] initWithArgs:[updaterArguments copy]]; + [[ElevatedUpdateServer alloc] initWithArgs:updaterArguments + marChannelID:channelID]; bool didSucceed = [updater runServer]; [updater release]; diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build new file mode 100644 index 0000000000..e1f4ad0981 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Framework("UpdateSettings-WrongChannel") +FINAL_TARGET = "_tests/xpcshell/toolkit/mozapps/update/tests" + +DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"wrong-channel"' + +UNIFIED_SOURCES += [ + "../UpdateSettings/UpdateSettings.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build new file mode 100644 index 0000000000..6c9b43b146 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Framework("UpdateSettings-xpcshell") +FINAL_TARGET = "_tests/xpcshell/toolkit/mozapps/update/tests" + +DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"xpcshell-test"' + +UNIFIED_SOURCES += [ + "../UpdateSettings/UpdateSettings.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist new file mode 100644 index 0000000000..65777a475f --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + UpdateSettings + CFBundleIdentifier + org.mozilla.updatesettings + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + UpdateSettings + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + + diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md new file mode 100644 index 0000000000..32b9d2ea48 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md @@ -0,0 +1,77 @@ +# UpdateSettings macOS Framework + +## Summary + +The UpdateSettings macOS Framework is used to set the accepted MAR download +channels. + +## What are MAR update channels and what are they used for? + +As the name implies, MAR update channels are the channels where MAR update files +are served from and we want to ensure that the updater only applies MAR files +from accepted channels. + +## Why do we need a Framework instead of compiling the accepted MAR update channels directly into the executable? + +There are three main use cases that make it necessary for the accepted MAR +update channels to be set by external means, such as a macOS Framework: + + 1. Allowing users on the Beta channel to test RC builds + +Our beta users test release candidate builds before they are released to the +release population. The MAR files related to release candidates have their MAR +channel set to `release`. We make it possible for beta users to test these +release candidate MAR files by having beta Firefox installs accept MAR files +with their internal update channel set to either `release` or `beta`. + + 2. Switching users to another channel, such as ESR + +In contrast to the Beta use case outlined above, there are times where we +explicitly WANT to switch users to a different channel. An example of this is +when hardware or a particular macOS version have reached their EOL. In this +case, we usually switch users to our ESR channel for extended support. We switch +users to a different channel by serving a MAR file that forces a change to the +update channels that will be accepted for future updates. In other words, while +users may have previously accepted MAR update files from the `release` channel, +they now only accept MAR files from the `esr` channel. + + 3. QA update testing + +QA requires a way to temporarily switch the MAR update channel to a test channel +in order to test MAR updates before new releases. + +## How does the UpdateSettings macOS Framework address these use cases? + +We are able to accommodate all three use cases above by enabling the updater to +ignore certain files on disk if they are already present, but continue to force +update them if so desired. + +In the case of a Beta user updating to an RC build, the updater would encounter +an UpdateSettings macOS Framework inside the .app bundle that has the accepted +MAR update channels set to `beta` and `release`. In this case, the updater will +not update the Framework, but update everything else. This beta user is now able +to run the RC build with the update channel still set to `beta` and `release` +and will be able to apply MAR files related to the next beta cycle once the end +of RC builds is reached. + +In the case of switching users to the ESR channel, the updater will be set to +forcefully update the UpdateSettings macOS Framework, even if already present on +disk. After the update, the user will now be set to accept MAR updates from the +`esr` channel only. + +Before releases, QA replaces the UpdateSettings macOS Framework within the .app +bundle and set the accepted MAR update channels to a test channel in order to +test MAR updates. During testing, the new Framework file would remain in place +for typical update testing, but gets replaced in case QA was testing channel +switching. + +## Why is a macOS Framework the best solution to store the accepted MAR update channels? + +Apple has started strengthening code signature checks and the requirements on +developers such as ourselves on how their apps are signed. In particular, +most files in the .app bundle are now included in signature verifications. + +A macOS Framework is the ideal solution to store the accepted MAR update +channels because Frameworks are the only component within a .app bundle that can +be replaced without invalidating the code signature on the .app bundle, as long +as both the previous and the new Framework are signed. diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h new file mode 100644 index 0000000000..65a7ba3e00 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef UpdateSettings_h_ +#define UpdateSettings_h_ + +#import + +extern "C" { + +// Returns the accepted MAR channels, as an autoreleased string. +extern NSString* UpdateSettingsGetAcceptedMARChannels(void) + __attribute__((weak_import)) __attribute__((visibility("default"))); +} + +#endif // UpdateSettings_h_ diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm new file mode 100644 index 0000000000..2c39f13f3b --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "UpdateSettings.h" + +#include "mozilla/HelperMacros.h" + +NSString* UpdateSettingsGetAcceptedMARChannels(void) { + return + [NSString stringWithFormat:@"[Settings]\nACCEPTED_MAR_CHANNEL_IDS=%s\n", + ACCEPTED_MAR_CHANNEL_IDS]; +} diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build new file mode 100644 index 0000000000..67de1d68f7 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build @@ -0,0 +1,24 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Framework("UpdateSettings") + +if CONFIG["ACCEPTED_MAR_CHANNEL_IDS"]: + DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '"%s"' % CONFIG["ACCEPTED_MAR_CHANNEL_IDS"] +else: + DEFINES["ACCEPTED_MAR_CHANNEL_IDS"] = '""' + +EXPORTS += [ + "UpdateSettings.h", +] + +UNIFIED_SOURCES += [ + "UpdateSettings.mm", +] + +OS_LIBS += [ + "-framework Foundation", +] diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h new file mode 100644 index 0000000000..5964d9fb18 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef UpdateSettingsUtil_h_ +#define UpdateSettingsUtil_h_ + +#include +#include + +class UpdateSettingsUtil { + public: + static std::optional GetAcceptedMARChannelsValue(); +}; + +#endif // UpdateSettingsUtil_h_ diff --git a/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm new file mode 100644 index 0000000000..6555fd1350 --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm @@ -0,0 +1,21 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: + * 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#import "UpdateSettings/UpdateSettings.h" + +#include "UpdateSettingsUtil.h" + +/* static */ +std::optional UpdateSettingsUtil::GetAcceptedMARChannelsValue() { + // `UpdateSettingsGetAcceptedMARChannels` is resolved at runtime and requires + // the UpdateSettings framework to be loaded. + if (UpdateSettingsGetAcceptedMARChannels) { + NSString* marChannels = UpdateSettingsGetAcceptedMARChannels(); + return [marChannels UTF8String]; + } + return {}; +} diff --git a/toolkit/mozapps/update/updater/macos-frameworks/moz.build b/toolkit/mozapps/update/updater/macos-frameworks/moz.build new file mode 100644 index 0000000000..19fa11942e --- /dev/null +++ b/toolkit/mozapps/update/updater/macos-frameworks/moz.build @@ -0,0 +1,18 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("Toolkit", "Application Update") + +DIRS += ["UpdateSettings", "UpdateSettings-xpcshell", "UpdateSettings-WrongChannel"] + +EXPORTS += [ + "UpdateSettingsUtil.h", +] + +UNIFIED_SOURCES += [ + "UpdateSettingsUtil.mm", +] diff --git a/toolkit/mozapps/update/updater/moz.build b/toolkit/mozapps/update/updater/moz.build index eede9cd723..9620dde22c 100644 --- a/toolkit/mozapps/update/updater/moz.build +++ b/toolkit/mozapps/update/updater/moz.build @@ -26,6 +26,9 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": "__launchd_plist", SRCDIR + "/Launchd.plist", ] + DIRS += [ + "macos-frameworks", + ] GENERATED_FILES = [ "dep1Cert.h", diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build index fe0b4a85fa..6c6d0adf6f 100644 --- a/toolkit/mozapps/update/updater/updater-common.build +++ b/toolkit/mozapps/update/updater/updater-common.build @@ -22,6 +22,17 @@ if CONFIG["MOZ_VERIFY_MAR_SIGNATURE"]: "verifymar", ] + if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa": + srcs += [ + "macos-frameworks/UpdateSettingsUtil.mm", + ] + USE_LIBS += [ + "UpdateSettings", + ] + LDFLAGS += [ + "-Wl,-rpath,@executable_path/../Frameworks/UpdateSettings.framework" + ] + if CONFIG["OS_ARCH"] == "WINNT": have_progressui = 1 srcs += [ @@ -114,7 +125,7 @@ if CONFIG["MOZ_TSAN"]: DEFINES["SPRINTF_H_USES_VSNPRINTF"] = True DEFINES["NS_NO_XPCOM"] = True DisableStlWrapping() -for var in ("MAR_CHANNEL_ID", "MOZ_APP_VERSION"): +for var in ("MAR_CHANNEL_ID", "MOZ_APP_VERSION", "ACCEPTED_MAR_CHANNEL_IDS"): DEFINES[var] = '"%s"' % CONFIG[var] LOCAL_INCLUDES += [ diff --git a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in index 533533c4d9..7ef90f9ce5 100644 --- a/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in +++ b/toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in @@ -30,6 +30,10 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) $(call py_action,preprocessor updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/../macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Resources/English.lproj/InfoPlist.strings) $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/MacOS $(NSINSTALL) $(FINAL_TARGET)/updater-xpcshell $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/MacOS + $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks + $(NSINSTALL) -D $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework + cp $(XPCSHELLTESTDIR)/UpdateSettings-xpcshell $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework/UpdateSettings + $(NSINSTALL) $(srcdir)/../macos-frameworks/UpdateSettings/Info.plist $(XPCSHELLTESTDIR)/data/updater-xpcshell.app/Contents/Frameworks/UpdateSettings.framework/Resources rm -Rf $(XPCSHELLTESTDIR)/data/updater.app mv $(XPCSHELLTESTDIR)/data/updater-xpcshell.app $(XPCSHELLTESTDIR)/data/updater.app mv $(XPCSHELLTESTDIR)/data/updater.app/Contents/MacOS/updater-xpcshell $(XPCSHELLTESTDIR)/data/updater.app/Contents/MacOS/org.mozilla.updater diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 6b01450b31..084945dc44 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -46,6 +46,7 @@ #include "updatecommon.h" #ifdef XP_MACOSX +# include "UpdateSettingsUtil.h" # include "updaterfileutils_osx.h" #endif // XP_MACOSX @@ -75,13 +76,16 @@ bool IsOwnedByGroupAdmin(const char* aAppBundle); bool IsRecursivelyWritable(const char* aPath); void LaunchChild(int argc, const char** argv); void LaunchMacPostProcess(const char* aAppBundle); -bool ObtainUpdaterArguments(int* argc, char*** argv); -bool ServeElevatedUpdate(int argc, const char** argv); +bool ObtainUpdaterArguments(int* aArgc, char*** aArgv, + MARChannelStringTable* aMARStrings); +bool ServeElevatedUpdate(int aArgc, const char** aArgv, + const char* aMARChannelID); void SetGroupOwnershipAndPermissions(const char* aAppBundle); bool PerformInstallationFromDMG(int argc, char** argv); struct UpdateServerThreadArgs { int argc; const NS_tchar** argv; + const char* marChannelID; }; #endif @@ -187,15 +191,6 @@ class AutoFile { } }; -struct MARChannelStringTable { - MARChannelStringTable() { - MARChannelID = mozilla::MakeUnique(1); - MARChannelID[0] = '\0'; - } - - mozilla::UniquePtr MARChannelID; -}; - //----------------------------------------------------------------------------- #ifdef XP_MACOSX @@ -292,6 +287,10 @@ static bool sUsingService = false; // that iteration will run with `gIsElevated == true`. static bool gIsElevated = false; +// This string contains the MAR channel IDs that are later extracted by one of +// the `ReadMARChannelIDsFrom` variants. +static MARChannelStringTable gMARStrings; + // Normally, we run updates as a result of user action (the user started Firefox // or clicked a "Restart to Update" button). But there are some cases when // we are not: @@ -2659,23 +2658,67 @@ static void WaitForServiceFinishThread(void* param) { #endif #ifdef MOZ_VERIFY_MAR_SIGNATURE +# ifndef XP_MACOSX /** * This function reads in the ACCEPTED_MAR_CHANNEL_IDS from update-settings.ini * - * @param path The path to the ini file that is to be read - * @param results A pointer to the location to store the read strings + * @param aPath The path to the ini file that is to be read + * @param aResults A pointer to the location to store the read strings + * @return OK on success + */ +static int ReadMARChannelIDsFromPath(const NS_tchar* aPath, + MARChannelStringTable* aResults) { + const unsigned int kNumStrings = 1; + const char* kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0"; + return ReadStrings(aPath, kUpdaterKeys, kNumStrings, &aResults->MARChannelID, + "Settings"); +} +# else // XP_MACOSX +/** + * This function reads in the ACCEPTED_MAR_CHANNEL_IDS from a string buffer. + * + * @param aChannels A string buffer containing the MAR channel(s). + * @param aResults A pointer to the location to store the read strings. * @return OK on success */ -static int ReadMARChannelIDs(const NS_tchar* path, - MARChannelStringTable* results) { +static int ReadMARChannelIDsFromBuffer(char* aChannels, + MARChannelStringTable* aResults) { const unsigned int kNumStrings = 1; const char* kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0"; - int result = ReadStrings(path, kUpdaterKeys, kNumStrings, - &results->MARChannelID, "Settings"); + return ReadStringsFromBuffer(aChannels, kUpdaterKeys, kNumStrings, + &aResults->MARChannelID, "Settings"); +} +# endif // XP_MACOSX - return result; +/** + * This function reads in the `ACCEPTED_MAR_CHANNEL_IDS` from the appropriate + * (platform-dependent) source and populates `gMARStrings`. + * + * @return + * `OK` on success, `UPDATE_SETTINGS_FILE_CHANNEL` on failure. + */ +static int PopulategMARStrings() { + int rv = UPDATE_SETTINGS_FILE_CHANNEL; +# ifdef XP_MACOSX + if (gIsElevated) { + // An elevated update process will have already populated gMARStrings when + // it connected to the unelevated update process to obtain the command line + // args. See `ObtainUpdaterArguments`. + rv = OK; + } else if (auto marChannels = + UpdateSettingsUtil::GetAcceptedMARChannelsValue()) { + rv = ReadMARChannelIDsFromBuffer(marChannels->data(), &gMARStrings); + } +# else + NS_tchar updateSettingsPath[MAXPATHLEN]; + NS_tsnprintf(updateSettingsPath, + sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), + NS_T("%s/update-settings.ini"), gInstallDirPath); + rv = ReadMARChannelIDsFromPath(updateSettingsPath, &gMARStrings); +# endif + return rv == OK ? OK : UPDATE_SETTINGS_FILE_CHANNEL; } -#endif +#endif // MOZ_VERIFY_MAR_SIGNATURE static int GetUpdateFileName(NS_tchar* fileName, int maxChars) { NS_tsnprintf(fileName, maxChars, NS_T("%s/update.mar"), gPatchDirPath); @@ -2700,21 +2743,10 @@ static void UpdateThreadFunc(void* param) { } if (rv == OK) { - NS_tchar updateSettingsPath[MAXPATHLEN]; - NS_tsnprintf(updateSettingsPath, - sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]), -# ifdef XP_MACOSX - NS_T("%s/Contents/Resources/update-settings.ini"), -# else - NS_T("%s/update-settings.ini"), -# endif - gInstallDirPath); - MARChannelStringTable MARStrings; - if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) { - rv = UPDATE_SETTINGS_FILE_CHANNEL; - } else { + rv = PopulategMARStrings(); + if (rv == OK) { rv = gArchiveReader.VerifyProductInformation( - MARStrings.MARChannelID.get(), MOZ_APP_VERSION); + gMARStrings.MARChannelID.get(), MOZ_APP_VERSION); } } #endif @@ -2819,7 +2851,8 @@ static void UpdateThreadFunc(void* param) { #ifdef XP_MACOSX static void ServeElevatedUpdateThreadFunc(void* param) { UpdateServerThreadArgs* threadArgs = (UpdateServerThreadArgs*)param; - gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv); + gSucceeded = ServeElevatedUpdate(threadArgs->argc, threadArgs->argv, + threadArgs->marChannelID); if (!gSucceeded) { WriteStatusFile(ELEVATION_CANCELED); } @@ -2955,6 +2988,21 @@ int NS_main(int argc, NS_tchar** argv) { putenv(const_cast("MOZ_USING_SERVICE=")); #endif + if (argc == 2 && NS_tstrcmp(argv[1], NS_T("--channels-allowed")) == 0) { +#ifdef MOZ_VERIFY_MAR_SIGNATURE + int rv = PopulategMARStrings(); + if (rv == OK) { + printf("Channels Allowed: %s\n", gMARStrings.MARChannelID.get()); + return 0; + } + printf("Error: %d\n", rv); + return 1; +#else + printf("Not Applicable: No support for signature verification\n"); + return 0; +#endif + } + // The callback is the remaining arguments starting at callbackIndex. // The argument specified by callbackIndex is the callback executable and the // argument prior to callbackIndex is the working directory. @@ -2977,7 +3025,7 @@ int NS_main(int argc, NS_tchar** argv) { strstr(argv[0], "/Library/PrivilegedHelperTools/org.mozilla.updater") != 0; if (isElevated) { - if (!ObtainUpdaterArguments(&argc, &argv)) { + if (!ObtainUpdaterArguments(&argc, &argv, &gMARStrings)) { // Won't actually get here because ObtainUpdaterArguments will terminate // the current process on failure. return 1; @@ -3288,6 +3336,7 @@ int NS_main(int argc, NS_tchar** argv) { UpdateServerThreadArgs threadArgs; threadArgs.argc = argc; threadArgs.argv = const_cast(argv); + threadArgs.marChannelID = gMARStrings.MARChannelID.get(); Thread t1; if (t1.Run(ServeElevatedUpdateThreadFunc, &threadArgs) == 0) { @@ -4179,7 +4228,7 @@ int NS_main(int argc, NS_tchar** argv) { // Run update process on a background thread. ShowProgressUI may return // before QuitProgressUI has been called, so wait for UpdateThreadFunc to // terminate. Avoid showing the progress UI when staging an update, or if - // this is an elevated process on OSX. + // this is an elevated process on macOS. Thread t; if (t.Run(UpdateThreadFunc, nullptr) == 0) { if (!sStagedUpdate && !sReplaceRequest && !sUpdateSilently -- cgit v1.2.3