From c78f7a01ce2269a791220527ae8c59d95b3de22e Mon Sep 17 00:00:00 2001 From: eDO Team Date: Mon, 10 Aug 2026 15:12:33 -0700 Subject: [PATCH] Fix EDOHostNamingService registry poisoning vulnerability using a Read-Only Proxy. PiperOrigin-RevId: 962393451 --- Service/Sources/EDOHostNamingService.m | 34 ++++++++++++++++++- .../UnitTests/EDOHostNamingServiceTest.m | 31 +++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/Service/Sources/EDOHostNamingService.m b/Service/Sources/EDOHostNamingService.m index 0ba45ab8..8e28cd3e 100644 --- a/Service/Sources/EDOHostNamingService.m +++ b/Service/Sources/EDOHostNamingService.m @@ -22,6 +22,36 @@ #import "Service/Sources/EDOHostService.h" #import "Service/Sources/EDOServicePort.h" +@interface EDOHostNamingServiceProxy : NSObject +- (instancetype)initWithNamingService:(EDOHostNamingService *)namingService; +@end + +@implementation EDOHostNamingServiceProxy { + __weak EDOHostNamingService *_namingService; +} + ++ (BOOL)accessInstanceVariablesDirectly { + return NO; +} + +- (instancetype)initWithNamingService:(EDOHostNamingService *)namingService { + self = [super init]; + if (self) { + _namingService = namingService; + } + return self; +} + +- (UInt16)portForServiceWithName:(NSString *)name { + return [_namingService portForServiceWithName:name]; +} + +- (UInt16)serviceConnectionPort { + return _namingService.serviceConnectionPort; +} + +@end + @implementation EDOHostNamingService { // The mapping from service name to host service port. NSMutableDictionary *_servicePortsInfo; @@ -84,8 +114,10 @@ - (BOOL)start { if (self->_service) { return; } + EDOHostNamingServiceProxy *proxy = + [[EDOHostNamingServiceProxy alloc] initWithNamingService:self]; self->_service = [EDOHostService serviceWithPort:EDOHostNamingService.namingServerPort - rootObject:self + rootObject:proxy queue:self->_namingServiceEventQueue]; result = self->_service.port.hostPort.port != 0; }); diff --git a/Service/Tests/UnitTests/EDOHostNamingServiceTest.m b/Service/Tests/UnitTests/EDOHostNamingServiceTest.m index b37ddf61..dbb6669d 100644 --- a/Service/Tests/UnitTests/EDOHostNamingServiceTest.m +++ b/Service/Tests/UnitTests/EDOHostNamingServiceTest.m @@ -55,6 +55,37 @@ - (void)testStartEDONamingServiceObject { XCTAssertEqual([namingService portForServiceWithName:kDummyServiceName], kDummyServicePort); } +/** Verifies that remote invocation of private mutators throws an exception. */ +- (void)testRemoteInvocationOfPrivateMutatorThrowsException { + [EDOHostNamingService.sharedService start]; + id remoteNamingService = + [EDOClientService rootObjectWithPort:EDOHostNamingService.namingServerPort]; + + // addServicePort: is a private mutator and should not be available remotely when using proxy. + EDOServicePort *dummyPort = [EDOServicePort servicePortWithPort:12345 + serviceName:@"com.google.poison"]; + XCTAssertThrows([remoteNamingService addServicePort:dummyPort]); +} + +/** Verifies that remote invocation of stop throws an exception. */ +- (void)testRemoteInvocationOfStopThrowsException { + [EDOHostNamingService.sharedService start]; + id remoteNamingService = + [EDOClientService rootObjectWithPort:EDOHostNamingService.namingServerPort]; + + // stop is a lifecycle method and should not be available remotely when using proxy. + XCTAssertThrows([remoteNamingService stop]); +} + +/** Verifies that remote invocation of serviceConnectionPort works. */ +- (void)testRemoteInvocationOfServiceConnectionPort { + [EDOHostNamingService.sharedService start]; + id remoteNamingService = + [EDOClientService rootObjectWithPort:EDOHostNamingService.namingServerPort]; + + XCTAssertNotEqual([remoteNamingService serviceConnectionPort], 0); +} + /** * Tests sending object request to the naming service after stopping it, and verifies that * exception happens.