1*b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2cdff2642SJohn Johansen /* 3cdff2642SJohn Johansen * AppArmor security module 4cdff2642SJohn Johansen * 5cdff2642SJohn Johansen * This file contains AppArmor function for pathnames 6cdff2642SJohn Johansen * 7cdff2642SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 8cdff2642SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 9cdff2642SJohn Johansen */ 10cdff2642SJohn Johansen 11cdff2642SJohn Johansen #include <linux/magic.h> 12cdff2642SJohn Johansen #include <linux/mount.h> 13cdff2642SJohn Johansen #include <linux/namei.h> 14cdff2642SJohn Johansen #include <linux/nsproxy.h> 15cdff2642SJohn Johansen #include <linux/path.h> 16cdff2642SJohn Johansen #include <linux/sched.h> 17cdff2642SJohn Johansen #include <linux/slab.h> 18cdff2642SJohn Johansen #include <linux/fs_struct.h> 19cdff2642SJohn Johansen 20cdff2642SJohn Johansen #include "include/apparmor.h" 21cdff2642SJohn Johansen #include "include/path.h" 22cdff2642SJohn Johansen #include "include/policy.h" 23cdff2642SJohn Johansen 24cdff2642SJohn Johansen /* modified from dcache.c */ 25cdff2642SJohn Johansen static int prepend(char **buffer, int buflen, const char *str, int namelen) 26cdff2642SJohn Johansen { 27cdff2642SJohn Johansen buflen -= namelen; 28cdff2642SJohn Johansen if (buflen < 0) 29cdff2642SJohn Johansen return -ENAMETOOLONG; 30cdff2642SJohn Johansen *buffer -= namelen; 31cdff2642SJohn Johansen memcpy(*buffer, str, namelen); 32cdff2642SJohn Johansen return 0; 33cdff2642SJohn Johansen } 34cdff2642SJohn Johansen 35cdff2642SJohn Johansen #define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT) 36cdff2642SJohn Johansen 37bd35db8bSJohn Johansen /* If the path is not connected to the expected root, 38bd35db8bSJohn Johansen * check if it is a sysctl and handle specially else remove any 39bd35db8bSJohn Johansen * leading / that __d_path may have returned. 40bd35db8bSJohn Johansen * Unless 41bd35db8bSJohn Johansen * specifically directed to connect the path, 42bd35db8bSJohn Johansen * OR 43bd35db8bSJohn Johansen * if in a chroot and doing chroot relative paths and the path 44bd35db8bSJohn Johansen * resolves to the namespace root (would be connected outside 45bd35db8bSJohn Johansen * of chroot) and specifically directed to connect paths to 46bd35db8bSJohn Johansen * namespace root. 47bd35db8bSJohn Johansen */ 48bd35db8bSJohn Johansen static int disconnect(const struct path *path, char *buf, char **name, 4972c8a768SJohn Johansen int flags, const char *disconnected) 50bd35db8bSJohn Johansen { 51bd35db8bSJohn Johansen int error = 0; 52bd35db8bSJohn Johansen 53bd35db8bSJohn Johansen if (!(flags & PATH_CONNECT_PATH) && 54bd35db8bSJohn Johansen !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) && 55bd35db8bSJohn Johansen our_mnt(path->mnt))) { 56bd35db8bSJohn Johansen /* disconnected path, don't return pathname starting 57bd35db8bSJohn Johansen * with '/' 58bd35db8bSJohn Johansen */ 59bd35db8bSJohn Johansen error = -EACCES; 60bd35db8bSJohn Johansen if (**name == '/') 61bd35db8bSJohn Johansen *name = *name + 1; 6272c8a768SJohn Johansen } else { 6372c8a768SJohn Johansen if (**name != '/') 64bd35db8bSJohn Johansen /* CONNECT_PATH with missing root */ 65bd35db8bSJohn Johansen error = prepend(name, *name - buf, "/", 1); 6672c8a768SJohn Johansen if (!error && disconnected) 6772c8a768SJohn Johansen error = prepend(name, *name - buf, disconnected, 6872c8a768SJohn Johansen strlen(disconnected)); 6972c8a768SJohn Johansen } 70bd35db8bSJohn Johansen 71bd35db8bSJohn Johansen return error; 72bd35db8bSJohn Johansen } 73bd35db8bSJohn Johansen 74cdff2642SJohn Johansen /** 75cdff2642SJohn Johansen * d_namespace_path - lookup a name associated with a given path 76cdff2642SJohn Johansen * @path: path to lookup (NOT NULL) 77cdff2642SJohn Johansen * @buf: buffer to store path to (NOT NULL) 78cdff2642SJohn Johansen * @name: Returns - pointer for start of path name with in @buf (NOT NULL) 79cdff2642SJohn Johansen * @flags: flags controlling path lookup 8072c8a768SJohn Johansen * @disconnected: string to prefix to disconnected paths 81cdff2642SJohn Johansen * 82cdff2642SJohn Johansen * Handle path name lookup. 83cdff2642SJohn Johansen * 84cdff2642SJohn Johansen * Returns: %0 else error code if path lookup fails 85cdff2642SJohn Johansen * When no error the path name is returned in @name which points to 86cdff2642SJohn Johansen * to a position in @buf 87cdff2642SJohn Johansen */ 884227c333SJohn Johansen static int d_namespace_path(const struct path *path, char *buf, char **name, 894227c333SJohn Johansen int flags, const char *disconnected) 90cdff2642SJohn Johansen { 91cdff2642SJohn Johansen char *res; 9202125a82SAl Viro int error = 0; 9302125a82SAl Viro int connected = 1; 944227c333SJohn Johansen int isdir = (flags & PATH_IS_DIR) ? 1 : 0; 954227c333SJohn Johansen int buflen = aa_g_path_max - isdir; 96cdff2642SJohn Johansen 9702125a82SAl Viro if (path->mnt->mnt_flags & MNT_INTERNAL) { 9802125a82SAl Viro /* it's not mounted anywhere */ 9902125a82SAl Viro res = dentry_path(path->dentry, buf, buflen); 10002125a82SAl Viro *name = res; 10102125a82SAl Viro if (IS_ERR(res)) { 10202125a82SAl Viro *name = buf; 10302125a82SAl Viro return PTR_ERR(res); 10402125a82SAl Viro } 10502125a82SAl Viro if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC && 10602125a82SAl Viro strncmp(*name, "/sys/", 5) == 0) { 10702125a82SAl Viro /* TODO: convert over to using a per namespace 10802125a82SAl Viro * control instead of hard coded /proc 10902125a82SAl Viro */ 1104227c333SJohn Johansen error = prepend(name, *name - buf, "/proc", 5); 1114227c333SJohn Johansen goto out; 112bd35db8bSJohn Johansen } else 1134227c333SJohn Johansen error = disconnect(path, buf, name, flags, 11472c8a768SJohn Johansen disconnected); 1154227c333SJohn Johansen goto out; 116cdff2642SJohn Johansen } 117cdff2642SJohn Johansen 11802125a82SAl Viro /* resolve paths relative to chroot?*/ 11902125a82SAl Viro if (flags & PATH_CHROOT_REL) { 12002125a82SAl Viro struct path root; 12102125a82SAl Viro get_fs_root(current->fs, &root); 12202125a82SAl Viro res = __d_path(path, &root, buf, buflen); 12302125a82SAl Viro path_put(&root); 1243372b68aSJohn Johansen } else { 12502125a82SAl Viro res = d_absolute_path(path, buf, buflen); 1263372b68aSJohn Johansen if (!our_mnt(path->mnt)) 1273372b68aSJohn Johansen connected = 0; 1283372b68aSJohn Johansen } 129cdff2642SJohn Johansen 130cdff2642SJohn Johansen /* handle error conditions - and still allow a partial path to 131cdff2642SJohn Johansen * be returned. 132cdff2642SJohn Johansen */ 1333372b68aSJohn Johansen if (!res || IS_ERR(res)) { 1344227c333SJohn Johansen if (PTR_ERR(res) == -ENAMETOOLONG) { 1354227c333SJohn Johansen error = -ENAMETOOLONG; 1364227c333SJohn Johansen *name = buf; 1374227c333SJohn Johansen goto out; 1384227c333SJohn Johansen } 1393372b68aSJohn Johansen connected = 0; 140fbba8d89SJohn Johansen res = dentry_path_raw(path->dentry, buf, buflen); 141fbba8d89SJohn Johansen if (IS_ERR(res)) { 142cdff2642SJohn Johansen error = PTR_ERR(res); 143cdff2642SJohn Johansen *name = buf; 144cdff2642SJohn Johansen goto out; 145fbba8d89SJohn Johansen }; 146fbba8d89SJohn Johansen } else if (!our_mnt(path->mnt)) 14702125a82SAl Viro connected = 0; 148cdff2642SJohn Johansen 149fbba8d89SJohn Johansen *name = res; 150fbba8d89SJohn Johansen 1514227c333SJohn Johansen if (!connected) 1524227c333SJohn Johansen error = disconnect(path, buf, name, flags, disconnected); 1534227c333SJohn Johansen 154e819ff51SJohn Johansen /* Handle two cases: 155e819ff51SJohn Johansen * 1. A deleted dentry && profile is not allowing mediation of deleted 156e819ff51SJohn Johansen * 2. On some filesystems, newly allocated dentries appear to the 157e819ff51SJohn Johansen * security_path hooks as a deleted dentry except without an inode 158e819ff51SJohn Johansen * allocated. 159e819ff51SJohn Johansen */ 160729b8a3dSDavid Howells if (d_unlinked(path->dentry) && d_is_positive(path->dentry) && 1614227c333SJohn Johansen !(flags & (PATH_MEDIATE_DELETED | PATH_DELEGATE_DELETED))) { 162cdff2642SJohn Johansen error = -ENOENT; 163cdff2642SJohn Johansen goto out; 164cdff2642SJohn Johansen } 165cdff2642SJohn Johansen 166cdff2642SJohn Johansen out: 167cdff2642SJohn Johansen /* 168cdff2642SJohn Johansen * Append "/" to the pathname. The root directory is a special 169cdff2642SJohn Johansen * case; it already ends in slash. 170cdff2642SJohn Johansen */ 1714227c333SJohn Johansen if (!error && isdir && ((*name)[1] != '\0' || (*name)[0] != '/')) 1724227c333SJohn Johansen strcpy(&buf[aa_g_path_max - 2], "/"); 17357fa1e18SJohn Johansen 174cdff2642SJohn Johansen return error; 175cdff2642SJohn Johansen } 176cdff2642SJohn Johansen 177cdff2642SJohn Johansen /** 1784227c333SJohn Johansen * aa_path_name - get the pathname to a buffer ensure dir / is appended 179cdff2642SJohn Johansen * @path: path the file (NOT NULL) 180cdff2642SJohn Johansen * @flags: flags controlling path name generation 1814227c333SJohn Johansen * @buffer: buffer to put name in (NOT NULL) 182cdff2642SJohn Johansen * @name: Returns - the generated path name if !error (NOT NULL) 18357fa1e18SJohn Johansen * @info: Returns - information on why the path lookup failed (MAYBE NULL) 18472c8a768SJohn Johansen * @disconnected: string to prepend to disconnected paths 185cdff2642SJohn Johansen * 186cdff2642SJohn Johansen * @name is a pointer to the beginning of the pathname (which usually differs 187cdff2642SJohn Johansen * from the beginning of the buffer), or NULL. If there is an error @name 188cdff2642SJohn Johansen * may contain a partial or invalid name that can be used for audit purposes, 189cdff2642SJohn Johansen * but it can not be used for mediation. 190cdff2642SJohn Johansen * 191cdff2642SJohn Johansen * We need PATH_IS_DIR to indicate whether the file is a directory or not 192cdff2642SJohn Johansen * because the file may not yet exist, and so we cannot check the inode's 193cdff2642SJohn Johansen * file type. 194cdff2642SJohn Johansen * 195cdff2642SJohn Johansen * Returns: %0 else error code if could retrieve name 196cdff2642SJohn Johansen */ 1974227c333SJohn Johansen int aa_path_name(const struct path *path, int flags, char *buffer, 19872c8a768SJohn Johansen const char **name, const char **info, const char *disconnected) 199cdff2642SJohn Johansen { 2004227c333SJohn Johansen char *str = NULL; 2014227c333SJohn Johansen int error = d_namespace_path(path, buffer, &str, flags, disconnected); 202cdff2642SJohn Johansen 2034227c333SJohn Johansen if (info && error) { 2044227c333SJohn Johansen if (error == -ENOENT) 2054227c333SJohn Johansen *info = "Failed name lookup - deleted entry"; 2064227c333SJohn Johansen else if (error == -EACCES) 2074227c333SJohn Johansen *info = "Failed name lookup - disconnected path"; 2084227c333SJohn Johansen else if (error == -ENAMETOOLONG) 2094227c333SJohn Johansen *info = "Failed name lookup - name too long"; 2104227c333SJohn Johansen else 2114227c333SJohn Johansen *info = "Failed name lookup"; 212cdff2642SJohn Johansen } 2134227c333SJohn Johansen 214cdff2642SJohn Johansen *name = str; 215cdff2642SJohn Johansen 216cdff2642SJohn Johansen return error; 217cdff2642SJohn Johansen } 218