diff options
-rw-r--r-- | fs/nfs/file.c | 20 | ||||
-rw-r--r-- | fs/nfs/proc.c | 24 | ||||
-rw-r--r-- | include/linux/nfs_xdr.h | 1 |
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: | |||
593 | static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) | 593 | static 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); | ||
620 | out_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) | ||
603 | static 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; | ||
621 | out_einval: | ||
622 | return -EINVAL; | ||
623 | } | ||
601 | 624 | ||
602 | const struct nfs_rpc_ops nfs_v2_clientops = { | 625 | const 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 | ||