On Fri, Mar 13, 2020, at 11:45 AM Otto Moerbeek <[email protected]> wrote:
>
> Please indent your code snippets.
yeah, my apologies. I shall indent the code snippets.

>
> di_info is special. Having a guard page on both sides for regular
> allocation can be done, but would waste more pages. Note that
> allocations are already spread throughout the address space, so it is
> very likely that an allocation is surrounded by unmapped pages.
>
Okay, So, as from omalloc_poolinit() code it is not there, but we can do
but it will be wastage of one-page memory and also entire address space is
spread with unmapped pages. So, it is very likely that there will some
unmapped page beside dir_info in the memory.

>
> We need two pages to store dir_info.
>
>
> > Now, MMAPNONE maps up to len (8192 + (4096 * 2)) = 16384
>
> We allocate 4 pages prot none.
>
> > then, mprotecting the pages through p + MALLOC_PAGESIZE + DIR_INFO_RSZ
- 1
>
> the two middle pages are r/w.
>
> > d_avail = (8192 - 4824) >> 4 = 3368 >> 4 = 210
> >
> > Now, d = (p + MALLOC_PAGESIZE + (random_no_under_210 << 4)
>
> di_info ends up on an aligned address somewhere in the middle pages on
> an offset between 0 and (210<<4) = 0..3360, counting from the start of
> the two middle pages.
Thank you for the information. So, it is like [(p + MALLOC_PAGESIZE) +
(0..3360)]. It is kind of like array, For example, let's suppose, x = p +
MALLOC_PAGESIZE. So, it will be x[0..3360].
Am I right?
>
> MALLOC_CHUNK_LISTS could be increased at the cost of overhead.
> MALLOC_MAXSHIFT cannot, it is the shift of the max chunk size that fits in
> a page.
Okay. I understood. And, yeah more randomization means more cost overhead.

Thank you, Otto, for your detailed information.

Please find the code below:

948     /*
949      * Allocate a chunk
950      */
951     static void *
952     malloc_bytes(struct dir_info *d, size_t size, void *f)
953     {
954             u_int i, r;
955             int j, listnum;
956             size_t k;
957             u_short *lp;
958             struct chunk_info *bp;
959             void *p;
960     
961             if (mopts.malloc_canary != (d->canary1 ^ 
(u_int32_t)(uintptr_t)d) ||
962                 d->canary1 != ~d->canary2)
963                     wrterror(d, "internal struct corrupt");
964     
965             j = find_chunksize(size);
966     
967             r = ((u_int)getrbyte(d) << 8) | getrbyte(d);
968             listnum = r % MALLOC_CHUNK_LISTS;
969             /* If it's empty, make a page more of that size chunks */
970             if ((bp = LIST_FIRST(&d->chunk_dir[j][listnum])) == NULL) {
971                     bp = omalloc_make_chunks(d, j, listnum);
972                     if (bp == NULL)
973                             return NULL;
974             }
975     
976             if (bp->canary != (u_short)d->canary1)
977                     wrterror(d, "chunk info corrupted");


Here, in the code mentioned above, we can see that on line 961 and
line 976. I don't understand why it is checking for
canaries of malloc_readonly with d and then allocated chunk bp with d,
because I have seen that validation of canary
happens in free(3) not in malloc(3). So, it is like there may be some
cases where one can corrupt these also??


978     
979             i = (r / MALLOC_CHUNK_LISTS) & (bp->total - 1);
980     
981             /* start somewhere in a short */
982             lp = &bp->bits[i / MALLOC_BITS];
983             if (*lp) {
984                     j = i % MALLOC_BITS;
985                     k = ffs(*lp >> j);
986                     if (k != 0) {
987                             k += j - 1;
988                             goto found;
989                     }
990             }
991             /* no bit halfway, go to next full short */
992             i /= MALLOC_BITS;
993             for (;;) {
994                     if (++i >= bp->total / MALLOC_BITS)
995                             i = 0;
996                     lp = &bp->bits[i];
997                     if (*lp) {
998                             k = ffs(*lp) - 1;
999                             break;
1000                    }
1001            }
1002    found:
1003    #ifdef MALLOC_STATS
1004            if (i == 0 && k == 0) {
1005                    struct region_info *r = find(d, bp->page);
1006                    r->f = f;
1007            }
1008    #endif
1009    
1010            *lp ^= 1 << k;
1011    
1012            /* If there are no more free, remove from free-list */
1013            if (--bp->free == 0)
1014                    LIST_REMOVE(bp, entries);
1015    
1016            /* Adjust to the real offset of that chunk */
1017            k += (lp - bp->bits) * MALLOC_BITS;
1018    
1019            if (mopts.chunk_canaries && size > 0)
1020                    bp->bits[bp->offset + k] = size;
1021    
1022            k <<= bp->shift;
1023    
1024            p = (char *)bp->page + k;
1025            if (bp->size > 0) {
1026                    if (d->malloc_junk == 2)
1027                            memset(p, SOME_JUNK, bp->size);
1028                    else if (mopts.chunk_canaries)
1029                            fill_canary(p, size, bp->size);
1030            }
1031            return p;
1032    }

And, the calculations above, is it for calculating the offset in the page,
that is, k. Because I have seen that during free(3) operations, it again
calculates this offset to find the same. So, is it doing only offset
calculation?

Please confirm.

Regards,
Neeraj

Reply via email to