This patch contains code for checking non-posix capability.
TOMOYO is ready to support 65536 types of non-posix capabilities.
But I can't utilize TOMOYO's ability because
(1) Hooks are missing.
or
(2) Posix's capability and functionality are not one to one mapping.
Therefore I can't derive functionality the caller wants to use from
posix's capability number (e.g. CAP_SYS_ADMIN).
or
(3) Hooks are provided but it is not permitted to sleep (e.g. CAP_SYS_NICE)
while TOMOYO needs hooks where it is permitted to sleep.
or
(4) System calls and device drivers use the same posix's capability number.
Thus whether MAC's policy suits or not depends on hardware the system
is running. TOMOYO wants to distinguish requests from userland
applications and requests from kernel drivers, but I can't distinguish
it from posix's capability number.
Therefore, LSM version of TOMOYO has very poor support compared to non-LSM
version of TOMOYO. I hope this problem is solved in the future.
Signed-off-by: Tetsuo Handa <[email protected]>
---
security/tomoyo/capability.c | 141 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 141 insertions(+)
--- /dev/null
+++ security-testing-2.6/security/tomoyo/capability.c
@@ -0,0 +1,141 @@
+/*
+ * security/tomoyo/capability.c
+ *
+ * Copyright (C) 2005-2009 NTT DATA CORPORATION
+ */
+#include "internal.h"
+
+/**
+ * tomoyo_audit_capability_log - Audit capability log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @operation: Type of operation.
+ * @is_granted: True if this is a granted log.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_audit_capability_log(struct tomoyo_request_info *r,
+ const u8 operation,
+ const bool is_granted)
+{
+ if (!is_granted)
+ tomoyo_warn_log(r, "capability %s",
+ tomoyo_cap2keyword(operation));
+ return tomoyo_write_audit_log(is_granted, r,
+ TOMOYO_KEYWORD_ALLOW_CAPABILITY "%s\n",
+ tomoyo_cap2keyword(operation));
+}
+
+/**
+ * tomoyo_capable - Check permission for capability.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_capable2(const u8 operation)
+{
+ struct tomoyo_request_info r;
+ struct tomoyo_acl_info *ptr;
+ int error;
+ if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAX_MAC_INDEX +
+ operation) == TOMOYO_CONFIG_DISABLED)
+ return true;
+ do {
+ error = -EPERM;
+ list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) {
+ struct tomoyo_capability_acl *acl;
+ if (ptr->is_deleted ||
+ ptr->type != TOMOYO_TYPE_CAPABILITY_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_capability_acl,
+ head);
+ if (acl->operation != operation ||
+ !tomoyo_condition(&r, ptr))
+ continue;
+ r.cond = ptr->cond;
+ error = 0;
+ break;
+ }
+ tomoyo_audit_capability_log(&r, operation, !error);
+ if (!error)
+ break;
+ error = tomoyo_supervisor(&r, TOMOYO_KEYWORD_ALLOW_CAPABILITY
+ "%s\n",
+ tomoyo_cap2keyword(operation));
+ } while (error == 1);
+ return !error;
+}
+
+/**
+ * tomoyo_capable - Check permission for capability.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_capable(const u8 operation)
+{
+ const int idx = tomoyo_read_lock();
+ const int error = tomoyo_capable2(operation);
+ tomoyo_read_unlock(idx);
+ return error;
+}
+
+/**
+ * tomoyo_write_capability_policy - Write "struct tomoyo_capability_acl" list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @condition: Pointer to "struct tomoyo_condition". May be NULL.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_capability_policy(char *data,
+ struct tomoyo_domain_info *domain,
+ struct tomoyo_condition *condition,
+ const bool is_delete)
+{
+ struct tomoyo_capability_acl e = {
+ .head.type = TOMOYO_TYPE_CAPABILITY_ACL,
+ .head.cond = condition,
+ };
+ struct tomoyo_capability_acl *entry = NULL;
+ struct tomoyo_acl_info *ptr;
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ u8 capability;
+ for (capability = 0; capability < TOMOYO_MAX_CAPABILITY_INDEX;
+ capability++) {
+ if (strcmp(data, tomoyo_cap2keyword(capability)))
+ continue;
+ break;
+ }
+ if (capability == TOMOYO_MAX_CAPABILITY_INDEX)
+ return -EINVAL;
+ e.operation = capability;
+ if (!is_delete)
+ entry = kmalloc(sizeof(e), GFP_KERNEL);
+ mutex_lock(&tomoyo_policy_lock);
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_capability_acl *acl =
+ container_of(ptr, struct tomoyo_capability_acl,
+ head);
+ if (ptr->type != TOMOYO_TYPE_CAPABILITY_ACL ||
+ ptr->cond != condition || acl->operation != capability)
+ continue;
+ ptr->is_deleted = is_delete;
+ error = 0;
+ break;
+ }
+ if (!is_delete && error && tomoyo_commit_ok(entry, &e, sizeof(e))) {
+ tomoyo_add_domain_acl(domain, &entry->head);
+ entry = NULL;
+ error = 0;
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ kfree(entry);
+ return error;
+}
--
Quoting Tetsuo Handa ([email protected]):
> This patch contains code for checking non-posix capability.
>
> TOMOYO is ready to support 65536 types of non-posix capabilities.
> But I can't utilize TOMOYO's ability because
>
> (1) Hooks are missing.
please send patches.
> or
> (2) Posix's capability and functionality are not one to one mapping.
> Therefore I can't derive functionality the caller wants to use from
> posix's capability number (e.g. CAP_SYS_ADMIN).
Hmm, it should be possible to address this in a back-compatible way. I.e.,
#define CAP_CHOWN 0
...
#define CAP_SYS_ADMIN 21
...
#define CAP_MAC_ADMIN 33
/* start enhanced capabilities */
#ifdef CONFIG_CAPABILITIES_ENHANCED
#define CAP_SAK_CONFIG 200
#define CAP_RND_ADMIN 201
#define CAP_SYS_HOSTNAME 202
...
#else
#define CAP_SAK_CONFIG CAP_SYS_ADMIN
#define CAP_RND_ADMIN CAP_SYS_ADMIN
#define CAP_SYS_HOSTNAME CAP_SYS_ADMIN
#endif
Plus of course all that is needed (if CONFIG_CAPABILITIES_ENHANCED=y)
to support all those caps.
> or
> (3) Hooks are provided but it is not permitted to sleep (e.g. CAP_SYS_NICE)
> while TOMOYO needs hooks where it is permitted to sleep.
> or
> (4) System calls and device drivers use the same posix's capability number.
> Thus whether MAC's policy suits or not depends on hardware the system
> is running. TOMOYO wants to distinguish requests from userland
> applications and requests from kernel drivers, but I can't distinguish
> it from posix's capability number.
Same thing?
> Therefore, LSM version of TOMOYO has very poor support compared to non-LSM
> version of TOMOYO. I hope this problem is solved in the future.
>
> Signed-off-by: Tetsuo Handa <[email protected]>
> ---
> security/tomoyo/capability.c | 141 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 141 insertions(+)
>
> --- /dev/null
> +++ security-testing-2.6/security/tomoyo/capability.c
> @@ -0,0 +1,141 @@
> +/*
> + * security/tomoyo/capability.c
> + *
> + * Copyright (C) 2005-2009 NTT DATA CORPORATION
> + */
> +#include "internal.h"
> +
> +/**
> + * tomoyo_audit_capability_log - Audit capability log.
> + *
> + * @r: Pointer to "struct tomoyo_request_info".
> + * @operation: Type of operation.
> + * @is_granted: True if this is a granted log.
> + *
> + * Returns 0 on success, negative value otherwise.
> + */
> +static int tomoyo_audit_capability_log(struct tomoyo_request_info *r,
> + const u8 operation,
> + const bool is_granted)
> +{
> + if (!is_granted)
> + tomoyo_warn_log(r, "capability %s",
> + tomoyo_cap2keyword(operation));
> + return tomoyo_write_audit_log(is_granted, r,
> + TOMOYO_KEYWORD_ALLOW_CAPABILITY "%s\n",
> + tomoyo_cap2keyword(operation));
> +}
> +
> +/**
> + * tomoyo_capable - Check permission for capability.
> + *
> + * @operation: Type of operation.
> + *
> + * Returns true on success, false otherwise.
> + *
> + * Caller holds tomoyo_read_lock().
> + */
> +static bool tomoyo_capable2(const u8 operation)
> +{
> + struct tomoyo_request_info r;
> + struct tomoyo_acl_info *ptr;
> + int error;
> + if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAX_MAC_INDEX +
> + operation) == TOMOYO_CONFIG_DISABLED)
> + return true;
> + do {
> + error = -EPERM;
> + list_for_each_entry_rcu(ptr, &r.domain->acl_info_list, list) {
> + struct tomoyo_capability_acl *acl;
> + if (ptr->is_deleted ||
> + ptr->type != TOMOYO_TYPE_CAPABILITY_ACL)
> + continue;
> + acl = container_of(ptr, struct tomoyo_capability_acl,
> + head);
> + if (acl->operation != operation ||
> + !tomoyo_condition(&r, ptr))
> + continue;
> + r.cond = ptr->cond;
> + error = 0;
> + break;
> + }
> + tomoyo_audit_capability_log(&r, operation, !error);
> + if (!error)
> + break;
> + error = tomoyo_supervisor(&r, TOMOYO_KEYWORD_ALLOW_CAPABILITY
> + "%s\n",
> + tomoyo_cap2keyword(operation));
> + } while (error == 1);
> + return !error;
> +}
> +
> +/**
> + * tomoyo_capable - Check permission for capability.
> + *
> + * @operation: Type of operation.
> + *
> + * Returns true on success, false otherwise.
> + */
> +bool tomoyo_capable(const u8 operation)
> +{
> + const int idx = tomoyo_read_lock();
> + const int error = tomoyo_capable2(operation);
> + tomoyo_read_unlock(idx);
> + return error;
> +}
> +
> +/**
> + * tomoyo_write_capability_policy - Write "struct tomoyo_capability_acl" list.
> + *
> + * @data: String to parse.
> + * @domain: Pointer to "struct tomoyo_domain_info".
> + * @condition: Pointer to "struct tomoyo_condition". May be NULL.
> + * @is_delete: True if it is a delete request.
> + *
> + * Returns 0 on success, negative value otherwise.
> + */
> +int tomoyo_write_capability_policy(char *data,
> + struct tomoyo_domain_info *domain,
> + struct tomoyo_condition *condition,
> + const bool is_delete)
> +{
> + struct tomoyo_capability_acl e = {
> + .head.type = TOMOYO_TYPE_CAPABILITY_ACL,
> + .head.cond = condition,
> + };
> + struct tomoyo_capability_acl *entry = NULL;
> + struct tomoyo_acl_info *ptr;
> + int error = is_delete ? -ENOENT : -ENOMEM;
> + u8 capability;
> + for (capability = 0; capability < TOMOYO_MAX_CAPABILITY_INDEX;
> + capability++) {
> + if (strcmp(data, tomoyo_cap2keyword(capability)))
> + continue;
> + break;
> + }
> + if (capability == TOMOYO_MAX_CAPABILITY_INDEX)
> + return -EINVAL;
> + e.operation = capability;
> + if (!is_delete)
> + entry = kmalloc(sizeof(e), GFP_KERNEL);
> + mutex_lock(&tomoyo_policy_lock);
> + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
> + struct tomoyo_capability_acl *acl =
> + container_of(ptr, struct tomoyo_capability_acl,
> + head);
> + if (ptr->type != TOMOYO_TYPE_CAPABILITY_ACL ||
> + ptr->cond != condition || acl->operation != capability)
> + continue;
> + ptr->is_deleted = is_delete;
> + error = 0;
> + break;
> + }
> + if (!is_delete && error && tomoyo_commit_ok(entry, &e, sizeof(e))) {
> + tomoyo_add_domain_acl(domain, &entry->head);
> + entry = NULL;
> + error = 0;
> + }
> + mutex_unlock(&tomoyo_policy_lock);
> + kfree(entry);
> + return error;
> +}
>
> --
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html