Skip to content

Commit

Permalink
Improve input validation of UUIDs on iOS to avoid crashes (#1014, #905)
Browse files Browse the repository at this point in the history
  • Loading branch information
peitschie committed Jul 13, 2024
1 parent 2ebde63 commit bdd6f7e
Showing 1 changed file with 145 additions and 44 deletions.
189 changes: 145 additions & 44 deletions src/ios/BLECentralPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
@interface BLECentralPlugin() {
NSDictionary *bluetoothStates;
}
- (CBPeripheral *)findPeripheralByUUID:(NSString *)uuid;
- (CBPeripheral *)retrievePeripheralWithUUID:(NSString *)uuid;
- (CBPeripheral *)findPeripheralByUUID:(NSUUID *)uuid;
- (CBPeripheral *)retrievePeripheralWithUUID:(NSUUID *)uuid;
- (void)stopScanTimer:(NSTimer *)timer;
@end

Expand Down Expand Up @@ -124,7 +124,11 @@ - (void)connect:(CDVInvokedUrlCommand *)command {
return;
}

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];
if (!peripheral) {
peripheral = [self retrievePeripheralWithUUID:uuid];
Expand Down Expand Up @@ -158,7 +162,10 @@ - (void)autoConnect:(CDVInvokedUrlCommand *)command {
return;
}

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];
if (!peripheral) {
Expand All @@ -184,7 +191,11 @@ - (void)autoConnect:(CDVInvokedUrlCommand *)command {
- (void)disconnect:(CDVInvokedUrlCommand*)command {
NSLog(@"disconnect");

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];

if (!peripheral) {
Expand Down Expand Up @@ -367,7 +378,21 @@ - (void)startScanWithOptions:(CDVInvokedUrlCommand*)command {

discoverPeripheralCallbackId = [command.callbackId copy];
NSArray<NSString *> *serviceUUIDStrings = [command argumentAtIndex:0];
if (serviceUUIDStrings != nil && ![serviceUUIDStrings isKindOfClass:[NSArray class]]) {
NSLog(@"Malformed UUID");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Malformed UUID"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSArray<CBUUID *> *serviceUUIDs = [self uuidStringsToCBUUIDs:serviceUUIDStrings];
if (serviceUUIDs == nil) {
NSLog(@"Malformed UUID");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Malformed UUID"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSDictionary *options = command.arguments[1];

NSMutableDictionary *scanOptions = [NSMutableDictionary new];
Expand Down Expand Up @@ -453,8 +478,11 @@ - (void)onReset {

- (void)readRSSI:(CDVInvokedUrlCommand*)command {
NSLog(@"readRSSI");
NSString *uuid = [command argumentAtIndex:0];

NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];

if (peripheral && peripheral.state == CBPeripheralStateConnected) {
Expand Down Expand Up @@ -482,8 +510,21 @@ - (void)connectedPeripheralsWithServices:(CDVInvokedUrlCommand*)command {
return;
}

NSArray *serviceUUIDStrings = [command argumentAtIndex:0];
NSArray<NSString *> *serviceUUIDStrings = [command argumentAtIndex:0];
if (serviceUUIDStrings != nil && ![serviceUUIDStrings isKindOfClass:[NSArray class]]) {
NSLog(@"Malformed UUID");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Malformed UUID"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSArray<CBUUID *> *serviceUUIDs = [self uuidStringsToCBUUIDs:serviceUUIDStrings];
if (serviceUUIDs == nil) {
NSLog(@"Malformed UUID");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Malformed UUID"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSArray<CBPeripheral *> *connectedPeripherals = [manager retrieveConnectedPeripheralsWithServices:serviceUUIDs];
NSMutableArray<NSDictionary *> *connected = [NSMutableArray new];
Expand All @@ -505,6 +546,12 @@ - (void)peripheralsWithIdentifiers:(CDVInvokedUrlCommand*)command {
NSLog(@"peripheralsWithIdentifiers");
NSArray *identifierUUIDStrings = [command argumentAtIndex:0];
NSArray<NSUUID *> *identifiers = [self uuidStringsToNSUUIDs:identifierUUIDStrings];
if (identifiers == nil) {
NSLog(@"Malformed UUID");
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Malformed UUID"];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

NSArray<CBPeripheral *> *foundPeripherals = [manager retrievePeripheralsWithIdentifiers:identifiers];
// TODO are any of these connected?
Expand All @@ -524,7 +571,11 @@ - (void)peripheralsWithIdentifiers:(CDVInvokedUrlCommand*)command {
- (void)closeL2Cap:(CDVInvokedUrlCommand*)command {
NSLog(@"closeL2Cap");

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

NSNumber *psm = [command argumentAtIndex:1];
CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];

Expand All @@ -545,7 +596,11 @@ - (void)closeL2Cap:(CDVInvokedUrlCommand*)command {
- (void)openL2Cap:(CDVInvokedUrlCommand*)command {
NSLog(@"openL2Cap");

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

NSNumber *psm = [command argumentAtIndex:1];
CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];

Expand All @@ -565,7 +620,11 @@ - (void)openL2Cap:(CDVInvokedUrlCommand*)command {
- (void)receiveDataL2Cap:(CDVInvokedUrlCommand*)command {
NSLog(@"receiveDataL2Cap");

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

NSNumber *psm = [command argumentAtIndex:1];
CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];

Expand All @@ -583,7 +642,11 @@ - (void)receiveDataL2Cap:(CDVInvokedUrlCommand*)command {
- (void)writeL2Cap:(CDVInvokedUrlCommand *)command {
NSLog(@"writeL2Cap");

NSString *uuid = [command argumentAtIndex:0];
NSUUID *uuid = [self getUUID:command argumentAtIndex:0];
if (uuid == nil) {
return;
}

NSNumber *psm = [command argumentAtIndex:1];
NSData *message = [command argumentAtIndex:2]; // This is binary
CBPeripheral *peripheral = [self findPeripheralByUUID:uuid];
Expand Down Expand Up @@ -921,23 +984,22 @@ - (void)peripheral:(CBPeripheral *)peripheral didOpenL2CAPChannel:(CBL2CAPChanne

#pragma mark - internal implemetation

- (CBPeripheral*)findPeripheralByUUID:(NSString*)uuid {
- (CBPeripheral*)findPeripheralByUUID:(NSUUID*)uuid {
CBPeripheral *peripheral = nil;

for (CBPeripheral *p in peripherals) {

NSString* other = p.identifier.UUIDString;
NSUUID* other = p.identifier;

if ([uuid isEqualToString:other]) {
if ([uuid isEqual:other]) {
peripheral = p;
break;
}
}
return peripheral;
}

- (CBPeripheral*)retrievePeripheralWithUUID:(NSString*)uuid {
NSUUID *typedUUID = [[NSUUID alloc] initWithUUIDString:uuid];
- (CBPeripheral*)retrievePeripheralWithUUID:(NSUUID*)typedUUID {
NSArray *existingPeripherals = [manager retrievePeripheralsWithIdentifiers:@[typedUUID]];
CBPeripheral *peripheral = nil;
if ([existingPeripherals count] > 0) {
Expand Down Expand Up @@ -1008,26 +1070,52 @@ -(int) compareCBUUID:(CBUUID *) UUID1 UUID2:(CBUUID *)UUID2 {
return 0;
}

-(NSUUID*) getUUID:(CDVInvokedUrlCommand*)command argumentAtIndex:(NSUInteger)index {
NSLog(@"getUUID");

NSString *uuidString = [command argumentAtIndex:index withDefault:@"" andClass:[NSString class]];
NSUUID *uuid = [[NSUUID alloc] initWithUUIDString:uuidString];
if (uuid == nil) {
NSString *errorMessage = [NSString stringWithFormat:@"Malformed UUID: %@", [command argumentAtIndex:index]];
NSLog(@"%@", errorMessage);
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:errorMessage];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return nil;
}
return uuid;
}

// expecting deviceUUID, serviceUUID, characteristicUUID in command.arguments
-(BLECommandContext*) getData:(CDVInvokedUrlCommand*)command prop:(CBCharacteristicProperties)prop {
NSLog(@"getData");

CDVPluginResult *pluginResult = nil;

NSString *deviceUUIDString = [command argumentAtIndex:0];
NSString *serviceUUIDString = [command argumentAtIndex:1];
NSString *characteristicUUIDString = [command argumentAtIndex:2];
NSUUID *deviceUUID = [self getUUID:command argumentAtIndex:0];
if (deviceUUID == nil) {
return nil;
}

CBUUID *serviceUUID = [CBUUID UUIDWithString:serviceUUIDString];
CBUUID *characteristicUUID = [CBUUID UUIDWithString:characteristicUUIDString];
NSUUID *serviceNSUUID = [self getUUID:command argumentAtIndex:1];
if (serviceNSUUID == nil) {
return nil;
}

NSUUID *characteristicNSUUID = [self getUUID:command argumentAtIndex:2];
if (characteristicNSUUID == nil) {
return nil;
}

CBUUID *serviceUUID = [CBUUID UUIDWithNSUUID:serviceNSUUID];
CBUUID *characteristicUUID = [CBUUID UUIDWithNSUUID:characteristicNSUUID];

CBPeripheral *peripheral = [self findPeripheralByUUID:deviceUUIDString];
CBPeripheral *peripheral = [self findPeripheralByUUID:deviceUUID];

if (!peripheral) {

NSLog(@"Could not find peripheral with UUID %@", deviceUUIDString);
NSLog(@"Could not find peripheral with UUID %@", deviceUUID);

NSString *errorMessage = [NSString stringWithFormat:@"Could not find peripheral with UUID %@", deviceUUIDString];
NSString *errorMessage = [NSString stringWithFormat:@"Could not find peripheral with UUID %@", deviceUUID];
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:errorMessage];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

Expand All @@ -1036,16 +1124,11 @@ -(BLECommandContext*) getData:(CDVInvokedUrlCommand*)command prop:(CBCharacteris

CBService *service = [self findServiceFromUUID:serviceUUID p:peripheral];

if (!service)
{
NSLog(@"Could not find service with UUID %@ on peripheral with UUID %@",
serviceUUIDString,
peripheral.identifier.UUIDString);


if (!service) {
NSString *errorMessage = [NSString stringWithFormat:@"Could not find service with UUID %@ on peripheral with UUID %@",
serviceUUIDString,
serviceNSUUID.UUIDString,
peripheral.identifier.UUIDString];
NSLog(@"%@", errorMessage);
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:errorMessage];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

Expand All @@ -1064,18 +1147,13 @@ -(BLECommandContext*) getData:(CDVInvokedUrlCommand*)command prop:(CBCharacteris
characteristic = [self findCharacteristicFromUUID:characteristicUUID service:service];
}

if (!characteristic)
{
NSLog(@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
characteristicUUIDString,
serviceUUIDString,
peripheral.identifier.UUIDString);

if (!characteristic) {
NSString *errorMessage = [NSString stringWithFormat:
@"Could not find characteristic with UUID %@ on service with UUID %@ on peripheral with UUID %@",
characteristicUUIDString,
serviceUUIDString,
characteristicNSUUID.UUIDString,
serviceNSUUID.UUIDString,
peripheral.identifier.UUIDString];
NSLog(@"%@", errorMessage);
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:errorMessage];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];

Expand Down Expand Up @@ -1181,7 +1259,19 @@ - (NSString*) centralManagerStateToString: (int)state {
- (NSArray<CBUUID *> *) uuidStringsToCBUUIDs: (NSArray<NSString *> *)uuidStrings {
NSMutableArray *uuids = [NSMutableArray new];
for (int i = 0; i < [uuidStrings count]; i++) {
CBUUID *uuid = [CBUUID UUIDWithString:[uuidStrings objectAtIndex: i]];
NSString *uuidString = [uuidStrings objectAtIndex: i];
if (![uuidString isKindOfClass:[NSString class]]) {
NSLog(@"Malformed UUID found: %@", uuidString);
return nil;
}

NSUUID *nsuuid = [[NSUUID alloc]initWithUUIDString:uuidString];
if (nsuuid == nil) {
NSLog(@"Malformed UUID found: %@", uuidString);
return nil;
}

CBUUID *uuid = [CBUUID UUIDWithNSUUID:nsuuid];
[uuids addObject:uuid];
}
return uuids;
Expand All @@ -1190,7 +1280,18 @@ - (NSString*) centralManagerStateToString: (int)state {
- (NSArray<NSUUID *> *) uuidStringsToNSUUIDs: (NSArray<NSString *> *)uuidStrings {
NSMutableArray *uuids = [NSMutableArray new];
for (int i = 0; i < [uuidStrings count]; i++) {
NSUUID *uuid = [[NSUUID alloc]initWithUUIDString:[uuidStrings objectAtIndex: i]];
NSString *uuidString = [uuidStrings objectAtIndex: i];
if (![uuidString isKindOfClass:[NSString class]]) {
NSLog(@"Malformed UUID found: %@", uuidString);
return nil;
}

NSUUID *uuid = [[NSUUID alloc]initWithUUIDString:uuidString];
if (uuid == nil) {
NSLog(@"Malformed UUID found: %@", uuidString);
return nil;
}

[uuids addObject:uuid];
}
return uuids;
Expand Down

0 comments on commit bdd6f7e

Please sign in to comment.