1cdff2642SJohn Johansen /* 2cdff2642SJohn Johansen * AppArmor security module 3cdff2642SJohn Johansen * 4cdff2642SJohn Johansen * This file contains AppArmor function for pathnames 5cdff2642SJohn Johansen * 6cdff2642SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 7cdff2642SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 8cdff2642SJohn Johansen * 9cdff2642SJohn Johansen * This program is free software; you can redistribute it and/or 10cdff2642SJohn Johansen * modify it under the terms of the GNU General Public License as 11cdff2642SJohn Johansen * published by the Free Software Foundation, version 2 of the 12cdff2642SJohn Johansen * License. 13cdff2642SJohn Johansen */ 14cdff2642SJohn Johansen 15cdff2642SJohn Johansen #include <linux/magic.h> 16cdff2642SJohn Johansen #include <linux/mount.h> 17cdff2642SJohn Johansen #include <linux/namei.h> 18cdff2642SJohn Johansen #include <linux/nsproxy.h> 19cdff2642SJohn Johansen #include <linux/path.h> 20cdff2642SJohn Johansen #include <linux/sched.h> 21cdff2642SJohn Johansen #include <linux/slab.h> 22cdff2642SJohn Johansen #include <linux/fs_struct.h> 23cdff2642SJohn Johansen 24cdff2642SJohn Johansen #include "include/apparmor.h" 25cdff2642SJohn Johansen #include "include/path.h" 26cdff2642SJohn Johansen #include "include/policy.h" 27cdff2642SJohn Johansen 28cdff2642SJohn Johansen 29cdff2642SJohn Johansen /* modified from dcache.c */ 30cdff2642SJohn Johansen static int prepend(char **buffer, int buflen, const char *str, int namelen) 31cdff2642SJohn Johansen { 32cdff2642SJohn Johansen buflen -= namelen; 33cdff2642SJohn Johansen if (buflen < 0) 34cdff2642SJohn Johansen return -ENAMETOOLONG; 35cdff2642SJohn Johansen *buffer -= namelen; 36cdff2642SJohn Johansen memcpy(*buffer, str, namelen); 37cdff2642SJohn Johansen return 0; 38cdff2642SJohn Johansen } 39cdff2642SJohn Johansen 40cdff2642SJohn Johansen #define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT) 41cdff2642SJohn Johansen 42cdff2642SJohn Johansen /** 43cdff2642SJohn Johansen * d_namespace_path - lookup a name associated with a given path 44cdff2642SJohn Johansen * @path: path to lookup (NOT NULL) 45cdff2642SJohn Johansen * @buf: buffer to store path to (NOT NULL) 46cdff2642SJohn Johansen * @buflen: length of @buf 47cdff2642SJohn Johansen * @name: Returns - pointer for start of path name with in @buf (NOT NULL) 48cdff2642SJohn Johansen * @flags: flags controlling path lookup 49cdff2642SJohn Johansen * 50cdff2642SJohn Johansen * Handle path name lookup. 51cdff2642SJohn Johansen * 52cdff2642SJohn Johansen * Returns: %0 else error code if path lookup fails 53cdff2642SJohn Johansen * When no error the path name is returned in @name which points to 54cdff2642SJohn Johansen * to a position in @buf 55cdff2642SJohn Johansen */ 56cdff2642SJohn Johansen static int d_namespace_path(struct path *path, char *buf, int buflen, 57cdff2642SJohn Johansen char **name, int flags) 58cdff2642SJohn Johansen { 59cdff2642SJohn Johansen char *res; 6002125a82SAl Viro int error = 0; 6102125a82SAl Viro int connected = 1; 62cdff2642SJohn Johansen 6302125a82SAl Viro if (path->mnt->mnt_flags & MNT_INTERNAL) { 6402125a82SAl Viro /* it's not mounted anywhere */ 6502125a82SAl Viro res = dentry_path(path->dentry, buf, buflen); 6602125a82SAl Viro *name = res; 6702125a82SAl Viro if (IS_ERR(res)) { 6802125a82SAl Viro *name = buf; 6902125a82SAl Viro return PTR_ERR(res); 7002125a82SAl Viro } 7102125a82SAl Viro if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC && 7202125a82SAl Viro strncmp(*name, "/sys/", 5) == 0) { 7302125a82SAl Viro /* TODO: convert over to using a per namespace 7402125a82SAl Viro * control instead of hard coded /proc 7502125a82SAl Viro */ 7602125a82SAl Viro return prepend(name, *name - buf, "/proc", 5); 7702125a82SAl Viro } 7802125a82SAl Viro return 0; 79cdff2642SJohn Johansen } 80cdff2642SJohn Johansen 8102125a82SAl Viro /* resolve paths relative to chroot?*/ 8202125a82SAl Viro if (flags & PATH_CHROOT_REL) { 8302125a82SAl Viro struct path root; 8402125a82SAl Viro get_fs_root(current->fs, &root); 8502125a82SAl Viro res = __d_path(path, &root, buf, buflen); 8602125a82SAl Viro if (res && !IS_ERR(res)) { 8702125a82SAl Viro /* everything's fine */ 8802125a82SAl Viro *name = res; 8902125a82SAl Viro path_put(&root); 9002125a82SAl Viro goto ok; 9102125a82SAl Viro } 9202125a82SAl Viro path_put(&root); 9302125a82SAl Viro connected = 0; 9428042fabSJohn Johansen } else 9502125a82SAl Viro res = d_absolute_path(path, buf, buflen); 96cdff2642SJohn Johansen 97cdff2642SJohn Johansen *name = res; 98cdff2642SJohn Johansen /* handle error conditions - and still allow a partial path to 99cdff2642SJohn Johansen * be returned. 100cdff2642SJohn Johansen */ 101cdff2642SJohn Johansen if (IS_ERR(res)) { 102cdff2642SJohn Johansen error = PTR_ERR(res); 103cdff2642SJohn Johansen *name = buf; 104cdff2642SJohn Johansen goto out; 105cdff2642SJohn Johansen } 10602125a82SAl Viro if (!our_mnt(path->mnt)) 10702125a82SAl Viro connected = 0; 108cdff2642SJohn Johansen 10902125a82SAl Viro ok: 110e819ff51SJohn Johansen /* Handle two cases: 111e819ff51SJohn Johansen * 1. A deleted dentry && profile is not allowing mediation of deleted 112e819ff51SJohn Johansen * 2. On some filesystems, newly allocated dentries appear to the 113e819ff51SJohn Johansen * security_path hooks as a deleted dentry except without an inode 114e819ff51SJohn Johansen * allocated. 115e819ff51SJohn Johansen */ 116e819ff51SJohn Johansen if (d_unlinked(path->dentry) && path->dentry->d_inode && 117e819ff51SJohn Johansen !(flags & PATH_MEDIATE_DELETED)) { 118cdff2642SJohn Johansen error = -ENOENT; 119cdff2642SJohn Johansen goto out; 120cdff2642SJohn Johansen } 121cdff2642SJohn Johansen 12202125a82SAl Viro /* If the path is not connected to the expected root, 123cdff2642SJohn Johansen * check if it is a sysctl and handle specially else remove any 124cdff2642SJohn Johansen * leading / that __d_path may have returned. 125cdff2642SJohn Johansen * Unless 126cdff2642SJohn Johansen * specifically directed to connect the path, 127cdff2642SJohn Johansen * OR 128cdff2642SJohn Johansen * if in a chroot and doing chroot relative paths and the path 129cdff2642SJohn Johansen * resolves to the namespace root (would be connected outside 130cdff2642SJohn Johansen * of chroot) and specifically directed to connect paths to 131cdff2642SJohn Johansen * namespace root. 132cdff2642SJohn Johansen */ 133cdff2642SJohn Johansen if (!connected) { 13402125a82SAl Viro if (!(flags & PATH_CONNECT_PATH) && 135cdff2642SJohn Johansen !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) && 13602125a82SAl Viro our_mnt(path->mnt))) { 137cdff2642SJohn Johansen /* disconnected path, don't return pathname starting 138cdff2642SJohn Johansen * with '/' 139cdff2642SJohn Johansen */ 140*ef9a7622SJohn Johansen error = -EACCES; 141cdff2642SJohn Johansen if (*res == '/') 142cdff2642SJohn Johansen *name = res + 1; 143cdff2642SJohn Johansen } 144cdff2642SJohn Johansen } 145cdff2642SJohn Johansen 146cdff2642SJohn Johansen out: 147cdff2642SJohn Johansen return error; 148cdff2642SJohn Johansen } 149cdff2642SJohn Johansen 150cdff2642SJohn Johansen /** 151cdff2642SJohn Johansen * get_name_to_buffer - get the pathname to a buffer ensure dir / is appended 152cdff2642SJohn Johansen * @path: path to get name for (NOT NULL) 153cdff2642SJohn Johansen * @flags: flags controlling path lookup 154cdff2642SJohn Johansen * @buffer: buffer to put name in (NOT NULL) 155cdff2642SJohn Johansen * @size: size of buffer 156cdff2642SJohn Johansen * @name: Returns - contains position of path name in @buffer (NOT NULL) 157cdff2642SJohn Johansen * 158cdff2642SJohn Johansen * Returns: %0 else error on failure 159cdff2642SJohn Johansen */ 160cdff2642SJohn Johansen static int get_name_to_buffer(struct path *path, int flags, char *buffer, 161cdff2642SJohn Johansen int size, char **name) 162cdff2642SJohn Johansen { 163cdff2642SJohn Johansen int adjust = (flags & PATH_IS_DIR) ? 1 : 0; 164cdff2642SJohn Johansen int error = d_namespace_path(path, buffer, size - adjust, name, flags); 165cdff2642SJohn Johansen 166cdff2642SJohn Johansen if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0') 167cdff2642SJohn Johansen /* 168cdff2642SJohn Johansen * Append "/" to the pathname. The root directory is a special 169cdff2642SJohn Johansen * case; it already ends in slash. 170cdff2642SJohn Johansen */ 171cdff2642SJohn Johansen strcpy(&buffer[size - 2], "/"); 172cdff2642SJohn Johansen 173cdff2642SJohn Johansen return error; 174cdff2642SJohn Johansen } 175cdff2642SJohn Johansen 176cdff2642SJohn Johansen /** 177cdff2642SJohn Johansen * aa_get_name - compute the pathname of a file 178cdff2642SJohn Johansen * @path: path the file (NOT NULL) 179cdff2642SJohn Johansen * @flags: flags controlling path name generation 180cdff2642SJohn Johansen * @buffer: buffer that aa_get_name() allocated (NOT NULL) 181cdff2642SJohn Johansen * @name: Returns - the generated path name if !error (NOT NULL) 182cdff2642SJohn Johansen * 183cdff2642SJohn Johansen * @name is a pointer to the beginning of the pathname (which usually differs 184cdff2642SJohn Johansen * from the beginning of the buffer), or NULL. If there is an error @name 185cdff2642SJohn Johansen * may contain a partial or invalid name that can be used for audit purposes, 186cdff2642SJohn Johansen * but it can not be used for mediation. 187cdff2642SJohn Johansen * 188cdff2642SJohn Johansen * We need PATH_IS_DIR to indicate whether the file is a directory or not 189cdff2642SJohn Johansen * because the file may not yet exist, and so we cannot check the inode's 190cdff2642SJohn Johansen * file type. 191cdff2642SJohn Johansen * 192cdff2642SJohn Johansen * Returns: %0 else error code if could retrieve name 193cdff2642SJohn Johansen */ 194cdff2642SJohn Johansen int aa_get_name(struct path *path, int flags, char **buffer, const char **name) 195cdff2642SJohn Johansen { 196cdff2642SJohn Johansen char *buf, *str = NULL; 197cdff2642SJohn Johansen int size = 256; 198cdff2642SJohn Johansen int error; 199cdff2642SJohn Johansen 200cdff2642SJohn Johansen *name = NULL; 201cdff2642SJohn Johansen *buffer = NULL; 202cdff2642SJohn Johansen for (;;) { 203cdff2642SJohn Johansen /* freed by caller */ 204cdff2642SJohn Johansen buf = kmalloc(size, GFP_KERNEL); 205cdff2642SJohn Johansen if (!buf) 206cdff2642SJohn Johansen return -ENOMEM; 207cdff2642SJohn Johansen 208cdff2642SJohn Johansen error = get_name_to_buffer(path, flags, buf, size, &str); 209cdff2642SJohn Johansen if (error != -ENAMETOOLONG) 210cdff2642SJohn Johansen break; 211cdff2642SJohn Johansen 212cdff2642SJohn Johansen kfree(buf); 213cdff2642SJohn Johansen size <<= 1; 214cdff2642SJohn Johansen if (size > aa_g_path_max) 215cdff2642SJohn Johansen return -ENAMETOOLONG; 216cdff2642SJohn Johansen } 217cdff2642SJohn Johansen *buffer = buf; 218cdff2642SJohn Johansen *name = str; 219cdff2642SJohn Johansen 220cdff2642SJohn Johansen return error; 221cdff2642SJohn Johansen } 222