Commit 9fc2f990 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd updates from Chuck Lever:
 "Two significant security enhancements are part of this release:

   - NFSD's RPC header encoding and decoding, including RPCSEC GSS and
     gssproxy header parsing, has been overhauled to make it more
     memory-safe.

   - Support for Kerberos AES-SHA2-based encryption types has been added
     for both the NFS client and server. This provides a clean path for
     deprecating and removing insecure encryption types based on DES and
     SHA-1. AES-SHA2 is also FIPS-140 compliant, so that NFS with
     Kerberos may now be used on systems with fips enabled.

  In addition to these, NFSD is now able to handle crossing into an
  auto-mounted mount point on an exported NFS mount. A number of fixes
  have been made to NFSD's server-side copy implementation.

  RPC metrics have been converted to per-CPU variables. This helps
  reduce unnecessary cross-CPU and cross-node memory bus traffic, and
  significantly reduces noise when KCSAN is enabled"

* tag 'nfsd-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (121 commits)
  NFSD: Clean up nfsd_symlink()
  NFSD: copy the whole verifier in nfsd_copy_write_verifier
  nfsd: don't fsync nfsd_files on last close
  SUNRPC: Fix occasional warning when destroying gss_krb5_enctypes
  nfsd: fix courtesy client with deny mode handling in nfs4_upgrade_open
  NFSD: fix problems with cleanup on errors in nfsd4_copy
  nfsd: fix race to check ls_layouts
  nfsd: don't hand out delegation on setuid files being opened for write
  SUNRPC: Remove ->xpo_secure_port()
  SUNRPC: Clean up the svc_xprt_flags() macro
  nfsd: remove fs/nfsd/fault_inject.c
  NFSD: fix leaked reference count of nfsd4_ssc_umount_item
  nfsd: clean up potential nfsd_file refcount leaks in COPY codepath
  nfsd: zero out pointers after putting nfsd_files on COPY setup error
  SUNRPC: Fix whitespace damage in svcauth_unix.c
  nfsd: eliminate __nfs4_get_fd
  nfsd: add some kerneldoc comments for stateid preprocessing functions
  nfsd: eliminate find_deleg_file_locked
  nfsd: don't take nfsd4_copy ref for OP_OFFLOAD_STATUS
  SUNRPC: Add encryption self-tests
  ...
parents 25ac8c12 4b471a8b
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -685,17 +685,16 @@ module_exit(exit_nlm);
/**
 * nlmsvc_dispatch - Process an NLM Request
 * @rqstp: incoming request
 * @statp: pointer to location of accept_stat field in RPC Reply buffer
 *
 * Return values:
 *  %0: Processing complete; do not send a Reply
 *  %1: Processing complete; send Reply in rqstp->rq_res
 */
static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
static int nlmsvc_dispatch(struct svc_rqst *rqstp)
{
	const struct svc_procedure *procp = rqstp->rq_procinfo;
	__be32 *statp = rqstp->rq_accept_statp;

	svcxdr_init_decode(rqstp);
	if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream))
		goto out_decode_err;

@@ -705,7 +704,6 @@ static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
	if (*statp != rpc_success)
		return 1;

	svcxdr_init_encode(rqstp);
	if (!procp->pc_encode(rqstp, &rqstp->rq_res_stream))
		goto out_encode_err;

@@ -723,7 +721,7 @@ static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp)
/*
 * Define NLM program and procedures
 */
