summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/update/updater
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/update/updater')
-rw-r--r--toolkit/mozapps/update/updater/Makefile.in3
-rw-r--r--toolkit/mozapps/update/updater/launchchild_osx.mm56
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-WrongChannel/moz.build18
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings-xpcshell/moz.build18
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/Info.plist24
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/README.md77
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.h17
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/UpdateSettings.mm13
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettings/moz.build24
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.h17
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/UpdateSettingsUtil.mm21
-rw-r--r--toolkit/mozapps/update/updater/macos-frameworks/moz.build18
-rw-r--r--toolkit/mozapps/update/updater/moz.build3
-rw-r--r--toolkit/mozapps/update/updater/updater-common.build13
-rw-r--r--toolkit/mozapps/update/updater/updater-xpcshell/Makefile.in4
-rw-r--r--toolkit/mozapps/update/updater/updater.cpp121
16 files changed, 396 insertions, 51 deletions
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<char[]>(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 @@
+<?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>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>UpdateSettings</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.mozilla.updatesettings</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>UpdateSettings</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+</dict>
+</plist>
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 <Foundation/Foundation.h>
+
+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 <optional>
+#include <string>
+
+class UpdateSettingsUtil {
+ public:
+ static std::optional<std::string> 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<std::string> 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<char[]>(1);
- MARChannelID[0] = '\0';
- }
-
- mozilla::UniquePtr<char[]> 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<char*>("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<const NS_tchar**>(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