Permalink
Browse files

Check against integer overflow in RCTNetworking decodeTextData

Summary:
It's currently possible to crash React Native on iOS when using XMLHTTPRequest with onreadystatechange by having the server send a bunch of bad unicode (we found the problem when a bad deploy caused this to happen).

This is due to an integer overflow when handling carryover data in decodeTextData.

Create Express server with mock endpoint:

```js
var express = require('express');
var app = express();

app.get('/', function(req, res) {
  res.writeHead(200, {'content-type': 'text/plain; charset=utf-8'});
  res.flushHeaders();
  res.write(new Buffer(Array(4097).join(0x48).concat(0xC2)));
  res.write(new Buffer([0xA9]));
  res.end();
});

app.listen(3000);
```

Create React Native application which tries to hit the endpoint:

```js
export default class App extends Component<{}> {
  componentDidMount() {
    const xhr = new XMLHttpRequest()
    xhr.open('get', 'http://localhost:3000', true);
    xhr.onreadystatechange = function () {
      if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
        console.warn(xhr.responseText);
      }
    };
    xhr.send();
  }

  render() {
    return null;
  }
}
```

Observe that the application crashes when running master and doesn't when including the changes from this pull request.

[IOS] [BUGFIX] [RCTNetworking] - |Check against integer overflow when parsing response|
Closes #16286

Differential Revision: D6060975

Pulled By: hramos

fbshipit-source-id: 650e401a3bc033725078ea064f8fbca5441f9db5
  • Loading branch information...
cdlewis authored and facebook-github-bot committed Nov 7, 2017
1 parent 3c5a55d commit 1c04ceeb4ba954eee7ab34fc5b6c660d9772d9f6
Showing with 8 additions and 2 deletions.
  1. +8 −2 Libraries/Network/RCTNetworking.mm
@@ -402,8 +402,14 @@ + (NSString *)decodeTextData:(NSData *)data fromResponse:(NSURLResponse *)respon
if (inputCarryData) {
NSUInteger encodedResponseLength = [encodedResponse dataUsingEncoding:encoding].length;
NSData *newCarryData = [currentCarryData subdataWithRange:NSMakeRange(encodedResponseLength, currentCarryData.length - encodedResponseLength)];
[inputCarryData setData:newCarryData];
// Ensure a valid subrange exists within currentCarryData
if (currentCarryData.length >= encodedResponseLength) {
NSData *newCarryData = [currentCarryData subdataWithRange:NSMakeRange(encodedResponseLength, currentCarryData.length - encodedResponseLength)];
[inputCarryData setData:newCarryData];
} else {
[inputCarryData setLength:0];
}
}
return encodedResponse;

0 comments on commit 1c04cee

Please sign in to comment.