summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Tanskanen <aleta@cendio.com>2020-02-20 16:12:35 +0100
committerAlex Tanskanen <aleta@cendio.com>2020-02-21 09:39:31 +0100
commitceb8ef4ec1a21bc5917185d43360aa78ff735afe (patch)
tree7ff372bc38116e39673cc43bd31a8fefa8bf152b
parente4e6a9b9b40545094530cf1d751b33466d2ed57d (diff)
downloadnovnc-ceb8ef4ec1a21bc5917185d43360aa78ff735afe.tar.gz
Fix crash with too large clipboard data
If too much text is copied in the session, String.fromCharCode.apply() would crash in Safari on macOS and Chrome on Linux. This commit fixes this issue by avoiding apply() altogether. Also added test to cover this issue.
-rw-r--r--core/rfb.js6
-rw-r--r--tests/test.rfb.js32
2 files changed, 37 insertions, 1 deletions
diff --git a/core/rfb.js b/core/rfb.js
index 9e6881f..536ea25 100644
--- a/core/rfb.js
+++ b/core/rfb.js
@@ -1504,7 +1504,11 @@ export default class RFB extends EventTargetMixin {
streamInflator.setInput(null);
if (textData !== null) {
- textData = String.fromCharCode.apply(null, textData);
+ let tmpText = "";
+ for (let i = 0; i < textData.length; i++) {
+ tmpText += String.fromCharCode(textData[i]);
+ }
+ textData = tmpText;
textData = decodeUTF8(textData);
if ((textData.length > 0) && "\0" === textData.charAt(textData.length - 1)) {
diff --git a/tests/test.rfb.js b/tests/test.rfb.js
index bb690ce..41232ae 100644
--- a/tests/test.rfb.js
+++ b/tests/test.rfb.js
@@ -2514,6 +2514,38 @@ describe('Remote Frame Buffer Protocol Client', function () {
client.removeEventListener("clipboard", spy);
});
+ it('should be able to handle large Provide messages', function () {
+ // repeat() is not supported in IE so a loop is needed instead
+ let expectedData = "hello";
+ for (let i = 1; i <= 100000; i++) {
+ expectedData += "hello";
+ }
+
+ let data = [3, 0, 0, 0];
+ const flags = [0x10, 0x00, 0x00, 0x01];
+
+ let text = encodeUTF8(expectedData + "\0");
+
+ let deflatedText = deflateWithSize(text);
+
+ // How much data we are sending.
+ push32(data, toUnsigned32bit(-(4 + deflatedText.length)));
+
+ data = data.concat(flags);
+
+ let sendData = new Uint8Array(data.length + deflatedText.length);
+ sendData.set(data);
+ sendData.set(deflatedText, data.length);
+
+ const spy = sinon.spy();
+ client.addEventListener("clipboard", spy);
+
+ client._sock._websocket._receive_data(sendData);
+ expect(spy).to.have.been.calledOnce;
+ expect(spy.args[0][0].detail.text).to.equal(expectedData);
+ client.removeEventListener("clipboard", spy);
+ });
+
});
describe('Handle Notify', function () {