RFC: chgsbsize doesn't handle -ve sbsize correctly
John Baldwin
jhb at freebsd.org
Mon Apr 6 19:19:25 UTC 2015
On Friday, April 03, 2015 07:38:59 AM Anuranjan Shukla wrote:
> Hi,
> In struct uidinfo{}, ui_sbsize member is an int. In a system with large
> number of sockets owned by a user it's possible for ui_sbsize to roll over
> to a negative value. When that happens, further calls to _increase_ sbsize
> don't detect this condition as they should per design. But when the
> sockets start shutting down this condition would be detected and you'll
> see the console prints ("negative sbsize for uid =") happen. As a worst
> case the console being flooded with these prints can create a DoS scenario
> (specially on single CPU systems).
>
> Regardless of the end result, the code itself needs to be fixed for
> correctness. There are two things to note:
> - Int doesn't seem to be the correct type for ui_sbsize. Should be a u_int
> atleast.
> - Since there's no real prevention of the overflow as it happens, the
> warning print isn't helpful and should be a DEBUG level log at best. If we
> change ui_sbsize to be a u_int, the negative check itself can go.
>
>
> int
> chgsbsize(uip, hiwat, to, max)
> {
> int diff;
>
> diff = to - *hiwat;
> if (diff > 0) {
> if (atomic_fetchadd_long(&uip->ui_sbsize, (long)diff) +
> diff > max) {
> <======= -ve ui_sbsize goes undetected and we'll pass the above
> check
> atomic_subtract_long(&uip->ui_sbsize, (long)diff);
> return (0);
> }
> } else {
> atomic_add_long(&uip->ui_sbsize, (long)diff);
> if (uip->ui_sbsize < 0)
> printf("negative sbsize for uid = %d\n",
> uip->ui_uid);
>
> <==== Now we'll detect, far too late, that sbsize went -ve
Note that ui_sbsize is long, not int. That doesn't help you on 32-bit
platforms, but you are also stuck with 32 bits since you typically don't
have 64-bit atomics on 32-bit platforms.
Making it unsigned just means you can't detect overflow anymore. Instead
I think it should be fixed to detect the overflow when increasing the size
and fail then. Several nearby functions would need the same fix btw:
Index: kern_resource.c
===================================================================
--- kern_resource.c (revision 281146)
+++ kern_resource.c (working copy)
@@ -1380,17 +1380,18 @@ chgproccnt(struct uidinfo *uip, int diff, rlim_t m
int
chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to, rlim_t max)
{
+ long new;
int diff;
diff = to - *hiwat;
+ new = atomic_fetchadd_long(&uip->ui_sbsize, (long)diff) + diff;
if (diff > 0) {
- if (atomic_fetchadd_long(&uip->ui_sbsize, (long)diff) + diff > max) {
+ if (new < 0 || new > max) {
atomic_subtract_long(&uip->ui_sbsize, (long)diff);
return (0);
}
} else {
- atomic_add_long(&uip->ui_sbsize, (long)diff);
- if (uip->ui_sbsize < 0)
+ if (new < 0)
printf("negative sbsize for uid = %d\n", uip->ui_uid);
}
*hiwat = to;
--
John Baldwin
More information about the freebsd-arch
mailing list