Skip to content

Commit

Permalink
Merge pull request from GHSA-9jgj-jfwg-99fv
Browse files Browse the repository at this point in the history
Harden NSConnection security in handling third-party connections
  • Loading branch information
ychin authored Sep 12, 2023
2 parents 3927f58 + 0380d81 commit 399b43e
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 28 deletions.
36 changes: 26 additions & 10 deletions src/MacVim/MMAppController.m
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,9 @@ - (id)init
// unlikely to fix it, we graciously give them the default connection.)
connection = [[NSConnection alloc] initWithReceivePort:[NSPort port]
sendPort:nil];
[connection setRootObject:self];
NSProtocolChecker *rootObject = [NSProtocolChecker protocolCheckerWithTarget:self
protocol:@protocol(MMAppProtocol)];
[connection setRootObject:rootObject];
[connection setRequestTimeout:MMRequestTimeout];
[connection setReplyTimeout:MMReplyTimeout];

Expand All @@ -315,6 +317,20 @@ - (id)init
if (![connection registerName:name]) {
ASLogCrit(@"Failed to register connection with name '%@'", name);
[connection release]; connection = nil;

NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:NSLocalizedString(@"OK",
@"Dialog button")];
[alert setMessageText:NSLocalizedString(@"MacVim cannot be opened",
@"MacVim cannot be opened, title")];
[alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(
@"MacVim could not set up its connection. It's likely you already have MacVim opened elsewhere.",
@"MacVim already opened, text")]];
[alert setAlertStyle:NSAlertStyleCritical];
[alert runModal];
[alert release];

[[NSApplication sharedApplication] terminate:nil];
}

// Register help search handler to support search Vim docs via the Help menu
Expand Down Expand Up @@ -859,7 +875,7 @@ - (NSMenuItem *)appMenuItemTemplate

