lkml.org 
[lkml]   [2009]   [Oct]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[TOMOYO #16 22/25] TOMOYO: Add pathname calculation functions.
This patch contains code for getting canonicalized pathnames used by TOMOYO.
TOMOYO 2.2.0 uses __d_path() for getting canonicalized pathnames, but there are
several issues.

(1) The " (deleted)" is appended to the returned pathname if the pathname was
deleted. This causes TOMOYO to check

allow_truncate /tmp/file

for

int fd = open("/tmp/file", O_WRONLY | O_CREAT, 0600);
ftruncate(fd, 0);
unlink("/tmp/file");
close(fd);

sequence and

allow_truncate /tmp/file\040(deleted)

for

int fd = open("/tmp/file", O_WRONLY | O_CREAT, 0600);
unlink("/tmp/file");
ftruncate(fd, 0);
close(fd);

sequence, although these sequences are doing the same operations in
different order. Since this is annoying for policy developers, I want
to avoid trailing " (deleted)".

(2) __d_path() does not replace /proc/PID/ with /proc/self/ if PID is equals to
the current process's PID. Pathname based access control can prevent
current process from accessing other process's information if we can map
/proc/PID/ to /proc/self/ . The caller of __d_path() can't replace "PID"
with "self" after returning from __d_path() because the caller cannot tell
whether the numeric part of the returned pathname is a PID or not.
To tell whether the numeric part of the returned pathname is a PID or not,
the caller has to do dentry/vfsmount traversal by its own, and that makes
use of __d_path() meaningless.

(3) The pathname for socket is in "socket:[%u]" format. But such pathname is
too useless for pathname based access control.
I want to use pathnames in "socket:[family=%u:type=%u:protocol=%u]" format.
The best pathname might include socket's peer address information, but it
would be difficult to fetch and represent address information.

To solve these issues, I'd like to introduce custom __d_path() functions
(or add some flags to __d_path()).

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
security/tomoyo/new-realpath.c | 251 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 251 insertions(+)

--- /dev/null
+++ security-testing-2.6/security/tomoyo/new-realpath.c
@@ -0,0 +1,251 @@
+/*
+ * security/tomoyo/realpath.c
+ *
+ * Copyright (C) 2005-2009 NTT DATA CORPORATION
+ */
+#include "internal.h"
+#include <net/sock.h>
+#include <linux/magic.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+
+/**
+ * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
+ *
+ * @path: Pointer to "struct path".
+ * @buffer: Pointer to buffer to return value in.
+ * @buflen: Sizeof @buffer.
+ *
+ * Returns the buffer on success, an error code otherwise.
+ *
+ * Caller holds the dcache_lock and vfsmount_lock.
+ * Based on __d_path() in fs/dcache.c
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ * /proc/pid is represented as /proc/self if pid is current.
+ */
+static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
+ const int buflen)
+{
+ char *pos = buffer + buflen - 1;
+ struct dentry *dentry = path->dentry;
+ struct vfsmount *vfsmnt = path->mnt;
+ bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
+ const char *name;
+ int len;
+
+ if (buflen < 256)
+ goto out;
+
+ *pos = '\0';
+ for (;;) {
+ struct dentry *parent;
+ if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+ if (vfsmnt->mnt_parent == vfsmnt)
+ break;
+ dentry = vfsmnt->mnt_mountpoint;
+ vfsmnt = vfsmnt->mnt_parent;
+ continue;
+ }
+ if (is_dir) {
+ is_dir = false;
+ *--pos = '/';
+ }
+ parent = dentry->d_parent;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
+ if (IS_ROOT(parent) && *name > '0' && *name <= '9' &&
+ parent->d_sb &&
+ parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
+ char *ep;
+ const pid_t pid = (pid_t) simple_strtoul(name, &ep,
+ 10);
+ const pid_t tgid = task_tgid_nr_ns(current,
+ dentry->d_sb->
+ s_fs_info);
+ if (!*ep && pid == tgid && tgid) {
+ name = "self";
+ len = 4;
+ }
+ }
+ pos -= len;
+ if (pos <= buffer)
+ goto out;
+ memmove(pos, name, len);
+ *--pos = '/';
+ dentry = parent;
+ }
+ if (*pos == '/')
+ pos++;
+ len = dentry->d_name.len;
+ pos -= len;
+ if (pos < buffer)
+ goto out;
+ memmove(pos, dentry->d_name.name, len);
+ return pos;
+ out:
+ return ERR_PTR(-ENOMEM);
+}
+
+#define SOCKFS_MAGIC 0x534F434B
+
+/**
+ * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
+ *
+ * @path: Pointer to "struct path".
+ *
+ * Returns the realpath of the given @path on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_realpath_from_path(struct path *path)
+{
+ char *buf = NULL;
+ char *name = NULL;
+ unsigned int buf_len = PAGE_SIZE / 2;
+ struct dentry *dentry = path->dentry;
+ if (!dentry)
+ return NULL;
+ while (1) {
+ char *pos;
+ buf_len <<= 1;
+ kfree(buf);
+ buf = kmalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ break;
+ /* Get better name for socket. */
+ if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
+ struct inode *inode = dentry->d_inode;
+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+ struct sock *sk = sock ? sock->sk : NULL;
+ if (sk) {
+ snprintf(buf, buf_len - 1, "socket:[family=%u:"
+ "type=%u:protocol=%u]", sk->sk_family,
+ sk->sk_type, sk->sk_protocol);
+ } else {
+ snprintf(buf, buf_len - 1, "socket:[unknown]");
+ }
+ name = tomoyo_encode(buf);
+ break;
+ }
+ /* For "socket:[\$]" and "pipe:[\$]". */
+ if (dentry->d_op && dentry->d_op->d_dname) {
+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
+ if (IS_ERR(pos))
+ continue;
+ name = tomoyo_encode(pos);
+ break;
+ }
+ if (!path->mnt)
+ break;
+ path_get(path);
+ spin_lock(&dcache_lock);
+ spin_lock(&vfsmount_lock);
+ pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
+ spin_unlock(&vfsmount_lock);
+ spin_unlock(&dcache_lock);
+ path_put(path);
+ if (IS_ERR(pos))
+ continue;
+ name = tomoyo_encode(pos);
+ break;
+ }
+ kfree(buf);
+ if (!name)
+ tomoyo_warn_oom(__func__);
+ return name;
+}
+
+/**
+ * tomoyo_symlink_path - Get symlink's pathname.
+ *
+ * @pathname: The pathname to solve.
+ * @name: Pointer to "struct tomoyo_path_info".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+int tomoyo_symlink_path(const char *pathname, struct tomoyo_path_info *name)
+{
+ char *buf;
+ struct path path;
+ if (!pathname || kern_path(pathname, 0, &path))
+ return -ENOENT;
+ buf = tomoyo_realpath_from_path(&path);
+ path_put(&path);
+ if (buf) {
+ name->name = buf;
+ tomoyo_fill_path_info(name);
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+/**
+ * tomoyo_encode: Encode binary string to ascii string.
+ *
+ * @str: String in binary format.
+ *
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+char *tomoyo_encode(const char *str)
+{
+ int len = 0;
+ const char *p = str;
+ char *cp;
+ char *cp0;
+ if (!p)
+ return NULL;
+ while (*p) {
+ const unsigned char c = *p++;
+ if (c == '\\')
+ len += 2;
+ else if (c > ' ' && c < 127)
+ len++;
+ else
+ len += 4;
+ }
+ len++;
+ /* Reserve space for appending "/". */
+ cp = kzalloc(len + 10, GFP_KERNEL);
+ if (!cp)
+ return NULL;
+ cp0 = cp;
+ p = str;
+ while (*p) {
+ const unsigned char c = *p++;
+ if (c == '\\') {
+ *cp++ = '\\';
+ *cp++ = '\\';
+ } else if (c > ' ' && c < 127) {
+ *cp++ = c;
+ } else {
+ *cp++ = '\\';
+ *cp++ = (c >> 6) + '0';
+ *cp++ = ((c >> 3) & 7) + '0';
+ *cp++ = (c & 7) + '0';
+ }
+ }
+ return cp0;
+}
+
+/**
+ * tomoyo_get_path - Get dentry/vfsmmount of a pathname.
+ *
+ * @pathname: The pathname to solve.
+ * @path: Pointer to "struct path".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_get_path(const char *pathname, struct path *path)
+{
+ if (!pathname || kern_path(pathname, LOOKUP_FOLLOW, path))
+ return -ENOENT;
+ return 0;
+}
--


\
 
 \ /
  Last update: 2009-10-04 15:15    [W:0.184 / U:0.048 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site