Knowsec Blockchain Lab | Depth understanding of EVM storage mechanism and security issues

Introduction

EVM is a lightweight virtual machine designed to provide a virtual execution environment for the Ethereum network to run smart contracts regardless of hardware, operating system, and another compatibility.

EVM storage structure

code

When code deploys the contract, it stores the data field, which is the space of the contract content, that is, the space especially storing the binary source code of the smart contract.

Storage

Storage is a persistent Storage space where you can read, write, modify, and persist data for each contract. Storage is a large map with 2 ^ 256 slots (slots), each with 32 bytes, into which the state variables in the contract are stored, depending on their type.

Stack

The stack, known as the “run stack,” holds the input and output data of EVM instructions. Free to use, no gas consumption, the number of local variables used to hold functions is limited to 16.

Args

Args, also called CallData, is a read-only addressable space that holds the parameters of a function call. Unlike the stack, to use the data in the call data, you must manually specify the offset and the number of bytes to read.

Memory

Memory A simple array of bytes that primarily stores data at run time, passing arguments to internal functions. Addressing and extending based on 32byte.

Overview of EVM Datastores

Storage is a place where data is stored persistently by each contract. The way to store data is through slots. Now we will introduce how it is implemented:

State variables

1. Variables (constants) whose size is less than 32 bytes are stored as their index values in the order they are defined. The first variable has the index key(0) and the second variable key(1)…

pragma solidity ^0.4.11;

contract C {

uint256 a = 12;
uint256 c = 12;
uint256 b = 12;
uint256 d = 12;
function m() view public returns(uint256,uint256,uint256,uint256){
return (a,b,c,d);
}

}
pragma solidity ^0.4.11;

contract C {

uint64 a = 12;
uint64 c = 12;
uint64 b = 12;
uint64 d = 12;
function m() view public returns(uint64,uint64,uint64,uint64){
return (a,b,c,d);
}

}

The structure of the body

Structures with sizes less than 32 bytes are also stored sequentially. For example, if the structure variable index is defined at position 0 and there are two members inside the structure, the two members are stored sequentially as 0 and 1.

pragma solidity ^0.4.11;

contract C {

struct Info {
uint256 a ;
uint256 b ;
}
function m() external returns(uint256,uint256){
Info storage info;
info.a = 12 ;
info.b = 24 ;
return(info.a,info.b);
}


}

Map

The map storage location is calculated by kECCAK256 (Bytes32 (key) + Bytes32 (position)). Position indicates the storage location of the variable corresponding to the key.

pragma solidity ^0.4.11;

contract Test {
mapping(uint256 => uint256) knownsec;

function go() public {
knownsec[0x60] = 0x40;
}
}

Array

Fixed-length array

pragma solidity ^0.4.11;

contract C {

uint256[3] a = [12,24,48] ;

function m() public view returns(uint256,uint256,uint256){
return (a[0],a[1],a[2]);
}

}
pragma solidity ^0.4.11;

contract C {

uint256[3] a = [12,24,48] ;

function m() public view returns(uint256,uint256,uint256){
return (a[0],a[1],a[2]);
}

}

Byte arrays and strings

If the length is less than or equal to 31 bytes:

pragma solidity ^0.4.4;

contract A{
string public name0 = "knownsec";
bytes8 public name=0x6b6e6f776e736563;
bytes public g ;

function test() public {
g.push(0xAA);
g.push(0xBB);
g.push(0xCC);
}
function go() public view returns(bytes){
return g;
}
}
string public name = "knownsecooooooooooooooooooooooooo";

Security issues

The storage structure and storage mechanism of EVM have been mentioned before, now we will discuss its security.

Uninitialized variables

Principle of vulnerability:

pragma solidity ^0.4.0;

contract testContract{

bool public unlocked = false;

address public owner = 0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c;

struct Person {

bytes32 name;

address mappedAddress;

}

function test(bytes32 _name , address _mappedAddress) public{

Person person;

person.name = _name;

person.mappedAddress = _mappedAddress;

require(unlocked);

}


}

Conclusion

The EVM memory is a ‘key=>value’ database, and the stored data can be checksum to ensure consistency.