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

mount.c (18732B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AppArmor security module
      4 *
      5 * This file contains AppArmor mediation of files
      6 *
      7 * Copyright (C) 1998-2008 Novell/SUSE
      8 * Copyright 2009-2017 Canonical Ltd.
      9 */
     10
     11#include <linux/fs.h>
     12#include <linux/mount.h>
     13#include <linux/namei.h>
     14#include <uapi/linux/mount.h>
     15
     16#include "include/apparmor.h"
     17#include "include/audit.h"
     18#include "include/cred.h"
     19#include "include/domain.h"
     20#include "include/file.h"
     21#include "include/match.h"
     22#include "include/mount.h"
     23#include "include/path.h"
     24#include "include/policy.h"
     25
     26
     27static void audit_mnt_flags(struct audit_buffer *ab, unsigned long flags)
     28{
     29	if (flags & MS_RDONLY)
     30		audit_log_format(ab, "ro");
     31	else
     32		audit_log_format(ab, "rw");
     33	if (flags & MS_NOSUID)
     34		audit_log_format(ab, ", nosuid");
     35	if (flags & MS_NODEV)
     36		audit_log_format(ab, ", nodev");
     37	if (flags & MS_NOEXEC)
     38		audit_log_format(ab, ", noexec");
     39	if (flags & MS_SYNCHRONOUS)
     40		audit_log_format(ab, ", sync");
     41	if (flags & MS_REMOUNT)
     42		audit_log_format(ab, ", remount");
     43	if (flags & MS_MANDLOCK)
     44		audit_log_format(ab, ", mand");
     45	if (flags & MS_DIRSYNC)
     46		audit_log_format(ab, ", dirsync");
     47	if (flags & MS_NOATIME)
     48		audit_log_format(ab, ", noatime");
     49	if (flags & MS_NODIRATIME)
     50		audit_log_format(ab, ", nodiratime");
     51	if (flags & MS_BIND)
     52		audit_log_format(ab, flags & MS_REC ? ", rbind" : ", bind");
     53	if (flags & MS_MOVE)
     54		audit_log_format(ab, ", move");
     55	if (flags & MS_SILENT)
     56		audit_log_format(ab, ", silent");
     57	if (flags & MS_POSIXACL)
     58		audit_log_format(ab, ", acl");
     59	if (flags & MS_UNBINDABLE)
     60		audit_log_format(ab, flags & MS_REC ? ", runbindable" :
     61				 ", unbindable");
     62	if (flags & MS_PRIVATE)
     63		audit_log_format(ab, flags & MS_REC ? ", rprivate" :
     64				 ", private");
     65	if (flags & MS_SLAVE)
     66		audit_log_format(ab, flags & MS_REC ? ", rslave" :
     67				 ", slave");
     68	if (flags & MS_SHARED)
     69		audit_log_format(ab, flags & MS_REC ? ", rshared" :
     70				 ", shared");
     71	if (flags & MS_RELATIME)
     72		audit_log_format(ab, ", relatime");
     73	if (flags & MS_I_VERSION)
     74		audit_log_format(ab, ", iversion");
     75	if (flags & MS_STRICTATIME)
     76		audit_log_format(ab, ", strictatime");
     77	if (flags & MS_NOUSER)
     78		audit_log_format(ab, ", nouser");
     79}
     80
     81/**
     82 * audit_cb - call back for mount specific audit fields
     83 * @ab: audit_buffer  (NOT NULL)
     84 * @va: audit struct to audit values of  (NOT NULL)
     85 */
     86static void audit_cb(struct audit_buffer *ab, void *va)
     87{
     88	struct common_audit_data *sa = va;
     89
     90	if (aad(sa)->mnt.type) {
     91		audit_log_format(ab, " fstype=");
     92		audit_log_untrustedstring(ab, aad(sa)->mnt.type);
     93	}
     94	if (aad(sa)->mnt.src_name) {
     95		audit_log_format(ab, " srcname=");
     96		audit_log_untrustedstring(ab, aad(sa)->mnt.src_name);
     97	}
     98	if (aad(sa)->mnt.trans) {
     99		audit_log_format(ab, " trans=");
    100		audit_log_untrustedstring(ab, aad(sa)->mnt.trans);
    101	}
    102	if (aad(sa)->mnt.flags) {
    103		audit_log_format(ab, " flags=\"");
    104		audit_mnt_flags(ab, aad(sa)->mnt.flags);
    105		audit_log_format(ab, "\"");
    106	}
    107	if (aad(sa)->mnt.data) {
    108		audit_log_format(ab, " options=");
    109		audit_log_untrustedstring(ab, aad(sa)->mnt.data);
    110	}
    111}
    112
    113/**
    114 * audit_mount - handle the auditing of mount operations
    115 * @profile: the profile being enforced  (NOT NULL)
    116 * @op: operation being mediated (NOT NULL)
    117 * @name: name of object being mediated (MAYBE NULL)
    118 * @src_name: src_name of object being mediated (MAYBE_NULL)
    119 * @type: type of filesystem (MAYBE_NULL)
    120 * @trans: name of trans (MAYBE NULL)
    121 * @flags: filesystem independent mount flags
    122 * @data: filesystem mount flags
    123 * @request: permissions requested
    124 * @perms: the permissions computed for the request (NOT NULL)
    125 * @info: extra information message (MAYBE NULL)
    126 * @error: 0 if operation allowed else failure error code
    127 *
    128 * Returns: %0 or error on failure
    129 */
    130static int audit_mount(struct aa_profile *profile, const char *op,
    131		       const char *name, const char *src_name,
    132		       const char *type, const char *trans,
    133		       unsigned long flags, const void *data, u32 request,
    134		       struct aa_perms *perms, const char *info, int error)
    135{
    136	int audit_type = AUDIT_APPARMOR_AUTO;
    137	DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, op);
    138
    139	if (likely(!error)) {
    140		u32 mask = perms->audit;
    141
    142		if (unlikely(AUDIT_MODE(profile) == AUDIT_ALL))
    143			mask = 0xffff;
    144
    145		/* mask off perms that are not being force audited */
    146		request &= mask;
    147
    148		if (likely(!request))
    149			return 0;
    150		audit_type = AUDIT_APPARMOR_AUDIT;
    151	} else {
    152		/* only report permissions that were denied */
    153		request = request & ~perms->allow;
    154
    155		if (request & perms->kill)
    156			audit_type = AUDIT_APPARMOR_KILL;
    157
    158		/* quiet known rejects, assumes quiet and kill do not overlap */
    159		if ((request & perms->quiet) &&
    160		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
    161		    AUDIT_MODE(profile) != AUDIT_ALL)
    162			request &= ~perms->quiet;
    163
    164		if (!request)
    165			return error;
    166	}
    167
    168	aad(&sa)->name = name;
    169	aad(&sa)->mnt.src_name = src_name;
    170	aad(&sa)->mnt.type = type;
    171	aad(&sa)->mnt.trans = trans;
    172	aad(&sa)->mnt.flags = flags;
    173	if (data && (perms->audit & AA_AUDIT_DATA))
    174		aad(&sa)->mnt.data = data;
    175	aad(&sa)->info = info;
    176	aad(&sa)->error = error;
    177
    178	return aa_audit(audit_type, profile, &sa, audit_cb);
    179}
    180
    181/**
    182 * match_mnt_flags - Do an ordered match on mount flags
    183 * @dfa: dfa to match against
    184 * @state: state to start in
    185 * @flags: mount flags to match against
    186 *
    187 * Mount flags are encoded as an ordered match. This is done instead of
    188 * checking against a simple bitmask, to allow for logical operations
    189 * on the flags.
    190 *
    191 * Returns: next state after flags match
    192 */
    193static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state,
    194				    unsigned long flags)
    195{
    196	unsigned int i;
    197
    198	for (i = 0; i <= 31 ; ++i) {
    199		if ((1 << i) & flags)
    200			state = aa_dfa_next(dfa, state, i + 1);
    201	}
    202
    203	return state;
    204}
    205
    206/**
    207 * compute_mnt_perms - compute mount permission associated with @state
    208 * @dfa: dfa to match against (NOT NULL)
    209 * @state: state match finished in
    210 *
    211 * Returns: mount permissions
    212 */
    213static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa,
    214					   unsigned int state)
    215{
    216	struct aa_perms perms = {
    217		.allow = dfa_user_allow(dfa, state),
    218		.audit = dfa_user_audit(dfa, state),
    219		.quiet = dfa_user_quiet(dfa, state),
    220		.xindex = dfa_user_xindex(dfa, state),
    221	};
    222
    223	return perms;
    224}
    225
    226static const char * const mnt_info_table[] = {
    227	"match succeeded",
    228	"failed mntpnt match",
    229	"failed srcname match",
    230	"failed type match",
    231	"failed flags match",
    232	"failed data match"
    233};
    234
    235/*
    236 * Returns 0 on success else element that match failed in, this is the
    237 * index into the mnt_info_table above
    238 */
    239static int do_match_mnt(struct aa_dfa *dfa, unsigned int start,
    240			const char *mntpnt, const char *devname,
    241			const char *type, unsigned long flags,
    242			void *data, bool binary, struct aa_perms *perms)
    243{
    244	unsigned int state;
    245
    246	AA_BUG(!dfa);
    247	AA_BUG(!perms);
    248
    249	state = aa_dfa_match(dfa, start, mntpnt);
    250	state = aa_dfa_null_transition(dfa, state);
    251	if (!state)
    252		return 1;
    253
    254	if (devname)
    255		state = aa_dfa_match(dfa, state, devname);
    256	state = aa_dfa_null_transition(dfa, state);
    257	if (!state)
    258		return 2;
    259
    260	if (type)
    261		state = aa_dfa_match(dfa, state, type);
    262	state = aa_dfa_null_transition(dfa, state);
    263	if (!state)
    264		return 3;
    265
    266	state = match_mnt_flags(dfa, state, flags);
    267	if (!state)
    268		return 4;
    269	*perms = compute_mnt_perms(dfa, state);
    270	if (perms->allow & AA_MAY_MOUNT)
    271		return 0;
    272
    273	/* only match data if not binary and the DFA flags data is expected */
    274	if (data && !binary && (perms->allow & AA_MNT_CONT_MATCH)) {
    275		state = aa_dfa_null_transition(dfa, state);
    276		if (!state)
    277			return 4;
    278
    279		state = aa_dfa_match(dfa, state, data);
    280		if (!state)
    281			return 5;
    282		*perms = compute_mnt_perms(dfa, state);
    283		if (perms->allow & AA_MAY_MOUNT)
    284			return 0;
    285	}
    286
    287	/* failed at end of flags match */
    288	return 4;
    289}
    290
    291
    292static int path_flags(struct aa_profile *profile, const struct path *path)
    293{
    294	AA_BUG(!profile);
    295	AA_BUG(!path);
    296
    297	return profile->path_flags |
    298		(S_ISDIR(path->dentry->d_inode->i_mode) ? PATH_IS_DIR : 0);
    299}
    300
    301/**
    302 * match_mnt_path_str - handle path matching for mount
    303 * @profile: the confining profile
    304 * @mntpath: for the mntpnt (NOT NULL)
    305 * @buffer: buffer to be used to lookup mntpath
    306 * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR)
    307 * @type: string for the dev type (MAYBE NULL)
    308 * @flags: mount flags to match
    309 * @data: fs mount data (MAYBE NULL)
    310 * @binary: whether @data is binary
    311 * @devinfo: error str if (IS_ERR(@devname))
    312 *
    313 * Returns: 0 on success else error
    314 */
    315static int match_mnt_path_str(struct aa_profile *profile,
    316			      const struct path *mntpath, char *buffer,
    317			      const char *devname, const char *type,
    318			      unsigned long flags, void *data, bool binary,
    319			      const char *devinfo)
    320{
    321	struct aa_perms perms = { };
    322	const char *mntpnt = NULL, *info = NULL;
    323	int pos, error;
    324
    325	AA_BUG(!profile);
    326	AA_BUG(!mntpath);
    327	AA_BUG(!buffer);
    328
    329	if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
    330		return 0;
    331
    332	error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer,
    333			     &mntpnt, &info, profile->disconnected);
    334	if (error)
    335		goto audit;
    336	if (IS_ERR(devname)) {
    337		error = PTR_ERR(devname);
    338		devname = NULL;
    339		info = devinfo;
    340		goto audit;
    341	}
    342
    343	error = -EACCES;
    344	pos = do_match_mnt(profile->policy.dfa,
    345			   profile->policy.start[AA_CLASS_MOUNT],
    346			   mntpnt, devname, type, flags, data, binary, &perms);
    347	if (pos) {
    348		info = mnt_info_table[pos];
    349		goto audit;
    350	}
    351	error = 0;
    352
    353audit:
    354	return audit_mount(profile, OP_MOUNT, mntpnt, devname, type, NULL,
    355			   flags, data, AA_MAY_MOUNT, &perms, info, error);
    356}
    357
    358/**
    359 * match_mnt - handle path matching for mount
    360 * @profile: the confining profile
    361 * @mntpath: for the mntpnt (NOT NULL)
    362 * @buffer: buffer to be used to lookup mntpath
    363 * @devpath: path devname/src_name (MAYBE NULL)
    364 * @devbuffer: buffer to be used to lookup devname/src_name
    365 * @type: string for the dev type (MAYBE NULL)
    366 * @flags: mount flags to match
    367 * @data: fs mount data (MAYBE NULL)
    368 * @binary: whether @data is binary
    369 *
    370 * Returns: 0 on success else error
    371 */
    372static int match_mnt(struct aa_profile *profile, const struct path *path,
    373		     char *buffer, const struct path *devpath, char *devbuffer,
    374		     const char *type, unsigned long flags, void *data,
    375		     bool binary)
    376{
    377	const char *devname = NULL, *info = NULL;
    378	int error = -EACCES;
    379
    380	AA_BUG(!profile);
    381	AA_BUG(devpath && !devbuffer);
    382
    383	if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
    384		return 0;
    385
    386	if (devpath) {
    387		error = aa_path_name(devpath, path_flags(profile, devpath),
    388				     devbuffer, &devname, &info,
    389				     profile->disconnected);
    390		if (error)
    391			devname = ERR_PTR(error);
    392	}
    393
    394	return match_mnt_path_str(profile, path, buffer, devname, type, flags,
    395				  data, binary, info);
    396}
    397
    398int aa_remount(struct aa_label *label, const struct path *path,
    399	       unsigned long flags, void *data)
    400{
    401	struct aa_profile *profile;
    402	char *buffer = NULL;
    403	bool binary;
    404	int error;
    405
    406	AA_BUG(!label);
    407	AA_BUG(!path);
    408
    409	binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA;
    410
    411	buffer = aa_get_buffer(false);
    412	if (!buffer)
    413		return -ENOMEM;
    414	error = fn_for_each_confined(label, profile,
    415			match_mnt(profile, path, buffer, NULL, NULL, NULL,
    416				  flags, data, binary));
    417	aa_put_buffer(buffer);
    418
    419	return error;
    420}
    421
    422int aa_bind_mount(struct aa_label *label, const struct path *path,
    423		  const char *dev_name, unsigned long flags)
    424{
    425	struct aa_profile *profile;
    426	char *buffer = NULL, *old_buffer = NULL;
    427	struct path old_path;
    428	int error;
    429
    430	AA_BUG(!label);
    431	AA_BUG(!path);
    432
    433	if (!dev_name || !*dev_name)
    434		return -EINVAL;
    435
    436	flags &= MS_REC | MS_BIND;
    437
    438	error = kern_path(dev_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path);
    439	if (error)
    440		return error;
    441
    442	buffer = aa_get_buffer(false);
    443	old_buffer = aa_get_buffer(false);
    444	error = -ENOMEM;
    445	if (!buffer || !old_buffer)
    446		goto out;
    447
    448	error = fn_for_each_confined(label, profile,
    449			match_mnt(profile, path, buffer, &old_path, old_buffer,
    450				  NULL, flags, NULL, false));
    451out:
    452	aa_put_buffer(buffer);
    453	aa_put_buffer(old_buffer);
    454	path_put(&old_path);
    455
    456	return error;
    457}
    458
    459int aa_mount_change_type(struct aa_label *label, const struct path *path,
    460			 unsigned long flags)
    461{
    462	struct aa_profile *profile;
    463	char *buffer = NULL;
    464	int error;
    465
    466	AA_BUG(!label);
    467	AA_BUG(!path);
    468
    469	/* These are the flags allowed by do_change_type() */
    470	flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE |
    471		  MS_UNBINDABLE);
    472
    473	buffer = aa_get_buffer(false);
    474	if (!buffer)
    475		return -ENOMEM;
    476	error = fn_for_each_confined(label, profile,
    477			match_mnt(profile, path, buffer, NULL, NULL, NULL,
    478				  flags, NULL, false));
    479	aa_put_buffer(buffer);
    480
    481	return error;
    482}
    483
    484int aa_move_mount(struct aa_label *label, const struct path *path,
    485		  const char *orig_name)
    486{
    487	struct aa_profile *profile;
    488	char *buffer = NULL, *old_buffer = NULL;
    489	struct path old_path;
    490	int error;
    491
    492	AA_BUG(!label);
    493	AA_BUG(!path);
    494
    495	if (!orig_name || !*orig_name)
    496		return -EINVAL;
    497
    498	error = kern_path(orig_name, LOOKUP_FOLLOW, &old_path);
    499	if (error)
    500		return error;
    501
    502	buffer = aa_get_buffer(false);
    503	old_buffer = aa_get_buffer(false);
    504	error = -ENOMEM;
    505	if (!buffer || !old_buffer)
    506		goto out;
    507	error = fn_for_each_confined(label, profile,
    508			match_mnt(profile, path, buffer, &old_path, old_buffer,
    509				  NULL, MS_MOVE, NULL, false));
    510out:
    511	aa_put_buffer(buffer);
    512	aa_put_buffer(old_buffer);
    513	path_put(&old_path);
    514
    515	return error;
    516}
    517
    518int aa_new_mount(struct aa_label *label, const char *dev_name,
    519		 const struct path *path, const char *type, unsigned long flags,
    520		 void *data)
    521{
    522	struct aa_profile *profile;
    523	char *buffer = NULL, *dev_buffer = NULL;
    524	bool binary = true;
    525	int error;
    526	int requires_dev = 0;
    527	struct path tmp_path, *dev_path = NULL;
    528
    529	AA_BUG(!label);
    530	AA_BUG(!path);
    531
    532	if (type) {
    533		struct file_system_type *fstype;
    534
    535		fstype = get_fs_type(type);
    536		if (!fstype)
    537			return -ENODEV;
    538		binary = fstype->fs_flags & FS_BINARY_MOUNTDATA;
    539		requires_dev = fstype->fs_flags & FS_REQUIRES_DEV;
    540		put_filesystem(fstype);
    541
    542		if (requires_dev) {
    543			if (!dev_name || !*dev_name)
    544				return -ENOENT;
    545
    546			error = kern_path(dev_name, LOOKUP_FOLLOW, &tmp_path);
    547			if (error)
    548				return error;
    549			dev_path = &tmp_path;
    550		}
    551	}
    552
    553	buffer = aa_get_buffer(false);
    554	if (!buffer) {
    555		error = -ENOMEM;
    556		goto out;
    557	}
    558	if (dev_path) {
    559		dev_buffer = aa_get_buffer(false);
    560		if (!dev_buffer) {
    561			error = -ENOMEM;
    562			goto out;
    563		}
    564		error = fn_for_each_confined(label, profile,
    565			match_mnt(profile, path, buffer, dev_path, dev_buffer,
    566				  type, flags, data, binary));
    567	} else {
    568		error = fn_for_each_confined(label, profile,
    569			match_mnt_path_str(profile, path, buffer, dev_name,
    570					   type, flags, data, binary, NULL));
    571	}
    572
    573out:
    574	aa_put_buffer(buffer);
    575	aa_put_buffer(dev_buffer);
    576	if (dev_path)
    577		path_put(dev_path);
    578
    579	return error;
    580}
    581
    582static int profile_umount(struct aa_profile *profile, const struct path *path,
    583			  char *buffer)
    584{
    585	struct aa_perms perms = { };
    586	const char *name = NULL, *info = NULL;
    587	unsigned int state;
    588	int error;
    589
    590	AA_BUG(!profile);
    591	AA_BUG(!path);
    592
    593	if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
    594		return 0;
    595
    596	error = aa_path_name(path, path_flags(profile, path), buffer, &name,
    597			     &info, profile->disconnected);
    598	if (error)
    599		goto audit;
    600
    601	state = aa_dfa_match(profile->policy.dfa,
    602			     profile->policy.start[AA_CLASS_MOUNT],
    603			     name);
    604	perms = compute_mnt_perms(profile->policy.dfa, state);
    605	if (AA_MAY_UMOUNT & ~perms.allow)
    606		error = -EACCES;
    607
    608audit:
    609	return audit_mount(profile, OP_UMOUNT, name, NULL, NULL, NULL, 0, NULL,
    610			   AA_MAY_UMOUNT, &perms, info, error);
    611}
    612
    613int aa_umount(struct aa_label *label, struct vfsmount *mnt, int flags)
    614{
    615	struct aa_profile *profile;
    616	char *buffer = NULL;
    617	int error;
    618	struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
    619
    620	AA_BUG(!label);
    621	AA_BUG(!mnt);
    622
    623	buffer = aa_get_buffer(false);
    624	if (!buffer)
    625		return -ENOMEM;
    626
    627	error = fn_for_each_confined(label, profile,
    628			profile_umount(profile, &path, buffer));
    629	aa_put_buffer(buffer);
    630
    631	return error;
    632}
    633
    634/* helper fn for transition on pivotroot
    635 *
    636 * Returns: label for transition or ERR_PTR. Does not return NULL
    637 */
    638static struct aa_label *build_pivotroot(struct aa_profile *profile,
    639					const struct path *new_path,
    640					char *new_buffer,
    641					const struct path *old_path,
    642					char *old_buffer)
    643{
    644	const char *old_name, *new_name = NULL, *info = NULL;
    645	const char *trans_name = NULL;
    646	struct aa_perms perms = { };
    647	unsigned int state;
    648	int error;
    649
    650	AA_BUG(!profile);
    651	AA_BUG(!new_path);
    652	AA_BUG(!old_path);
    653
    654	if (profile_unconfined(profile) ||
    655	    !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT))
    656		return aa_get_newest_label(&profile->label);
    657
    658	error = aa_path_name(old_path, path_flags(profile, old_path),
    659			     old_buffer, &old_name, &info,
    660			     profile->disconnected);
    661	if (error)
    662		goto audit;
    663	error = aa_path_name(new_path, path_flags(profile, new_path),
    664			     new_buffer, &new_name, &info,
    665			     profile->disconnected);
    666	if (error)
    667		goto audit;
    668
    669	error = -EACCES;
    670	state = aa_dfa_match(profile->policy.dfa,
    671			     profile->policy.start[AA_CLASS_MOUNT],
    672			     new_name);
    673	state = aa_dfa_null_transition(profile->policy.dfa, state);
    674	state = aa_dfa_match(profile->policy.dfa, state, old_name);
    675	perms = compute_mnt_perms(profile->policy.dfa, state);
    676
    677	if (AA_MAY_PIVOTROOT & perms.allow)
    678		error = 0;
    679
    680audit:
    681	error = audit_mount(profile, OP_PIVOTROOT, new_name, old_name,
    682			    NULL, trans_name, 0, NULL, AA_MAY_PIVOTROOT,
    683			    &perms, info, error);
    684	if (error)
    685		return ERR_PTR(error);
    686
    687	return aa_get_newest_label(&profile->label);
    688}
    689
    690int aa_pivotroot(struct aa_label *label, const struct path *old_path,
    691		 const struct path *new_path)
    692{
    693	struct aa_profile *profile;
    694	struct aa_label *target = NULL;
    695	char *old_buffer = NULL, *new_buffer = NULL, *info = NULL;
    696	int error;
    697
    698	AA_BUG(!label);
    699	AA_BUG(!old_path);
    700	AA_BUG(!new_path);
    701
    702	old_buffer = aa_get_buffer(false);
    703	new_buffer = aa_get_buffer(false);
    704	error = -ENOMEM;
    705	if (!old_buffer || !new_buffer)
    706		goto out;
    707	target = fn_label_build(label, profile, GFP_KERNEL,
    708			build_pivotroot(profile, new_path, new_buffer,
    709					old_path, old_buffer));
    710	if (!target) {
    711		info = "label build failed";
    712		error = -ENOMEM;
    713		goto fail;
    714	} else if (!IS_ERR(target)) {
    715		error = aa_replace_current_label(target);
    716		if (error) {
    717			/* TODO: audit target */
    718			aa_put_label(target);
    719			goto out;
    720		}
    721	} else
    722		/* already audited error */
    723		error = PTR_ERR(target);
    724out:
    725	aa_put_buffer(old_buffer);
    726	aa_put_buffer(new_buffer);
    727
    728	return error;
    729
    730fail:
    731	/* TODO: add back in auditing of new_name and old_name */
    732	error = fn_for_each(label, profile,
    733			audit_mount(profile, OP_PIVOTROOT, NULL /*new_name */,
    734				    NULL /* old_name */,
    735				    NULL, NULL,
    736				    0, NULL, AA_MAY_PIVOTROOT, &nullperms, info,
    737				    error));
    738	goto out;
    739}