Skip to content

Commit b5489de

Browse files
committed
Merge pull request #376 from chriseth/nobreakout
Only allow including from allowed directories.
2 parents bdbb7d8 + 02161b2 commit b5489de

File tree

4 files changed

+50
-11
lines changed

4 files changed

+50
-11
lines changed

docs/layout-of-source-files.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@ and then run the compiler as
7171

7272
`solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol`
7373

74+
Note that solc only allows you to include files from certain directories:
75+
They have to be in the directory (or subdirectory) of one of the explicitly
76+
specified source files or in the directory (or subdirectory) of a remapping
77+
target. If you want to allow direct absolute includes, just add the
78+
remapping `=/`.
79+
80+
If there are multiple remappings that lead to a valid file, the remapping
81+
with the longest common prefix is chosen.
82+
7483
**browser-solidity**:
7584

7685
The `browser-based compiler <https://chriseth.github.io/browser-solidity>`_

docs/miscellaneous.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,11 @@ it is also possible to provide path redirects using `prefix=path` in the followi
111111
This essentially instructs the compiler to search for anything starting with
112112
`github.com/ethereum/dapp-bin/` under `/usr/local/lib/dapp-bin` and if it does not
113113
find the file there, it will look at `/usr/local/lib/fallback` (the empty prefix
114-
always matches) and if also that fails, it will make a full path lookup
115-
on the filesystem.
114+
always matches). `solc` will not read files from the filesystem that lie outside of
115+
the remapping targets and outside of the directories where explicitly specified source
116+
files reside, so things like `import "/etc/passwd";` only work if you add `=/` as a remapping.
117+
118+
If there are multiple matches due to remappings, the one with the longest common prefix is selected.
116119

117120
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:
118121

solc/CommandLineInterface.cpp

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <fstream>
2828

2929
#include <boost/filesystem.hpp>
30+
#include <boost/filesystem/operations.hpp>
3031
#include <boost/algorithm/string.hpp>
3132

3233
#include "solidity/BuildInfo.h"
@@ -313,10 +314,11 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
313314
{
314315
auto eq = find(infile.begin(), infile.end(), '=');
315316
if (eq != infile.end())
316-
m_remappings.push_back(make_pair(
317-
string(infile.begin(), eq),
318-
string(eq + 1, infile.end())
319-
));
317+
{
318+
string target(eq + 1, infile.end());
319+
m_remappings.push_back(make_pair(string(infile.begin(), eq), target));
320+
m_allowedDirectories.push_back(boost::filesystem::path(target).remove_filename());
321+
}
320322
else
321323
{
322324
auto path = boost::filesystem::path(infile);
@@ -332,7 +334,8 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
332334
continue;
333335
}
334336

335-
m_sourceCodes[infile] = dev::contentsString(infile);
337+
m_sourceCodes[path.string()] = dev::contentsString(path.string());
338+
m_allowedDirectories.push_back(boost::filesystem::canonical(path).remove_filename());
336339
}
337340
}
338341
// Add empty remapping to try the path itself.
@@ -515,8 +518,9 @@ bool CommandLineInterface::processInput()
515518

516519
function<pair<string,string>(string const&)> fileReader = [this](string const& _path)
517520
{
518-
// Try to find the longest prefix match in all remappings. At the end, there will be an
519-
// empty remapping so that we also try the path itself.
521+
// Try to find the longest prefix match in all remappings. At the end, there will bean
522+
// empty remapping so that we also try the path itself, but any file should be either
523+
// in (a subdirectory of) the directory of an explicit source or a remapping target.
520524
int errorLevel = 0;
521525
size_t longestPrefix = 0;
522526
string bestMatchPath;
@@ -531,7 +535,26 @@ bool CommandLineInterface::processInput()
531535
path.append(_path.begin() + virt.length(), _path.end());
532536
auto boostPath = boost::filesystem::path(path);
533537
if (!boost::filesystem::exists(boostPath))
538+
{
534539
errorLevel = max(errorLevel, 0);
540+
continue;
541+
}
542+
boostPath = boost::filesystem::canonical(boostPath);
543+
bool isAllowed = false;
544+
for (auto const& dir: m_allowedDirectories)
545+
{
546+
// If dir is a prefix of boostPath, we are fine.
547+
if (
548+
std::distance(dir.begin(), dir.end()) <= std::distance(boostPath.begin(), boostPath.end()) &&
549+
std::equal(dir.begin(), dir.end(), boostPath.begin())
550+
)
551+
{
552+
isAllowed = true;
553+
break;
554+
}
555+
}
556+
if (!isAllowed)
557+
errorLevel = max(errorLevel, 2);
535558
else if (!boost::filesystem::is_regular_file(boostPath))
536559
errorLevel = max(errorLevel, 1);
537560
else
@@ -544,9 +567,10 @@ bool CommandLineInterface::processInput()
544567
return make_pair(m_sourceCodes[bestMatchPath] = dev::contentsString(bestMatchPath), string());
545568
if (errorLevel == 0)
546569
return make_pair(string(), string("File not found."));
547-
else
570+
else if (errorLevel == 1)
548571
return make_pair(string(), string("Not a valid file."));
549-
572+
else
573+
return make_pair(string(), string("File outside of allowed directories."));
550574
};
551575

552576
m_compiler.reset(new CompilerStack(m_args.count(g_argAddStandard) > 0, fileReader));

solc/CommandLineInterface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <libsolidity/interface/CompilerStack.h>
2525
#include <memory>
2626
#include <boost/program_options.hpp>
27+
#include <boost/filesystem/path.hpp>
2728

2829
namespace dev
2930
{
@@ -80,6 +81,8 @@ class CommandLineInterface
8081
std::map<std::string, std::string> m_sourceCodes;
8182
/// list of path prefix remappings, e.g. github.com/ethereum -> /usr/local/ethereum
8283
std::vector<std::pair<std::string, std::string>> m_remappings;
84+
/// list of allowed directories to read files from
85+
std::vector<boost::filesystem::path> m_allowedDirectories;
8386
/// map of library names to addresses
8487
std::map<std::string, h160> m_libraries;
8588
/// Solidity compiler stack

0 commit comments

Comments
 (0)