Hi,

when p->p_rlimit[RLIMIT_DATA].rlim_cur < ptoa(p->p_vmspace->vm_dused),
the following comparison fails because the subtraction wraps around
to huge positive values.

I noticed this because i tried to do systematic testing of specific
malloc failure codepaths.  But whenever i used setrlimit(2) to set
a low RLIMIT_DATA, a subsequent malloc(3) with a big argument always
succeeded.

It may be unsusual for a program to lower its own RLIMIT_DATA, and
i'm neither sure whether there are other use cases besides testing
nor whether there are other ways to arrive in a situation with
p->p_rlimit[RLIMIT_DATA].rlim_cur < ptoa(p->p_vmspace->vm_dused)
besides late setrlimit(2) to a low value.

But even if there are no use cases besides testing, do we want
to have an unsigned comparison in the kernel that can wrap around?

I can hardly believe i'm sending such a diff...  :-o

I'm running it right now.  So far, i noticed no regressions,
and testing of malloc failure codepaths has become much easier.
I consider that useful to make out software better.

What do you think?

Yours,
  Ingo


Index: uvm/uvm_mmap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_mmap.c,v
retrieving revision 1.130
diff -u -p -r1.130 uvm_mmap.c
--- uvm/uvm_mmap.c      1 Jun 2016 04:53:54 -0000       1.130
+++ uvm/uvm_mmap.c      2 Jun 2016 01:23:20 -0000
@@ -526,8 +526,9 @@ sys_mmap(struct proc *p, void *v, regist
                }
                if ((flags & MAP_ANON) != 0 ||
                    ((flags & MAP_PRIVATE) != 0 && (prot & PROT_WRITE) != 0)) {
-                       if (size >
-                           (p->p_rlimit[RLIMIT_DATA].rlim_cur - 
ptoa(p->p_vmspace->vm_dused))) {
+                       if (p->p_rlimit[RLIMIT_DATA].rlim_cur < size ||
+                           p->p_rlimit[RLIMIT_DATA].rlim_cur - size <
+                           ptoa(p->p_vmspace->vm_dused)) {
                                error = ENOMEM;
                                goto out;
                        }
@@ -545,8 +546,9 @@ is_anon:    /* label for SunOS style /dev/z
 
                if ((flags & MAP_ANON) != 0 ||
                    ((flags & MAP_PRIVATE) != 0 && (prot & PROT_WRITE) != 0)) {
-                       if (size >
-                           (p->p_rlimit[RLIMIT_DATA].rlim_cur - 
ptoa(p->p_vmspace->vm_dused))) {
+                       if (p->p_rlimit[RLIMIT_DATA].rlim_cur < size ||
+                           p->p_rlimit[RLIMIT_DATA].rlim_cur - size <
+                           ptoa(p->p_vmspace->vm_dused)) {
                                return ENOMEM;
                        }
                }

Reply via email to