Platform: Code4rena
Start Date: 14/04/2023
Pot Size: $90,500 USDC
Total HM: 7
Participants: 59
Period: 14 days
Judge: LSDan
Total Solo HM: 3
Id: 232
League: ETH
Rank: 23/59
Findings: 1
Award: $637.07
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Sathish9098
Also found by: 0x73696d616f, 0xAgro, 0xSmartContract, 0xTheC0der, ABA, ArbitraryExecution, Aymen0909, BRONZEDISC, Bauchibred, Dyear, Eurovickk, IceBear, Jerry0x, Jorgect, Josiah, MalfurionWhitehat, MohammedRizwan, RaymondFam, Recep, Rickard, SAAJ, Shubham, Udsen, auditor0517, brgltd, catellatech, chaduke, codeslide, eierina, favelanky, j4ld1na, lukris02, matrix_0wl, naman1778, pontifex, schrodinger, tnevler, urataps
637.0684 USDC - $637.07
During the audit, 2 low, 6 non-critical and 3 refactoring issues were found.
Total: 2 instances over 2 issues
# | Issue | Instances |
---|---|---|
[L-01] | BytesUtils.equals reverts if input length is less then offset | 1 |
[L-02] | DNSRegistrar.proveAndClaimWithResolver always sets subnode record TTL to 0 | 1 |
Total: 3 instances over 3 issues
# | Issue | Instances |
---|---|---|
[R-01] | readTXT asset offset check is ambiguous | 1 |
[R-02] | verify function from P256SHA256Algorithm can be changed to pure | 1 |
[R-03] | Reuse RRUtils.done() instead of duplicating code | 1 |
Total: 30 instances over 6 issues
# | Issue | Instances |
---|---|---|
[NC-01] | Non-ABI exposed functions should be _ prepended | 7 |
[NC-02] | Remove unused Debug event from SHA1.sol | 1 |
[NC-03] | Incomplete, misleading or missing important key information NatSpec comments | 8 |
[NC-04] | Parameter resolver shadows already declared variable in DNSRegistrar.proveAndClaimWithResolver | 1 |
[NC-05] | Missing SPDX license identifier | 11 |
[NC-06] | now param declaration shadows built-in symbol | 2 |
BytesUtils.equals
reverts if input length is less then offsetFunction equals
from BytesUtils
reverts if input length is less then offset
function equals( bytes memory self, uint256 offset, bytes memory other, uint256 otherOffset ) internal pure returns (bool) { return keccak(self, offset, self.length - offset) == keccak(other, otherOffset, other.length - otherOffset); }
This function should specifically consider this case, one way or another.
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/BytesUtils.sol#L129-L138
Modify function to check if offset > length and either:
Or modify function to revert with meaningful message
DNSRegistrar.proveAndClaimWithResolver
always sets subnode record TTL to 0Function proveAndClaimWithResolver
from DNSRegistrar
always sets subnode record TTL to 0.
ens.setSubnodeRecord(rootNode, labelHash, owner, resolver, 0);
setSubnodeRecord
will continue execution and arrive at _setResolverAndTTL
where the TTL is set regardless of value.
if (ttl != records[node].ttl) { records[node].ttl = ttl; emit NewTTL(node, ttl);
Depending on how TTL will be used in the future, this severely impacts protocol.
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnsregistrar/DNSRegistrar.sol#L114
Suggestions:
readTXT
asset offset check is ambiguousFunction readTXT
from OffchainDNSResolver
is a function used to read an DNS encoded string starting from an offset in a byte array.
It also does a check that the next offset (or last) must be further ahead then the bounds of the current string (label).
assert(startIdx + fieldLength < lastIdx);
This check is slightly done incorrect:
startIdx
is from where to read the next label/encoded string length (1 byte)startIdx+1
is from where the label starts; string length of fieldLength
startIdx+1+fieldLength
is the end offset from the begining of the label at handAs such, the logical lastIdx
assessment should be assert(startIdx + 1 + fieldLength <= lastIdx);
startIdx startIdx+1 endLabel=startIdx+1+fieldLength lastIdx +-----------+----------------------------------------------------------------+---- |fieldLength| fieldLength x bytes | | ... +-----------+---------------------------------------------------------------------
Mathematically, if we substract one from the left part, then startIdx + fieldLength < lastIdx
does proves to be a valid constraint.
Keeping the original form of the check would be a more clearer solution that would not bring upon it further scrutiny.
Change assert(startIdx + fieldLength < lastIdx)
to assert(startIdx + 1 + fieldLength <= lastIdx)
verify
function from P256SHA256Algorithm
can be changed to pureverify
function from P256SHA256Algorithm
can be changed to pure.
Change verify
function state mutability to pure.
RRUtils.done()
instead of duplicating codeIn RRUtils
, in the function next
the first check, to determine if to exit the function
if (iter.offset >= iter.data.length) { return; }
can be written using the done
function, as it contains the same code; no need for duplication.
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/RRUtils.sol#L160
Change the check to:
if (done(iter)) { return; }
It is generally considered a good practice to prepend _ to all internal/private functions so as to more easelly distinguish them from functions that are ABI exposed.
This is a general concern seen thought the codebase, some file examples:
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnsregistrar/OffchainDNSResolver.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnsregistrar/DNSClaimChecker.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/BytesUtils.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/RRUtils.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/utils/NameEncoder.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/utils/HexUtils.sol
Prepend _ to all private/internal functions in the code-base.
Debug
event from SHA1.sol
In SHA1.sol
there is a debug event declared but not used
event Debug(bytes32 x);
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/SHA1.sol#L4
Remove the event.
There are cases where function NatSpec comments are either severely incomplete, misleading or missing important key information.
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnsregistrar/RecordParser.sol#L9-L14
type(uint256).max
when parsing an invalid key-value pairhttps://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/BytesUtils.sol#L235
@dev Returns the 32 byte value ...
to @dev Returns the 20 byte value ...
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/BytesUtils.sol#L186
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/RRUtils.sol
RRUtils
(nameLength
, readName
, labelCount
, iterateRRs
) expect the input offset to always start at an encoded DNS length type string although this is never mentionedhttps://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L252
The serialized DS or DNSKEY record to use as proof.
to The serialized DNSKEY record to use as proof.
as this portraits to DNSKEY input onlyhttps://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L328
The serialized DS or DNSKEY record to use as proof.
to The serialized DS record to use as proof.
as this portraits to DS input onlyhttps://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L324-L325
@dev Attempts to verify a signed RRSET against an already known hash. This function assumes that the record
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L130-L140
Add/correct the missing documentation.
resolver
shadows already declared variable in DNSRegistrar.proveAndClaimWithResolver
Parameter resolver
shadows already declared variable in DNSRegistrar: proveAndClaimWithResolver
shadows:
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnsregistrar/DNSRegistrar.sol#L30
Rename function parameter to
SPDX license identifier not provided in source file.
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/RRUtils.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/BytesUtils.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/algorithms/RSAVerify.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/digests/SHA1Digest.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/digests/SHA256Digest.sol
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle\SHA1.sol
Before publishing, consider adding a comment containing "SPDX-License-Identifier: <SPDX-License>" to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. See https://spdx.org for more information.
now
param declaration shadows built-in symbolIn validateSignedSet and verifyRRSet functions from DNSSECImpl the now
param declaration shadows built-in symbol:
now (uint): current block timestamp (alias for block.timestamp)
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L109
https://github.com/code-423n4/2023-04-ens/blob/main/contracts/dnssec-oracle/DNSSECImpl.sol#L143
Rename now
co timestamp, as it is even mentioned as so in NatSpec @param now The Unix timestamp to validate the records at.
and it does not imply the current block time, just an arbitrary time at which to verify the input data.
#0 - c4-judge
2023-05-08T15:16:29Z
dmvt marked the issue as grade-a