Discussion:
[PATCH] Fix strerror_r segfault on non-glibc systems
Add Reply
Ioan-Adrian Ratiu
2018-03-29 11:41:30 UTC
Reply
Permalink
Raw Message
POSIX strerror_r returns an int while the glibc "extension" returns a char* and
this causes segfaults when running on systems with libc's like musl which only
implement the portable version or deliberately don't provide a flag to identify
compiling using their headers.

Glibc provides the POSIX variant of the function, but only if _GNU_SOURCE is
not set i.e. all gnu extensions are disabled. Meson sets _GNU_SOURCE globally
at build time.

So detect during build if we have the char* version and #ifdef the logic.

Signed-off-by: Ioan-Adrian Ratiu <***@adirat.com>
---
meson.build | 13 +++++++++++++
src/journal/journal-send.c | 9 +++++++++
src/libsystemd/sd-bus/bus-error.c | 9 +++++++++
3 files changed, 31 insertions(+)

diff --git a/meson.build b/meson.build
index b53dfaa94..fe807237f 100644
--- a/meson.build
+++ b/meson.build
@@ -383,6 +383,19 @@ if cc.compiles('''
add_project_arguments('-Werror=shadow', language : 'c')
endif

+if cc.compiles('
+ #include <string.h>
+ int func (void) {
+ char error_string[256];
+ char *ptr = strerror_r(-2, error_string, 256);
+ char c = *strerror_r(-2, error_string, 256);
+ return c != 0 && ptr != (void*) 0L;
+ }
+', name : 'strerror_r() returns char *', args : '-D_GNU_SOURCE')
+ conf.set('STRERROR_R_CHAR_P', 1,
+ description: 'Defined if strerror_r returns char *')
+endif
+
if cc.get_id() == 'clang'
foreach arg : ['-Wno-typedef-redefinition',
'-Wno-gnu-variable-sized-type-not-at-end',
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index b6adf64c2..9b33c6c3b 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -355,7 +355,16 @@ static int fill_iovec_perror_and_send(const char *message, int skip, struct iove
char* j;

errno = 0;
+
+#ifdef STRERROR_R_CHAR_P
j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k);
+#else
+ j = buffer + 8 + k;
+ int ret = strerror_r(_saved_errno_, j, n - 8 - k);
+ if (ret)
+ errno = ret;
+#endif
+
if (errno == 0) {
char error[STRLEN("ERRNO=") + DECIMAL_STR_MAX(int) + 1];

diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c
index 66a09a35f..10390f0d8 100644
--- a/src/libsystemd/sd-bus/bus-error.c
+++ b/src/libsystemd/sd-bus/bus-error.c
@@ -378,7 +378,16 @@ static void bus_error_strerror(sd_bus_error *e, int error) {
return;

errno = 0;
+
+#ifdef STRERROR_R_CHAR_P
x = strerror_r(error, m, k);
+#else
+ int ret = strerror_r(error, m, k);
+ if (ret)
+ errno = ret;
+ x = m;
+#endif
+
if (errno == ERANGE || strlen(x) >= k - 1) {
free(m);
k *= 2;
--
2.16.3
Lennart Poettering
2018-03-29 09:14:26 UTC
Reply
Permalink
Raw Message
Post by Ioan-Adrian Ratiu
POSIX strerror_r returns an int while the glibc "extension" returns a char* and
this causes segfaults when running on systems with libc's like musl which only
implement the portable version or deliberately don't provide a flag to identify
compiling using their headers.
Glibc provides the POSIX variant of the function, but only if _GNU_SOURCE is
not set i.e. all gnu extensions are disabled. Meson sets _GNU_SOURCE globally
at build time.
So detect during build if we have the char* version and #ifdef the logic.
Sorry, but as usual: please work with the other libcs to provide glibc
compatibility. At this point glibc is *the* Linux API, and it would be
much easier for everybody if the alternative libcs would just get over
themselves and provide proper compatibility, instead of expecting
people to add hacks to every single package using them.

Thank you for understanding,

Lennart
--
Lennart Poettering, Red Hat
systemd github import bot
2018-03-29 09:06:35 UTC
Reply
Permalink
Raw Message
Patchset imported to github.
To create a pull request, one of the main developers has to initiate one via:
<https://github.com/systemd/systemd/compare/master...systemd-mailing-devs:20180329114130.14928-1-adi%40adirat.com>

--
Generated by https://github.com/haraldh/mail2git

Loading...