From: John Engel <jhe@us.ibm.com>

Here's a patch to fix a bug in compat_sys_fcntl64 in fs/compat.c.  The bug
occurs with a 32 bit app that calls fcntl and checking for a lock near the
end of a file.

    struct flock sflp;
    sflp.l_start = 2147483345;
    sflp.l_len = 302;
    /* 2147483345 + 302 == 2147483647 (this should not overflow 31 bits) */
    /* 2^31 ==             2147483648 */
    fcntl_stat = fcntl(fd, F_GETLK, &sflp);

The patch also contains a fix to handle l_len < 0 which is now defined in
POSIX 1003.1-2001 from the fcntl man page.

Signed-off-by: John Engel <jhe@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/fs/compat.c |   18 ++++++++++++++++--
 1 files changed, 16 insertions(+), 2 deletions(-)

diff -puN fs/compat.c~compat_sys_fcntl64-fix-for-locking-near-end-of-file fs/compat.c
--- 25/fs/compat.c~compat_sys_fcntl64-fix-for-locking-near-end-of-file	2004-09-20 10:30:04.844226624 -0700
+++ 25-akpm/fs/compat.c	2004-09-20 10:30:04.849225864 -0700
@@ -528,8 +528,15 @@ asmlinkage long compat_sys_fcntl64(unsig
 		ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 		set_fs(old_fs);
 		if ((cmd == F_GETLK) && (ret == 0)) {
+			/* POSIX-2001 now defines negative l_len */
+			if (f.l_len < 0) {
+				f.l_start += f.l_len;
+				f.l_len = -f.l_len;
+			}
+			if (f.l_start < 0)
+				return -EINVAL;
 			if ((f.l_start >= COMPAT_OFF_T_MAX) ||
-			    ((f.l_start + f.l_len) >= COMPAT_OFF_T_MAX))
+			    ((f.l_start + f.l_len) > COMPAT_OFF_T_MAX))
 				ret = -EOVERFLOW;
 			if (ret == 0)
 				ret = put_compat_flock(&f, compat_ptr(arg));
@@ -549,8 +556,15 @@ asmlinkage long compat_sys_fcntl64(unsig
 				(unsigned long)&f);
 		set_fs(old_fs);
 		if ((cmd == F_GETLK64) && (ret == 0)) {
+			/* POSIX-2001 now defines negative l_len */
+			if (f.l_len < 0) {
+				f.l_start += f.l_len;
+				f.l_len = -f.l_len;
+			}
+			if (f.l_start < 0)
+				return -EINVAL;
 			if ((f.l_start >= COMPAT_LOFF_T_MAX) ||
-			    ((f.l_start + f.l_len) >= COMPAT_LOFF_T_MAX))
+			    ((f.l_start + f.l_len) > COMPAT_LOFF_T_MAX))
 				ret = -EOVERFLOW;
 			if (ret == 0)
 				ret = put_compat_flock64(&f, compat_ptr(arg));
_