svn commit: r360215 - stable/12/lib/libc/nls

Xin LI delphij at FreeBSD.org
Thu Apr 23 04:51:33 UTC 2020


Author: delphij
Date: Thu Apr 23 04:51:32 2020
New Revision: 360215
URL: https://svnweb.freebsd.org/changeset/base/360215

Log:
  MFC r359118: Fix race condition in catopen(3).

Modified:
  stable/12/lib/libc/nls/msgcat.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/lib/libc/nls/msgcat.c
==============================================================================
--- stable/12/lib/libc/nls/msgcat.c	Thu Apr 23 04:27:55 2020	(r360214)
+++ stable/12/lib/libc/nls/msgcat.c	Thu Apr 23 04:51:32 2020	(r360215)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 
 #include <arpa/inet.h>		/* for ntohl() */
+#include <machine/atomic.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -76,19 +77,25 @@ __FBSDID("$FreeBSD$");
 
 #define	NLERR		((nl_catd) -1)
 #define NLRETERR(errc)  { errno = errc; return (NLERR); }
-#define SAVEFAIL(n, l, e)	{ WLOCK(NLERR);					\
-				  np = malloc(sizeof(struct catentry));		\
+#define SAVEFAIL(n, l, e)	{ np = calloc(1, sizeof(struct catentry));	\
 				  if (np != NULL) {				\
 				  	np->name = strdup(n);			\
-					np->path = NULL;			\
 					np->catd = NLERR;			\
-					np->refcount = 0;			\
 					np->lang = (l == NULL) ? NULL :		\
 					    strdup(l);				\
 					np->caterrno = e;			\
-				  	SLIST_INSERT_HEAD(&cache, np, list);	\
+					if (np->name == NULL ||			\
+					    (l != NULL && np->lang == NULL)) {	\
+						free(np->name);			\
+						free(np->lang);			\
+						free(np);			\
+					} else {				\
+						WLOCK(NLERR);			\
+						SLIST_INSERT_HEAD(&cache, np,	\
+						    list);			\
+						UNLOCK;				\
+					}					\
 				  }						\
-				  UNLOCK;					\
 				  errno = e;					\
 				}
 
@@ -152,7 +159,7 @@ catopen(const char *name, int type)
 				NLRETERR(np->caterrno);
 			} else {
 				/* Found cached successful entry */
-				np->refcount++;
+				atomic_add_int(&np->refcount, 1);
 				UNLOCK;
 				return (np->catd);
 			}
@@ -355,8 +362,7 @@ catclose(nl_catd catd)
 	WLOCK(-1);
 	SLIST_FOREACH(np, &cache, list) {
 		if (catd == np->catd) {
-			np->refcount--;
-			if (np->refcount == 0)
+			if (atomic_fetchadd_int(&np->refcount, -1) == 1)
 				catfree(np);
 			break;
 		}
@@ -376,6 +382,7 @@ load_msgcat(const char *path, const char *name, const 
 	nl_catd	catd;
 	struct catentry *np;
 	void *data;
+	char *copy_path, *copy_name, *copy_lang;
 	int fd;
 
 	/* path/name will never be NULL here */
@@ -387,7 +394,7 @@ load_msgcat(const char *path, const char *name, const 
 	RLOCK(NLERR);
 	SLIST_FOREACH(np, &cache, list) {
 		if ((np->path != NULL) && (strcmp(np->path, path) == 0)) {
-			np->refcount++;
+			atomic_add_int(&np->refcount, 1);
 			UNLOCK;
 			return (np->catd);
 		}
@@ -432,7 +439,20 @@ load_msgcat(const char *path, const char *name, const 
 		NLRETERR(EFTYPE);
 	}
 
-	if ((catd = malloc(sizeof (*catd))) == NULL) {
+	copy_name = strdup(name);
+	copy_path = strdup(path);
+	copy_lang = (lang == NULL) ? NULL : strdup(lang);
+	catd = malloc(sizeof (*catd));
+	np = calloc(1, sizeof(struct catentry));
+
+	if (copy_name == NULL || copy_path == NULL ||
+	    (lang != NULL && copy_lang == NULL) ||
+	    catd == NULL || np == NULL) {
+		free(copy_name);
+		free(copy_path);
+		free(copy_lang);
+		free(catd);
+		free(np);
 		munmap(data, (size_t)st.st_size);
 		SAVEFAIL(name, lang, ENOMEM);
 		NLRETERR(ENOMEM);
@@ -442,16 +462,13 @@ load_msgcat(const char *path, const char *name, const 
 	catd->__size = (int)st.st_size;
 
 	/* Caching opened catalog */
+	np->name = copy_name;
+	np->path = copy_path;
+	np->catd = catd;
+	np->lang = copy_lang;
+	atomic_store_int(&np->refcount, 1);
 	WLOCK(NLERR);
-	if ((np = malloc(sizeof(struct catentry))) != NULL) {
-		np->name = strdup(name);
-		np->path = strdup(path);
-		np->catd = catd;
-		np->lang = (lang == NULL) ? NULL : strdup(lang);
-		np->refcount = 1;
-		np->caterrno = 0;
-		SLIST_INSERT_HEAD(&cache, np, list);
-	}
+	SLIST_INSERT_HEAD(&cache, np, list);
 	UNLOCK;
 	return (catd);
 }


More information about the svn-src-stable-12 mailing list