readRaw_service_default parsed the IndexRange of each node to read, but
never freed the dimensions of the parsed range. Every raw history read with
an IndexRange leaked them. They are now freed after the backend call.
Reject circular HistoryRead continuation points whose skip exceeds the available result count, and cap the backend copy to the allocated response capacity. A forged skip could otherwise underflow the copy length and cause a heap-buffer-overflow when the response size was capped.
The default HistoryDatabase checked only the Variable node AccessLevel. Apply the session-specific AccessControl getUserAccessLevel result as well so clients denied HISTORYREAD or HISTORYWRITE cannot read, insert, replace, update or delete stored values.
Return BadOutOfMemory before invoking the read backend or writing HistoryUpdate operation results when their per-result allocations fail. This prevents null pointers from reaching the backend and avoids a null write under memory pressure.
UA_DataValue_backend_copyRange() performed a shallow memcpy of the
source UA_DataValue before attempting the range copy. Because the
destination's UA_Variant fields were not reinitialized first, a
failing UA_Variant_copyRange() (for example when the client-supplied
indexRange exceeds UA_MAX_ARRAY_DIMS) left the destination value as an
uninitialized alias of the backend-owned storage instead of an
independent copy.
copyDataValues_backend_memory() also discarded the status code from
both UA_DataValue_backend_copyRange() and UA_DataValue_copy(), so the
aliased, partially-copied value was still counted as a successful
result and forwarded to the HistoryRead response. Freeing that
response later released the backend's live storage, leaving the
backend with a dangling pointer that was dereferenced on a subsequent
HistoryRead.
Reinitialize the destination variant before the range copy and clear
it again on failure, mirroring the safe pattern already used by
UA_DataValue_copyRange(). Propagate copy failures out of
copyDataValues_backend_memory() immediately instead of counting a
failed entry as provided.
Internal Vulnerability Advisory: open62541-SA-2026-0021
Co-authored-by: gff-cw <gff-cw@users.noreply.github.com>
In getHistoryData_service_default(), the outer continuation point encodes
a skip count that was read directly from client-controlled bytes without
validation. Two independent arithmetic errors could cause a heap-buffer-
overflow in the subsequent backend copy call:
1. When skip > _resultSize, the subtraction `_resultSize - skip` wraps
around in size_t, producing a very large value. After clamping to
maxSize, the allocation is correct, but the wrapped large skip is
still used to recompute valueSize for the backend call.
2. When the reconstructed valueSize exceeds the number of entries actually
allocated in outResult, copyDataValues() writes beyond the end of the
result array (heap-buffer-overflow write).
Fix both issues in getHistoryData_service_default():
- Reject continuation points whose skip value exceeds the computed result
set size, returning UA_STATUSCODE_BADCONTINUATIONPOINTINVALID.
- After computing valueSize, cap it to the remaining allocated capacity in
outResult so the backend cannot be instructed to write past the buffer.
Internal Vulnerability Advisory: open62541-SA-2026-0027
* Fix memory leak in UA_HistoryDataBackend_Memory
* Fix uninitialized memory in the default history data gathering plugin
After extending the memory block with realloc, the additional memory is
not initialized with null bytes.
This commit drops the 'ua_' prefix and changes the public includes
to the form `#include <open62541/server.h>` instead of the old
`#include <ua_server.h>`