backport some patches

(cherry picked from commit 6f859a83e8b96a406cdbdd0b679bc4009f870183)
This commit is contained in:
qsw33 2023-11-09 21:40:35 +08:00 committed by openeuler-sync-bot
parent e87e6f3ee4
commit 40d22c3533
23 changed files with 2135 additions and 36 deletions

View File

@ -0,0 +1,29 @@
From eaebea55a495a56317ed85e959b3599f73c6bdf2 Mon Sep 17 00:00:00 2001
From: David Michael <fedora.dm0@gmail.com>
Date: Sun, 23 Oct 2022 18:51:33 -0400
Subject: [PATCH] useradd: Fix buffer overflow when using a prefix
The buffer length did not count the string's trailing null byte.
Signed-off-by: David Michael <fedora.dm0@gmail.com>
Conflict: if(prefix[0]) There is no space after it.
Reference: https://github.com/shadow-maint/shadow/commit/f6f8bcd2a57c06983296485cc028ebdf467ebfd7
---
src/useradd.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/useradd.c b/src/useradd.c
index 39a744ee0..7ea0a9c4d 100644
--- a/src/useradd.c
+++ b/src/useradd.c
@@ -2372,7 +2372,7 @@ static void create_mail (void)
if (NULL == spool) {
spool = "/var/mail";
}
- file = alloca (strlen (prefix) + strlen (spool) + strlen (user_name) + 2);
+ file = alloca (strlen (prefix) + strlen (spool) + strlen (user_name) + 3);
if(prefix[0])
sprintf (file, "%s/%s/%s", prefix, spool, user_name);
else

View File

@ -0,0 +1,28 @@
From aff4989d1acf3afc718813144658c295d8d10f20 Mon Sep 17 00:00:00 2001
From: Andy Zaugg <andy.zaugg@gmail.com>
Date: Mon, 20 Sep 2021 20:41:50 -0700
Subject: [PATCH] Added documentation around CREATE_MAIL_SPOOL
Adding documentation aroud the parameter CREATE_MAIL_SPOOL in the
/etc/default/useradd file
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/aff4989d1acf3afc718813144658c295d8d10f20
---
man/login.defs.d/MAIL_DIR.xml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/man/login.defs.d/MAIL_DIR.xml b/man/login.defs.d/MAIL_DIR.xml
index 60b82d6b1..b5adb888b 100644
--- a/man/login.defs.d/MAIL_DIR.xml
+++ b/man/login.defs.d/MAIL_DIR.xml
@@ -35,6 +35,8 @@
The mail spool directory. This is needed to manipulate the mailbox
when its corresponding user account is modified or deleted. If not
specified, a compile-time default is used.
+ The parameter CREATE_MAIL_SPOOL in <filename>/etc/default/useradd</filename>
+ determines whether the mail spool should be created.
</para>
</listitem>
</varlistentry><varlistentry>

View File

