Skip to content

Commit

Permalink
Randomize the download archive name the installer extracts/executes (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
zorgiepoo committed Jun 16, 2024
1 parent 37d1fee commit 007e9ae
Showing 1 changed file with 30 additions and 2 deletions.
32 changes: 30 additions & 2 deletions Autoupdate/AppInstaller.m
Original file line number Diff line number Diff line change
Expand Up @@ -415,13 +415,41 @@ - (void)handleMessageWithIdentifier:(int32_t)identifier data:(NSData *)data
SULog(SULogLevelError, @"Error: bookmark data for update download is stale.. but still continuing.");
}

NSString *downloadName = downloadURL.lastPathComponent;
if (downloadName == nil) {
NSString *originalDownloadName = downloadURL.lastPathComponent;
if (originalDownloadName == nil) {
[self cleanupAndExitWithStatus:EXIT_FAILURE error:[NSError errorWithDomain:SUSparkleErrorDomain code:SPUInstallerError userInfo:@{ NSLocalizedDescriptionKey: @"Error: Failed to retrieve download name from download URL" }]];

return;
}

// Randomize the download name if possible
// This adds better security if there are any vulnerabilities in extracting/executing archives
// which allow writing in unexpected locations. For zip/tar/dmg archives we may also extract them before
// performing signing validation (due to key rotation).
NSString *downloadName;
NSString *randomizedUUIDString = [[NSUUID UUID] UUIDString];
if (randomizedUUIDString != nil) {
// Find the real path extension of the download name
// We cannot use -[NSString pathExtension] because it may not give us the full path extension
// E.g. for "foo.tar.xz" we need "tar.xz", not "xz"
NSString *downloadPathExtension;
NSRange pathExtensionDelimiterRange = [originalDownloadName rangeOfString:@"."];
if (pathExtensionDelimiterRange.location == NSNotFound) {
downloadPathExtension = @"";
} else {
downloadPathExtension = [originalDownloadName substringFromIndex:pathExtensionDelimiterRange.location + 1];
}

NSString *randomizedDownloadName = [randomizedUUIDString stringByAppendingPathExtension:downloadPathExtension];
if (randomizedDownloadName != nil) {
downloadName = randomizedDownloadName;
} else {
downloadName = originalDownloadName;
}
} else {
downloadName = originalDownloadName;
}

// Move the download archive to somewhere where probably only we will be touching it
// This prevents eg: if a bug exists in the updater that removes files we are trying to install
// When this tool is ran as root, we are moving it into a directory that only root will have access to
Expand Down

0 comments on commit 007e9ae

Please sign in to comment.