Re: svn commit: r230583 - head/sys/kern

2012-02-01 Thread Konstantin Belousov
On Tue, Jan 31, 2012 at 12:48:49PM -0500, David Schultz wrote:
 On Tue, Jan 31, 2012, Konstantin Belousov wrote:
  On Mon, Jan 30, 2012 at 02:07:03PM -0500, David Schultz wrote:
   On Mon, Jan 30, 2012, Kostik Belousov wrote:
On Sun, Jan 29, 2012 at 05:39:04PM -0500, David Schultz wrote:
 On Sun, Jan 29, 2012, Kostik Belousov wrote:
  On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:
   On Sat, Jan 28, 2012, Kostik Belousov wrote:
On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
 The correct limit on the maximum size of a single read/write 
 is
 SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise 
 the
 limit yet, though, because of bugs in several filesystems.  
 For
 example, FFS copies uio_resid into a local variable of type 
 int.
 I have some old patches that fix some of these issues for FFS 
 and
 cd9660, but surely there are more places I didn't notice.
 
Absolutely agree.

http://people.freebsd.org/~kib/misc/uio_resid.5.patch
   
   Nice.  You found a lot more than I've got in my tree, and you even
   fixed the return values.  There are at least a few more places to
   fix.  For instance, cd9660 and the NFS client pass uio_resid or
   iov_len to min(), which operates on ints.  (Incidentally, C11
   generics ought to make it possible to write type-generic min()
   and max() functions.)
  
  Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
  changed them to MIN().
 
 This looks good to me.  I tried to think of other places that you
 might have missed, and the only one that occurred to me is the
Might ? I think this is a blatant understate.

 pipe code.  sys_pipe.c has an `int orig_resid' and lots of bogus
 casts of iov_len and uio_resid to type u_int.  Some look harmless,
 although it appears that writing a multiple of 2^32 bytes might
 result in pipe_build_write_buffer() allocating a 0-length buffer.
 
 My only reservation is that raising the limit could unmask a
 kernel buffer overflow if we missed something, but I guess we have
 to cross that bridge some day anyway.
Yes, and it is an obvious reason why I am chicken to commit this for
so long time. One more place, if this is reasonable to count as 'one'
place, are the cdevsw methods. devfs passes uio down to the drivers.
   
   That's why I'm glad I'm not committing it. :)  A more conservative
   change (also known as kicking the can down the road) would be to
   add a VFS flag, e.g., VFCF_LONGIO, and only set it on file systems
   that have been thoroughly reviewed.  The VFS layer could cap the size
   at INT_MAX for file systems without the flag.
  At least I will get more mail after the commit, I hope.
  
  I disagree with the VFCF_LONGIO approach. It will cause much head-scratching
  for unsuspecting user who would try to use  4GB transfers.
  
  What I can do, is to commit all changes except removals of the checks
  for INT_MAX. After type changes settle, I can try to gather enough
  bravery to flip the checks in HEAD, possibly with temporary sysctl
  to return to old behaviour for emergency (AKA hole).
 
 That sounds like a good plan to me.
 
 As an aside, I wonder if we could convince the clang folks to add
 a warning similar to `lint -a', which complains about every long-int
 narrowing conversion that doesn't have an explicit cast.  Modern
 languages such as Java and C# require casts for narrowing
 conversions, and I'd be a lot more confident about this change if
 we did the same for the FreeBSD kernel.
 
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 9edcb74..332ec37 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
   [...]
