Skip to content

Commit 93adc1e

Browse files
neilbrownchucklever
authored andcommitted
NFSD: set attributes when creating symlinks
The NFS protocol includes attributes when creating symlinks. Linux does store attributes for symlinks and allows them to be set, though they are not used for permission checking. NFSD currently doesn't set standard (struct iattr) attributes when creating symlinks, but for NFSv4 it does set ACLs and security labels. This is inconsistent. To improve consistency, pass the provided attributes into nfsd_symlink() and call nfsd_create_setattr() to set them. NOTE: this results in a behaviour change for all NFS versions when the client sends non-default attributes with a SYMLINK request. With the Linux client, the only attributes are: attr.ia_mode = S_IFLNK | S_IRWXUGO; attr.ia_valid = ATTR_MODE; so the final outcome will be unchanged. Other clients might sent different attributes, and if they did they probably expect them to be honoured. We ignore any error from nfsd_create_setattr(). It isn't really clear what should be done if a file is successfully created, but the attributes cannot be set. NFS doesn't allow partial success to be reported. Reporting failure is probably more misleading than reporting success, so the status is ignored. Signed-off-by: NeilBrown <[email protected]> Signed-off-by: Chuck Lever <[email protected]>
1 parent 7fe2a71 commit 93adc1e

File tree

5 files changed

+30
-12
lines changed

5 files changed

+30
-12
lines changed

fs/nfsd/nfs3proc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
397397
{
398398
struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
399399
struct nfsd3_diropres *resp = rqstp->rq_resp;
400+
struct nfsd_attrs attrs = {
401+
.na_iattr = &argp->attrs,
402+
};
400403

401404
if (argp->tlen == 0) {
402405
resp->status = nfserr_inval;
@@ -423,7 +426,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
423426
fh_copy(&resp->dirfh, &argp->ffh);
424427
fh_init(&resp->fh, NFS3_FHSIZE);
425428
resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
426-
argp->flen, argp->tname, &resp->fh);
429+
argp->flen, argp->tname, &attrs, &resp->fh);
427430
kfree(argp->tname);
428431
out:
429432
return rpc_success;

fs/nfsd/nfs4proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
813813
case NF4LNK:
814814
status = nfsd_symlink(rqstp, &cstate->current_fh,
815815
create->cr_name, create->cr_namelen,
816-
create->cr_data, &resfh);
816+
create->cr_data, &attrs, &resfh);
817817
break;
818818

819819
case NF4BLK:

fs/nfsd/nfsproc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
478478
{
479479
struct nfsd_symlinkargs *argp = rqstp->rq_argp;
480480
struct nfsd_stat *resp = rqstp->rq_resp;
481+
struct nfsd_attrs attrs = {
482+
.na_iattr = &argp->attrs,
483+
};
481484
struct svc_fh newfh;
482485

483486
if (argp->tlen > NFS_MAXPATHLEN) {
@@ -499,7 +502,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp)
499502

500503
fh_init(&newfh, NFS_FHSIZE);
501504
resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
502-
argp->tname, &newfh);
505+
argp->tname, &attrs, &newfh);
503506

504507
kfree(argp->tname);
505508
fh_put(&argp->ffh);

fs/nfsd/vfs.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,15 +1445,25 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
14451445
return 0;
14461446
}
14471447

1448-
/*
1449-
* Create a symlink and look up its inode
1448+
/**
1449+
* nfsd_symlink - Create a symlink and look up its inode
1450+
* @rqstp: RPC transaction being executed
1451+
* @fhp: NFS filehandle of parent directory
1452+
* @fname: filename of the new symlink
1453+
* @flen: length of @fname
1454+
* @path: content of the new symlink (NUL-terminated)
1455+
* @attrs: requested attributes of new object
1456+
* @resfhp: NFS filehandle of new object
1457+
*
14501458
* N.B. After this call _both_ fhp and resfhp need an fh_put
1459+
*
1460+
* Returns nfs_ok on success, or an nfsstat in network byte order.
14511461
*/
14521462
__be32
14531463
nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
1454-
char *fname, int flen,
1455-
char *path,
1456-
struct svc_fh *resfhp)
1464+
char *fname, int flen,
1465+
char *path, struct nfsd_attrs *attrs,
1466+
struct svc_fh *resfhp)
14571467
{
14581468
struct dentry *dentry, *dnew;
14591469
__be32 err, cerr;
@@ -1483,13 +1493,14 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
14831493

14841494
host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path);
14851495
err = nfserrno(host_err);
1496+
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
1497+
if (!err)
1498+
nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
14861499
fh_unlock(fhp);
14871500
if (!err)
14881501
err = nfserrno(commit_metadata(fhp));
1489-
14901502
fh_drop_write(fhp);
14911503

1492-
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
14931504
dput(dnew);
14941505
if (err==0) err = cerr;
14951506
out:

fs/nfsd/vfs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,9 @@ __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
114114
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
115115
char *, int *);
116116
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
117-
char *name, int len, char *path,
118-
struct svc_fh *res);
117+
char *name, int len, char *path,
118+
struct nfsd_attrs *attrs,
119+
struct svc_fh *res);
119120
__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
120121
char *, int, struct svc_fh *);
121122
ssize_t nfsd_copy_file_range(struct file *, u64,

0 commit comments

Comments
 (0)