Skip to content

Commit

Permalink
Mount a tmpfs at /dev/shm in the sandbox.
Browse files Browse the repository at this point in the history
...To get shm_open() and friends working.

Fixes #3196.
  • Loading branch information
zenhack committed Mar 10, 2020
1 parent 3168f0b commit 161f4bb
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 3 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ NODE_HEADERS=$(METEOR_DEV_BUNDLE)/include/node
WARNINGS=-Wall -Wextra -Wglobal-constructors -Wno-sign-compare -Wno-unused-parameter
CXXFLAGS2=-std=c++1z $(WARNINGS) $(CXXFLAGS) -DSANDSTORM_BUILD=$(BUILD) -DKJ_HAS_OPENSSL -DKJ_HAS_ZLIB -DKJ_HAS_LIBDL -pthread -fPIC -I$(NODE_HEADERS) -DKJ_STD_COMPAT
CFLAGS2=$(CFLAGS) -pthread -fPIC -DKJ_STD_COMPAT
LIBS2=$(LIBS) deps/libsodium/build/src/libsodium/.libs/libsodium.a deps/boringssl/build/ssl/libssl.a deps/boringssl/build/crypto/libcrypto.a -lz -ldl -pthread
# -lrt is not used by sandstorm itself, but the test app uses it. It would be
# nice if we could not link everything against it.
LIBS2=$(LIBS) deps/libsodium/build/src/libsodium/.libs/libsodium.a deps/boringssl/build/ssl/libssl.a deps/boringssl/build/crypto/libcrypto.a -lz -ldl -pthread -lrt

define color
printf '\033[0;34m==== $1 ====\033[0m\n'
Expand Down
21 changes: 19 additions & 2 deletions src/sandstorm/supervisor.c++
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,12 @@ void SupervisorMain::makeCharDeviceNode(
KJ_SYSCALL(mount(kj::str("/dev/", realName).cStr(), dst.cStr(), nullptr, MS_BIND, nullptr));
}

void mountTmpFs(const char *name, const char *dest) {
KJ_SYSCALL(mount(name, dest, "tmpfs",
MS_NOSUID | MS_NODEV,
"size=16m,nr_inodes=4k,mode=770"));
}

void SupervisorMain::setupFilesystem() {
// The root of our mount namespace will be the app package itself. We optionally create
// tmp, dev, and var. tmp is an ordinary tmpfs. dev is a read-only tmpfs that contains
Expand Down Expand Up @@ -986,8 +992,7 @@ void SupervisorMain::setupFilesystem() {
// 2) When we exit, the mount namespace disappears and the tmpfs is thus automatically
// unmounted. No need for careful cleanup, and no need to implement a risky recursive
// delete.
KJ_SYSCALL(mount("sandstorm-tmp", "tmp", "tmpfs", MS_NOSUID,
"size=16m,nr_inodes=4k,mode=770"));
mountTmpFs("sandstorm-tmp", "tmp");
}
if (access("dev", F_OK) == 0) {
KJ_SYSCALL(mount("sandstorm-dev", "dev", "tmpfs",
Expand All @@ -997,6 +1002,18 @@ void SupervisorMain::setupFilesystem() {
makeCharDeviceNode("zero", "zero", 1, 5);
makeCharDeviceNode("random", "urandom", 1, 9);
makeCharDeviceNode("urandom", "urandom", 1, 9);

// Create /dev/shm so shm_open() and friends work. Note that even though /dev
// is already a tmpfs, we need to mount a separate tmpfs for /dev/shm, because
// the former will be read-only.
//
// TODO: it might be nice to have /dev/shm and /tmp share the same partition,
// so we don't have to strictly separate their storage capacity. We could mount
// a single tmpfs somewhere invisible, create subdirectories, and then bind-mount
// them to their final destinations.
mkdir("/dev/shm", 0700);
mountTmpFs("sandstorm-shm", "/dev/shm");

KJ_SYSCALL(mount("dev", "dev", nullptr,
MS_REMOUNT | MS_BIND | MS_NOEXEC | MS_NOSUID | MS_NODEV | MS_RDONLY,
nullptr));
Expand Down
41 changes: 41 additions & 0 deletions src/sandstorm/test-app/test-app.c++
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#include <map>

#include <sys/time.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <kj/main.h>
#include <kj/debug.h>
Expand Down Expand Up @@ -93,6 +97,40 @@ private:

// =======================================================================================

void testSystemApi() {
// Test that some syscalls & platform APIs work as expected. Print a success
// message to the console so the test suite can verify this.

std::cout << "Testing System APIs" << std::endl;

auto result = kj::runCatchingExceptions([]() {
// Test use of /dev/shm:
const char *obj_name = "/shome-shm-obj";
int shm_fd;
KJ_SYSCALL(shm_fd = shm_open(obj_name, O_RDWR|O_CREAT, 0700));
KJ_DEFER(KJ_SYSCALL(shm_unlink(obj_name)));

KJ_ASSERT(close(shm_fd) == 0, "Closing shm_fd failed");

// Make sure the mapping actually works:
int *mapped = (int *)mmap(
nullptr, sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0
);
KJ_ASSERT(mapped != nullptr, "mmap() failed");
KJ_SYSCALL(munmap(mapped, sizeof(int)));
});

KJ_IF_MAYBE(exception, result) {
auto msg = kj::str(*exception);
std::cout << msg.cStr() << std::endl;
throw(*exception);
}

std::cout << "testSystemApi() passed." << std::endl;
}

// =======================================================================================

class WebSessionImpl final: public sandstorm::WebSession::Server {
public:
WebSessionImpl(sandstorm::UserInfo::Reader userInfo,
Expand Down Expand Up @@ -148,6 +186,9 @@ public:
httpResponse.setMimeType("text/plain");
httpResponse.getBody().setBytes(response.getText().asBytes());
});
} else if(path == "test-system-api") {
testSystemApi();
return kj::READY_NOW;
} else if(path == "schedule") {
context.getResults().initNoContent();
// Put the extra headers in a map, so we can easily look for specific ones:
Expand Down
2 changes: 2 additions & 0 deletions src/sandstorm/test-app/test-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,7 @@ <h1>Test App</h1>

<p><button onclick="postScheduledJob({shouldCancel: false, refStr: 'oneshot'})" id="do-schedule-oneshot">
Schedule a one-shot job.</button></p>

<p><button onclick="doPost('/test-system-api', '')" id="do-test-system-api">Test the system api.</button></p>
</body>
</html>

0 comments on commit 161f4bb

Please sign in to comment.