Linux: Don't access file system outside of core

This patch changes the way of how dataspace content is accessed by
processes outside of core. Dataspaces are opened by core only and the
corresponding file descriptors are handed out the other processes via
the 'Linux_dataspace::fd()' RPC function. At the client side, the
returned file descriptor is then used to mmap the file.

Consequently, this patch eliminates all files from 'lx_rpath'. The
path is still needed by core to temporarily create dataspaces and
unix domain sockets. However, those files are unlinked immediately
after their creation.
This commit is contained in:
Norman Feske 2012-08-10 14:21:26 +02:00
parent aee0a2061b
commit 7cb45e9648
7 changed files with 86 additions and 43 deletions

View File

@ -40,7 +40,8 @@ namespace Genode {
** Linux-specific dataspace interface **
****************************************/
Filename fname() { return call<Rpc_fname>(); }
Filename fname() { return call<Rpc_fname>(); }
Untyped_capability fd() { return call<Rpc_fd>(); }
};
}

View File

@ -24,23 +24,31 @@ namespace Genode {
struct Linux_dataspace : Dataspace
{
enum { FNAME_LEN = 32 };
struct Filename { char buf[FNAME_LEN]; };
virtual ~Linux_dataspace() { }
/**
* Request name of file that represents the dataspace on Linux
*
* This function is used for calling execve on files passed as ROM
* dataspaces.
*/
virtual Filename fname() = 0;
/**
* Request file descriptor of the dataspace
*/
virtual Untyped_capability fd() = 0;
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_fname, Filename, fname);
GENODE_RPC_INTERFACE_INHERIT(Dataspace, Rpc_fname);
GENODE_RPC(Rpc_fd, Untyped_capability, fd);
GENODE_RPC_INTERFACE_INHERIT(Dataspace, Rpc_fname, Rpc_fd);
};
}

View File

@ -46,29 +46,30 @@ static void *map_local(Dataspace_capability ds, Genode::size_t size,
addr_t offset, bool use_local_addr, addr_t local_addr,
bool executable)
{
Linux_dataspace::Filename fname = Linux_dataspace_client(ds).fname();
fname.buf[sizeof(fname.buf) - 1] = 0;
int const fd = Linux_dataspace_client(ds).fd().dst().socket;
bool const writable = Dataspace_client(ds).writable();
bool writable = Dataspace_client(ds).writable();
int fd = lx_open(fname.buf, (writable ? O_RDWR : O_RDONLY) | LX_O_CLOEXEC);
if (fd < 0) {
PERR("map_local: Could not open file \"%s\"", fname.buf);
throw Rm_session::Invalid_dataspace();
}
int flags = MAP_SHARED | (use_local_addr ? MAP_FIXED : 0);
int prot = PROT_READ | (writable ? PROT_WRITE : 0) | (executable ? PROT_EXEC : 0);
void *addr = lx_mmap(use_local_addr ? (void*)local_addr : 0, size,
prot, flags, fd, offset);
int const flags = MAP_SHARED | (use_local_addr ? MAP_FIXED : 0);
int const prot = PROT_READ
| (writable ? PROT_WRITE : 0)
| (executable ? PROT_EXEC : 0);
void * const addr_in = use_local_addr ? (void*)local_addr : 0;
void * const addr_out = lx_mmap(addr_in, size, prot, flags, fd, offset);
/*
* We can close the file after calling mmap. The Linux kernel will still
* keep the file mapped. By immediately closing the file descriptor, we
* won't need to keep track of dataspace file descriptors within the
* process.
*/
lx_close(fd);
if (((long)addr < 0) && ((long)addr > -4095)) {
PERR("map_local: return value of mmap is %ld", (long)addr);
if (((long)addr_out < 0) && ((long)addr_out > -4095)) {
PERR("map_local: return value of mmap is %ld", (long)addr_out);
throw Rm_session::Region_conflict();
}
return addr;
return addr_out;
}

View File

@ -39,6 +39,7 @@ namespace Genode {
size_t _size; /* size of dataspace in bytes */
addr_t _addr; /* meaningless on linux */
Filename _fname; /* filename for mmap */
int _fd; /* file descriptor */
bool _writable; /* false if read-only */
/* Holds the dataspace owner if a distinction between owner and
@ -53,14 +54,14 @@ namespace Genode {
Dataspace_component(size_t size, addr_t addr,
bool /* write_combined */, bool writable,
Dataspace_owner * owner)
: _size(size), _addr(addr), _writable(writable),
: _size(size), _addr(addr), _fd(-1), _writable(writable),
_owner(owner) { }
/**
* Default constructor returns invalid dataspace
*/
Dataspace_component() : _size(0), _addr(0), _writable(false),
_owner(0) { }
Dataspace_component()
: _size(0), _addr(0), _fd(-1), _writable(false), _owner(0) { }
/**
* This constructor is only provided for compatibility
@ -69,20 +70,29 @@ namespace Genode {
Dataspace_component(size_t size, addr_t core_local_addr,
addr_t phys_addr, bool write_combined,
bool writable, Dataspace_owner * _owner)
: _size(size), _addr(phys_addr), _owner(_owner)
:
_size(size), _addr(phys_addr), _fd(-1), _owner(_owner)
{
PWRN("Should only be used for IOMEM and not within Linux.");
_fname.buf[0] = 0;
}
/**
* Define/request corresponding filename of dataspace
* Define corresponding filename of dataspace
*
* To use dataspaces as shared memory objects on Linux, we have to
* assign a file to each dataspace. This way, multiple Linux process
* can mmap this file.
* The file name is only relevant for ROM dataspaces that should
* be executed via execve.
*/
void fname(const char *fname) { strncpy(_fname.buf, fname, sizeof(_fname.buf)); }
/**
* Assign file descriptor to dataspace
*
* The file descriptor assigned to the dataspace will be enable
* processes outside of core to mmap the dataspace.
*/
void fd(int fd) { _fd = fd; }
/**
* Check if dataspace is owned by a specified object
*/
@ -102,6 +112,13 @@ namespace Genode {
****************************************/
Filename fname() { return _fname; }
Untyped_capability fd()
{
typedef Untyped_capability::Dst Dst;
enum { DUMMY_LOCAL_NAME = 0 };
return Untyped_capability(Dst(_fd), DUMMY_LOCAL_NAME);
}
};
}

