CVE-2015-5224 (published 2017-08-23T15:29Z)

The mkostemp function in login-utils in util-linux when used incorrectly allows remote attackers to cause file name collision and possibly other attacks.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/karelzak/util-linux
commit_details: repo_url: https://github.com/karelzak/util-linux
author: Karel Zak
author_date: 2015-08-24 10:05:55+02:00
msg: chsh, chfn, vipw: fix filenames collision

The utils when compiled WITHOUT libuser then mkostemp()ing
"/etc/%s.XXXXXX" where the filename prefix is argv[0] basename.

An attacker could repeatedly execute the util with modified argv[0]
and after many many attempts mkostemp() may generate suffix which
makes sense. The result maybe temporary file with name like rc.status
ld.so.preload or krb5.keytab, etc.

Note that distros usually use libuser based ch{sh,fn} or stuff from
shadow-utils.

It's probably very minor security bug.

Addresses: CVE-2015-5224
Signed-off-by: Karel Zak <kzak@redhat.com>
repository: repo_url: https://github.com/karelzak/util-linux
repo_name: util-linux/util-linux
repo_language: C
owner: karelzak
file_changes: filename: fileutils.h
change_type: ModificationType.MODIFY
diff: @@ -7,14 +7,14 @@
 
 #include "c.h"
 
-extern int xmkstemp(char **tmpname, char *dir);
+extern int xmkstemp(char **tmpname, const char *dir, const char *prefix);
 
-static inline FILE *xfmkstemp(char **tmpname, char *dir)
+static inline FILE *xfmkstemp(char **tmpname, const char *dir, const char *prefix)
 {
 	int fd;
 	FILE *ret;
 
-	fd = xmkstemp(tmpname, dir);
+	fd = xmkstemp(tmpname, dir, prefix);
 	if (fd == -1)
 		return NULL;
 

programming_language: C
filename: fileutils.c
change_type: ModificationType.MODIFY
diff: @@ -15,27 +15,20 @@
 
 /* Create open temporary file in safe way.  Please notice that the
  * file permissions are -rw------- by default. */
-int xmkstemp(char **tmpname, char *dir)
+int xmkstemp(char **tmpname, const char *dir, const char *prefix)
 {
 	char *localtmp;
-	char *tmpenv;
+	const char *tmpenv;
 	mode_t old_mode;
 	int fd, rc;
 
 	/* Some use cases must be capable of being moved atomically
 	 * with rename(2), which is the reason why dir is here.  */
-	if (dir != NULL)
-		tmpenv = dir;
-	else
-		tmpenv = getenv("TMPDIR");
-
-	if (tmpenv)
-		rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv,
-			  program_invocation_short_name);
-	else
-		rc = asprintf(&localtmp, "%s/%s.XXXXXX", _PATH_TMP,
-			  program_invocation_short_name);
+	tmpenv = dir ? dir : getenv("TMPDIR");
+	if (!tmpenv)
+		tmpenv = _PATH_TMP;
 
+	rc = asprintf(&localtmp, "%s/%s.XXXXXX", tmpenv, prefix);
 	if (rc < 0)
 		return -1;
 
@@ -107,7 +100,7 @@ int main(void)
 {
 	FILE *f;
 	char *tmpname;
-	f = xfmkstemp(&tmpname, NULL);
+	f = xfmkstemp(&tmpname, NULL, "test");
 	unlink(tmpname);
 	free(tmpname);
 	fclose(f);

programming_language: C
filename: chfn.c
change_type: ModificationType.MODIFY
diff: @@ -373,7 +373,7 @@ static int save_new_data(struct chfn_control *ctl)
 #else /* HAVE_LIBUSER */
 	/* write the new struct passwd to the passwd file. */
 	ctl->pw->pw_gecos = gecos;
-	if (setpwnam(ctl->pw) < 0) {
+	if (setpwnam(ctl->pw, ".chfn") < 0) {
 		warn("setpwnam failed");
 #endif
 		printf(_

programming_language: C
filename: chsh.c
change_type: ModificationType.MODIFY
diff: @@ -323,7 +323,7 @@ int main(int argc, char **argv)
 		errx(EXIT_FAILURE, _("Shell *NOT* changed.  Try again later."));
 #else
 	pw->pw_shell = info.shell;
-	if (setpwnam(pw) < 0)
+	if (setpwnam(pw, ".chsh") < 0)
 		err(EXIT_FAILURE, _("setpwnam failed\n"
 			"Shell *NOT* changed.  Try again later."));
 #endif

programming_language: C
filename: setpwnam.c
change_type: ModificationType.MODIFY
diff: @@ -71,7 +71,7 @@ static void pw_init(void);
  *	If the given username exists in the passwd file, the entry is
  *	replaced with the given entry.
  */
-int setpwnam(struct passwd *pwd)
+int setpwnam(struct passwd *pwd, const char *prefix)
 {
 	FILE *fp = NULL, *pwf = NULL;
 	int save_errno;
@@ -81,11 +81,10 @@ int setpwnam(struct passwd *pwd)
 	int contlen, rc;
 	char *linebuf = NULL;
 	char *tmpname = NULL;
-	char *atomic_dir = "/etc";
 
 	pw_init();
 
-	if ((fp = xfmkstemp(&tmpname, atomic_dir)) == NULL)
+	if ((fp = xfmkstemp(&tmpname, "/etc", prefix)) == NULL)
 		return -1;
 
 	/* ptmp should be owned by root.root or root.wheel */

programming_language: C
filename: setpwnam.h
change_type: ModificationType.MODIFY
diff: @@ -11,6 +11,8 @@
  *  published by the Free Software Foundation; either version 2 of the
  *  License, or (at your option) any later version.
  */
+#ifndef UTIL_LINUX_SETPWNAM_H
+#define UTIL_LINUX_SETPWNAM_H
 
 #include "pathnames.h"
 
@@ -26,4 +28,6 @@
 # define SGROUP_FILE	"/tmp/gshadow"
 #endif
 
-extern int setpwnam (struct passwd *pwd);
+extern int setpwnam (struct passwd *pwd, const char *prefix);
+
+#endif /* UTIL_LINUX_SETPWNAM_H */

programming_language: C
filename: vipw.c
change_type: ModificationType.MODIFY
diff: @@ -135,9 +135,8 @@ static FILE * pw_tmpfile(int lockfd)
 {
 	FILE *fd;
 	char *tmpname = NULL;
-	char *dir = "/etc";
 
-	if ((fd = xfmkstemp(&tmpname, dir)) == NULL) {
+	if ((fd = xfmkstemp(&tmpname, "/etc", ".vipw")) == NULL) {
 		ulckpwdf();
 		err(EXIT_FAILURE, _("can't open temporary file"));
 	}

programming_language: C