Re: [patch v3] mm, oom: fix unnecessary killing of additional processes

2018-07-03 Thread penguin-kernel
David Rientjes wrote:
> Ping?
> 
> This can be something that can easily be removed if it becomes obsoleted 
> because the oom reaper is always able to free memory to the extent of 
> exit_mmap().  I argue that it cannot, because it cannot do free_pgtables() 
> for large amounts of virtual memory, but am fine to be proved wrong.

This is "[PATCH 3/8] mm,oom: Fix unnecessary killing of additional processes." 
in my series.

> 
> In the meantime, however, this patch should introduce no significant 
> change in functionality and the only interface it is added is in debugfs 
> and can easily be removed if it is obsoleted.
> 
> The work to make the oom reaper more effective or realible can still 
> continue with this patch.
> 


Re: [patch v3] mm, oom: fix unnecessary killing of additional processes

2018-07-03 Thread penguin-kernel
David Rientjes wrote:
> Ping?
> 
> This can be something that can easily be removed if it becomes obsoleted 
> because the oom reaper is always able to free memory to the extent of 
> exit_mmap().  I argue that it cannot, because it cannot do free_pgtables() 
> for large amounts of virtual memory, but am fine to be proved wrong.

This is "[PATCH 3/8] mm,oom: Fix unnecessary killing of additional processes." 
in my series.

> 
> In the meantime, however, this patch should introduce no significant 
> change in functionality and the only interface it is added is in debugfs 
> and can easily be removed if it is obsoleted.
> 
> The work to make the oom reaper more effective or realible can still 
> continue with this patch.
> 


Re: [patch 1/2] [RFC] Simple tamper-proof device filesystem.

2007-12-16 Thread penguin-kernel
Hello.

David Wagner wrote:
> If the attacker gets full administrator-level access on your machine,
> there are a gazillion ways the attacker can prevent other admins from
> logging on. This patch can't prevent that.  It sounds like this patch
> is trying to solve a fundamentally unsolveable problem.

Please be aware that I'm saying "if this filesystem is used with MAC".

Without MAC, an attacker who got root privilege can do whatever he/she want to 
do.
But with MAC, an attacker who got root privilege can't do whatever he/she want 
to do.
Only actions permitted by MAC's policy are permitted for the attacker who got 
root privilege.

I'm not saying that
"this filesystem can prevent attackers from mounting other filesystem over this 
filesystem",
nor "this filesystem can prevent attackers from executing /sbin/iptables or 
/usr/bin/passwd".
They are MAC's business.
What this filesystem can do is "guarantee filename and its attribute".

If MAC(such as SELinux, TOMOYO Linux) allows attackers to
"mount other filesystem over this filesystem", this filesystem is no longer 
tamper-proof.
But as long as MAC prevents attackers from mounting other filesystem over this 
filesystem,
this filesystem can remain tamper-proof.

Regards.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [patch 1/2] [RFC] Simple tamper-proof device filesystem.

2007-12-16 Thread penguin-kernel
Hello.

David Wagner wrote:
 If the attacker gets full administrator-level access on your machine,
 there are a gazillion ways the attacker can prevent other admins from
 logging on. This patch can't prevent that.  It sounds like this patch
 is trying to solve a fundamentally unsolveable problem.

Please be aware that I'm saying if this filesystem is used with MAC.

Without MAC, an attacker who got root privilege can do whatever he/she want to 
do.
But with MAC, an attacker who got root privilege can't do whatever he/she want 
to do.
Only actions permitted by MAC's policy are permitted for the attacker who got 
root privilege.

I'm not saying that
this filesystem can prevent attackers from mounting other filesystem over this 
filesystem,
nor this filesystem can prevent attackers from executing /sbin/iptables or 
/usr/bin/passwd.
They are MAC's business.
What this filesystem can do is guarantee filename and its attribute.

If MAC(such as SELinux, TOMOYO Linux) allows attackers to
mount other filesystem over this filesystem, this filesystem is no longer 
tamper-proof.
But as long as MAC prevents attackers from mounting other filesystem over this 
filesystem,
this filesystem can remain tamper-proof.

Regards.
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 05/18] Memory and pathname management functions.

2007-11-16 Thread penguin-kernel
Basic functions to get canonicalized absolute pathnames
for TOMOYO Linux. Even the requested pathname is symlink()ed
or chroot()ed, TOMOYO Linux uses the original pathname.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/realpath.c 2007-11-14 15:58:58.0 
+0900
@@ -0,0 +1,658 @@
+/*
+ * security/tomoyo/realpath.c
+ *
+ * Get the canonicalized absolute pathnames.
+ * The basis for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/* realpath handler */
+
+static int tmy_print_ascii(const char *sp, const char *cp,
+  int *buflen0, char **end0)
+{
+   int buflen = *buflen0;
+   char *end = *end0;
+
+   while (sp <= cp) {
+   unsigned char c;
+
+   c = *(unsigned char *) cp;
+   if (c == '\\') {
+   buflen -= 2;
+   if (buflen < 0)
+   goto out;
+   *--end = '\\';
+   *--end = '\\';
+   } else if (c > ' ' && c < 127) {
+   if (--buflen < 0)
+   goto out;
+   *--end = (char) c;
+   } else {
+   buflen -= 4;
+   if (buflen < 0)
+   goto out;
+   *--end = (c & 7) + '0';
+   *--end = ((c >> 3) & 7) + '0';
+   *--end = (c >> 6) + '0';
+   *--end = '\\';
+   }
+   cp--;
+   }
+
+   *buflen0 = buflen;
+   *end0 = end;
+
+   return 0;
+out: ;
+   return -ENOMEM;
+}
+
+/**
+ * tmy_get_absolute_path - return the realpath of a dentry.
+ * @dentry: pointer to "struct dentry".
+ * @vfsmnt: pointer to "struct vfsmount" to which the @dentry belongs.
+ * @buffer: size of buffer to save the result.
+ * @buflen: size of @buffer .
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ *
+ * Caller holds the dcache_lock.
+ * Based on __d_path() in fs/dcache.c
+ *
+ * Unlike d_path(), this function traverses upto the root directory of
+ * process's namespace.
+ *
+ * If @dentry is a directory, trailing '/' is appended.
+ * Characters other than ' ' < c < 127 are converted to \ooo style octal 
string.
+ * Character \ is converted to \\ string.
+ */
+static int tmy_get_absolute_path(struct dentry *dentry,
+struct vfsmount *vfsmnt,
+char *buffer,
+int buflen)
+{
+   char *start = buffer;
+   char *end = buffer + buflen;
+   bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
+   const char *sp;
+   const char *cp;
+
+   if (buflen < 256)
+   goto out;
+
+   *--end = '\0';
+   buflen--;
+
+   while (1) {
+   struct dentry *parent;
+
+   if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+   /* Global root? */
+   spin_lock(_lock);
+   if (vfsmnt->mnt_parent == vfsmnt) {
+   spin_unlock(_lock);
+   break;
+   }
+   dentry = vfsmnt->mnt_mountpoint;
+   vfsmnt = vfsmnt->mnt_parent;
+   spin_unlock(_lock);
+   continue;
+   }
+
+   if (is_dir) {
+   is_dir = 0;
+   *--end = '/';
+   buflen--;
+   }
+
+   parent = dentry->d_parent;
+   sp = dentry->d_name.name;
+   cp = sp + dentry->d_name.len - 1;
+
+   /* Exception: Use /proc/self/ rather than */
+   /* /proc/\$/ for current process. */
+   if (IS_ROOT(parent) &&
+   *sp > '0' && *sp <= '9' && parent->d_sb &&
+   parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
+
+   char *ep;
+   const pid_t pid = (pid_t) simple_strtoul(sp, , 10);
+
+   if (!*ep && pid == current->tgid) {
+   sp = "self";
+   cp = sp + 3;
+   }
+
+   }
+
+   if (tmy_print_ascii(sp, cp, , ))
+   goto out;
+
+   if (--buflen < 0)
+   goto out;
+   *--end = '/';
+
+   dentry = parent;
+   }
+   if (*end == '/') {
+   buflen++;
+   end++;
+   }
+
+   sp = dentry->d_name.name;
+   cp = sp + dentry->d_name.len - 

