代码拉取完成,页面将自动刷新
同步操作将从 yangshicheng/systemd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 055ba736e12255cf79acc81aac382344129d03c5 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 8 Sep 2021 16:51:16 -0500
Subject: [PATCH] nss-systemd: ensure returned strings point into provided
buffer
Jamie Bainbridge found an issue where glib's g_get_user_database_entry()
may crash after doing:
```
error = getpwnam_r (logname, &pwd, buffer, bufsize, &pw);
// ...
pw->pw_name[0] = g_ascii_toupper (pw->pw_name[0]);
```
in order to uppercase the first letter of the user's real name. This is
a glib bug, because there is a different codepath that gets the pwd from
vanilla getpwnam instead of getpwnam_r as shown here. When the pwd
struct is returned by getpwnam, its fields point to static data owned by
glibc/NSS, and so it must not be modified by the caller. After much
debugging, Jamie Bainbridge has fixed this in https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2244
by making a copy of the data before modifying it, and that resolves all
problems for glib. Yay!
However, glib is crashing even when getpwnam_r is used instead of
getpwnam! According to getpwnam_r(3), the strings in the pwd struct are
supposed to be pointers into the buffer passed by the caller, so glib
should be able to safely edit it directly in this case, so long as it
doesn't try to increase the size of any of the strings.
Problem is various functions throughout nss-systemd.c return synthesized
records declared at the top of the file. These records are returned
directly and so contain pointers to static strings owned by
libsystemd-nss. systemd must instead copy all the strings into the
provided buffer.
This crash is reproducible if nss-systemd is listed first on the passwd
line in /etc/nsswitch.conf, and the application looks up one of the
synthesized user accounts "root" or "nobody", and finally the
application attempts to edit one of the strings in the returned struct.
All our synthesized records for the other struct types have the same
problem, so this commit fixes them all at once.
Fixes #20679
(cherry picked from commit 47fd7fa6c650d7a0ac41bc89747e3b866ffb9534)
Conflict:NA
Reference:https://github.com/systemd/systemd/commit/055ba736e12255cf79acc81aac382344129d03c5
---
src/nss-systemd/nss-systemd.c | 204 ++++++++++++++++++++++++++++------
1 file changed, 168 insertions(+), 36 deletions(-)
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index 1b0866109a..1840a0d508 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -2,6 +2,7 @@
#include <nss.h>
#include <pthread.h>
+#include <string.h>
#include "env-util.h"
#include "errno-util.h"
@@ -139,6 +140,155 @@ NSS_GRENT_PROTOTYPES(systemd);
NSS_SGENT_PROTOTYPES(systemd);
NSS_INITGROUPS_PROTOTYPE(systemd);
+/* Since our NSS functions implement reentrant glibc APIs, we have to guarantee
+ * all the string pointers we return point into the buffer provided by the
+ * caller, not into our own static memory. */
+
+static enum nss_status copy_synthesized_passwd(
+ struct passwd *dest,
+ const struct passwd *src,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ size_t required;
+
+ assert(dest);
+ assert(src);
+ assert(src->pw_name);
+ assert(src->pw_passwd);
+ assert(src->pw_gecos);
+ assert(src->pw_dir);
+ assert(src->pw_shell);
+
+ required = strlen(src->pw_name) + 1;
+ required += strlen(src->pw_passwd) + 1;
+ required += strlen(src->pw_gecos) + 1;
+ required += strlen(src->pw_dir) + 1;
+ required += strlen(src->pw_shell) + 1;
+
+ if (buflen < required) {
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ assert(buffer);
+
+ *dest = *src;
+
+ /* String fields point into the user-provided buffer */
+ dest->pw_name = buffer;
+ dest->pw_passwd = stpcpy(dest->pw_name, src->pw_name) + 1;
+ dest->pw_gecos = stpcpy(dest->pw_passwd, src->pw_passwd) + 1;
+ dest->pw_dir = stpcpy(dest->pw_gecos, src->pw_gecos) + 1;
+ dest->pw_shell = stpcpy(dest->pw_dir, src->pw_dir) + 1;
+ strcpy(dest->pw_shell, src->pw_shell);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status copy_synthesized_spwd(
+ struct spwd *dest,
+ const struct spwd *src,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ size_t required;
+
+ assert(dest);
+ assert(src);
+ assert(src->sp_namp);
+ assert(src->sp_pwdp);
+
+ required = strlen(src->sp_namp) + 1;
+ required += strlen(src->sp_pwdp) + 1;
+
+ if (buflen < required) {
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ assert(buffer);
+
+ *dest = *src;
+
+ /* String fields point into the user-provided buffer */
+ dest->sp_namp = buffer;
+ dest->sp_pwdp = stpcpy(dest->sp_namp, src->sp_namp) + 1;
+ strcpy(dest->sp_pwdp, src->sp_pwdp);
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status copy_synthesized_group(
+ struct group *dest,
+ const struct group *src,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ size_t required;
+
+ assert(dest);
+ assert(src);
+ assert(src->gr_name);
+ assert(src->gr_passwd);
+ assert(src->gr_mem);
+ assert(!*src->gr_mem); /* Our synthesized records' gr_mem is always just NULL... */
+
+ required = strlen(src->gr_name) + 1;
+ required += strlen(src->gr_passwd) + 1;
+ required += 1; /* ...but that NULL still needs to be stored into the buffer! */
+
+ if (buflen < required) {
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ assert(buffer);
+
+ *dest = *src;
+
+ /* String fields point into the user-provided buffer */
+ dest->gr_name = buffer;
+ dest->gr_passwd = stpcpy(dest->gr_name, src->gr_name) + 1;
+ dest->gr_mem = (char **) strcpy(dest->gr_passwd, src->gr_passwd) + 1;
+ *dest->gr_mem = NULL;
+
+ return NSS_STATUS_SUCCESS;
+}
+
+static enum nss_status copy_synthesized_sgrp(
+ struct sgrp *dest,
+ const struct sgrp *src,
+ char *buffer, size_t buflen,
+ int *errnop) {
+
+ size_t required;
+
+ assert(dest);
+ assert(src);
+ assert(src->sg_namp);
+ assert(src->sg_passwd);
+
+ required = strlen(src->sg_namp) + 1;
+ required += strlen(src->sg_passwd) + 1;
+
+ if (buflen < required) {
+ *errnop = ERANGE;
+ return NSS_STATUS_TRYAGAIN;
+ }
+
+ assert(buffer);
+
+ *dest = *src;
+
+ /* String fields point into the user-provided buffer */
+ dest->sg_namp = buffer;
+ dest->sg_passwd = stpcpy(dest->sg_namp, src->sg_namp) + 1;
+ strcpy(dest->sg_passwd, src->sg_passwd);
+
+ return NSS_STATUS_SUCCESS;
+}
+
enum nss_status _nss_systemd_getpwnam_r(
const char *name,
struct passwd *pwd,
@@ -164,17 +314,14 @@ enum nss_status _nss_systemd_getpwnam_r(
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
- if (streq(name, root_passwd.pw_name)) {
- *pwd = root_passwd;
- return NSS_STATUS_SUCCESS;
- }
+ if (streq(name, root_passwd.pw_name))
+ return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop);
if (streq(name, nobody_passwd.pw_name)) {
if (!synthesize_nobody())
return NSS_STATUS_NOTFOUND;
- *pwd = nobody_passwd;
- return NSS_STATUS_SUCCESS;
+ return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop);
}
} else if (STR_IN_SET(name, root_passwd.pw_name, nobody_passwd.pw_name))
@@ -211,17 +358,14 @@ enum nss_status _nss_systemd_getpwuid_r(
/* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
- if (uid == root_passwd.pw_uid) {
- *pwd = root_passwd;
- return NSS_STATUS_SUCCESS;
- }
+ if (uid == root_passwd.pw_uid)
+ return copy_synthesized_passwd(pwd, &root_passwd, buffer, buflen, errnop);
if (uid == nobody_passwd.pw_uid) {
if (!synthesize_nobody())
return NSS_STATUS_NOTFOUND;
- *pwd = nobody_passwd;
- return NSS_STATUS_SUCCESS;
+ return copy_synthesized_passwd(pwd, &nobody_passwd, buffer, buflen, errnop);
}
} else if (uid == root_passwd.pw_uid || uid == nobody_passwd.pw_uid)
@@ -259,17 +403,14 @@ enum nss_status _nss_systemd_getspnam_r(
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
- if (streq(name, root_spwd.sp_namp)) {
- *spwd = root_spwd;
- return NSS_STATUS_SUCCESS;
- }
+ if (streq(name, root_spwd.sp_namp))
+ return copy_synthesized_spwd(spwd, &root_spwd, buffer, buflen, errnop);
if (streq(name, nobody_spwd.sp_namp)) {
if (!synthesize_nobody())
return NSS_STATUS_NOTFOUND;
- *spwd = nobody_spwd;
- return NSS_STATUS_SUCCESS;
+ return copy_synthesized_spwd(spwd, &nobody_spwd, buffer, buflen, errnop);
}
} else if (STR_IN_SET(name, root_spwd.sp_namp, nobody_spwd.sp_namp))
@@ -309,17 +450,14 @@ enum nss_status _nss_systemd_getgrnam_r(
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
- if (streq(name, root_group.gr_name)) {
- *gr = root_group;
- return NSS_STATUS_SUCCESS;
- }
+ if (streq(name, root_group.gr_name))
+ return copy_synthesized_group(gr, &root_group, buffer, buflen, errnop);
if (streq(name, nobody_group.gr_name)) {
if (!synthesize_nobody())
return NSS_STATUS_NOTFOUND;
- *gr = nobody_group;
- return NSS_STATUS_SUCCESS;
+ return copy_synthesized_group(gr, &nobody_group, buffer, buflen, errnop);
}
} else if (STR_IN_SET(name, root_group.gr_name, nobody_group.gr_name))
@@ -356,17 +494,14 @@ enum nss_status _nss_systemd_getgrgid_r(
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
- if (gid == root_group.gr_gid) {
- *gr = root_group;
- return NSS_STATUS_SUCCESS;
- }
+ if (gid == root_group.gr_gid)
+ return copy_synthesized_group(gr, &root_group, buffer, buflen, errnop);
if (gid == nobody_group.gr_gid) {
if (!synthesize_nobody())
return NSS_STATUS_NOTFOUND;
- *gr = nobody_group;
- return NSS_STATUS_SUCCESS;
+ return copy_synthesized_group(gr, &nobody_group, buffer, buflen, errnop);
}
} else if (gid == root_group.gr_gid || gid == nobody_group.gr_gid)
@@ -404,17 +539,14 @@ enum nss_status _nss_systemd_getsgnam_r(
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_SYNTHETIC") <= 0) {
- if (streq(name, root_sgrp.sg_namp)) {
- *sgrp = root_sgrp;
- return NSS_STATUS_SUCCESS;
- }
+ if (streq(name, root_sgrp.sg_namp))
+ return copy_synthesized_sgrp(sgrp, &root_sgrp, buffer, buflen, errnop);
if (streq(name, nobody_sgrp.sg_namp)) {
if (!synthesize_nobody())
return NSS_STATUS_NOTFOUND;
- *sgrp = nobody_sgrp;
- return NSS_STATUS_SUCCESS;
+ return copy_synthesized_sgrp(sgrp, &nobody_sgrp, buffer, buflen, errnop);
}
} else if (STR_IN_SET(name, root_sgrp.sg_namp, nobody_sgrp.sg_namp))
--
2.33.0
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。