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