Add protection from some network issues - #107
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | -2 |
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 pvDataCPP 1.0.81 completed (commit 3ab6d1c8c3 by @anjohnson) |
050cf76 to
c22ea27
Compare
|
✅ Build pvDataCPP 1.0.82 completed (commit d0d55663d1 by @anjohnson) |
c22ea27 to
2cc9ee0
Compare
|
How to handle the POD array template I'm currently looking at the RTEMS-4.9 test failure. |
|
The pvData / 7.0 Ub-22 gcc + RT-4.9 pc386 build is failing in the new Those symptoms look like a stack overflow or similar issue, 1000 elements is the largest the new tests request. The RT-4.10 and 5.1 builds don't fail; is this worth chasing? |
|
✅ Build pvDataCPP 1.0.83 completed (commit 61dbdc3e7c by @anjohnson) |
anjohnson
left a comment
There was a problem hiding this comment.
/code-review comments from Claude; some fixes to come, but not the generic PVValueArray<T>::deserialize() fix which we haven't decided on yet.
| data.resize(0); | ||
| data.reserve(size < 64 ? size : 64); |
There was a problem hiding this comment.
Claude Sonnet 5: The old per-element reuse optimization (reuse still-unique PVStructure/PVUnion objects across deserialize calls) is silently discarded.
The new reserve(min(size,64)) + push_back growth pattern interacts badly with shared_vector's fixed +1024-element growth increment above 1024 items, causing O(n²) copy work for legitimately large arrays.
There was a problem hiding this comment.
The shared_vector<…>::push_back() method only grows geometrically up to 1024 elements, thereafter it adds 1024 elements every time it expands. An areaDetector NTNDArray has an epics:nt/NTAttribute:1.0[] attribute array field which would hit the O(n²) allocation, but hopefully only the first time the data is published.
Subsequent monitor updates should re-use the array storage where the attribute list doesn't change, but some experiments may continue to add attributes over time, and those would be the ones I worry about.
There was a problem hiding this comment.
Subsequent monitor updates should re-use the array storage ...
A reuse() is attempted because it is low cost. However, I think it is unlikely to succeed in the most important cases (AD). It would be unlikely in the case of a QSRV1 group mapping as a reference to the most recent value is kept.
I worry that this attempt to "harden" against a malicious peer will unduly harm performance on all others. So I am going to hold off on this part until the core developer group agrees on a policy on regarding DoS mitigations which negatively impact performance.
2cc9ee0 to
be0d506
Compare
|
✅ Build pvDataCPP 1.0.85 completed (commit b43c30a277 by @anjohnson) |
Move bounds check to before the allocation. Treat NULL bitset values as empty to avoid overflow. Add tests for excessive allocation, and Null values.
Ensure container types PVStructureArray and PVUnionArray can't be used to allocate huge arrays, unless they really are that big. New containers start small and grow as as elements are deserialized from the input stream.
df17c76 to
a8e4961
Compare
Ensure PVValueArray<string> containers can't allocate huge arrays unless the client provides string values for all the elements. Start containers small and grow them as elements are deserialized from the input stream. Adds tests for all the array deserialization hardening. Limit array growth tests on RTEMS 4.x.
a8e4961 to
a0e1375
Compare
|
✅ Build pvDataCPP 1.0.86 completed (commit 4d46ed1dbe by @anjohnson) |
|
✅ Build pvDataCPP 1.0.87 completed (commit 4fbed20dcd by @anjohnson) |
|
✅ Build pvDataCPP 1.0.88 completed (commit 95f04cfc9d by @anjohnson) |
|
✅ Build pvDataCPP 1.0.91 completed (commit 7f84e62be6 by @anjohnson) |
Defaults to INT32_MAX if not provided, but several places in pvAccess can set limits, e.g. MAX_CHANNEL_NAME_LENGTH, and this is the best way to harden them against huge values. Document that SerializeHelper::readSize() returns -1 for NULL.
8b56d62 to
84e29e8
Compare
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
| Duplication | -2 |
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 pvDataCPP 1.0.92 failed (commit 1f6f3b31dc by @anjohnson) |
|
✅ Build pvDataCPP 1.0.92 completed (commit 1f6f3b31dc by @anjohnson) |
| selector = index; | ||
| value.reset(); | ||
| } | ||
| else if (index < 0 || size_t(index) >= unionPtr->getFields().size()) |
There was a problem hiding this comment.
This check is redundant to the later getField(selector);, which bounds checks its argument. Still, an explicit check here gives a better error message.
| */ | ||
| static std::string deserializeString(ByteBuffer* buffer, | ||
| DeserializableControl* control); | ||
| DeserializableControl* control, std::size_t max = INT32_MAX); |
There was a problem hiding this comment.
No objection to the added argument. I have a small concern about whether the INT32_MAX macro will be defined on all targets. Strictly speaking, the C++ way is std::numeric_limits. However, since this is a fixed value, I will just change it to 0x7fffffff.
| m_statusType = STATUSTYPE_FATAL; | ||
| m_message = "deserialized type code was invalid"; | ||
| m_stackDump.clear(); | ||
| THROW_BASE_EXCEPTION("invalid Status type code"); |
There was a problem hiding this comment.
While I do not see much chance that we will want to add codes in future, it seems unnecessary to close the door on this possibility now. I will instead treat all currently unknown codes as FATAL.
| data.resize(0); | ||
| data.reserve(size < 64 ? size : 64); |
There was a problem hiding this comment.
Subsequent monitor updates should re-use the array storage ...
A reuse() is attempted because it is low cost. However, I think it is unlikely to succeed in the most important cases (AD). It would be unlikely in the case of a QSRV1 group mapping as a reference to the most recent value is kept.
I worry that this attempt to "harden" against a malicious peer will unduly harm performance on all others. So I am going to hold off on this part until the core developer group agrees on a policy on regarding DoS mitigations which negatively impact performance.
|
Core: Some changes have been merged by cherry-pick. This PR needs further thought, the performance-affecting changes might not be wanted. |
Malicious traffic from the network wasn't being checked properly. These changes don't prevent sending huge arrays or string values, but they do stop issues related to overflows caused by negative sizes, which PVA specifies to be positive int32 values.
BitSet::deserialize()to the size actually needed. Support deserializing a NULL value. Includes new tests.2, 3. The
PVStructureArray,PVUnionArrayandPVValueArray<string>deserialize()methods now allocate their storage as data arrives, and reject negative sizes. Includes new basic and malicious tests.Add a maximum string length to
SerializeHelper::deserializeString(), with a default of INT32_MAX.Protect
Status::::deserialize()from a bad status.Protect
PVUnion::deserialize()from a bad selector value.