static unsigned int nlmsvc_version1_count[17];
static DEFINE_PER_CPU_ALIGNED(unsigned long, nlmsvc_version1_count[17]);
static const struct svc_version	nlmsvc_version1 = {
	.vs_vers	= 1,
	.vs_nproc	= 17,
@@ -732,26 +730,31 @@ static const struct svc_version nlmsvc_version1 = {
	.vs_dispatch	= nlmsvc_dispatch,
	.vs_xdrsize	= NLMSVC_XDRSIZE,
};
static unsigned int nlmsvc_version3_count[24];

static DEFINE_PER_CPU_ALIGNED(unsigned long,
			      nlmsvc_version3_count[ARRAY_SIZE(nlmsvc_procedures)]);
static const struct svc_version	nlmsvc_version3 = {
	.vs_vers	= 3,
	.vs_nproc	= 24,
	.vs_nproc	= ARRAY_SIZE(nlmsvc_procedures),
	.vs_proc	= nlmsvc_procedures,
	.vs_count	= nlmsvc_version3_count,
	.vs_dispatch	= nlmsvc_dispatch,
	.vs_xdrsize	= NLMSVC_XDRSIZE,
};

#ifdef CONFIG_LOCKD_V4
static unsigned int nlmsvc_version4_count[24];
static DEFINE_PER_CPU_ALIGNED(unsigned long,
			      nlmsvc_version4_count[ARRAY_SIZE(nlmsvc_procedures4)]);
static const struct svc_version	nlmsvc_version4 = {
	.vs_vers	= 4,
	.vs_nproc	= 24,
	.vs_nproc	= ARRAY_SIZE(nlmsvc_procedures4),
	.vs_proc	= nlmsvc_procedures4,
	.vs_count	= nlmsvc_version4_count,
	.vs_dispatch	= nlmsvc_dispatch,
	.vs_xdrsize	= NLMSVC_XDRSIZE,
};
#endif

static const struct svc_version *nlmsvc_version[] = {
	[1] = &nlmsvc_version1,
	[3] = &nlmsvc_version3,
+3 −3
Original line number Diff line number Diff line
@@ -1459,11 +1459,11 @@ EXPORT_SYMBOL(follow_down_one);
 * point, the filesystem owning that dentry may be queried as to whether the
 * caller is permitted to proceed or not.
 */
int follow_down(struct path *path)
int follow_down(struct path *path, unsigned int flags)
{
	struct vfsmount *mnt = path->mnt;
	bool jumped;
	int ret = traverse_mounts(path, &jumped, NULL, 0);
	int ret = traverse_mounts(path, &jumped, NULL, flags);

	if (path->mnt != mnt)
		mntput(mnt);
@@ -2865,7 +2865,7 @@ int path_pts(struct path *path)

	path->dentry = child;
	dput(parent);
	follow_down(path);
	follow_down(path, 0);
	return 0;
}
#endif
+6 −7
Original line number Diff line number Diff line
@@ -980,14 +980,11 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp)
}

static int
nfs_callback_dispatch(struct svc_rqst *rqstp, __be32 *statp)
nfs_callback_dispatch(struct svc_rqst *rqstp)
{
	const struct svc_procedure *procp = rqstp->rq_procinfo;

	svcxdr_init_decode(rqstp);
	svcxdr_init_encode(rqstp);

	*statp = procp->pc_func(rqstp);
	*rqstp->rq_accept_statp = procp->pc_func(rqstp);
	return 1;
}

@@ -1072,7 +1069,8 @@ static const struct svc_procedure nfs4_callback_procedures1[] = {
	}
};

static unsigned int nfs4_callback_count1[ARRAY_SIZE(nfs4_callback_procedures1)];
static DEFINE_PER_CPU_ALIGNED(unsigned long,
			      nfs4_callback_count1[ARRAY_SIZE(nfs4_callback_procedures1)]);
