Skip to content

Commit 5e9bccb

Browse files
Transpile 138d094
1 parent 6b9807b commit 5e9bccb

File tree

11 files changed

+118
-8
lines changed

11 files changed

+118
-8
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 4.7.1 (2022-07-19)
4+
5+
* `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552))
6+
* `ERC165Checker`: Fix an issue that causes `supportsInterface` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552))
7+
38
## 4.7.0 (2022-06-29)
49

510
* `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317))

contracts/mocks/ERC1271WalletMockUpgradeable.sol

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,24 @@ contract ERC1271WalletMockUpgradeable is Initializable, OwnableUpgradeable, IERC
2828
*/
2929
uint256[50] private __gap;
3030
}
31+
32+
contract ERC1271MaliciousMockUpgradeable is Initializable, IERC1271Upgradeable {
33+
function __ERC1271MaliciousMock_init() internal onlyInitializing {
34+
}
35+
36+
function __ERC1271MaliciousMock_init_unchained() internal onlyInitializing {
37+
}
38+
function isValidSignature(bytes32, bytes memory) public pure override returns (bytes4) {
39+
assembly {
40+
mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
41+
return(0, 32)
42+
}
43+
}
44+
45+
/**
46+
* @dev This empty reserved space is put in place to allow future versions to add new
47+
* variables without shifting down storage in the inheritance chain.
48+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
49+
*/
50+
uint256[50] private __gap;
51+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
import "../../proxy/utils/Initializable.sol";
5+
6+
contract ERC165MaliciousDataUpgradeable is Initializable {
7+
function __ERC165MaliciousData_init() internal onlyInitializing {
8+
}
9+
10+
function __ERC165MaliciousData_init_unchained() internal onlyInitializing {
11+
}
12+
function supportsInterface(bytes4) public view returns (bool) {
13+
assembly {
14+
mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
15+
return(0, 32)
16+
}
17+
}
18+
19+
/**
20+
* @dev This empty reserved space is put in place to allow future versions to add new
21+
* variables without shifting down storage in the inheritance chain.
22+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
23+
*/
24+
uint256[50] private __gap;
25+
}

contracts/mocks/WithInit.sol

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ contract ERC1271WalletMockUpgradeableWithInit is ERC1271WalletMockUpgradeable {
132132
__ERC1271WalletMock_init(originalOwner);
133133
}
134134
}
135+
import "./ERC1271WalletMockUpgradeable.sol";
136+
137+
contract ERC1271MaliciousMockUpgradeableWithInit is ERC1271MaliciousMockUpgradeable {
138+
constructor() payable initializer {
139+
__ERC1271MaliciousMock_init();
140+
}
141+
}
135142
import "./SignatureCheckerMockUpgradeable.sol";
136143

137144
contract SignatureCheckerMockUpgradeableWithInit is SignatureCheckerMockUpgradeable {
@@ -1079,6 +1086,13 @@ contract DummyImplementationV2UpgradeableWithInit is DummyImplementationV2Upgrad
10791086
__DummyImplementationV2_init();
10801087
}
10811088
}
1089+
import "./ERC165/ERC165MaliciousDataUpgradeable.sol";
1090+
1091+
contract ERC165MaliciousDataUpgradeableWithInit is ERC165MaliciousDataUpgradeable {
1092+
constructor() payable initializer {
1093+
__ERC165MaliciousData_init();
1094+
}
1095+
}
10821096
import "./ERC165/ERC165MissingDataUpgradeable.sol";
10831097

10841098
contract ERC165MissingDataUpgradeableWithInit is ERC165MissingDataUpgradeable {

contracts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@openzeppelin/contracts-upgradeable",
33
"description": "Secure Smart Contract library for Solidity",
4-
"version": "4.7.0",
4+
"version": "4.7.1",
55
"files": [
66
"**/*.sol",
77
"/build/contracts/*.json",

contracts/utils/cryptography/SignatureCheckerUpgradeable.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
// OpenZeppelin Contracts (last updated v4.5.0) (utils/cryptography/SignatureChecker.sol)
2+
// OpenZeppelin Contracts (last updated v4.7.1) (utils/cryptography/SignatureChecker.sol)
33

44
pragma solidity ^0.8.0;
55

@@ -35,6 +35,8 @@ library SignatureCheckerUpgradeable {
3535
(bool success, bytes memory result) = signer.staticcall(
3636
abi.encodeWithSelector(IERC1271Upgradeable.isValidSignature.selector, hash, signature)
3737
);
38-
return (success && result.length == 32 && abi.decode(result, (bytes4)) == IERC1271Upgradeable.isValidSignature.selector);
38+
return (success &&
39+
result.length == 32 &&
40+
abi.decode(result, (bytes32)) == bytes32(IERC1271Upgradeable.isValidSignature.selector));
3941
}
4042
}

contracts/utils/introspection/ERC165CheckerUpgradeable.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol)
2+
// OpenZeppelin Contracts (last updated v4.7.1) (utils/introspection/ERC165Checker.sol)
33

