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

getroot.c (4515B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* getroot.c: get the root dentry for an NFS mount
      3 *
      4 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/init.h>
     10
     11#include <linux/time.h>
     12#include <linux/kernel.h>
     13#include <linux/mm.h>
     14#include <linux/string.h>
     15#include <linux/stat.h>
     16#include <linux/errno.h>
     17#include <linux/unistd.h>
     18#include <linux/sunrpc/clnt.h>
     19#include <linux/sunrpc/stats.h>
     20#include <linux/nfs_fs.h>
     21#include <linux/nfs_mount.h>
     22#include <linux/lockd/bind.h>
     23#include <linux/seq_file.h>
     24#include <linux/mount.h>
     25#include <linux/vfs.h>
     26#include <linux/namei.h>
     27#include <linux/security.h>
     28
     29#include <linux/uaccess.h>
     30
     31#include "internal.h"
     32
     33#define NFSDBG_FACILITY		NFSDBG_CLIENT
     34
     35/*
     36 * Set the superblock root dentry.
     37 * Note that this function frees the inode in case of error.
     38 */
     39static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode)
     40{
     41	/* The mntroot acts as the dummy root dentry for this superblock */
     42	if (sb->s_root == NULL) {
     43		sb->s_root = d_make_root(inode);
     44		if (sb->s_root == NULL)
     45			return -ENOMEM;
     46		ihold(inode);
     47		/*
     48		 * Ensure that this dentry is invisible to d_find_alias().
     49		 * Otherwise, it may be spliced into the tree by
     50		 * d_splice_alias if a parent directory from the same
     51		 * filesystem gets mounted at a later time.
     52		 * This again causes shrink_dcache_for_umount_subtree() to
     53		 * Oops, since the test for IS_ROOT() will fail.
     54		 */
     55		spin_lock(&d_inode(sb->s_root)->i_lock);
     56		spin_lock(&sb->s_root->d_lock);
     57		hlist_del_init(&sb->s_root->d_u.d_alias);
     58		spin_unlock(&sb->s_root->d_lock);
     59		spin_unlock(&d_inode(sb->s_root)->i_lock);
     60	}
     61	return 0;
     62}
     63
     64/*
     65 * get an NFS2/NFS3 root dentry from the root filehandle
     66 */
     67int nfs_get_root(struct super_block *s, struct fs_context *fc)
     68{
     69	struct nfs_fs_context *ctx = nfs_fc2context(fc);
     70	struct nfs_server *server = NFS_SB(s), *clone_server;
     71	struct nfs_fsinfo fsinfo;
     72	struct dentry *root;
     73	struct inode *inode;
     74	char *name;
     75	int error = -ENOMEM;
     76	unsigned long kflags = 0, kflags_out = 0;
     77
     78	name = kstrdup(fc->source, GFP_KERNEL);
     79	if (!name)
     80		goto out;
     81
     82	/* get the actual root for this mount */
     83	fsinfo.fattr = nfs_alloc_fattr_with_label(server);
     84	if (fsinfo.fattr == NULL)
     85		goto out_name;
     86
     87	error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
     88	if (error < 0) {
     89		dprintk("nfs_get_root: getattr error = %d\n", -error);
     90		nfs_errorf(fc, "NFS: Couldn't getattr on root");
     91		goto out_fattr;
     92	}
     93
     94	inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr);
     95	if (IS_ERR(inode)) {
     96		dprintk("nfs_get_root: get root inode failed\n");
     97		error = PTR_ERR(inode);
     98		nfs_errorf(fc, "NFS: Couldn't get root inode");
     99		goto out_fattr;
    100	}
    101
    102	error = nfs_superblock_set_dummy_root(s, inode);
    103	if (error != 0)
    104		goto out_fattr;
    105
    106	/* root dentries normally start off anonymous and get spliced in later
    107	 * if the dentry tree reaches them; however if the dentry already
    108	 * exists, we'll pick it up at this point and use it as the root
    109	 */
    110	root = d_obtain_root(inode);
    111	if (IS_ERR(root)) {
    112		dprintk("nfs_get_root: get root dentry failed\n");
    113		error = PTR_ERR(root);
    114		nfs_errorf(fc, "NFS: Couldn't get root dentry");
    115		goto out_fattr;
    116	}
    117
    118	security_d_instantiate(root, inode);
    119	spin_lock(&root->d_lock);
    120	if (IS_ROOT(root) && !root->d_fsdata &&
    121	    !(root->d_flags & DCACHE_NFSFS_RENAMED)) {
    122		root->d_fsdata = name;
    123		name = NULL;
    124	}
    125	spin_unlock(&root->d_lock);
    126	fc->root = root;
    127	if (server->caps & NFS_CAP_SECURITY_LABEL)
    128		kflags |= SECURITY_LSM_NATIVE_LABELS;
    129	if (ctx->clone_data.sb) {
    130		if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
    131			error = -ESTALE;
    132			goto error_splat_root;
    133		}
    134		/* clone lsm security options from the parent to the new sb */
    135		error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
    136						   s, kflags, &kflags_out);
    137		if (error)
    138			goto error_splat_root;
    139		clone_server = NFS_SB(ctx->clone_data.sb);
    140		server->has_sec_mnt_opts = clone_server->has_sec_mnt_opts;
    141	} else {
    142		error = security_sb_set_mnt_opts(s, fc->security,
    143							kflags, &kflags_out);
    144	}
    145	if (error)
    146		goto error_splat_root;
    147	if (server->caps & NFS_CAP_SECURITY_LABEL &&
    148		!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
    149		server->caps &= ~NFS_CAP_SECURITY_LABEL;
    150
    151	nfs_setsecurity(inode, fsinfo.fattr);
    152	error = 0;
    153
    154out_fattr:
    155	nfs_free_fattr(fsinfo.fattr);
    156out_name:
    157	kfree(name);
    158out:
    159	return error;
    160error_splat_root:
    161	dput(fc->root);
    162	fc->root = NULL;
    163	goto out_fattr;
    164}