@@ -757,14 +757,14 @@ pipe_build_write_buffer(wpipe, uio)
   struct pipe *wpipe;
   struct uio *uio;
 {
-   u_int size;
+   size_t size;
int i;
 
PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
KASSERT(wpipe-pipe_state  PIPE_DIRECTW,
  (Clone attempt on non-direct write 
pipe!));
 
-   size = (u_int) uio-uio_iov-iov_len;
+   size = uio-uio_iov-iov_len;
if (size  wpipe-pipe_buffer.size)
   size = wpipe-pipe_buffer.size;
   
   The transfer can't be bigger than the max pipe buffer size (64k),
   so `size = (int)MIN(uio-uio_iov-iov_len, wpipe-pipe_buffer.size)'
   should suffice.  The same comment applies elsewhere in the file.
  
  True. If you much prefer this version, I will change the patch. But I do
  think that my changes are cleaner.
 
 I don't mind either way.  I haven't touched anything remotely
 close to that code in years.

I did the changes along the way suggested by Bruce.

Also, I put the patch under the real test for UFS and new 

Re: svn commit: r230583 - head/sys/kern

2012-01-31 Thread Konstantin Belousov
On Mon, Jan 30, 2012 at 02:07:03PM -0500, David Schultz wrote:
 On Mon, Jan 30, 2012, Kostik Belousov wrote:
  On Sun, Jan 29, 2012 at 05:39:04PM -0500, David Schultz wrote:
   On Sun, Jan 29, 2012, Kostik Belousov wrote:
On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:
 On Sat, Jan 28, 2012, Kostik Belousov wrote:
  On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
   The correct limit on the maximum size of a single read/write is
   SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
   limit yet, though, because of bugs in several filesystems.  For
   example, FFS copies uio_resid into a local variable of type int.
   I have some old patches that fix some of these issues for FFS and
   cd9660, but surely there are more places I didn't notice.
   
  Absolutely agree.
  
  http://people.freebsd.org/~kib/misc/uio_resid.5.patch
 
 Nice.  You found a lot more than I've got in my tree, and you even
 fixed the return values.  There are at least a few more places to
 fix.  For instance, cd9660 and the NFS client pass uio_resid or
 iov_len to min(), which operates on ints.  (Incidentally, C11
 generics ought to make it possible to write type-generic min()
 and max() functions.)

Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
changed them to MIN().
   
   This looks good to me.  I tried to think of other places that you
   might have missed, and the only one that occurred to me is the
  Might ? I think this is a blatant understate.
  
   pipe code.  sys_pipe.c has an `int orig_resid' and lots of bogus
   casts of iov_len and uio_resid to type u_int.  Some look harmless,
   although it appears that writing a multiple of 2^32 bytes might
   result in pipe_build_write_buffer() allocating a 0-length buffer.
   
   My only reservation is that raising the limit could unmask a
   kernel buffer overflow if we missed something, but I guess we have
   to cross that bridge some day anyway.
  Yes, and it is an obvious reason why I am chicken to commit this for
  so long time. One more place, if this is reasonable to count as 'one'
  place, are the cdevsw methods. devfs passes uio down to the drivers.
 
 That's why I'm glad I'm not committing it. :)  A more conservative
 change (also known as kicking the can down the road) would be to
 add a VFS flag, e.g., VFCF_LONGIO, and only set it on file systems
 that have been thoroughly reviewed.  The VFS layer could cap the size
 at INT_MAX for file systems without the flag.
At least I will get more mail after the commit, I hope.

I disagree with the VFCF_LONGIO approach. It will cause much head-scratching
for unsuspecting user who would try to use  4GB transfers.

What I can do, is to commit all changes except removals of the checks
for INT_MAX. After type changes settle, I can try to gather enough
bravery to flip the checks in HEAD, possibly with temporary sysctl
to return to old behaviour for emergency (AKA hole).

 
  diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
  index 9edcb74..332ec37 100644
  --- a/sys/kern/sys_pipe.c
  +++ b/sys/kern/sys_pipe.c
 [...]
  @@ -757,14 +757,14 @@ pipe_build_write_buffer(wpipe, uio)
 struct pipe *wpipe;
 struct uio *uio;
   {
  -   u_int size;
  +   size_t size;
  int i;
   
  PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
  KASSERT(wpipe-pipe_state  PIPE_DIRECTW,
(Clone attempt on non-direct write pipe!));
   
  -   size = (u_int) uio-uio_iov-iov_len;
  +   size = uio-uio_iov-iov_len;
  if (size  wpipe-pipe_buffer.size)
 size = wpipe-pipe_buffer.size;
 
 The transfer can't be bigger than the max pipe buffer size (64k),
 so `size = (int)MIN(uio-uio_iov-iov_len, wpipe-pipe_buffer.size)'
 should suffice.  The same comment applies elsewhere in the file.

True. If you much prefer this version, I will change the patch. But I do
think that my changes are cleaner.


pgpfSMIx7snmI.pgp
Description: PGP signature


Re: svn commit: r230583 - head/sys/kern

2012-01-31 Thread Bruce Evans

On Tue, 31 Jan 2012, Konstantin Belousov wrote:


On Mon, Jan 30, 2012 at 02:07:03PM -0500, David Schultz wrote:

That's why I'm glad I'm not committing it. :)  A more conservative
change (also known as kicking the can down the road) would be to
add a VFS flag, e.g., VFCF_LONGIO, and only set it on file systems
that have been thoroughly reviewed.  The VFS layer could cap the size
at INT_MAX for file systems without the flag.

At least I will get more mail after the commit, I hope.

I disagree with the VFCF_LONGIO approach. It will cause much head-scratching
for unsuspecting user who would try to use  4GB transfers.


No one cared when this was broken for almost 10 years by 4.4BSD changing
the type of iov_len from int to size_t.  You can almost equally safely
break it again :(.  Previously (in FreeBSD-1 and presumably in Net/2)
iov_len had the same type as uio_resid, and the code in readv(), etc.,
depended on this and also on benign undefined behaviour on overflow
to detect overflow (after it gave undefined behaviour by occurring)
when adding up iov_len's to get uio_resid.  The bug didn't require
passing a buffer of size  INT_MAX to reach -- it just required a
single or multiple iov_len whose total size exceeded INT_MAX.  FreeBSD
fixed this in 2003.

size_t for iov_len is bogus even if the limit is SSIZE max.  It allows
a single iov to have a size that cannot work, and n iov's to have a
size almost 2*n times too large to work.  Unfortunately, POSIX
standardizes the type of iov_len as size_t.  It is interesting that
POSIX says shall fail for readv() when the sum of the iov_len values
overflowed [sic] an ssize_t.  For read(), the behaviour when the count
exceeds {SSIZE_MAX} is implementation-defined.  This gives the silly
possibility that read() can work for a size that is almost twice as
large as readv(), using a single count instead of an array of counts.
It is also strange that readv() refers to ssize_t while read() refers
to {SSIZE_MAX}.  POSIX standardizes the bug that {SSIZE_MAX} is the
limit of the type, although that may be unrelated to sizes that can
work.  If these APIs had been correctly designed, then the limit would
be {READ_MAX} and unrelated to any size type (except that the type
must be large enough to represent {READ_MAX}).  It would normally be
INT_MAX or much smaller.  readv() also has the bogus specification
that if iovcnt is = 0 or  {IOV_MAX}, then failure is optional.
So failure is optional for a hard error like iovcnt  {IOV_MAX},
but is required for a condition that is not required to be an error
for a similar API (count  {SSIZE_MAX}).  I only checked a 2001
draft for this.  Maybe some of these bugs have been fixed.


What I can do, is to commit all changes except removals of the checks
for INT_MAX. After type changes settle, I can try to gather enough
bravery to flip the checks in HEAD, possibly with temporary sysctl
to return to old behaviour for emergency (AKA hole).




diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
index 9edcb74..332ec37 100644
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c

[...]

@@ -757,14 +757,14 @@ pipe_build_write_buffer(wpipe, uio)
   struct pipe *wpipe;
   struct uio *uio;
 {
-   u_int size;
+   size_t size;
int i;

PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
KASSERT(wpipe-pipe_state  PIPE_DIRECTW,
  (Clone attempt on non-direct write pipe!));

-   size = (u_int) uio-uio_iov-iov_len;
+   size = uio-uio_iov-iov_len;
if (size  wpipe-pipe_buffer.size)
   size = wpipe-pipe_buffer.size;


The transfer can't be bigger than the max pipe buffer size (64k),
so `size = (int)MIN(uio-uio_iov-iov_len, wpipe-pipe_buffer.size)'
should suffice.  The same comment applies elsewhere in the file.


True. If you much prefer this version, I will change the patch. But I do
think that my changes are cleaner.


size_t is a bogus type for `size', since it must still be a u_int to
work.  For example, when it is assigned to the u_int wpipe-pipe_map.cnt.
This shouldn't be fixed by bloating the type to size_t throughout
(any global change should be to int to give suitably undefined behaviour
on overflow).  There must be an implicit or explicit check on it
somewhere that it fits.  This check is provided by the comparison with
wpipe-pipe_buffer.size.  But the above is a bad way to write it --
it should be checked before assignment, to avoid any possibility of
overflow or sign extension of either operand before the check:

u_int size;

if (uio-uio_iov-iov_len  wpipe-pipe_buffer.size)
size = wpipe-pipe_buffer.size;
else
size = uio-uio_iov-iov_len;

This is the same as the MIN() expression (without a bogus cast).  I
think I want to write it out verbosely like this and not use MIN(),
even if MIN() were not a style bug, to make it clear that this is
a correct bounds check.

Bruce
___

Re: svn commit: r230583 - head/sys/kern

2012-01-31 Thread David Schultz
On Tue, Jan 31, 2012, Konstantin Belousov wrote:
 On Mon, Jan 30, 2012 at 02:07:03PM -0500, David Schultz wrote:
  On Mon, Jan 30, 2012, Kostik Belousov wrote:
   On Sun, Jan 29, 2012 at 05:39:04PM -0500, David Schultz wrote:
On Sun, Jan 29, 2012, Kostik Belousov wrote:
 On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:
  On Sat, Jan 28, 2012, Kostik Belousov wrote:
   On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
The correct limit on the maximum size of a single read/write is
SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
limit yet, though, because of bugs in several filesystems.  For
example, FFS copies uio_resid into a local variable of type int.
I have some old patches that fix some of these issues for FFS 
and
cd9660, but surely there are more places I didn't notice.

   Absolutely agree.
   
   http://people.freebsd.org/~kib/misc/uio_resid.5.patch
  
  Nice.  You found a lot more than I've got in my tree, and you even
  fixed the return values.  There are at least a few more places to
  fix.  For instance, cd9660 and the NFS client pass uio_resid or
  iov_len to min(), which operates on ints.  (Incidentally, C11
  generics ought to make it possible to write type-generic min()
  and max() functions.)
 
 Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
 changed them to MIN().

This looks good to me.  I tried to think of other places that you
might have missed, and the only one that occurred to me is the
   Might ? I think this is a blatant understate.
   
pipe code.  sys_pipe.c has an `int orig_resid' and lots of bogus
casts of iov_len and uio_resid to type u_int.  Some look harmless,
although it appears that writing a multiple of 2^32 bytes might
result in pipe_build_write_buffer() allocating a 0-length buffer.

My only reservation is that raising the limit could unmask a
kernel buffer overflow if we missed something, but I guess we have
to cross that bridge some day anyway.
   Yes, and it is an obvious reason why I am chicken to commit this for
   so long time. One more place, if this is reasonable to count as 'one'
   place, are the cdevsw methods. devfs passes uio down to the drivers.
  
  That's why I'm glad I'm not committing it. :)  A more conservative
  change (also known as kicking the can down the road) would be to
  add a VFS flag, e.g., VFCF_LONGIO, and only set it on file systems
  that have been thoroughly reviewed.  The VFS layer could cap the size
  at INT_MAX for file systems without the flag.
 At least I will get more mail after the commit, I hope.
 
 I disagree with the VFCF_LONGIO approach. It will cause much head-scratching
 for unsuspecting user who would try to use  4GB transfers.
 
 What I can do, is to commit all changes except removals of the checks
 for INT_MAX. After type changes settle, I can try to gather enough
 bravery to flip the checks in HEAD, possibly with temporary sysctl
 to return to old behaviour for emergency (AKA hole).

That sounds like a good plan to me.

As an aside, I wonder if we could convince the clang folks to add
a warning similar to `lint -a', which complains about every long-int
narrowing conversion that doesn't have an explicit cast.  Modern
languages such as Java and C# require casts for narrowing
conversions, and I'd be a lot more confident about this change if
we did the same for the FreeBSD kernel.

   diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
   index 9edcb74..332ec37 100644
   --- a/sys/kern/sys_pipe.c
   +++ b/sys/kern/sys_pipe.c
  [...]
   @@ -757,14 +757,14 @@ pipe_build_write_buffer(wpipe, uio)
  struct pipe *wpipe;
  struct uio *uio;
{
   - u_int size;
   + size_t size;
 int i;

 PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
 KASSERT(wpipe-pipe_state  PIPE_DIRECTW,
   (Clone attempt on non-direct write pipe!));

   - size = (u_int) uio-uio_iov-iov_len;
   + size = uio-uio_iov-iov_len;
 if (size  wpipe-pipe_buffer.size)
size = wpipe-pipe_buffer.size;
  
  The transfer can't be bigger than the max pipe buffer size (64k),
  so `size = (int)MIN(uio-uio_iov-iov_len, wpipe-pipe_buffer.size)'
  should suffice.  The same comment applies elsewhere in the file.
 
 True. If you much prefer this version, I will change the patch. But I do
 think that my changes are cleaner.

I don't mind either way.  I haven't touched anything remotely
close to that code in years.
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-30 Thread David Schultz
On Mon, Jan 30, 2012, Kostik Belousov wrote:
 On Sun, Jan 29, 2012 at 05:39:04PM -0500, David Schultz wrote:
  On Sun, Jan 29, 2012, Kostik Belousov wrote:
   On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:
On Sat, Jan 28, 2012, Kostik Belousov wrote:
 On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
  The correct limit on the maximum size of a single read/write is
  SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
  limit yet, though, because of bugs in several filesystems.  For
  example, FFS copies uio_resid into a local variable of type int.
  I have some old patches that fix some of these issues for FFS and
  cd9660, but surely there are more places I didn't notice.
  
 Absolutely agree.
 
 http://people.freebsd.org/~kib/misc/uio_resid.5.patch

Nice.  You found a lot more than I've got in my tree, and you even
fixed the return values.  There are at least a few more places to
fix.  For instance, cd9660 and the NFS client pass uio_resid or
iov_len to min(), which operates on ints.  (Incidentally, C11
generics ought to make it possible to write type-generic min()
and max() functions.)
   
   Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
   changed them to MIN().
  
  This looks good to me.  I tried to think of other places that you
  might have missed, and the only one that occurred to me is the
 Might ? I think this is a blatant understate.
 
  pipe code.  sys_pipe.c has an `int orig_resid' and lots of bogus
  casts of iov_len and uio_resid to type u_int.  Some look harmless,
  although it appears that writing a multiple of 2^32 bytes might
  result in pipe_build_write_buffer() allocating a 0-length buffer.
  
  My only reservation is that raising the limit could unmask a
  kernel buffer overflow if we missed something, but I guess we have
  to cross that bridge some day anyway.
 Yes, and it is an obvious reason why I am chicken to commit this for
 so long time. One more place, if this is reasonable to count as 'one'
 place, are the cdevsw methods. devfs passes uio down to the drivers.

That's why I'm glad I'm not committing it. :)  A more conservative
change (also known as kicking the can down the road) would be to
add a VFS flag, e.g., VFCF_LONGIO, and only set it on file systems
that have been thoroughly reviewed.  The VFS layer could cap the size
at INT_MAX for file systems without the flag.

 diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
 index 9edcb74..332ec37 100644
 --- a/sys/kern/sys_pipe.c
 +++ b/sys/kern/sys_pipe.c
[...]
 @@ -757,14 +757,14 @@ pipe_build_write_buffer(wpipe, uio)
struct pipe *wpipe;
struct uio *uio;
  {
 - u_int size;
 + size_t size;
   int i;
  
   PIPE_LOCK_ASSERT(wpipe, MA_NOTOWNED);
   KASSERT(wpipe-pipe_state  PIPE_DIRECTW,
 (Clone attempt on non-direct write pipe!));
  
 - size = (u_int) uio-uio_iov-iov_len;
 + size = uio-uio_iov-iov_len;
   if (size  wpipe-pipe_buffer.size)
  size = wpipe-pipe_buffer.size;

The transfer can't be bigger than the max pipe buffer size (64k),
so `size = (int)MIN(uio-uio_iov-iov_len, wpipe-pipe_buffer.size)'
should suffice.  The same comment applies elsewhere in the file.
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-29 Thread Bruce Evans

On Sun, 29 Jan 2012, Kostik Belousov wrote:


On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:

On Sat, Jan 28, 2012, Kostik Belousov wrote:

On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:

On Fri, Jan 27, 2012, Kostik Belousov wrote:

On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:

On Thu, 26 Jan 2012, Gleb Smirnoff wrote:


On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
B   return (error);
B   }
B 
B  +/* XXX: aio_nbytes is later casted to signed types. */
B  +if ((int)aiocbe-uaiocb.aio_nbytes  0) {
B
B This should avoid implementation-defined behaviour by checking if
B
B   (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.



Is the attached patch okay?


Yes.  It now matches the style used for read^Wsys_read() and friends.
This used to have to fit the count in int uio_resid.  uio_resid now
has type ssize_t, but for some reason the old INT_MAX limits remain.


Well, I can revive the patch. I still think it is good to get rid of
the limit.


The correct limit on the maximum size of a single read/write is
SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
limit yet, though, because of bugs in several filesystems.  For
example, FFS copies uio_resid into a local variable of type int.
I have some old patches that fix some of these issues for FFS and
cd9660, but surely there are more places I didn't notice.


Absolutely agree.

http://people.freebsd.org/~kib/misc/uio_resid.5.patch


Nice.  You found a lot more than I've got in my tree, and you even
fixed the return values.  There are at least a few more places to
fix.  For instance, cd9660 and the NFS client pass uio_resid or
iov_len to min(), which operates on ints.  (Incidentally, C11
generics ought to make it possible to write type-generic min()
and max() functions.)


So does gnu typeof(), and much more portably in practice (we're still
waiting for a C99 compiler).


Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
changed them to MIN().


Ugh, the existence of MIN() is API breakage (similarly for MAX()):
- in FreeBSD-1 (and probably in Net/2), MIN() was min() in the kernel,
  where min() was an extern function with the same semantics as the
  current inline min().  This was quite broken, since MIN() is almost
  type-generic, while min() forces everything to u_int.  min() was
  implemented in kern/subr_xxx.c.  FreeBSD-1 (and maybe Net/2) also
  had imin/max(), lmin/max() and ulmin/max() there.
- 4.4BSD completed removing MIN() in the kernel.  It was left undefined.
  This was fragile, and probably still more broken than old code that
  used MIN(), since the conversions given by prototypes combined with
  no warnings for dangerous conversions tend to give even more sign
  extension and overflow bugs that the implicit conversions in MIN().
- MIN() remained intentionally left out in the kernel in FreeBSD-[2-4].
  Some contribed code that didn't know the BSD API rolled its own MIN()
  and used that.  There are no less than 38 home made definitions of
  MIN() in FreeBSD-4 to replace the one that is intentionally left
  out :-(.  Some of these are ifdefed, but since the system doesn't
  have MIN(), they are always used.
- the API was broken in FreeBSD-5 by removing the ifdef that left out
  MIN().
- even more code that doesn't know the old BSD API now uses MIN().
  Now there are only 16 home made definitions of MIN().  Most of these
  are ifdefed.

I have had (but not used) the following fairly type-generic and safe
macros for min() since FreeBSD-~2.0:

% Index: libkern.h
% ===
% RCS file: /home/ncvs/src/sys/sys/libkern.h,v
% retrieving revision 1.45
% diff -u -2 -r1.45 libkern.h
% --- libkern.h 7 Apr 2004 04:19:49 -   1.45
% +++ libkern.h 7 Apr 2004 11:31:02 -
% @@ -49,4 +51,74 @@
%  #define  hex2ascii(hex)  (hex2ascii_data[hex])
% 
% +#if 0

% +#define __max(x, y)  \
% +({   \
% + __typeof(x) __x = (x);  \
% + __typeof(y) __y = (y);  \
% + __x  __y ? __x : __y;   \
% +})
% +
% +#define __min(x, y)  \
% +({   \
% + __typeof(x) __x = (x);  \
% + __typeof(y) __y = (y);  \
% + __x  __y ? __x : __y;   \
% +})
% +#endif

Normal use of gnu typeof() to write safe type-generic macros for things
like this.  This is almost verbatime from gcc.info.

% +
% +#define __max(x, y)  \
% +(\
% + (sizeof(x) == 8 || sizeof(y) == 8) ?\
% + ((__typeof(x))-1 == -1  (__typeof(y))-1 == -1) ?  \
% + _qmax((x), (y)) \
% + :   \
% + _uqmax((x), (y))   

Re: svn commit: r230583 - head/sys/kern

2012-01-29 Thread David Schultz
On Sun, Jan 29, 2012, Kostik Belousov wrote:
 On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:
  On Sat, Jan 28, 2012, Kostik Belousov wrote:
   On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
On Fri, Jan 27, 2012, Kostik Belousov wrote:
 On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:
  On Thu, 26 Jan 2012, Gleb Smirnoff wrote:
  
  On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
  B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct 
  aio
  Breturn (error);
  B}
  B 
  B  + /* XXX: aio_nbytes is later casted to signed types. */
  B  + if ((int)aiocbe-uaiocb.aio_nbytes  0) {
  B
  B This should avoid implementation-defined behaviour by checking 
  if
  B
  B (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.
  
  Is the attached patch okay?
  
  Yes.  It now matches the style used for read^Wsys_read() and 
  friends.
  This used to have to fit the count in int uio_resid.  uio_resid 
  now
  has type ssize_t, but for some reason the old INT_MAX limits remain.
 
 Well, I can revive the patch. I still think it is good to get rid of
 the limit.

The correct limit on the maximum size of a single read/write is
SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
limit yet, though, because of bugs in several filesystems.  For
example, FFS copies uio_resid into a local variable of type int.
I have some old patches that fix some of these issues for FFS and
cd9660, but surely there are more places I didn't notice.

   Absolutely agree.
   
   http://people.freebsd.org/~kib/misc/uio_resid.5.patch
  
  Nice.  You found a lot more than I've got in my tree, and you even
  fixed the return values.  There are at least a few more places to
  fix.  For instance, cd9660 and the NFS client pass uio_resid or
  iov_len to min(), which operates on ints.  (Incidentally, C11
  generics ought to make it possible to write type-generic min()
  and max() functions.)
 
 Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
 changed them to MIN().

This looks good to me.  I tried to think of other places that you
might have missed, and the only one that occurred to me is the
pipe code.  sys_pipe.c has an `int orig_resid' and lots of bogus
casts of iov_len and uio_resid to type u_int.  Some look harmless,
although it appears that writing a multiple of 2^32 bytes might
result in pipe_build_write_buffer() allocating a 0-length buffer.

My only reservation is that raising the limit could unmask a
kernel buffer overflow if we missed something, but I guess we have
to cross that bridge some day anyway.
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-29 Thread Kostik Belousov
On Sun, Jan 29, 2012 at 05:39:04PM -0500, David Schultz wrote:
 On Sun, Jan 29, 2012, Kostik Belousov wrote:
  On Sat, Jan 28, 2012 at 07:12:25PM -0500, David Schultz wrote:
   On Sat, Jan 28, 2012, Kostik Belousov wrote:
On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
 On Fri, Jan 27, 2012, Kostik Belousov wrote:
  On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:
   On Thu, 26 Jan 2012, Gleb Smirnoff wrote:
   
   On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
   B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct 
   aio
   B  return (error);
   B  }
   B 
   B  +   /* XXX: aio_nbytes is later casted to signed types. */
   B  +   if ((int)aiocbe-uaiocb.aio_nbytes  0) {
   B
   B This should avoid implementation-defined behaviour by 
   checking if
   B
   B   (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.
   
   Is the attached patch okay?
   
   Yes.  It now matches the style used for read^Wsys_read() and 
   friends.
   This used to have to fit the count in int uio_resid.  uio_resid 
   now
   has type ssize_t, but for some reason the old INT_MAX limits 
   remain.
  
  Well, I can revive the patch. I still think it is good to get rid of
  the limit.
 
 The correct limit on the maximum size of a single read/write is
 SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
 limit yet, though, because of bugs in several filesystems.  For
 example, FFS copies uio_resid into a local variable of type int.
 I have some old patches that fix some of these issues for FFS and
 cd9660, but surely there are more places I didn't notice.
 
Absolutely agree.

http://people.freebsd.org/~kib/misc/uio_resid.5.patch
   
   Nice.  You found a lot more than I've got in my tree, and you even
   fixed the return values.  There are at least a few more places to
   fix.  For instance, cd9660 and the NFS client pass uio_resid or
   iov_len to min(), which operates on ints.  (Incidentally, C11
   generics ought to make it possible to write type-generic min()
   and max() functions.)
  
  Thank you, http://people.freebsd.org/~kib/misc/uio_resid.6.patch
  changed them to MIN().
 
 This looks good to me.  I tried to think of other places that you
 might have missed, and the only one that occurred to me is the
Might ? I think this is a blatant understate.

 pipe code.  sys_pipe.c has an `int orig_resid' and lots of bogus
 casts of iov_len and uio_resid to type u_int.  Some look harmless,
 although it appears that writing a multiple of 2^32 bytes might
 result in pipe_build_write_buffer() allocating a 0-length buffer.
 
 My only reservation is that raising the limit could unmask a
 kernel buffer overflow if we missed something, but I guess we have
 to cross that bridge some day anyway.
Yes, and it is an obvious reason why I am chicken to commit this for
so long time. One more place, if this is reasonable to count as 'one'
place, are the cdevsw methods. devfs passes uio down to the drivers.

http://people.freebsd.org/~kib/misc/uio_resid.7.patch
contains the sys_pipe.c changes.


pgpOSaHOEp5Rh.pgp
Description: PGP signature


Re: svn commit: r230583 - head/sys/kern

2012-01-28 Thread Kostik Belousov
On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
 On Fri, Jan 27, 2012, Kostik Belousov wrote:
  On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:
   On Thu, 26 Jan 2012, Gleb Smirnoff wrote:
   
   On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
   B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
   B  return (error);
   B  }
   B 
   B  +   /* XXX: aio_nbytes is later casted to signed types. */
   B  +   if ((int)aiocbe-uaiocb.aio_nbytes  0) {
   B
   B This should avoid implementation-defined behaviour by checking if
   B
   B   (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.
   
   Is the attached patch okay?
   
   Yes.  It now matches the style used for read^Wsys_read() and friends.
   This used to have to fit the count in int uio_resid.  uio_resid now
   has type ssize_t, but for some reason the old INT_MAX limits remain.
  
  Well, I can revive the patch. I still think it is good to get rid of
  the limit.
 
 The correct limit on the maximum size of a single read/write is
 SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
 limit yet, though, because of bugs in several filesystems.  For
 example, FFS copies uio_resid into a local variable of type int.
 I have some old patches that fix some of these issues for FFS and
 cd9660, but surely there are more places I didn't notice.
 
Absolutely agree.

http://people.freebsd.org/~kib/misc/uio_resid.5.patch

 By the way, PR 147226 is about this.


pgpcFsmpLEZVe.pgp
Description: PGP signature


Re: svn commit: r230583 - head/sys/kern

2012-01-28 Thread David Schultz
On Sat, Jan 28, 2012, Kostik Belousov wrote:
 On Fri, Jan 27, 2012 at 02:42:21PM -0500, David Schultz wrote:
  On Fri, Jan 27, 2012, Kostik Belousov wrote:
   On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:
On Thu, 26 Jan 2012, Gleb Smirnoff wrote:

On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
Breturn (error);
B}
B 
B  + /* XXX: aio_nbytes is later casted to signed types. */
B  + if ((int)aiocbe-uaiocb.aio_nbytes  0) {
B
B This should avoid implementation-defined behaviour by checking if
B
B (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.

Is the attached patch okay?

Yes.  It now matches the style used for read^Wsys_read() and friends.
This used to have to fit the count in int uio_resid.  uio_resid now
has type ssize_t, but for some reason the old INT_MAX limits remain.
   
   Well, I can revive the patch. I still think it is good to get rid of
   the limit.
  
  The correct limit on the maximum size of a single read/write is
  SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
  limit yet, though, because of bugs in several filesystems.  For
  example, FFS copies uio_resid into a local variable of type int.
  I have some old patches that fix some of these issues for FFS and
  cd9660, but surely there are more places I didn't notice.
  
 Absolutely agree.
 
 http://people.freebsd.org/~kib/misc/uio_resid.5.patch

Nice.  You found a lot more than I've got in my tree, and you even
fixed the return values.  There are at least a few more places to
fix.  For instance, cd9660 and the NFS client pass uio_resid or
iov_len to min(), which operates on ints.  (Incidentally, C11
generics ought to make it possible to write type-generic min()
and max() functions.)
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-27 Thread Bruce Evans

On Thu, 26 Jan 2012, Gleb Smirnoff wrote:


On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
B   return (error);
B   }
B 
B  +/* XXX: aio_nbytes is later casted to signed types. */
B  +if ((int)aiocbe-uaiocb.aio_nbytes  0) {
B
B This should avoid implementation-defined behaviour by checking if
B
B   (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.



Is the attached patch okay?


Yes.  It now matches the style used for read^Wsys_read() and friends.
This used to have to fit the count in int uio_resid.  uio_resid now
has type ssize_t, but for some reason the old INT_MAX limits remain.

Bruce
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-27 Thread Kostik Belousov
On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:
 On Thu, 26 Jan 2012, Gleb Smirnoff wrote:
 
 On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
 B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
 B  return (error);
 B  }
 B 
 B  +   /* XXX: aio_nbytes is later casted to signed types. */
 B  +   if ((int)aiocbe-uaiocb.aio_nbytes  0) {
 B
 B This should avoid implementation-defined behaviour by checking if
 B
 B   (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.
 
 Is the attached patch okay?
 
 Yes.  It now matches the style used for read^Wsys_read() and friends.
 This used to have to fit the count in int uio_resid.  uio_resid now
 has type ssize_t, but for some reason the old INT_MAX limits remain.

Well, I can revive the patch. I still think it is good to get rid of
the limit.


pgpl04w0rAyFf.pgp
Description: PGP signature


Re: svn commit: r230583 - head/sys/kern

2012-01-27 Thread David Schultz
On Fri, Jan 27, 2012, Kostik Belousov wrote:
 On Fri, Jan 27, 2012 at 07:50:30PM +1100, Bruce Evans wrote:
  On Thu, 26 Jan 2012, Gleb Smirnoff wrote:
  
  On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
  B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
  Breturn (error);
  B}
  B 
  B  + /* XXX: aio_nbytes is later casted to signed types. */
  B  + if ((int)aiocbe-uaiocb.aio_nbytes  0) {
  B
  B This should avoid implementation-defined behaviour by checking if
  B
  B (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.
  
  Is the attached patch okay?
  
  Yes.  It now matches the style used for read^Wsys_read() and friends.
  This used to have to fit the count in int uio_resid.  uio_resid now
  has type ssize_t, but for some reason the old INT_MAX limits remain.
 
 Well, I can revive the patch. I still think it is good to get rid of
 the limit.

The correct limit on the maximum size of a single read/write is
SSIZE_MAX, but FreeBSD uses INT_MAX.  It's not safe to raise the
limit yet, though, because of bugs in several filesystems.  For
example, FFS copies uio_resid into a local variable of type int.
I have some old patches that fix some of these issues for FFS and
cd9660, but surely there are more places I didn't notice.

By the way, PR 147226 is about this.
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-26 Thread Bruce Evans

On Thu, 26 Jan 2012, Gleb Smirnoff wrote:


Log:
 Although aio_nbytes is size_t, later is is signed to
 casted types: to ssize_t in filesystem code and to
 int in buf code, thus supplying a negative argument
 leads to kernel panic later.


And supplying a large positive argument leads to undefined
behaviour later in the buf case.


To fix that check user
 supplied argument in the beginning of syscall.


Now, supplying a large positive argument gives implementation-
defined behaviour immediately.  Sometimes the implementation-
defined behaviour is to have no effect immediately and allow
a panic later.


Modified: head/sys/kern/vfs_aio.c
==
--- head/sys/kern/vfs_aio.c Thu Jan 26 11:15:12 2012(r230582)
+++ head/sys/kern/vfs_aio.c Thu Jan 26 11:59:48 2012(r230583)
@@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
return (error);
}

+   /* XXX: aio_nbytes is later casted to signed types. */
+   if ((int)aiocbe-uaiocb.aio_nbytes  0) {


This should avoid implementation-defined behaviour by checking if

(uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.

It isn't clear what the effects of the implementation-defined behaviour
are even when you know what it is.  It certainly results in the
check passing values that exceed INT_MAX.  For example, with 32-bit
int and 64-bit size_t, and everything 2's complement, and no perverse
implementation-defined behaviour like the result of converting to
int when the argment exceeds INT_MAX is always 42, then
(int)0x1000 is 0.


+   uma_zfree(aiocb_zone, aiocbe);
+   return (EINVAL);
+   }
+
if (aiocbe-uaiocb.aio_sigevent.sigev_notify != SIGEV_KEVENT 
aiocbe-uaiocb.aio_sigevent.sigev_notify != SIGEV_SIGNAL 
aiocbe-uaiocb.aio_sigevent.sigev_notify != SIGEV_THREAD_ID 


Bruce
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org


Re: svn commit: r230583 - head/sys/kern

2012-01-26 Thread Gleb Smirnoff
  Bruce,

On Thu, Jan 26, 2012 at 11:53:57PM +1100, Bruce Evans wrote:
B  Log:
B   Although aio_nbytes is size_t, later is is signed to
B   casted types: to ssize_t in filesystem code and to
B   int in buf code, thus supplying a negative argument
B   leads to kernel panic later.
B 
B And supplying a large positive argument leads to undefined
B behaviour later in the buf case.
B 
B  To fix that check user
B   supplied argument in the beginning of syscall.
B 
B Now, supplying a large positive argument gives implementation-
B defined behaviour immediately.  Sometimes the implementation-
B defined behaviour is to have no effect immediately and allow
B a panic later.
B 
B  Modified: head/sys/kern/vfs_aio.c
B  
==
B  --- head/sys/kern/vfs_aio.cThu Jan 26 11:15:12 2012
(r230582)
B  +++ head/sys/kern/vfs_aio.cThu Jan 26 11:59:48 2012
(r230583)
B  @@ -1552,6 +1552,12 @@ aio_aqueue(struct thread *td, struct aio
B return (error);
B }
B 
B  +  /* XXX: aio_nbytes is later casted to signed types. */
B  +  if ((int)aiocbe-uaiocb.aio_nbytes  0) {
B 
B This should avoid implementation-defined behaviour by checking if
B 
B  (uncast)aiocbe-uaiocb.aio_nbytes  INT_MAX.
B 
B It isn't clear what the effects of the implementation-defined behaviour
B are even when you know what it is.  It certainly results in the
B check passing values that exceed INT_MAX.  For example, with 32-bit
B int and 64-bit size_t, and everything 2's complement, and no perverse
B implementation-defined behaviour like the result of converting to
B int when the argment exceeds INT_MAX is always 42, then
B (int)0x1000 is 0.

Is the attached patch okay?

-- 
Totus tuus, Glebius.
Index: vfs_aio.c
===
--- vfs_aio.c	(revision 230585)
+++ vfs_aio.c	(working copy)
@@ -1553,7 +1553,7 @@
 	}
 
 	/* XXX: aio_nbytes is later casted to signed types. */
-	if ((int)aiocbe-uaiocb.aio_nbytes  0) {
+	if (aiocbe-uaiocb.aio_nbytes  INT_MAX) {
 		uma_zfree(aiocb_zone, aiocbe);
 		return (EINVAL);
 	}
___
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to svn-src-head-unsubscr...@freebsd.org