44
pragma solidity ^0.8.0;
55

@@ -108,6 +108,6 @@ library ERC165CheckerUpgradeable {
108108
bytes memory encodedParams = abi.encodeWithSelector(IERC165Upgradeable.supportsInterface.selector, interfaceId);
109109
(bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams);
110110
if (result.length < 32) return false;
111-
return success && abi.decode(result, (bool));
111+
return success && abi.decode(result, (uint256)) > 0;
112112
}
113113
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"private": true,
33
"name": "openzeppelin-solidity",
44
"description": "Secure Smart Contract library for Solidity",
5-
"version": "4.7.0",
5+
"version": "4.7.1",
66
"files": [
77
"/contracts/**/*.sol",
88
"/build/contracts/*.json",

test/utils/cryptography/SignatureChecker.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { expect } = require('chai');
44

55
const SignatureCheckerMock = artifacts.require('SignatureCheckerMock');
66
const ERC1271WalletMock = artifacts.require('ERC1271WalletMock');
7+
const ERC1271MaliciousMock = artifacts.require('ERC1271MaliciousMock');
78

89
const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin');
910
const WRONG_MESSAGE = web3.utils.sha3('Nope');
@@ -14,6 +15,7 @@ contract('SignatureChecker (ERC1271)', function (accounts) {
1415
before('deploying', async function () {
1516
this.signaturechecker = await SignatureCheckerMock.new();
1617
this.wallet = await ERC1271WalletMock.new(signer);
18+
this.malicious = await ERC1271MaliciousMock.new();
1719
this.signature = await web3.eth.sign(TEST_MESSAGE, signer);
1820
});
1921

@@ -67,5 +69,13 @@ contract('SignatureChecker (ERC1271)', function (accounts) {
6769
this.signature,
6870
)).to.equal(false);
6971
});
72+
73+
it('with malicious wallet', async function () {
74+
expect(await this.signaturechecker.isValidSignatureNow(
75+
this.malicious.address,
76+
toEthSignedMessageHash(TEST_MESSAGE),
77+
this.signature,
78+
)).to.equal(false);
79+
});
7080
});
7181
});

test/utils/introspection/ERC165Checker.test.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { expect } = require('chai');
44

55
const ERC165CheckerMock = artifacts.require('ERC165CheckerMock');
66
const ERC165MissingData = artifacts.require('ERC165MissingData');
7+
const ERC165MaliciousData = artifacts.require('ERC165MaliciousData');
78
const ERC165NotSupported = artifacts.require('ERC165NotSupported');
89
const ERC165InterfacesSupported = artifacts.require('ERC165InterfacesSupported');
910

@@ -46,6 +47,38 @@ contract('ERC165Checker', function (accounts) {
4647
});
4748
});
4849

50+
context('ERC165 malicious return data', function () {
51+
beforeEach(async function () {
52+
this.target = await ERC165MaliciousData.new();
53+
});
54+
55+
it('does not support ERC165', async function () {
56+
const supported = await this.mock.supportsERC165(this.target.address);
57+
expect(supported).to.equal(false);
58+
});
59+
60+
it('does not support mock interface via supportsInterface', async function () {
61+
const supported = await this.mock.supportsInterface(this.target.address, DUMMY_ID);
62+
expect(supported).to.equal(false);
63+
});
64+
65+
it('does not support mock interface via supportsAllInterfaces', async function () {
66+
const supported = await this.mock.supportsAllInterfaces(this.target.address, [DUMMY_ID]);
67+
expect(supported).to.equal(false);
68+
});
69+
70+
it('does not support mock interface via getSupportedInterfaces', async function () {
71+
const supported = await this.mock.getSupportedInterfaces(this.target.address, [DUMMY_ID]);
72+
expect(supported.length).to.equal(1);
73+
expect(supported[0]).to.equal(false);
74+
});
75+
76+
it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () {
77+
const supported = await this.mock.supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID);
78+
expect(supported).to.equal(true);
79+
});
80+
});
81+
4982
context('ERC165 not supported', function () {
5083
beforeEach(async function () {
5184
this.target = await ERC165NotSupported.new();

0 commit comments

Comments
 (0)