Add generic static permissions to metadata

This allows you do do something like
  flatpak build-finish --add-policy=subsystem.key=v1 --add-policy=subsystem.key=v2

Which maps to this metadata keys:

[Policy subsystem]
key=v1;v2;

You can also --remove-policy to remove values from a key.

The policy values are parsed from the app and runtime metadata, and
are overridable by per-app overrides and on the command line, however
the values are never used by flatpak. They do end up in the flatpak-info
file for the running application though, so external agents can look
at them.

These
This commit is contained in:
Alexander Larsson
2016-10-19 20:39:17 +02:00
parent 27654ceb2f
commit 041d3eeb39
2 changed files with 177 additions and 0 deletions

View File

@@ -130,6 +130,7 @@ struct FlatpakContext
GHashTable *filesystems;
GHashTable *session_bus_policy;
GHashTable *system_bus_policy;
GHashTable *generic_policy;
};
FlatpakContext *
@@ -143,6 +144,8 @@ flatpak_context_new (void)
context->filesystems = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
context->session_bus_policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
context->system_bus_policy = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
context->generic_policy = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify)g_strfreev);
return context;
}
@@ -155,6 +158,7 @@ flatpak_context_free (FlatpakContext *context)
g_hash_table_destroy (context->filesystems);
g_hash_table_destroy (context->session_bus_policy);
g_hash_table_destroy (context->system_bus_policy);
g_hash_table_destroy (context->generic_policy);
g_slice_free (FlatpakContext, context);
}
@@ -477,6 +481,38 @@ flatpak_context_set_system_bus_policy (FlatpakContext *context,
g_hash_table_insert (context->system_bus_policy, g_strdup (name), GINT_TO_POINTER (policy));
}
void
flatpak_context_apply_generic_policy (FlatpakContext *context,
const char *key,
const char *value)
{
GPtrArray *new = g_ptr_array_new ();
const char **old_v;
int i;
g_assert (strchr (key, '.') != NULL);
old_v = g_hash_table_lookup (context->generic_policy, key);
for (i = 0; old_v != NULL && old_v[i] != NULL; i++)
{
const char *old = old_v[i];
const char *cmp1 = old;
const char *cmp2 = value;
if (*cmp1 == '!')
cmp1++;
if (*cmp2 == '!')
cmp2++;
if (strcmp (cmp1, cmp2) != 0)
g_ptr_array_add (new, g_strdup (old));
}
g_ptr_array_add (new, g_strdup (value));
g_ptr_array_add (new, NULL);
g_hash_table_insert (context->generic_policy, g_strdup (key),
g_ptr_array_free (new, FALSE));
}
static void
flatpak_context_set_persistent (FlatpakContext *context,
const char *path)
@@ -693,6 +729,21 @@ flatpak_context_merge (FlatpakContext *context,
g_hash_table_iter_init (&iter, other->system_bus_policy);
while (g_hash_table_iter_next (&iter, &key, &value))
g_hash_table_insert (context->system_bus_policy, g_strdup (key), value);
g_hash_table_iter_init (&iter, other->system_bus_policy);
while (g_hash_table_iter_next (&iter, &key, &value))
g_hash_table_insert (context->system_bus_policy, g_strdup (key), value);
g_hash_table_iter_init (&iter, other->generic_policy);
while (g_hash_table_iter_next (&iter, &key, &value))
{
const char **policy_values = (const char **)value;
int i;
for (i = 0; policy_values[i] != NULL; i++)
flatpak_context_apply_generic_policy (context, (char *)key, policy_values[i]);
}
}
static gboolean
@@ -950,6 +1001,63 @@ option_system_talk_name_cb (const gchar *option_name,
return TRUE;
}
static gboolean
option_add_generic_policy_cb (const gchar *option_name,
const gchar *value,
gpointer data,
GError **error)
{
FlatpakContext *context = data;
char *t;
g_autofree char *key = NULL;
const char *policy_value;
t = strchr (value, '=');
if (t == NULL)
return flatpak_fail (error, "--policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE");
policy_value = t + 1;
key = g_strndup (value, t - value);
if (strchr (key, '.') == NULL)
return flatpak_fail (error, "--policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE");
if (policy_value[0] == '!')
return flatpak_fail (error, "--policy values can't start with \"!\"");
flatpak_context_apply_generic_policy (context, key, policy_value);
return TRUE;
}
static gboolean
option_remove_generic_policy_cb (const gchar *option_name,
const gchar *value,
gpointer data,
GError **error)
{
FlatpakContext *context = data;
char *t;
g_autofree char *key = NULL;
const char *policy_value;
g_autofree char *extended_value = NULL;
t = strchr (value, '=');
if (t == NULL)
return flatpak_fail (error, "--policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE");
policy_value = t + 1;
key = g_strndup (value, t - value);
if (strchr (key, '.') == NULL)
return flatpak_fail (error, "--policy arguments must be in the form SUBSYSTEM.KEY=[!]VALUE");
if (policy_value[0] == '!')
return flatpak_fail (error, "--policy values can't start with \"!\"");
extended_value = g_strconcat ("!", policy_value, NULL);
flatpak_context_apply_generic_policy (context, key, extended_value);
return TRUE;
}
static gboolean
option_persist_cb (const gchar *option_name,
const gchar *value,
@@ -980,6 +1088,8 @@ static GOptionEntry context_options[] = {
{ "talk-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_talk_name_cb, N_("Allow app to talk to name on the session bus"), N_("DBUS_NAME") },
{ "system-own-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_system_own_name_cb, N_("Allow app to own name on the system bus"), N_("DBUS_NAME") },
{ "system-talk-name", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_system_talk_name_cb, N_("Allow app to talk to name on the system bus"), N_("DBUS_NAME") },
{ "add-policy", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_add_generic_policy_cb, N_("Add generic policy option"), N_("SUBSYSTEM.KEY=VALUE") },
{ "remove-policy", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_remove_generic_policy_cb, N_("Remove generic policy option"), N_("SUBSYSTEM.KEY=VALUE") },
{ "persist", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_CALLBACK, &option_persist_cb, N_("Persist home directory"), N_("FILENAME") },
/* This is not needed/used anymore, so hidden, but we accept it for backwards compat */
{ "no-desktop", 0, G_OPTION_FLAG_IN_MAIN | G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &option_no_desktop_deprecated, N_("Don't require a running session (no cgroups creation)"), NULL },
@@ -1031,6 +1141,7 @@ flatpak_context_load_metadata (FlatpakContext *context,
GError **error)
{
gboolean remove;
g_auto(GStrv) groups = NULL;
int i;
if (g_key_file_has_key (metakey, FLATPAK_METADATA_GROUP_CONTEXT, FLATPAK_METADATA_KEY_SHARED, NULL))
@@ -1204,6 +1315,33 @@ flatpak_context_load_metadata (FlatpakContext *context,
}
}
groups = g_key_file_get_groups (metakey, NULL);
for (i = 0; groups[i] != NULL; i++)
{
const char *group = groups[i];
const char *subsystem;
int j;
if (g_str_has_prefix (group, FLATPAK_METADATA_GROUP_PREFIX_POLICY))
{
g_auto(GStrv) keys = NULL;
subsystem = group + strlen (FLATPAK_METADATA_GROUP_PREFIX_POLICY);
keys = g_key_file_get_keys (metakey, group, NULL, NULL);
for (j = 0; keys != NULL && keys[j] != NULL; j++)
{
const char *key = keys[j];
g_autofree char *policy_key = g_strdup_printf ("%s.%s", subsystem, key);
g_auto(GStrv) values = NULL;
int k;
values = g_key_file_get_string_list (metakey, group, key, NULL, NULL);
for (k = 0; values != NULL && values[k] != NULL; k++)
flatpak_context_apply_generic_policy (context, policy_key,
values[k]);
}
}
}
return TRUE;
}
@@ -1226,6 +1364,8 @@ flatpak_context_save_metadata (FlatpakContext *context,
FlatpakContextDevices devices_valid = context->devices_valid;
FlatpakContextFeatures features_mask = context->features;
FlatpakContextFeatures features_valid = context->features;
g_auto(GStrv) groups = NULL;
int i;
if (flatten)
{
@@ -1387,6 +1527,42 @@ flatpak_context_save_metadata (FlatpakContext *context,
FLATPAK_METADATA_GROUP_ENVIRONMENT,
(char *) key, (char *) value);
}
groups = g_key_file_get_groups (metakey, NULL);
for (i = 0; groups[i] != NULL; i++)
{
const char *group = groups[i];
if (g_str_has_prefix (group, FLATPAK_METADATA_GROUP_PREFIX_POLICY))
g_key_file_remove_group (metakey, group, NULL);
}
g_hash_table_iter_init (&iter, context->generic_policy);
while (g_hash_table_iter_next (&iter, &key, &value))
{
g_auto(GStrv) parts = g_strsplit ((const char *)key, ".", 2);
g_autofree char *group = NULL;
g_assert (parts[1] != NULL);
const char **policy_values = (const char **)value;
g_autoptr(GPtrArray) new = g_ptr_array_new ();
for (i = 0; policy_values[i] != NULL; i++)
{
const char *policy_value = policy_values[i];
if (!flatten || policy_value[0] != '!')
g_ptr_array_add (new, (char *)policy_value);
}
if (new->len > 0)
{
group = g_strconcat (FLATPAK_METADATA_GROUP_PREFIX_POLICY,
parts[0], NULL);
g_key_file_set_string_list (metakey, group, parts[1],
(const char * const*)new->pdata,
new->len);
}
}
}
void

View File

@@ -32,6 +32,7 @@ gboolean flatpak_run_in_transient_unit (const char *app_id,
#define FLATPAK_METADATA_GROUP_CONTEXT "Context"
#define FLATPAK_METADATA_GROUP_SESSION_BUS_POLICY "Session Bus Policy"
#define FLATPAK_METADATA_GROUP_SYSTEM_BUS_POLICY "System Bus Policy"
#define FLATPAK_METADATA_GROUP_PREFIX_POLICY "Policy "
#define FLATPAK_METADATA_GROUP_ENVIRONMENT "Environment"
#define FLATPAK_METADATA_KEY_SHARED "shared"
#define FLATPAK_METADATA_KEY_SOCKETS "sockets"