https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113211
Bug ID: 113211
Summary: Trying to initialize the tripwire database ends up
with a SEGV if a uid cannot be found
Product: gcc
Version: 11.4.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: alexis at m2osw dot com
Target Milestone: ---
On some systems, when I install tripwire, it crashes.
Now I have had the problem many times, so I decided to look into why it
happens. In most cases, one can avoid the issue just by skipping checking
certain files and then go on with their life. I don't think that tripwire
should ever SEGV, though.
Thus, this time I compiled from source on Ubuntu 22.04 and got a stacktrace.
The SEGV actually happens in a systemd library which uses a thread safe
variable.
The systemd function looks like this:
_public_ bool _nss_systemd_is_blocked(void) {
return _blocked > 0;
}
The _blocked variable is defined like this:
static thread_local unsigned _blocked = 0;
When reading the value, the `eax` register is 0 and we get the SEGV. This seems
to be a compiler functionality that fails. There are other tools that have a
similar issue and also SEGV. Note that it only happens if the `uid` does not
exist in the `/etc/passwd` file and that function will have been called many
times before, so the variable should already have been initialized.
Here is the stack trace:
#0 0x77bf86a4 in _nss_systemd_is_blocked () from
/lib/x86_64-linux-gnu/libnss_systemd.so.2
#1 0x77bfa46d in _nss_systemd_getpwuid_r () from
/lib/x86_64-linux-gnu/libnss_systemd.so.2
#2 0x005e5bcf in getpwuid_r ()
#3 0x005e59d3 in getpwuid ()
#4 0x00481b6f in cUnixFSServices::GetUserName (this=,
user_id=501, tstrUser=...) at ../core/unixfsservices.cpp:542
#5 0x00459892 in cFSPropDisplayer::InitForProp (this=0x760be0,
pFCO=, propIdx=)
at ../fs/./../core/fsservices.h:353
#6 0x00453ab6 in cFSPropDisplayer::InitForFCO (this=0x760be0,
ifco=0x8e2550) at ../fs/fspropdisplayer.cpp:248
#7 0x00427631 in cTripwireUtil::CalcProps (pFCO=0x8e2550,
pSpec=, pCalc=, pPD=0x760be0)
at ./src/tripwire/tripwireutil.cpp:79
#8 0x00423740 in util_ProcessDir (dbIter=..., pIter=0x9a0110,
pSpec=0x770330, pPC=0x747070, pPD=0x760be0)
at ./src/tripwire/generatedb.cpp:92
#9 0x0042389f in util_ProcessDir (dbIter=..., pIter=0x99b370,
pSpec=0x770330, pPC=0x747070, pPD=0x760be0)
at ./src/tripwire/generatedb.cpp:105
#10 0x0042389f in util_ProcessDir (dbIter=..., pIter=0x949370,
pSpec=0x770330, pPC=0x747070, pPD=0x760be0)
at ./src/tripwire/generatedb.cpp:105
#11 0x0042389f in util_ProcessDir (dbIter=..., pIter=0x9482b0,
pSpec=0x770330, pPC=0x747070, pPD=0x760be0)
at ./src/tripwire/generatedb.cpp:105
and the assembly code of the very function that SEGV:
0x77bf86a4 in _nss_systemd_is_blocked () from
/lib/x86_64-linux-gnu/libnss_systemd.so.2
(gdb) disassemble
Dump of assembler code for function _nss_systemd_is_blocked:
0x77bf8690 <+0>:endbr64
0x77bf8694 <+4>:sub$0x8,%rsp
0x77bf8698 <+8>:lea0x44919(%rip),%rdi#
0x77c3cfb8
0x77bf869f <+15>:call 0x77bf7c80 <__tls_get_addr@plt>
=> 0x77bf86a4 <+20>:mov0x1c(%rax),%eax
0x77bf86aa <+26>:test %eax,%eax
0x77bf86ac <+28>:setne %al
0x77bf86af <+31>:add$0x8,%rsp
0x77bf86b3 <+35>:ret
End of assembler dump.
If I try a simple `getpwuid()` call with an unknown UID, it returns nullptr
just as expected. I'm not too sure what tripwire adds that would cause the
issue. It's rather complex and still looks like it happens because the C
compiler returns a nullptr in a location where it is never expected to happen.
To reproduce, you can create a VM, change the ownership of a file to an
undefined user on a file that tripwire will read (as under /root or /etc), then
install tripwire. At the time it tries to initializes its database, it will
SEGV instead.
Note: this has been happening for a long time. I think the first time was under
Ubuntu 16.04 so this bug has been around for a while.