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

nfs2acl.c (9518B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Process version 2 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#define NFSDDBG_FACILITY		NFSDDBG_PROC
     17
     18/*
     19 * NULL call.
     20 */
     21static __be32
     22nfsacld_proc_null(struct svc_rqst *rqstp)
     23{
     24	return rpc_success;
     25}
     26
     27/*
     28 * Get the Access and/or Default ACL of a file.
     29 */
     30static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
     31{
     32	struct nfsd3_getaclargs *argp = rqstp->rq_argp;
     33	struct nfsd3_getaclres *resp = rqstp->rq_resp;
     34	struct posix_acl *acl;
     35	struct inode *inode;
     36	svc_fh *fh;
     37
     38	dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
     39
     40	fh = fh_copy(&resp->fh, &argp->fh);
     41	resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
     42	if (resp->status != nfs_ok)
     43		goto out;
     44
     45	inode = d_inode(fh->fh_dentry);
     46
     47	if (argp->mask & ~NFS_ACL_MASK) {
     48		resp->status = nfserr_inval;
     49		goto out;
     50	}
     51	resp->mask = argp->mask;
     52
     53	resp->status = fh_getattr(fh, &resp->stat);
     54	if (resp->status != nfs_ok)
     55		goto out;
     56
     57	if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
     58		acl = get_acl(inode, ACL_TYPE_ACCESS);
     59		if (acl == NULL) {
     60			/* Solaris returns the inode's minimum ACL. */
     61			acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
     62		}
     63		if (IS_ERR(acl)) {
     64			resp->status = nfserrno(PTR_ERR(acl));
     65			goto fail;
     66		}
     67		resp->acl_access = acl;
     68	}
     69	if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
     70		/* Check how Solaris handles requests for the Default ACL
     71		   of a non-directory! */
     72		acl = get_acl(inode, ACL_TYPE_DEFAULT);
     73		if (IS_ERR(acl)) {
     74			resp->status = nfserrno(PTR_ERR(acl));
     75			goto fail;
     76		}
     77		resp->acl_default = acl;
     78	}
     79
     80	/* resp->acl_{access,default} are released in nfssvc_release_getacl. */
     81out:
     82	return rpc_success;
     83
     84fail:
     85	posix_acl_release(resp->acl_access);
     86	posix_acl_release(resp->acl_default);
     87	goto out;
     88}
     89
     90/*
     91 * Set the Access and/or Default ACL of a file.
     92 */
     93static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
     94{
     95	struct nfsd3_setaclargs *argp = rqstp->rq_argp;
     96	struct nfsd_attrstat *resp = rqstp->rq_resp;
     97	struct inode *inode;
     98	svc_fh *fh;
     99	int error;
    100
    101	dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
    102
    103	fh = fh_copy(&resp->fh, &argp->fh);
    104	resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
    105	if (resp->status != nfs_ok)
    106		goto out;
    107
    108	inode = d_inode(fh->fh_dentry);
    109
    110	error = fh_want_write(fh);
    111	if (error)
    112		goto out_errno;
    113
    114	fh_lock(fh);
    115
    116	error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_ACCESS,
    117			      argp->acl_access);
    118	if (error)
    119		goto out_drop_lock;
    120	error = set_posix_acl(&init_user_ns, inode, ACL_TYPE_DEFAULT,
    121			      argp->acl_default);
    122	if (error)
    123		goto out_drop_lock;
    124
    125	fh_unlock(fh);
    126
    127	fh_drop_write(fh);
    128
    129	resp->status = fh_getattr(fh, &resp->stat);
    130
    131out:
    132	/* argp->acl_{access,default} may have been allocated in
    133	   nfssvc_decode_setaclargs. */
    134	posix_acl_release(argp->acl_access);
    135	posix_acl_release(argp->acl_default);
    136	return rpc_success;
    137
    138out_drop_lock:
    139	fh_unlock(fh);
    140	fh_drop_write(fh);
    141out_errno:
    142	resp->status = nfserrno(error);
    143	goto out;
    144}
    145
    146/*
    147 * Check file attributes
    148 */
    149static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
    150{
    151	struct nfsd_fhandle *argp = rqstp->rq_argp;
    152	struct nfsd_attrstat *resp = rqstp->rq_resp;
    153
    154	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
    155
    156	fh_copy(&resp->fh, &argp->fh);
    157	resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
    158	if (resp->status != nfs_ok)
    159		goto out;
    160	resp->status = fh_getattr(&resp->fh, &resp->stat);
    161out:
    162	return rpc_success;
    163}
    164
    165/*
    166 * Check file access
    167 */
    168static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
    169{
    170	struct nfsd3_accessargs *argp = rqstp->rq_argp;
    171	struct nfsd3_accessres *resp = rqstp->rq_resp;
    172
    173	dprintk("nfsd: ACCESS(2acl)   %s 0x%x\n",
    174			SVCFH_fmt(&argp->fh),
    175			argp->access);
    176
    177	fh_copy(&resp->fh, &argp->fh);
    178	resp->access = argp->access;
    179	resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
    180	if (resp->status != nfs_ok)
    181		goto out;
    182	resp->status = fh_getattr(&resp->fh, &resp->stat);
    183out:
    184	return rpc_success;
    185}
    186
    187/*
    188 * XDR decode functions
    189 */
    190
    191static bool
    192nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    193{
    194	struct nfsd3_getaclargs *argp = rqstp->rq_argp;
    195
    196	if (!svcxdr_decode_fhandle(xdr, &argp->fh))
    197		return false;
    198	if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
    199		return false;
    200
    201	return true;
    202}
    203
    204static bool
    205nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    206{
    207	struct nfsd3_setaclargs *argp = rqstp->rq_argp;
    208
    209	if (!svcxdr_decode_fhandle(xdr, &argp->fh))
    210		return false;
    211	if (xdr_stream_decode_u32(xdr, &argp->mask) < 0)
    212		return false;
    213	if (argp->mask & ~NFS_ACL_MASK)
    214		return false;
    215	if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ?
    216				   &argp->acl_access : NULL))
    217		return false;
    218	if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ?
    219				   &argp->acl_default : NULL))
    220		return false;
    221
    222	return true;
    223}
    224
    225static bool
    226nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    227{
    228	struct nfsd3_accessargs *args = rqstp->rq_argp;
    229
    230	if (!svcxdr_decode_fhandle(xdr, &args->fh))
    231		return false;
    232	if (xdr_stream_decode_u32(xdr, &args->access) < 0)
    233		return false;
    234
    235	return true;
    236}
    237
    238/*
    239 * XDR encode functions
    240 */
    241
    242/* GETACL */
    243static bool
    244nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    245{
    246	struct nfsd3_getaclres *resp = rqstp->rq_resp;
    247	struct dentry *dentry = resp->fh.fh_dentry;
    248	struct inode *inode;
    249	int w;
    250
    251	if (!svcxdr_encode_stat(xdr, resp->status))
    252		return false;
    253
    254	if (dentry == NULL || d_really_is_negative(dentry))
    255		return true;
    256	inode = d_inode(dentry);
    257
    258	if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
    259		return false;
    260	if (xdr_stream_encode_u32(xdr, resp->mask) < 0)
    261		return false;
    262
    263	rqstp->rq_res.page_len = w = nfsacl_size(
    264		(resp->mask & NFS_ACL)   ? resp->acl_access  : NULL,
    265		(resp->mask & NFS_DFACL) ? resp->acl_default : NULL);
    266	while (w > 0) {
    267		if (!*(rqstp->rq_next_page++))
    268			return true;
    269		w -= PAGE_SIZE;
    270	}
    271
    272	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access,
    273				   resp->mask & NFS_ACL, 0))
    274		return false;
    275	if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default,
    276				   resp->mask & NFS_DFACL, NFS_ACL_DEFAULT))
    277		return false;
    278
    279	return true;
    280}
    281
    282/* ACCESS */
    283static bool
    284nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
    285{
    286	struct nfsd3_accessres *resp = rqstp->rq_resp;
    287
    288	if (!svcxdr_encode_stat(xdr, resp->status))
    289		return false;
    290	switch (resp->status) {
    291	case nfs_ok:
    292		if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
    293			return false;
    294		if (xdr_stream_encode_u32(xdr, resp->access) < 0)
    295			return false;
    296		break;
    297	}
    298
    299	return true;
    300}
    301
    302/*
    303 * XDR release functions
    304 */
    305static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp)
    306{
    307	struct nfsd3_getaclres *resp = rqstp->rq_resp;
    308
    309	fh_put(&resp->fh);
    310	posix_acl_release(resp->acl_access);
    311	posix_acl_release(resp->acl_default);
    312}
    313
    314static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
    315{
    316	struct nfsd3_accessres *resp = rqstp->rq_resp;
    317
    318	fh_put(&resp->fh);
    319}
    320
    321struct nfsd3_voidargs { int dummy; };
    322
    323#define ST 1		/* status*/
    324#define AT 21		/* attributes */
    325#define pAT (1+AT)	/* post attributes - conditional */
    326#define ACL (1+NFS_ACL_MAX_ENTRIES*3)  /* Access Control List */
    327
    328static const struct svc_procedure nfsd_acl_procedures2[5] = {
    329	[ACLPROC2_NULL] = {
    330		.pc_func = nfsacld_proc_null,
    331		.pc_decode = nfssvc_decode_voidarg,
    332		.pc_encode = nfssvc_encode_voidres,
    333		.pc_argsize = sizeof(struct nfsd_voidargs),
    334		.pc_ressize = sizeof(struct nfsd_voidres),
    335		.pc_cachetype = RC_NOCACHE,
    336		.pc_xdrressize = ST,
    337		.pc_name = "NULL",
    338	},
    339	[ACLPROC2_GETACL] = {
    340		.pc_func = nfsacld_proc_getacl,
    341		.pc_decode = nfsaclsvc_decode_getaclargs,
    342		.pc_encode = nfsaclsvc_encode_getaclres,
    343		.pc_release = nfsaclsvc_release_getacl,
    344		.pc_argsize = sizeof(struct nfsd3_getaclargs),
    345		.pc_ressize = sizeof(struct nfsd3_getaclres),
    346		.pc_cachetype = RC_NOCACHE,
    347		.pc_xdrressize = ST+1+2*(1+ACL),
    348		.pc_name = "GETACL",
    349	},
    350	[ACLPROC2_SETACL] = {
    351		.pc_func = nfsacld_proc_setacl,
    352		.pc_decode = nfsaclsvc_decode_setaclargs,
    353		.pc_encode = nfssvc_encode_attrstatres,
    354		.pc_release = nfssvc_release_attrstat,
    355		.pc_argsize = sizeof(struct nfsd3_setaclargs),
    356		.pc_ressize = sizeof(struct nfsd_attrstat),
    357		.pc_cachetype = RC_NOCACHE,
    358		.pc_xdrressize = ST+AT,
    359		.pc_name = "SETACL",
    360	},
    361	[ACLPROC2_GETATTR] = {
    362		.pc_func = nfsacld_proc_getattr,
    363		.pc_decode = nfssvc_decode_fhandleargs,
    364		.pc_encode = nfssvc_encode_attrstatres,
    365		.pc_release = nfssvc_release_attrstat,
    366		.pc_argsize = sizeof(struct nfsd_fhandle),
    367		.pc_ressize = sizeof(struct nfsd_attrstat),
    368		.pc_cachetype = RC_NOCACHE,
    369		.pc_xdrressize = ST+AT,
    370		.pc_name = "GETATTR",
    371	},
    372	[ACLPROC2_ACCESS] = {
    373		.pc_func = nfsacld_proc_access,
    374		.pc_decode = nfsaclsvc_decode_accessargs,
    375		.pc_encode = nfsaclsvc_encode_accessres,
    376		.pc_release = nfsaclsvc_release_access,
    377		.pc_argsize = sizeof(struct nfsd3_accessargs),
    378		.pc_ressize = sizeof(struct nfsd3_accessres),
    379		.pc_cachetype = RC_NOCACHE,
    380		.pc_xdrressize = ST+AT+1,
    381		.pc_name = "SETATTR",
    382	},
    383};
    384
    385static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
    386const struct svc_version nfsd_acl_version2 = {
    387	.vs_vers	= 2,
    388	.vs_nproc	= 5,
    389	.vs_proc	= nfsd_acl_procedures2,
    390	.vs_count	= nfsd_acl_count2,
    391	.vs_dispatch	= nfsd_dispatch,
    392	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
    393};