- (void)removeVimController:(id)controller
{
ASLogDebug(@"Remove Vim controller pid=%d id=%d (processingFlag=%d)",
ASLogDebug(@"Remove Vim controller pid=%d id=%lu (processingFlag=%d)",
[controller pid], [controller vimControllerId], processingFlag);

NSUInteger idx = [vimControllers indexOfObject:controller];
Expand Down Expand Up @@ -1540,7 +1556,7 @@ - (MMVimController *)keyVimController
return nil;
}

- (unsigned)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid
- (unsigned long)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid
{
ASLogDebug(@"pid=%d", pid);

Expand Down Expand Up @@ -1570,21 +1586,21 @@ - (unsigned)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid
}

- (oneway void)processInput:(in bycopy NSArray *)queue
forIdentifier:(unsigned)identifier
forIdentifier:(unsigned long)identifier
{
// NOTE: Input is not handled immediately since this is a distributed
// object call and as such can arrive at unpredictable times. Instead,
// queue the input and process it when the run loop is updated.

if (!(queue && identifier)) {
ASLogWarn(@"Bad input for identifier=%d", identifier);
ASLogWarn(@"Bad input for identifier=%lu", identifier);
return;
}

ASLogDebug(@"QUEUE for identifier=%d: <<< %@>>>", identifier,
ASLogDebug(@"QUEUE for identifier=%lu: <<< %@>>>", identifier,
debugStringForMessageQueue(queue));

NSNumber *key = [NSNumber numberWithUnsignedInt:identifier];
NSNumber *key = [NSNumber numberWithUnsignedLong:identifier];
NSArray *q = [inputQueues objectForKey:key];
if (q) {
q = [q arrayByAddingObjectsFromArray:queue];
Expand Down Expand Up @@ -2715,7 +2731,7 @@ - (void)processInputQueues:(id)sender
NSEnumerator *e = [queues keyEnumerator];
NSNumber *key;
while ((key = [e nextObject])) {
unsigned ukey = [key unsignedIntValue];
unsigned long ukey = [key unsignedLongValue];
int i = 0, count = [vimControllers count];
for (i = 0; i < count; ++i) {
MMVimController *vc = [vimControllers objectAtIndex:i];
Expand All @@ -2737,7 +2753,7 @@ - (void)processInputQueues:(id)sender
}

if (i == count) {
ASLogWarn(@"No Vim controller for identifier=%d", ukey);
ASLogWarn(@"No Vim controller for identifier=%lu", ukey);
}
}

Expand All @@ -2758,7 +2774,7 @@ - (void)processInputQueues:(id)sender

- (void)addVimController:(MMVimController *)vc
{
ASLogDebug(@"Add Vim controller pid=%d id=%d",
ASLogDebug(@"Add Vim controller pid=%d id=%lu",
[vc pid], [vc vimControllerId]);

int pid = [vc pid];
Expand Down
2 changes: 1 addition & 1 deletion src/MacVim/MMBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
NSConnection *connection;
NSConnection *vimServerConnection;
id appProxy;
unsigned identifier;
unsigned long identifier;
NSDictionary *colorDict;
NSDictionary *sysColorDict;
NSDictionary *actionDict;
Expand Down
4 changes: 2 additions & 2 deletions src/MacVim/MMVimController.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#endif
>
{
unsigned identifier;
unsigned long identifier;
BOOL isInitialized;
MMWindowController *windowController;
id backendProxy;
Expand All @@ -58,7 +58,7 @@

- (id)initWithBackend:(id)backend pid:(int)processIdentifier;
- (void)uninitialize;
- (unsigned)vimControllerId;
- (unsigned long)vimControllerId;
- (id)backendProxy;
- (int)pid;
- (void)setServerName:(NSString *)name;
Expand Down
31 changes: 18 additions & 13 deletions src/MacVim/MMVimController.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@
// Timeout used for setDialogReturn:.
static NSTimeInterval MMSetDialogReturnTimeout = 1.0;

static unsigned identifierCounter = 1;

static BOOL isUnsafeMessage(int msgid);


Expand Down Expand Up @@ -168,8 +166,15 @@ - (id)initWithBackend:(id)backend pid:(int)processIdentifier
if (!(self = [super init]))
return nil;

// TODO: Come up with a better way of creating an identifier.
identifier = identifierCounter++;
// Use a random identifier. Currently, MMBackend connects using a public
// NSConnection, which has security implications. Using random identifiers
// make it much harder for third-party attacker to spoof.
int secSuccess = SecRandomCopyBytes(kSecRandomDefault, sizeof(identifier), &identifier);
if (secSuccess != errSecSuccess) {
// Don't know what concrete reasons secure random would fail, but just
// as a failsafe, use a less secure option.
identifier = ((unsigned long)arc4random()) << 32 | (unsigned long)arc4random();
}

windowController =
[[MMWindowController alloc] initWithVimController:self];
Expand Down Expand Up @@ -257,7 +262,7 @@ - (void)uninitialize
isInitialized = NO;
}

- (unsigned)vimControllerId
- (unsigned long)vimControllerId
{
return identifier;
}
Expand Down Expand Up @@ -436,7 +441,7 @@ - (void)sendMessage:(int)msgid data:(NSData *)data
[backendProxy processInput:msgid data:data];
}
@catch (NSException *ex) {
ASLogDebug(@"processInput:data: failed: pid=%d id=%d msg=%s reason=%@",
ASLogDebug(@"processInput:data: failed: pid=%d id=%lu msg=%s reason=%@",
pid, identifier, MMVimMsgIDStrings[msgid], ex);
}
}
Expand Down Expand Up @@ -468,7 +473,7 @@ - (BOOL)sendMessageNow:(int)msgid data:(NSData *)data
}
@catch (NSException *ex) {
sendOk = NO;
ASLogDebug(@"processInput:data: failed: pid=%d id=%d msg=%s reason=%@",
ASLogDebug(@"processInput:data: failed: pid=%d id=%lu msg=%s reason=%@",
pid, identifier, MMVimMsgIDStrings[msgid], ex);
}
@finally {
Expand Down Expand Up @@ -500,7 +505,7 @@ - (NSString *)evaluateVimExpression:(NSString *)expr
ASLogDebug(@"eval(%@)=%@", expr, eval);
}
@catch (NSException *ex) {
ASLogDebug(@"evaluateExpression: failed: pid=%d id=%d reason=%@",
ASLogDebug(@"evaluateExpression: failed: pid=%d id=%lu reason=%@",
pid, identifier, ex);
}

Expand All @@ -517,7 +522,7 @@ - (id)evaluateVimExpressionCocoa:(NSString *)expr
errorString:errstr];
ASLogDebug(@"eval(%@)=%@", expr, eval);
} @catch (NSException *ex) {
ASLogDebug(@"evaluateExpressionCocoa: failed: pid=%d id=%d reason=%@",
ASLogDebug(@"evaluateExpressionCocoa: failed: pid=%d id=%lu reason=%@",
pid, identifier, ex);
*errstr = [ex reason];
}
Expand Down Expand Up @@ -556,7 +561,7 @@ - (void)processInputQueue:(NSArray *)queue
[windowController processInputQueueDidFinish];
}
@catch (NSException *ex) {
ASLogDebug(@"Exception: pid=%d id=%d reason=%@", pid, identifier, ex);
ASLogDebug(@"Exception: pid=%d id=%lu reason=%@", pid, identifier, ex);
}
}

Expand Down Expand Up @@ -1275,7 +1280,7 @@ - (void)savePanelDidEnd:(NSSavePanel *)panel code:(int)code
noteNewRecentFilePath:path];
}
@catch (NSException *ex) {
ASLogDebug(@"Exception: pid=%d id=%d reason=%@", pid, identifier, ex);
ASLogDebug(@"Exception: pid=%d id=%lu reason=%@", pid, identifier, ex);
}
@finally {
[conn setRequestTimeout:oldTimeout];
Expand Down Expand Up @@ -1308,7 +1313,7 @@ - (void)alertDidEnd:(MMAlert *)alert code:(int)code context:(void *)context
[backendProxy setDialogReturn:ret];
}
@catch (NSException *ex) {
ASLogDebug(@"setDialogReturn: failed: pid=%d id=%d reason=%@",
ASLogDebug(@"setDialogReturn: failed: pid=%d id=%lu reason=%@",
pid, identifier, ex);
}
}
Expand Down Expand Up @@ -2089,7 +2094,7 @@ - (void)connectionDidDie:(NSNotification *)notification

- (void)scheduleClose
{
ASLogDebug(@"pid=%d id=%d", pid, identifier);
ASLogDebug(@"pid=%d id=%lu", pid, identifier);

// NOTE! This message can arrive at pretty much anytime, e.g. while
// the run loop is the 'event tracking' mode. This means that Cocoa may
Expand Down
4 changes: 2 additions & 2 deletions src/MacVim/MacVim.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ typedef NSString* NSAttributedStringKey;
// connectBackend:pid: and processInput:forIdentifier:).
//
@protocol MMAppProtocol
- (unsigned)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid;
- (unsigned long)connectBackend:(byref in id <MMBackendProtocol>)proxy pid:(int)pid;
- (oneway void)processInput:(in bycopy NSArray *)queue
forIdentifier:(unsigned)identifier;
forIdentifier:(unsigned long)identifier;
- (NSArray *)serverList;
@end

Expand Down
4 changes: 4 additions & 0 deletions src/MacVim/MacVim.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
909894382A56EB1E007B84A3 /* WhatsNew.xib in Resources */ = {isa = PBXBuildFile; fileRef = 909894362A56EB1E007B84A3 /* WhatsNew.xib */; };
9098943C2A56ECF6007B84A3 /* MMWhatsNewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9098943B2A56ECF6007B84A3 /* MMWhatsNewController.m */; };
90A33BEA28D563DF003A2E2F /* MMSparkle2Delegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 90A33BE928D563DF003A2E2F /* MMSparkle2Delegate.m */; };
90AF83AB2A8C37F70046DA2E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90AF83A92A8C37F70046DA2E /* Security.framework */; };
90B9877D2A579F9500FC95D6 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90B9877B2A579F9500FC95D6 /* WebKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -423,6 +424,7 @@
90AF83B62AA15C660046DA2E /* nv_cmds.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = nv_cmds.h; path = ../nv_cmds.h; sourceTree = "<group>"; };
90AF83B72AA15C660046DA2E /* vim9cmds.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = vim9cmds.c; path = ../vim9cmds.c; sourceTree = "<group>"; };
90AF83B82AA15C660046DA2E /* termdefs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = termdefs.h; path = ../termdefs.h; sourceTree = "<group>"; };
90AF83A92A8C37F70046DA2E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
90B9877B2A579F9500FC95D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
90F84F1E2521F2270000268B /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/MainMenu.strings; sourceTree = "<group>"; };
90F84F232521F6480000268B /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/MainMenu.strings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -462,6 +464,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
90AF83AB2A8C37F70046DA2E /* Security.framework in Frameworks */,
90B9877D2A579F9500FC95D6 /* WebKit.framework in Frameworks */,
1DFE25A50C527BC4003000F7 /* PSMTabBarControl.framework in Frameworks */,
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
Expand Down Expand Up @@ -650,6 +653,7 @@
29B97323FDCFA39411CA2CEA /* Frameworks */ = {
isa = PBXGroup;
children = (
90AF83A92A8C37F70046DA2E /* Security.framework */,
90B9877B2A579F9500FC95D6 /* WebKit.framework */,
52A364721C4A5789005757EC /* Sparkle.framework */,
1D8B5A52104AF9FF002E59D5 /* Carbon.framework */,
Expand Down

0 comments on commit 399b43e

Please sign in to comment.