Omniscia 0xPhase Audit
DBV1 Manual Review Findings
DBV1 Manual Review Findings
DBV-01M: Incorrect Addition of Value
Type | Severity | Location |
---|---|---|
Input Sanitization | DBV1.sol:L213 |
Description:
The DBV1::add(bytes32[],bytes32)
function will add a value to the _valueList
regardless of whether any keys were defined in the function's invocation.
Impact:
It is possible to corrupt the _valueList
data entries by specifying a zero-length keys
array and a value
to the DBV1::add(bytes32[],bytes32)
function.
Example:
197/// @inheritdoc IDB198/// @custom:protected onlyOwner199function add(bytes32[] memory keys, bytes32 value) public override onlyOwner {200 Set storage valueSet = _values[value];201
202 for (uint256 i = 0; i < keys.length; i++) {203 bytes32 key = keys[i];204 Set storage keySet = _keys[key];205
206 keySet.exists = true;207 valueSet.exists = true;208
209 keySet.list.add(value);210 valueSet.list.add(key);211 }212
213 _valueList.add(value);214}
Recommendation:
We advise the DBV1::add(bytes32[],bytes32)
code to either mandate that a non-zero length
is present in the keys
array or to execute the _valueList
inclusion conditionally, either of which we consider an adequate resolution to this exhibit.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The 0xPhase team opted to apply the former of the two recommended courses of action, introducing a require
check that mandates a non-zero length for the keys
array and thus alleviates this exhibit.
DBV-02M: Unsafe Type Casting
Type | Severity | Location |
---|---|---|
Language Specific | DBV1.sol:L260 |
Description:
The DBV1::getAddressB32
function performs a casting operation of a bytes32
variable to a bytes20
variable unsafely, potentially truncating data points.
Impact:
It is presently possible to use any bytes32
variable stored in the contract as an address
entry regardless of whether it contains more bits set than an address
(i.e. regardless of whether it was meant for another purpose).
Example:
258/// @inheritdoc IDB259function getAddressB32(bytes32 key) public view override returns (address) {260 return address(bytes20(getValueB32(key)));261}
Recommendation:
We advise it to evaluate that the bytes32
value yielded by DBV1::getValueB32
is at most 20 bytes in length, using either bitwise operators or numeric limits to achieve this.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The DBV1::getAddressB32
function properly validates the value
it extracts via a bitwise operator in the latest implementation of the codebase, alleviating this exhibit.
DBV-03M: Discrepant Behaviour of NAND
Operator
Type | Severity | Location |
---|---|---|
Logical Fault | DBV1.sol:L404 |
Description:
The NAND
logical construct is meant to be satisfied if both mem
and digested
entries are not true
, however, in the referenced instance only the case whereby the first entry (mem
) is true
and the second entry (digested
) is false
satisfies the circuit.
Impact:
The NAND
operation code will fail to behave as expected in half of the evaluation instances, rendering the DBV1::_digest
function insecure when dealing with NAND
clauses.
Example:
399if (op == OpcodeType.AND) {400 mem[j] = ((mem[j] > 0) && (digested[j] > 0)) ? 1 : 0;401} else if (op == OpcodeType.OR) {402 mem[j] = ((mem[j] > 0) || (digested[j] > 0)) ? 1 : 0;403} else if (op == OpcodeType.NAND) {404 mem[j] = ((mem[j] > 0) && !(digested[j] > 0)) ? 1 : 0;405}
Recommendation:
We advise the first entry (mem
) being false
and the second entry (digested
) being true
to also satisfy the circuit by applying a logical negation (!
) to the result of (mem[j] > 0) && (digested[j] > 0)
, properly implementing the NAND
logical circuit's behaviour.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The behaviour of the NAND
operator has been standardized to perform an actual NOT AND
operation via the relevant logical operators, alleviating this exhibit.
DBV-04M: Incorrect Arithmetic Operator Methodology
Type | Severity | Location |
---|---|---|
Logical Fault | DBV1.sol:L345, L347, L349, L351 |
Description:
The DBV1::_digest
function is expected to support multiple types of operators one category of which is arithmetic ones. In those operators, the code is expected to perform a calculation per element, however, the referenced calculations are performed with the currently active element which is always 0
rather than the previous one.
Impact:
The OpcodeType.ADD
through to OpcodeType.DIV
operators are presently broken in the current DBV1::_digest
implementation, either misbehaving or being inoperable.
Example:
338for (uint256 j = 0; j < length; j++) {339 if (i == 0) {340 mem[j] = digested[j];341 continue;342 }343
344 if (op == OpcodeType.ADD) {345 mem[j] = mem[j] + digested[j];346 } else if (op == OpcodeType.SUB) {347 mem[j] = mem[j] - digested[j];348 } else if (op == OpcodeType.MUL) {349 mem[j] = mem[j] * digested[j];350 } else if (op == OpcodeType.DIV) {351 mem[j] = mem[j] / digested[j];352 }353}
Recommendation:
We advise the referenced instances to utilize j - 1
as an index to mem
as otherwise they will greatly misbehave and at times be inoperable (i.e. in the subtraction).
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The elements are now properly consumed by utilizing the previous element and carrying it over with the relevant arithmetic operator and the digested value of the currently iterated element.
DBV-05M: Incorrect Logical Operator Methodology
Type | Severity | Location |
---|---|---|
Logical Fault | DBV1.sol:L400, L402, L404 |
Description:
The DBV1::_digest
function is expected to support multiple types of operators one category of which is logical ones. In those operators, the code is expected to perform a logical combination (AND
, OR
, or NAND
) per element pair, however, the referenced logical combinations are performed with the currently active element which is always 0
rather than the previous one.
Impact:
The OpcodeType.AND
through to OpcodeType.NAND
operators are presently broken in the current DBV1::_digest
implementation, yielding significantly discrepant results.
Example:
388for (uint256 j = 0; j < length; j++) {389 if (i == 0) {390 if (op == OpcodeType.NAND) {391 mem[j] = (digested[j] > 0 ? 0 : 1);392 } else {393 mem[j] = (digested[j] > 0 ? 1 : 0);394 }395
396 continue;397 }398
399 if (op == OpcodeType.AND) {400 mem[j] = ((mem[j] > 0) && (digested[j] > 0)) ? 1 : 0;401 } else if (op == OpcodeType.OR) {402 mem[j] = ((mem[j] > 0) || (digested[j] > 0)) ? 1 : 0;403 } else if (op == OpcodeType.NAND) {404 mem[j] = ((mem[j] > 0) && !(digested[j] > 0)) ? 1 : 0;405 }406}
Recommendation:
We advise the referenced instances to utilize j - 1
as an index to mem
as otherwise they will greatly misbehave.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The elements are now properly consumed by utilizing the previous element and carrying it over with the relevant logical operator and the digested value of the currently iterated element.
DBV-06M: Incorrect Removal of Value
Type | Severity | Location |
---|---|---|
Logical Fault | DBV1.sol:L99 |
Description:
The DBV1::removePair
function will remove the specified input value
from the global _valueList
regardless of whether the value is still referenced by another key.
Impact:
A value will be removed from the _valueList
incorrectly if it is pointed to by multiple keys, rendering the database's data structure corrupt.
Example:
89/// @inheritdoc IDB90/// @custom:protected onlyOwner91function removePair(bytes32 key, bytes32 value) external override onlyOwner {92 if (!hasPair(key, value)) return;93
94 Set storage keySet = _keys[key];95 Set storage valueSet = _values[value];96
97 keySet.list.remove(value);98 valueSet.list.remove(key);99 _valueList.remove(value);100
101 if (keySet.list.length() == 0) {102 valueSet.exists = false;103 }104
105 if (valueSet.list.length() == 0) {106 valueSet.exists = false;107 }108}
Recommendation:
We advise the value
to be removed from the _valueList
solely when valueSet.exists
is set to false
, meaning that it is no longer pointed to by any key.
Alleviation (3dd3d7bf0c2693b2f9c23bacedfa420393f7ea84):
The code was updated per our recommendation, removing the value from the _valueList
during a correct system state and thus alleviating this exhibit.