Skip to content

Crash when calling mm_mapopt_update() due to NULL pointer dereference #1147

@blawrence-ont

Description

@blawrence-ont

Crash seen when calling mm_mapopt_update() due to NULL pointer dereference. Minimised repro case:

#include "minimap.h"

int main()
{
    mm_idxopt_t idx_opt;
    mm_mapopt_t map_opt;
    mm_set_opt(0, &idx_opt, &map_opt);
    mm_set_opt("map-hifi", &idx_opt, &map_opt);

    const char *seq = "ACGT";
    const char *name = "query";
    mm_idx_t *index = mm_idx_str(idx_opt.w, idx_opt.k, 0, idx_opt.bucket_bits, 1, &seq, &name);
    mm_mapopt_update(&map_opt, index);
}

This doesn't repro on every system due to implementation defined behaviour of malloc(0). However ASAN can show the issue on macOS (Linux's glibc doesn't have the same allocation strategy so ASAN doesn't highlight the issue there):

$ git clone https://github.com/lh3/minimap2.git
$ cd minimap2
$ make asan=1 -j 8
$ cc -fsanitize=address libminimap2.a -lm -lz -lpthread repro.c
$ ./a.out
==93948==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x000106e006b0 at pc 0x000104114c94 bp 0x00016bcf2f50 sp 0x00016bcf2f48
READ of size 4 at 0x000106e006b0 thread T0
    #0 0x104114c90 in ks_ksmall_uint32_t misc.c
    #1 0x10411edfc in mm_idx_cal_max_occ index.c:205
    #2 0x104119d30 in mm_mapopt_update options.c:72
    #3 0x104127af0 in main+0x3d4 (a.out:arm64+0x10001baf0)
    #4 0x180c610dc  (<unknown module>)

0x000106e006b1 is located 0 bytes after 1-byte region [0x000106e006b0,0x000106e006b1)
allocated by thread T0 here:
    #0 0x1049e3244 in wrap_malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x53244)
    #1 0x10411eec0 in mm_idx_cal_max_occ index.c:196
    #2 0x104119d30 in mm_mapopt_update options.c:72
    #3 0x104127af0 in main+0x3d4 (a.out:arm64+0x10001baf0)
    #4 0x180c610dc  (<unknown module>)

The allocation can be traced back to the line:

a = (uint32_t*)malloc(n * 4);

At this point n == 0 and hence a cannot be dereferenced, however ks_ksmall_uint32_t() does this here (since both high and low are 0):

if (high <= low) return *k;

Suggestion was made for the following in mm_idx_cal_max_occ() to match the f <= 0. check:

+if (n == 0) return INT32_MAX;
 a = (uint32_t*)malloc(n * 4);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions