Closed marxin closed 2 years ago
In this case, umockdev
primarily redirects the path when opening files to point to a fake temporary directory instead.
So we are looking at udev_device_get_subsystem
returning NULL suddenly (after udev_device_new_from_syspath
). My thinking would be, that we are more likely looking at another change here (e.g. systemd/systemd@13659527efd4cf00677ccacba5994bb77dc866b0), and you are simply compiling a newer libudev.
Could that be the case?
In this case,
umockdev
primarily redirects the path when opening files to point to a fake temporary directory instead.
I see. How exactly is utilized the libdev
library? I noticed it's not a shared library dependency of test binary test-umockdev-record
, right? Maybe the returned udev_device
object is somehow changed, can I dump it?
So we are looking at
udev_device_get_subsystem
returning NULL suddenly (afterudev_device_new_from_syspath
). My thinking would be, that we are more likely looking at another change here (e.g. systemd/systemd@1365952), and you are simply compiling a newer libudev.
Note I'm using a stable release package that is fixed. The only change is that I build the package with -D_FORTIFY_SOURCE=3
instead of -D_FORTIFY_SOURCE=2
. Plus I include the following fix:
https://github.com/systemd/systemd/pull/22917
Could that be the case?
No.
I see. How exactly is utilized the libdev library? I noticed it's not a shared library dependency of test binary test-umockdev-record, right? Maybe the returned udev_device object is somehow changed, can I dump it?
The assert you are seeing is coming from umockdev itself. i.e. the test code crashes while creating a umockdev testbed.
I believe this is the crashing call:
So, looking at the udev code, it seems that it does a readlink
on the subsystem
link. I suspect, that this readlink is not intercepted properly for some reason.
You could:
strace
the process, to see if you see the readlink and verify it returns ENOENT (and, that it is looking at the wrong path)sd_device_get_subsystem
and step through to see if the LD_PRELOAD library is used in the end for the readlink
call to glibc.So, not sure what _FORTIFY_SOURCE
does, but verifying the umockdev LD_PRELOAD is working seems like a good plan.
So, looking at the udev code, it seems that it does a
readlink
on thesubsystem
link. I suspect, that this readlink is not intercepted properly for some reason.
Oh, that would be the root cause as readlink
is one of the fortified functions and it's very likely that libudev.so
calls the foritifed version: __readlink_chk
:
nm /lib64/libudev.so | grep readlink
U __readlinkat_chk@GLIBC_2.5
...
You could:
strace
the process, to see if you see the readlink and verify it returns ENOENT (and, that it is looking at the wrong path)
I see the following:
$ LD_LIBRARY_PATH=/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux GI_TYPELIB_PATH=/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux G_DEBUG=fatal-warnings,fatal-criticals,gc-friendly PATH=/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux:/usr/local/bin:/usr/bin:/bin TOP_SRCDIR=/home/abuild/rpmbuild/BUILD/umockdev-0.17.8 strace -f -s512 /home/abuild/rpmbuild/BUILD/umockdev-0.17.8/src/umockdev-wrapper /home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/test-umockdev-run 2>&1 | grep readlink
readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/test-umockdev-run", 4096) = 79
[pid 31145] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31147] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31153] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31158] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31173] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31177] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31182] readlink("/proc/self/exe", "/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/x86_64-suse-linux/umockdev-run", 4096) = 74
[pid 31182] readlink("/proc/self/fd/8", "/", 4096) = 1
[pid 31182] readlink("/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/devices", 0x7fffffff93c0, 1023) = -1 EINVAL (Invalid argument)
[pid 31182] readlink("/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/virtual", 0x7fffffff93c0, 1023) = -1 ENOENT (No such file or directory)
[pid 31182] readlink("/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/block", 0x7fffffff93c0, 1023) = -1 ENOENT (No such file or directory)
[pid 31182] readlink("/home/abuild/rpmbuild/BUILD/umockdev-0.17.8/loop23", 0x7fffffff93c0, 1023) = -1 ENOENT (No such file or directory)
[pid 31182] readlinkat(AT_FDCWD, "/sys/devices/virtual/block/loop23/subsystem", 0x55555557ab20, 4096) = -1 ENOENT (No such file or directory)
Does it explain our problem?
Anyway, thanks for help!
- break in
sd_device_get_subsystem
and step through to see if the LD_PRELOAD library is used in the end for thereadlink
call to glibc.So, not sure what
_FORTIFY_SOURCE
does, but verifying the umockdev LD_PRELOAD is working seems like a good plan.
Please take a look at explanation: https://developers.redhat.com/blog/2021/04/16/broadening-compiler-checks-for-buffer-overflows-in-_fortify_source#_fortify_source_under_the_hood
Nice! I can confirm the following patch fixes that:
diff --git a/src/libumockdev-preload.c b/src/libumockdev-preload.c
index 87b64a8..098640b 100644
--- a/src/libumockdev-preload.c
+++ b/src/libumockdev-preload.c
@@ -1516,6 +1516,13 @@ ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
return r;
}
+
+ssize_t __readlinkat_chk (int dirfd, const char *pathname, char *buf, size_t bufsiz,
+ size_t buflen)
+{
+ return readlinkat (dirfd, pathname, buf, bufsiz);
+}
+
WRAP_2ARGS_PATHRET(char *, NULL, realpath, char *);
char *__realpath_chk(const char *path, char *resolved, size_t size);
I'm going to do a proper fix tomorrow.
Thanks @marxin ! Indeed umockdev doesn't currently test with fortify at all. I am adding a test for _FORTIFY_SOURCE=2
, and that succeeds.
Unfortunately I can't yet enable =3
yet everywhere:
/usr/include/features.h:424:5: error: #warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform [-Werror=cpp]
424 | # warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform
| ^~~~~~~
That is with gcc 11.2 on Fedora 35. It does work with gcc 12.0.1 in Fedora rawhide, though, so I'll make the test conditional on the compiler version.
However, this also means that I cannot reproduce this bug. (I ran this before your PR). Still, I think adding the test makes sense to cover other cases of breaking fortify. I'll land your PR and then add the test.
Thanks!
However, this also means that I cannot reproduce this bug. (I ran this before your PR). Still, I think adding the test makes sense to cover other cases of breaking fortify. I'll land your PR and then add the test.
As mentioned, you will see the error with GCC 12 if you would use systemd
(libudev
) package compiled with _FORTIFY_SOURCE=3
.
I'm in the middle of the debugging session where I'm trying to use
-D_FORTIFY_SOURCE=3
with the upcoming GCC compiler. I noticed that using the flags forsystemd
and then using/lib64/libudev.so.xyz
library triggers errors in your project test-suite:As seen, we hit the following assert
uevent_sender.c:248: uevent_sender_send: Assertion subsystem != NULL' failed.
.So the question is: how can I debug it? Am I correct that
umockdev
shadows (implements) some of thelibudev.so
functions?@siddhesh