aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-05-20 19:34:39 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-07-09 12:08:40 -0400
commit2116271a347d1181b5497602c2bfada1de8fd53b (patch)
tree537498aa91bbe1fbbfc7f2c1e00910ca7fbc2261 /fs
parentf3d47a3a6a1484a93c8cfe1e8c8d4399c95199c7 (diff)
NFS: Add correct bounds checking to NFSv2 locks
NFSv2 file locking currently fails the Connectathon tests, because the calls to the VFS locking code do not return an EINVAL error if the struct file_lock overflows the 32-bit boundaries. The problem is due to the fact that we occasionally call helpers from fs/locks.c in order to avoid RPC calls to the server when we know that a local process holds the lock. These helpers are, of course, always 64-bit enabled, so EINVAL is not returned in cases when it would if the call had gone to the NLM code. For consistency, we therefore add support for a bounds-checking helper. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/file.c20
-rw-r--r--fs/nfs/proc.c24
2 files changed, 39 insertions, 5 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index d84a3d8f32af..7c73f06692b6 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -593,6 +593,7 @@ out:
593static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) 593static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
594{ 594{
595 struct inode * inode = filp->f_mapping->host; 595 struct inode * inode = filp->f_mapping->host;
596 int ret = -ENOLCK;
596 597
597 dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n", 598 dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
598 inode->i_sb->s_id, inode->i_ino, 599 inode->i_sb->s_id, inode->i_ino,
@@ -602,13 +603,22 @@ static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
602 603
603 /* No mandatory locks over NFS */ 604 /* No mandatory locks over NFS */
604 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) 605 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
605 return -ENOLCK; 606 goto out_err;
607
608 if (NFS_PROTO(inode)->lock_check_bounds != NULL) {
609 ret = NFS_PROTO(inode)->lock_check_bounds(fl);
610 if (ret < 0)
611 goto out_err;
612 }
606 613
607 if (IS_GETLK(cmd)) 614 if (IS_GETLK(cmd))
608 return do_getlk(filp, cmd, fl); 615 ret = do_getlk(filp, cmd, fl);
609 if (fl->fl_type == F_UNLCK) 616 else if (fl->fl_type == F_UNLCK)
610 return do_unlk(filp, cmd, fl); 617 ret = do_unlk(filp, cmd, fl);
611 return do_setlk(filp, cmd, fl); 618 else
619 ret = do_setlk(filp, cmd, fl);
620out_err:
621 return ret;
612} 622}
613 623
614/* 624/*
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 03599bfe81cf..5c35b02857f3 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -598,6 +598,29 @@ nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
598 return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl); 598 return nlmclnt_proc(NFS_SERVER(inode)->nlm_host, cmd, fl);
599} 599}
600 600
601/* Helper functions for NFS lock bounds checking */
602#define NFS_LOCK32_OFFSET_MAX ((__s32)0x7fffffffUL)
603static int nfs_lock_check_bounds(const struct file_lock *fl)
604{
605 __s32 start, end;
606
607 start = (__s32)fl->fl_start;
608 if ((loff_t)start != fl->fl_start)
609 goto out_einval;
610
611 if (fl->fl_end != OFFSET_MAX) {
612 end = (__s32)fl->fl_end;
613 if ((loff_t)end != fl->fl_end)
614 goto out_einval;
615 } else
616 end = NFS_LOCK32_OFFSET_MAX;
617
618 if (start < 0 || start > end)
619 goto out_einval;
620 return 0;
621out_einval:
622 return -EINVAL;
623}
601 624
602const struct nfs_rpc_ops nfs_v2_clientops = { 625const struct nfs_rpc_ops nfs_v2_clientops = {
603 .version = 2, /* protocol version */ 626 .version = 2, /* protocol version */
@@ -633,4 +656,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
633 .file_open = nfs_open, 656 .file_open = nfs_open,
634 .file_release = nfs_release, 657 .file_release = nfs_release,
635 .lock = nfs_proc_lock, 658 .lock = nfs_proc_lock,
659 .lock_check_bounds = nfs_lock_check_bounds,
636}; 660};