Support defining read-only filesystem access

If you do something like "--filesystem=host:ro" you get a read-only mount
of the specified filesystem location.
tingping/wmclass
Alexander Larsson 2015-11-26 17:22:37 +01:00
parent 612bf0d08c
commit f5cadc018b
2 changed files with 96 additions and 34 deletions

View File

@ -469,17 +469,18 @@ usage (char **argv)
fprintf (stderr,
" -a Specify path for application (mounted at /app)\n"
" -b DEST[=SOURCE] Bind extra source path readonly into DEST\n"
" -b DEST[=SOURCE] Bind extra source path read-only into DEST\n"
" -B DEST[=SOURCE] Bind extra source path into DEST\n"
" -M DEST[=SOURCE] Bind extra source path into DEST and remove original\n"
" -d SOCKETPATH Use SOCKETPATH as dbus session bus\n"
" -D SOCKETPATH Use SOCKETPATH as dbus system bus\n"
" -e Make /app/exports writable\n"
" -E Make /etc a pure symlink to /usr/etc\n"
" -f Mount the host filesystems\n"
" -F Mount the host filesystems\n"
" -f Mount the host filesystems read-only\n"
" -g Allow use of direct rendering graphics\n"
" -F Mount the host filesystems read-only\n"
" -H Mount the users home directory (implied by -f)\n"
" -H Mount the users home directory\n"
" -h Mount the users home directory read-only\n"
" -i Share IPC namespace with session\n"
" -I APPID Set app id (used to find app data)\n"
" -l Lock .ref files in all mounts\n"
@ -1565,7 +1566,7 @@ mount_extra_root_dirs (int readonly)
}
static void
create_homedir (int mount_real_home, const char *app_id)
create_homedir (int mount_real_home, int mount_home_ro, const char *app_id)
{
const char *home;
const char *relative_home;
@ -1586,10 +1587,12 @@ create_homedir (int mount_real_home, const char *app_id)
if (mount_real_home)
{
writable_home = home;
if (bind_mount (writable_home, relative_home, BIND_RECURSIVE))
if (bind_mount (writable_home, relative_home, BIND_RECURSIVE | (mount_home_ro ? BIND_READONLY : 0)))
die_with_error ("unable to mount %s", home);
}
else if (app_id != NULL)
if (app_id != NULL &&
(!mount_real_home || mount_home_ro))
{
app_id_dir = strconcat3 (home, "/.var/app/", app_id);
if (stat (app_id_dir, &st) == 0 && S_ISDIR (st.st_mode))
@ -2022,6 +2025,7 @@ main (int argc,
bool mount_host_fs = FALSE;
bool mount_host_fs_ro = FALSE;
bool mount_home = FALSE;
bool mount_home_ro = FALSE;
bool lock_files = FALSE;
bool writable = FALSE;
bool writable_app = FALSE;
@ -2044,7 +2048,7 @@ main (int argc,
clean_argv (argc, argv);
while ((c = getopt (argc, argv, "+inWwceEsfFHra:m:M:b:B:p:x:ly:d:D:v:I:gS:")) >= 0)
while ((c = getopt (argc, argv, "+inWwceEsfFHhra:m:M:b:B:p:x:ly:d:D:v:I:gS:")) >= 0)
{
switch (c)
{
@ -2110,11 +2114,11 @@ main (int argc,
create_etc_dir = FALSE;
break;
case 'f':
case 'F':
mount_host_fs = TRUE;
break;
case 'F':
case 'f':
mount_host_fs = TRUE;
mount_host_fs_ro = TRUE;
break;
@ -2127,6 +2131,11 @@ main (int argc,
mount_home = TRUE;
break;
case 'h':
mount_home = TRUE;
mount_home_ro = TRUE;
break;
case 'i':
ipc = TRUE;
break;
@ -2439,8 +2448,8 @@ main (int argc,
bind_mount ("/run/media", "run/media", BIND_RECURSIVE | (mount_host_fs_ro ? BIND_READONLY : 0));
}
if (!mount_host_fs)
create_homedir (mount_home, app_id);
if (!mount_host_fs || mount_host_fs_ro)
create_homedir (mount_home, mount_home_ro, app_id);
if (mount_host_fs || mount_home)
{
@ -2461,7 +2470,7 @@ main (int argc,
}
/* If the user has homedir access, also allow dconf run dir access */
bind_mount (dconf_run_path, get_relative_path (dconf_run_path), 0);
bind_mount (dconf_run_path, get_relative_path (dconf_run_path), BIND_READONLY);
free (dconf_run_path);
}

View File

@ -43,6 +43,12 @@ typedef enum {
XDG_APP_CONTEXT_SHARED_IPC = 1 << 1,
} XdgAppContextShares;
typedef enum {
XDG_APP_FILESYSTEM_MODE_READ_WRITE = 1,
XDG_APP_FILESYSTEM_MODE_READ_ONLY = 2,
} XdgAppFilesystemMode;
/* Same order as enum */
static const char *xdg_app_context_shares[] = {
"network",
@ -376,10 +382,36 @@ get_user_dir_from_string (const char *filesystem)
return -1;
}
static char *
parse_filesystem_flags (const char *filesystem, XdgAppFilesystemMode *mode)
{
gsize len = strlen (filesystem);
if (mode)
*mode = XDG_APP_FILESYSTEM_MODE_READ_WRITE;
if (g_str_has_suffix (filesystem, ":ro"))
{
len -= 3;
if (mode)
*mode = XDG_APP_FILESYSTEM_MODE_READ_ONLY;
}
else if (g_str_has_suffix (filesystem, ":rw"))
{
len -= 3;
if (mode)
*mode = XDG_APP_FILESYSTEM_MODE_READ_WRITE;
}
return g_strndup (filesystem, len);
}
static gboolean
xdg_app_context_verify_filesystem (const char *filesystem,
xdg_app_context_verify_filesystem (const char *filesystem_and_mode,
GError **error)
{
char *filesystem = parse_filesystem_flags (filesystem_and_mode, NULL);
if (strcmp (filesystem, "host") == 0)
return TRUE;
if (strcmp (filesystem, "home") == 0)
@ -400,14 +432,19 @@ static void
xdg_app_context_add_filesystem (XdgAppContext *context,
const char *what)
{
g_hash_table_insert (context->filesystems, g_strdup (what), GINT_TO_POINTER (1));
XdgAppFilesystemMode mode;
char *fs = parse_filesystem_flags (what, &mode);
g_hash_table_insert (context->filesystems, fs, GINT_TO_POINTER (mode));
}
static void
xdg_app_context_remove_filesystem (XdgAppContext *context,
const char *what)
{
g_hash_table_insert (context->filesystems, g_strdup (what), NULL);
g_hash_table_insert (context->filesystems,
parse_filesystem_flags (what, NULL),
NULL);
}
void
@ -650,7 +687,7 @@ static GOptionEntry context_options[] = {
{ "nosocket", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_nosocket_cb, "Don't expose socket to app", "SOCKET" },
{ "device", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_device_cb, "Expose device to app", "DEVICE" },
{ "nodevice", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_nodevice_cb, "Don't expose device to app", "DEVICE" },
{ "filesystem", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_filesystem_cb, "Expose filesystem to app", "FILESYSTEM" },
{ "filesystem", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_filesystem_cb, "Expose filesystem to app (:ro for read-only)", "FILESYSTEM[:ro]" },
{ "nofilesystem", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_nofilesystem_cb, "Don't expose filesystem to app", "FILESYSTEM" },
{ "env", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_env_cb, "Set environment variable", "VAR=VALUE" },
{ "own-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_own_name_cb, "Allow app to own name on the session bus", "DBUS_NAME" },
@ -873,13 +910,17 @@ xdg_app_context_save_metadata (XdgAppContext *context,
if (g_hash_table_size (context->filesystems) > 0)
{
GPtrArray *array = g_ptr_array_new ();
g_autoptr(GPtrArray) array = g_ptr_array_new_with_free_func (g_free);
g_hash_table_iter_init (&iter, context->filesystems);
while (g_hash_table_iter_next (&iter, &key, &value))
{
if (value != NULL)
g_ptr_array_add (array, key);
XdgAppFilesystemMode mode = GPOINTER_TO_INT (value);
if (mode == XDG_APP_FILESYSTEM_MODE_READ_ONLY)
g_ptr_array_add (array, g_strconcat (key, ":ro", NULL));
else if (value != NULL)
g_ptr_array_add (array, g_strdup (key));
}
g_key_file_set_string_list (metakey,
@ -1287,6 +1328,7 @@ xdg_app_run_add_environment_args (GPtrArray *argv_array,
gboolean home_access = FALSE;
GString *xdg_dirs_conf = NULL;
char opts[16];
XdgAppFilesystemMode fs_mode, home_mode;
int i;
i = 0;
@ -1310,19 +1352,29 @@ xdg_app_run_add_environment_args (GPtrArray *argv_array,
opts[i++] = 'g';
}
if (g_hash_table_lookup (context->filesystems, "host"))
fs_mode = (XdgAppFilesystemMode)g_hash_table_lookup (context->filesystems, "host");
if (fs_mode != 0)
{
g_debug ("Allowing host-fs access");
opts[i++] = 'f';
if (fs_mode == XDG_APP_FILESYSTEM_MODE_READ_WRITE)
opts[i++] = 'F';
else
opts[i++] = 'f';
home_access = TRUE;
}
else if (g_hash_table_lookup (context->filesystems, "home"))
home_mode = (XdgAppFilesystemMode)g_hash_table_lookup (context->filesystems, "home");
if (home_mode != 0)
{
g_debug ("Allowing homedir access");
opts[i++] = 'H';
if (home_mode == XDG_APP_FILESYSTEM_MODE_READ_WRITE)
opts[i++] = 'H';
else
opts[i++] = 'h';
home_access = TRUE;
}
else
if (!home_access)
{
/* Enable persistant mapping only if no access to real home dir */
@ -1351,20 +1403,24 @@ xdg_app_run_add_environment_args (GPtrArray *argv_array,
while (g_hash_table_iter_next (&iter, &key, &value))
{
const char *filesystem = key;
XdgAppFilesystemMode mode = GPOINTER_TO_INT(value);
const char *mode_arg;
if (value == NULL ||
strcmp (filesystem, "host") == 0 ||
strcmp (filesystem, "home") == 0)
continue;
if (mode == XDG_APP_FILESYSTEM_MODE_READ_WRITE)
mode_arg = "-B";
else
mode_arg = "-b";
if (g_str_has_prefix (filesystem, "xdg-"))
{
const char *path;
int dir = get_user_dir_from_string (filesystem);
if (home_access)
continue;
if (dir < 0)
{
g_warning ("Unsupported xdg dir %s\n", filesystem);
@ -1388,7 +1444,7 @@ xdg_app_run_add_environment_args (GPtrArray *argv_array,
g_string_append_printf (xdg_dirs_conf, "%s=\"%s\"\n", get_user_dir_config_key (dir), path);
g_ptr_array_add (argv_array, g_strdup ("-B"));
g_ptr_array_add (argv_array, g_strdup (mode_arg));
g_ptr_array_add (argv_array, g_strdup_printf ("%s", path));
}
}
@ -1396,13 +1452,10 @@ xdg_app_run_add_environment_args (GPtrArray *argv_array,
{
g_autofree char *path = NULL;
if (home_access)
continue;
path = g_build_filename (g_get_home_dir(), filesystem+2, NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
{
g_ptr_array_add (argv_array, g_strdup ("-B"));
g_ptr_array_add (argv_array, g_strdup (mode_arg));
g_ptr_array_add (argv_array, g_strdup (path));
}
}
@ -1410,7 +1463,7 @@ xdg_app_run_add_environment_args (GPtrArray *argv_array,
{
if (g_file_test (filesystem, G_FILE_TEST_EXISTS))
{
g_ptr_array_add (argv_array, g_strdup ("-B"));
g_ptr_array_add (argv_array, g_strdup (mode_arg));
g_ptr_array_add (argv_array, g_strdup_printf ("%s", filesystem));
}
}