Add protection against some network issues - #226
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 8 |
| Duplication | 0 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
|
✅ Build pvAccessCPP 1.0.159 completed (commit 8c5d306e77 by @anjohnson) |
Control messages treat this int32 as an opaque value, but application messages use it as a length, so must reject it. Applies to both UDP and TCP streams. Test added to testCodec.cpp
They're already validated in the channel-creation path.
I had AI analyse these commented-out guards and produce a report, which said they should all be uncommented. Happy to discuss them or provide a copy on request.
cc2de0f to
f6b31b9
Compare
|
Oops, that last commit needs a change from my pvDataCPP add-protection branch. |
No problem with UDP. I have some hesitation about TCP. Have you instead tried to switch The semantics around segmented messages has never been clear to me. Currently PVXS can receive segmented messages, but will never send them. It does handle message length as unsigned 32-bit. @kasemir Does core.pva do anything with the segmentation flags? |
|
❌ Build pvAccessCPP 1.0.161 failed (commit 1308b3737f by @anjohnson) |
There is code to detect a segmented message and assemble the pieces, but I don't think I've ever been able to check that against a PVA server which generates such messages. |
Why? Doing that would require much more complicated changes to the code and tests. The PVA protocol Wiki explicitly says about sizes:
It does go on to suggest how larger sizes would be encoded if they were supported though. Have you implemented them in PVXS without updating the spec? Does the new Java implementation also support that? |
f6b31b9 to
555fff2
Compare
555fff2 to
fead494
Compare
|
✅ Build pvAccessCPP 1.0.165 completed (commit 459f6df111 by @anjohnson) |
|
✅ Build pvAccessCPP 1.0.166 completed (commit cef563ab8d by @anjohnson) |
anjohnson
left a comment
There was a problem hiding this comment.
Core comments with detail fixes.
| { | ||
| if(impl) { | ||
| strm<<typeid(*impl->channel.get()).name()<<" : "; | ||
| pva::Channel& channel = *impl->channel; |
There was a problem hiding this comment.
Needs to call get() to get the type-id of the contained object. Ditto below.
Move to a non-hardening PR.
| POINTER_DEFINITIONS(PipelineControl); | ||
|
|
||
| virtual ~PipelineControl() {}; | ||
| virtual ~PipelineControl(); |
|
|
||
| // command ID and paylaod | ||
| int8 command = receiveBuffer->getByte(); | ||
| // TODO check this cast (size_t must be 32-bit) |
| size_t payloadSize = receiveBuffer->getInt(); | ||
|
|
||
| // control message check (skip message) | ||
| if (flags & 0x01) | ||
| continue; | ||
|
|
||
| // reject negative payload size (sign-extends to a huge size_t) | ||
| if (static_cast<int32>(payloadSize) < 0) | ||
| return false; | ||
|
|
There was a problem hiding this comment.
Core: Add an int32 payload size var above which is assigned from the buffer, then exclude negatives and assign to the size_t version (with no renames or casts below).
| _command = _socketBuffer.getByte(); | ||
|
|
||
| // read payload size | ||
| _payloadSize = _socketBuffer.getInt(); |
There was a problem hiding this comment.
Do the –ve checks for payload size with the magicCode check on 193 below, not later on.
|
|
||
| if (channelGet) | ||
| channelGet->destroy(); |
There was a problem hiding this comment.
MAD checked and is good with this.
| //Lock guard(_mutex); | ||
| Lock guard(_mutex); | ||
| _pvPutBitSet->serialize(buffer, control); | ||
| _pvPutStructure->serialize(buffer, control, _pvPutBitSet.get()); | ||
| } |
There was a problem hiding this comment.
What data is being guarded here?
| Lock guard(_mutex); | ||
| ScopedLock lock(channelArray); | ||
| _pvArray->serialize(buffer, control, 0, _pvArray->getLength()); |
There was a problem hiding this comment.
Locking order here is different than above QOS stuff, is this correct?
| Channel& channel = *_channel; | ||
| fprintf(fd,"CLASS : %s\n", typeid(*this).name()); | ||
| fprintf(fd,"CHANNEL : %s\n", typeid(*_channel).name()); | ||
| fprintf(fd,"CHANNEL : %s\n", typeid(channel).name()); |
There was a problem hiding this comment.
Ack, but not hardening.
| // reject negative payload size (sign-extends to a huge size_t) | ||
| if (_payloadSize < 0) | ||
| { | ||
| invalidDataStreamHandler(); | ||
| throw invalid_data_stream_exception("negative payload size"); | ||
| } | ||
|
|
There was a problem hiding this comment.
Remove this change, and the next one.
Moved from the private area.
By commit:
Reject negative payload sizes in messages over UDP and TCP, with tests.
It looks like this module can't handle TCP or UDP messages over 2^31 Bytes, although the TCP code apparently understands joining segmented messages.
Ignore over-long channel names in search messages.
This commit skips over names longer than would be accepted by the channel create code. A better response might be to immediately discard the search message, research needed on how to implement that.
Uncomment Lock guards that were improperly disabled long ago.
See the gist here (2nd document) for Claude's assessment of the lock guard history.
Prevent deadlocks in
destroy()methods.See the gist here (1st document) for Claude's explanation of fixes like one by @mdavidsaver in 2018.
Limit strings accepted as channel names to
MAX_CHANNEL_NAME_LENGTH, ignoring anything larger. This requires a change implemented in my pvData add-protection branch, Add protection from some network issues pvDataCPP#107