This patch allows administrators use conditional permission.
TOMOYO Linux supports conditional permission based on
process's UID,GID etc. and/or requested pathname's UID/GID.

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 security/tomoyo/condition.c |  680 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 680 insertions(+)

--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/security/tomoyo/condition.c       2007-10-02 11:26:22.000000000 
+0900
@@ -0,0 +1,680 @@
+/*
+ * security/tomoyo/condition.c
+ *
+ * Functions to support conditional access control for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/**
+ * tmy_find_condition_part - check whether a line contains condition part.
+ * @data: a line to check.
+ *
+ * Returns pointer to condition part if found.
+ * Returns NULL if not found.
+ *
+ * Since the trailing spaces are removed by tmy_normalize_line(),
+ * the last "\040if\040" sequence corresponds to condition part.
+ */
+char *tmy_find_condition_part(char *data)
+{
+       char *cp = strstr(data, " if ");
+       if (cp) {
+               char *cp2;
+               while ((cp2 = strstr(cp + 3, " if ")) != NULL)
+                       cp = cp2;
+               *cp++ = '\0';
+       }
+       return cp;
+}
+
+#define VALUE_TYPE_DECIMAL     1 /* 01 */
+#define VALUE_TYPE_OCTAL       2 /* 10 */
+#define VALUE_TYPE_HEXADECIMAL 3 /* 11 */
+
+static int tmy_parse_ulong(unsigned long *result, const char **str)
+{
+       const char *cp = *str;
+       char *ep;
+       int base = 10;
+       if (*cp == '0') {
+               char c = *(cp + 1);
+               if (c == 'x' || c == 'X') {
+                       base = 16; cp += 2;
+               } else if (c >= '0' && c <= '7') {
+                       base = 8; cp++;
+               }
+       }
+       *result = simple_strtoul(cp, &ep, base);
+       if (cp == ep) return 0; /* 00 */
+       *str = ep;
+       return (base == 16 ? VALUE_TYPE_HEXADECIMAL :
+               (base == 8 ? VALUE_TYPE_OCTAL : VALUE_TYPE_DECIMAL));
+}
+
+static void tmy_print_ulong(char *buffer, const int buffer_len,
+                       const unsigned long value, const int type)
+{
+       if (type == VALUE_TYPE_DECIMAL)
+               snprintf(buffer, buffer_len, "%lu", value);
+       else if (type == VALUE_TYPE_OCTAL)
+               snprintf(buffer, buffer_len, "0%lo", value);
+       else
+               snprintf(buffer, buffer_len, "0x%lX", value);
+}
+
+/* List of conditins. */
+static struct condition_list {
+       struct condition_list *next;
+       int length;
+       /* "unsigned long condition[length]" comes here.*/
+} head;
+
+#define TASK_UID          0
+#define TASK_EUID         1
+#define TASK_SUID         2
+#define TASK_FSUID        3
+#define TASK_GID          4
+#define TASK_EGID         5
+#define TASK_SGID         6
+#define TASK_FSGID        7
+#define TASK_PID          8
+#define TASK_PPID         9
+#define PATH1_UID        10
+#define PATH1_GID        11
+#define PATH1_INO        12
+#define PATH1_PARENT_UID 13
+#define PATH1_PARENT_GID 14
+#define PATH1_PARENT_INO 15
+#define PATH2_PARENT_UID 16
+#define PATH2_PARENT_GID 17
+#define PATH2_PARENT_INO 18
+#define MAX_KEYWORD      19
+
+static struct {
+       const char *keyword;
+       const int keyword_len; /* strlen(keyword) */
+} cc_keyword[MAX_KEYWORD] = {
+       [TASK_UID]         = { "task.uid",           8 },
+       [TASK_EUID]        = { "task.euid",          9 },
+       [TASK_SUID]        = { "task.suid",          9 },
+       [TASK_FSUID]       = { "task.fsuid",        10 },
+       [TASK_GID]         = { "task.gid",           8 },
+       [TASK_EGID]        = { "task.egid",          9 },
+       [TASK_SGID]        = { "task.sgid",          9 },
+       [TASK_FSGID]       = { "task.fsgid",        10 },
+       [TASK_PID]         = { "task.pid",           8 },
+       [TASK_PPID]        = { "task.ppid",          9 },
+       [PATH1_UID]        = { "path1.uid",          9 },
+       [PATH1_GID]        = { "path1.gid",          9 },
+       [PATH1_INO]        = { "path1.ino",          9 },
+       [PATH1_PARENT_UID] = { "path1.parent.uid",  16 },
+       [PATH1_PARENT_GID] = { "path1.parent.gid",  16 },
+       [PATH1_PARENT_INO] = { "path1.parent.ino",  16 },
+       [PATH2_PARENT_UID] = { "path2.parent.uid",  16 },
+       [PATH2_PARENT_GID] = { "path2.parent.gid",  16 },
+       [PATH2_PARENT_INO] = { "path2.parent.ino",  16 }
+};
+
+/**
+ * tmy_assign_condition - create condition part.
+ * @condition: pointer to condition part.
+ *
+ * Returns pointer to "struct condition_list" on success.
+ * Returns NULL on failure.
+ */
+const struct condition_list *tmy_assign_condition(const char *condition)
+{
+       const char *start;
+       struct condition_list *ptr;
+       struct condition_list *new_ptr;
+       unsigned long *ptr2;
+       int counter = 0;
+       int size;
+       int left;
+       int right;
+       unsigned long left_min = 0;
+       unsigned long left_max = 0;
+       unsigned long right_min = 0;
+       unsigned long right_max = 0;
+       if (strncmp(condition, "if ", 3))
+               return NULL;
+       condition += 3;
+       start = condition;
+       while (*condition) {
+               if (*condition == ' ')
+                       condition++;
+               for (left = 0; left < MAX_KEYWORD; left++) {
+                       if (strncmp(condition, cc_keyword[left].keyword,
+                                   cc_keyword[left].keyword_len))
+                               continue;
+                       condition += cc_keyword[left].keyword_len;
+                       break;
+               }
+               if (left == MAX_KEYWORD) {
+                       if (!tmy_parse_ulong(&left_min, &condition))
+                               goto out;
+                       counter++; /* body */
+                       if (*condition != '-')
+                               goto not_range1;
+                       condition++;
+                       if (!tmy_parse_ulong(&left_max, &condition)
+                           || left_min > left_max)
+                               goto out;
+                       counter++; /* body */
+not_range1: ;
+               }
+               if (strncmp(condition, "!=", 2) == 0)
+                       condition += 2;
+               else if (*condition == '=')
+                       condition++;
+               else
+                       goto out;
+               counter++; /* header */
+               for (right = 0; right < MAX_KEYWORD; right++) {
+                       if (strncmp(condition, cc_keyword[right].keyword,
+                                   cc_keyword[right].keyword_len))
+                               continue;
+                       condition += cc_keyword[right].keyword_len;
+                       break;
+               }
+               if (right == MAX_KEYWORD) {
+                       if (!tmy_parse_ulong(&right_min, &condition))
+                               goto out;
+                       counter++; /* body */
+                       if (*condition != '-')
+                               goto not_range2;
+                       condition++;
+                       if (!tmy_parse_ulong(&right_max, &condition)
+                           || right_min > right_max)
+                               goto out;
+                       counter++; /* body */
+not_range2: ;
+               }
+       }
+       size = sizeof(*new_ptr) + counter * sizeof(unsigned long);
+       new_ptr = tmy_alloc(size);
+       if (!new_ptr)
+               return NULL;
+       new_ptr->length = counter;
+       ptr2 = (unsigned long *) (((u8 *) new_ptr) + sizeof(*new_ptr));
+       condition = start;
+       while (*condition) {
+               unsigned int match = 0;
+               if (*condition == ' ')
+                       condition++;
+               for (left = 0; left < MAX_KEYWORD; left++) {
+                       if (strncmp(condition, cc_keyword[left].keyword,
+                           cc_keyword[left].keyword_len))
+                               continue;
+                       condition += cc_keyword[left].keyword_len;
+                       break;
+               }
+               if (left == MAX_KEYWORD) {
+                       match |= tmy_parse_ulong(&left_min, &condition) << 2;
+                       counter--; /* body */
+                       if (*condition != '-')
+                               goto not_range3;
+                       condition++;
+                       match |= tmy_parse_ulong(&left_max, &condition) << 4;
+                       counter--; /* body */
+                       left++;
+not_range3: ;
+               }
+               if (strncmp(condition, "!=", 2) == 0)
+                       condition += 2;
+               else if (*condition == '=') {
+                       match |= 1; condition++;
+               } else
+                       goto out2;
+               counter--; /* header */
+               for (right = 0; right < MAX_KEYWORD; right++) {
+                       if (strncmp(condition, cc_keyword[right].keyword,
+                           cc_keyword[right].keyword_len))
+                               continue;
+                       condition += cc_keyword[right].keyword_len;
+                       break;
+               }
+               if (right == MAX_KEYWORD) {
+                       match |= tmy_parse_ulong(&right_min, &condition) << 6;
+                       counter--; /* body */
+                       if (*condition != '-')
+                               goto not_range4;
+                       condition++;
+                       match |= tmy_parse_ulong(&right_max, &condition) << 8;
+                       counter--; /* body */
+                       right++;
+not_range4: ;
+               }
+               if (counter < 0)
+                       goto out2;
+               *ptr2++ = (match << 16) | (left << 8) | right;
+               if (left >= MAX_KEYWORD)
+                       *ptr2++ = left_min;
+               if (left == MAX_KEYWORD + 1)
+                       *ptr2++ = left_max;
+               if (right >= MAX_KEYWORD)
+                       *ptr2++ = right_min;
+               if (right == MAX_KEYWORD + 1)
+                       *ptr2++ = right_max;
+       }
+       {
+               static DECLARE_MUTEX(lock);
+               struct condition_list *prev = NULL;
+               down(&lock);
+               for (ptr = &head; ptr; prev = ptr, ptr = ptr->next) {
+                       /* Don't compare if size differs. */
+                       if (ptr->length != new_ptr->length)
+                               continue;
+                       /*
+                        * Compare ptr and new_ptr
+                        * except ptr->next and new_ptr->next .
+                        */
+                       if (memcmp(((u8 *) ptr) + sizeof(ptr->next),
+                                  ((u8 *) new_ptr) + sizeof(new_ptr->next),
+                                  size - sizeof(ptr->next)))
+                               continue;
+                       /* Same entry found. Share this entry. */
+                       tmy_free(new_ptr);
+                       new_ptr = ptr;
+                       goto ok;
+               }
+               /* Same entry not found. Save this entry. */
+               ptr = tmy_alloc_element(size);
+               if (ptr)
+                       memmove(ptr, new_ptr, size);
+               tmy_free(new_ptr);
+               new_ptr = ptr;
+               /* Append to chain. */
+               prev->next = new_ptr;
+ok: ;
+               up(&lock);
+       }
+       return new_ptr;
+out2: ;
+       tmy_free(new_ptr);
+out: ;
+       return NULL;
+}
+
+/* Get inode's attribute information. */
+static void tmy_get_attributes(struct obj_info *obj)
+{
+       struct vfsmount *mnt;
+       struct dentry *dentry;
+       struct inode *inode;
+       struct kstat stat;
+
+       mnt = obj->path1_vfsmnt;
+       dentry = obj->path1_dentry;
+       inode = dentry->d_inode;
+       if (inode) {
+               if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
+                       /* Nothing to do. */
+               } else {
+                       obj->path1_stat.uid = stat.uid;
+                       obj->path1_stat.gid = stat.gid;
+                       obj->path1_stat.ino = stat.ino;
+                       obj->path1_valid = 1;
+               }
+       }
+
+       dentry = dget_parent(obj->path1_dentry);
+       inode = dentry->d_inode;
+       if (inode) {
+               if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
+                       /* Nothing to do. */
+               } else {
+                       obj->path1_parent_stat.uid = stat.uid;
+                       obj->path1_parent_stat.gid = stat.gid;
+                       obj->path1_parent_stat.ino = stat.ino;
+                       obj->path1_parent_valid = 1;
+               }
+       }
+       dput(dentry);
+
+       mnt = obj->path2_vfsmnt;
+       if (mnt) {
+               dentry = dget_parent(obj->path2_dentry);
+               inode = dentry->d_inode;
+               if (inode) {
+                       if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
+                               /* Nothing to do. */
+                       } else {
+                               obj->path2_parent_stat.uid = stat.uid;
+                               obj->path2_parent_stat.gid = stat.gid;
+                               obj->path2_parent_stat.ino = stat.ino;
+                               obj->path2_parent_valid = 1;
+                       }
+               }
+               dput(dentry);
+       }
+}
+
+/**
+ * tmy_check_condition - check condition part.
+ * @ptr: pointer to "struct condition_list".
+ * @obj: pointer to "struct obj_info". May be NULL.
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ */
+int tmy_check_condition(const struct condition_list *ptr, struct obj_info *obj)
+{
+       struct task_struct *task = current;
+       int i;
+       unsigned long left_min = 0;
+       unsigned long left_max = 0;
+       unsigned long right_min = 0;
+       unsigned long right_max = 0;
+       const unsigned long *ptr2;
+       if (!ptr)
+               return 0;
+       ptr2 = (unsigned long *) (((u8 *) ptr) + sizeof(*ptr));
+       for (i = 0; i < ptr->length; i++) {
+               const u8 match = ((*ptr2) >> 16) & 1;
+               const u8 left = (*ptr2) >> 8;
+               const u8 right = *ptr2;
+               ptr2++;
+               if ((left >= PATH1_UID && left < MAX_KEYWORD)
+                   || (right >= PATH1_UID && right < MAX_KEYWORD)) {
+                       if (!obj)
+                               goto out;
+                       if (!obj->validate_done) {
+                               tmy_get_attributes(obj);
+                               obj->validate_done = 1;
+                       }
+               }
+               switch (left) {
+               case TASK_UID:
+                       left_min = task->uid;
+                       left_max = left_min;
+                       break;
+               case TASK_EUID:
+                       left_min = task->euid;
+                       left_max = left_min;
+                       break;
+               case TASK_SUID:
+                       left_min = task->suid;
+                       left_max = left_min;
+                       break;
+               case TASK_FSUID:
+                       left_min = task->fsuid;
+                       left_max = left_min;
+                       break;
+               case TASK_GID:
+                       left_min = task->gid;
+                       left_max = left_min;
+                       break;
+               case TASK_EGID:
+                       left_min = task->egid;
+                       left_max = left_min;
+                       break;
+               case TASK_SGID:
+                       left_min = task->sgid;
+                       left_max = left_min;
+                       break;
+               case TASK_FSGID:
+                       left_min = task->fsgid;
+                       left_max = left_min;
+                       break;
+               case TASK_PID:
+                       left_min = task->pid;
+                       left_max = left_min;
+                       break;
+               case TASK_PPID:
+                       left_min = sys_getppid();
+                       left_max = left_min;
+                       break;
+               case PATH1_UID:
+                       if (!obj->path1_valid)
+                               goto out;
+                       left_min = obj->path1_stat.uid;
+                       left_max = left_min;
+                       break;
+               case PATH1_GID:
+                       if (!obj->path1_valid)
+                               goto out;
+                       left_min = obj->path1_stat.gid;
+                       left_max = left_min;
+                       break;
+               case PATH1_INO:
+                       if (!obj->path1_valid)
+                               goto out;
+                       left_min = obj->path1_stat.ino;
+                       left_max = left_min;
+                       break;
+               case PATH1_PARENT_UID:
+                       if (!obj->path1_parent_valid)
+                               goto out;
+                       left_min = obj->path1_parent_stat.uid;
+                       left_max = left_min;
+                       break;
+               case PATH1_PARENT_GID:
+                       if (!obj->path1_parent_valid)
+                               goto out;
+                       left_min = obj->path1_parent_stat.gid;
+                       left_max = left_min;
+                       break;
+               case PATH1_PARENT_INO:
+                       if (!obj->path1_parent_valid)
+                               goto out;
+                       left_min = obj->path1_parent_stat.ino;
+                       left_max = left_min;
+                       break;
+               case PATH2_PARENT_UID:
+                       if (!obj->path2_parent_valid)
+                               goto out;
+                       left_min = obj->path2_parent_stat.uid;
+                       left_max = left_min;
+                       break;
+               case PATH2_PARENT_GID:
+                       if (!obj->path2_parent_valid)
+                               goto out;
+                       left_min = obj->path2_parent_stat.gid;
+                       left_max = left_min;
+                       break;
+               case PATH2_PARENT_INO:
+                       if (!obj->path2_parent_valid)
+                               goto out;
+                       left_min = obj->path2_parent_stat.ino;
+                       left_max = left_min;
+                       break;
+               case MAX_KEYWORD:
+                       left_min = *ptr2++;
+                       left_max = left_min;
+                       i++;
+                       break;
+               case MAX_KEYWORD + 1:
+                       left_min = *ptr2++;
+                       left_max = *ptr2++;
+                       i += 2;
+                       break;
+               }
+               switch (right) {
+               case TASK_UID:
+                       right_min = task->uid;
+                       right_max = right_min;
+                       break;
+               case TASK_EUID:
+                       right_min = task->euid;
+                       right_max = right_min;
+                       break;
+               case TASK_SUID:
+                       right_min = task->suid;
+                       right_max = right_min;
+                       break;
+               case TASK_FSUID:
+                       right_min = task->fsuid;
+                       right_max = right_min;
+                       break;
+               case TASK_GID:
+                       right_min = task->gid;
+                       right_max = right_min;
+                       break;
+               case TASK_EGID:
+                       right_min = task->egid;
+                       right_max = right_min;
+                       break;
+               case TASK_SGID:
+                       right_min = task->sgid;
+                       right_max = right_min;
+                       break;
+               case TASK_FSGID:
+                       right_min = task->fsgid;
+                       right_max = right_min;
+                       break;
+               case TASK_PID:
+                       right_min = task->pid;
+                       right_max = right_min;
+                       break;
+               case TASK_PPID:
+                       right_min = sys_getppid();
+                       right_max = right_min;
+                       break;
+               case PATH1_UID:
+                       if (!obj->path1_valid)
+                               goto out;
+                       right_min = obj->path1_stat.uid;
+                       right_max = right_min;
+                       break;
+               case PATH1_GID:
+                       if (!obj->path1_valid)
+                               goto out;
+                       right_min = obj->path1_stat.gid;
+                       right_max = right_min;
+                       break;
+               case PATH1_INO:
+                       if (!obj->path1_valid)
+                               goto out;
+                       right_min = obj->path1_stat.ino;
+                       right_max = right_min;
+                       break;
+               case PATH1_PARENT_UID:
+                       if (!obj->path1_parent_valid)
+                               goto out;
+                       right_min = obj->path1_parent_stat.uid;
+                       right_max = right_min;
+                       break;
+               case PATH1_PARENT_GID:
+                       if (!obj->path1_parent_valid)
+                               goto out;
+                       right_min = obj->path1_parent_stat.gid;
+                       right_max = right_min;
+                       break;
+               case PATH1_PARENT_INO:
+                       if (!obj->path1_parent_valid)
+                               goto out;
+                       right_min = obj->path1_parent_stat.ino;
+                       right_max = right_min;
+                       break;
+               case PATH2_PARENT_UID:
+                       if (!obj->path2_parent_valid)
+                               goto out;
+                       right_min = obj->path2_parent_stat.uid;
+                       right_max = right_min;
+                       break;
+               case PATH2_PARENT_GID:
+                       if (!obj->path2_parent_valid)
+                               goto out;
+                       right_min = obj->path2_parent_stat.gid;
+                       right_max = right_min;
+                       break;
+               case PATH2_PARENT_INO:
+                       if (!obj->path2_parent_valid)
+                               goto out;
+                       right_min = obj->path2_parent_stat.ino;
+                       right_max = right_min;
+                       break;
+               case MAX_KEYWORD:
+                       right_min = *ptr2++;
+                       right_max = right_min;
+                       i++;
+                       break;
+               case MAX_KEYWORD + 1:
+                       right_min = *ptr2++;
+                       right_max = *ptr2++;
+                       i += 2;
+                       break;
+               }
+               if (match) {
+                       if (left_min <= right_max && left_max >= right_min)
+                               continue;
+               } else {
+                       if (left_min > right_max || left_max < right_min)
+                               continue;
+               }
+out: ;
+               return -EPERM;
+       }
+       return 0;
+}
+
+/**
+ * tmy_dump_condition - dump condition part.
+ * @head: pointer to "struct io_buffer".
+ * @ptr:  pointer to "struct condition_list". May be NULL.
+ *
+ * Returns nonzero if reading incomplete.
+ * Returns zero otherwise.
+ */
+int tmy_dump_condition(struct io_buffer *head, const struct condition_list 
*ptr)
+{
+       int i;
+       const unsigned long *ptr2;
+       char buffer[32];
+       if (!ptr)
+               goto last;
+       ptr2 = (unsigned long *) (((u8 *) ptr) + sizeof(*ptr));
+       memset(buffer, 0, sizeof(buffer));
+       for (i = 0; i < ptr->length; i++) {
+               const u16 match = (*ptr2) >> 16;
+               const u8 left = (*ptr2) >> 8;
+               const u8 right = *ptr2;
+               ptr2++;
+               if (tmy_io_printf(head, "%s", i ? " " : " if "))
+                       break;
+               if (left < MAX_KEYWORD) {
+                       if (tmy_io_printf(head, "%s", cc_keyword[left].keyword))
+                               break;
+               } else {
+                       tmy_print_ulong(buffer, sizeof(buffer) - 1, *ptr2++,
+                                       (match >> 2) & 3);
+                       if (tmy_io_printf(head, "%s", buffer))
+                               break;
+                       i++;
+                       if (left == MAX_KEYWORD + 1) {
+                               tmy_print_ulong(buffer, sizeof(buffer) - 1,
+                                               *ptr2++, (match >> 4) & 3);
+                               if (tmy_io_printf(head, "-%s", buffer))
+                                       break;
+                               i++;
+                       }
+               }
+               if (tmy_io_printf(head, "%s", (match & 1) ? "=" : "!="))
+                       break;
+               if (right < MAX_KEYWORD) {
+                       if (tmy_io_printf(head, "%s",
+                                         cc_keyword[right].keyword))
+                               break;
+               } else {
+                       tmy_print_ulong(buffer, sizeof(buffer) - 1, *ptr2++,
+                                       (match >> 6) & 3);
+                       if (tmy_io_printf(head, "%s", buffer))
+                               break;
+                       i++;
+                       if (right == MAX_KEYWORD + 1) {
+                               tmy_print_ulong(buffer, sizeof(buffer) - 1,
+                                               *ptr2++, (match >> 8) & 3);
+                               if (tmy_io_printf(head, "-%s", buffer))
+                                       break;
+                               i++;
+                       }
+               }
+       }
+       if (i < ptr->length)
+               return -ENOMEM;
+last: ;
+       return tmy_io_printf(head, "\n") ? -ENOMEM : 0;
+}


-
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

Reply via email to