| Summary: | RFE: --track-origins=yes identifies system call source of Uninitialized value | ||
|---|---|---|---|
| Product: | [Developer tools] valgrind | Reporter: | John Reiser <jreiser> |
| Component: | memcheck | Assignee: | Julian Seward <jseward> |
| Status: | REPORTED --- | ||
| Severity: | wishlist | CC: | philippe.waroquiers, sam |
| Priority: | NOR | ||
| Version First Reported In: | 3.13 SVN | ||
| Target Milestone: | --- | ||
| Platform: | Other | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
John Reiser
2017-06-17 04:57:26 UTC
Do you have a reproducer ? And/or a list of syscalls that can produce uninit data ? Thanks The system routines in musl libc (https://www.musl-libc.org/) are coded with the system call instruction as a common tail. The system call which produces uninit values is brk()/sbrk(), which libmusl invokes from malloc(). New pages from the OS are known to be 0, but "re-alloc()ed" pages [sbrk() of a positive increment after sbrk() of a negative increment; or a sequence of brk() whose arguments are not monotonically non-decreasing] need not be 0, and must be treated as uninit. Proving that nobody else touched the new pages (thus that they are still all initialized [namely, to zero]) can be tricky; see https://bugs.kde.org/show_bug.cgi?id=381299 . The socket() system calls is a multiplexed group of syscalls where the interpretation of arguments depends heavily on flags. Many fields are defined only in some circumstances, and there are many cases. When combined with a malloc() that does not integrate with memcheck (see https://bugs.kde.org/show_bug.cgi?id=381326) then it can look like socket() is the source of uninit. I ran into this problem while working on https://github.com/upx/upx/issues/105 . If still available, then the link https://www.dropbox.com/s/s6f6agxsjo32zzt/Uw32f.tar.gz?dl=0 (of 2017-06-16 or so) provides a pre-compiled i386 program with symbols where memcheck complains many times about socket() calls. [I have run the program many times, both bare and under memcheck; I believe it is safe to run.] It looks now like libmusl __malloc0() is the ultimate cause of all the reported problems, but it took a while to figure that out. It would have taken much less time if brk() had been identified in [all] the memcheck reports. Another syscall that produces uninit is readlink(). The portion of the result buffer that is beyond the returned length, should be regarded as Uninit. There is no guarantee that the kernel avoids writing into any portion of the whole buffer, although all known implementations write only an initial string [non-terminated] of the returned length. [memcheck 3.13.0 implements the observed behavior, which is a risk for "false negative" complaints.]
link_length = readlink(pathname, buf, buflen)
if (link_length > 0) { // no error
// buf[link_length, buflen) should be regarded as Uninit.
}
read_length = read(fd, buf, buflen) should regard buf[read_length, buflen) as Uninit when there is no error. When there is an error, then ALL of buf[0, buflen) should be regarded as Uninit. This is particularly true for character special devices: tty, "raw" tape drive, etc. These devices can misbehave readily. (In reply to John Reiser from comment #3) > There is no guarantee that the kernel avoids writing into any > portion of the whole buffer, although all known implementations write only > an initial string [non-terminated] of the returned length. One easily-imagined implementation technique would be for the kernel to build the result in the output buffer incrementally, path-component by path-component. If the last path component is a symlink to a short absolute path, then the result can be shorter than the preceding intermediate step. |