2002-07-22 14:10:58

by Marcin Dalecki

[permalink] [raw]
Subject: [PATCH] 2.5.27 read_write

diff -urN linux-2.5.27/fs/read_write.c linux/fs/read_write.c
--- linux-2.5.27/fs/read_write.c 2002-07-22 13:08:04.000000000 +0200
+++ linux/fs/read_write.c 2002-07-22 13:44:04.000000000 +0200
@@ -307,11 +307,11 @@
ret = -EINVAL;
for (i = 0 ; i < count ; i++) {
size_t tmp = tot_len;
- int len = iov[i].iov_len;
- if (len < 0)
- goto out;
- (u32)tot_len += len;
- if (tot_len < tmp || tot_len < (u32)len)
+ size_t len = iov[i].iov_len;
+
+ tot_len += len;
+ /* check for overflows */
+ if (tot_len < tmp || tot_len < len)
goto out;
}


Attachments:
read_write-2.5.27.diff (558.00 B)

2002-07-22 15:39:44

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.27 read_write

On Mon, 2002-07-22 at 15:08, Marcin Dalecki wrote:
> - It is fixing completely confused wild casting to 32 bits.
>
> - Actually adding a comment explaining the obscure code, which is
> relying on integer arithmetics overflow.

Better yet take the code from 2.4.19-rc3. The code you fixed up is still
wrong. Sincie iov_len is not permitted to exceed 2Gb (SuS v3, found by
the LSB test suite) the actual fix turns out to be even simpler and
cleaner than the one you did


2002-07-22 15:49:05

by Alan

[permalink] [raw]
Subject: Re: [PATCH] 2.5.27 read_write

On Mon, 2002-07-22 at 15:08, Marcin Dalecki wrote:
> - This is making the read_write.c C.
>
> - It is fixing completely confused wild casting to 32 bits.
>
> - Actually adding a comment explaining the obscure code, which is
> relying on integer arithmetics overflow.

This is the 2.4 patch. This passes the SuS LSB validation tests and gets
32/64bit behaviour as well as sign rules for iov_len elements right. At
least I hope it does.

--- linux-2.5.27/fs/read_write.c Sat Jul 20 20:11:25 2002
+++ linux-2.5.27-ac1/fs/read_write.c Mon Jul 22 15:43:46 2002
@@ -301,17 +301,23 @@
if (copy_from_user(iov, vector, count*sizeof(*vector)))
goto out;

- /* BSD readv/writev returns EINVAL if one of the iov_len
- values < 0 or tot_len overflowed a 32-bit integer. -ink */
+ /*
+ * Single unix specification:
+ * We should -EINVAL if an element length is not >= 0 and fitting an ssize_t
+ * The total length is fitting an ssize_t
+ *
+ * Be careful here because iov_len is a size_t not an ssize_t
+ */
+
tot_len = 0;
ret = -EINVAL;
for (i = 0 ; i < count ; i++) {
- size_t tmp = tot_len;
- int len = iov[i].iov_len;
- if (len < 0)
+ ssize_t tmp = tot_len;
+ ssize_t len = (ssize_t)iov[i].iov_len;
+ if (len < 0) /* size_t not fitting an ssize_t .. */
goto out;
- (u32)tot_len += len;
- if (tot_len < tmp || tot_len < (u32)len)
+ tot_len += len;
+ if (tot_len < tmp) /* maths overflow on the ssize_t */
goto out;
}