Merge pull request #376 from chriseth/nobreakout

Only allow including from allowed directories.
This commit is contained in:
chriseth 2016-01-30 15:37:28 +01:00
commit b5489de1f0
4 changed files with 50 additions and 11 deletions

View File

@ -71,6 +71,15 @@ and then run the compiler as
`solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol` `solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol`
Note that solc only allows you to include files from certain directories:
They have to be in the directory (or subdirectory) of one of the explicitly
specified source files or in the directory (or subdirectory) of a remapping
target. If you want to allow direct absolute includes, just add the
remapping `=/`.
If there are multiple remappings that lead to a valid file, the remapping
with the longest common prefix is chosen.
**browser-solidity**: **browser-solidity**:
The `browser-based compiler <https://chriseth.github.io/browser-solidity>`_ The `browser-based compiler <https://chriseth.github.io/browser-solidity>`_

View File

@ -111,8 +111,11 @@ it is also possible to provide path redirects using `prefix=path` in the followi
This essentially instructs the compiler to search for anything starting with This essentially instructs the compiler to search for anything starting with
`github.com/ethereum/dapp-bin/` under `/usr/local/lib/dapp-bin` and if it does not `github.com/ethereum/dapp-bin/` under `/usr/local/lib/dapp-bin` and if it does not
find the file there, it will look at `/usr/local/lib/fallback` (the empty prefix find the file there, it will look at `/usr/local/lib/fallback` (the empty prefix
always matches) and if also that fails, it will make a full path lookup always matches). `solc` will not read files from the filesystem that lie outside of
on the filesystem. the remapping targets and outside of the directories where explicitly specified source
files reside, so things like `import "/etc/passwd";` only work if you add `=/` as a remapping.
If there are multiple matches due to remappings, the one with the longest common prefix is selected.
If your contracts use [libraries](#libraries), you will notice that the bytecode contains substrings of the form `__LibraryName______`. You can use `solc` as a linker meaning that it will insert the library addresses for you at those points: If your contracts use [libraries](#libraries), you will notice that the bytecode contains substrings of the form `__LibraryName______`. You can use `solc` as a linker meaning that it will insert the library addresses for you at those points:

View File

@ -27,6 +27,7 @@
#include <fstream> #include <fstream>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "solidity/BuildInfo.h" #include "solidity/BuildInfo.h"
@ -313,10 +314,11 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
{ {
auto eq = find(infile.begin(), infile.end(), '='); auto eq = find(infile.begin(), infile.end(), '=');
if (eq != infile.end()) if (eq != infile.end())
m_remappings.push_back(make_pair( {
string(infile.begin(), eq), string target(eq + 1, infile.end());
string(eq + 1, infile.end()) m_remappings.push_back(make_pair(string(infile.begin(), eq), target));
)); m_allowedDirectories.push_back(boost::filesystem::path(target).remove_filename());
}
else else
{ {
auto path = boost::filesystem::path(infile); auto path = boost::filesystem::path(infile);
@ -332,7 +334,8 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
continue; continue;
} }
m_sourceCodes[infile] = dev::contentsString(infile); m_sourceCodes[path.string()] = dev::contentsString(path.string());
m_allowedDirectories.push_back(boost::filesystem::canonical(path).remove_filename());
} }
} }
// Add empty remapping to try the path itself. // Add empty remapping to try the path itself.
@ -515,8 +518,9 @@ bool CommandLineInterface::processInput()
function<pair<string,string>(string const&)> fileReader = [this](string const& _path) function<pair<string,string>(string const&)> fileReader = [this](string const& _path)
{ {
// Try to find the longest prefix match in all remappings. At the end, there will be an // Try to find the longest prefix match in all remappings. At the end, there will bean
// empty remapping so that we also try the path itself. // empty remapping so that we also try the path itself, but any file should be either
// in (a subdirectory of) the directory of an explicit source or a remapping target.
int errorLevel = 0; int errorLevel = 0;
size_t longestPrefix = 0; size_t longestPrefix = 0;
string bestMatchPath; string bestMatchPath;
@ -531,7 +535,26 @@ bool CommandLineInterface::processInput()
path.append(_path.begin() + virt.length(), _path.end()); path.append(_path.begin() + virt.length(), _path.end());
auto boostPath = boost::filesystem::path(path); auto boostPath = boost::filesystem::path(path);
if (!boost::filesystem::exists(boostPath)) if (!boost::filesystem::exists(boostPath))
{
errorLevel = max(errorLevel, 0); errorLevel = max(errorLevel, 0);
continue;
}
boostPath = boost::filesystem::canonical(boostPath);
bool isAllowed = false;
for (auto const& dir: m_allowedDirectories)
{
// If dir is a prefix of boostPath, we are fine.
if (
std::distance(dir.begin(), dir.end()) <= std::distance(boostPath.begin(), boostPath.end()) &&
std::equal(dir.begin(), dir.end(), boostPath.begin())
)
{
isAllowed = true;
break;
}
}
if (!isAllowed)
errorLevel = max(errorLevel, 2);
else if (!boost::filesystem::is_regular_file(boostPath)) else if (!boost::filesystem::is_regular_file(boostPath))
errorLevel = max(errorLevel, 1); errorLevel = max(errorLevel, 1);
else else
@ -544,9 +567,10 @@ bool CommandLineInterface::processInput()
return make_pair(m_sourceCodes[bestMatchPath] = dev::contentsString(bestMatchPath), string()); return make_pair(m_sourceCodes[bestMatchPath] = dev::contentsString(bestMatchPath), string());
if (errorLevel == 0) if (errorLevel == 0)
return make_pair(string(), string("File not found.")); return make_pair(string(), string("File not found."));
else else if (errorLevel == 1)
return make_pair(string(), string("Not a valid file.")); return make_pair(string(), string("Not a valid file."));
else
return make_pair(string(), string("File outside of allowed directories."));
}; };
m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0, fileReader)); m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0, fileReader));

View File

@ -24,6 +24,7 @@
#include <libsolidity/interface/CompilerStack.h> #include <libsolidity/interface/CompilerStack.h>
#include <memory> #include <memory>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <boost/filesystem/path.hpp>
namespace dev namespace dev
{ {
@ -80,6 +81,8 @@ private:
std::map<std::string, std::string> m_sourceCodes; std::map<std::string, std::string> m_sourceCodes;
/// list of path prefix remappings, e.g. github.com/ethereum -> /usr/local/ethereum /// list of path prefix remappings, e.g. github.com/ethereum -> /usr/local/ethereum
std::vector<std::pair<std::string, std::string>> m_remappings; std::vector<std::pair<std::string, std::string>> m_remappings;
/// list of allowed directories to read files from
std::vector<boost::filesystem::path> m_allowedDirectories;
/// map of library names to addresses /// map of library names to addresses
std::map<std::string, h160> m_libraries; std::map<std::string, h160> m_libraries;
/// Solidity compiler stack /// Solidity compiler stack