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

nfs3acl.c (7060B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Process version 3 NFSACL requests.
      4 *
      5 * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
      6 */
      7
      8#include "nfsd.h"
      9/* FIXME: nfsacl.h is a broken header */
     10#include <linux/nfsacl.h>
     11#include <linux/gfp.h>
     12#include "cache.h"
     13#include "xdr3.h"
     14#include "vfs.h"
     15
     16/*
     17 * NULL call.
     18 */
     19static __be32
     20nfsd3_proc_null(struct svc_rqst *rqstp)
     21{
     22	return rpc_success;
     23}
     24
     25/*
     26 * Get the Access and/or Default ACL of a file.
     27 */
     28static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
     29{
     30	struct nfsd3_getaclargs *argp = rqstp->rq_argp;
     31	struct nfsd3_getaclres *resp = rqstp->rq_resp;
     32	struct posix_acl *acl;
     33	struct inode *inode;
     34	svc_fh *fh;
     35
     36	fh = fh_copy(&resp->fh, &argp->fh);
     37	resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
     38	if (resp->status != nfs_ok)
     39		goto out;
     40
     41	inode = d_inode(fh->fh_dentry);
     42
     43	if (argp->mask & ~NFS_ACL_MASK) {
     44		resp->status = nfserr_inval;
     45		goto out;
     46	}
     47	resp->mask = argp->mask;
     48
     49	if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
     50		acl = get_acl(inode, ACL_TYPE_ACCESS);
     51		if (acl == NULL) {
     52			/* Solaris returns the inode's minimum ACL. */
     53			acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
     54		}
     55		if (IS_ERR(acl)) {
     56			resp->status = nfserrno(PTR_ERR(acl));
     57			goto fail;
     58		}
     59		resp->acl_access = acl;
     60	}
     61	if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
     62		/* Check how Solaris handles requests for the Default ACL
     63		   of a non-directory! */
     64		acl = get_acl(inode, ACL_TYPE_DEFAULT);
     65		if (IS_ERR(acl)) {
     66			resp->status = nfserrno(PTR_ERR(acl));
     67			goto fail;
     68		}
     69		resp->acl_default = acl;
     70	}
     71
     72	/* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
     73out:
     74	return rpc_success;
     75
     76fail:
     77	posix_acl_release(resp->acl_access);
     78	posix_acl_release(resp->acl_default);
     79	goto out;
     80}
     81
     82/*
     83 * Set the Access and/or Default ACL of a file.
     84 */
     85static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
     86{
     87	struct nfsd3_setaclargs *argp = rqstp->rq_argp;
     88	struct nfsd3_attrstat *resp = rqstp->rq_resp;
     89	struct inode *inode;
     90	svc_fh *fh;
     91	int error;
     92
     93	fh = fh_copy(&resp->fh, &argp->fh);
     94	resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
     95	if (resp->status != nfs_ok)
     96		goto out;
     97
     98	inode = d_inode(fh->fh_dentry);
     99
    100	error = fh_want_write(fh);
    101	if (error)
    102		goto out_errno;
    103
    104	fh_lock(fh);
    105
    106	error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
    107			      argp->acl_access);
    108	if (error)
    109		goto out_drop_lock;
    110	error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
    111			      argp->acl_default);
    112
    113out_drop_lock:
    114	fh_unlock(fh);
    115	fh_drop_write(fh);
    116out_errno:
    117	resp->status = nfserrno(error);
    118out:
    119	/* argp->acl_{access,default} may have been allocated in
    120	   nfs3svc_decode_setaclargs. */
    121	posix_acl_release(argp->acl_access);
    122	posix_acl_release(argp->acl_default);
    123	return rpc_success;
    124}
    125
    126/*
    127 * XDR decode functions
    128 */
    129
    130static bool
    131nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    132{
    133	struct nfsd3_getaclargs *args = rqstp->rq_argp;
    134
    135	if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
    136		return false;
    137	if (xdr_stream_decode_u32(xdr, &args->mask) < 0)
    138		return false;
    139
    140	return true;
    141}
    142
    143static bool
    144nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    145{
    146	struct nfsd3_setaclargs *argp = rqstp->rq_argp;
    147
    148	if (!svcxdr_decode_nfs_fh3(xdr, &argp->fh))
    149		return false;
    150	if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
    151		return false;
    152	if (argp->mask & ~NFS_ACL_MASK)
    153		return false;
    154	if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ?
    155				   &argp->acl_access : NULL))
    156		return false;
    157	if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ?
    158				   &argp->acl_default : NULL))
    159		return false;
    160
    161	return true;
    162}
    163
    164/*
    165 * XDR encode functions
    166 */
    167
    168/* GETACL */
    169static bool
    170nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    171{
    172	struct nfsd3_getaclres *resp = rqstp->rq_resp;
    173	struct dentry *dentry = resp->fh.fh_dentry;
    174	struct kvec *head = rqstp->rq_res.head;
    175	struct inode *inode;
    176	unsigned int base;
    177	int n;
    178	int w;
    179
    180	if (!svcxdr_encode_nfsstat3(xdr, resp->status))
    181		return false;
    182	switch (resp->status) {
    183	case nfs_ok:
    184		inode = d_inode(dentry);
    185		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
    186			return false;
    187		if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
    188			return false;
    189
    190		base = (char *)xdr->p - (char *)head->iov_base;
    191
    192		rqstp->rq_res.page_len = w = nfsacl_size(
    193			(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
    194			(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
    195		while (w > 0) {
    196			if (!*(rqstp->rq_next_page++))
    197				return false;
    198			w -= PAGE_SIZE;
    199		}
    200
    201		n = nfsacl_encode(&rqstp->rq_res, base, inode,
    202				  resp->acl_access,
    203				  resp->mask & NFS_ACL, 0);
    204		if (n > 0)
    205			n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
    206					  resp->acl_default,
    207					  resp->mask & NFS_DFACL,
    208					  NFS_ACL_DEFAULT);
    209		if (n <= 0)
    210			return false;
    211		break;
    212	default:
    213		if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
    214			return false;
    215	}
    216
    217	return true;
    218}
    219
    220/* SETACL */
    221static bool
    222nfs3svc_encode_setaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    223{
    224	struct nfsd3_attrstat *resp = rqstp->rq_resp;
    225
    226	return svcxdr_encode_nfsstat3(xdr, resp->status) &&
    227		svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh);
    228}
    229
    230/*
    231 * XDR release functions
    232 */
    233static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
    234{
    235	struct nfsd3_getaclres *resp = rqstp->rq_resp;
    236
    237	fh_put(&resp->fh);
    238	posix_acl_release(resp->acl_access);
    239	posix_acl_release(resp->acl_default);
    240}
    241
    242struct nfsd3_voidargs { int dummy; };
    243
    244#define ST 1		/* status*/
    245#define AT 21		/* attributes */
    246#define pAT (1+AT)	/* post attributes - conditional */
    247#define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
    248
    249static const struct svc_procedure nfsd_acl_procedures3[3] = {
    250	[ACLPROC3_NULL] = {
    251		.pc_func = nfsd3_proc_null,
    252		.pc_decode = nfssvc_decode_voidarg,
    253		.pc_encode = nfssvc_encode_voidres,
    254		.pc_argsize = sizeof(struct nfsd_voidargs),
    255		.pc_ressize = sizeof(struct nfsd_voidres),
    256		.pc_cachetype = RC_NOCACHE,
    257		.pc_xdrressize = ST,
    258		.pc_name = "NULL",
    259	},
    260	[ACLPROC3_GETACL] = {
    261		.pc_func = nfsd3_proc_getacl,
    262		.pc_decode = nfs3svc_decode_getaclargs,
    263		.pc_encode = nfs3svc_encode_getaclres,
    264		.pc_release = nfs3svc_release_getacl,
    265		.pc_argsize = sizeof(struct nfsd3_getaclargs),
    266		.pc_ressize = sizeof(struct nfsd3_getaclres),
    267		.pc_cachetype = RC_NOCACHE,
    268		.pc_xdrressize = ST+1+2*(1+ACL),
    269		.pc_name = "GETACL",
    270	},
    271	[ACLPROC3_SETACL] = {
    272		.pc_func = nfsd3_proc_setacl,
    273		.pc_decode = nfs3svc_decode_setaclargs,
    274		.pc_encode = nfs3svc_encode_setaclres,
    275		.pc_release = nfs3svc_release_fhandle,
    276		.pc_argsize = sizeof(struct nfsd3_setaclargs),
    277		.pc_ressize = sizeof(struct nfsd3_attrstat),
    278		.pc_cachetype = RC_NOCACHE,
    279		.pc_xdrressize = ST+pAT,
    280		.pc_name = "SETACL",
    281	},
    282};
    283
    284static unsigned int nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)];
    285const struct svc_version nfsd_acl_version3 = {
    286	.vs_vers	= 3,
    287	.vs_nproc	= 3,
    288	.vs_proc	= nfsd_acl_procedures3,
    289	.vs_count	= nfsd_acl_count3,
    290	.vs_dispatch	= nfsd_dispatch,
    291	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
    292};
    293