util-lib: wrap personality() to fix up broken glibc error handling (#6766)

glibc appears to propagate different errors in different ways, let's fix
this up, so that our own code doesn't get confused by this.

See #6752 + #6737 for details.

Fixes: #6755
This commit is contained in:
Lennart Poettering
2017-09-08 17:16:29 +03:00
committed by Evgeny Vereshchagin
parent 5463fa0a88
commit 21022b9dde
5 changed files with 53 additions and 57 deletions
+24 -2
View File
@@ -904,6 +904,28 @@ const char* personality_to_string(unsigned long p) {
return architecture_to_string(architecture);
}
int safe_personality(unsigned long p) {
int ret;
/* So here's the deal, personality() is weirdly defined by glibc. In some cases it returns a failure via errno,
* and in others as negative return value containing an errno-like value. Let's work around this: this is a
* wrapper that uses errno if it is set, and uses the return value otherwise. And then it sets both errno and
* the return value indicating the same issue, so that we are definitely on the safe side.
*
* See https://github.com/systemd/systemd/issues/6737 */
errno = 0;
ret = personality(p);
if (ret < 0) {
if (errno != 0)
return -errno;
errno = -ret;
}
return ret;
}
int opinionated_personality(unsigned long *ret) {
int current;
@@ -911,9 +933,9 @@ int opinionated_personality(unsigned long *ret) {
* opinionated though, and ignores all the finer-grained bits and exotic personalities, only distinguishing the
* two most relevant personalities: PER_LINUX and PER_LINUX32. */
current = personality(PERSONALITY_INVALID);
current = safe_personality(PERSONALITY_INVALID);
if (current < 0)
return -errno;
return current;
if (((unsigned long) current & 0xffff) == PER_LINUX32)
*ret = PER_LINUX32;