summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDjalal Harouni <tixxdz@opendz.org>2014-09-08 14:18:26 +0100
committerDaniel Mack <daniel@zonque.org>2014-09-09 10:35:04 +0200
commite09aeadfacd613b58d7b0c8562c477dbc1c8473c (patch)
treeae6fd72a50b4eca4f963133968cc1e194bb56c98
parentba8bc7bb7b845bf2a8707fe0b2b66aecb72dac3e (diff)
downloadkdbus-bus-e09aeadfacd613b58d7b0c8562c477dbc1c8473c.tar.gz
kdbus-bus-e09aeadfacd613b58d7b0c8562c477dbc1c8473c.tar.bz2
kdbus-bus-e09aeadfacd613b58d7b0c8562c477dbc1c8473c.zip
policy: make policy checks work across user namespaces
Use the global kuid_t and kgid_t to store uid/gid values, this way we our policy checks will work across user namespaces. Note that currently we ignore that the user is privileged in its own namespaces and the policy access kuid_t and kgid_t were mapped into that namespace. If this is requested we can add it later a la: fs/inode.c:inode_owner_or_capable() Add kdbus_policy_make_access() to convert the user provided info to the current user namespace. Userspace struct is not changed, only the kernel one. This patch fixes test #8 of test-kdbus-policy Signed-off-by: Djalal Harouni <tixxdz@opendz.org> [daniel: group kdbus_policy_db_entry_access->{uid,gid} in a union]
-rw-r--r--policy.c78
1 files changed, 60 insertions, 18 deletions
diff --git a/policy.c b/policy.c
index c4ac36119b4..ed1e108fcd2 100644
--- a/policy.c
+++ b/policy.c
@@ -3,6 +3,7 @@
* Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
* Copyright (C) 2013 Daniel Mack <daniel@zonque.org>
* Copyright (C) 2013 Linux Foundation
+ * Copyright (C) 2014 Djalal Harouni
*
* kdbus is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the
@@ -42,16 +43,19 @@ struct kdbus_policy_db_cache_entry {
* struct kdbus_policy_db_entry_access - a database entry access item
* @type: One of KDBUS_POLICY_ACCESS_* types
* @access: Access to grant. One of KDBUS_POLICY_*
- * @id: For KDBUS_POLICY_ACCESS_USER, the uid
- * For KDBUS_POLICY_ACCESS_GROUP, the gid
+ * @uid: For KDBUS_POLICY_ACCESS_USER, the global uid
+ * @gid: For KDBUS_POLICY_ACCESS_GROUP, the global gid
* @list: List entry item for the entry's list
*
* This is the internal version of struct kdbus_policy_db_access.
*/
struct kdbus_policy_db_entry_access {
- u8 type; /* USER, GROUP, WORLD */
- u8 access; /* OWN, TALK, SEE */
- u64 id; /* uid, gid, 0 */
+ u8 type; /* USER, GROUP, WORLD */
+ u8 access; /* OWN, TALK, SEE */
+ union {
+ kuid_t uid; /* global uid */
+ kgid_t gid; /* global gid */
+ };
struct list_head list;
};
@@ -189,30 +193,30 @@ static int kdbus_policy_check_access(const struct kdbus_policy_db_entry *e,
{
struct kdbus_policy_db_entry_access *a;
struct group_info *group_info;
- struct user_namespace *ns;
- uid_t uid;
int i;
if (!e)
return -EPERM;
- ns = cred->user_ns;
group_info = cred->group_info;
- uid = from_kuid(ns, cred->uid);
list_for_each_entry(a, &e->access_list, list) {
if (a->access >= access) {
switch (a->type) {
case KDBUS_POLICY_ACCESS_USER:
- if (a->id == uid)
+ if (uid_eq(cred->uid, a->uid))
return 0;
break;
case KDBUS_POLICY_ACCESS_GROUP:
+ if (gid_eq(cred->gid, a->gid))
+ return 0;
+
for (i = 0; i < group_info->ngroups; i++) {
kgid_t gid = GROUP_AT(group_info, i);
- if (a->id == from_kgid_munged(ns, gid))
+ if (gid_eq(gid, a->gid))
return 0;
}
+
break;
case KDBUS_POLICY_ACCESS_WORLD:
return 0;
@@ -444,6 +448,49 @@ struct kdbus_policy_list_entry {
struct list_head entry;
};
+/*
+ * Convert user provided policy access to internal kdbus policy
+ * access
+ */
+static int
+kdbus_policy_make_access(const struct kdbus_policy_access *uaccess,
+ struct kdbus_policy_db_entry_access **entry)
+{
+ int ret;
+ struct kdbus_policy_db_entry_access *a;
+
+ a = kzalloc(sizeof(*a), GFP_KERNEL);
+ if (!a)
+ return -ENOMEM;
+
+ ret = -EINVAL;
+ switch (uaccess->type) {
+ case KDBUS_POLICY_ACCESS_USER:
+ a->uid = make_kuid(current_user_ns(), uaccess->id);
+ if (!uid_valid(a->uid))
+ goto err;
+
+ break;
+ case KDBUS_POLICY_ACCESS_GROUP:
+ a->gid = make_kgid(current_user_ns(), uaccess->id);
+ if (!gid_valid(a->gid))
+ goto err;
+
+ break;
+ }
+
+ a->type = uaccess->type;
+ a->access = uaccess->access;
+
+ *entry = a;
+
+ return 0;
+
+err:
+ kfree(a);
+ return ret;
+}
+
/**
* kdbus_policy_set() - set a connection's policy rules
* @db: The policy database
@@ -571,15 +618,10 @@ int kdbus_policy_set(struct kdbus_policy_db *db,
goto exit;
}
- a = kzalloc(sizeof(*a), GFP_KERNEL);
- if (!a) {
- ret = -ENOMEM;
+ ret = kdbus_policy_make_access(&item->policy_access, &a);
+ if (ret < 0)
goto exit;
- }
- a->type = item->policy_access.type;
- a->access = item->policy_access.access;
- a->id = item->policy_access.id;
list_add_tail(&a->list, &e->access_list);
break;
}