@ -0,0 +1,46 @@
From 6cbec2d0aa29d6d25e9eed007ded4e79eb637519 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:29 +0200
Subject: [PATCH] Address minor compiler warnings
copydir.c:666:44: warning: unsigned conversion from 'int' to '__mode_t' {aka 'unsigned int'} changes value from '-4096' to '4294963200' [-Wsign-conversion]
666 | if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
| ^
copydir.c:116:1: warning: missing initializer for field 'quote' of 'struct error_context' [-Wmissing-field-initializers]
116 | };
| ^
In file included from copydir.c:27:
/usr/include/attr/error_context.h:30:23: note: 'quote' declared here
30 | const char *(*quote) (struct error_context *, const char *);
| ^~~~~
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/6cbec2d0aa29d6d25e9eed007ded4e79eb637519
---
libmisc/copydir.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
index 95042187b..e753d7cf0 100644
--- a/libmisc/copydir.c
+++ b/libmisc/copydir.c
@@ -112,7 +112,7 @@ static void error_acl (unused struct error_context *ctx, const char *fmt, ...)
}
static struct error_context ctx = {
- error_acl
+ error_acl, NULL, NULL
};
#endif /* WITH_ACL || WITH_ATTR */
@@ -663,7 +663,7 @@ static int copy_special (const char *src, const char *dst,
}
#endif /* WITH_SELINUX */
- if ( (mknod (dst, statp->st_mode & ~07777, statp->st_rdev) != 0)
+ if ( (mknod (dst, statp->st_mode & ~07777U, statp->st_rdev) != 0)
|| (chown_if_needed (dst, statp,
old_uid, new_uid, old_gid, new_gid) != 0)
#ifdef WITH_ACL

View File

@ -0,0 +1,228 @@
From e9ae247cb14f977d8881f481488843b10665dba8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:19 +0200
Subject: [PATCH] Avoid races in chown_tree()
Use *at() functions to pin the directory operating in to avoid being
redirected by unprivileged users replacing parts of paths by symlinks to
privileged files.
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/e9ae247cb14f977d8881f481488843b10665dba8
---
libmisc/chowndir.c | 130 +++++++++++++++++----------------------------
1 file changed, 49 insertions(+), 81 deletions(-)
diff --git a/libmisc/chowndir.c b/libmisc/chowndir.c
index 0edc3b609..d31618a56 100644
--- a/libmisc/chowndir.c
+++ b/libmisc/chowndir.c
@@ -17,45 +17,28 @@
#include "defines.h"
#include <fcntl.h>
#include <stdio.h>
-/*
- * chown_tree - change ownership of files in a directory tree
- *
- * chown_dir() walks a directory tree and changes the ownership
- * of all files owned by the provided user ID.
- *
- * Only files owned (resp. group-owned) by old_uid (resp. by old_gid)
- * will have their ownership (resp. group-ownership) modified, unless
- * old_uid (resp. old_gid) is set to -1.
- *
- * new_uid and new_gid can be set to -1 to indicate that no owner or
- * group-owner shall be changed.
- */
-int chown_tree (const char *root,
+#include <unistd.h>
+
+static int chown_tree_at (int at_fd,
+ const char *path,
uid_t old_uid,
uid_t new_uid,
gid_t old_gid,
gid_t new_gid)
{
- char *new_name;
- size_t new_name_len;
- int rc = 0;
- struct DIRECT *ent;
- struct stat sb;
DIR *dir;
+ const struct DIRECT *ent;
+ struct stat dir_sb;
+ int dir_fd, rc = 0;
- new_name = malloc (1024);
- if (NULL == new_name) {
+ dir_fd = openat (at_fd, path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (dir_fd < 0) {
return -1;
}
- new_name_len = 1024;
- /*
- * Make certain the directory exists. This routine is called
- * directly by the invoker, or recursively.
- */
-
- if (access (root, F_OK) != 0) {
- free (new_name);
+ dir = fdopendir (dir_fd);
+ if (!dir) {
+ (void) close (dir_fd);
return -1;
}
@@ -65,68 +48,34 @@ int chown_tree (const char *root,
* recursively. If not, it is checked to see if an ownership
* shall be changed.
*/
-
- dir = opendir (root);
- if (NULL == dir) {
- free (new_name);
- return -1;
- }
-
while ((ent = readdir (dir))) {
- size_t ent_name_len;
uid_t tmpuid = (uid_t) -1;
gid_t tmpgid = (gid_t) -1;
+ struct stat ent_sb;
/*
* Skip the "." and ".." entries
*/
-
if ( (strcmp (ent->d_name, ".") == 0)
|| (strcmp (ent->d_name, "..") == 0)) {
continue;
}
- /*
- * Make the filename for both the source and the
- * destination files.
- */
-
- ent_name_len = strlen (root) + strlen (ent->d_name) + 2;
- if (ent_name_len > new_name_len) {
- /*@only@*/char *tmp = realloc (new_name, ent_name_len);
- if (NULL == tmp) {
- rc = -1;
- break;
- }
- new_name = tmp;
- new_name_len = ent_name_len;
- }
-
- (void) snprintf (new_name, new_name_len, "%s/%s", root, ent->d_name);
-
- /* Don't follow symbolic links! */
- if (LSTAT (new_name, &sb) == -1) {
- continue;
+ rc = fstatat (dirfd(dir), ent->d_name, &ent_sb, AT_SYMLINK_NOFOLLOW);
+ if (rc < 0) {
+ break;
}
- if (S_ISDIR (sb.st_mode) && !S_ISLNK (sb.st_mode)) {
-
+ if (S_ISDIR (ent_sb.st_mode)) {
/*
* Do the entire subdirectory.
*/
-
- rc = chown_tree (new_name, old_uid, new_uid,
- old_gid, new_gid);
+ rc = chown_tree_at (dirfd(dir), ent->d_name, old_uid, new_uid, old_gid, new_gid);
if (0 != rc) {
break;
}
}
-#ifndef HAVE_LCHOWN
- /* don't use chown (follows symbolic links!) */
- if (S_ISLNK (sb.st_mode)) {
- continue;
- }
-#endif
+
/*
* By default, the IDs are not changed (-1).
*
@@ -136,43 +85,62 @@ int chown_tree (const char *root,
* If the file is not group-owned by the group, the
* group-owner is not changed.
*/
- if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
+ if (((uid_t) -1 == old_uid) || (ent_sb.st_uid == old_uid)) {
tmpuid = new_uid;
}
- if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
+ if (((gid_t) -1 == old_gid) || (ent_sb.st_gid == old_gid)) {
tmpgid = new_gid;
}
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
- rc = LCHOWN (new_name, tmpuid, tmpgid);
+ rc = fchownat (dirfd(dir), ent->d_name, tmpuid, tmpgid, AT_SYMLINK_NOFOLLOW);
if (0 != rc) {
break;
}
}
}
- free (new_name);
- (void) closedir (dir);
-
/*
* Now do the root of the tree
*/
-
- if ((0 == rc) && (stat (root, &sb) == 0)) {
+ if ((0 == rc) && (fstat (dirfd(dir), &dir_sb) == 0)) {
uid_t tmpuid = (uid_t) -1;
gid_t tmpgid = (gid_t) -1;
- if (((uid_t) -1 == old_uid) || (sb.st_uid == old_uid)) {
+ if (((uid_t) -1 == old_uid) || (dir_sb.st_uid == old_uid)) {
tmpuid = new_uid;
}
- if (((gid_t) -1 == old_gid) || (sb.st_gid == old_gid)) {
+ if (((gid_t) -1 == old_gid) || (dir_sb.st_gid == old_gid)) {
tmpgid = new_gid;
}
if (((uid_t) -1 != tmpuid) || ((gid_t) -1 != tmpgid)) {
- rc = LCHOWN (root, tmpuid, tmpgid);
+ rc = fchown (dirfd(dir), tmpuid, tmpgid);
}
} else {
rc = -1;
}
+ (void) closedir (dir);
+
return rc;
}
+/*
+ * chown_tree - change ownership of files in a directory tree
+ *
+ * chown_dir() walks a directory tree and changes the ownership
+ * of all files owned by the provided user ID.
+ *
+ * Only files owned (resp. group-owned) by old_uid (resp. by old_gid)
+ * will have their ownership (resp. group-ownership) modified, unless
+ * old_uid (resp. old_gid) is set to -1.
+ *
+ * new_uid and new_gid can be set to -1 to indicate that no owner or
+ * group-owner shall be changed.
+ */
+int chown_tree (const char *root,
+ uid_t old_uid,
+ uid_t new_uid,
+ gid_t old_gid,
+ gid_t new_gid)
+{
+ return chown_tree_at (AT_FDCWD, root, old_uid, new_uid, old_gid, new_gid);
+}

View File

@ -0,0 +1,657 @@
From faeab50e710131816b261de66141524898c2c487 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:32 +0200
Subject: [PATCH] Avoid races in copy_tree()
Use *at() functions to pin the directory operating in to avoid being
redirected by unprivileged users replacing parts of paths by symlinks to
privileged files.
Introduce a path_info struct with the full path and dirfd and name
information for *at() functions, since the full path is needed for link
resolution, SELinux label lookup and ACL attributes.
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/faeab50e710131816b261de66141524898c2c487
---
libmisc/copydir.c | 330 ++++++++++++++++++++++++++++++----------------
1 file changed, 218 insertions(+), 112 deletions(-)
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
index e753d7cf0..5605f6fe0 100644
--- a/libmisc/copydir.c
+++ b/libmisc/copydir.c
@@ -47,40 +47,43 @@ struct link_name {
};
static /*@exposed@*/struct link_name *links;
-static int copy_entry (const char *src, const char *dst,
+struct path_info {
+ const char *full_path;
+ int dirfd;
+ const char *name;
+};
+
+static int copy_entry (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-static int copy_dir (const char *src, const char *dst,
+static int copy_dir (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
static /*@null@*/char *readlink_malloc (const char *filename);
-static int copy_symlink (const char *src, const char *dst,
+static int copy_symlink (const struct path_info *src, const struct path_info *dst,
unused bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-static int copy_hardlink (const char *dst,
+static int copy_hardlink (const struct path_info *dst,
unused bool reset_selinux,
struct link_name *lp);
-static int copy_special (const char *src, const char *dst,
+static int copy_special (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-static int copy_file (const char *src, const char *dst,
+static int copy_file (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-static int chown_if_needed (const char *dst, const struct stat *statp,
+static int chownat_if_needed (const struct path_info *dst, const struct stat *statp,
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-static int lchown_if_needed (const char *dst, const struct stat *statp,
- uid_t old_uid, uid_t new_uid,
- gid_t old_gid, gid_t new_gid);
static int fchown_if_needed (int fdst, const struct stat *statp,
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
@@ -116,6 +119,57 @@ static struct error_context ctx = {
};
#endif /* WITH_ACL || WITH_ATTR */
+#ifdef WITH_ACL
+static int perm_copy_path(const struct path_info *src,
+ const struct path_info *dst,
+ struct error_context *errctx)
+{
+ int src_fd, dst_fd, ret;
+
+ src_fd = openat(src->dirfd, src->name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (src_fd < 0) {
+ return -1;
+ }
+
+ dst_fd = openat(dst->dirfd, dst->name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (dst_fd < 0) {
+ (void) close (src_fd);
+ return -1;
+ }
+
+ ret = perm_copy_fd(src->full_path, src_fd, dst->full_path, dst_fd, errctx);
+ (void) close (src_fd);
+ (void) close (dst_fd);
+ return ret;
+}
+#endif /* WITH_ACL */
+
+#ifdef WITH_ATTR
+static int attr_copy_path(const struct path_info *src,
+ const struct path_info *dst,
+ int (*callback) (const char *, struct error_context *),
+ struct error_context *errctx)
+{
+ int src_fd, dst_fd, ret;
+
+ src_fd = openat(src->dirfd, src->name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (src_fd < 0) {
+ return -1;
+ }
+
+ dst_fd = openat(dst->dirfd, dst->name, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (dst_fd < 0) {
+ (void) close (src_fd);
+ return -1;
+ }
+
+ ret = attr_copy_fd(src->full_path, src_fd, dst->full_path, dst_fd, callback, errctx);
+ (void) close (src_fd);
+ (void) close (dst_fd);
+ return ret;
+}
+#endif /* WITH_ATTR */
+
/*
* remove_link - delete a link from the linked list
*/
@@ -188,51 +242,36 @@ static /*@exposed@*/ /*@null@*/struct link_name *check_link (const char *name, c
return NULL;
}
-/*
- * copy_tree - copy files in a directory tree
- *
- * copy_tree() walks a directory tree and copies ordinary files
- * as it goes.
- *
- * When reset_selinux is enabled, extended attributes (and thus
- * SELinux attributes) are not copied.
- *
- * old_uid and new_uid are used to set the ownership of the copied
- * files. Unless old_uid is set to -1, only the files owned by
- * old_uid have their ownership changed to new_uid. In addition, if
- * new_uid is set to -1, no ownership will be changed.
- *
- * The same logic applies for the group-ownership and
- * old_gid/new_gid.
- */
-int copy_tree (const char *src_root, const char *dst_root,
+static int copy_tree_impl (const struct path_info *src, const struct path_info *dst,
bool copy_root, bool reset_selinux,
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid)
{
- int err = 0;
+ int dst_fd, src_fd, err = 0;
bool set_orig = false;
- struct DIRECT *ent;
+ const struct DIRECT *ent;
DIR *dir;
if (copy_root) {
struct stat sb;
- if (access (dst_root, F_OK) == 0) {
+
+ if ( fstatat (dst->dirfd, dst->name, &sb, 0) == 0
+ || errno != ENOENT) {
return -1;
}
- if (lstat (src_root, &sb) == -1) {
+ if (fstatat (src->dirfd, src->name, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
return -1;
}
if (!S_ISDIR (sb.st_mode)) {
fprintf (shadow_logfd,
"%s: %s is not a directory",
- Prog, src_root);
+ Prog, src->full_path);
return -1;
}
- return copy_entry (src_root, dst_root, reset_selinux,
+ return copy_entry (src, dst, reset_selinux,
old_uid, new_uid, old_gid, new_gid);
}
@@ -242,8 +281,14 @@ int copy_tree (const char *src_root, const char *dst_root,
* target is created. It assumes the target directory exists.
*/
- if ( (access (src_root, F_OK) != 0)
- || (access (dst_root, F_OK) != 0)) {
+ src_fd = openat (src->dirfd, src->name, O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (src_fd < 0) {
+ return -1;
+ }
+
+ dst_fd = openat (dst->dirfd, dst->name, O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
+ if (dst_fd < 0) {
+ (void) close (src_fd);
return -1;
}
@@ -254,14 +299,16 @@ int copy_tree (const char *src_root, const char *dst_root,
* regular files (and directories ...) are copied, and no file
* is made set-ID.
*/
- dir = opendir (src_root);
+ dir = fdopendir (src_fd);
if (NULL == dir) {
+ (void) close (src_fd);
+ (void) close (dst_fd);
return -1;
}
if (src_orig == NULL) {
- src_orig = src_root;
- dst_orig = dst_root;
+ src_orig = src->full_path;
+ dst_orig = dst->full_path;
set_orig = true;
}
while ((0 == err) && (ent = readdir (dir)) != NULL) {
@@ -274,8 +321,8 @@ int copy_tree (const char *src_root, const char *dst_root,
char *dst_name;
size_t src_len = strlen (ent->d_name) + 2;
size_t dst_len = strlen (ent->d_name) + 2;
- src_len += strlen (src_root);
- dst_len += strlen (dst_root);
+ src_len += strlen (src->full_path);
+ dst_len += strlen (dst->full_path);
src_name = (char *) malloc (src_len);
dst_name = (char *) malloc (dst_len);
@@ -287,12 +334,22 @@ int copy_tree (const char *src_root, const char *dst_root,
* Build the filename for both the source and
* the destination files.
*/
+ struct path_info src_entry, dst_entry;
+
(void) snprintf (src_name, src_len, "%s/%s",
- src_root, ent->d_name);
+ src->full_path, ent->d_name);
(void) snprintf (dst_name, dst_len, "%s/%s",
- dst_root, ent->d_name);
+ dst->full_path, ent->d_name);
+
+ src_entry.full_path = src_name;
+ src_entry.dirfd = dirfd(dir);
+ src_entry.name = ent->d_name;
- err = copy_entry (src_name, dst_name,
+ dst_entry.full_path = dst_name;
+ dst_entry.dirfd = dst_fd;
+ dst_entry.name = ent->d_name;
+
+ err = copy_entry (&src_entry, &dst_entry,
reset_selinux,
old_uid, new_uid,
old_gid, new_gid);
@@ -306,6 +363,7 @@ int copy_tree (const char *src_root, const char *dst_root,
}
}
(void) closedir (dir);
+ (void) close (dst_fd);
if (set_orig) {
src_orig = NULL;
@@ -352,7 +410,7 @@ int copy_tree (const char *src_root, const char *dst_root,
* old_gid) will be modified, unless old_uid (resp. old_gid) is set
* to -1.
*/
-static int copy_entry (const char *src, const char *dst,
+static int copy_entry (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid)
@@ -360,32 +418,32 @@ static int copy_entry (const char *src, const char *dst,
int err = 0;
struct stat sb;
struct link_name *lp;
- struct timeval mt[2];
+ struct timespec mt[2];
- if (lstat (src, &sb) == -1) {
+ if (fstatat(src->dirfd, src->name, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
/* If we cannot stat the file, do not care. */
} else {
#ifdef HAVE_STRUCT_STAT_ST_ATIM
mt[0].tv_sec = sb.st_atim.tv_sec;
- mt[0].tv_usec = sb.st_atim.tv_nsec / 1000;
+ mt[0].tv_nsec = sb.st_atim.tv_nsec;
#else /* !HAVE_STRUCT_STAT_ST_ATIM */
mt[0].tv_sec = sb.st_atime;
# ifdef HAVE_STRUCT_STAT_ST_ATIMENSEC
- mt[0].tv_usec = sb.st_atimensec / 1000;
+ mt[0].tv_nsec = sb.st_atimensec;
# else /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
- mt[0].tv_usec = 0;
+ mt[0].tv_nsec = 0;
# endif /* !HAVE_STRUCT_STAT_ST_ATIMENSEC */
#endif /* !HAVE_STRUCT_STAT_ST_ATIM */
#ifdef HAVE_STRUCT_STAT_ST_MTIM
mt[1].tv_sec = sb.st_mtim.tv_sec;
- mt[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
+ mt[1].tv_nsec = sb.st_mtim.tv_nsec;
#else /* !HAVE_STRUCT_STAT_ST_MTIM */
mt[1].tv_sec = sb.st_mtime;
# ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
- mt[1].tv_usec = sb.st_mtimensec / 1000;
+ mt[1].tv_nsec = sb.st_mtimensec;
# else /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
- mt[1].tv_usec = 0;
+ mt[1].tv_nsec = 0;
# endif /* !HAVE_STRUCT_STAT_ST_MTIMENSEC */
#endif /* !HAVE_STRUCT_STAT_ST_MTIM */
@@ -407,7 +465,7 @@ static int copy_entry (const char *src, const char *dst,
* See if this is a previously copied link
*/
- else if ((lp = check_link (src, &sb)) != NULL) {
+ else if ((lp = check_link (src->full_path, &sb)) != NULL) {
err = copy_hardlink (dst, reset_selinux, lp);
}
@@ -446,9 +504,9 @@ static int copy_entry (const char *src, const char *dst,
*
* Return 0 on success, -1 on error.
*/
-static int copy_dir (const char *src, const char *dst,
+static int copy_dir (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid)
{
@@ -460,15 +518,15 @@ static int copy_dir (const char *src, const char *dst,
*/
#ifdef WITH_SELINUX
- if (set_selinux_file_context (dst, S_IFDIR) != 0) {
+ if (set_selinux_file_context (dst->full_path, S_IFDIR) != 0) {
return -1;
}
#endif /* WITH_SELINUX */
- if ( (mkdir (dst, statp->st_mode) != 0)
- || (chown_if_needed (dst, statp,
+ if ( (mkdirat (dst->dirfd, dst->name, statp->st_mode) != 0)
+ || (chownat_if_needed (dst, statp,
old_uid, new_uid, old_gid, new_gid) != 0)
#ifdef WITH_ACL
- || ( (perm_copy_file (src, dst, &ctx) != 0)
+ || ( (perm_copy_path (src, dst, &ctx) != 0)
&& (errno != 0))
#else /* !WITH_ACL */
|| (chmod (dst, statp->st_mode) != 0)
@@ -482,12 +540,12 @@ static int copy_dir (const char *src, const char *dst,
* additional logic so that no unexpected permissions result.
*/
|| ( !reset_selinux
- && (attr_copy_file (src, dst, NULL, &ctx) != 0)
+ && (attr_copy_path (src, dst, NULL, &ctx) != 0)
&& (errno != 0))
#endif /* WITH_ATTR */
- || (copy_tree (src, dst, false, reset_selinux,
+ || (copy_tree_impl (src, dst, false, reset_selinux,
old_uid, new_uid, old_gid, new_gid) != 0)
- || (utimes (dst, mt) != 0)) {
+ || (utimensat (dst->dirfd, dst->name, mt, AT_SYMLINK_NOFOLLOW) != 0)) {
err = -1;
}
@@ -540,9 +598,9 @@ static /*@null@*/char *readlink_malloc (const char *filename)
*
* Return 0 on success, -1 on error.
*/
-static int copy_symlink (const char *src, const char *dst,
+static int copy_symlink (const struct path_info *src, const struct path_info *dst,
unused bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid)
{
@@ -560,7 +618,7 @@ static int copy_symlink (const char *src, const char *dst,
* destination directory name.
*/
- oldlink = readlink_malloc (src);
+ oldlink = readlink_malloc (src->full_path);
if (NULL == oldlink) {
return -1;
}
@@ -580,13 +638,13 @@ static int copy_symlink (const char *src, const char *dst,
}
#ifdef WITH_SELINUX
- if (set_selinux_file_context (dst, S_IFLNK) != 0) {
+ if (set_selinux_file_context (dst->full_path, S_IFLNK) != 0) {
free (oldlink);
return -1;
}
#endif /* WITH_SELINUX */
- if ( (symlink (oldlink, dst) != 0)
- || (lchown_if_needed (dst, statp,
+ if ( (symlinkat (oldlink, dst->dirfd, dst->name) != 0)
+ || (chownat_if_needed (dst, statp,
old_uid, new_uid, old_gid, new_gid) != 0)) {
/* FIXME: there are no modes on symlinks, right?
* ACL could be copied, but this would be much more
@@ -600,14 +658,9 @@ static int copy_symlink (const char *src, const char *dst,
}
free (oldlink);
-#ifdef HAVE_LUTIMES
- /* 2007-10-18: We don't care about
- * exit status of lutimes because
- * it returns ENOSYS on many system
- * - not implemented
- */
- (void) lutimes (dst, mt);
-#endif /* HAVE_LUTIMES */
+ if (utimensat (dst->dirfd, dst->name, mt, AT_SYMLINK_NOFOLLOW) != 0) {
+ return -1;
+ }
return 0;
}
@@ -619,13 +672,13 @@ static int copy_symlink (const char *src, const char *dst,
*
* Return 0 on success, -1 on error.
*/
-static int copy_hardlink (const char *dst,
+static int copy_hardlink (const struct path_info *dst,
unused bool reset_selinux,
struct link_name *lp)
{
/* FIXME: selinux, ACL, Extended Attributes needed? */
- if (link (lp->ln_name, dst) != 0) {
+ if (linkat (AT_FDCWD, lp->ln_name, dst->dirfd, dst->name, 0) != 0) {
return -1;
}
@@ -649,28 +702,28 @@ static int copy_hardlink (const char *dst,
*
* Return 0 on success, -1 on error.
*/
-static int copy_special (const char *src, const char *dst,
+static int copy_special (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid)
{
int err = 0;
#ifdef WITH_SELINUX
- if (set_selinux_file_context (dst, statp->st_mode & S_IFMT) != 0) {
+ if (set_selinux_file_context (dst->full_path, statp->st_mode & S_IFMT) != 0) {
return -1;
}
#endif /* WITH_SELINUX */
- if ( (mknod (dst, statp->st_mode & ~07777U, statp->st_rdev) != 0)
- || (chown_if_needed (dst, statp,
+ if ( (mknodat (dst->dirfd, dst->name, statp->st_mode & ~07777U, statp->st_rdev) != 0)
+ || (chownat_if_needed (dst, statp,
old_uid, new_uid, old_gid, new_gid) != 0)
#ifdef WITH_ACL
- || ( (perm_copy_file (src, dst, &ctx) != 0)
+ || ( (perm_copy_path (src, dst, &ctx) != 0)
&& (errno != 0))
#else /* !WITH_ACL */
- || (chmod (dst, statp->st_mode & 07777) != 0)
+ || (fchmodat (dst->dirfd, dst->name, statp->st_mode & 07777, AT_SYMLINK_NOFOLLOW) != 0)
#endif /* !WITH_ACL */
#ifdef WITH_ATTR
/*
@@ -681,10 +734,10 @@ static int copy_special (const char *src, const char *dst,
* additional logic so that no unexpected permissions result.
*/
|| ( !reset_selinux
- && (attr_copy_file (src, dst, NULL, &ctx) != 0)
+ && (attr_copy_path (src, dst, NULL, &ctx) != 0)
&& (errno != 0))
#endif /* WITH_ATTR */
- || (utimes (dst, mt) != 0)) {
+ || (utimensat (dst->dirfd, dst->name, mt, AT_SYMLINK_NOFOLLOW) != 0)) {
err = -1;
}
@@ -737,9 +790,9 @@ static ssize_t full_write(int fd, const void *buf, size_t count) {
*
* Return 0 on success, -1 on error.
*/
-static int copy_file (const char *src, const char *dst,
+static int copy_file (const struct path_info *src, const struct path_info *dst,
bool reset_selinux,
- const struct stat *statp, const struct timeval mt[],
+ const struct stat *statp, const struct timespec mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid)
{
@@ -747,22 +800,22 @@ static int copy_file (const char *src, const char *dst,
int ifd;
int ofd;
- ifd = open (src, O_RDONLY|O_NOFOLLOW);
+ ifd = openat (src->dirfd, src->name, O_RDONLY|O_NOFOLLOW|O_CLOEXEC);
if (ifd < 0) {
return -1;
}
#ifdef WITH_SELINUX
- if (set_selinux_file_context (dst, S_IFREG) != 0) {
+ if (set_selinux_file_context (dst->full_path, S_IFREG) != 0) {
(void) close (ifd);
return -1;
}
#endif /* WITH_SELINUX */
- ofd = open (dst, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, statp->st_mode & 07777);
+ ofd = openat (dst->dirfd, dst->name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, statp->st_mode & 07777);
if ( (ofd < 0)
|| (fchown_if_needed (ofd, statp,
old_uid, new_uid, old_gid, new_gid) != 0)
#ifdef WITH_ACL
- || ( (perm_copy_fd (src, ifd, dst, ofd, &ctx) != 0)
+ || ( (perm_copy_fd (src->full_path, ifd, dst->full_path, ofd, &ctx) != 0)
&& (errno != 0))
#else /* !WITH_ACL */
|| (fchmod (ofd, statp->st_mode & 07777) != 0)
@@ -776,7 +829,7 @@ static int copy_file (const char *src, const char *dst,
* additional logic so that no unexpected permissions result.
*/
|| ( !reset_selinux
- && (attr_copy_fd (src, ifd, dst, ofd, NULL, &ctx) != 0)
+ && (attr_copy_fd (src->full_path, ifd, dst->full_path, ofd, NULL, &ctx) != 0)
&& (errno != 0))
#endif /* WITH_ATTR */
) {
@@ -812,23 +865,13 @@ static int copy_file (const char *src, const char *dst,
}
(void) close (ifd);
-
-#ifdef HAVE_FUTIMES
- if (futimes (ofd, mt) != 0) {
- (void) close (ofd);
- return -1;
- }
-#endif /* HAVE_FUTIMES */
-
if (close (ofd) != 0) {
return -1;
}
-#ifndef HAVE_FUTIMES
- if (utimes(dst, mt) != 0) {
+ if (utimensat (dst->dirfd, dst->name, mt, AT_SYMLINK_NOFOLLOW) != 0) {
return -1;
}
-#endif /* !HAVE_FUTIMES */
return err;
}
@@ -863,7 +906,70 @@ static int chown_function ## _if_needed (type_dst dst, \
return chown_function (dst, tmpuid, tmpgid); \
}
-def_chown_if_needed (chown, const char *)
-def_chown_if_needed (lchown, const char *)
def_chown_if_needed (fchown, int)
+static int chownat_if_needed (const struct path_info *dst,
+ const struct stat *statp,
+ uid_t old_uid, uid_t new_uid,
+ gid_t old_gid, gid_t new_gid)
+{
+ uid_t tmpuid = (uid_t) -1;
+ gid_t tmpgid = (gid_t) -1;
+
+ /* Use new_uid if old_uid is set to -1 or if the file was
+ * owned by the user. */
+ if (((uid_t) -1 == old_uid) || (statp->st_uid == old_uid)) {
+ tmpuid = new_uid;
+ }
+ /* Otherwise, or if new_uid was set to -1, we keep the same
+ * owner. */
+ if ((uid_t) -1 == tmpuid) {
+ tmpuid = statp->st_uid;
+ }
+
+ if (((gid_t) -1 == old_gid) || (statp->st_gid == old_gid)) {
+ tmpgid = new_gid;
+ }
+ if ((gid_t) -1 == tmpgid) {
+ tmpgid = statp->st_gid;
+ }
+
+ return fchownat (dst->dirfd, dst->name, tmpuid, tmpgid, AT_SYMLINK_NOFOLLOW);
+}
+
+/*
+ * copy_tree - copy files in a directory tree
+ *
+ * copy_tree() walks a directory tree and copies ordinary files
+ * as it goes.
+ *
+ * When reset_selinux is enabled, extended attributes (and thus
+ * SELinux attributes) are not copied.
+ *
+ * old_uid and new_uid are used to set the ownership of the copied
+ * files. Unless old_uid is set to -1, only the files owned by
+ * old_uid have their ownership changed to new_uid. In addition, if
+ * new_uid is set to -1, no ownership will be changed.
+ *
+ * The same logic applies for the group-ownership and
+ * old_gid/new_gid.
+ */
+int copy_tree (const char *src_root, const char *dst_root,
+ bool copy_root, bool reset_selinux,
+ uid_t old_uid, uid_t new_uid,
+ gid_t old_gid, gid_t new_gid)
+{
+ const struct path_info src = {
+ .full_path = src_root,
+ .dirfd = AT_FDCWD,
+ .name = src_root
+ };
+ const struct path_info dst = {
+ .full_path = dst_root,
+ .dirfd = AT_FDCWD,
+ .name = dst_root
+ };
+
+ return copy_tree_impl(&src, &dst, copy_root, reset_selinux,
+ old_uid, new_uid, old_gid, new_gid);
+}

View File

@ -0,0 +1,157 @@
From f6f8bcd2a57c06983296485cc028ebdf467ebfd7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:22 +0200
Subject: [PATCH] Avoid races in remove_tree()
Use *at() functions to pin the directory operating in to avoid being
redirected by unprivileged users replacing parts of paths by symlinks to
privileged files.
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/f6f8bcd2a57c06983296485cc028ebdf467ebfd7
---
libmisc/remove_tree.c | 87 +++++++++++++++++++------------------------
1 file changed, 39 insertions(+), 48 deletions(-)
diff --git a/libmisc/remove_tree.c b/libmisc/remove_tree.c
index 04bc7fc4a..3d76b95e0 100644
--- a/libmisc/remove_tree.c
+++ b/libmisc/remove_tree.c
@@ -11,6 +11,7 @@
#ident "$Id$"
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -21,90 +22,80 @@
#include "prototypes.h"
#include "defines.h"
-/*
- * remove_tree - delete a directory tree
- *
- * remove_tree() walks a directory tree and deletes all the files
- * and directories.
- * At the end, it deletes the root directory itself.
- */
-
-int remove_tree (const char *root, bool remove_root)
+static int remove_tree_at (int at_fd, const char *path, bool remove_root)
{
- char *new_name = NULL;
- int err = 0;
- struct DIRECT *ent;
- struct stat sb;
DIR *dir;
+ const struct DIRECT *ent;
+ int dir_fd, rc = 0;
- /*
- * Open the source directory and read each entry. Every file
- * entry in the directory is copied with the UID and GID set
- * to the provided values. As an added security feature only
- * regular files (and directories ...) are copied, and no file
- * is made set-ID.
- */
- dir = opendir (root);
- if (NULL == dir) {
+ dir_fd = openat (at_fd, path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
+ if (dir_fd < 0) {
+ return -1;
+ }
+
+ dir = fdopendir (dir_fd);
+ if (!dir) {
+ (void) close (dir_fd);
return -1;
}
+ /*
+ * Open the source directory and delete each entry.
+ */
while ((ent = readdir (dir))) {
- size_t new_len = strlen (root) + strlen (ent->d_name) + 2;
+ struct stat ent_sb;
/*
* Skip the "." and ".." entries
*/
-
if (strcmp (ent->d_name, ".") == 0 ||
strcmp (ent->d_name, "..") == 0) {
continue;
}
- /*
- * Make the filename for the current entry.
- */
-
- free (new_name);
- new_name = (char *) malloc (new_len);
- if (NULL == new_name) {
- err = -1;
+ rc = fstatat (dirfd(dir), ent->d_name, &ent_sb, AT_SYMLINK_NOFOLLOW);
+ if (rc < 0) {
break;
}
- (void) snprintf (new_name, new_len, "%s/%s", root, ent->d_name);
- if (LSTAT (new_name, &sb) == -1) {
- continue;
- }
- if (S_ISDIR (sb.st_mode)) {
+ if (S_ISDIR (ent_sb.st_mode)) {
/*
* Recursively delete this directory.
*/
- if (remove_tree (new_name, true) != 0) {
- err = -1;
+ if (remove_tree_at (dirfd(dir), ent->d_name, true) != 0) {
+ rc = -1;
break;
}
} else {
/*
* Delete the file.
*/
- if (unlink (new_name) != 0) {
- err = -1;
+ if (unlinkat (dirfd(dir), ent->d_name, 0) != 0) {
+ rc = -1;
break;
}
}
}
- if (NULL != new_name) {
- free (new_name);
- }
+
(void) closedir (dir);
- if (remove_root && (0 == err)) {
- if (rmdir (root) != 0) {
- err = -1;
+ if (remove_root && (0 == rc)) {
+ if (unlinkat (at_fd, path, AT_REMOVEDIR) != 0) {
+ rc = -1;
}
}
- return err;
+ return rc;
}
+/*
+ * remove_tree - delete a directory tree
+ *
+ * remove_tree() walks a directory tree and deletes all the files
+ * and directories.
+ * At the end, it deletes the root directory itself.
+ */
+int remove_tree (const char *root, bool remove_root)
+{
+ return remove_tree_at (AT_FDCWD, root, remove_root);
+}

View File

@ -0,0 +1,34 @@
From b4472167c2f5057d56686d3349a9b55fc508efe6 Mon Sep 17 00:00:00 2001
From: ed neville <ed@s5h.net>
Date: Fri, 31 Dec 2021 22:40:13 +0000
Subject: [PATCH] Adding nofollow to opens
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/b4472167c2f5057d56686d3349a9b55fc508efe6
---
libmisc/copydir.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
index f2130bcac..a296d925d 100644
--- a/libmisc/copydir.c
+++ b/libmisc/copydir.c
@@ -741,7 +741,7 @@ static int copy_file (const char *src, const char *dst,
char buf[1024];
ssize_t cnt;
- ifd = open (src, O_RDONLY);
+ ifd = open (src, O_RDONLY|O_NOFOLLOW);
if (ifd < 0) {
return -1;
}
@@ -751,7 +751,7 @@ static int copy_file (const char *src, const char *dst,
return -1;
}
#endif /* WITH_SELINUX */
- ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC, statp->st_mode & 07777);
+ ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, statp->st_mode & 07777);
if ( (ofd < 0)
|| (fchown_if_needed (ofd, statp,
old_uid, new_uid, old_gid, new_gid) != 0)

View File

@ -0,0 +1,28 @@
From 1d281273b149f2bb992d893d8ca9ffffddc95cc8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:26 +0200
Subject: [PATCH] Fail if regular file pre-exists in copy_tree()
Similar to the default behavior of mkdir(2), symlink(2), link(2) and
mknod(2).
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/1d281273b149f2bb992d893d8ca9ffffddc95cc8
---
libmisc/copydir.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
index 648f562a1..90895cfb0 100644
--- a/libmisc/copydir.c
+++ b/libmisc/copydir.c
@@ -723,7 +723,7 @@ static int copy_file (const char *src, const char *dst,
return -1;
}
#endif /* WITH_SELINUX */
- ofd = open (dst, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, statp->st_mode & 07777);
+ ofd = open (dst, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, statp->st_mode & 07777);
if ( (ofd < 0)
|| (fchown_if_needed (ofd, statp,
old_uid, new_uid, old_gid, new_gid) != 0)

View File

@ -0,0 +1,27 @@
From 049f9a7f6b320c728a6274299041e360381d7cd5 Mon Sep 17 00:00:00 2001
From: Andy Zaugg <andy.zaugg@gmail.com>
Date: Tue, 21 Sep 2021 21:51:10 -0700
Subject: [PATCH] Fix parentheses in configure.ac
Resolving issue https://github.com/shadow-maint/shadow/issues/419
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/049f9a7f6b320c728a6274299041e360381d7cd5
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 994836bda..6cbb6bd27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -345,7 +345,7 @@ if test "$with_sssd" = "yes"; then
[AC_MSG_ERROR([posix_spawn is needed for sssd support])])
fi
-AS_IF([test "$with_su" != "no"], AC_DEFINE(WITH_SU, 1, [Build with su])])
+AS_IF([test "$with_su" != "no"], AC_DEFINE(WITH_SU, 1, [Build with su]))
AM_CONDITIONAL([WITH_SU], [test "x$with_su" != "xno"])
dnl Check for some functions in libc first, only if not found check for

View File

@ -0,0 +1,34 @@
From 63a96706b1205f91c4a57de21ac56e996d270ff1 Mon Sep 17 00:00:00 2001
From: Tobias Stoeckmann <tobias@stoeckmann.org>
Date: Fri, 29 Oct 2021 19:44:46 +0200
Subject: [PATCH] Handle malformed lines in hushlogins file.
If a line in hushlogins file, e.g. /etc/hushlogins, starts with
'\0', then current code performs an out of boundary write.
If the line lacks a newline at the end, then another character is
overridden.
With strcspn both cases are solved.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/63a96706b1205f91c4a57de21ac56e996d270ff1
---
libmisc/hushed.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmisc/hushed.c b/libmisc/hushed.c
index b71b99ce2..3c3adafca 100644
--- a/libmisc/hushed.c
+++ b/libmisc/hushed.c
@@ -90,7 +90,7 @@ bool hushed (const char *username)
return false;
}
for (found = false; !found && (fgets (buf, (int) sizeof buf, fp) == buf);) {
- buf[strlen (buf) - 1] = '\0';
+ buf[strcspn (buf, "\n")] = '\0';
found = (strcmp (buf, pw->pw_shell) == 0) ||
(strcmp (buf, pw->pw_name) == 0);
}

View File

@ -0,0 +1,62 @@
From 624d57c08caceed306212d24c2147f6273f3fc4b Mon Sep 17 00:00:00 2001
From: Tobias Stoeckmann <tobias@stoeckmann.org>
Date: Sun, 14 Nov 2021 12:01:32 +0100
Subject: [PATCH] Improve child error handling
Always set SIGCHLD handler to default, even if the caller of vipw has
set SIGCHLD to ignore. If SIGCHLD is ignored no zombie processes would
be created, which in turn could mean that kill is called with an already
recycled pid.
Proof of Concept:
1. Compile nochld:
--
#include <signal.h>
#include <unistd.h>
int main(void) {
char *argv[] = { "vipw", NULL };
signal(SIGCHLD, SIG_IGN);
execvp("vipw", argv);
return 1;
}
--
2. Run nochld
3. Suspend child vi, which suspends vipw too:
`kill -STOP childpid`
4. Kill vi:
`kill -9 childpid`
5. You can see with ps that childpid is no zombie but disappeared
6. Bring vipw back into foreground
`fg`
The kill call sends SIGCONT to "childpid" which in turn could have been
already recycled for another process.
This is definitely not a vulnerability. It would take super user
operations, at which point an attacker would have already elevated
permissions.
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/624d57c08caceed306212d24c2147f6273f3fc4b
---
src/vipw.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/vipw.c b/src/vipw.c
index 94185c3df..1a69ef285 100644
--- a/src/vipw.c
+++ b/src/vipw.c
@@ -349,6 +349,9 @@ vipwedit (const char *file, int (*file_lock) (void), int (*file_unlock) (void))
sigprocmask(SIG_BLOCK, &mask, &omask);
}
+ /* set SIGCHLD to default for waitpid */
+ signal(SIGCHLD, SIG_DFL);
+
for (;;) {
pid = waitpid (pid, &status, WUNTRACED);
if ((pid != -1) && (WIFSTOPPED (status) != 0)) {

View File

@ -0,0 +1,98 @@
From f606314f0c22fb5d13e5af17a70860d57559e808 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:27 +0200
Subject: [PATCH] More robust file content copy in copy_tree()
Bail out on read(2) failure, continue on EINTR, support short writes and
increase chunk size.
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/f606314f0c22fb5d13e5af17a70860d57559e808
---
libmisc/copydir.c | 58 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 54 insertions(+), 4 deletions(-)
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
index 90895cfb0..95042187b 100644
--- a/libmisc/copydir.c
+++ b/libmisc/copydir.c
@@ -691,6 +691,42 @@ static int copy_special (const char *src, const char *dst,
return err;
}
+/*
+ * full_write - write entire buffer
+ *
+ * Write up to count bytes from the buffer starting at buf to the
+ * file referred to by the file descriptor fd.
+ * Retry in case of a short write.
+ *
+ * Returns the number of bytes written on success, -1 on error.
+ */
+static ssize_t full_write(int fd, const void *buf, size_t count) {
+ ssize_t written = 0;
+
+ while (count > 0) {
+ ssize_t res;
+
+ res = write(fd, buf, count);
+ if (res < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ return res;
+ }
+
+ if (res == 0) {
+ break;
+ }
+
+ written += res;
+ buf = (const unsigned char*)buf + res;
+ count -= (size_t)res;
+ }
+
+ return written;
+}
+
/*
* copy_file - copy a file
*
@@ -710,8 +746,6 @@ static int copy_file (const char *src, const char *dst,
int err = 0;
int ifd;
int ofd;
- char buf[1024];
- ssize_t cnt;
ifd = open (src, O_RDONLY|O_NOFOLLOW);
if (ifd < 0) {
@@ -753,8 +787,24 @@ static int copy_file (const char *src, const char *dst,
return -1;
}
- while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
- if (write (ofd, buf, (size_t)cnt) != cnt) {
+ while (true) {
+ char buf[8192];
+ ssize_t cnt;
+
+ cnt = read (ifd, buf, sizeof buf);
+ if (cnt < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ (void) close (ofd);
+ (void) close (ifd);
+ return -1;
+ }
+ if (cnt == 0) {
+ break;
+ }
+
+ if (full_write (ofd, buf, (size_t)cnt) < 0) {
(void) close (ofd);
(void) close (ifd);
return -1;

View File

@ -0,0 +1,43 @@
From 117bc66c6f95fa85ca75ecfdb8fbd3615deca0b6 Mon Sep 17 00:00:00 2001
From: Michael Vetter <jubalh@iodoru.org>
Date: Mon, 20 Sep 2021 11:04:50 +0200
Subject: [PATCH] Only free sgent if it was initialized
`sgent` is only initialized in `get_group()` if `is_shadowgrp` is true.
So we should also only attempt to free it if this is actually the case.
Can otherwise lead to:
```
free() double free detected in tcache 2 (gpasswd)
```
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/117bc66c6f95fa85ca75ecfdb8fbd3615deca0b6
---
src/gpasswd.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/src/gpasswd.c b/src/gpasswd.c
index a43d9a590..04bed83d6 100644
--- a/src/gpasswd.c
+++ b/src/gpasswd.c
@@ -1207,11 +1207,13 @@ int main (int argc, char **argv)
sssd_flush_cache (SSSD_DB_GROUP);
#ifdef SHADOWGRP
- if (sgent.sg_adm) {
- xfree(sgent.sg_adm);
- }
- if (sgent.sg_mem) {
- xfree(sgent.sg_mem);
+ if (is_shadowgrp) {
+ if (sgent.sg_adm) {
+ xfree(sgent.sg_adm);
+ }
+ if (sgent.sg_mem) {
+ xfree(sgent.sg_mem);
+ }
}
#endif
if (grent.gr_mem) {

View File

@ -0,0 +1,148 @@
From dab764d0195fc16d1d39330eee8a33e8917826d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Fri, 5 Aug 2022 17:57:24 +0200
Subject: [PATCH] Require symlink support
Require lstat(2), lchown(2), S_IFLNK and S_ISLNK from POSIX.1-2001.
Already unconditionally used in lib/tcbfuncs.c and lib/run_part.c.
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/dab764d0195fc16d1d39330eee8a33e8917826d8
---
configure.ac | 2 +-
lib/commonio.c | 2 --
lib/defines.h | 16 ----------------
libmisc/copydir.c | 10 ++--------
4 files changed, 3 insertions(+), 27 deletions(-)
diff --git a/configure.ac b/configure.ac
index b9a2263bb..7e954c29c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,7 +53,7 @@ AC_CHECK_HEADER([shadow.h],,[AC_MSG_ERROR([You need a libc with shadow.h])])
AC_CHECK_FUNCS(arc4random_buf l64a fchmod fchown fsync futimes getgroups \
gethostname getentropy getrandom getspnam gettimeofday getusershell \
- getutent initgroups lchown lckpwdf lstat lutimes memcpy memset \
+ getutent initgroups lckpwdf lutimes memcpy memset \
setgroups sigaction strchr updwtmp updwtmpx innetgr getpwnam_r \
getpwuid_r getgrnam_r getgrgid_r getspnam_r getaddrinfo ruserok \
dlopen)
diff --git a/lib/commonio.c b/lib/commonio.c
index 9e0fde600..80288d644 100644
--- a/lib/commonio.c
+++ b/lib/commonio.c
@@ -65,7 +65,6 @@ int lrename (const char *old, const char *new)
int res;
char *r = NULL;
-#if defined(S_ISLNK)
#ifndef __GLIBC__
char resolved_path[PATH_MAX];
#endif /* !__GLIBC__ */
@@ -82,7 +81,6 @@ int lrename (const char *old, const char *new)
new = r;
}
}
-#endif /* S_ISLNK */
res = rename (old, new);
diff --git a/lib/defines.h b/lib/defines.h
index 4a2b90c9e..ee33aa0da 100644
--- a/lib/defines.h
+++ b/lib/defines.h
@@ -205,22 +205,6 @@ static inline void memzero(void *ptr, size_t size)
# endif
#endif
-#ifndef S_ISLNK
-#define S_ISLNK(x) (0)
-#endif
-
-#if HAVE_LCHOWN
-#define LCHOWN lchown
-#else
-#define LCHOWN chown
-#endif
-
-#if HAVE_LSTAT
-#define LSTAT lstat
-#else
-#define LSTAT stat
-#endif
-
#if HAVE_TERMIOS_H
# include <termios.h>
# define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio)
diff --git a/libmisc/copydir.c b/libmisc/copydir.c
index 2929151db..648f562a1 100644
--- a/libmisc/copydir.c
+++ b/libmisc/copydir.c
@@ -56,14 +56,12 @@ static int copy_dir (const char *src, const char *dst,
const struct stat *statp, const struct timeval mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-#ifdef S_IFLNK
static /*@null@*/char *readlink_malloc (const char *filename);
static int copy_symlink (const char *src, const char *dst,
unused bool reset_selinux,
const struct stat *statp, const struct timeval mt[],
uid_t old_uid, uid_t new_uid,
gid_t old_gid, gid_t new_gid);
-#endif /* S_IFLNK */
static int copy_hardlink (const char *dst,
unused bool reset_selinux,
struct link_name *lp);
@@ -223,7 +221,7 @@ int copy_tree (const char *src_root, const char *dst_root,
return -1;
}
- if (LSTAT (src_root, &sb) == -1) {
+ if (lstat (src_root, &sb) == -1) {
return -1;
}
@@ -364,7 +362,7 @@ static int copy_entry (const char *src, const char *dst,
struct link_name *lp;
struct timeval mt[2];
- if (LSTAT (src, &sb) == -1) {
+ if (lstat (src, &sb) == -1) {
/* If we cannot stat the file, do not care. */
} else {
#ifdef HAVE_STRUCT_STAT_ST_ATIM
@@ -396,7 +394,6 @@ static int copy_entry (const char *src, const char *dst,
old_uid, new_uid, old_gid, new_gid);
}
-#ifdef S_IFLNK
/*
* Copy any symbolic links
*/
@@ -405,7 +402,6 @@ static int copy_entry (const char *src, const char *dst,
err = copy_symlink (src, dst, reset_selinux, &sb, mt,
old_uid, new_uid, old_gid, new_gid);
}
-#endif /* S_IFLNK */
/*
* See if this is a previously copied link
@@ -498,7 +494,6 @@ static int copy_dir (const char *src, const char *dst,
return err;
}
-#ifdef S_IFLNK
/*
* readlink_malloc - wrapper for readlink
*
@@ -616,7 +611,6 @@ static int copy_symlink (const char *src, const char *dst,
return 0;
}
-#endif /* S_IFLNK */
/*
* copy_hardlink - copy a hardlink

View File

@ -0,0 +1,29 @@
From 54ab542887994f8b6e5411469d6867e3a2e58800 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
Date: Thu, 26 Jan 2023 21:03:56 +0100
Subject: [PATCH] lib/btrfs: avoid NULL-dereference
btrfs.c:42:13: warning: use of NULL 'cmd' where non-null expected [CWE-476] [-Wanalyzer-null-argument]
Reviewed-by: Alejandro Colomar <alx@kernel.org>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/54ab542887994f8b6e5411469d6867e3a2e58800
---
libmisc/btrfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libmisc/btrfs.c b/libmisc/btrfs.c
index a2563f7c3..03915981c 100644
--- a/libmisc/btrfs.c
+++ b/libmisc/btrfs.c
@@ -39,7 +39,7 @@ static int run_btrfs_subvolume_cmd(const char *subcmd, const char *arg1, const c
NULL
};
- if (access(cmd, X_OK)) {
+ if (!cmd || access(cmd, X_OK)) {
return 1;
}

View File

@ -0,0 +1,70 @@
From d594243fbbdabc73fdee50886f6dd11867b5cfab Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedrosa@redhat.com>
Date: Thu, 18 Nov 2021 16:48:26 +0100
Subject: [PATCH] lib: check NULL before freeing passwd data
Add an additional NULL check condition in spw_free() and pw_free() to
avoid freeing an already empty pointer.
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/d594243fbbdabc73fdee50886f6dd11867b5cfab
---
lib/pwmem.c | 18 ++++++++++--------
lib/shadowmem.c | 12 +++++++-----
2 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/lib/pwmem.c b/lib/pwmem.c
index 17d2eb219..9f184d5e1 100644
--- a/lib/pwmem.c
+++ b/lib/pwmem.c
@@ -93,14 +93,16 @@
void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent)
{
- free (pwent->pw_name);
- if (pwent->pw_passwd) {
- memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
- free (pwent->pw_passwd);
+ if (pwent != NULL) {
+ free (pwent->pw_name);
+ if (pwent->pw_passwd) {
+ memzero (pwent->pw_passwd, strlen (pwent->pw_passwd));
+ free (pwent->pw_passwd);
+ }
+ free (pwent->pw_gecos);
+ free (pwent->pw_dir);
+ free (pwent->pw_shell);
+ free (pwent);
}
- free (pwent->pw_gecos);
- free (pwent->pw_dir);
- free (pwent->pw_shell);
- free (pwent);
}
diff --git a/lib/shadowmem.c b/lib/shadowmem.c
index 8989598f8..1d047cc04 100644
--- a/lib/shadowmem.c
+++ b/lib/shadowmem.c
@@ -79,11 +79,13 @@
void spw_free (/*@out@*/ /*@only@*/struct spwd *spent)
{
- free (spent->sp_namp);
- if (NULL != spent->sp_pwdp) {
- memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
- free (spent->sp_pwdp);
+ if (spent != NULL) {
+ free (spent->sp_namp);
+ if (NULL != spent->sp_pwdp) {
+ memzero (spent->sp_pwdp, strlen (spent->sp_pwdp));
+ free (spent->sp_pwdp);
+ }
+ free (spent);
}
- free (spent);
}

View File

@ -0,0 +1,58 @@
From d324c6776b3a1d4ac22bced543f72dc5dd366927 Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedrosa@redhat.com>
Date: Thu, 6 Oct 2022 11:21:18 +0200
Subject: [PATCH] libmisc: minimum id check for system accounts
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The minimum id allocation for system accounts shouldn't be 0 as this is
reserved for root.
Signed-off-by: Tomáš Mráz <tm@t8m.info>
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/d324c6776b3a1d4ac22bced543f72dc5dd366927
---
libmisc/find_new_gid.c | 7 +++++++
libmisc/find_new_uid.c | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/libmisc/find_new_gid.c b/libmisc/find_new_gid.c
index 666b61078..65ab5d013 100644
--- a/libmisc/find_new_gid.c
+++ b/libmisc/find_new_gid.c
@@ -60,6 +60,13 @@ static int get_ranges (bool sys_group, gid_t *min_id, gid_t *max_id,
(unsigned long) *max_id);
return EINVAL;
}
+ /*
+ * Zero is reserved for root and the allocation algorithm does not
+ * work right with it.
+ */
+ if (*min_id == 0) {
+ *min_id = (gid_t) 1;
+ }
} else {
/* Non-system groups */
diff --git a/libmisc/find_new_uid.c b/libmisc/find_new_uid.c
index 322d15ab7..5f7e74b53 100644
--- a/libmisc/find_new_uid.c
+++ b/libmisc/find_new_uid.c
@@ -60,6 +60,13 @@ static int get_ranges (bool sys_user, uid_t *min_id, uid_t *max_id,
(unsigned long) *max_id);
return EINVAL;
}
+ /*
+ * Zero is reserved for root and the allocation algorithm does not
+ * work right with it.
+ */
+ if (*min_id == 0) {
+ *min_id = (uid_t) 1;
+ }
} else {
/* Non-system users */

View File

@ -0,0 +1,45 @@
From 02b200c9aa501ad4e1651c553cea1aaf9e5e0f4f Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge@hallyn.com>
Date: Sat, 14 Aug 2021 14:24:03 -0500
Subject: [PATCH] man/po/Makefile.in: switch from xml2po to itstool
xml2po is deprecated. We've previously replaced xml2po with
itstool in man/generate_translations.mak, but there was still
an instance of it that only is exercised for 'make dist'.
Update that one. Now 'make dist' succeeds on a ubuntu focal
or newer host where xml2po is not available.
Signed-off-by: Serge Hallyn <serge@hallyn.com>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/02b200c9aa501ad4e1651c553cea1aaf9e5e0f4f
---
man/po/Makefile.in | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/man/po/Makefile.in b/man/po/Makefile.in
index deaa87058..f194957b4 100644
--- a/man/po/Makefile.in
+++ b/man/po/Makefile.in
@@ -90,9 +90,17 @@ $(DOMAIN).pot-update: $(XMLFILES) $(srcdir)/XMLFILES remove-potcdate.sed
@set -e; tmpdir=`pwd`; \
echo "cd $(top_srcdir)/man"; \
cd $(top_srcdir)/man; \
- echo "xml2po --expand-all-entities -o $$tmpdir/$(DOMAIN).po $(notdir $(XMLFILES))"; \
- xml2po --expand-all-entities -o $$tmpdir/$(DOMAIN).po $(notdir $(XMLFILES)); \
- cd $$tmpdir
+ files=""; \
+ for file in $(notdir $(XMLFILES)); do \
+ if grep -q SHADOW-CONFIG-HERE $$file ; then \
+ sed -e 's/^<!-- SHADOW-CONFIG-HERE -->/<!ENTITY % config SYSTEM "config.xml">%config;/' $$file > $$file.out; \
+ else \
+ sed -e 's/^\(<!DOCTYPE .*docbookx.dtd"\)>/\1 [<!ENTITY % config SYSTEM "config.xml">%config;]>/' $$file > $$file.out; \
+ fi; \
+ files="$$files $$file.out"; \
+ done; \
+ itstool -d -o $$tmpdir/$(DOMAIN).po $$files; \
+ cd $$tmpdir; \
test ! -f $(DOMAIN).po || { \
if test -f $(srcdir)/$(DOMAIN).pot; then \
sed -f remove-potcdate.sed < $(srcdir)/$(DOMAIN).pot > $(DOMAIN).1po && \

View File

@ -0,0 +1,125 @@
From 4e1f674c41724dd96ad2c3a0c02ac9f6666697ba Mon Sep 17 00:00:00 2001
From: ed neville <ed@s5h.net>
Date: Mon, 27 Mar 2023 20:23:03 +0100
Subject: [PATCH] run_parts for groupadd and groupdel
run_parts currently exists in useradd and userdel, this commit mirrors
the functionality with groupadd and groupdel
Hook for group{add,del} to include killing processes that have group
membership that would no longer exist to avoid membership ID reuse.
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/4e1f674c41724dd96ad2c3a0c02ac9f6666697ba
---
.../groupdel-pre.d/01-kill_group_procs.sh | 26 +++++++++++++++++++
src/groupadd.c | 11 ++++++++
src/groupdel.c | 11 ++++++++
3 files changed, 48 insertions(+)
create mode 100644 etc/shadow-maint/groupdel-pre.d/01-kill_group_procs.sh
diff --git a/etc/shadow-maint/groupdel-pre.d/01-kill_group_procs.sh b/etc/shadow-maint/groupdel-pre.d/01-kill_group_procs.sh
new file mode 100644
index 000000000..10db52794
--- /dev/null
+++ b/etc/shadow-maint/groupdel-pre.d/01-kill_group_procs.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+GROUPID=`awk -F: '$1 == "'"${SUBJECT}"'" { print $3 }' /etc/group`
+
+if [ "${GROUPID}" = "" ]; then
+ exit 0
+fi
+
+for status in /proc/*/status; do
+ # either this isn't a process or its already dead since expanding the list
+ [ -f "$status" ] || continue
+
+ tbuf=${status%/status}
+ pid=${tbuf#/proc/}
+ case "$pid" in
+ "$$") continue;;
+ [0-9]*) :;;
+ *) continue
+ esac
+
+ grep -q '^Groups:.*\b'"${GROUPID}"'\b.*' "/proc/$pid/status" || continue
+
+ kill -9 "$pid" || echo "cannot kill $pid" 1>&2
+done
+
diff --git a/src/groupadd.c b/src/groupadd.c
index 311421014..2eda1c680 100644
--- a/src/groupadd.c
+++ b/src/groupadd.c
@@ -34,6 +34,7 @@
#ifdef SHADOWGRP
#include "sgroupio.h"
#endif
+#include "run_part.h"
/*
* exit status values
@@ -603,6 +604,11 @@ int main (int argc, char **argv)
check_perms ();
+ if (run_parts ("/etc/shadow-maint/groupadd-pre.d", group_name,
+ "groupadd")) {
+ exit(1);
+ }
+
#ifdef SHADOWGRP
is_shadow_grp = sgr_file_present ();
#endif
@@ -621,6 +627,11 @@ int main (int argc, char **argv)
grp_update ();
close_files ();
+ if (run_parts ("/etc/shadow-maint/groupadd-post.d", group_name,
+ "groupadd")) {
+ exit(1);
+ }
+
nscd_flush_cache ("group");
sssd_flush_cache (SSSD_DB_GROUP);
diff --git a/src/groupdel.c b/src/groupdel.c
index fdccf5e15..bae4367ba 100644
--- a/src/groupdel.c
+++ b/src/groupdel.c
@@ -32,6 +32,7 @@
#ifdef SHADOWGRP
#include "sgroupio.h"
#endif
+#include "run_part.h"
/*
* Global variables
*/
@@ -461,6 +462,11 @@ int main (int argc, char **argv)
group_busy (group_id);
}
+ if (run_parts ("/etc/shadow-maint/groupdel-pre.d", group_name,
+ "groupdel")) {
+ exit(1);
+ }
+
/*
* Do the hard stuff - open the files, delete the group entries,
* then close and update the files.
@@ -471,6 +477,11 @@ int main (int argc, char **argv)
close_files ();
+ if (run_parts ("/etc/shadow-maint/groupdel-post.d", group_name,
+ "groupdel")) {
+ exit(1);
+ }
+
nscd_flush_cache ("group");
sssd_flush_cache (SSSD_DB_GROUP);

View File

@ -0,0 +1,60 @@
From 23634d8de7d01ed65bd70e316d4da4fe4d9b370d Mon Sep 17 00:00:00 2001
From: genBTC <genBTC@gmx.com>
Date: Tue, 23 Aug 2022 10:25:51 -0400
Subject: [PATCH] useradd: check MLS enablement before setting serange
Resolves: https://github.com/shadow-maint/shadow/issues/552
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/23634d8de7d01ed65bd70e316d4da4fe4d9b370d
---
lib/semanage.c | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/lib/semanage.c b/lib/semanage.c
index 54f996238..082a6e8ee 100644
--- a/lib/semanage.c
+++ b/lib/semanage.c
@@ -122,12 +122,14 @@ static int semanage_user_mod (semanage_handle_t *handle,
goto done;
}
- ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
- if (ret != 0) {
- fprintf (shadow_logfd,
- _("Could not set serange for %s\n"), login_name);
- ret = 1;
- goto done;
+ if (semanage_mls_enabled(handle)) {
+ ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
+ if (ret != 0) {
+ fprintf (shadow_logfd,
+ _("Could not set serange for %s\n"), login_name);
+ ret = 1;
+ goto done;
+ }
}
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);
@@ -179,13 +181,14 @@ static int semanage_user_add (semanage_handle_t *handle,
goto done;
}
- ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
- if (ret != 0) {
- fprintf (shadow_logfd,
- _("Could not set serange for %s\n"),
- login_name);
- ret = 1;
- goto done;
+ if (semanage_mls_enabled(handle)) {
+ ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE);
+ if (ret != 0) {
+ fprintf (shadow_logfd,
+ _("Could not set serange for %s\n"), login_name);
+ ret = 1;
+ goto done;
+ }
}
ret = semanage_seuser_set_sename (handle, seuser, seuser_name);

View File

@ -0,0 +1,39 @@
From e0524e813a3bae2891b33a66f35876841c11cee7 Mon Sep 17 00:00:00 2001
From: Iker Pedrosa <ipedrosa@redhat.com>
Date: Mon, 24 Oct 2022 10:46:36 +0200
Subject: [PATCH] useradd: check if subid range exists for user
Check if a user already has a subid range before assigning one.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2012929
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Conflict: NA
Reference: https://github.com/shadow-maint/shadow/commit/f6f8bcd2a57c06983296485cc028ebdf467ebfd7
---
src/useradd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/useradd.c b/src/useradd.c
index 7ea0a9c4d..e784d6029 100644
--- a/src/useradd.c
+++ b/src/useradd.c
@@ -2188,14 +2188,14 @@ static void usr_update (unsigned long subuid_count, unsigned long subgid_count)
fail_exit (E_PW_UPDATE);
}
#ifdef ENABLE_SUBIDS
- if (is_sub_uid &&
+ if (is_sub_uid && !local_sub_uid_assigned(user_name) &&
(sub_uid_add(user_name, sub_uid_start, subuid_count) == 0)) {
fprintf (stderr,
_("%s: failed to prepare the new %s entry\n"),
Prog, sub_uid_dbname ());
fail_exit (E_SUB_UID_UPDATE);
}
- if (is_sub_gid &&
+ if (is_sub_gid && !local_sub_gid_assigned(user_name) &&
(sub_gid_add(user_name, sub_gid_start, subgid_count) == 0)) {
fprintf (stderr,
_("%s: failed to prepare the new %s entry\n"),

26
chpasswd.sh Normal file
View File

@ -0,0 +1,26 @@
# chpasswd(8) completion -*- shell-script -*-
_chpasswd()
{
local cur prev words cword split
_init_completion -s || return
case $prev in
-c|--crypt)
COMPREPLY=( $( compgen -W 'DES MD5 NONE SHA256 SHA512 SM3' \
-- "$cur" ) )
return
;;
-s|--sha-rounds)
return
;;
esac
$split && return
COMPREPLY=( $( compgen -W '$( _parse_help "$1" )' -- "$cur" ) )
[[ $COMPREPLY == *= ]] && compopt -o nospace
} &&
complete -F _chpasswd chpasswd
# ex: filetype=sh

View File

@ -1,6 +1,6 @@
Name: shadow Name: shadow
Version: 4.9 Version: 4.9
Release: 13 Release: 14
Epoch: 2 Epoch: 2
License: BSD and GPLv2+ License: BSD and GPLv2+
Summary: Tools for managing accounts and shadow password files Summary: Tools for managing accounts and shadow password files
@ -12,6 +12,7 @@ Source4: shadow-bsd.txt
Source5: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt Source5: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
Source6: chpasswd Source6: chpasswd
Source7: newusers Source7: newusers
Source8: chpasswd.sh
%global includesubiddir %{_includedir}/shadow %global includesubiddir %{_includedir}/shadow
@ -37,41 +38,62 @@ Patch17: newgrp-fix-segmentation-fault.patch
Patch18: groupdel-fix-SIGSEGV-when-passwd-does-not-exist.patch Patch18: groupdel-fix-SIGSEGV-when-passwd-does-not-exist.patch
Patch19: shadow-add-sm3-crypt-support.patch Patch19: shadow-add-sm3-crypt-support.patch
Patch20: backport-useradd-modify-check-ID-range-for-system-users.patch Patch20: backport-useradd-modify-check-ID-range-for-system-users.patch
Patch21: backport-Add-header-guards.patch Patch21: backport-man-po-Makefile.in-switch-from-xml2po-to-itstool.patch
Patch22: backport-Change-to-strncat.patch Patch22: backport-Only-free-sgent-if-it-was-initialized.patch
Patch23: backport-Do-not-return-garbage-in-run_parts.patch Patch23: backport-Fix-parentheses-in-configure.ac.patch
Patch24: backport-Handle-ERANGE-error-correctly.patch Patch24: backport-Added-documentation-around-CREATE_MAIL_SPOOL.patch
Patch25: backport-Initialize-local-variables.patch Patch26: backport-Handle-malformed-lines-in-hushlogins-file.patch
Patch26: backport-Remove-commented-out-code-and-FIXMEs.patch Patch27: backport-Improve-child-error-handling.patch
Patch27: backport-Remove-redeclared-variable.patch Patch28: backport-lib-check-NULL-before-freeing-passwd-data.patch
Patch28: backport-libmisc-add-check-fopen-return-value-in-read_random_.patch Patch29: backport-CVE-2013-4235.patch
Patch29: backport-passwd-erase-password-copy-on-all-error-branches.patch Patch30: backport-Add-header-guards.patch
Patch30: backport-chpasswd-add-get_salt-for-generating-salt-value.patch Patch31: backport-Change-to-strncat.patch
Patch31: backport-chpasswd-fix-function-problem-with-R-parameter.patch Patch32: backport-Handle-ERANGE-error-correctly.patch
Patch32: backport-Fix-off-by-one-mistakes.patch Patch33: backport-Do-not-return-garbage-in-run_parts.patch
Patch33: backport-Fix-typos-in-length-calculations.patch Patch34: backport-Initialize-local-variables.patch
Patch34: backport-Correctly-handle-illegal-system-file-in-tz.patch Patch35: backport-libmisc-add-check-fopen-return-value-in-read_random_.patch
Patch35: backport-Explicitly-override-only-newlines.patch Patch36: backport-passwd-erase-password-copy-on-all-error-branches.patch
Patch36: backport-Prevent-out-of-boundary-access.patch Patch37: backport-Remove-commented-out-code-and-FIXMEs.patch
Patch37: backport-Added-control-character-check.patch Patch38: backport-Remove-redeclared-variable.patch
Patch38: backport-Overhaul-valid_field.patch Patch39: backport-chpasswd-add-get_salt-for-generating-salt-value.patch
Patch39: backport-Read-whole-line-in-yes_or_no.patch Patch40: backport-chpasswd-fix-function-problem-with-R-parameter.patch
Patch40: backport-commonio-free-removed-database-entries.patch Patch41: backport-script-to-kill-subjects-processes-from-userdel.patch
Patch41: backport-semanage-disconnect-to-free-libsemanage-internals.patch Patch42: backport-Avoid-races-in-chown_tree.patch
Patch42: shadow-Remove-encrypted-passwd-for-useradd-gr.patch Patch43: backport-Avoid-races-in-remove_tree.patch
Patch43: backport-process_prefix_flag-Drop-privileges.patch Patch44: backport-Require-symlink-support.patch
Patch44: backport-chsh-Verify-that-login-shell-path-is-absolute.patch Patch45: backport-Fail-if-regular-file-pre-exists-in-copy_tree.patch
Patch45: backport-Plug-econf-memory-leaks.patch Patch46: backport-More-robust-file-content-copy-in-copy_tree.patch
Patch46: backport-def_load-avoid-NULL-deref.patch Patch47: backport-Address-minor-compiler-warnings.patch
Patch47: backport-Check-if-crypt_method-null-before-dereferencing.patch Patch48: backport-Avoid-races-in-copy_tree.patch
Patch48: backport-usermod-fix-off-by-one-issues.patch Patch49: backport-useradd-check-MLS-enablement-before-setting-serange.patch
Patch49: backport-gpasswd-1-Fix-password-leak.patch Patch50: backport-libmisc-minimum-id-check-for-system-accounts.patch
Patch50: backport-chgpasswd-fix-segfault-in-command-line-options.patch Patch51: backort-useradd-Fix-buffer-overflow-when-using-a-prefix.patch
Patch51: backport-chpasswd-add-IS_CRYPT_METHOD.patch Patch52: backport-useradd-check-if-subid-range-exists-for-user.patch
Patch52: backport-Fix-yescrypt-support.patch Patch53: backport-Fix-off-by-one-mistakes.patch
Patch53: backport-newgrp-fix-potential-string-injection.patch Patch54: backport-Fix-typos-in-length-calculations.patch
Patch54: backport-script-to-kill-subjects-processes-from-userdel.patch Patch55: backport-Correctly-handle-illegal-system-file-in-tz.patch
Patch55: backport-shadow-userdel-add-the-adaptation-to-the-busybox-ps-.patch Patch56: backport-Explicitly-override-only-newlines.patch
Patch57: backport-Prevent-out-of-boundary-access.patch
Patch58: backport-Added-control-character-check.patch
Patch59: backport-Overhaul-valid_field.patch
Patch60: backport-Read-whole-line-in-yes_or_no.patch
Patch61: backport-run_parts-for-groupadd-and-groupdel.patch
Patch62: backport-commonio-free-removed-database-entries.patch
Patch63: backport-semanage-disconnect-to-free-libsemanage-internals.patch
Patch64: backport-process_prefix_flag-Drop-privileges.patch
Patch65: backport-chsh-Verify-that-login-shell-path-is-absolute.patch
Patch66: backport-Plug-econf-memory-leaks.patch
Patch67: backport-def_load-avoid-NULL-deref.patch
Patch68: backport-Check-if-crypt_method-null-before-dereferencing.patch
Patch69: backport-usermod-fix-off-by-one-issues.patch
Patch70: backport-gpasswd-1-Fix-password-leak.patch
Patch71: backport-chgpasswd-fix-segfault-in-command-line-options.patch
Patch72: backport-chpasswd-add-IS_CRYPT_METHOD.patch
Patch73: backport-Fix-yescrypt-support.patch
Patch74: backport-newgrp-fix-potential-string-injection.patch
Patch75: shadow-Remove-encrypted-passwd-for-useradd-gr.patch
Patch76: backport-shadow-userdel-add-the-adaptation-to-the-busybox-ps-.patch
Patch77: backport-lib-btrfs-avoid-NULL-dereference.patch
BuildRequires: gcc, libselinux-devel, audit-libs-devel, libsemanage-devel BuildRequires: gcc, libselinux-devel, audit-libs-devel, libsemanage-devel
BuildRequires: libacl-devel, libattr-devel BuildRequires: libacl-devel, libattr-devel
@ -134,6 +156,8 @@ install -p -c -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/%{_sysconfdir}/login.defs
install -p -c -m 0600 %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/default/useradd install -p -c -m 0600 %{SOURCE2} $RPM_BUILD_ROOT/%{_sysconfdir}/default/useradd
install -p -c -m 0644 %{SOURCE6} $RPM_BUILD_ROOT/%{_sysconfdir}/pam.d/chpasswd install -p -c -m 0644 %{SOURCE6} $RPM_BUILD_ROOT/%{_sysconfdir}/pam.d/chpasswd
install -p -c -m 0644 %{SOURCE7} $RPM_BUILD_ROOT/%{_sysconfdir}/pam.d/newusers install -p -c -m 0644 %{SOURCE7} $RPM_BUILD_ROOT/%{_sysconfdir}/pam.d/newusers
mkdir -p -m755 $RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d
install -p -c -m 0644 %{SOURCE8} $RPM_BUILD_ROOT/%{_sysconfdir}/bash_completion.d/chpasswd.sh
ln -s useradd $RPM_BUILD_ROOT%{_sbindir}/adduser ln -s useradd $RPM_BUILD_ROOT%{_sbindir}/adduser
ln -s useradd.8 $RPM_BUILD_ROOT/%{_mandir}/man8/adduser.8 ln -s useradd.8 $RPM_BUILD_ROOT/%{_mandir}/man8/adduser.8
@ -228,6 +252,7 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.la
%{_sysconfdir}/pam.d/chpasswd %{_sysconfdir}/pam.d/chpasswd
%{_sysconfdir}/pam.d/groupmems %{_sysconfdir}/pam.d/groupmems
%{_sysconfdir}/pam.d/newusers %{_sysconfdir}/pam.d/newusers
%{_sysconfdir}/bash_completion.d/chpasswd.sh
%files subid-devel %files subid-devel
%{_libdir}/libsubid.so.* %{_libdir}/libsubid.so.*
@ -238,6 +263,9 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/libsubid.la
%{_mandir}/*/* %{_mandir}/*/*
%changelog %changelog
* Thu Nov 9 2023 wangqingsan <wangqingsan@huawei.com> - 2:4.9-14
- backport some patches
* Wed Sep 20 2023 wangyunjia <yunjia.wang@huawei.com> - 2:4.9-13 * Wed Sep 20 2023 wangyunjia <yunjia.wang@huawei.com> - 2:4.9-13
- backport some patches - backport some patches