Bug 234494 - dns/maradns: Memory exhaustion crash with default config
Summary: dns/maradns: Memory exhaustion crash with default config
Status: In Progress
Alias: None
Product: Ports & Packages
Classification: Unclassified
Component: Individual Port(s) (show other bugs)
Version: Latest
Hardware: Any Any
: --- Affects Only Me
Assignee: Kenji Takefu
Keywords: crash, needs-qa
Depends on:
Reported: 2018-12-29 21:03 UTC by Nino
Modified: 2019-05-23 05:40 UTC (History)
1 user (show)

See Also:
antoine: exp-run-
koobs: merge-quarterly?

maradns-2.0.16.patch (2.61 KB, patch)
2019-01-07 06:58 UTC, takefu
takefu: maintainer-approval-
Details | Diff
maradns-2.0.16.patch (2.61 KB, patch)
2019-02-04 01:30 UTC, takefu
takefu: maintainer-approval+
Details | Diff
maradns-2.0.17.patch (2.76 KB, patch)
2019-04-19 08:15 UTC, takefu
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Nino 2018-12-29 21:03:39 UTC
12.0-RELEASE FreeBSD 12.0-RELEASE r341666 GENERIC  i386 w/ 512MB RAM

After upgrading the system to 12.0-RELEASE and updating MaraDNS to the latest package (2.0.15), MaraDNS started consistently crashing with the following error in the log:

Dec 28 12:58:31 srv /usr/local/sbin/maradns: Aieeeeee, can not allocate memory!

Traced the error to the following code section in js_alloc() in JsStrOS.c:

    data = (void *)malloc(unit_count * unit_size);
    if(data == NULL) {
        /* Securty: In a situtation where we can not allocate memory,
           the subsequent behavior of the program is undefined.  Hence,
           the best thing to do is exit then and there */
        printf("Aieeeeee, can not allocate memory!");
        return (void *)0;

Results in the following trace:

    mmap(0x0,20480,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) ERR#12 'Cannot allocate memory'
    write(1,"Aieeeeee, can not allocate memor"...,34) = 34 (0x22)

MaraDNS appears to limit memory usage itself to about 2.5MB by default:

    setrlimit(RLIMIT_VMEM,{ cur=2646016,max=2646016 }) = 0 (0x0)

I have checked the arguments to malloc (unit_count, unit_size) and the overall memory allocation and there doesn't appear to be a bug or a leak. While MaraDNS is not memory-hungry, it seems that small heap size and some heap fragmentation is enough to exhaust the available memory. 

Workaround is to add max_mem parameter to mararc config. I have set it to 8MB (in bytes) and that helped to avoid crash so far. Will keep monitoring and update the PR if further crashes are experienced.
Comment 1 Kubilay Kocak freebsd_committer freebsd_triage 2018-12-30 01:35:53 UTC
It's difficult to determine what a good (safe, reasonable) default configuration might be for most port/package users.

Docs state:

max_mem determined the maximum amount of memory MaraDNS is allowed to allocate. This is a numeric variable, and the value is in kilobytes. The default value of this is to allocate 1 megabyte for MaraDNS' general use, and in addition, to allocate 1536 bytes for each element we can have in the cache or DNS record that we are authoritatively serving.

If, for whatever reason, you wish to disable this feature, add the following lint to your mararc file:

max_mem = 0

The "and in addition" bit reads like the the max_mem value is variable based on the data that is being served. I have not verified this.

Is the default max_mem value specified statically in a configuration file that maradns uses out of the box for the freebsd ports/packages, or is it an internal default value if not specified in a configuration?
Comment 2 Nino 2018-12-30 04:17:56 UTC
The value is hard-coded in the source if there is no specific override value in the conf file:

    maxprocs = read_numeric_kvar("max_mem",
               1048576 + thread_overhead +
               ((cache_size + dns_records_served) * 1536));
    if(maxprocs < 262144 && maxprocs > 0) { maxprocs = 262144; }
    if(maxprocs > 0) {
      rlim.rlim_cur = rlim.rlim_max = maxprocs;
      if(setrlimit(MAX_MEM,&rlim) != 0) {

max_mem depends on the number of records served. In my case, I only have ~20 records, so the limit is still dominated with the (default) cache_size of 1024. In fact, with no records served, memory limit is exactly 2621440 (1048576+1024*1536) which possibly suggests this is a typo in the code (262144 instead of 2621440). 

NB - quoted documentation is wrong, max_mem is in bytes and not kilobytes (installed man page is correct).
Comment 3 takefu 2019-01-07 06:58:34 UTC
Created attachment 200858 [details]

Update to 2.0.16

  broken in 12.0-RELEASE.
  IPv6 support for sample files.
  portlint(1) complied.
Comment 4 takefu 2019-02-04 01:30:03 UTC
Created attachment 201702 [details]

fix server/MaraDNS.c
Comment 5 takefu 2019-04-19 08:15:41 UTC
Created attachment 203789 [details]

Update up 2.0.17
Comment 6 Kenji Takefu freebsd_committer 2019-04-22 02:53:59 UTC
(In reply to takefu from comment #5)