Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Jul 2015 17:31:00 +0000 (UTC)
From:      Renato Botelho <garga@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r285050 - in head: lib/libutil usr.sbin/pwd_mkdb
Message-ID:  <201507021731.t62HV074085188@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: garga (ports committer)
Date: Thu Jul  2 17:30:59 2015
New Revision: 285050
URL: https://svnweb.freebsd.org/changeset/base/285050

Log:
  When passwd or group information is changed (by pw, vipw, chpass, ...)
  temporary file is created and then a rename() call move it to official file.
  This operation didn't have any check to make sure data was written to disk
  and if a power cycle happens system could end up with a 0 length passwd
  or group database.
  
  There is a pfSense bug with more infor about it:
  
  https://redmine.pfsense.org/issues/4523
  
  The following changes were made to protect passwd and group operations:
  
  * lib/libutil/gr_util.c:
   - Replace mkstemp() by mkostemp() with O_SYNC flag to create temp file
   - After rename(), fsync() call on directory for faster result
  
  * lib/libutil/pw_util.c
   - Replace mkstemp() by mkostemp() with O_SYNC flag to create temp file
  
  * usr.sbin/pwd_mkdb/pwd_mkdb.c
   - Added O_SYNC flag on dbopen() calls
   - After rename(), fsync() call on directory for faster result
  
  * lib/libutil/pw_util.3
   - pw_lock() returns a file descriptor to master password file on success
  
  Differential Revision:	https://reviews.freebsd.org/D2978
  Approved by:	bapt
  Sponsored by:	Netgate

Modified:
  head/lib/libutil/gr_util.c
  head/lib/libutil/pw_util.3
  head/lib/libutil/pw_util.c
  head/usr.sbin/pwd_mkdb/pwd_mkdb.c

Modified: head/lib/libutil/gr_util.c
==============================================================================
--- head/lib/libutil/gr_util.c	Thu Jul  2 16:17:05 2015	(r285049)
+++ head/lib/libutil/gr_util.c	Thu Jul  2 17:30:59 2015	(r285050)
@@ -141,7 +141,7 @@ gr_tmp(int mfd)
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
-	if ((tfd = mkstemp(tempname)) == -1)
+	if ((tfd = mkostemp(tempname, O_SYNC)) == -1)
 		return (-1);
 	if (mfd != -1) {
 		while ((nr = read(mfd, buf, sizeof(buf))) > 0)
@@ -318,10 +318,28 @@ gr_copy(int ffd, int tfd, const struct g
 int
 gr_mkdb(void)
 {
+	int fd;
+
 	if (chmod(tempname, 0644) != 0)
 		return (-1);
 
-	return (rename(tempname, group_file));
+	if (rename(tempname, group_file) != 0)
+		return (-1);
+
+	/*
+	 * Make sure new group file is safe on disk. To improve performance we
+	 * will call fsync() to the directory where file lies
+	 */
+	if ((fd = open(group_dir, O_RDONLY|O_DIRECTORY)) == -1)
+		return (-1);
+
+	if (fsync(fd) != 0) {
+		close(fd);
+		return (-1);
+	}
+
+	close(fd);
+	return(0);
 }
 
 /*

Modified: head/lib/libutil/pw_util.3
==============================================================================
--- head/lib/libutil/pw_util.3	Thu Jul  2 16:17:05 2015	(r285049)
+++ head/lib/libutil/pw_util.3	Thu Jul  2 17:30:59 2015	(r285050)
@@ -233,7 +233,8 @@ function returns 0 in case of success an
 The
 .Fn pw_lock
 function locks the master password file.
-It returns 0 in case of success and -1 in case of failure.
+It returns a file descriptor to master password file in case of success
+and -1 in case of failure.
 .Pp
 The
 .Fn pw_scan

Modified: head/lib/libutil/pw_util.c
==============================================================================
--- head/lib/libutil/pw_util.c	Thu Jul  2 16:17:05 2015	(r285049)
+++ head/lib/libutil/pw_util.c	Thu Jul  2 17:30:59 2015	(r285050)
@@ -226,7 +226,7 @@ pw_tmp(int mfd)
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
-	if ((tfd = mkstemp(tempname)) == -1)
+	if ((tfd = mkostemp(tempname, O_SYNC)) == -1)
 		return (-1);
 	if (mfd != -1) {
 		while ((nr = read(mfd, buf, sizeof(buf))) > 0)

Modified: head/usr.sbin/pwd_mkdb/pwd_mkdb.c
==============================================================================
--- head/usr.sbin/pwd_mkdb/pwd_mkdb.c	Thu Jul  2 16:17:05 2015	(r285049)
+++ head/usr.sbin/pwd_mkdb/pwd_mkdb.c	Thu Jul  2 17:30:59 2015	(r285050)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <libgen.h>
 #include <limits.h>
 #include <pwd.h>
 #include <signal.h>
@@ -227,14 +228,14 @@ main(int argc, char *argv[])
 		clean = FILE_INSECURE;
 		cp(buf2, buf, PERM_INSECURE);
 		dp = dbopen(buf,
-		    O_RDWR|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
+		    O_RDWR|O_EXCL|O_SYNC, PERM_INSECURE, DB_HASH, &openinfo);
 		if (dp == NULL)
 			error(buf);
 
 		clean = FILE_SECURE;
 		cp(sbuf2, sbuf, PERM_SECURE);
 		sdp = dbopen(sbuf,
-		    O_RDWR|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+		    O_RDWR|O_EXCL|O_SYNC, PERM_SECURE, DB_HASH, &openinfo);
 		if (sdp == NULL)
 			error(sbuf);
 
@@ -291,13 +292,13 @@ main(int argc, char *argv[])
 		method = 0;
 	} else {
 		dp = dbopen(buf,
-		    O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
+		    O_RDWR|O_CREAT|O_EXCL|O_SYNC, PERM_INSECURE, DB_HASH, &openinfo);
 		if (dp == NULL)
 			error(buf);
 		clean = FILE_INSECURE;
 
 		sdp = dbopen(sbuf,
-		    O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+		    O_RDWR|O_CREAT|O_EXCL|O_SYNC, PERM_SECURE, DB_HASH, &openinfo);
 		if (sdp == NULL)
 			error(sbuf);
 		clean = FILE_SECURE;
@@ -721,13 +722,27 @@ void
 mv(char *from, char *to)
 {
 	char buf[MAXPATHLEN];
+	char *to_dir;
+	int to_dir_fd = -1;
 
-	if (rename(from, to)) {
+	/*
+	 * Make sure file is safe on disk. To improve performance we will call
+	 * fsync() to the directory where file lies
+	 */
+	if (rename(from, to) != 0 ||
+	    (to_dir = dirname(to)) == NULL ||
+	    (to_dir_fd = open(to_dir, O_RDONLY|O_DIRECTORY)) == -1 ||
+	    fsync(to_dir_fd) != 0) {
 		int sverrno = errno;
 		(void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
 		errno = sverrno;
+		if (to_dir_fd != -1)
+			close(to_dir_fd);
 		error(buf);
 	}
+
+	if (to_dir_fd != -1)
+		close(to_dir_fd);
 }
 
 void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507021731.t62HV074085188>