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 _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"