diff options
Diffstat (limited to 'common/rfb/SMsgReader.cxx')
-rw-r--r-- | common/rfb/SMsgReader.cxx | 192 |
1 files changed, 156 insertions, 36 deletions
diff --git a/common/rfb/SMsgReader.cxx b/common/rfb/SMsgReader.cxx index dc7ddea6..944f9315 100644 --- a/common/rfb/SMsgReader.cxx +++ b/common/rfb/SMsgReader.cxx @@ -38,7 +38,7 @@ static LogWriter vlog("SMsgReader"); static IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024); SMsgReader::SMsgReader(SMsgHandler* handler_, rdr::InStream* is_) - : handler(handler_), is(is_) + : handler(handler_), is(is_), state(MSGSTATE_IDLE) { } @@ -46,71 +46,105 @@ SMsgReader::~SMsgReader() { } -void SMsgReader::readClientInit() +bool SMsgReader::readClientInit() { + if (!is->hasData(1)) + return false; bool shared = is->readU8(); handler->clientInit(shared); + return true; } -void SMsgReader::readMsg() +bool SMsgReader::readMsg() { - int msgType = is->readU8(); - switch (msgType) { + bool ret; + + if (state == MSGSTATE_IDLE) { + if (!is->hasData(1)) + return false; + + currentMsgType = is->readU8(); + state = MSGSTATE_MESSAGE; + } + + switch (currentMsgType) { case msgTypeSetPixelFormat: - readSetPixelFormat(); + ret = readSetPixelFormat(); break; case msgTypeSetEncodings: - readSetEncodings(); + ret = readSetEncodings(); break; case msgTypeSetDesktopSize: - readSetDesktopSize(); + ret = readSetDesktopSize(); break; case msgTypeFramebufferUpdateRequest: - readFramebufferUpdateRequest(); + ret = readFramebufferUpdateRequest(); break; case msgTypeEnableContinuousUpdates: - readEnableContinuousUpdates(); + ret = readEnableContinuousUpdates(); break; case msgTypeClientFence: - readFence(); + ret = readFence(); break; case msgTypeKeyEvent: - readKeyEvent(); + ret = readKeyEvent(); break; case msgTypePointerEvent: - readPointerEvent(); + ret = readPointerEvent(); break; case msgTypeClientCutText: - readClientCutText(); + ret = readClientCutText(); break; case msgTypeQEMUClientMessage: - readQEMUMessage(); + ret = readQEMUMessage(); break; default: - vlog.error("unknown message type %d", msgType); + vlog.error("unknown message type %d", currentMsgType); throw Exception("unknown message type"); } + + if (ret) + state = MSGSTATE_IDLE; + + return ret; } -void SMsgReader::readSetPixelFormat() +bool SMsgReader::readSetPixelFormat() { + if (!is->hasData(3 + 16)) + return false; is->skip(3); PixelFormat pf; pf.read(is); handler->setPixelFormat(pf); + return true; } -void SMsgReader::readSetEncodings() +bool SMsgReader::readSetEncodings() { + if (!is->hasData(3)) + return false; + + is->setRestorePoint(); + is->skip(1); + int nEncodings = is->readU16(); + + if (!is->hasDataOrRestore(nEncodings * 4)) + return false; + is->clearRestorePoint(); + rdr::S32Array encodings(nEncodings); for (int i = 0; i < nEncodings; i++) encodings.buf[i] = is->readU32(); + handler->setEncodings(nEncodings, encodings.buf); + + return true; } -void SMsgReader::readSetDesktopSize() +bool SMsgReader::readSetDesktopSize() { int width, height; int screens, i; @@ -118,6 +152,11 @@ void SMsgReader::readSetDesktopSize() int sx, sy, sw, sh; ScreenSet layout; + if (!is->hasData(7)) + return true; + + is->setRestorePoint(); + is->skip(1); width = is->readU16(); @@ -126,6 +165,10 @@ void SMsgReader::readSetDesktopSize() screens = is->readU8(); is->skip(1); + if (!is->hasDataOrRestore(screens * 24)) + return false; + is->clearRestorePoint(); + for (i = 0;i < screens;i++) { id = is->readU32(); sx = is->readU16(); @@ -138,23 +181,31 @@ void SMsgReader::readSetDesktopSize() } handler->setDesktopSize(width, height, layout); + + return true; } -void SMsgReader::readFramebufferUpdateRequest() +bool SMsgReader::readFramebufferUpdateRequest() { + if (!is->hasData(17)) + return false; bool inc = is->readU8(); int x = is->readU16(); int y = is->readU16(); int w = is->readU16(); int h = is->readU16(); handler->framebufferUpdateRequest(Rect(x, y, x+w, y+h), inc); + return true; } -void SMsgReader::readEnableContinuousUpdates() +bool SMsgReader::readEnableContinuousUpdates() { bool enable; int x, y, w, h; + if (!is->hasData(17)) + return false; + enable = is->readU8(); x = is->readU16(); @@ -163,81 +214,121 @@ void SMsgReader::readEnableContinuousUpdates() h = is->readU16(); handler->enableContinuousUpdates(enable, x, y, w, h); + + return true; } -void SMsgReader::readFence() +bool SMsgReader::readFence() { rdr::U32 flags; rdr::U8 len; char data[64]; + if (!is->hasData(8)) + return false; + + is->setRestorePoint(); + is->skip(3); flags = is->readU32(); len = is->readU8(); + + if (!is->hasDataOrRestore(len)) + return false; + is->clearRestorePoint(); + if (len > sizeof(data)) { vlog.error("Ignoring fence with too large payload"); is->skip(len); - return; + return true; } is->readBytes(data, len); handler->fence(flags, len, data); + + return true; } -void SMsgReader::readKeyEvent() +bool SMsgReader::readKeyEvent() { + if (!is->hasData(7)) + return false; bool down = is->readU8(); is->skip(2); rdr::U32 key = is->readU32(); handler->keyEvent(key, 0, down); + return true; } -void SMsgReader::readPointerEvent() +bool SMsgReader::readPointerEvent() { + if (!is->hasData(5)) + return false; int mask = is->readU8(); int x = is->readU16(); int y = is->readU16(); handler->pointerEvent(Point(x, y), mask); + return true; } -void SMsgReader::readClientCutText() +bool SMsgReader::readClientCutText() { + if (!is->hasData(7)) + return false; + + is->setRestorePoint(); + is->skip(3); rdr::U32 len = is->readU32(); if (len & 0x80000000) { rdr::S32 slen = len; slen = -slen; - readExtendedClipboard(slen); - return; + if (readExtendedClipboard(slen)) { + is->clearRestorePoint(); + return true; + } else { + is->gotoRestorePoint(); + return false; + } } + if (!is->hasDataOrRestore(len)) + return false; + is->clearRestorePoint(); + if (len > (size_t)maxCutText) { is->skip(len); vlog.error("Cut text too long (%d bytes) - ignoring", len); - return; + return true; } + CharArray ca(len); is->readBytes(ca.buf, len); CharArray filtered(convertLF(ca.buf, len)); handler->clientCutText(filtered.buf); + + return true; } -void SMsgReader::readExtendedClipboard(rdr::S32 len) +bool SMsgReader::readExtendedClipboard(rdr::S32 len) { rdr::U32 flags; rdr::U32 action; + if (!is->hasData(len)) + return false; + if (len < 4) throw Exception("Invalid extended clipboard message"); if (len > maxCutText) { vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len); is->skip(len); - return; + return true; } flags = is->readU32(); @@ -279,7 +370,14 @@ void SMsgReader::readExtendedClipboard(rdr::S32 len) if (!(flags & 1 << i)) continue; + if (!zis.hasData(4)) + throw Exception("Extended clipboard decode error"); + lengths[num] = zis.readU32(); + + if (!zis.hasData(lengths[num])) + throw Exception("Extended clipboard decode error"); + if (lengths[num] > (size_t)maxCutText) { vlog.error("Extended clipboard data too long (%d bytes) - ignoring", (unsigned)lengths[num]); @@ -319,28 +417,50 @@ void SMsgReader::readExtendedClipboard(rdr::S32 len) throw Exception("Invalid extended clipboard action"); } } + + return true; } -void SMsgReader::readQEMUMessage() +bool SMsgReader::readQEMUMessage() { - int subType = is->readU8(); + int subType; + bool ret; + + if (!is->hasData(1)) + return false; + + is->setRestorePoint(); + + subType = is->readU8(); + switch (subType) { case qemuExtendedKeyEvent: - readQEMUKeyEvent(); + ret = readQEMUKeyEvent(); break; default: throw Exception("unknown QEMU submessage type %d", subType); } + + if (!ret) { + is->gotoRestorePoint(); + return false; + } else { + is->clearRestorePoint(); + return true; + } } -void SMsgReader::readQEMUKeyEvent() +bool SMsgReader::readQEMUKeyEvent() { + if (!is->hasData(10)) + return false; bool down = is->readU16(); rdr::U32 keysym = is->readU32(); rdr::U32 keycode = is->readU32(); if (!keycode) { vlog.error("Key event without keycode - ignoring"); - return; + return true; } handler->keyEvent(keysym, keycode, down); + return true; } |