Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Service/Sources/EDOHostService+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (BOOL)isObjectAliveWithPort:(EDOServicePort *)port remoteAddress:(EDOPointerType)remoteAddress;

/**
* Resolves the local object that this service has previously vended for the given address.
*
* The address is treated purely as an opaque lookup key into the service's tracked-object table; it
* is never dereferenced. This is the safe replacement for casting a wire-supplied @c EDOPointerType
* back to @c id.
*
* @param remoteAddress The address that was previously returned to the client in an @c EDOObject.
* @return The tracked local object, or @c nil if @c remoteAddress is not known to this service.
*/
- (nullable id)localObjectForAddress:(EDOPointerType)remoteAddress;

/**
* Removes an EDOObject with the specified address in the host cache.
*
Expand Down
12 changes: 12 additions & 0 deletions Service/Sources/EDOHostService.m
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,18 @@ - (EDOObject *)distantObjectForLocalObject:(id)object hostPort:(EDOHostPort *)ho
return [EDOObject edo_remoteProxyFromUnderlyingObject:object withPort:port];
}
}
- (id)localObjectForAddress:(EDOPointerType)remoteAddress {
// ivar is used directly here to avoid the service lazily creating the listen port.
if (_rootLocalObject && (EDOPointerType)_rootLocalObject == remoteAddress) {
return _rootLocalObject;
}
NSNumber *edoKey = [NSNumber numberWithLongLong:remoteAddress];
__block id object;
dispatch_sync(_localObjectsSyncQueue, ^{
object = self.localObjects[edoKey];
});
return object;
}

- (BOOL)isObjectAliveWithPort:(EDOServicePort *)port remoteAddress:(EDOPointerType)remoteAddress {
if (![_port match:port]) {
Expand Down
19 changes: 18 additions & 1 deletion Service/Sources/EDOInvocationMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,24 @@ + (EDORequestHandler)requestHandler {
NSAssert([request isKindOfClass:[EDOInvocationRequest class]],
@"EDOInvocationRequest is expected.");
EDOHostPort *hostPort = request.hostPort;
id target = (__bridge id)(void *)request.target;
// The target address arrives off the wire as a raw 64-bit integer. It must NOT be cast to id
// until the service has confirmed it is an object it previously vended; otherwise an attacker
// can supply an arbitrary pointer and obtain a wild dereference / objc_msgSend on a fake isa.
id target = [service localObjectForAddress:request.target];
if (!target) {
NSString *reason =
[NSString stringWithFormat:@"The target address (%llx) is not tracked by this service.",
request.target];
EDORemoteException *remoteException =
[[EDORemoteException alloc] initWithName:EDOServiceGenericException
reason:reason
callStackSymbols:@[]];
return [EDOInvocationResponse responseWithReturnValue:nil
exception:remoteException
outValues:nil
forRequest:request
targetClass:Nil];
}
SEL sel = NSSelectorFromString(request.selectorName);

EDOBoxedValueType *returnValue;
Expand Down
8 changes: 7 additions & 1 deletion Service/Sources/EDOMethodSignatureMessage.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#import "Service/Sources/EDOMethodSignatureMessage.h"

#import "Service/Sources/EDOHostService+Private.h"
#import "Service/Sources/EDOHostService.h"
#import "Service/Sources/EDOMessage.h"
#import "Service/Sources/EDOObject+Private.h"
Expand Down Expand Up @@ -97,7 +98,12 @@ + (EDORequestHandler)requestHandler {
}

EDOMethodSignatureRequest *methodRequest = (EDOMethodSignatureRequest *)request;
id object = (__bridge Class)(void *)methodRequest.object;
id object = [service localObjectForAddress:methodRequest.object];
if (!object) {
// If the object is not found, we can't get method signature.
// Returning nil signature will eventually result in an exception at the client.
return [[EDOMethodSignatureResponse alloc] initWithSignature:nil forRequest:request];
}
SEL sel = NSSelectorFromString(methodRequest.selectorName);

NSMethodSignature *signature = EDOGetMethodSignature(object, sel);
Expand Down
9 changes: 8 additions & 1 deletion Service/Tests/UnitTests/EDOMessageTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,13 @@ - (void)testClassMethodInvocationHandler {
EDOTestDummy *dummyLocal = [[EDOTestDummy alloc] init];
[self edo_createQueueAndServiceWithRootObject:dummyLocal
block:^(EDOHostService *service) {
// Simulate the client asking for the class first to
// register it securely.
EDOServiceRequest *classRequest = [EDOClassRequest
requestWithClassName:@"EDOTestDummy"
hostPort:service.port.hostPort];
EDOClassRequest.requestHandler(classRequest, service);

EDOInvocationResponse *response = [self
edo_runInvocationWithService:service
target:[dummyLocal class]
Expand Down Expand Up @@ -507,7 +514,7 @@ - (void)testMethodSignatureRequestHandler {
void *remoteAddress = (__bridge void *)dummyLocal;

EDOHostService *service = [EDOHostService serviceWithPort:0
rootObject:self
rootObject:dummyLocal
queue:dispatch_get_main_queue()];

[EDOTestDummy enumerateSelector:^(SEL selector) {
Expand Down