Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tomoyo: Don't use nifty names on sockets.

syzbot is reporting that use of SOCKET_I()->sk from open() can result in
use after free problem [1], for socket's inode is still reachable via
/proc/pid/fd/n despite destruction of SOCKET_I()->sk already completed.

At first I thought that this race condition applies to only open/getattr
permission checks. But James Morris has pointed out that there are more
permission checks where this race condition applies to. Thus, get rid of
tomoyo_get_socket_name() instead of conditionally bypassing permission
checks on sockets. As a side effect of this patch,
"socket:[family=\$:type=\$:protocol=\$]" in the policy files has to be
rewritten to "socket:[\$]".

[1] https://syzkaller.appspot.com/bug?id=73d590010454403d55164cca23bd0565b1eb3b74

Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Reported-by: syzbot <syzbot+0341f6a4d729d4e0acf1@syzkaller.appspotmail.com>
Reported-by: James Morris <jmorris@namei.org>

+1 -31
+1 -31
security/tomoyo/realpath.c
··· 218 218 } 219 219 220 220 /** 221 - * tomoyo_get_socket_name - Get the name of a socket. 222 - * 223 - * @path: Pointer to "struct path". 224 - * @buffer: Pointer to buffer to return value in. 225 - * @buflen: Sizeof @buffer. 226 - * 227 - * Returns the buffer. 228 - */ 229 - static char *tomoyo_get_socket_name(const struct path *path, char * const buffer, 230 - const int buflen) 231 - { 232 - struct inode *inode = d_backing_inode(path->dentry); 233 - struct socket *sock = inode ? SOCKET_I(inode) : NULL; 234 - struct sock *sk = sock ? sock->sk : NULL; 235 - 236 - if (sk) { 237 - snprintf(buffer, buflen, "socket:[family=%u:type=%u:protocol=%u]", 238 - sk->sk_family, sk->sk_type, sk->sk_protocol); 239 - } else { 240 - snprintf(buffer, buflen, "socket:[unknown]"); 241 - } 242 - return buffer; 243 - } 244 - 245 - /** 246 221 * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root. 247 222 * 248 223 * @path: Pointer to "struct path". ··· 254 279 break; 255 280 /* To make sure that pos is '\0' terminated. */ 256 281 buf[buf_len - 1] = '\0'; 257 - /* Get better name for socket. */ 258 - if (sb->s_magic == SOCKFS_MAGIC) { 259 - pos = tomoyo_get_socket_name(path, buf, buf_len - 1); 260 - goto encode; 261 - } 262 - /* For "pipe:[\$]". */ 282 + /* For "pipe:[\$]" and "socket:[\$]". */ 263 283 if (dentry->d_op && dentry->d_op->d_dname) { 264 284 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1); 265 285 goto encode;