Author: garga (ports committer)
Date: Mon Jul  6 13:01:01 2015
New Revision: 285205
URL: https://svnweb.freebsd.org/changeset/base/285205

Log:
  MFC r285050, r285053, r285059:
  
  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 information 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:  re (kib), bapt (implicit agreed)
  Sponsored by: Netgate

Modified:
  stable/10/lib/libutil/gr_util.c
  stable/10/lib/libutil/pw_util.3
  stable/10/lib/libutil/pw_util.c
  stable/10/usr.sbin/pwd_mkdb/pwd_mkdb.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/lib/libutil/gr_util.c
==============================================================================
--- stable/10/lib/libutil/gr_util.c     Mon Jul  6 12:40:31 2015        
(r285204)
+++ stable/10/lib/libutil/gr_util.c     Mon Jul  6 13:01:01 2015        
(r285205)
@@ -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: stable/10/lib/libutil/pw_util.3
==============================================================================
--- stable/10/lib/libutil/pw_util.3     Mon Jul  6 12:40:31 2015        
(r285204)
+++ stable/10/lib/libutil/pw_util.3     Mon Jul  6 13:01:01 2015        
(r285205)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 30, 2012
+.Dd July 02, 2015
 .Dt PW_UTIL 3
 .Os
 .Sh NAME
@@ -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 the master password file on success
+and -1 on failure.
 .Pp
 The
 .Fn pw_scan

Modified: stable/10/lib/libutil/pw_util.c
==============================================================================
--- stable/10/lib/libutil/pw_util.c     Mon Jul  6 12:40:31 2015        
(r285204)
+++ stable/10/lib/libutil/pw_util.c     Mon Jul  6 13:01:01 2015        
(r285205)
@@ -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: stable/10/usr.sbin/pwd_mkdb/pwd_mkdb.c
==============================================================================
--- stable/10/usr.sbin/pwd_mkdb/pwd_mkdb.c      Mon Jul  6 12:40:31 2015        
(r285204)
+++ stable/10/usr.sbin/pwd_mkdb/pwd_mkdb.c      Mon Jul  6 13:01:01 2015        
(r285205)
@@ -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>
@@ -224,14 +225,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);
 
@@ -288,13 +289,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;
@@ -714,13 +715,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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to