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 https://github.com/facebook/react-native/pull/16286

Differential Revision: D6060975

Pulled By: hramos

fbshipit-source-id: 650e401a3bc033725078ea064f8fbca5441f9db5
This commit is contained in:
Chris Lewis 2017-11-07 08:03:08 -08:00 committed by Facebook Github Bot
parent 3c5a55ddc2
commit 1c04ceeb4b
1 changed files with 8 additions and 2 deletions

View File

@ -402,8 +402,14 @@ RCT_EXPORT_MODULE()
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;