[TOMOYO #5 15/18] LSM adapter functions.

2007-11-16 Thread penguin-kernel
To avoid namespace_sem deadlock, this patch uses
"current->last_vfsmount" associated by wrapper functions.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/tomoyo.c   2007-11-14 15:56:26.0 
+0900
@@ -0,0 +1,822 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+LIST_HEAD(domain_list);
+
+static struct kmem_cache *tmy_cachep;
+
+static int tmy_task_alloc_security(struct task_struct *p)
+{
+   struct tmy_security *ptr = kmem_cache_alloc(tmy_cachep, GFP_KERNEL);
+
+   if (!ptr)
+   return -ENOMEM;
+   memcpy(ptr, TMY_SECURITY, sizeof(*ptr));
+   p->security = ptr;
+   return 0;
+}
+
+static void tmy_task_free_security(struct task_struct *p)
+{
+   kmem_cache_free(tmy_cachep, p->security);
+}
+
+static int tmy_bprm_alloc_security(struct linux_binprm *bprm)
+{
+   TMY_SECURITY->prev_domain = TMY_SECURITY->domain;
+   return 0;
+}
+
+static int tmy_bprm_check_security(struct linux_binprm *bprm)
+{
+   struct domain_info *next_domain = NULL;
+   int retval = 0;
+
+   tmy_load_policy(bprm->filename);
+
+   /*
+* TMY_CHECK_READ_FOR_OPEN_EXEC bit indicates whether this function is
+* called by do_execve() or not.
+* If called by do_execve(), I do domain transition.
+*/
+   if (!(TMY_SECURITY->flags
+ & TMY_CHECK_READ_FOR_OPEN_EXEC)) {
+   retval = tmy_find_next_domain(bprm, _domain);
+   if (retval == 0) {
+   TMY_SECURITY->domain = next_domain;
+   TMY_SECURITY->flags |=
+   TMY_CHECK_READ_FOR_OPEN_EXEC;
+   }
+   }
+
+   return retval;
+}
+
+static void tmy_bprm_post_apply_creds(struct linux_binprm *bprm)
+{
+   TMY_SECURITY->prev_domain = TMY_SECURITY->domain;
+}
+
+static void tmy_bprm_free_security(struct linux_binprm *bprm)
+{
+   TMY_SECURITY->domain = TMY_SECURITY->prev_domain;
+   TMY_SECURITY->flags &= ~TMY_CHECK_READ_FOR_OPEN_EXEC;
+}
+
+static int tmy_sysctl(struct ctl_table *table, int op)
+{
+   int error;
+   char *name;
+
+   if ((op & 6) == 0)
+   return 0;
+
+   name = sysctlpath_from_table(table);
+   if (!name)
+   return -ENOMEM;
+
+   error = tmy_file_perm(name, op & 6, "sysctl");
+   tmy_free(name);
+
+   return error;
+}
+
+static int tmy_inode_permission(struct inode *inode,
+   int mask,
+   struct nameidata *nd)
+{
+   int flag = 0;
+
+   if (S_ISDIR(inode->i_mode)) /* ignore because inode is directory */
+   return 0;
+   /*
+   if (!nd) {
+   printk("tmy_inode_permission: NULL nameidata\n");
+   dump_stack();
+   return 0;
+   } else if (!nd->mnt) {
+   printk("tmy_inode_permission: NULL vfsmount\n");
+   dump_stack();
+   return 0;
+   }
+   */
+   if (!nd || !nd->path.dentry || !nd->path.mnt)
+   return 0;
+   /*
+* If called by other than do_execve(), I check for read permission of
+* interpreter.
+* Unlike DAC, I don't check for read permission of pathname passed to
+* do_execve().
+* TOMOYO Linux checks for program's execute permission and
+* interpreter's read permission.
+*/
+   if ((mask == MAY_EXEC) &&
+   (TMY_SECURITY->flags & TMY_CHECK_READ_FOR_OPEN_EXEC))
+   mask = MAY_READ;
+   if ((mask == MAY_EXEC) || (mask == 0))
+   return 0;
+
+   if (mask == (MAY_READ | MAY_EXEC))
+   flag |= O_RDONLY + 1;
+   else {
+   if (mask & MAY_READ)
+   flag |= O_RDONLY + 1;
+   if (mask & MAY_WRITE)
+   flag |= O_WRONLY + 1;
+   if ((mask & MAY_APPEND))
+   flag |= O_APPEND;
+   }
+
+   return tmy_open_perm(nd->path.dentry, nd->path.mnt, flag);
+}
+
+static int tmy_do_single_write_perm(int operation, struct dentry *dentry)
+{
+   struct vfsmount *mnt = current->last_vfsmount;
+   if (!dentry || !mnt)
+   return 0;
+   if (!sbin_init_started)
+   return 0;
+   return tmy_single_write_perm(operation, dentry, mnt);
+}
+
+static int tmy_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+   int err = 0;
+   unsigned int ia_valid = iattr->ia_valid;
+   if (ia_valid & ATTR_MODE)
+   err = tmy_capable(TMY_SYS_CHMOD);
+   if (!err && (ia_valid & (ATTR_UID | 

[TOMOYO #5 16/18] Conditional permission support.

2007-11-16 Thread penguin-kernel
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 file changed, 680 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/condition.c2007-11-14 15:15:44.0 
+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, , 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_FSUID3
+#define TASK_GID  4
+#define TASK_EGID 5
+#define TASK_SGID 6
+#define TASK_FSGID7
+#define TASK_PID  8
+#define TASK_PPID 9
+#define PATH1_UID10
+#define PATH1_GID11
+#define PATH1_INO12
+#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 

[TOMOYO #5 14/18] Capability access control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks permission for non-POSIX capability
so that the number of capabilities won't be limited to 32 or 64.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/capability.c   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,320 @@
+/*
+ * security/tomoyo/capability.c
+ *
+ * Capability access control functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+static struct {
+   const char *keyword;
+   unsigned int current_value;
+   const char *capability_name;
+} capability_control_array[TMY_MAX_CAPABILITY_INDEX] = {
+   [TMY_INET_STREAM_SOCKET_CREATE]  = /* OK */
+   { "inet_tcp_create", 0, "socket(PF_INET, SOCK_STREAM)" },
+   [TMY_INET_STREAM_SOCKET_LISTEN]  = /* OK */
+   { "inet_tcp_listen", 0, "listen(PF_INET, SOCK_STREAM)" },
+   [TMY_INET_STREAM_SOCKET_CONNECT] = /* OK */
+   { "inet_tcp_connect", 0, "connect(PF_INET, SOCK_STREAM)" },
+   [TMY_USE_INET_DGRAM_SOCKET]  = /* OK */
+   { "use_inet_udp", 0, "socket(PF_INET, SOCK_DGRAM)" },
+   [TMY_USE_INET_RAW_SOCKET]= /* OK */
+   { "use_inet_ip", 0, "socket(PF_INET, SOCK_RAW)" },
+   [TMY_USE_ROUTE_SOCKET]   = /* OK */
+   { "use_route", 0, "socket(PF_ROUTE)" },
+   [TMY_USE_PACKET_SOCKET]  = /* OK */
+   { "use_packet", 0, "socket(PF_PACKET)" },
+   [TMY_SYS_MOUNT]  = /* OK */
+   { "SYS_MOUNT", 0, "sys_mount()" },
+   [TMY_SYS_UMOUNT] = /* OK */
+   { "SYS_UMOUNT", 0, "sys_umount()" },
+   [TMY_SYS_REBOOT] = /* Too many hooks. */
+   { "SYS_REBOOT", 0, "sys_reboot()" },
+   [TMY_SYS_CHROOT] = /* OK */
+   { "SYS_CHROOT", 0, "sys_chroot()" },
+   [TMY_SYS_KILL]   = /* No appropriate hook. */
+   { "SYS_KILL", 0, "sys_kill()" },
+   [TMY_SYS_VHANGUP]= /* Too many hooks. */
+   { "SYS_VHANGUP", 0, "sys_vhangup()" },
+   [TMY_SYS_SETTIME]= /* Too many hooks. */
+   { "SYS_TIME", 0, "sys_settimeofday()" },
+   [TMY_SYS_NICE]   = /* No appropriate hook. */
+   { "SYS_NICE", 0, "sys_nice()" },
+   [TMY_SYS_SETHOSTNAME]= /* No appropriate hook. */
+   { "SYS_SETHOSTNAME", 0, "sys_sethostname()" },
+   [TMY_USE_KERNEL_MODULE]  = /* Too many hooks. */
+   { "use_kernel_module", 0, "kernel_module" },
+   [TMY_CREATE_FIFO]= /* OK */
+   { "create_fifo", 0, "mknod(FIFO)" },
+   [TMY_CREATE_BLOCK_DEV]   = /* OK */
+   { "create_block_dev", 0, "mknod(BDEV)" },
+   [TMY_CREATE_CHAR_DEV]= /* OK */
+   { "create_char_dev", 0, "mknod(CDEV)" },
+   [TMY_CREATE_UNIX_SOCKET] = /* OK */
+   { "create_unix_socket", 0, "mknod(SOCKET)" },
+   [TMY_SYS_LINK]   = /* OK */
+   { "SYS_LINK", 0, "sys_link()" },
+   [TMY_SYS_SYMLINK]= /* OK */
+   { "SYS_SYMLINK", 0, "sys_symlink()" },
+   [TMY_SYS_RENAME] = /* OK */
+   { "SYS_RENAME", 0, "sys_rename()" },
+   [TMY_SYS_UNLINK] = /* OK */
+   { "SYS_UNLINK", 0, "sys_unlink()" },
+   [TMY_SYS_CHMOD]  = /* OK */
+   { "SYS_CHMOD", 0, "sys_chmod()" },
+   [TMY_SYS_CHOWN]  = /* OK */
+   { "SYS_CHOWN", 0, "sys_chown()" },
+   [TMY_SYS_IOCTL]  = /* Too many hooks. */
+   { "SYS_IOCTL", 0, "sys_ioctl()" },
+   [TMY_SYS_KEXEC_LOAD] = /* No appropriate hook. */
+   { "SYS_KEXEC_LOAD", 0, "sys_kexec_load()" },
+   [TMY_SYS_PIVOT_ROOT] = /* OK */
+   { "SYS_PIVOT_ROOT", 0, "sys_pivot_root()" },
+};
+
+struct profile {
+   unsigned char value[TMY_MAX_CAPABILITY_INDEX];
+};
+
+static struct profile *profile_ptr[TMY_MAX_PROFILES];
+
+/*  UTILITY FUNCTIONS  */
+
+const char *tmy_capability2keyword(const unsigned int capability)
+{
+   return capability < TMY_MAX_CAPABILITY_INDEX ?
+   capability_control_array[capability].keyword : NULL;
+}
+
+static const char *tmy_capability2name(const unsigned int capability)
+{
+   return capability < TMY_MAX_CAPABILITY_INDEX ?
+   capability_control_array[capability].capability_name : NULL;
+}
+
+/* Check whether the given capability control is enabled. */
+static unsigned int tmy_capability_flags(const unsigned int index)
+{
+   const u8 profile = TMY_SECURITY->domain->profile;
+   /* All operations might sleep. See tmy_supervisor(). 

[TOMOYO #5 18/18] LSM expansion for TOMOYO Linux.

2007-11-16 Thread penguin-kernel
LSM hooks for sending signal:
   * task_kill_unlocked is added in sys_kill
   * task_tkill_unlocked is added in sys_tkill
   * task_tgkill_unlocked is added in sys_tgkill
LSM hooks for network accept and recv:
   * socket_post_accept is modified to return int.
   * post_recv_datagram is added in skb_recv_datagram.

You can try TOMOYO Linux without this patch, but in that case, you
can't use access control functionality for restricting signal
transmission and incoming network data.

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
 include/linux/security.h |   74 +++
 kernel/signal.c  |   17 ++
 net/core/datagram.c  |   22 +
 net/socket.c |7 +++-
 security/dummy.c |   32 ++--
 security/security.c  |   25 ++-
 6 files changed, 165 insertions(+), 12 deletions(-)

--- linux-2.6-mm.orig/include/linux/security.h  2007-11-14 15:14:10.0 
+0900
+++ linux-2.6-mm/include/linux/security.h   2007-11-14 15:15:44.0 
+0900
@@ -657,6 +657,25 @@ struct request_sock;
  * @sig contains the signal value.
  * @secid contains the sid of the process where the signal originated
  * Return 0 if permission is granted.
+ * @task_kill_unlocked:
+ * Check permission before sending signal @sig to the process of @pid
+ * with sys_kill.
+ * @pid contains the pid of target process.
+ * @sig contains the signal value.
+ * Return 0 if permission is granted.
+ * @task_tkill_unlocked:
+ * Check permission before sending signal @sig to the process of @pid
+ * with sys_tkill.
+ * @pid contains the pid of target process.
+ * @sig contains the signal value.
+ * Return 0 if permission is granted.
+ * @task_tgkill_unlocked:
+ * Check permission before sending signal @sig to the process of @pid
+ * with sys_tgkill.
+ * @tgid contains the thread group id.
+ * @pid contains the pid of target process.
+ * @sig contains the signal value.
+ * Return 0 if permission is granted.
  * @task_wait:
  * Check permission before allowing a process to reap a child process @p
  * and collect its status information.
@@ -778,8 +797,12 @@ struct request_sock;
  * @socket_post_accept:
  * This hook allows a security module to copy security
  * information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers.
+ * The connection will be aborted if this hook returns nonzero.
  * @sock contains the listening socket structure.
  * @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
  * @socket_sendmsg:
  * Check permission before transmitting a message to another socket.
  * @sock contains the socket structure.
@@ -793,6 +816,12 @@ struct request_sock;
  * @size contains the size of message structure.
  * @flags contains the operational flags.
  * Return 0 if permission is granted.  
+ * @post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * @sk contains the socket.
+ * @skb contains the socket buffer (may be NULL).
+ * @flags contains the operational flags.
+ * Return 0 if permission is granted.
  * @socket_getsockname:
  * Check permission before the local address (name) of the socket object
  * @sock is retrieved.
@@ -1319,6 +1348,9 @@ struct security_operations {
int (*task_movememory) (struct task_struct * p);
int (*task_kill) (struct task_struct * p,
  struct siginfo * info, int sig, u32 secid);
+   int (*task_kill_unlocked) (int pid, int sig);
+   int (*task_tkill_unlocked) (int pid, int sig);
+   int (*task_tgkill_unlocked) (int tgid, int pid, int sig);
int (*task_wait) (struct task_struct * p);
int (*task_prctl) (int option, unsigned long arg2,
   unsigned long arg3, unsigned long arg4,
@@ -1384,12 +1416,16 @@ struct security_operations {
   struct sockaddr * address, int addrlen);
int (*socket_listen) (struct socket * sock, int backlog);
int (*socket_accept) (struct socket * sock, struct socket * newsock);
-   void (*socket_post_accept) (struct socket * sock,
-   struct socket * newsock);
+#define TMY_LSM_EXPANSION
+   int (*socket_post_accept) (struct socket *sock,
+  struct socket *newsock);
int (*socket_sendmsg) (struct socket * sock,
   struct msghdr * msg, int size);
int (*socket_recvmsg) (struct socket * sock,
   struct msghdr * msg, int size, int flags);
+   int (*post_recv_datagram) (struct sock *sk,
+  struct sk_buff *skb,
+   

[TOMOYO #5 17/18] Kconfig and Makefile

2007-11-16 Thread penguin-kernel
TOMOYO Linux is placed in security/tomoyo .

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
 security/Kconfig |1 +
 security/Makefile|1 +
 security/tomoyo/Kconfig  |   26 ++
 security/tomoyo/Makefile |2 ++
 4 files changed, 30 insertions(+)

--- linux-2.6-mm.orig/security/Kconfig  2007-11-14 15:12:08.0 +0900
+++ linux-2.6-mm/security/Kconfig   2007-11-14 15:15:44.0 +0900
@@ -104,6 +104,7 @@ config SECURITY_ROOTPLUG
  If you are unsure how to answer this question, answer N.
 
 source security/selinux/Kconfig
+source security/tomoyo/Kconfig
 
 endmenu
 
--- linux-2.6-mm.orig/security/Makefile 2007-10-10 05:31:38.0 +0900
+++ linux-2.6-mm/security/Makefile  2007-11-14 15:15:44.0 +0900
@@ -16,3 +16,4 @@ obj-$(CONFIG_SECURITY)+= security.o d
 obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)+= commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)+= commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_TOMOYO)   += tomoyo/
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/Kconfig2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,26 @@
+config SECURITY_TOMOYO
+   bool "TOMOYO Linux support"
+   depends on SECURITY
+   select SECURITY_NETWORK
+   default n
+   help
+ This selects TOMOYO Linux.
+
+ TOMOYO Linux is a domain-based access control method using LSM.
+ If you answer Y, you will need a policy loader program
+ (/sbin/tomoyo-init) and some configuration files.
+ You can get them from
+ 
+
+ TOMOYO Linux is also applicable to figuring out the behavior
+ of your system, for TOMOYO uses the canonicalized absolute
+ pathnames and TreeView style domain transitions.
+
+config SECURITY_TOMOYO_USE_AUDITD
+   bool "Use standard auditing subsystem"
+   depends on SECURITY_TOMOYO && AUDIT
+   default y
+   help
+ This makes messages sent to auditing subsystem.
+
+ If you say 'N' here, messages will be sent to printk().
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/Makefile   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo.o domain.o common.o realpath.o audit.o 
file.o exec.o net.o mount.o signal.o capability.o condition.o
+EXTRA_CFLAGS += -Isecurity/tomoyo/include

-- 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 13/18] Signal control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks sending signal by signal number and
the domain of target process. In order to check signal
permission, LSM expansion patch [TOMOYO 18/18] is needed.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/signal.c   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,227 @@
+/*
+ * security/tomoyo/signal.c
+ *
+ * Signal access contol functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/*  AUDIT FUNCTIONS  */
+
+static int tmy_audit_signal_log(const int signal,
+   const struct path_info *dest_domain,
+   const bool is_granted,
+   const u8 profile,
+   const unsigned int mode)
+{
+   char *buf;
+   int len;
+
+   if (is_granted) {
+   if (!tmy_audit_grant())
+   return 0;
+   } else {
+   if (!tmy_audit_reject())
+   return 0;
+   }
+
+   len = dest_domain->total_len;
+   buf = tmy_init_audit_log(, profile, mode);
+
+   if (!buf)
+   return -ENOMEM;
+
+   snprintf(buf + strlen(buf),
+len - strlen(buf) - 1,
+"%s%d %s\n",
+TMY_ALLOW_SIGNAL, signal, dest_domain->name);
+
+   return tmy_write_audit_log(buf, is_granted);
+}
+
+/*  SIGNAL ACL HANDLER  */
+
+static int tmy_add_signal_entry(const u16 sig, const char *dest_pattern,
+   struct domain_info *domain,
+   const struct condition_list *cond,
+   const bool is_delete)
+{
+   struct acl_info *ptr;
+   struct signal_acl *acl;
+   const struct path_info *saved_dest_pattern;
+   int error = -ENOMEM;
+
+   if (!domain)
+   return -EINVAL;
+   if (!dest_pattern ||
+   !tmy_is_correct_domain(dest_pattern, __FUNCTION__))
+   return -EINVAL;
+
+   saved_dest_pattern = tmy_save_name(dest_pattern);
+   if (!saved_dest_pattern)
+   return -ENOMEM;
+
+   mutex_lock(_acl_lock);
+
+   if (is_delete)
+   goto remove;
+
+   list_for_each_entry(ptr, >acl_info_list, list) {
+   acl = (struct signal_acl *) ptr;
+
+   if (ptr->type == TMY_TYPE_SIGNAL_ACL && acl->sig == sig
+   && ptr->cond == cond
+   && !tmy_pathcmp(acl->domainname, saved_dest_pattern)) {
+   ptr->is_deleted = 0;
+   /* Found. Nothing to do. */
+   error = 0;
+   goto ok;
+   }
+   }
+   /* Not found. Append it to the tail. */
+   acl = tmy_alloc_element(sizeof(*acl));
+   if (!acl)
+   goto ok;
+
+   acl->head.type = TMY_TYPE_SIGNAL_ACL;
+   acl->head.cond = cond;
+   acl->sig = sig;
+   acl->domainname = saved_dest_pattern;
+   error = tmy_add_acl(domain, (struct acl_info *) acl);
+   goto ok;
+remove: ;
+   error = -ENOENT;
+   list_for_each_entry(ptr, >acl_info_list, list) {
+   acl = (struct signal_acl *) ptr;
+   if (ptr->type != TMY_TYPE_SIGNAL_ACL || ptr->cond != cond ||
+   ptr->is_deleted || acl->sig != sig ||
+   tmy_pathcmp(acl->domainname, saved_dest_pattern))
+   continue;
+   error = tmy_del_acl(ptr);
+   break;
+   }
+
+ok: ;
+   mutex_unlock(_acl_lock);
+
+   return error;
+}
+
+/**
+ * tmy_signal_acl - check permission for kill(2)/tkill(2)/tgkill(2).
+ * @sig:  signal number.
+ * @pid:  pid of destination process.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_signal_acl(const int sig, const int pid)
+{
+   struct domain_info *domain = TMY_SECURITY->domain;
+   struct domain_info *dest = NULL;
+   const char *dest_pattern;
+   struct acl_info *ptr;
+   const u16 hash = sig;
+   const u8 profile = domain->profile;
+   const unsigned int mode = tmy_flags(TMY_MAC_FOR_SIGNAL);
+   const bool is_enforce = (mode == 3);
+   bool found = 0;
+
+   if (!mode)
+   return 0;
+   if (!sig)
+   return 0; /* No check for NULL signal. */
+   if (current->pid == pid) {
+   tmy_audit_signal_log(sig, domain->domainname, 1, profile, mode);
+   return 0; /* No check for self. */
+   }
+
+   { /* Simplified 

[TOMOYO #5 12/18] Namespace manipulation control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks mount permission based on
device name, mount point, filesystem type and optional flags.
TOMOYO Linux also checks permission in umount and pivot_root.

Each permission can be automatically accumulated into
the policy using 'learning mode'.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/mount.c2007-11-14 15:59:44.0 
+0900
@@ -0,0 +1,908 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Mount access control functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/* KEYWORDS for mount restrictions. */
+
+#define MOUNT_BIND_KEYWORD   "--bind"
+#define MOUNT_MOVE_KEYWORD   "--move"
+#define MOUNT_REMOUNT_KEYWORD"--remount"
+#define MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable"
+#define MOUNT_MAKE_PRIVATE_KEYWORD"--make-private"
+#define MOUNT_MAKE_SLAVE_KEYWORD  "--make-slave"
+#define MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
+
+/* The structure for mount restrictions. */
+
+struct mount_entry {
+   struct list_head list;
+   const struct path_info *dev_name;
+   const struct path_info *dir_name;
+   const struct path_info *fs_type;
+   unsigned int flags; /* Mount flags. */
+   bool is_deleted;
+};
+
+struct no_umount_entry {
+   struct list_head list;
+   const struct path_info *dir;
+   bool is_deleted;
+};
+
+/  MOUNT RESTRICTION HANDLER  /
+
+static LIST_HEAD(mount_list);
+
+/* Add or remove a mount entry. */
+static int tmy_add_mount_acl(const char *dev_name,
+const char *dir_name,
+const char *fs_type,
+const unsigned int flags,
+const bool is_delete)
+{
+   struct mount_entry *new_entry;
+   struct mount_entry  *ptr;
+   const struct path_info *fs;
+   const struct path_info *dev;
+   const struct path_info *dir;
+   static DEFINE_MUTEX(mutex);
+   int error = -ENOMEM;
+
+   fs = tmy_save_name(fs_type);
+   if (!fs)
+   return -EINVAL;
+
+   if (!dev_name)
+   /* Map dev_name to "" for if no dev_name given. */
+   dev_name = "";
+   if (strcmp(fs->name, MOUNT_REMOUNT_KEYWORD) == 0)
+   /* Fix dev_name to "any" for remount permission. */
+   dev_name = "any";
+   if (strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
+   strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
+   strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
+   strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD) == 0)
+   dev_name = "any";
+
+   if (!tmy_correct_path(dev_name, 0, 0, 0, __FUNCTION__) ||
+   !tmy_correct_path(dir_name, 1, 0, 1, __FUNCTION__))
+   return -EINVAL;
+
+   dev = tmy_save_name(dev_name);
+   if (!dev)
+   return -ENOMEM;
+   dir = tmy_save_name(dir_name);
+   if (!dir)
+   return -ENOMEM;
+
+   mutex_lock();
+
+   list_for_each_entry(ptr, _list, list) {
+   if (ptr->flags != flags ||
+   tmy_pathcmp(ptr->dev_name, dev) ||
+   tmy_pathcmp(ptr->dir_name, dir) ||
+   tmy_pathcmp(ptr->fs_type, fs))
+   continue;
+   ptr->is_deleted = is_delete;
+   error = 0;
+   goto out;
+   }
+
+   if (is_delete) {
+   error = -ENOENT;
+   goto out;
+   }
+
+   new_entry = tmy_alloc_element(sizeof(*new_entry));
+   if (!new_entry)
+   goto out;
+
+   new_entry->dev_name = dev;
+   new_entry->dir_name = dir;
+   new_entry->fs_type = fs;
+   new_entry->flags = flags;
+   list_add_tail_mb(_entry->list, _list);
+   error = 0;
+out: ;
+   mutex_unlock();
+   return error;
+}
+
+/* Print error message for mount request. */
+static inline int tmy_mount_perm_error(char *dev_name,
+  char *dir_name,
+  char *type,
+  unsigned long flags,
+  const u8 profile,
+  const unsigned int mode)
+{
+   int error = -EPERM;
+   const char *realname1 = tmy_realpath(dev_name);
+   const char *realname2 = tmy_realpath(dir_name);
+   const char *exename = tmy_get_exe();
+   const bool is_enforce = (mode == 3);
+
+   if (!strcmp(type, MOUNT_REMOUNT_KEYWORD)) {
+   tmy_audit(KERN_WARNING "TOMOYO-%s: mount -o remount %s 0x%lX "
+ "(pid=%d:exe=%s): Permission 

[TOMOYO #5 11/18] Network access control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks permission by the following four parameters.
  * protocol type (TCP, UDP, RAW)
  * access type (bind, listen, connect, accept)
  * IP address (Both IPv4 and IPv6 are available)
  * port number
In order to check 'TCP accept' and 'UDP connect',
LSM expansion patch ([TOMOYO 18/18]) is needed.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/net.c  2007-11-14 15:15:44.0 +0900
@@ -0,0 +1,952 @@
+/*
+ * security/tomoyo/net.c
+ *
+ * Network access control functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/*  AUDIT FUNCTIONS  */
+
+static int tmy_audit_network_log(const bool is_ipv6,
+const char *operation,
+const u32 *address,
+const u16 port,
+const bool is_granted,
+const u8 profile,
+const unsigned int mode)
+{
+   char *buf;
+   int len = 256;
+
+   if (is_granted) {
+   if (!tmy_audit_grant())
+   return 0;
+   } else {
+   if (!tmy_audit_reject())
+   return 0;
+   }
+
+   buf = tmy_init_audit_log(, profile, mode);
+   if (!buf)
+   return -ENOMEM;
+
+   snprintf(buf + strlen(buf), len - strlen(buf) - 1,
+TMY_ALLOW_NETWORK "%s ", operation);
+
+   if (is_ipv6)
+   tmy_print_ipv6(buf + strlen(buf), len - strlen(buf),
+  (const u16 *) address);
+   else {
+   u32 ip = *address;
+   snprintf(buf + strlen(buf), len - strlen(buf) - 1,
+NIPQUAD_FMT, NIPQUAD(ip));
+   }
+
+   snprintf(buf + strlen(buf), len - strlen(buf) - 1, " %u\n", port);
+
+   return tmy_write_audit_log(buf, is_granted);
+}
+
+/*  ADDRESS GROUP HANDLER  */
+
+/* List of address group. */
+static LIST_HEAD(address_group_list);
+
+static int tmy_add_address_group_entry(const char *group_name,
+   const bool is_ipv6,
+   const u16 *min_address,
+   const u16 *max_address,
+   const bool is_delete)
+{
+   static DEFINE_MUTEX(mutex);
+   struct address_group_entry *new_group;
+   struct address_group_entry *group;
+   struct address_group_member *new_member;
+   struct address_group_member *member;
+   const struct path_info *saved_group_name;
+   int error = -ENOMEM;
+   bool found = 0;
+
+   if (!tmy_correct_path(group_name, 0, 0, 0, __FUNCTION__) ||
+   !group_name[0])
+   return -EINVAL;
+
+   saved_group_name = tmy_save_name(group_name);
+   if (!saved_group_name)
+   return -ENOMEM;
+
+   mutex_lock();
+
+   list_for_each_entry(group, _group_list, list) {
+   if (saved_group_name != group->group_name)
+   continue;
+   list_for_each_entry(member, >address_group_member_list,
+   list) {
+   if (member->is_ipv6 != is_ipv6)
+   continue;
+   if (is_ipv6) {
+   if (memcmp(member->min.ipv6, min_address, 16) ||
+   memcmp(member->max.ipv6, max_address, 16))
+   continue;
+   } else {
+   if (member->min.ipv4 != *(u32 *) min_address ||
+   member->max.ipv4 != *(u32 *) max_address)
+   continue;
+   }
+   member->is_deleted = is_delete;
+   error = 0;
+   goto out;
+   }
+   found = 1;
+   break;
+   }
+
+   if (is_delete) {
+   error = -ENOENT;
+   goto out;
+   }
+
+   if (!found) {
+   new_group = tmy_alloc_element(sizeof(*new_group));
+   if (!new_group)
+   goto out;
+   INIT_LIST_HEAD(_group->address_group_member_list);
+   new_group->group_name = saved_group_name;
+   list_add_tail_mb(_group->list, _group_list);
+   group = new_group;
+   }
+
+   new_member = tmy_alloc_element(sizeof(*new_member));
+   if 

[TOMOYO #5 09/18] File access control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks permission in
open/creat/unlink/truncate/ftruncate/mknod/mkdir/
rmdir/symlink/link/rename/uselib/sysctl .

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/file.c 2007-11-14 15:15:44.0 +0900
@@ -0,0 +1,1471 @@
+/*
+ * security/tomoyo/file.c
+ *
+ * File access control functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+#define ACC_MODE(x) ("\000\004\002\006"[(x)_ACCMODE])
+
+/*  VARIABLES  */
+
+/* The structure for globally readable files. */
+
+struct globally_readable_file_entry {
+   struct list_head list;
+   const struct path_info *filename;
+   bool is_deleted;
+};
+
+/* The structure for filename patterns. */
+
+struct pattern_entry {
+   struct list_head list;
+   const struct path_info *pattern;
+   bool is_deleted;
+};
+
+/* The structure for non-rewritable-by-default file patterns. */
+
+struct no_rewrite_entry {
+   struct list_head list;
+   const struct path_info *pattern;
+   bool is_deleted;
+};
+
+/* The structure for detailed write operations. */
+
+static struct {
+   const char *keyword;
+   const int paths;
+} acl_type_array[] = {
+   { "create",   1 }, /* TMY_TYPE_CREATE_ACL */
+   { "unlink",   1 }, /* TMY_TYPE_UNLINK_ACL */
+   { "mkdir",1 }, /* TMY_TYPE_MKDIR_ACL */
+   { "rmdir",1 }, /* TMY_TYPE_RMDIR_ACL */
+   { "mkfifo",   1 }, /* TMY_TYPE_MKFIFO_ACL */
+   { "mksock",   1 }, /* TMY_TYPE_MKSOCK_ACL */
+   { "mkblock",  1 }, /* TMY_TYPE_MKBLOCK_ACL */
+   { "mkchar",   1 }, /* TMY_TYPE_MKCHAR_ACL */
+   { "truncate", 1 }, /* TMY_TYPE_TRUNCATE_ACL */
+   { "symlink",  1 }, /* TMY_TYPE_SYMLINK_ACL */
+   { "link", 2 }, /* TMY_TYPE_LINK_ACL */
+   { "rename",   2 }, /* TMY_TYPE_RENAME_ACL */
+   { "rewrite",  1 }, /* TMY_TYPE_REWRITE_ACL */
+   { NULL, 0 }
+};
+
+/*  UTILITY FUNCTIONS  */
+
+/**
+ * tmy_acltype2keyword - get keyword from access control index.
+ * @acl_type: index number.
+ *
+ * Returns keyword that corresponds with @acl_type .
+ */
+const char *tmy_acltype2keyword(const unsigned int acl_type)
+{
+   return (acl_type < ARRAY_SIZE(acl_type_array))
+   ? acl_type_array[acl_type].keyword : NULL;
+}
+
+/**
+ * tmy_acltype2paths - get number of arguments from access control index.
+ * @acl_type: index number.
+ *
+ * Returns number of arguments that corresponds with @acl_type .
+ */
+int tmy_acltype2paths(const unsigned int acl_type)
+{
+   return (acl_type < ARRAY_SIZE(acl_type_array))
+   ? acl_type_array[acl_type].paths : 0;
+}
+
+static int tmy_strendswith(const char *name, const char *tail)
+{
+   int len;
+
+   if (!name || !tail)
+   return 0;
+
+   len = strlen(name) - strlen(tail);
+   return len >= 0 && strcmp(name + len, tail) == 0;
+}
+
+static struct path_info *tmy_get_path(struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+   /* sizeof(struct path_info_with_data) <= PAGE_SIZE */
+   struct path_info_with_data {
+   /* Keep this first, this pointer is passed to tmy_free(). */
+   struct path_info head;
+   char bariier1[16];
+   char body[TMY_MAX_PATHNAME_LEN];
+   char barrier2[16];
+   } *buf = tmy_alloc(sizeof(*buf));
+
+   if (buf) {
+   int error = tmy_realpath_dentry2(dentry,
+mnt,
+buf->body,
+sizeof(buf->body) - 1);
+
+   if (error == 0) {
+   buf->head.name = buf->body;
+   tmy_fill_path_info(>head);
+   return >head;
+   }
+
+   tmy_free(buf);
+   buf = NULL;
+   printk(KERN_INFO "tmy_realpath_dentry = %d\n", error);
+   }
+
+   return NULL;
+}
+
+/*  PROTOTYPES  */
+
+static int tmy_add_double_write_acl(const u8 type,
+   const char *filename1,
+   const char *filename2,
+   struct domain_info * const domain,
+   const struct condition_list *cond,
+   const bool is_delete);
+static int tmy_add_single_write_acl(const u8 type,
+   

[TOMOYO #5 07/18] Domain transition functions.

2007-11-16 Thread penguin-kernel
Every process belongs to a domain in TOMOYO Linux.
Domain transition occurs when execve(2) is called
and the domain is expressed as 'process invocation history',
such as ' /sbin/init /etc/init.d/rc'.
Domain information is stored in task_struct->security.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/domain.c   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,1168 @@
+/*
+ * security/tomoyo/domain.c
+ *
+ * Domain transition functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/*  VARIABLES  */
+
+/* The initial domain. */
+struct domain_info KERNEL_DOMAIN;
+
+/* Lock for appending domain's ACL. */
+DEFINE_MUTEX(domain_acl_lock);
+
+/* Domain creation lock. */
+static DEFINE_MUTEX(new_domain_assign_lock);
+
+/* The structure for program files to force domain reconstruction. */
+
+struct domain_initializer_entry {
+   struct list_head list;
+   const struct path_info *domainname;/* This may be NULL */
+   const struct path_info *program;
+   bool is_deleted;
+   bool is_not;
+   bool is_last_name;
+};
+
+/* The structure for domains to not to transit domains. */
+
+struct domain_keeper_entry {
+   struct list_head list;
+   const struct path_info *domainname;
+   const struct path_info *program;   /* This may be NULL */
+   bool is_deleted;
+   bool is_not;
+   bool is_last_name;
+};
+
+/* The structure for program files that should be aggregated. */
+
+struct aggregator_entry {
+   struct list_head list;
+   const struct path_info *original_name;
+   const struct path_info *aggregated_name;
+   bool is_deleted;
+};
+
+/* The structure for program files that should be aliased. */
+
+struct alias_entry {
+   struct list_head list;
+   const struct path_info *original_name;
+   const struct path_info *aliased_name;
+   bool is_deleted;
+};
+
+/*  UTILITY FUNCTIONS  */
+
+/**
+ * tmy_is_domain_def - check if the line is likely a domain definition.
+ * @buffer: the line to check.
+ *
+ * Returns true if @buffer is likely a domain definition.
+ * Returns false otherwise.
+ *
+ * For complete validation check, use tmy_is_correct_domain().
+ */
+bool tmy_is_domain_def(const unsigned char *buffer)
+{
+   return strncmp(buffer, TMY_ROOT_NAME, TMY_ROOT_NAME_LEN) == 0;
+}
+
+/**
+ * tmy_add_acl - add an entry to a domain.
+ * @domain: pointer to "struct domain_info".
+ * @acl: pointer to "struct acl_info" to add.
+ *
+ * Returns zero.
+ */
+int tmy_add_acl(struct domain_info *domain,
+   struct acl_info *acl)
+{
+   list_add_tail_mb(>list, >acl_info_list);
+   tmy_update_counter(TMY_UPDATE_DOMAINPOLICY);
+   return 0;
+}
+
+/**
+ * tmy_del_acl - remove an entry from a domain
+ * @ptr: pointer to "struct acl_info" to remove.
+ *
+ * Returns zero.
+ *
+ * TOMOYO Linux doesn't free memory used by policy because policies are not
+ * so frequently changed after entring into enforcing mode.
+ * This makes the code free of read-lock.
+ * The caller uses "down(_acl_lock);" as write-lock.
+ */
+int tmy_del_acl(struct acl_info *ptr)
+{
+   ptr->is_deleted = 1;
+   tmy_update_counter(TMY_UPDATE_DOMAINPOLICY);
+   return 0;
+}
+
+/  DOMAIN INITIALIZER HANDLER  
/
+
+static LIST_HEAD(domain_initializer_list);
+
+/* Update domain initializer list. */
+static int tmy_add_domain_initializer_entry(const char *domainname,
+   const char *program,
+   const bool is_not,
+   const bool is_delete)
+{
+   struct domain_initializer_entry *new_entry;
+   struct domain_initializer_entry *ptr;
+   static DEFINE_MUTEX(mutex);
+   const struct path_info *saved_program;
+   const struct path_info *saved_domainname = NULL;
+   int error = -ENOMEM;
+   bool is_last_name = 0;
+
+   if (!tmy_correct_path(program, 1, -1, -1, __FUNCTION__))
+   return -EINVAL; /* No patterns allowed. */
+
+   if (domainname) {
+   if (!tmy_is_domain_def(domainname) &&
+   tmy_correct_path(domainname, 1, -1, -1, __FUNCTION__))
+   is_last_name = 1;
+
+   else if (!tmy_is_correct_domain(domainname, __FUNCTION__))
+   return -EINVAL;
+
+   saved_domainname = tmy_save_name(domainname);
+   if (!saved_domainname)
+   return -ENOMEM;
+   }
+
+   saved_program = tmy_save_name(program);
+   if 

[TOMOYO #5 10/18] argv0 check functions.

2007-11-16 Thread penguin-kernel
If the executed program name and argv[0] is different,
TOMOYO Linux checks permission.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/exec.c 2007-11-14 15:15:44.0 +0900
@@ -0,0 +1,218 @@
+/*
+ * security/tomoyo/exec.c
+ *
+ * Argv0 access control functions for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+/*  AUDIT FUNCTIONS  */
+
+static int tmy_audit_argv0_log(const struct path_info *filename,
+  const char *argv0,
+  const bool is_granted,
+  const u8 profile,
+  const unsigned int mode)
+{
+   char *buf;
+   int len;
+
+   if (is_granted) {
+   if (!tmy_audit_grant())
+   return 0;
+   } else {
+   if (!tmy_audit_reject())
+   return 0;
+   }
+
+   len = filename->total_len + strlen(argv0) + 8;
+   buf = tmy_init_audit_log(, profile, mode);
+
+   if (!buf)
+   return -ENOMEM;
+
+   snprintf(buf + strlen(buf),
+len - strlen(buf) - 1,
+TMY_ALLOW_ARGV0 "%s %s",
+filename->name,
+argv0);
+
+   return tmy_write_audit_log(buf, is_granted);
+}
+
+/*  ARGV0 MISMATCH HANDLER  */
+
+static int tmy_add_argv0_entry(const char *filename,
+  const char *argv0,
+  struct domain_info *domain,
+  const struct condition_list *cond,
+  const bool is_delete)
+{
+   struct acl_info *ptr;
+   struct argv0_acl *acl;
+   const struct path_info *saved_filename;
+   const struct path_info *saved_argv0;
+   int error = -ENOMEM;
+
+   if (!tmy_correct_path(filename, 1, 0, -1, __FUNCTION__) ||
+   !tmy_correct_path(argv0, -1, 0, -1, __FUNCTION__) ||
+   strchr(argv0, '/'))
+   return -EINVAL;
+
+   saved_filename = tmy_save_name(filename);
+   saved_argv0 = tmy_save_name(argv0);
+   if (!saved_filename || !saved_argv0)
+   return -ENOMEM;
+
+   mutex_lock(_acl_lock);
+
+   if (is_delete)
+   goto remove;
+
+   list_for_each_entry(ptr, >acl_info_list, list) {
+   acl = (struct argv0_acl *) ptr;
+   if (ptr->type == TMY_TYPE_ARGV0_ACL && ptr->cond == cond &&
+   acl->filename == saved_filename &&
+   acl->argv0 == saved_argv0) {
+   ptr->is_deleted = 0;
+   /* Found. Nothing to do. */
+   error = 0;
+   goto ok;
+   }
+   }
+
+   /* Not found. Append it to the tail. */
+   acl = tmy_alloc_element(sizeof(*acl));
+   if (!acl)
+   goto ok;
+
+   acl->head.type = TMY_TYPE_ARGV0_ACL;
+   acl->head.cond = cond;
+   acl->filename = saved_filename;
+   acl->argv0 = saved_argv0;
+   error = tmy_add_acl(domain,
+   (struct acl_info *) acl);
+   goto ok;
+remove: ;
+   error = -ENOENT;
+   list_for_each_entry(ptr, >acl_info_list, list) {
+   acl = (struct argv0_acl *) ptr;
+   if (ptr->type != TMY_TYPE_ARGV0_ACL ||
+   ptr->cond != cond || ptr->is_deleted ||
+   acl->filename != saved_filename ||
+   acl->argv0 != saved_argv0)
+   continue;
+
+   error = tmy_del_acl(ptr);
+   break;
+   }
+ok: ;
+   mutex_unlock(_acl_lock);
+
+   return error;
+}
+
+static int tmy_argv0_acl(const struct path_info *filename,
+const char *argv0_)
+{
+   const struct domain_info *domain = TMY_SECURITY->domain;
+   int error = -EPERM;
+   struct acl_info *ptr;
+   struct path_info argv0;
+
+   if (!tmy_flags(TMY_MAC_FOR_ARGV0))
+   return 0;
+
+   argv0.name = argv0_;
+   tmy_fill_path_info();
+
+   list_for_each_entry(ptr, >acl_info_list, list) {
+   struct argv0_acl *acl = (struct argv0_acl *) ptr;
+
+   if (ptr->type == TMY_TYPE_ARGV0_ACL &&
+   ptr->is_deleted == 0 &&
+   tmy_check_condition(ptr->cond, NULL) == 0 &&
+   tmy_path_match(filename, acl->filename) &&
+   tmy_path_match(, acl->argv0)) {
+   error = 0;
+   break;
+   }
+   

[TOMOYO #5 08/18] Auditing interface.

2007-11-16 Thread penguin-kernel
TOMOYO Linux uses /sys/kernel/security/tomoyo/ interface
for reporting access logs in domain policy format.
One is 'grant_log', used for auditing accesses which are
granted in the TOMOYO Linux policy.
The other is 'reject_log', used for auditing accesses which
are not granted in the TOMOYO Linux policy.
The userland daemon /usr/lib/ccs/ccs-auditd will save these logs.

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

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/audit.c2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,238 @@
+/*
+ * security/tomoyo/audit.c
+ *
+ * Audit functions for TOMOYO Linux
+ */
+
+#include "tomoyo.h"
+
+#ifdef CONFIG_SECURITY_TOMOYO_USE_AUDITD
+/**
+ * tmy_audit - write audit log.
+ * @fmt:  format strings for printf().
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ *
+ * Write audit log.
+ */
+int tmy_audit(const char *fmt, ...)
+{
+   struct audit_buffer *ab;
+   int len;
+   va_list args;
+   char *buf;
+   char *cp;
+   ab = audit_log_start(current->audit_context, GFP_KERNEL, AUDIT_KERNEL);
+   if (!ab)
+   return -ENOMEM;
+   buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+   if (!buf)
+   goto out;
+   va_start(args, fmt);
+   len = vsnprintf(buf, PAGE_SIZE - 1, fmt, args);
+   va_end(args);
+   if (len > PAGE_SIZE - 1) {
+   kfree(buf);
+   buf = kzalloc(len + 16, GFP_KERNEL);
+   if (!buf)
+   goto out;
+   va_start(args, fmt);
+   vsnprintf(buf, len + 15, fmt, args);
+   va_end(args);
+   }
+   cp = strchr(buf, '\0') - 1;
+   if (cp >= buf && *cp == '\n')
+   *cp = '\0';
+   audit_log_format(ab, "TOMOYO: %s", buf);
+   kfree(buf);
+out: ;
+   audit_log_end(ab);
+   return buf ? 0 : -ENOMEM;
+}
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(grant_log_wait);
+static DECLARE_WAIT_QUEUE_HEAD(reject_log_wait);
+
+static DEFINE_SPINLOCK(audit_log_lock);
+
+struct log_entry {
+   struct list_head list;
+   char *log;
+};
+
+static LIST_HEAD(grant_log);
+static LIST_HEAD(reject_log);
+
+static int grant_log_count;
+static int reject_log_count;
+
+/**
+ * tmy_audit_grant - get flags of auditing grant logs.
+ *
+ * Returns current value of auditing grant log flags.
+ */
+bool tmy_audit_grant(void)
+{
+   return grant_log_count < tmy_flags(TMY_MAX_GRANT_LOG);
+}
+
+/**
+ * tmy_audit_reject - get flags of auditing reject logs.
+ *
+ * Returns current value of auditing reject log flags.
+ */
+bool tmy_audit_reject(void)
+{
+   return reject_log_count < tmy_flags(TMY_MAX_REJECT_LOG);
+}
+
+/**
+ * tmy_init_audit_log - allocate and initialize audit buffer.
+ * @len: pointer to length of requested size.
+ * @profile: profile number for this log.
+ * @mode: profile value for this log.
+ *
+ * Returns pointer to audit buffer on success. @len received allocated size.
+ * Returns NULL on failure.
+ *
+ * @len must not be a NULL.
+ */
+char *tmy_init_audit_log(int *len, const u8 profile, const unsigned int mode)
+{
+   char *buf;
+   struct timeval tv;
+   struct task_struct *task = current;
+   const char *domainname = TMY_SECURITY->domain->domainname->name;
+   do_gettimeofday();
+   *len += strlen(domainname) + 256;
+   buf = tmy_alloc(*len);
+   if (!buf)
+   return NULL;
+   snprintf(buf, (*len) - 1, "#timestamp=%lu profile=%u mode=%u "
+"pid=%d uid=%d gid=%d euid=%d egid=%d "
+"suid=%d sgid=%d fsuid=%d fsgid=%d \n%s\n",
+tv.tv_sec, profile, mode,
+task->pid, task->uid, task->gid, task->euid, task->egid,
+task->suid, task->sgid, task->fsuid, task->fsgid, domainname);
+   return buf;
+}
+
+/**
+ * tmy_write_audit_log - write audit log.
+ * @buf:pointer to access log contents.
+ * @is_granted: is the access request granted?
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ *
+ * Write audit log.
+ * Caller must allocate @buf with tmy_init_audit_log().
+ */
+int tmy_write_audit_log(char *buf, const bool is_granted)
+{
+   struct log_entry *new_entry;
+   new_entry = tmy_alloc(sizeof(*new_entry));
+   if (!new_entry) {
+   tmy_free(buf);
+   return -ENOMEM;
+   }
+   INIT_LIST_HEAD(_entry->list);
+   new_entry->log = buf;
+   /* CRITICAL SECTION START */
+   spin_lock(_log_lock);
+   if (is_granted) {
+   list_add_tail(_entry->list, _log);
+   grant_log_count++;
+   buf = NULL;
+   tmy_update_counter(TMY_UPDATE_GRANT_LOG);
+   } else {
+   list_add_tail(_entry->list, _log);
+  

[TOMOYO #5 04/18] Data structures and prototype defitions.

2007-11-16 Thread penguin-kernel
Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
 security/tomoyo/include/realpath.h |   45 ++
 security/tomoyo/include/tomoyo.h   |  671 +
 2 files changed, 716 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/include/realpath.h 2007-11-14 
15:15:41.0 +0900
@@ -0,0 +1,45 @@
+/*
+ * security/tomoyo/include/realpath.h
+ *
+ * Get the canonicalized absolute pathnames.
+ * The basis for TOMOYO.
+ */
+
+#ifndef _TMY_REALPATH_H
+#define _TMY_REALPATH_H
+
+#include "tomoyo.h"
+
+struct path_info;
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+int tmy_realpath_dentry2(struct dentry *dentry,
+struct vfsmount *mnt,
+char *newname,
+int newname_len);
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+/* These functions use tmy_alloc(), so caller must tmy_free() */
+/* if these functions didn't return NULL. */
+char *tmy_realpath(const char *pathname);
+char *tmy_realpath_nofollow(const char *pathname);
+char *tmy_realpath_dentry(struct dentry *dentry, struct vfsmount *mnt);
+
+/* Allocate memory for structures. */
+/* The RAM is chunked, so NEVER try to kfree() the returned pointer. */
+void *tmy_alloc_element(const unsigned int size);
+
+/* Get used RAM size for tmy_alloc_elements(). */
+unsigned int tmy_get_memory_used_for_elements(void);
+
+/* Keep the given name on the RAM. */
+/* The RAM is shared, so NEVER try to modify or kfree() the returned name. */
+const struct path_info *tmy_save_name(const char *name);
+
+/* Get used RAM size for tmy_save_name(). */
+unsigned int tmy_get_memory_used_for_save_name(void);
+
+unsigned int tmy_get_memory_used_for_dynamic(void);
+char *sysctlpath_from_table(struct ctl_table *table);
+
+#endif
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/include/tomoyo.h   2007-11-14 
15:15:41.0 +0900
@@ -0,0 +1,671 @@
+/*
+ * security/tomoyo/include/tomoyo.h
+ *
+ * Header for TOMOYO Linux.
+ */
+
+#ifndef _TOMOYO_H
+#define _TOMOYO_H
+
+#define TOMOYO_VERSION_CODE "2.1.0"
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/**
+ * list_for_each_cookie - iterate over a list with cookie.
+ * @pos:the  list_head to use as a loop cursor.
+ * @cookie: the  list_head to use as a cookie.
+ * @head:   the head for your list.
+ *
+ * Same with list_for_each except that this primitive uses cookie
+ * so that we can continue iteration.
+ */
+#define list_for_each_cookie(pos, cookie, head) \
+   for ((cookie) || ((cookie) = (head)), pos = (cookie)->next; \
+prefetch(pos->next), pos != (head) || ((cookie) = NULL); \
+(cookie) = pos, pos = pos->next)
+
+/**
+ * list_add_tail_mb - add a new entry with memory barrier.
+ * @new: new entry to be added.
+ * @head: list head to add it before.
+ *
+ * Same with list_add_tail_rcu() except that this primitive uses mb()
+ * so that we can traverse forwards using list_for_each() and
+ * list_for_each_cookie().
+ */
+static inline void list_add_tail_mb(struct list_head *new,
+   struct list_head *head)
+{
+   struct list_head *prev = head->prev;
+   struct list_head *next = head;
+   new->next = next;
+   new->prev = prev;
+   mb(); /* Avoid out-of-order execution. */
+   next->prev = new;
+   prev->next = new;
+}
+
+extern struct seq_operations mounts_op;
+extern struct mutex domain_acl_lock;
+extern bool sbin_init_started;
+
+struct tmy_security {
+   struct domain_info *domain;
+   struct domain_info *prev_domain;
+   u32 flags;
+};
+
+#define TMY_SECURITY ((struct tmy_security *) current->security)
+
+struct path_info {
+   const char *name;
+   u32 hash;/* = full_name_hash(name, strlen(name)) */
+   u16 total_len;   /* = strlen(name)   */
+   u16 const_len;   /* = tmy_const_part_length(name)*/
+   bool is_dir;   /* = tmy_strendswith(name, "/") */
+   bool is_patterned; /* = PathContainsPattern(name)  */
+   u16 depth;   /* = tmy_path_depth(name)   */
+};
+
+#define TMY_MAX_PATHNAME_LEN 4000
+
+struct path_group_member {
+   struct list_head list;
+   const struct path_info *member_name;
+   bool is_deleted;
+};
+
+struct path_group_entry {
+   struct list_head list;
+   const struct path_info *group_name;
+   struct list_head path_group_member_list;
+};
+
+
+struct mini_stat {
+   uid_t uid;
+   

[TOMOYO #5 02/18] Add wrapper functions for VFS helper functions.

2007-11-16 Thread penguin-kernel
This patch allows LSM hooks refer previously associated "struct vfsmount" 
parameter
so that they can calculate pathname of given "struct dentry".

Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 include/linux/fs.h |  138 +
 1 file changed, 138 insertions(+)

--- linux-2.6-mm.orig/include/linux/fs.h2007-11-14 15:14:52.0 
+0900
+++ linux-2.6-mm/include/linux/fs.h 2007-11-14 15:20:32.0 +0900
@@ -1086,6 +1086,116 @@ extern int vfs_rmdir(struct inode *, str
 extern int vfs_unlink(struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct 
dentry *);
 
+#include 
+#include 
+
+static inline int vfs_create2(struct inode *dir, struct dentry *dentry,
+ int mode, struct nameidata *nd)
+{
+   int ret;
+   struct vfsmount *mnt = nd ? nd->path.mnt : NULL;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_create(dir, dentry, mode, nd);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_mkdir2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt, int mode)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_mkdir(dir, dentry, mode);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_mknod2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt, int mode, dev_t dev)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_mknod(dir, dentry, mode, dev);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_symlink2(struct inode *dir, struct dentry *dentry,
+  struct vfsmount *mnt, const char *oldname,
+  int mode)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_symlink(dir, dentry, oldname, mode);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_link2(struct dentry *old_dentry, struct inode *dir,
+   struct dentry *new_dentry, struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_link(old_dentry, dir, new_dentry);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_rmdir2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_rmdir(dir, dentry);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_unlink2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_unlink(dir, dentry);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
+   task->last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
 /*
  * VFS dentry helper functions.
  */
@@ -1548,6 +1658,21 @@ static inline int break_lease(struct ino
 
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
   struct file *filp);
+
+static inline int do_truncate2(struct dentry *dentry, struct vfsmount *mnt,
+  loff_t length, unsigned int time_attrs,
+  struct file *filp)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task->last_vfsmount;
+   task->last_vfsmount = mntget(mnt);
+   ret = 

[TOMOYO #5 03/18] Replace VFS with wrapper functions.

2007-11-16 Thread penguin-kernel
This patch replaces VFS helper function calls caused by
userland process's request with VFS wrapper functions call.
This patch doesn't modify individual filesystems in fs/*/ directory.

Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 fs/namei.c |   34 +++---
 fs/open.c  |   23 +--
 net/unix/af_unix.c |3 ++-
 3 files changed, 34 insertions(+), 26 deletions(-)

--- linux-2.6-mm.orig/fs/open.c 2007-11-14 15:14:48.0 +0900
+++ linux-2.6-mm/fs/open.c  2007-11-14 15:15:38.0 +0900
@@ -271,7 +271,8 @@ static long do_sys_truncate(const char _
error = locks_verify_truncate(inode, NULL, length);
if (!error) {
DQUOT_INIT(inode);
-   error = do_truncate(nd.path.dentry, length, 0, NULL);
+   error = do_truncate2(nd.path.dentry, nd.path.mnt, length, 0,
+NULL);
}
 
 put_write_and_out:
@@ -326,7 +327,8 @@ static long do_sys_ftruncate(unsigned in
 
error = locks_verify_truncate(inode, file, length);
if (!error)
-   error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, 
file);
+   error = do_truncate2(dentry, file->f_path.mnt, length,
+ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
fput(file);
 out:
@@ -589,7 +591,7 @@ asmlinkage long sys_fchmod(unsigned int 
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-   err = notify_change(dentry, );
+   err = notify_change2(dentry, file->f_path.mnt, );
mutex_unlock(>i_mutex);
 
 out_drop_write:
@@ -626,7 +628,7 @@ asmlinkage long sys_fchmodat(int dfd, co
mode = inode->i_mode;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-   error = notify_change(nd.path.dentry, );
+   error = notify_change2(nd.path.dentry, nd.path.mnt, );
mutex_unlock(>i_mutex);
 
 out_drop_write:
@@ -642,7 +644,8 @@ asmlinkage long sys_chmod(const char __u
return sys_fchmodat(AT_FDCWD, filename, mode);
 }
 
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+static int chown_common(struct dentry *dentry, struct vfsmount *mnt,
+   uid_t user, gid_t group)
 {
struct inode * inode;
int error;
@@ -669,7 +672,7 @@ static int chown_common(struct dentry * 
newattrs.ia_valid |=
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
mutex_lock(>i_mutex);
-   error = notify_change(dentry, );
+   error = notify_change2(dentry, mnt, );
mutex_unlock(>i_mutex);
 out:
return error;
@@ -686,7 +689,7 @@ asmlinkage long sys_chown(const char __u
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_release;
-   error = chown_common(nd.path.dentry, user, group);
+   error = chown_common(nd.path.dentry, nd.path.mnt, user, group);
mnt_drop_write(nd.path.mnt);
 out_release:
path_put();
@@ -711,7 +714,7 @@ asmlinkage long sys_fchownat(int dfd, co
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_release;
-   error = chown_common(nd.path.dentry, user, group);
+   error = chown_common(nd.path.dentry, nd.path.mnt, user, group);
mnt_drop_write(nd.path.mnt);
 out_release:
path_put();
@@ -730,7 +733,7 @@ asmlinkage long sys_lchown(const char __
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_release;
-   error = chown_common(nd.path.dentry, user, group);
+   error = chown_common(nd.path.dentry, nd.path.mnt, user, group);
mnt_drop_write(nd.path.mnt);
 out_release:
path_put();
@@ -754,7 +757,7 @@ asmlinkage long sys_fchown(unsigned int 
goto out_fput;
dentry = file->f_path.dentry;
audit_inode(NULL, dentry);
-   error = chown_common(dentry, user, group);
+   error = chown_common(dentry, file->f_vfsmnt, user, group);
mnt_drop_write(file->f_vfsmnt);
 out_fput:
fput(file);
--- linux-2.6-mm.orig/fs/namei.c2007-11-14 15:14:48.0 +0900
+++ linux-2.6-mm/fs/namei.c 2007-11-14 15:22:32.0 +0900
@@ -1663,7 +1663,7 @@ int may_open(struct nameidata *nd, int a
if (!error) {
DQUOT_INIT(inode);
 
-   error = do_truncate(dentry, 0,
+   error = do_truncate2(dentry, nd->path.mnt, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
NULL);
}
@@ -1690,7 +1690,7 @@ static int __open_namei_create(struct na
 
if (!IS_POSIXACL(dir->d_inode))
mode &= ~current->fs->umask;

[TOMOYO #5 00/18] TOMOYO Linux - MAC based on process invocation history.

2007-11-16 Thread penguin-kernel
"TOMOYO Linux" is our work in the field of security enhancement for Linux.
You can try TOMOYO Linux 1.5.1 on Ubuntu 7.10's Live CD
http://tomoyo.sourceforge.jp/wiki-e/?TomoyoLive

Changes from previous posting.

 * Made patches against latest -mm tree.

   This time, we made patches for -mm tree.
   Documents about installing and experiencing TOMOYO Linux
   are available at http://tomoyo.sourceforge.jp/en/lkml-5/ .

 * Avoid namespace_sem deadlock.

   To avoid the possibility of AB-BA deadlock
   (see http://lkml.org/lkml/2007/11/5/388 for detail),
   we made patches not to access namespace_sem from LSM.
   Instead, we made some wrapper functions to pass "struct vfsmount"
   to LSM functions in a way of associating "struct vfsmount"
   with "struct task_struct" suggested at
   http://www.mail-archive.com/[EMAIL PROTECTED]/msg01712.html .

   We would like to merge either AppArmor's "Pass struct vfsmount to ..." 
patches or
   our patches marked as [01/18], [02/18], [03/18] into mainline kernel
   so that AppArmor and TOMOYO Linux can safely access "struct vfsmount" from 
LSM.

 * Avoid rcu_read_lock() by inserting mb() when appending to list.

   I heard from an embedded system developer that holding RCU's read lock
   for long time affects response time since it disables preemption.
   Since list elements are append-only and nobody needs to refer ->prev element,
   we made patches not to call rcu_read_lock() by replacing smp_wmb() with mb().

 * Don't send access logs to auditing system.

   TOMOYO Linux generates two types of logs.
   One is access logs in the form of policy file.
   The other is other messages like warning/info.
   We were sending both logs to auditing system.
   But some users complain about the flooding of access logs on the console.
   Thus, we decided to stop sending access logs to auditing system
   and removed AUDIT_TMY_GRANTED and AUDIT_TMY_REJECTED from 
include/linux/audit.h .
   Now, we are sending access logs to /sys/kernel/security/tomoyo/ interface.
   Logs other than access logs are sent to auditing system or printk() 
depending on kernel config.

 * Added capabilities support.

   TOMOYO Linux 2.1 now supports capabilities supported by TOMOYO Linux 1.5.1 .
   But some of them doesn't work due to LSM limitation (i.e. missing hooks).

Patches consist of four types.

 * [TOMOYO 01-03/18]: Essential modifications against -mm kernel.
 * [TOMOYO 04-16/18]: LSM implementation of TOMOYO Linux.
 * [TOMOYO 17/18]:Makefile and Kconfig.
 * [TOMOYO 18/18]:Optional modifications against -mm kernel.

--
  Tetsuo Handa
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 01/18] Add struct vfsmount to struct task_struct.

2007-11-16 Thread penguin-kernel
This patch allows VFS wrapper functions associate "struct vfsmount"
with "struct task_struct" so that LSM hooks can calculate
pathname of given "struct dentry".

Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 include/linux/init_task.h |1 +
 include/linux/sched.h |2 ++
 2 files changed, 3 insertions(+)

--- linux-2.6-mm.orig/include/linux/init_task.h 2007-11-14 15:12:03.0 
+0900
+++ linux-2.6-mm/include/linux/init_task.h  2007-11-14 15:15:33.0 
+0900
@@ -173,6 +173,7 @@ extern struct group_info init_groups;
.dirties = INIT_PROP_LOCAL_SINGLE(dirties), \
INIT_TRACE_IRQFLAGS \
INIT_LOCKDEP\
+   .last_vfsmount  = NULL, \
 }
 
 
--- linux-2.6-mm.orig/include/linux/sched.h 2007-11-14 15:14:35.0 
+0900
+++ linux-2.6-mm/include/linux/sched.h  2007-11-14 15:15:33.0 +0900
@@ -1191,6 +1191,8 @@ struct task_struct {
int make_it_fail;
 #endif
struct prop_local_single dirties;
+   /* vfsmount info for LSM hooks. */
+   struct vfsmount *last_vfsmount;
 };
 
 /*

-- 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 01/18] Add struct vfsmount to struct task_struct.

2007-11-16 Thread penguin-kernel
This patch allows VFS wrapper functions associate struct vfsmount
with struct task_struct so that LSM hooks can calculate
pathname of given struct dentry.

Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
---
 include/linux/init_task.h |1 +
 include/linux/sched.h |2 ++
 2 files changed, 3 insertions(+)

--- linux-2.6-mm.orig/include/linux/init_task.h 2007-11-14 15:12:03.0 
+0900
+++ linux-2.6-mm/include/linux/init_task.h  2007-11-14 15:15:33.0 
+0900
@@ -173,6 +173,7 @@ extern struct group_info init_groups;
.dirties = INIT_PROP_LOCAL_SINGLE(dirties), \
INIT_TRACE_IRQFLAGS \
INIT_LOCKDEP\
+   .last_vfsmount  = NULL, \
 }
 
 
--- linux-2.6-mm.orig/include/linux/sched.h 2007-11-14 15:14:35.0 
+0900
+++ linux-2.6-mm/include/linux/sched.h  2007-11-14 15:15:33.0 +0900
@@ -1191,6 +1191,8 @@ struct task_struct {
int make_it_fail;
 #endif
struct prop_local_single dirties;
+   /* vfsmount info for LSM hooks. */
+   struct vfsmount *last_vfsmount;
 };
 
 /*

-- 
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 03/18] Replace VFS with wrapper functions.

2007-11-16 Thread penguin-kernel
This patch replaces VFS helper function calls caused by
userland process's request with VFS wrapper functions call.
This patch doesn't modify individual filesystems in fs/*/ directory.

Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
---
 fs/namei.c |   34 +++---
 fs/open.c  |   23 +--
 net/unix/af_unix.c |3 ++-
 3 files changed, 34 insertions(+), 26 deletions(-)

--- linux-2.6-mm.orig/fs/open.c 2007-11-14 15:14:48.0 +0900
+++ linux-2.6-mm/fs/open.c  2007-11-14 15:15:38.0 +0900
@@ -271,7 +271,8 @@ static long do_sys_truncate(const char _
error = locks_verify_truncate(inode, NULL, length);
if (!error) {
DQUOT_INIT(inode);
-   error = do_truncate(nd.path.dentry, length, 0, NULL);
+   error = do_truncate2(nd.path.dentry, nd.path.mnt, length, 0,
+NULL);
}
 
 put_write_and_out:
@@ -326,7 +327,8 @@ static long do_sys_ftruncate(unsigned in
 
error = locks_verify_truncate(inode, file, length);
if (!error)
-   error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, 
file);
+   error = do_truncate2(dentry, file-f_path.mnt, length,
+ATTR_MTIME|ATTR_CTIME, file);
 out_putf:
fput(file);
 out:
@@ -589,7 +591,7 @@ asmlinkage long sys_fchmod(unsigned int 
mode = inode-i_mode;
newattrs.ia_mode = (mode  S_IALLUGO) | (inode-i_mode  ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-   err = notify_change(dentry, newattrs);
+   err = notify_change2(dentry, file-f_path.mnt, newattrs);
mutex_unlock(inode-i_mutex);
 
 out_drop_write:
@@ -626,7 +628,7 @@ asmlinkage long sys_fchmodat(int dfd, co
mode = inode-i_mode;
newattrs.ia_mode = (mode  S_IALLUGO) | (inode-i_mode  ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-   error = notify_change(nd.path.dentry, newattrs);
+   error = notify_change2(nd.path.dentry, nd.path.mnt, newattrs);
mutex_unlock(inode-i_mutex);
 
 out_drop_write:
@@ -642,7 +644,8 @@ asmlinkage long sys_chmod(const char __u
return sys_fchmodat(AT_FDCWD, filename, mode);
 }
 
-static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
+static int chown_common(struct dentry *dentry, struct vfsmount *mnt,
+   uid_t user, gid_t group)
 {
struct inode * inode;
int error;
@@ -669,7 +672,7 @@ static int chown_common(struct dentry * 
newattrs.ia_valid |=
ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV;
mutex_lock(inode-i_mutex);
-   error = notify_change(dentry, newattrs);
+   error = notify_change2(dentry, mnt, newattrs);
mutex_unlock(inode-i_mutex);
 out:
return error;
@@ -686,7 +689,7 @@ asmlinkage long sys_chown(const char __u
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_release;
-   error = chown_common(nd.path.dentry, user, group);
+   error = chown_common(nd.path.dentry, nd.path.mnt, user, group);
mnt_drop_write(nd.path.mnt);
 out_release:
path_put(nd.path);
@@ -711,7 +714,7 @@ asmlinkage long sys_fchownat(int dfd, co
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_release;
-   error = chown_common(nd.path.dentry, user, group);
+   error = chown_common(nd.path.dentry, nd.path.mnt, user, group);
mnt_drop_write(nd.path.mnt);
 out_release:
path_put(nd.path);
@@ -730,7 +733,7 @@ asmlinkage long sys_lchown(const char __
error = mnt_want_write(nd.path.mnt);
if (error)
goto out_release;
-   error = chown_common(nd.path.dentry, user, group);
+   error = chown_common(nd.path.dentry, nd.path.mnt, user, group);
mnt_drop_write(nd.path.mnt);
 out_release:
path_put(nd.path);
@@ -754,7 +757,7 @@ asmlinkage long sys_fchown(unsigned int 
goto out_fput;
dentry = file-f_path.dentry;
audit_inode(NULL, dentry);
-   error = chown_common(dentry, user, group);
+   error = chown_common(dentry, file-f_vfsmnt, user, group);
mnt_drop_write(file-f_vfsmnt);
 out_fput:
fput(file);
--- linux-2.6-mm.orig/fs/namei.c2007-11-14 15:14:48.0 +0900
+++ linux-2.6-mm/fs/namei.c 2007-11-14 15:22:32.0 +0900
@@ -1663,7 +1663,7 @@ int may_open(struct nameidata *nd, int a
if (!error) {
DQUOT_INIT(inode);
 
-   error = do_truncate(dentry, 0,
+   error = do_truncate2(dentry, nd-path.mnt, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
NULL);
}
@@ -1690,7 +1690,7 @@ static int __open_namei_create(struct na
 
if 

[TOMOYO #5 00/18] TOMOYO Linux - MAC based on process invocation history.

2007-11-16 Thread penguin-kernel
TOMOYO Linux is our work in the field of security enhancement for Linux.
You can try TOMOYO Linux 1.5.1 on Ubuntu 7.10's Live CD
http://tomoyo.sourceforge.jp/wiki-e/?TomoyoLive

Changes from previous posting.

 * Made patches against latest -mm tree.

   This time, we made patches for -mm tree.
   Documents about installing and experiencing TOMOYO Linux
   are available at http://tomoyo.sourceforge.jp/en/lkml-5/ .

 * Avoid namespace_sem deadlock.

   To avoid the possibility of AB-BA deadlock
   (see http://lkml.org/lkml/2007/11/5/388 for detail),
   we made patches not to access namespace_sem from LSM.
   Instead, we made some wrapper functions to pass struct vfsmount
   to LSM functions in a way of associating struct vfsmount
   with struct task_struct suggested at
   http://www.mail-archive.com/[EMAIL PROTECTED]/msg01712.html .

   We would like to merge either AppArmor's Pass struct vfsmount to ... 
patches or
   our patches marked as [01/18], [02/18], [03/18] into mainline kernel
   so that AppArmor and TOMOYO Linux can safely access struct vfsmount from 
LSM.

 * Avoid rcu_read_lock() by inserting mb() when appending to list.

   I heard from an embedded system developer that holding RCU's read lock
   for long time affects response time since it disables preemption.
   Since list elements are append-only and nobody needs to refer -prev element,
   we made patches not to call rcu_read_lock() by replacing smp_wmb() with mb().

 * Don't send access logs to auditing system.

   TOMOYO Linux generates two types of logs.
   One is access logs in the form of policy file.
   The other is other messages like warning/info.
   We were sending both logs to auditing system.
   But some users complain about the flooding of access logs on the console.
   Thus, we decided to stop sending access logs to auditing system
   and removed AUDIT_TMY_GRANTED and AUDIT_TMY_REJECTED from 
include/linux/audit.h .
   Now, we are sending access logs to /sys/kernel/security/tomoyo/ interface.
   Logs other than access logs are sent to auditing system or printk() 
depending on kernel config.

 * Added capabilities support.

   TOMOYO Linux 2.1 now supports capabilities supported by TOMOYO Linux 1.5.1 .
   But some of them doesn't work due to LSM limitation (i.e. missing hooks).

Patches consist of four types.

 * [TOMOYO 01-03/18]: Essential modifications against -mm kernel.
 * [TOMOYO 04-16/18]: LSM implementation of TOMOYO Linux.
 * [TOMOYO 17/18]:Makefile and Kconfig.
 * [TOMOYO 18/18]:Optional modifications against -mm kernel.

--
  Tetsuo Handa
 
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 16/18] Conditional permission support.

2007-11-16 Thread penguin-kernel
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 file changed, 680 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/condition.c2007-11-14 15:15:44.0 
+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_FSUID3
+#define TASK_GID  4
+#define TASK_EGID 5
+#define TASK_SGID 6
+#define TASK_FSGID7
+#define TASK_PID  8
+#define TASK_PPID 9
+#define PATH1_UID10
+#define PATH1_GID11
+#define PATH1_INO12
+#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;
+

[TOMOYO #5 17/18] Kconfig and Makefile

2007-11-16 Thread penguin-kernel
TOMOYO Linux is placed in security/tomoyo .

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/Kconfig |1 +
 security/Makefile|1 +
 security/tomoyo/Kconfig  |   26 ++
 security/tomoyo/Makefile |2 ++
 4 files changed, 30 insertions(+)

--- linux-2.6-mm.orig/security/Kconfig  2007-11-14 15:12:08.0 +0900
+++ linux-2.6-mm/security/Kconfig   2007-11-14 15:15:44.0 +0900
@@ -104,6 +104,7 @@ config SECURITY_ROOTPLUG
  If you are unsure how to answer this question, answer N.
 
 source security/selinux/Kconfig
+source security/tomoyo/Kconfig
 
 endmenu
 
--- linux-2.6-mm.orig/security/Makefile 2007-10-10 05:31:38.0 +0900
+++ linux-2.6-mm/security/Makefile  2007-11-14 15:15:44.0 +0900
@@ -16,3 +16,4 @@ obj-$(CONFIG_SECURITY)+= security.o d
 obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)+= commoncap.o capability.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)+= commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_TOMOYO)   += tomoyo/
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/Kconfig2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,26 @@
+config SECURITY_TOMOYO
+   bool TOMOYO Linux support
+   depends on SECURITY
+   select SECURITY_NETWORK
+   default n
+   help
+ This selects TOMOYO Linux.
+
+ TOMOYO Linux is a domain-based access control method using LSM.
+ If you answer Y, you will need a policy loader program
+ (/sbin/tomoyo-init) and some configuration files.
+ You can get them from
+ http://tomoyo.sourceforge.jp/en/2.1.x/
+
+ TOMOYO Linux is also applicable to figuring out the behavior
+ of your system, for TOMOYO uses the canonicalized absolute
+ pathnames and TreeView style domain transitions.
+
+config SECURITY_TOMOYO_USE_AUDITD
+   bool Use standard auditing subsystem
+   depends on SECURITY_TOMOYO  AUDIT
+   default y
+   help
+ This makes messages sent to auditing subsystem.
+
+ If you say 'N' here, messages will be sent to printk().
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/Makefile   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo.o domain.o common.o realpath.o audit.o 
file.o exec.o net.o mount.o signal.o capability.o condition.o
+EXTRA_CFLAGS += -Isecurity/tomoyo/include

-- 
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[TOMOYO #5 13/18] Signal control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks sending signal by signal number and
the domain of target process. In order to check signal
permission, LSM expansion patch [TOMOYO 18/18] is needed.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/signal.c |  227 +++
 1 file changed, 227 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/signal.c   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,227 @@
+/*
+ * security/tomoyo/signal.c
+ *
+ * Signal access contol functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+/*  AUDIT FUNCTIONS  */
+
+static int tmy_audit_signal_log(const int signal,
+   const struct path_info *dest_domain,
+   const bool is_granted,
+   const u8 profile,
+   const unsigned int mode)
+{
+   char *buf;
+   int len;
+
+   if (is_granted) {
+   if (!tmy_audit_grant())
+   return 0;
+   } else {
+   if (!tmy_audit_reject())
+   return 0;
+   }
+
+   len = dest_domain-total_len;
+   buf = tmy_init_audit_log(len, profile, mode);
+
+   if (!buf)
+   return -ENOMEM;
+
+   snprintf(buf + strlen(buf),
+len - strlen(buf) - 1,
+%s%d %s\n,
+TMY_ALLOW_SIGNAL, signal, dest_domain-name);
+
+   return tmy_write_audit_log(buf, is_granted);
+}
+
+/*  SIGNAL ACL HANDLER  */
+
+static int tmy_add_signal_entry(const u16 sig, const char *dest_pattern,
+   struct domain_info *domain,
+   const struct condition_list *cond,
+   const bool is_delete)
+{
+   struct acl_info *ptr;
+   struct signal_acl *acl;
+   const struct path_info *saved_dest_pattern;
+   int error = -ENOMEM;
+
+   if (!domain)
+   return -EINVAL;
+   if (!dest_pattern ||
+   !tmy_is_correct_domain(dest_pattern, __FUNCTION__))
+   return -EINVAL;
+
+   saved_dest_pattern = tmy_save_name(dest_pattern);
+   if (!saved_dest_pattern)
+   return -ENOMEM;
+
+   mutex_lock(domain_acl_lock);
+
+   if (is_delete)
+   goto remove;
+
+   list_for_each_entry(ptr, domain-acl_info_list, list) {
+   acl = (struct signal_acl *) ptr;
+
+   if (ptr-type == TMY_TYPE_SIGNAL_ACL  acl-sig == sig
+ptr-cond == cond
+!tmy_pathcmp(acl-domainname, saved_dest_pattern)) {
+   ptr-is_deleted = 0;
+   /* Found. Nothing to do. */
+   error = 0;
+   goto ok;
+   }
+   }
+   /* Not found. Append it to the tail. */
+   acl = tmy_alloc_element(sizeof(*acl));
+   if (!acl)
+   goto ok;
+
+   acl-head.type = TMY_TYPE_SIGNAL_ACL;
+   acl-head.cond = cond;
+   acl-sig = sig;
+   acl-domainname = saved_dest_pattern;
+   error = tmy_add_acl(domain, (struct acl_info *) acl);
+   goto ok;
+remove: ;
+   error = -ENOENT;
+   list_for_each_entry(ptr, domain-acl_info_list, list) {
+   acl = (struct signal_acl *) ptr;
+   if (ptr-type != TMY_TYPE_SIGNAL_ACL || ptr-cond != cond ||
+   ptr-is_deleted || acl-sig != sig ||
+   tmy_pathcmp(acl-domainname, saved_dest_pattern))
+   continue;
+   error = tmy_del_acl(ptr);
+   break;
+   }
+
+ok: ;
+   mutex_unlock(domain_acl_lock);
+
+   return error;
+}
+
+/**
+ * tmy_signal_acl - check permission for kill(2)/tkill(2)/tgkill(2).
+ * @sig:  signal number.
+ * @pid:  pid of destination process.
+ *
+ * Returns zero if permission granted.
+ * Returns nonzero if permission denied.
+ */
+int tmy_signal_acl(const int sig, const int pid)
+{
+   struct domain_info *domain = TMY_SECURITY-domain;
+   struct domain_info *dest = NULL;
+   const char *dest_pattern;
+   struct acl_info *ptr;
+   const u16 hash = sig;
+   const u8 profile = domain-profile;
+   const unsigned int mode = tmy_flags(TMY_MAC_FOR_SIGNAL);
+   const bool is_enforce = (mode == 3);
+   bool found = 0;
+
+   if (!mode)
+   return 0;
+   if (!sig)
+   return 0; /* No check for NULL signal. */
+   if (current-pid == pid) {
+   tmy_audit_signal_log(sig, domain-domainname, 1, profile, mode);
+   return 0; /* No check for self. */
+   }
+
+   { /* Simplified 

[TOMOYO #5 09/18] File access control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks permission in
open/creat/unlink/truncate/ftruncate/mknod/mkdir/
rmdir/symlink/link/rename/uselib/sysctl .

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/file.c | 1471 +
 1 file changed, 1471 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/file.c 2007-11-14 15:15:44.0 +0900
@@ -0,0 +1,1471 @@
+/*
+ * security/tomoyo/file.c
+ *
+ * File access control functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+#define ACC_MODE(x) (\000\004\002\006[(x)O_ACCMODE])
+
+/*  VARIABLES  */
+
+/* The structure for globally readable files. */
+
+struct globally_readable_file_entry {
+   struct list_head list;
+   const struct path_info *filename;
+   bool is_deleted;
+};
+
+/* The structure for filename patterns. */
+
+struct pattern_entry {
+   struct list_head list;
+   const struct path_info *pattern;
+   bool is_deleted;
+};
+
+/* The structure for non-rewritable-by-default file patterns. */
+
+struct no_rewrite_entry {
+   struct list_head list;
+   const struct path_info *pattern;
+   bool is_deleted;
+};
+
+/* The structure for detailed write operations. */
+
+static struct {
+   const char *keyword;
+   const int paths;
+} acl_type_array[] = {
+   { create,   1 }, /* TMY_TYPE_CREATE_ACL */
+   { unlink,   1 }, /* TMY_TYPE_UNLINK_ACL */
+   { mkdir,1 }, /* TMY_TYPE_MKDIR_ACL */
+   { rmdir,1 }, /* TMY_TYPE_RMDIR_ACL */
+   { mkfifo,   1 }, /* TMY_TYPE_MKFIFO_ACL */
+   { mksock,   1 }, /* TMY_TYPE_MKSOCK_ACL */
+   { mkblock,  1 }, /* TMY_TYPE_MKBLOCK_ACL */
+   { mkchar,   1 }, /* TMY_TYPE_MKCHAR_ACL */
+   { truncate, 1 }, /* TMY_TYPE_TRUNCATE_ACL */
+   { symlink,  1 }, /* TMY_TYPE_SYMLINK_ACL */
+   { link, 2 }, /* TMY_TYPE_LINK_ACL */
+   { rename,   2 }, /* TMY_TYPE_RENAME_ACL */
+   { rewrite,  1 }, /* TMY_TYPE_REWRITE_ACL */
+   { NULL, 0 }
+};
+
+/*  UTILITY FUNCTIONS  */
+
+/**
+ * tmy_acltype2keyword - get keyword from access control index.
+ * @acl_type: index number.
+ *
+ * Returns keyword that corresponds with @acl_type .
+ */
+const char *tmy_acltype2keyword(const unsigned int acl_type)
+{
+   return (acl_type  ARRAY_SIZE(acl_type_array))
+   ? acl_type_array[acl_type].keyword : NULL;
+}
+
+/**
+ * tmy_acltype2paths - get number of arguments from access control index.
+ * @acl_type: index number.
+ *
+ * Returns number of arguments that corresponds with @acl_type .
+ */
+int tmy_acltype2paths(const unsigned int acl_type)
+{
+   return (acl_type  ARRAY_SIZE(acl_type_array))
+   ? acl_type_array[acl_type].paths : 0;
+}
+
+static int tmy_strendswith(const char *name, const char *tail)
+{
+   int len;
+
+   if (!name || !tail)
+   return 0;
+
+   len = strlen(name) - strlen(tail);
+   return len = 0  strcmp(name + len, tail) == 0;
+}
+
+static struct path_info *tmy_get_path(struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+   /* sizeof(struct path_info_with_data) = PAGE_SIZE */
+   struct path_info_with_data {
+   /* Keep this first, this pointer is passed to tmy_free(). */
+   struct path_info head;
+   char bariier1[16];
+   char body[TMY_MAX_PATHNAME_LEN];
+   char barrier2[16];
+   } *buf = tmy_alloc(sizeof(*buf));
+
+   if (buf) {
+   int error = tmy_realpath_dentry2(dentry,
+mnt,
+buf-body,
+sizeof(buf-body) - 1);
+
+   if (error == 0) {
+   buf-head.name = buf-body;
+   tmy_fill_path_info(buf-head);
+   return buf-head;
+   }
+
+   tmy_free(buf);
+   buf = NULL;
+   printk(KERN_INFO tmy_realpath_dentry = %d\n, error);
+   }
+
+   return NULL;
+}
+
+/*  PROTOTYPES  */
+
+static int tmy_add_double_write_acl(const u8 type,
+   const char *filename1,
+   const char *filename2,
+   struct domain_info * const domain,
+   const struct condition_list *cond,
+   const bool is_delete);
+static int tmy_add_single_write_acl(const u8 type,
+   const char *filename,
+  

[TOMOYO #5 07/18] Domain transition functions.

2007-11-16 Thread penguin-kernel
Every process belongs to a domain in TOMOYO Linux.
Domain transition occurs when execve(2) is called
and the domain is expressed as 'process invocation history',
such as 'kernel /sbin/init /etc/init.d/rc'.
Domain information is stored in task_struct-security.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/domain.c | 1168 +++
 1 file changed, 1168 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/domain.c   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,1168 @@
+/*
+ * security/tomoyo/domain.c
+ *
+ * Domain transition functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+/*  VARIABLES  */
+
+/* The initial domain. */
+struct domain_info KERNEL_DOMAIN;
+
+/* Lock for appending domain's ACL. */
+DEFINE_MUTEX(domain_acl_lock);
+
+/* Domain creation lock. */
+static DEFINE_MUTEX(new_domain_assign_lock);
+
+/* The structure for program files to force domain reconstruction. */
+
+struct domain_initializer_entry {
+   struct list_head list;
+   const struct path_info *domainname;/* This may be NULL */
+   const struct path_info *program;
+   bool is_deleted;
+   bool is_not;
+   bool is_last_name;
+};
+
+/* The structure for domains to not to transit domains. */
+
+struct domain_keeper_entry {
+   struct list_head list;
+   const struct path_info *domainname;
+   const struct path_info *program;   /* This may be NULL */
+   bool is_deleted;
+   bool is_not;
+   bool is_last_name;
+};
+
+/* The structure for program files that should be aggregated. */
+
+struct aggregator_entry {
+   struct list_head list;
+   const struct path_info *original_name;
+   const struct path_info *aggregated_name;
+   bool is_deleted;
+};
+
+/* The structure for program files that should be aliased. */
+
+struct alias_entry {
+   struct list_head list;
+   const struct path_info *original_name;
+   const struct path_info *aliased_name;
+   bool is_deleted;
+};
+
+/*  UTILITY FUNCTIONS  */
+
+/**
+ * tmy_is_domain_def - check if the line is likely a domain definition.
+ * @buffer: the line to check.
+ *
+ * Returns true if @buffer is likely a domain definition.
+ * Returns false otherwise.
+ *
+ * For complete validation check, use tmy_is_correct_domain().
+ */
+bool tmy_is_domain_def(const unsigned char *buffer)
+{
+   return strncmp(buffer, TMY_ROOT_NAME, TMY_ROOT_NAME_LEN) == 0;
+}
+
+/**
+ * tmy_add_acl - add an entry to a domain.
+ * @domain: pointer to struct domain_info.
+ * @acl: pointer to struct acl_info to add.
+ *
+ * Returns zero.
+ */
+int tmy_add_acl(struct domain_info *domain,
+   struct acl_info *acl)
+{
+   list_add_tail_mb(acl-list, domain-acl_info_list);
+   tmy_update_counter(TMY_UPDATE_DOMAINPOLICY);
+   return 0;
+}
+
+/**
+ * tmy_del_acl - remove an entry from a domain
+ * @ptr: pointer to struct acl_info to remove.
+ *
+ * Returns zero.
+ *
+ * TOMOYO Linux doesn't free memory used by policy because policies are not
+ * so frequently changed after entring into enforcing mode.
+ * This makes the code free of read-lock.
+ * The caller uses down(domain_acl_lock); as write-lock.
+ */
+int tmy_del_acl(struct acl_info *ptr)
+{
+   ptr-is_deleted = 1;
+   tmy_update_counter(TMY_UPDATE_DOMAINPOLICY);
+   return 0;
+}
+
+/  DOMAIN INITIALIZER HANDLER  
/
+
+static LIST_HEAD(domain_initializer_list);
+
+/* Update domain initializer list. */
+static int tmy_add_domain_initializer_entry(const char *domainname,
+   const char *program,
+   const bool is_not,
+   const bool is_delete)
+{
+   struct domain_initializer_entry *new_entry;
+   struct domain_initializer_entry *ptr;
+   static DEFINE_MUTEX(mutex);
+   const struct path_info *saved_program;
+   const struct path_info *saved_domainname = NULL;
+   int error = -ENOMEM;
+   bool is_last_name = 0;
+
+   if (!tmy_correct_path(program, 1, -1, -1, __FUNCTION__))
+   return -EINVAL; /* No patterns allowed. */
+
+   if (domainname) {
+   if (!tmy_is_domain_def(domainname) 
+   tmy_correct_path(domainname, 1, -1, -1, __FUNCTION__))
+   is_last_name = 1;
+
+   else if (!tmy_is_correct_domain(domainname, __FUNCTION__))
+   return -EINVAL;
+
+   saved_domainname = tmy_save_name(domainname);
+   if (!saved_domainname)
+   return -ENOMEM;
+   }
+
+   saved_program = tmy_save_name(program);
+   if 

[TOMOYO #5 08/18] Auditing interface.

2007-11-16 Thread penguin-kernel
TOMOYO Linux uses /sys/kernel/security/tomoyo/ interface
for reporting access logs in domain policy format.
One is 'grant_log', used for auditing accesses which are
granted in the TOMOYO Linux policy.
The other is 'reject_log', used for auditing accesses which
are not granted in the TOMOYO Linux policy.
The userland daemon /usr/lib/ccs/ccs-auditd will save these logs.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/audit.c |  238 
 1 file changed, 238 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/audit.c2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,238 @@
+/*
+ * security/tomoyo/audit.c
+ *
+ * Audit functions for TOMOYO Linux
+ */
+
+#include tomoyo.h
+
+#ifdef CONFIG_SECURITY_TOMOYO_USE_AUDITD
+/**
+ * tmy_audit - write audit log.
+ * @fmt:  format strings for printf().
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ *
+ * Write audit log.
+ */
+int tmy_audit(const char *fmt, ...)
+{
+   struct audit_buffer *ab;
+   int len;
+   va_list args;
+   char *buf;
+   char *cp;
+   ab = audit_log_start(current-audit_context, GFP_KERNEL, AUDIT_KERNEL);
+   if (!ab)
+   return -ENOMEM;
+   buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+   if (!buf)
+   goto out;
+   va_start(args, fmt);
+   len = vsnprintf(buf, PAGE_SIZE - 1, fmt, args);
+   va_end(args);
+   if (len  PAGE_SIZE - 1) {
+   kfree(buf);
+   buf = kzalloc(len + 16, GFP_KERNEL);
+   if (!buf)
+   goto out;
+   va_start(args, fmt);
+   vsnprintf(buf, len + 15, fmt, args);
+   va_end(args);
+   }
+   cp = strchr(buf, '\0') - 1;
+   if (cp = buf  *cp == '\n')
+   *cp = '\0';
+   audit_log_format(ab, TOMOYO: %s, buf);
+   kfree(buf);
+out: ;
+   audit_log_end(ab);
+   return buf ? 0 : -ENOMEM;
+}
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(grant_log_wait);
+static DECLARE_WAIT_QUEUE_HEAD(reject_log_wait);
+
+static DEFINE_SPINLOCK(audit_log_lock);
+
+struct log_entry {
+   struct list_head list;
+   char *log;
+};
+
+static LIST_HEAD(grant_log);
+static LIST_HEAD(reject_log);
+
+static int grant_log_count;
+static int reject_log_count;
+
+/**
+ * tmy_audit_grant - get flags of auditing grant logs.
+ *
+ * Returns current value of auditing grant log flags.
+ */
+bool tmy_audit_grant(void)
+{
+   return grant_log_count  tmy_flags(TMY_MAX_GRANT_LOG);
+}
+
+/**
+ * tmy_audit_reject - get flags of auditing reject logs.
+ *
+ * Returns current value of auditing reject log flags.
+ */
+bool tmy_audit_reject(void)
+{
+   return reject_log_count  tmy_flags(TMY_MAX_REJECT_LOG);
+}
+
+/**
+ * tmy_init_audit_log - allocate and initialize audit buffer.
+ * @len: pointer to length of requested size.
+ * @profile: profile number for this log.
+ * @mode: profile value for this log.
+ *
+ * Returns pointer to audit buffer on success. @len received allocated size.
+ * Returns NULL on failure.
+ *
+ * @len must not be a NULL.
+ */
+char *tmy_init_audit_log(int *len, const u8 profile, const unsigned int mode)
+{
+   char *buf;
+   struct timeval tv;
+   struct task_struct *task = current;
+   const char *domainname = TMY_SECURITY-domain-domainname-name;
+   do_gettimeofday(tv);
+   *len += strlen(domainname) + 256;
+   buf = tmy_alloc(*len);
+   if (!buf)
+   return NULL;
+   snprintf(buf, (*len) - 1, #timestamp=%lu profile=%u mode=%u 
+pid=%d uid=%d gid=%d euid=%d egid=%d 
+suid=%d sgid=%d fsuid=%d fsgid=%d \n%s\n,
+tv.tv_sec, profile, mode,
+task-pid, task-uid, task-gid, task-euid, task-egid,
+task-suid, task-sgid, task-fsuid, task-fsgid, domainname);
+   return buf;
+}
+
+/**
+ * tmy_write_audit_log - write audit log.
+ * @buf:pointer to access log contents.
+ * @is_granted: is the access request granted?
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ *
+ * Write audit log.
+ * Caller must allocate @buf with tmy_init_audit_log().
+ */
+int tmy_write_audit_log(char *buf, const bool is_granted)
+{
+   struct log_entry *new_entry;
+   new_entry = tmy_alloc(sizeof(*new_entry));
+   if (!new_entry) {
+   tmy_free(buf);
+   return -ENOMEM;
+   }
+   INIT_LIST_HEAD(new_entry-list);
+   new_entry-log = buf;
+   /* CRITICAL SECTION START */
+   spin_lock(audit_log_lock);
+   if (is_granted) {
+   list_add_tail(new_entry-list, grant_log);
+   grant_log_count++;
+   buf = NULL;
+   tmy_update_counter(TMY_UPDATE_GRANT_LOG);
+   } else {
+   list_add_tail(new_entry-list, reject_log);
+

[TOMOYO #5 02/18] Add wrapper functions for VFS helper functions.

2007-11-16 Thread penguin-kernel
This patch allows LSM hooks refer previously associated struct vfsmount 
parameter
so that they can calculate pathname of given struct dentry.

Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
---
 include/linux/fs.h |  138 +
 1 file changed, 138 insertions(+)

--- linux-2.6-mm.orig/include/linux/fs.h2007-11-14 15:14:52.0 
+0900
+++ linux-2.6-mm/include/linux/fs.h 2007-11-14 15:20:32.0 +0900
@@ -1086,6 +1086,116 @@ extern int vfs_rmdir(struct inode *, str
 extern int vfs_unlink(struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct 
dentry *);
 
+#include linux/mount.h
+#include linux/sched.h
+
+static inline int vfs_create2(struct inode *dir, struct dentry *dentry,
+ int mode, struct nameidata *nd)
+{
+   int ret;
+   struct vfsmount *mnt = nd ? nd-path.mnt : NULL;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_create(dir, dentry, mode, nd);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_mkdir2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt, int mode)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_mkdir(dir, dentry, mode);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_mknod2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt, int mode, dev_t dev)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_mknod(dir, dentry, mode, dev);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_symlink2(struct inode *dir, struct dentry *dentry,
+  struct vfsmount *mnt, const char *oldname,
+  int mode)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_symlink(dir, dentry, oldname, mode);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_link2(struct dentry *old_dentry, struct inode *dir,
+   struct dentry *new_dentry, struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_link(old_dentry, dir, new_dentry);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_rmdir2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_rmdir(dir, dentry);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_unlink2(struct inode *dir, struct dentry *dentry,
+struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_unlink(dir, dentry);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
+static inline int vfs_rename2(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ struct vfsmount *mnt)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
+   task-last_vfsmount = prev_mnt;
+   mntput(mnt);
+   return ret;
+}
+
 /*
  * VFS dentry helper functions.
  */
@@ -1548,6 +1658,21 @@ static inline int break_lease(struct ino
 
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
   struct file *filp);
+
+static inline int do_truncate2(struct dentry *dentry, struct vfsmount *mnt,
+  loff_t length, unsigned int time_attrs,
+  struct file *filp)
+{
+   int ret;
+   struct task_struct *task = current;
+   struct vfsmount *prev_mnt = task-last_vfsmount;
+   task-last_vfsmount = mntget(mnt);
+   ret = 

[TOMOYO #5 04/18] Data structures and prototype defitions.

2007-11-16 Thread penguin-kernel
Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/include/realpath.h |   45 ++
 security/tomoyo/include/tomoyo.h   |  671 +
 2 files changed, 716 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/include/realpath.h 2007-11-14 
15:15:41.0 +0900
@@ -0,0 +1,45 @@
+/*
+ * security/tomoyo/include/realpath.h
+ *
+ * Get the canonicalized absolute pathnames.
+ * The basis for TOMOYO.
+ */
+
+#ifndef _TMY_REALPATH_H
+#define _TMY_REALPATH_H
+
+#include tomoyo.h
+
+struct path_info;
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+int tmy_realpath_dentry2(struct dentry *dentry,
+struct vfsmount *mnt,
+char *newname,
+int newname_len);
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+/* These functions use tmy_alloc(), so caller must tmy_free() */
+/* if these functions didn't return NULL. */
+char *tmy_realpath(const char *pathname);
+char *tmy_realpath_nofollow(const char *pathname);
+char *tmy_realpath_dentry(struct dentry *dentry, struct vfsmount *mnt);
+
+/* Allocate memory for structures. */
+/* The RAM is chunked, so NEVER try to kfree() the returned pointer. */
+void *tmy_alloc_element(const unsigned int size);
+
+/* Get used RAM size for tmy_alloc_elements(). */
+unsigned int tmy_get_memory_used_for_elements(void);
+
+/* Keep the given name on the RAM. */
+/* The RAM is shared, so NEVER try to modify or kfree() the returned name. */
+const struct path_info *tmy_save_name(const char *name);
+
+/* Get used RAM size for tmy_save_name(). */
+unsigned int tmy_get_memory_used_for_save_name(void);
+
+unsigned int tmy_get_memory_used_for_dynamic(void);
+char *sysctlpath_from_table(struct ctl_table *table);
+
+#endif
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/include/tomoyo.h   2007-11-14 
15:15:41.0 +0900
@@ -0,0 +1,671 @@
+/*
+ * security/tomoyo/include/tomoyo.h
+ *
+ * Header for TOMOYO Linux.
+ */
+
+#ifndef _TOMOYO_H
+#define _TOMOYO_H
+
+#define TOMOYO_VERSION_CODE 2.1.0
+
+#include linux/kernel.h
+#include linux/sched.h
+
+#include asm/ioctls.h
+#include linux/audit.h
+#include linux/binfmts.h
+#include linux/delay.h
+#include linux/file.h
+#include linux/highmem.h
+#include linux/init.h
+#include linux/mm.h
+#include linux/module.h
+#include linux/mount.h
+#include linux/namei.h
+#include linux/net.h
+#include linux/poll.h
+#include linux/proc_fs.h
+#include linux/security.h
+#include linux/seq_file.h
+#include linux/slab.h
+#include linux/smp_lock.h
+#include linux/string.h
+#include linux/sysctl.h
+#include linux/utime.h
+#include linux/version.h
+#include net/ip.h
+#include net/ipv6.h
+#include stdarg.h
+#include linux/uaccess.h
+#include linux/hardirq.h
+#include linux/mount.h
+#include linux/mnt_namespace.h
+
+/**
+ * list_for_each_cookie - iterate over a list with cookie.
+ * @pos:the struct list_head to use as a loop cursor.
+ * @cookie: the struct list_head to use as a cookie.
+ * @head:   the head for your list.
+ *
+ * Same with list_for_each except that this primitive uses cookie
+ * so that we can continue iteration.
+ */
+#define list_for_each_cookie(pos, cookie, head) \
+   for ((cookie) || ((cookie) = (head)), pos = (cookie)-next; \
+prefetch(pos-next), pos != (head) || ((cookie) = NULL); \
+(cookie) = pos, pos = pos-next)
+
+/**
+ * list_add_tail_mb - add a new entry with memory barrier.
+ * @new: new entry to be added.
+ * @head: list head to add it before.
+ *
+ * Same with list_add_tail_rcu() except that this primitive uses mb()
+ * so that we can traverse forwards using list_for_each() and
+ * list_for_each_cookie().
+ */
+static inline void list_add_tail_mb(struct list_head *new,
+   struct list_head *head)
+{
+   struct list_head *prev = head-prev;
+   struct list_head *next = head;
+   new-next = next;
+   new-prev = prev;
+   mb(); /* Avoid out-of-order execution. */
+   next-prev = new;
+   prev-next = new;
+}
+
+extern struct seq_operations mounts_op;
+extern struct mutex domain_acl_lock;
+extern bool sbin_init_started;
+
+struct tmy_security {
+   struct domain_info *domain;
+   struct domain_info *prev_domain;
+   u32 flags;
+};
+
+#define TMY_SECURITY ((struct tmy_security *) current-security)
+
+struct path_info {
+   const char *name;
+   u32 hash;/* = full_name_hash(name, strlen(name)) */
+   u16 total_len;   /* = strlen(name)   */
+   u16 const_len;   /* = tmy_const_part_length(name)*/
+   bool is_dir;   /* = tmy_strendswith(name, /) */
+   bool is_patterned; /* = PathContainsPattern(name)  */
+   u16 depth;   /* = 

[TOMOYO #5 10/18] argv0 check functions.

2007-11-16 Thread penguin-kernel
If the executed program name and argv[0] is different,
TOMOYO Linux checks permission.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/exec.c |  218 +
 1 file changed, 218 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/exec.c 2007-11-14 15:15:44.0 +0900
@@ -0,0 +1,218 @@
+/*
+ * security/tomoyo/exec.c
+ *
+ * Argv0 access control functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+/*  AUDIT FUNCTIONS  */
+
+static int tmy_audit_argv0_log(const struct path_info *filename,
+  const char *argv0,
+  const bool is_granted,
+  const u8 profile,
+  const unsigned int mode)
+{
+   char *buf;
+   int len;
+
+   if (is_granted) {
+   if (!tmy_audit_grant())
+   return 0;
+   } else {
+   if (!tmy_audit_reject())
+   return 0;
+   }
+
+   len = filename-total_len + strlen(argv0) + 8;
+   buf = tmy_init_audit_log(len, profile, mode);
+
+   if (!buf)
+   return -ENOMEM;
+
+   snprintf(buf + strlen(buf),
+len - strlen(buf) - 1,
+TMY_ALLOW_ARGV0 %s %s,
+filename-name,
+argv0);
+
+   return tmy_write_audit_log(buf, is_granted);
+}
+
+/*  ARGV0 MISMATCH HANDLER  */
+
+static int tmy_add_argv0_entry(const char *filename,
+  const char *argv0,
+  struct domain_info *domain,
+  const struct condition_list *cond,
+  const bool is_delete)
+{
+   struct acl_info *ptr;
+   struct argv0_acl *acl;
+   const struct path_info *saved_filename;
+   const struct path_info *saved_argv0;
+   int error = -ENOMEM;
+
+   if (!tmy_correct_path(filename, 1, 0, -1, __FUNCTION__) ||
+   !tmy_correct_path(argv0, -1, 0, -1, __FUNCTION__) ||
+   strchr(argv0, '/'))
+   return -EINVAL;
+
+   saved_filename = tmy_save_name(filename);
+   saved_argv0 = tmy_save_name(argv0);
+   if (!saved_filename || !saved_argv0)
+   return -ENOMEM;
+
+   mutex_lock(domain_acl_lock);
+
+   if (is_delete)
+   goto remove;
+
+   list_for_each_entry(ptr, domain-acl_info_list, list) {
+   acl = (struct argv0_acl *) ptr;
+   if (ptr-type == TMY_TYPE_ARGV0_ACL  ptr-cond == cond 
+   acl-filename == saved_filename 
+   acl-argv0 == saved_argv0) {
+   ptr-is_deleted = 0;
+   /* Found. Nothing to do. */
+   error = 0;
+   goto ok;
+   }
+   }
+
+   /* Not found. Append it to the tail. */
+   acl = tmy_alloc_element(sizeof(*acl));
+   if (!acl)
+   goto ok;
+
+   acl-head.type = TMY_TYPE_ARGV0_ACL;
+   acl-head.cond = cond;
+   acl-filename = saved_filename;
+   acl-argv0 = saved_argv0;
+   error = tmy_add_acl(domain,
+   (struct acl_info *) acl);
+   goto ok;
+remove: ;
+   error = -ENOENT;
+   list_for_each_entry(ptr, domain-acl_info_list, list) {
+   acl = (struct argv0_acl *) ptr;
+   if (ptr-type != TMY_TYPE_ARGV0_ACL ||
+   ptr-cond != cond || ptr-is_deleted ||
+   acl-filename != saved_filename ||
+   acl-argv0 != saved_argv0)
+   continue;
+
+   error = tmy_del_acl(ptr);
+   break;
+   }
+ok: ;
+   mutex_unlock(domain_acl_lock);
+
+   return error;
+}
+
+static int tmy_argv0_acl(const struct path_info *filename,
+const char *argv0_)
+{
+   const struct domain_info *domain = TMY_SECURITY-domain;
+   int error = -EPERM;
+   struct acl_info *ptr;
+   struct path_info argv0;
+
+   if (!tmy_flags(TMY_MAC_FOR_ARGV0))
+   return 0;
+
+   argv0.name = argv0_;
+   tmy_fill_path_info(argv0);
+
+   list_for_each_entry(ptr, domain-acl_info_list, list) {
+   struct argv0_acl *acl = (struct argv0_acl *) ptr;
+
+   if (ptr-type == TMY_TYPE_ARGV0_ACL 
+   ptr-is_deleted == 0 
+   tmy_check_condition(ptr-cond, NULL) == 0 
+   tmy_path_match(filename, acl-filename) 
+   tmy_path_match(argv0, acl-argv0)) {
+   error = 0;
+   break;
+   }
+  

[TOMOYO #5 11/18] Network access control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks permission by the following four parameters.
  * protocol type (TCP, UDP, RAW)
  * access type (bind, listen, connect, accept)
  * IP address (Both IPv4 and IPv6 are available)
  * port number
In order to check 'TCP accept' and 'UDP connect',
LSM expansion patch ([TOMOYO 18/18]) is needed.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/net.c |  952 ++
 1 file changed, 952 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/net.c  2007-11-14 15:15:44.0 +0900
@@ -0,0 +1,952 @@
+/*
+ * security/tomoyo/net.c
+ *
+ * Network access control functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+/*  AUDIT FUNCTIONS  */
+
+static int tmy_audit_network_log(const bool is_ipv6,
+const char *operation,
+const u32 *address,
+const u16 port,
+const bool is_granted,
+const u8 profile,
+const unsigned int mode)
+{
+   char *buf;
+   int len = 256;
+
+   if (is_granted) {
+   if (!tmy_audit_grant())
+   return 0;
+   } else {
+   if (!tmy_audit_reject())
+   return 0;
+   }
+
+   buf = tmy_init_audit_log(len, profile, mode);
+   if (!buf)
+   return -ENOMEM;
+
+   snprintf(buf + strlen(buf), len - strlen(buf) - 1,
+TMY_ALLOW_NETWORK %s , operation);
+
+   if (is_ipv6)
+   tmy_print_ipv6(buf + strlen(buf), len - strlen(buf),
+  (const u16 *) address);
+   else {
+   u32 ip = *address;
+   snprintf(buf + strlen(buf), len - strlen(buf) - 1,
+NIPQUAD_FMT, NIPQUAD(ip));
+   }
+
+   snprintf(buf + strlen(buf), len - strlen(buf) - 1,  %u\n, port);
+
+   return tmy_write_audit_log(buf, is_granted);
+}
+
+/*  ADDRESS GROUP HANDLER  */
+
+/* List of address group. */
+static LIST_HEAD(address_group_list);
+
+static int tmy_add_address_group_entry(const char *group_name,
+   const bool is_ipv6,
+   const u16 *min_address,
+   const u16 *max_address,
+   const bool is_delete)
+{
+   static DEFINE_MUTEX(mutex);
+   struct address_group_entry *new_group;
+   struct address_group_entry *group;
+   struct address_group_member *new_member;
+   struct address_group_member *member;
+   const struct path_info *saved_group_name;
+   int error = -ENOMEM;
+   bool found = 0;
+
+   if (!tmy_correct_path(group_name, 0, 0, 0, __FUNCTION__) ||
+   !group_name[0])
+   return -EINVAL;
+
+   saved_group_name = tmy_save_name(group_name);
+   if (!saved_group_name)
+   return -ENOMEM;
+
+   mutex_lock(mutex);
+
+   list_for_each_entry(group, address_group_list, list) {
+   if (saved_group_name != group-group_name)
+   continue;
+   list_for_each_entry(member, group-address_group_member_list,
+   list) {
+   if (member-is_ipv6 != is_ipv6)
+   continue;
+   if (is_ipv6) {
+   if (memcmp(member-min.ipv6, min_address, 16) ||
+   memcmp(member-max.ipv6, max_address, 16))
+   continue;
+   } else {
+   if (member-min.ipv4 != *(u32 *) min_address ||
+   member-max.ipv4 != *(u32 *) max_address)
+   continue;
+   }
+   member-is_deleted = is_delete;
+   error = 0;
+   goto out;
+   }
+   found = 1;
+   break;
+   }
+
+   if (is_delete) {
+   error = -ENOENT;
+   goto out;
+   }
+
+   if (!found) {
+   new_group = tmy_alloc_element(sizeof(*new_group));
+   if (!new_group)
+   goto out;
+   INIT_LIST_HEAD(new_group-address_group_member_list);
+   new_group-group_name = saved_group_name;
+   list_add_tail_mb(new_group-list, address_group_list);
+   group = new_group;
+   }
+
+   new_member = tmy_alloc_element(sizeof(*new_member));
+  

[TOMOYO #5 12/18] Namespace manipulation control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks mount permission based on
device name, mount point, filesystem type and optional flags.
TOMOYO Linux also checks permission in umount and pivot_root.

Each permission can be automatically accumulated into
the policy using 'learning mode'.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/mount.c |  908 
 1 file changed, 908 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/mount.c2007-11-14 15:59:44.0 
+0900
@@ -0,0 +1,908 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Mount access control functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+/* KEYWORDS for mount restrictions. */
+
+#define MOUNT_BIND_KEYWORD   --bind
+#define MOUNT_MOVE_KEYWORD   --move
+#define MOUNT_REMOUNT_KEYWORD--remount
+#define MOUNT_MAKE_UNBINDABLE_KEYWORD --make-unbindable
+#define MOUNT_MAKE_PRIVATE_KEYWORD--make-private
+#define MOUNT_MAKE_SLAVE_KEYWORD  --make-slave
+#define MOUNT_MAKE_SHARED_KEYWORD --make-shared
+
+/* The structure for mount restrictions. */
+
+struct mount_entry {
+   struct list_head list;
+   const struct path_info *dev_name;
+   const struct path_info *dir_name;
+   const struct path_info *fs_type;
+   unsigned int flags; /* Mount flags. */
+   bool is_deleted;
+};
+
+struct no_umount_entry {
+   struct list_head list;
+   const struct path_info *dir;
+   bool is_deleted;
+};
+
+/  MOUNT RESTRICTION HANDLER  /
+
+static LIST_HEAD(mount_list);
+
+/* Add or remove a mount entry. */
+static int tmy_add_mount_acl(const char *dev_name,
+const char *dir_name,
+const char *fs_type,
+const unsigned int flags,
+const bool is_delete)
+{
+   struct mount_entry *new_entry;
+   struct mount_entry  *ptr;
+   const struct path_info *fs;
+   const struct path_info *dev;
+   const struct path_info *dir;
+   static DEFINE_MUTEX(mutex);
+   int error = -ENOMEM;
+
+   fs = tmy_save_name(fs_type);
+   if (!fs)
+   return -EINVAL;
+
+   if (!dev_name)
+   /* Map dev_name to NULL for if no dev_name given. */
+   dev_name = NULL;
+   if (strcmp(fs-name, MOUNT_REMOUNT_KEYWORD) == 0)
+   /* Fix dev_name to any for remount permission. */
+   dev_name = any;
+   if (strcmp(fs-name, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 ||
+   strcmp(fs-name, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 ||
+   strcmp(fs-name, MOUNT_MAKE_SLAVE_KEYWORD) == 0 ||
+   strcmp(fs-name, MOUNT_MAKE_SHARED_KEYWORD) == 0)
+   dev_name = any;
+
+   if (!tmy_correct_path(dev_name, 0, 0, 0, __FUNCTION__) ||
+   !tmy_correct_path(dir_name, 1, 0, 1, __FUNCTION__))
+   return -EINVAL;
+
+   dev = tmy_save_name(dev_name);
+   if (!dev)
+   return -ENOMEM;
+   dir = tmy_save_name(dir_name);
+   if (!dir)
+   return -ENOMEM;
+
+   mutex_lock(mutex);
+
+   list_for_each_entry(ptr, mount_list, list) {
+   if (ptr-flags != flags ||
+   tmy_pathcmp(ptr-dev_name, dev) ||
+   tmy_pathcmp(ptr-dir_name, dir) ||
+   tmy_pathcmp(ptr-fs_type, fs))
+   continue;
+   ptr-is_deleted = is_delete;
+   error = 0;
+   goto out;
+   }
+
+   if (is_delete) {
+   error = -ENOENT;
+   goto out;
+   }
+
+   new_entry = tmy_alloc_element(sizeof(*new_entry));
+   if (!new_entry)
+   goto out;
+
+   new_entry-dev_name = dev;
+   new_entry-dir_name = dir;
+   new_entry-fs_type = fs;
+   new_entry-flags = flags;
+   list_add_tail_mb(new_entry-list, mount_list);
+   error = 0;
+out: ;
+   mutex_unlock(mutex);
+   return error;
+}
+
+/* Print error message for mount request. */
+static inline int tmy_mount_perm_error(char *dev_name,
+  char *dir_name,
+  char *type,
+  unsigned long flags,
+  const u8 profile,
+  const unsigned int mode)
+{
+   int error = -EPERM;
+   const char *realname1 = tmy_realpath(dev_name);
+   const char *realname2 = tmy_realpath(dir_name);
+   const char *exename = tmy_get_exe();
+   const bool is_enforce = (mode == 3);
+
+   if (!strcmp(type, MOUNT_REMOUNT_KEYWORD)) {
+   tmy_audit(KERN_WARNING TOMOYO-%s: mount -o remount %s 0x%lX 
+ (pid=%d:exe=%s): Permission denied.\n,
+

[TOMOYO #5 18/18] LSM expansion for TOMOYO Linux.

2007-11-16 Thread penguin-kernel
LSM hooks for sending signal:
   * task_kill_unlocked is added in sys_kill
   * task_tkill_unlocked is added in sys_tkill
   * task_tgkill_unlocked is added in sys_tgkill
LSM hooks for network accept and recv:
   * socket_post_accept is modified to return int.
   * post_recv_datagram is added in skb_recv_datagram.

You can try TOMOYO Linux without this patch, but in that case, you
can't use access control functionality for restricting signal
transmission and incoming network data.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 include/linux/security.h |   74 +++
 kernel/signal.c  |   17 ++
 net/core/datagram.c  |   22 +
 net/socket.c |7 +++-
 security/dummy.c |   32 ++--
 security/security.c  |   25 ++-
 6 files changed, 165 insertions(+), 12 deletions(-)

--- linux-2.6-mm.orig/include/linux/security.h  2007-11-14 15:14:10.0 
+0900
+++ linux-2.6-mm/include/linux/security.h   2007-11-14 15:15:44.0 
+0900
@@ -657,6 +657,25 @@ struct request_sock;
  * @sig contains the signal value.
  * @secid contains the sid of the process where the signal originated
  * Return 0 if permission is granted.
+ * @task_kill_unlocked:
+ * Check permission before sending signal @sig to the process of @pid
+ * with sys_kill.
+ * @pid contains the pid of target process.
+ * @sig contains the signal value.
+ * Return 0 if permission is granted.
+ * @task_tkill_unlocked:
+ * Check permission before sending signal @sig to the process of @pid
+ * with sys_tkill.
+ * @pid contains the pid of target process.
+ * @sig contains the signal value.
+ * Return 0 if permission is granted.
+ * @task_tgkill_unlocked:
+ * Check permission before sending signal @sig to the process of @pid
+ * with sys_tgkill.
+ * @tgid contains the thread group id.
+ * @pid contains the pid of target process.
+ * @sig contains the signal value.
+ * Return 0 if permission is granted.
  * @task_wait:
  * Check permission before allowing a process to reap a child process @p
  * and collect its status information.
@@ -778,8 +797,12 @@ struct request_sock;
  * @socket_post_accept:
  * This hook allows a security module to copy security
  * information into the newly created socket's inode.
+ * This hook also allows a security module to filter connections
+ * from unwanted peers.
+ * The connection will be aborted if this hook returns nonzero.
  * @sock contains the listening socket structure.
  * @newsock contains the newly created server socket for connection.
+ * Return 0 if permission is granted.
  * @socket_sendmsg:
  * Check permission before transmitting a message to another socket.
  * @sock contains the socket structure.
@@ -793,6 +816,12 @@ struct request_sock;
  * @size contains the size of message structure.
  * @flags contains the operational flags.
  * Return 0 if permission is granted.  
+ * @post_recv_datagram:
+ * Check permission after receiving a datagram.
+ * @sk contains the socket.
+ * @skb contains the socket buffer (may be NULL).
+ * @flags contains the operational flags.
+ * Return 0 if permission is granted.
  * @socket_getsockname:
  * Check permission before the local address (name) of the socket object
  * @sock is retrieved.
@@ -1319,6 +1348,9 @@ struct security_operations {
int (*task_movememory) (struct task_struct * p);
int (*task_kill) (struct task_struct * p,
  struct siginfo * info, int sig, u32 secid);
+   int (*task_kill_unlocked) (int pid, int sig);
+   int (*task_tkill_unlocked) (int pid, int sig);
+   int (*task_tgkill_unlocked) (int tgid, int pid, int sig);
int (*task_wait) (struct task_struct * p);
int (*task_prctl) (int option, unsigned long arg2,
   unsigned long arg3, unsigned long arg4,
@@ -1384,12 +1416,16 @@ struct security_operations {
   struct sockaddr * address, int addrlen);
int (*socket_listen) (struct socket * sock, int backlog);
int (*socket_accept) (struct socket * sock, struct socket * newsock);
-   void (*socket_post_accept) (struct socket * sock,
-   struct socket * newsock);
+#define TMY_LSM_EXPANSION
+   int (*socket_post_accept) (struct socket *sock,
+  struct socket *newsock);
int (*socket_sendmsg) (struct socket * sock,
   struct msghdr * msg, int size);
int (*socket_recvmsg) (struct socket * sock,
   struct msghdr * msg, int size, int flags);
+   int (*post_recv_datagram) (struct sock *sk,
+  struct sk_buff *skb,
+   

[TOMOYO #5 14/18] Capability access control functions.

2007-11-16 Thread penguin-kernel
TOMOYO Linux checks permission for non-POSIX capability
so that the number of capabilities won't be limited to 32 or 64.

Each permission can be automatically accumulated into
the policy of each domain using 'learning mode'.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/capability.c |  320 +++
 1 file changed, 320 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/capability.c   2007-11-14 15:15:44.0 
+0900
@@ -0,0 +1,320 @@
+/*
+ * security/tomoyo/capability.c
+ *
+ * Capability access control functions for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+static struct {
+   const char *keyword;
+   unsigned int current_value;
+   const char *capability_name;
+} capability_control_array[TMY_MAX_CAPABILITY_INDEX] = {
+   [TMY_INET_STREAM_SOCKET_CREATE]  = /* OK */
+   { inet_tcp_create, 0, socket(PF_INET, SOCK_STREAM) },
+   [TMY_INET_STREAM_SOCKET_LISTEN]  = /* OK */
+   { inet_tcp_listen, 0, listen(PF_INET, SOCK_STREAM) },
+   [TMY_INET_STREAM_SOCKET_CONNECT] = /* OK */
+   { inet_tcp_connect, 0, connect(PF_INET, SOCK_STREAM) },
+   [TMY_USE_INET_DGRAM_SOCKET]  = /* OK */
+   { use_inet_udp, 0, socket(PF_INET, SOCK_DGRAM) },
+   [TMY_USE_INET_RAW_SOCKET]= /* OK */
+   { use_inet_ip, 0, socket(PF_INET, SOCK_RAW) },
+   [TMY_USE_ROUTE_SOCKET]   = /* OK */
+   { use_route, 0, socket(PF_ROUTE) },
+   [TMY_USE_PACKET_SOCKET]  = /* OK */
+   { use_packet, 0, socket(PF_PACKET) },
+   [TMY_SYS_MOUNT]  = /* OK */
+   { SYS_MOUNT, 0, sys_mount() },
+   [TMY_SYS_UMOUNT] = /* OK */
+   { SYS_UMOUNT, 0, sys_umount() },
+   [TMY_SYS_REBOOT] = /* Too many hooks. */
+   { SYS_REBOOT, 0, sys_reboot() },
+   [TMY_SYS_CHROOT] = /* OK */
+   { SYS_CHROOT, 0, sys_chroot() },
+   [TMY_SYS_KILL]   = /* No appropriate hook. */
+   { SYS_KILL, 0, sys_kill() },
+   [TMY_SYS_VHANGUP]= /* Too many hooks. */
+   { SYS_VHANGUP, 0, sys_vhangup() },
+   [TMY_SYS_SETTIME]= /* Too many hooks. */
+   { SYS_TIME, 0, sys_settimeofday() },
+   [TMY_SYS_NICE]   = /* No appropriate hook. */
+   { SYS_NICE, 0, sys_nice() },
+   [TMY_SYS_SETHOSTNAME]= /* No appropriate hook. */
+   { SYS_SETHOSTNAME, 0, sys_sethostname() },
+   [TMY_USE_KERNEL_MODULE]  = /* Too many hooks. */
+   { use_kernel_module, 0, kernel_module },
+   [TMY_CREATE_FIFO]= /* OK */
+   { create_fifo, 0, mknod(FIFO) },
+   [TMY_CREATE_BLOCK_DEV]   = /* OK */
+   { create_block_dev, 0, mknod(BDEV) },
+   [TMY_CREATE_CHAR_DEV]= /* OK */
+   { create_char_dev, 0, mknod(CDEV) },
+   [TMY_CREATE_UNIX_SOCKET] = /* OK */
+   { create_unix_socket, 0, mknod(SOCKET) },
+   [TMY_SYS_LINK]   = /* OK */
+   { SYS_LINK, 0, sys_link() },
+   [TMY_SYS_SYMLINK]= /* OK */
+   { SYS_SYMLINK, 0, sys_symlink() },
+   [TMY_SYS_RENAME] = /* OK */
+   { SYS_RENAME, 0, sys_rename() },
+   [TMY_SYS_UNLINK] = /* OK */
+   { SYS_UNLINK, 0, sys_unlink() },
+   [TMY_SYS_CHMOD]  = /* OK */
+   { SYS_CHMOD, 0, sys_chmod() },
+   [TMY_SYS_CHOWN]  = /* OK */
+   { SYS_CHOWN, 0, sys_chown() },
+   [TMY_SYS_IOCTL]  = /* Too many hooks. */
+   { SYS_IOCTL, 0, sys_ioctl() },
+   [TMY_SYS_KEXEC_LOAD] = /* No appropriate hook. */
+   { SYS_KEXEC_LOAD, 0, sys_kexec_load() },
+   [TMY_SYS_PIVOT_ROOT] = /* OK */
+   { SYS_PIVOT_ROOT, 0, sys_pivot_root() },
+};
+
+struct profile {
+   unsigned char value[TMY_MAX_CAPABILITY_INDEX];
+};
+
+static struct profile *profile_ptr[TMY_MAX_PROFILES];
+
+/*  UTILITY FUNCTIONS  */
+
+const char *tmy_capability2keyword(const unsigned int capability)
+{
+   return capability  TMY_MAX_CAPABILITY_INDEX ?
+   capability_control_array[capability].keyword : NULL;
+}
+
+static const char *tmy_capability2name(const unsigned int capability)
+{
+   return capability  TMY_MAX_CAPABILITY_INDEX ?
+   capability_control_array[capability].capability_name : NULL;
+}
+
+/* Check whether the given capability control is enabled. */
+static unsigned int tmy_capability_flags(const unsigned int index)
+{
+   const u8 profile = TMY_SECURITY-domain-profile;
+   /* All operations might sleep. See tmy_supervisor(). */
+   might_sleep();
+   if (in_interrupt())
+   return 0;
+   return sbin_init_started  index  

[TOMOYO #5 15/18] LSM adapter functions.

2007-11-16 Thread penguin-kernel
To avoid namespace_sem deadlock, this patch uses
current-last_vfsmount associated by wrapper functions.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/tomoyo.c |  822 +++
 1 file changed, 822 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/tomoyo.c   2007-11-14 15:56:26.0 
+0900
@@ -0,0 +1,822 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+LIST_HEAD(domain_list);
+
+static struct kmem_cache *tmy_cachep;
+
+static int tmy_task_alloc_security(struct task_struct *p)
+{
+   struct tmy_security *ptr = kmem_cache_alloc(tmy_cachep, GFP_KERNEL);
+
+   if (!ptr)
+   return -ENOMEM;
+   memcpy(ptr, TMY_SECURITY, sizeof(*ptr));
+   p-security = ptr;
+   return 0;
+}
+
+static void tmy_task_free_security(struct task_struct *p)
+{
+   kmem_cache_free(tmy_cachep, p-security);
+}
+
+static int tmy_bprm_alloc_security(struct linux_binprm *bprm)
+{
+   TMY_SECURITY-prev_domain = TMY_SECURITY-domain;
+   return 0;
+}
+
+static int tmy_bprm_check_security(struct linux_binprm *bprm)
+{
+   struct domain_info *next_domain = NULL;
+   int retval = 0;
+
+   tmy_load_policy(bprm-filename);
+
+   /*
+* TMY_CHECK_READ_FOR_OPEN_EXEC bit indicates whether this function is
+* called by do_execve() or not.
+* If called by do_execve(), I do domain transition.
+*/
+   if (!(TMY_SECURITY-flags
+  TMY_CHECK_READ_FOR_OPEN_EXEC)) {
+   retval = tmy_find_next_domain(bprm, next_domain);
+   if (retval == 0) {
+   TMY_SECURITY-domain = next_domain;
+   TMY_SECURITY-flags |=
+   TMY_CHECK_READ_FOR_OPEN_EXEC;
+   }
+   }
+
+   return retval;
+}
+
+static void tmy_bprm_post_apply_creds(struct linux_binprm *bprm)
+{
+   TMY_SECURITY-prev_domain = TMY_SECURITY-domain;
+}
+
+static void tmy_bprm_free_security(struct linux_binprm *bprm)
+{
+   TMY_SECURITY-domain = TMY_SECURITY-prev_domain;
+   TMY_SECURITY-flags = ~TMY_CHECK_READ_FOR_OPEN_EXEC;
+}
+
+static int tmy_sysctl(struct ctl_table *table, int op)
+{
+   int error;
+   char *name;
+
+   if ((op  6) == 0)
+   return 0;
+
+   name = sysctlpath_from_table(table);
+   if (!name)
+   return -ENOMEM;
+
+   error = tmy_file_perm(name, op  6, sysctl);
+   tmy_free(name);
+
+   return error;
+}
+
+static int tmy_inode_permission(struct inode *inode,
+   int mask,
+   struct nameidata *nd)
+{
+   int flag = 0;
+
+   if (S_ISDIR(inode-i_mode)) /* ignore because inode is directory */
+   return 0;
+   /*
+   if (!nd) {
+   printk(tmy_inode_permission: NULL nameidata\n);
+   dump_stack();
+   return 0;
+   } else if (!nd-mnt) {
+   printk(tmy_inode_permission: NULL vfsmount\n);
+   dump_stack();
+   return 0;
+   }
+   */
+   if (!nd || !nd-path.dentry || !nd-path.mnt)
+   return 0;
+   /*
+* If called by other than do_execve(), I check for read permission of
+* interpreter.
+* Unlike DAC, I don't check for read permission of pathname passed to
+* do_execve().
+* TOMOYO Linux checks for program's execute permission and
+* interpreter's read permission.
+*/
+   if ((mask == MAY_EXEC) 
+   (TMY_SECURITY-flags  TMY_CHECK_READ_FOR_OPEN_EXEC))
+   mask = MAY_READ;
+   if ((mask == MAY_EXEC) || (mask == 0))
+   return 0;
+
+   if (mask == (MAY_READ | MAY_EXEC))
+   flag |= O_RDONLY + 1;
+   else {
+   if (mask  MAY_READ)
+   flag |= O_RDONLY + 1;
+   if (mask  MAY_WRITE)
+   flag |= O_WRONLY + 1;
+   if ((mask  MAY_APPEND))
+   flag |= O_APPEND;
+   }
+
+   return tmy_open_perm(nd-path.dentry, nd-path.mnt, flag);
+}
+
+static int tmy_do_single_write_perm(int operation, struct dentry *dentry)
+{
+   struct vfsmount *mnt = current-last_vfsmount;
+   if (!dentry || !mnt)
+   return 0;
+   if (!sbin_init_started)
+   return 0;
+   return tmy_single_write_perm(operation, dentry, mnt);
+}
+
+static int tmy_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+   int err = 0;
+   unsigned int ia_valid = iattr-ia_valid;
+   if (ia_valid  ATTR_MODE)
+   err = tmy_capable(TMY_SYS_CHMOD);
+   if (!err  (ia_valid  (ATTR_UID | ATTR_GID)))
+   err = 

[TOMOYO #5 05/18] Memory and pathname management functions.

2007-11-16 Thread penguin-kernel
Basic functions to get canonicalized absolute pathnames
for TOMOYO Linux. Even the requested pathname is symlink()ed
or chroot()ed, TOMOYO Linux uses the original pathname.

Signed-off-by: Kentaro Takeda [EMAIL PROTECTED]
Signed-off-by: Tetsuo Handa [EMAIL PROTECTED]
 security/tomoyo/realpath.c |  658 +
 1 file changed, 658 insertions(+)

--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6-mm/security/tomoyo/realpath.c 2007-11-14 15:58:58.0 
+0900
@@ -0,0 +1,658 @@
+/*
+ * security/tomoyo/realpath.c
+ *
+ * Get the canonicalized absolute pathnames.
+ * The basis for TOMOYO Linux.
+ */
+
+#include tomoyo.h
+#include realpath.h
+
+/* realpath handler */
+
+static int tmy_print_ascii(const char *sp, const char *cp,
+  int *buflen0, char **end0)
+{
+   int buflen = *buflen0;
+   char *end = *end0;
+
+   while (sp = cp) {
+   unsigned char c;
+
+   c = *(unsigned char *) cp;
+   if (c == '\\') {
+   buflen -= 2;
+   if (buflen  0)
+   goto out;
+   *--end = '\\';
+   *--end = '\\';
+   } else if (c  ' '  c  127) {
+   if (--buflen  0)
+   goto out;
+   *--end = (char) c;
+   } else {
+   buflen -= 4;
+   if (buflen  0)
+   goto out;
+   *--end = (c  7) + '0';
+   *--end = ((c  3)  7) + '0';
+   *--end = (c  6) + '0';
+   *--end = '\\';
+   }
+   cp--;
+   }
+
+   *buflen0 = buflen;
+   *end0 = end;
+
+   return 0;
+out: ;
+   return -ENOMEM;
+}
+
+/**
+ * tmy_get_absolute_path - return the realpath of a dentry.
+ * @dentry: pointer to struct dentry.
+ * @vfsmnt: pointer to struct vfsmount to which the @dentry belongs.
+ * @buffer: size of buffer to save the result.
+ * @buflen: size of @buffer .
+ *
+ * Returns zero on success.
+ * Returns nonzero on failure.
+ *
+ * Caller holds the dcache_lock.
+ * Based on __d_path() in fs/dcache.c
+ *
+ * Unlike d_path(), this function traverses upto the root directory of
+ * process's namespace.
+ *
+ * If @dentry is a directory, trailing '/' is appended.
+ * Characters other than ' '  c  127 are converted to \ooo style octal 
string.
+ * Character \ is converted to \\ string.
+ */
+static int tmy_get_absolute_path(struct dentry *dentry,
+struct vfsmount *vfsmnt,
+char *buffer,
+int buflen)
+{
+   char *start = buffer;
+   char *end = buffer + buflen;
+   bool is_dir = (dentry-d_inode  S_ISDIR(dentry-d_inode-i_mode));
+   const char *sp;
+   const char *cp;
+
+   if (buflen  256)
+   goto out;
+
+   *--end = '\0';
+   buflen--;
+
+   while (1) {
+   struct dentry *parent;
+
+   if (dentry == vfsmnt-mnt_root || IS_ROOT(dentry)) {
+   /* Global root? */
+   spin_lock(vfsmount_lock);
+   if (vfsmnt-mnt_parent == vfsmnt) {
+   spin_unlock(vfsmount_lock);
+   break;
+   }
+   dentry = vfsmnt-mnt_mountpoint;
+   vfsmnt = vfsmnt-mnt_parent;
+   spin_unlock(vfsmount_lock);
+   continue;
+   }
+
+   if (is_dir) {
+   is_dir = 0;
+   *--end = '/';
+   buflen--;
+   }
+
+   parent = dentry-d_parent;
+   sp = dentry-d_name.name;
+   cp = sp + dentry-d_name.len - 1;
+
+   /* Exception: Use /proc/self/ rather than */
+   /* /proc/\$/ for current process. */
+   if (IS_ROOT(parent) 
+   *sp  '0'  *sp = '9'  parent-d_sb 
+   parent-d_sb-s_magic == PROC_SUPER_MAGIC) {
+
+   char *ep;
+   const pid_t pid = (pid_t) simple_strtoul(sp, ep, 10);
+
+   if (!*ep  pid == current-tgid) {
+   sp = self;
+   cp = sp + 3;
+   }
+
+   }
+
+   if (tmy_print_ascii(sp, cp, buflen, end))
+   goto out;
+
+   if (--buflen  0)
+   goto out;
+   *--end = '/';
+
+   dentry = parent;
+   }
+   if (*end == '/') {
+   buflen++;
+   end++;
+   }
+
+   sp = dentry-d_name.name;
+   cp = sp + dentry-d_name.len - 1;
+
+   if