aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/file.c20
-rw-r--r--fs/nfs/proc.c24
-rw-r--r--include/linux/nfs_xdr.h1
3 files changed, 40 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};
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 24263bb8e0be..8d780de371f0 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -832,6 +832,7 @@ struct nfs_rpc_ops {
832 int (*file_open) (struct inode *, struct file *); 832 int (*file_open) (struct inode *, struct file *);
833 int (*file_release) (struct inode *, struct file *); 833 int (*file_release) (struct inode *, struct file *);
834 int (*lock)(struct file *, int, struct file_lock *); 834 int (*lock)(struct file *, int, struct file_lock *);
835 int (*lock_check_bounds)(const struct file_lock *);
835 void (*clear_acl_cache)(struct inode *); 836 void (*clear_acl_cache)(struct inode *);
836}; 837};
837 838