|
Description
|
Every time dlmgmtd needs to read or write /etc/dladm/datalink.conf, it uses the process_db_write() function, which leaks the following dlmgmt_link_t structure:
bash-3.2# mdb core.100895
Loading modules: [ libumem.so.1 libc.so.1 libavl.so.1 ld.so.1 ]
> ::findleaks
CACHE LEAKED BUFCTL CALLER
080a7810 21 080ebbc0 libc.so.1`_ucred_alloc+0x21
080a5610 3 080ed268 linkattr_set+0x70
080a5610 40 080edc40 linkattr_set+0x70
080a5610 20 080ed3d0 linkattr_set+0x70
080a5610 6 080d17c0 linkattr_set+0x70
080a1a10 3 080cf198 linkattr_set+0xa7
080a1a10 25 080d0650 linkattr_set+0xa7
080a1a10 7 080d0470 linkattr_set+0xa7
080a1a10 13 080cf558 linkattr_set+0xa7
080a1c10 6 080daa38 linkattr_set+0xa7
080a1c10 3 080dad08 linkattr_set+0xa7
080a5010 1 080dd618 linkattr_set+0xa7
080a5010 2 080dd528 linkattr_set+0xa7
080a5210 6 080b32e0 linkattr_set+0xa7
080a5210 3 080b35b0 linkattr_set+0xa7
080a5a10 2 080c5360 process_link_line+0x6a
080a5a10 1 080c5810 process_link_line+0x6a
080a5a10 10 080c5108 process_link_line+0x6a
080a5a10 2 080c53d8 process_link_line+0x6a
080a5a10 5 080c5888 process_link_line+0x6a
080a5a10 2 080c5090 process_link_line+0x6a
080a5a10 1 080c5b58 process_link_line+0x6a
080a5a10 1 080c5ae0 process_link_line+0x6a
------------------------------------------------------------------------
Total 183 buffers, 14976 bytes
> 080ed3d0$<bufctl_audit
ADDR BUFADDR TIMESTAMP THREAD
CACHE LASTLOG CONTENTS
80ed3d0 80ef880 429af7a91e 2
80a5610 80702c0 0
libumem.so.1`umem_cache_alloc_debug+0x14f
libumem.so.1`umem_cache_alloc+0x180
libumem.so.1`umem_alloc+0xc5
libumem.so.1`malloc+0x27
libumem.so.1`calloc+0x47
linkattr_set+0x70
parse_linkprops+0x138
process_link_line+0xcd
process_db_write+0x1b8
dlmgmt_process_db_onereq+0x150
dlmgmt_process_db_req+0x4d
dlmgmt_db_update+0x55
dlmgmt_write_db_entry+0x36
dlmgmt_upcall_update+0x85
dlmgmt_handler+0xb5
The leak occurs in process_db_write(), where it's parsing the existing file in a loop using process_link_line():
647 while (err == 0 && fgets(buf, sizeof (buf), fp) != NULL &&
648 process_link_line(buf, &link_in_file)) {
649 if (link_in_file == NULL || done) {
650 /*
651 * this is a comment line, write it out.
652 */
653 if (fputs(buf, nfp) == EOF)
654 err = errno;
655 continue;
656 }
...
697 link_destroy(link_in_file);
698 }
The link_in_file buffer is allocated within process_link_line(), and is freed by link_destroy() at the end of the loop. The problem is that within the loop, "done" is set to true meaning that the remaining lines in the file should simply be written-out as-is. In that case, we hit the block at 649 and leak every link_in_file in the file until we reach the end of the file.
Note that in order to trigger this bug, one must coerce dlmgmtd into writing a line in /etc/dladm/datalink.conf that already exists. This happens when a previously attached device re-attaches, which can be manually trigerred by doing "modunload -i 0".
|