/*1* AppArmor security module2*3* This file contains AppArmor function for pathnames4*5* Copyright (C) 1998-2008 Novell/SUSE6* Copyright 2009-2010 Canonical Ltd.7*8* This program is free software; you can redistribute it and/or9* modify it under the terms of the GNU General Public License as10* published by the Free Software Foundation, version 2 of the11* License.12*/1314#include <linux/magic.h>15#include <linux/mnt_namespace.h>16#include <linux/mount.h>17#include <linux/namei.h>18#include <linux/nsproxy.h>19#include <linux/path.h>20#include <linux/sched.h>21#include <linux/slab.h>22#include <linux/fs_struct.h>2324#include "include/apparmor.h"25#include "include/path.h"26#include "include/policy.h"272829/* modified from dcache.c */30static int prepend(char **buffer, int buflen, const char *str, int namelen)31{32buflen -= namelen;33if (buflen < 0)34return -ENAMETOOLONG;35*buffer -= namelen;36memcpy(*buffer, str, namelen);37return 0;38}3940#define CHROOT_NSCONNECT (PATH_CHROOT_REL | PATH_CHROOT_NSCONNECT)4142/**43* d_namespace_path - lookup a name associated with a given path44* @path: path to lookup (NOT NULL)45* @buf: buffer to store path to (NOT NULL)46* @buflen: length of @buf47* @name: Returns - pointer for start of path name with in @buf (NOT NULL)48* @flags: flags controlling path lookup49*50* Handle path name lookup.51*52* Returns: %0 else error code if path lookup fails53* When no error the path name is returned in @name which points to54* to a position in @buf55*/56static int d_namespace_path(struct path *path, char *buf, int buflen,57char **name, int flags)58{59struct path root, tmp;60char *res;61int connected, error = 0;6263/* Get the root we want to resolve too, released below */64if (flags & PATH_CHROOT_REL) {65/* resolve paths relative to chroot */66get_fs_root(current->fs, &root);67} else {68/* resolve paths relative to namespace */69root.mnt = current->nsproxy->mnt_ns->root;70root.dentry = root.mnt->mnt_root;71path_get(&root);72}7374tmp = root;75res = __d_path(path, &tmp, buf, buflen);7677*name = res;78/* handle error conditions - and still allow a partial path to79* be returned.80*/81if (IS_ERR(res)) {82error = PTR_ERR(res);83*name = buf;84goto out;85}8687/* Handle two cases:88* 1. A deleted dentry && profile is not allowing mediation of deleted89* 2. On some filesystems, newly allocated dentries appear to the90* security_path hooks as a deleted dentry except without an inode91* allocated.92*/93if (d_unlinked(path->dentry) && path->dentry->d_inode &&94!(flags & PATH_MEDIATE_DELETED)) {95error = -ENOENT;96goto out;97}9899/* Determine if the path is connected to the expected root */100connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;101102/* If the path is not connected,103* check if it is a sysctl and handle specially else remove any104* leading / that __d_path may have returned.105* Unless106* specifically directed to connect the path,107* OR108* if in a chroot and doing chroot relative paths and the path109* resolves to the namespace root (would be connected outside110* of chroot) and specifically directed to connect paths to111* namespace root.112*/113if (!connected) {114/* is the disconnect path a sysctl? */115if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&116strncmp(*name, "/sys/", 5) == 0) {117/* TODO: convert over to using a per namespace118* control instead of hard coded /proc119*/120error = prepend(name, *name - buf, "/proc", 5);121} else if (!(flags & PATH_CONNECT_PATH) &&122!(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&123(tmp.mnt == current->nsproxy->mnt_ns->root &&124tmp.dentry == tmp.mnt->mnt_root))) {125/* disconnected path, don't return pathname starting126* with '/'127*/128error = -ESTALE;129if (*res == '/')130*name = res + 1;131}132}133134out:135path_put(&root);136137return error;138}139140/**141* get_name_to_buffer - get the pathname to a buffer ensure dir / is appended142* @path: path to get name for (NOT NULL)143* @flags: flags controlling path lookup144* @buffer: buffer to put name in (NOT NULL)145* @size: size of buffer146* @name: Returns - contains position of path name in @buffer (NOT NULL)147*148* Returns: %0 else error on failure149*/150static int get_name_to_buffer(struct path *path, int flags, char *buffer,151int size, char **name)152{153int adjust = (flags & PATH_IS_DIR) ? 1 : 0;154int error = d_namespace_path(path, buffer, size - adjust, name, flags);155156if (!error && (flags & PATH_IS_DIR) && (*name)[1] != '\0')157/*158* Append "/" to the pathname. The root directory is a special159* case; it already ends in slash.160*/161strcpy(&buffer[size - 2], "/");162163return error;164}165166/**167* aa_get_name - compute the pathname of a file168* @path: path the file (NOT NULL)169* @flags: flags controlling path name generation170* @buffer: buffer that aa_get_name() allocated (NOT NULL)171* @name: Returns - the generated path name if !error (NOT NULL)172*173* @name is a pointer to the beginning of the pathname (which usually differs174* from the beginning of the buffer), or NULL. If there is an error @name175* may contain a partial or invalid name that can be used for audit purposes,176* but it can not be used for mediation.177*178* We need PATH_IS_DIR to indicate whether the file is a directory or not179* because the file may not yet exist, and so we cannot check the inode's180* file type.181*182* Returns: %0 else error code if could retrieve name183*/184int aa_get_name(struct path *path, int flags, char **buffer, const char **name)185{186char *buf, *str = NULL;187int size = 256;188int error;189190*name = NULL;191*buffer = NULL;192for (;;) {193/* freed by caller */194buf = kmalloc(size, GFP_KERNEL);195if (!buf)196return -ENOMEM;197198error = get_name_to_buffer(path, flags, buf, size, &str);199if (error != -ENAMETOOLONG)200break;201202kfree(buf);203size <<= 1;204if (size > aa_g_path_max)205return -ENAMETOOLONG;206}207*buffer = buf;208*name = str;209210return error;211}212213214