From owner-svn-src-head@freebsd.org Thu Aug 10 16:45:07 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 0B4DCDD78CE; Thu, 10 Aug 2017 16:45:07 +0000 (UTC) (envelope-from oshogbo@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D5B4468B88; Thu, 10 Aug 2017 16:45:06 +0000 (UTC) (envelope-from oshogbo@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v7AGj51o089921; Thu, 10 Aug 2017 16:45:05 GMT (envelope-from oshogbo@FreeBSD.org) Received: (from oshogbo@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v7AGj5r4089920; Thu, 10 Aug 2017 16:45:05 GMT (envelope-from oshogbo@FreeBSD.org) Message-Id: <201708101645.v7AGj5r4089920@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: oshogbo set sender to oshogbo@FreeBSD.org using -f From: Mariusz Zaborski Date: Thu, 10 Aug 2017 16:45:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r322369 - head/lib/libutil X-SVN-Group: head X-SVN-Commit-Author: oshogbo X-SVN-Commit-Paths: head/lib/libutil X-SVN-Commit-Revision: 322369 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 10 Aug 2017 16:45:07 -0000 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 #include +#include +#include +#include +#include +#include #include #include -#include -#include #include #include -#include -#include -#include +#include 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