View File

@ -32,24 +32,32 @@ static int ram_ds_cnt = 0; /* counter for creating unique dataspace IDs */
void Ram_session_component::_export_ram_ds(Dataspace_component *ds)
{
char fname_buf[Linux_dataspace::FNAME_LEN];
char fname[Linux_dataspace::FNAME_LEN];
/* assign filename to dataspace */
snprintf(fname_buf, sizeof(fname_buf), "%s/ds-%d", lx_rpath(), ram_ds_cnt++);
ds->fname(fname_buf);
/* create new file representing the dataspace */
lx_unlink(fname_buf);
int fd = lx_open(fname_buf, O_CREAT | O_RDWR | O_TRUNC | LX_O_CLOEXEC, S_IRWXU);
/* create file using a unique file name in 'lx_rpath' */
snprintf(fname, sizeof(fname), "%s/ds-%d", lx_rpath(), ram_ds_cnt++);
lx_unlink(fname);
int const fd = lx_open(fname, O_CREAT|O_RDWR|O_TRUNC|LX_O_CLOEXEC, S_IRWXU);
lx_ftruncate(fd, ds->size());
lx_close(fd);
/* remember file descriptor in dataspace component object */
ds->fd(fd);
/*
* Wipe the file from the Linux file system. The kernel will still keep the
* then unnamed file around until the last reference to the file will be
* gone (i.e., an open file descriptor referring to the file). A process
* w/o the right file descriptor won't be able to open and access the file.
*/
lx_unlink(fname);
}
void Ram_session_component::_revoke_ram_ds(Dataspace_component *ds)
{
lx_unlink(ds->fname().buf);
int const fd = ds->fd().dst().socket;
if (fd != -1)
lx_close(fd);
}

View File

@ -45,15 +45,15 @@ Rom_session_component::Rom_session_component(Rom_fs *rom_fs,
: _ds_ep(ds_ep)
{
/* extract filename from session arguments */
char fname_buf[Linux_dataspace::FNAME_LEN];
Arg_string::find_arg(args, "filename").string(fname_buf, sizeof(fname_buf), "");
char fname[Linux_dataspace::FNAME_LEN];
Arg_string::find_arg(args, "filename").string(fname, sizeof(fname), "");
/* only files inside the current working directory are allowed */
for (const char *c = fname_buf; *c; c++)
for (const char *c = fname; *c; c++)
if (*c == '/')
throw Root::Invalid_args();
Genode::size_t fsize = file_size(fname_buf);
Genode::size_t const fsize = file_size(fname);
/* use invalid capability as default value */
_ds_cap = Rom_dataspace_capability();
@ -62,8 +62,11 @@ Rom_session_component::Rom_session_component(Rom_fs *rom_fs,
if (fsize == 0)
throw Root::Invalid_args();
int const fd = lx_open(fname, O_RDONLY | LX_O_CLOEXEC, S_IRUSR | S_IXUSR);
_ds = Dataspace_component(fsize, 0, false, false, 0);
_ds.fname(fname_buf);
_ds.fd(fd);
_ds.fname(fname);
Dataspace_capability ds_cap = _ds_ep->manage(&_ds);
_ds_cap = static_cap_cast<Rom_dataspace>(ds_cap);
@ -73,4 +76,8 @@ Rom_session_component::Rom_session_component(Rom_fs *rom_fs,
Rom_session_component::~Rom_session_component()
{
_ds_ep->dissolve(&_ds);
int const fd = _ds.fd().dst().socket;
if (fd != -1)
lx_close(fd);
}

View File

@ -38,6 +38,7 @@
#include <sched.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/fcntl.h>
/* Genode includes */
#include <util/string.h>