blob: a339187cad750ef375bbec610510e59b5e767a4e [file] [log] [blame]
Kentaro Takedac73bd6d2009-02-05 17:18:12 +09001/*
2 * security/tomoyo/realpath.c
3 *
Tetsuo Handac3ef1502010-05-17 10:12:46 +09004 * Pathname calculation functions for TOMOYO.
Kentaro Takedac73bd6d2009-02-05 17:18:12 +09005 *
Tetsuo Handac3ef1502010-05-17 10:12:46 +09006 * Copyright (C) 2005-2010 NTT DATA CORPORATION
Kentaro Takedac73bd6d2009-02-05 17:18:12 +09007 */
8
9#include <linux/types.h>
10#include <linux/mount.h>
11#include <linux/mnt_namespace.h>
Al Viro5ad4e532009-03-29 19:50:06 -040012#include <linux/fs_struct.h>
Tetsuo Handa67fa4882009-12-09 15:36:04 +090013#include <linux/magic.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Tetsuo Handac8c57e82010-06-03 20:36:43 +090015#include <net/sock.h>
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090016#include "common.h"
Nick Pigginda502952011-01-07 17:49:33 +110017#include "../../fs/internal.h"
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090018
19/**
20 * tomoyo_encode: Convert binary string to ascii string.
21 *
Tetsuo Handac8c57e82010-06-03 20:36:43 +090022 * @str: String in binary format.
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090023 *
Tetsuo Handac8c57e82010-06-03 20:36:43 +090024 * Returns pointer to @str in ascii format on success, NULL otherwise.
25 *
26 * This function uses kzalloc(), so caller must kfree() if this function
27 * didn't return NULL.
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090028 */
Tetsuo Handac8c57e82010-06-03 20:36:43 +090029char *tomoyo_encode(const char *str)
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090030{
Tetsuo Handac8c57e82010-06-03 20:36:43 +090031 int len = 0;
32 const char *p = str;
33 char *cp;
34 char *cp0;
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090035
Tetsuo Handac8c57e82010-06-03 20:36:43 +090036 if (!p)
37 return NULL;
38 while (*p) {
39 const unsigned char c = *p++;
40 if (c == '\\')
41 len += 2;
42 else if (c > ' ' && c < 127)
43 len++;
44 else
45 len += 4;
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090046 }
Tetsuo Handac8c57e82010-06-03 20:36:43 +090047 len++;
48 /* Reserve space for appending "/". */
49 cp = kzalloc(len + 10, GFP_NOFS);
50 if (!cp)
51 return NULL;
52 cp0 = cp;
53 p = str;
54 while (*p) {
55 const unsigned char c = *p++;
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090056
Tetsuo Handac8c57e82010-06-03 20:36:43 +090057 if (c == '\\') {
58 *cp++ = '\\';
59 *cp++ = '\\';
60 } else if (c > ' ' && c < 127) {
61 *cp++ = c;
62 } else {
63 *cp++ = '\\';
64 *cp++ = (c >> 6) + '0';
65 *cp++ = ((c >> 3) & 7) + '0';
66 *cp++ = (c & 7) + '0';
Eric W. Biedermana4054b62009-11-20 09:12:22 -080067 }
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090068 }
Tetsuo Handac8c57e82010-06-03 20:36:43 +090069 return cp0;
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090070}
71
72/**
73 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
74 *
75 * @path: Pointer to "struct path".
76 *
77 * Returns the realpath of the given @path on success, NULL otherwise.
78 *
Tetsuo Handac8c57e82010-06-03 20:36:43 +090079 * If dentry is a directory, trailing '/' is appended.
80 * Characters out of 0x20 < c < 0x7F range are converted to
81 * \ooo style octal string.
82 * Character \ is converted to \\ string.
83 *
Tetsuo Handa8e2d39a2010-01-26 20:45:27 +090084 * These functions use kzalloc(), so the caller must call kfree()
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090085 * if these functions didn't return NULL.
86 */
87char *tomoyo_realpath_from_path(struct path *path)
88{
Tetsuo Handac8c57e82010-06-03 20:36:43 +090089 char *buf = NULL;
90 char *name = NULL;
91 unsigned int buf_len = PAGE_SIZE / 2;
92 struct dentry *dentry = path->dentry;
93 bool is_dir;
94 if (!dentry)
Kentaro Takedac73bd6d2009-02-05 17:18:12 +090095 return NULL;
Tetsuo Handac8c57e82010-06-03 20:36:43 +090096 is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
97 while (1) {
Tetsuo Handac8c57e82010-06-03 20:36:43 +090098 char *pos;
99 buf_len <<= 1;
100 kfree(buf);
101 buf = kmalloc(buf_len, GFP_NOFS);
102 if (!buf)
103 break;
104 /* Get better name for socket. */
105 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
106 struct inode *inode = dentry->d_inode;
107 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
108 struct sock *sk = sock ? sock->sk : NULL;
109 if (sk) {
110 snprintf(buf, buf_len - 1, "socket:[family=%u:"
111 "type=%u:protocol=%u]", sk->sk_family,
112 sk->sk_type, sk->sk_protocol);
113 } else {
114 snprintf(buf, buf_len - 1, "socket:[unknown]");
115 }
116 name = tomoyo_encode(buf);
117 break;
118 }
119 /* For "socket:[\$]" and "pipe:[\$]". */
120 if (dentry->d_op && dentry->d_op->d_dname) {
121 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
122 if (IS_ERR(pos))
123 continue;
124 name = tomoyo_encode(pos);
125 break;
126 }
127 /* If we don't have a vfsmount, we can't calculate. */
128 if (!path->mnt)
129 break;
Al Viro58a48c42011-12-05 08:43:34 -0500130 pos = d_absolute_path(path, buf, buf_len - 1);
131 /* If path is disconnected, use "[unknown]" instead. */
132 if (pos == ERR_PTR(-EINVAL)) {
133 name = tomoyo_encode("[unknown]");
134 break;
135 }
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900136 /* Prepend "/proc" prefix if using internal proc vfs mount. */
137 if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
138 (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
139 pos -= 5;
140 if (pos >= buf)
141 memcpy(pos, "/proc", 5);
142 else
143 pos = ERR_PTR(-ENOMEM);
144 }
145 if (IS_ERR(pos))
146 continue;
147 name = tomoyo_encode(pos);
148 break;
149 }
Tetsuo Handa8e2d39a2010-01-26 20:45:27 +0900150 kfree(buf);
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900151 if (!name)
152 tomoyo_warn_oom(__func__);
153 else if (is_dir && *name) {
154 /* Append trailing '/' if dentry is a directory. */
155 char *pos = name + strlen(name) - 1;
156 if (*pos != '/')
157 /*
158 * This is OK because tomoyo_encode() reserves space
159 * for appending "/".
160 */
161 *++pos = '/';
162 }
163 return name;
Kentaro Takedac73bd6d2009-02-05 17:18:12 +0900164}
165
166/**
Kentaro Takedac73bd6d2009-02-05 17:18:12 +0900167 * tomoyo_realpath_nofollow - Get realpath of a pathname.
168 *
169 * @pathname: The pathname to solve.
170 *
171 * Returns the realpath of @pathname on success, NULL otherwise.
172 */
173char *tomoyo_realpath_nofollow(const char *pathname)
174{
Al Viroe24977d2009-04-02 21:17:03 -0400175 struct path path;
Kentaro Takedac73bd6d2009-02-05 17:18:12 +0900176
Al Viroe24977d2009-04-02 21:17:03 -0400177 if (pathname && kern_path(pathname, 0, &path) == 0) {
178 char *buf = tomoyo_realpath_from_path(&path);
179 path_put(&path);
Kentaro Takedac73bd6d2009-02-05 17:18:12 +0900180 return buf;
181 }
182 return NULL;
183}