cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

path.c (6177B)


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