svn commit: r322369 - head/lib/libutil

Mariusz Zaborski oshogbo at FreeBSD.org
Thu Aug 10 16:45:07 UTC 2017


Author: oshogbo
Date: Thu Aug 10 16:45:05 2017
New Revision: 322369
URL: https://svnweb.freebsd.org/changeset/base/322369

Log:
  Store directory descriptor in the pidfh structure and use unlinkat(2)
  function instead of unlink(2).
  
  Now when pidfile_remove() uses unlinkat(2) to remove the pidfile
  it is safe to use this function in capability mode.
  
  Style fix: sort headers.
  
  PR:		220524
  Reviewed by:	markj
  Differential Revision:	https://reviews.freebsd.org/D11692

Modified:
  head/lib/libutil/pidfile.c

Modified: head/lib/libutil/pidfile.c
==============================================================================
--- head/lib/libutil/pidfile.c	Thu Aug 10 15:42:25 2017	(r322368)
+++ head/lib/libutil/pidfile.c	Thu Aug 10 16:45:05 2017	(r322369)
@@ -31,19 +31,22 @@ __FBSDID("$FreeBSD$");
 #include <sys/file.h>
 #include <sys/stat.h>
 
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <libutil.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <string.h>
 #include <time.h>
-#include <err.h>
-#include <errno.h>
-#include <libutil.h>
+#include <unistd.h>
 
 struct pidfh {
+	int	pf_dirfd;
 	int	pf_fd;
-	char	pf_path[MAXPATHLEN + 1];
+	char	pf_dir[MAXPATHLEN + 1];
+	char	pf_filename[MAXPATHLEN + 1];
 	dev_t	pf_dev;
 	ino_t	pf_ino;
 };
@@ -68,12 +71,12 @@ pidfile_verify(const struct pidfh *pfh)
 }
 
 static int
-pidfile_read(const char *path, pid_t *pidptr)
+pidfile_read(int dirfd, const char *filename, pid_t *pidptr)
 {
 	char buf[16], *endptr;
 	int error, fd, i;
 
-	fd = open(path, O_RDONLY | O_CLOEXEC);
+	fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
 	if (fd == -1)
 		return (errno);
 
@@ -98,32 +101,50 @@ pidfile_open(const char *path, mode_t mode, pid_t *pid
 {
 	struct pidfh *pfh;
 	struct stat sb;
-	int error, fd, len, count;
+	int error, fd, dirfd, dirlen, filenamelen, count;
 	struct timespec rqtp;
 
 	pfh = malloc(sizeof(*pfh));
 	if (pfh == NULL)
 		return (NULL);
 
-	if (path == NULL)
-		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
-		    "/var/run/%s.pid", getprogname());
-	else
-		len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
+	if (path == NULL) {
+		dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
+		    "/var/run/");
+		filenamelen = snprintf(pfh->pf_filename,
+		    sizeof(pfh->pf_filename), "%s.pid", getprogname());
+	} else {
+		dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
 		    "%s", path);
-	if (len >= (int)sizeof(pfh->pf_path)) {
+		filenamelen = snprintf(pfh->pf_filename,
+		    sizeof(pfh->pf_filename), "%s", path);
+
+		dirname(pfh->pf_dir);
+		basename(pfh->pf_filename);
+	}
+
+	if (dirlen >= (int)sizeof(pfh->pf_dir) ||
+	    filenamelen >= (int)sizeof(pfh->pf_filename)) {
 		free(pfh);
 		errno = ENAMETOOLONG;
 		return (NULL);
 	}
 
+	dirfd = open(pfh->pf_dir, O_CLOEXEC | O_DIRECTORY | O_NONBLOCK);
+	if (dirfd == -1) {
+		error = errno;
+		free(pfh);
+		errno = error;
+		return (NULL);
+	}
+
 	/*
 	 * Open the PID file and obtain exclusive lock.
 	 * We truncate PID file here only to remove old PID immediately,
 	 * PID file will be truncated again in pidfile_write(), so
 	 * pidfile_write() can be called multiple times.
 	 */
-	fd = flopen(pfh->pf_path,
+	fd = flopenat(dirfd, pfh->pf_filename,
 	    O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
 	if (fd == -1) {
 		if (errno == EWOULDBLOCK) {
@@ -134,8 +155,8 @@ pidfile_open(const char *path, mode_t mode, pid_t *pid
 				rqtp.tv_sec = 0;
 				rqtp.tv_nsec = 5000000;
 				for (;;) {
-					errno = pidfile_read(pfh->pf_path,
-					    pidptr);
+					errno = pidfile_read(dirfd,
+					    pfh->pf_filename, pidptr);
 					if (errno != EAGAIN || --count == 0)
 						break;
 					nanosleep(&rqtp, 0);
@@ -146,7 +167,10 @@ pidfile_open(const char *path, mode_t mode, pid_t *pid
 					errno = EEXIST;
 			}
 		}
+		error = errno;
+		close(dirfd);
 		free(pfh);
+		errno = error;
 		return (NULL);
 	}
 
@@ -156,13 +180,15 @@ pidfile_open(const char *path, mode_t mode, pid_t *pid
 	 */
 	if (fstat(fd, &sb) == -1) {
 		error = errno;
-		unlink(pfh->pf_path);
+		unlinkat(dirfd, pfh->pf_filename, 0);
+		close(dirfd);
 		close(fd);
 		free(pfh);
 		errno = error;
 		return (NULL);
 	}
 
+	pfh->pf_dirfd = dirfd;
 	pfh->pf_fd = fd;
 	pfh->pf_dev = sb.st_dev;
 	pfh->pf_ino = sb.st_ino;
@@ -223,6 +249,9 @@ pidfile_close(struct pidfh *pfh)
 
 	if (close(pfh->pf_fd) == -1)
 		error = errno;
+	if (close(pfh->pf_dirfd) == -1 && error == 0)
+		error = errno;
+
 	free(pfh);
 	if (error != 0) {
 		errno = error;
@@ -242,12 +271,12 @@ _pidfile_remove(struct pidfh *pfh, int freeit)
 		return (-1);
 	}
 
-	if (unlink(pfh->pf_path) == -1)
+	if (unlinkat(pfh->pf_dirfd, pfh->pf_filename, 0) == -1)
 		error = errno;
-	if (close(pfh->pf_fd) == -1) {
-		if (error == 0)
-			error = errno;
-	}
+	if (close(pfh->pf_fd) == -1 && error == 0)
+		error = errno;
+	if (close(pfh->pf_dirfd) == -1 && error == 0)
+		error = errno;
 	if (freeit)
 		free(pfh);
 	else


More information about the svn-src-head mailing list