]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - security/tomoyo/common.c
TOMOYO: Allow reading only execute permission.
[net-next-2.6.git] / security / tomoyo / common.c
index 9eeb19ec6af470c1b94621600c9bba827f61435a..6c68981c0f5f51b70e47fb6098a3b262497b1ad3 100644 (file)
@@ -434,38 +434,6 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                head->read_eof = true;
 }
 
-/*
- * tomoyo_policy_manager_list is used for holding list of domainnames or
- * programs which are permitted to modify configuration via
- * /sys/kernel/security/tomoyo/ interface.
- *
- * An entry is added by
- *
- * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *  (if you want to specify by a domainname)
- *
- *  or
- *
- * # echo '/usr/sbin/tomoyo-editpolicy' > /sys/kernel/security/tomoyo/manager
- *  (if you want to specify by a program's location)
- *
- * and is deleted by
- *
- * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *
- *  or
- *
- * # echo 'delete /usr/sbin/tomoyo-editpolicy' > \
- *                                        /sys/kernel/security/tomoyo/manager
- *
- * and all entries are retrieved by
- *
- * # cat /sys/kernel/security/tomoyo/manager
- */
-LIST_HEAD(tomoyo_policy_manager_list);
-
 static bool tomoyo_same_manager_entry(const struct tomoyo_acl_head *a,
                                      const struct tomoyo_acl_head *b)
 {
@@ -503,7 +471,7 @@ static int tomoyo_update_manager_entry(const char *manager,
        if (!e.manager)
                return -ENOMEM;
        error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
-                                    &tomoyo_policy_manager_list,
+                                    &tomoyo_policy_list[TOMOYO_ID_MANAGER],
                                     tomoyo_same_manager_entry);
        tomoyo_put_name(e.manager);
        return error;
@@ -539,16 +507,14 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
  */
 static void tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
 {
-       struct list_head *pos;
        bool done = true;
 
        if (head->read_eof)
                return;
-       list_for_each_cookie(pos, head->read_var2,
-                            &tomoyo_policy_manager_list) {
-               struct tomoyo_policy_manager_entry *ptr;
-               ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
-                                head.list);
+       list_for_each_cookie(head->read_var2,
+                            &tomoyo_policy_list[TOMOYO_ID_MANAGER]) {
+               struct tomoyo_policy_manager_entry *ptr =
+                       list_entry(head->read_var2, typeof(*ptr), head.list);
                if (ptr->head.is_deleted)
                        continue;
                done = tomoyo_io_printf(head, "%s\n", ptr->manager->name);
@@ -578,7 +544,8 @@ static bool tomoyo_policy_manager(void)
                return true;
        if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, head.list) {
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+                               head.list) {
                if (!ptr->head.is_deleted && ptr->is_domain
                    && !tomoyo_pathcmp(domainname, ptr->manager)) {
                        found = true;
@@ -590,7 +557,8 @@ static bool tomoyo_policy_manager(void)
        exe = tomoyo_get_exe();
        if (!exe)
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, head.list) {
+       list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_MANAGER],
+                               head.list) {
                if (!ptr->head.is_deleted && !ptr->is_domain
                    && !strcmp(exe, ptr->manager->name)) {
                        found = true;
@@ -620,13 +588,16 @@ static bool tomoyo_policy_manager(void)
  *
  * Caller holds tomoyo_read_lock().
  */
-static bool tomoyo_select_one(struct tomoyo_io_buffer *head,
-                                const char *data)
+static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
 {
        unsigned int pid;
        struct tomoyo_domain_info *domain = NULL;
        bool global_pid = false;
 
+       if (!strcmp(data, "allow_execute")) {
+               head->print_execute_only = true;
+               return true;
+       }
        if (sscanf(data, "pid=%u", &pid) == 1 ||
            (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
                struct task_struct *p;
@@ -653,20 +624,12 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head,
        tomoyo_io_printf(head, "# select %s\n", data);
        head->read_single_domain = true;
        head->read_eof = !domain;
-       if (domain) {
-               struct tomoyo_domain_info *d;
-               head->read_var1 = NULL;
-               list_for_each_entry_rcu(d, &tomoyo_domain_list, list) {
-                       if (d == domain)
-                               break;
-                       head->read_var1 = &d->list;
-               }
-               head->read_var2 = NULL;
-               head->read_bit = 0;
-               head->read_step = 0;
-               if (domain->is_deleted)
-                       tomoyo_io_printf(head, "# This is a deleted domain.\n");
-       }
+       head->read_var1 = &domain->list;
+       head->read_var2 = NULL;
+       head->read_bit = 0;
+       head->read_step = 0;
+       if (domain && domain->is_deleted)
+               tomoyo_io_printf(head, "# This is a deleted domain.\n");
        return true;
 }
 
@@ -800,6 +763,8 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
        for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
                if (!(perm & (1 << bit)))
                        continue;
+               if (head->print_execute_only && bit != TOMOYO_TYPE_EXECUTE)
+                       continue;
                /* Print "read/write" instead of "read" and "write". */
                if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE)
                    && (perm & (1 << TOMOYO_TYPE_READ_WRITE)))
@@ -967,6 +932,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                        = container_of(ptr, struct tomoyo_path_acl, head);
                return tomoyo_print_path_acl(head, acl);
        }
+       if (head->print_execute_only)
+               return true;
        if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
                struct tomoyo_path2_acl *acl
                        = container_of(ptr, struct tomoyo_path2_acl, head);
@@ -1002,20 +969,18 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
  */
 static void tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
 {
-       struct list_head *dpos;
-       struct list_head *apos;
        bool done = true;
 
        if (head->read_eof)
                return;
        if (head->read_step == 0)
                head->read_step = 1;
-       list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
-               struct tomoyo_domain_info *domain;
+       list_for_each_cookie(head->read_var1, &tomoyo_domain_list) {
+               struct tomoyo_domain_info *domain =
+                       list_entry(head->read_var1, typeof(*domain), list);
                const char *quota_exceeded = "";
                const char *transition_failed = "";
                const char *ignore_global_allow_read = "";
-               domain = list_entry(dpos, struct tomoyo_domain_info, list);
                if (head->read_step != 1)
                        goto acl_loop;
                if (domain->is_deleted && !head->read_single_domain)
@@ -1041,17 +1006,17 @@ acl_loop:
                if (head->read_step == 3)
                        goto tail_mark;
                /* Print ACL entries in the domain. */
-               list_for_each_cookie(apos, head->read_var2,
+               list_for_each_cookie(head->read_var2,
                                     &domain->acl_info_list) {
-                       struct tomoyo_acl_info *ptr
-                               = list_entry(apos, struct tomoyo_acl_info,
-                                            list);
+                       struct tomoyo_acl_info *ptr =
+                               list_entry(head->read_var2, typeof(*ptr), list);
                        done = tomoyo_print_entry(head, ptr);
                        if (!done)
                                break;
                }
                if (!done)
                        break;
+               head->read_var2 = NULL;
                head->read_step = 3;
 tail_mark:
                done = tomoyo_io_printf(head, "\n");
@@ -1115,14 +1080,13 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
  */
 static void tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
 {
-       struct list_head *pos;
        bool done = true;
 
        if (head->read_eof)
                return;
-       list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
-               struct tomoyo_domain_info *domain;
-               domain = list_entry(pos, struct tomoyo_domain_info, list);
+       list_for_each_cookie(head->read_var1, &tomoyo_domain_list) {
+               struct tomoyo_domain_info *domain =
+                       list_entry(head->read_var1, typeof(*domain), list);
                if (domain->is_deleted)
                        continue;
                done = tomoyo_io_printf(head, "%u %s\n", domain->profile,
@@ -1180,6 +1144,15 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
        }
 }
 
+static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
+       [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE]
+       = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN,
+       [TOMOYO_TRANSITION_CONTROL_INITIALIZE]
+       = TOMOYO_KEYWORD_INITIALIZE_DOMAIN,
+       [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN,
+       [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN
+};
+
 /**
  * tomoyo_write_exception_policy - Write exception policy.
  *
@@ -1193,22 +1166,15 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
        bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
+       u8 i;
 
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
-               return tomoyo_write_domain_keeper_policy(data, false,
-                                                        is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
-               return tomoyo_write_domain_keeper_policy(data, true, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
-               return tomoyo_write_domain_initializer_policy(data, false,
-                                                             is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
-               return tomoyo_write_domain_initializer_policy(data, true,
-                                                             is_delete);
+       for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) {
+               if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
+                       return tomoyo_write_transition_control(data, is_delete,
+                                                              i);
+       }
        if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR))
                return tomoyo_write_aggregator_policy(data, is_delete);
-       if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
-               return tomoyo_write_alias_policy(data, is_delete);
        if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
                return tomoyo_write_globally_readable_policy(data, is_delete);
        if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
@@ -1216,81 +1182,196 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
        if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
                return tomoyo_write_no_rewrite_policy(data, is_delete);
        if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
-               return tomoyo_write_path_group_policy(data, is_delete);
+               return tomoyo_write_group(data, is_delete, TOMOYO_PATH_GROUP);
        if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NUMBER_GROUP))
-               return tomoyo_write_number_group_policy(data, is_delete);
+               return tomoyo_write_group(data, is_delete, TOMOYO_NUMBER_GROUP);
        return -EINVAL;
 }
 
+static void tomoyo_print_number(char *buffer, int buffer_len,
+                            const struct tomoyo_number_union *ptr)
+{
+       int i;
+       unsigned long min = ptr->values[0];
+       const unsigned long max = ptr->values[1];
+       u8 min_type = ptr->min_type;
+       const u8 max_type = ptr->max_type;
+       memset(buffer, 0, buffer_len);
+       buffer_len -= 2;
+       for (i = 0; i < 2; i++) {
+               int len;
+               switch (min_type) {
+               case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+                       snprintf(buffer, buffer_len, "0x%lX", min);
+                       break;
+               case TOMOYO_VALUE_TYPE_OCTAL:
+                       snprintf(buffer, buffer_len, "0%lo", min);
+                       break;
+               default:
+                       snprintf(buffer, buffer_len, "%lu", min);
+                       break;
+               }
+               if (min == max && min_type == max_type)
+                       break;
+               len = strlen(buffer);
+               buffer[len++] = '-';
+               buffer += len;
+               buffer_len -= len;
+               min_type = max_type;
+               min = max;
+       }
+}
+
+static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
+       [TOMOYO_PATH_GROUP] = TOMOYO_KEYWORD_PATH_GROUP,
+       [TOMOYO_NUMBER_GROUP] = TOMOYO_KEYWORD_NUMBER_GROUP
+};
+
 /**
- * tomoyo_read_exception_policy - Read exception policy.
+ * tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
  *
  * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx:  Index number.
+ *
+ * Returns true on success, false otherwise.
  *
  * Caller holds tomoyo_read_lock().
  */
-static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
 {
-       if (!head->read_eof) {
-               switch (head->read_step) {
-               case 0:
-                       head->read_var2 = NULL;
-                       head->read_step = 1;
-               case 1:
-                       if (!tomoyo_read_domain_keeper_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 2;
-               case 2:
-                       if (!tomoyo_read_globally_readable_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 3;
-               case 3:
-                       head->read_var2 = NULL;
-                       head->read_step = 4;
-               case 4:
-                       if (!tomoyo_read_domain_initializer_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 5;
-               case 5:
-                       if (!tomoyo_read_alias_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 6;
-               case 6:
-                       if (!tomoyo_read_aggregator_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 7;
-               case 7:
-                       if (!tomoyo_read_file_pattern(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 8;
-               case 8:
-                       if (!tomoyo_read_no_rewrite_policy(head))
-                               break;
-                       head->read_var2 = NULL;
-                       head->read_step = 9;
-               case 9:
-                       if (!tomoyo_read_path_group_policy(head))
-                               break;
-                       head->read_var1 = NULL;
-                       head->read_var2 = NULL;
-                       head->read_step = 10;
-               case 10:
-                       if (!tomoyo_read_number_group_policy(head))
-                               break;
-                       head->read_var1 = NULL;
-                       head->read_var2 = NULL;
-                       head->read_step = 11;
-               case 11:
-                       head->read_eof = true;
+       const char *w[3] = { "", "", "" };
+       w[0] = tomoyo_group_name[idx];
+       list_for_each_cookie(head->read_var1, &tomoyo_group_list[idx]) {
+               struct tomoyo_group *group =
+                       list_entry(head->read_var1, typeof(*group), list);
+               w[1] = group->group_name->name;
+               list_for_each_cookie(head->read_var2, &group->member_list) {
+                       char buffer[128];
+                       struct tomoyo_acl_head *ptr =
+                               list_entry(head->read_var2, typeof(*ptr), list);
+                       if (ptr->is_deleted)
+                               continue;
+                       if (idx == TOMOYO_PATH_GROUP) {
+                               w[2] = container_of(ptr,
+                                                   struct tomoyo_path_group,
+                                                   head)->member_name->name;
+                       } else if (idx == TOMOYO_NUMBER_GROUP) {
+                               tomoyo_print_number(buffer, sizeof(buffer),
+                                                   &container_of
+                                                   (ptr, struct
+                                                    tomoyo_number_group,
+                                                    head)->number);
+                               w[2] = buffer;
+                       }
+                       if (!tomoyo_io_printf(head, "%s%s %s\n", w[0], w[1],
+                                             w[2]))
+                               return false;
+               }
+               head->read_var2 = NULL;
+       }
+       head->read_var1 = NULL;
+       return true;
+}
+
+/**
+ * tomoyo_read_policy - Read "struct tomoyo_..._entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @idx:  Index number.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
+{
+       list_for_each_cookie(head->read_var2, &tomoyo_policy_list[idx]) {
+               const char *w[4] = { "", "", "", "" };
+               struct tomoyo_acl_head *acl =
+                       container_of(head->read_var2, typeof(*acl), list);
+               if (acl->is_deleted)
+                       continue;
+               switch (idx) {
+               case TOMOYO_ID_TRANSITION_CONTROL:
+                       {
+                               struct tomoyo_transition_control *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               w[0] = tomoyo_transition_type[ptr->type];
+                               if (ptr->program)
+                                       w[1] = ptr->program->name;
+                               if (ptr->domainname)
+                                       w[3] = ptr->domainname->name;
+                               if (w[1][0] && w[3][0])
+                                       w[2] = " from ";
+                       }
                        break;
+               case TOMOYO_ID_GLOBALLY_READABLE:
+                       {
+                               struct tomoyo_globally_readable_file_entry *ptr
+                                       = container_of(acl, typeof(*ptr), head);
+                               w[0] = TOMOYO_KEYWORD_ALLOW_READ;
+                               w[1] = ptr->filename->name;
+                       }
+                       break;
+               case TOMOYO_ID_AGGREGATOR:
+                       {
+                               struct tomoyo_aggregator_entry *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               w[0] = TOMOYO_KEYWORD_AGGREGATOR;
+                               w[1] = ptr->original_name->name;
+                               w[2] = " ";
+                               w[3] = ptr->aggregated_name->name;
+                       }
+                       break;
+               case TOMOYO_ID_PATTERN:
+                       {
+                               struct tomoyo_pattern_entry *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               w[0] = TOMOYO_KEYWORD_FILE_PATTERN;
+                               w[1] = ptr->pattern->name;
+                       }
+                       break;
+               case TOMOYO_ID_NO_REWRITE:
+                       {
+                               struct tomoyo_no_rewrite_entry *ptr =
+                                       container_of(acl, typeof(*ptr), head);
+                               w[0] = TOMOYO_KEYWORD_DENY_REWRITE;
+                               w[1] = ptr->pattern->name;
+                       }
+                       break;
+               default:
+                       continue;
                }
+               if (!tomoyo_io_printf(head, "%s%s%s%s\n", w[0], w[1], w[2],
+                                     w[3]))
+                       return false;
        }
+       head->read_var2 = NULL;
+       return true;
+}
+
+/**
+ * tomoyo_read_exception_policy - Read exception policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static void tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
+{
+       if (head->read_eof)
+               return;
+       while (head->read_step < TOMOYO_MAX_POLICY &&
+              tomoyo_read_policy(head, head->read_step))
+               head->read_step++;
+       if (head->read_step < TOMOYO_MAX_POLICY)
+               return;
+       while (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP &&
+              tomoyo_read_group(head, head->read_step - TOMOYO_MAX_POLICY))
+               head->read_step++;
+       if (head->read_step < TOMOYO_MAX_POLICY + TOMOYO_MAX_GROUP)
+               return;
+       head->read_eof = true;
 }
 
 /**