const struct svc_version nfs4_callback_version1 = {
	.vs_vers = 1,
	.vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
@@ -1084,7 +1082,8 @@ const struct svc_version nfs4_callback_version1 = {
	.vs_need_cong_ctrl = true,
};

static unsigned int nfs4_callback_count4[ARRAY_SIZE(nfs4_callback_procedures1)];
static DEFINE_PER_CPU_ALIGNED(unsigned long,
			      nfs4_callback_count4[ARRAY_SIZE(nfs4_callback_procedures1)]);
const struct svc_version nfs4_callback_version4 = {
	.vs_vers = 4,
	.vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent)
	dprintk("%s: max fh len %d inode %p parent %p",
		__func__, *max_len, inode, parent);

	if (*max_len < len || IS_AUTOMOUNT(inode)) {
	if (*max_len < len) {
		dprintk("%s: fh len %d too small, required %d\n",
			__func__, *max_len, len);
		*max_len = len;

fs/nfsd/fault_inject.c

deleted100644 → 0
+0 −142
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
 *
 * Uses debugfs to create fault injection points for client testing
 */

#include <linux/types.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/nsproxy.h>
#include <linux/sunrpc/addr.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>

#include "state.h"
#include "netns.h"

struct nfsd_fault_inject_op {
	char *file;
	u64 (*get)(void);
	u64 (*set_val)(u64);
	u64 (*set_clnt)(struct sockaddr_storage *, size_t);
};

static struct dentry *debug_dir;

static ssize_t fault_inject_read(struct file *file, char __user *buf,
				 size_t len, loff_t *ppos)
{
	static u64 val;
	char read_buf[25];
	size_t size;
	loff_t pos = *ppos;
	struct nfsd_fault_inject_op *op = file_inode(file)->i_private;

	if (!pos)
		val = op->get();
	size = scnprintf(read_buf, sizeof(read_buf), "%llu\n", val);

	return simple_read_from_buffer(buf, len, ppos, read_buf, size);
}

static ssize_t fault_inject_write(struct file *file, const char __user *buf,
				  size_t len, loff_t *ppos)
{
	char write_buf[INET6_ADDRSTRLEN];
	size_t size = min(sizeof(write_buf) - 1, len);
	struct net *net = current->nsproxy->net_ns;
	struct sockaddr_storage sa;
	struct nfsd_fault_inject_op *op = file_inode(file)->i_private;
	u64 val;
	char *nl;

	if (copy_from_user(write_buf, buf, size))
		return -EFAULT;
	write_buf[size] = '\0';

	/* Deal with any embedded newlines in the string */
	nl = strchr(write_buf, '\n');
	if (nl) {
		size = nl - write_buf;
		*nl = '\0';
	}

	size = rpc_pton(net, write_buf, size, (struct sockaddr *)&sa, sizeof(sa));
	if (size > 0) {
		val = op->set_clnt(&sa, size);
		if (val)
			pr_info("NFSD [%s]: Client %s had %llu state object(s)\n",
				op->file, write_buf, val);
	} else {
		val = simple_strtoll(write_buf, NULL, 0);
		if (val == 0)
			pr_info("NFSD Fault Injection: %s (all)", op->file);
		else
			pr_info("NFSD Fault Injection: %s (n = %llu)",
				op->file, val);
		val = op->set_val(val);
		pr_info("NFSD: %s: found %llu", op->file, val);
	}
	return len; /* on success, claim we got the whole input */
}

static const struct file_operations fops_nfsd = {
	.owner   = THIS_MODULE,
	.read    = fault_inject_read,
	.write   = fault_inject_write,
};

void nfsd_fault_inject_cleanup(void)
{
	debugfs_remove_recursive(debug_dir);
}

static struct nfsd_fault_inject_op inject_ops[] = {
	{
		.file     = "forget_clients",
		.get	  = nfsd_inject_print_clients,
		.set_val  = nfsd_inject_forget_clients,
		.set_clnt = nfsd_inject_forget_client,
	},
	{
		.file     = "forget_locks",
		.get	  = nfsd_inject_print_locks,
		.set_val  = nfsd_inject_forget_locks,
		.set_clnt = nfsd_inject_forget_client_locks,
	},
	{
		.file     = "forget_openowners",
		.get	  = nfsd_inject_print_openowners,
		.set_val  = nfsd_inject_forget_openowners,
		.set_clnt = nfsd_inject_forget_client_openowners,
	},
	{
		.file     = "forget_delegations",
		.get	  = nfsd_inject_print_delegations,
		.set_val  = nfsd_inject_forget_delegations,
		.set_clnt = nfsd_inject_forget_client_delegations,
	},
	{
		.file     = "recall_delegations",
		.get	  = nfsd_inject_print_delegations,
		.set_val  = nfsd_inject_recall_delegations,
		.set_clnt = nfsd_inject_recall_client_delegations,
	},
};

void nfsd_fault_inject_init(void)
{
	unsigned int i;
	struct nfsd_fault_inject_op *op;
	umode_t mode = S_IFREG | S_IRUSR | S_IWUSR;

	debug_dir = debugfs_create_dir("nfsd", NULL);

	for (i = 0; i < ARRAY_SIZE(inject_ops); i++) {
		op = &inject_ops[i];
		debugfs_create_file(op->file, mode, debug_dir, op, &fops_nfsd);
	}
}
Loading