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
This commit is contained in:
parent
303cbb93c5
commit
4f9612a321
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=322369
@ -31,19 +31,22 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <libutil.h>
|
#include <libutil.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
struct pidfh {
|
struct pidfh {
|
||||||
|
int pf_dirfd;
|
||||||
int pf_fd;
|
int pf_fd;
|
||||||
char pf_path[MAXPATHLEN + 1];
|
char pf_dir[MAXPATHLEN + 1];
|
||||||
|
char pf_filename[MAXPATHLEN + 1];
|
||||||
dev_t pf_dev;
|
dev_t pf_dev;
|
||||||
ino_t pf_ino;
|
ino_t pf_ino;
|
||||||
};
|
};
|
||||||
@ -68,12 +71,12 @@ pidfile_verify(const struct pidfh *pfh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pidfile_read(const char *path, pid_t *pidptr)
|
pidfile_read(int dirfd, const char *filename, pid_t *pidptr)
|
||||||
{
|
{
|
||||||
char buf[16], *endptr;
|
char buf[16], *endptr;
|
||||||
int error, fd, i;
|
int error, fd, i;
|
||||||
|
|
||||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
fd = openat(dirfd, filename, O_RDONLY | O_CLOEXEC);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
return (errno);
|
return (errno);
|
||||||
|
|
||||||
@ -98,32 +101,50 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
|
|||||||
{
|
{
|
||||||
struct pidfh *pfh;
|
struct pidfh *pfh;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int error, fd, len, count;
|
int error, fd, dirfd, dirlen, filenamelen, count;
|
||||||
struct timespec rqtp;
|
struct timespec rqtp;
|
||||||
|
|
||||||
pfh = malloc(sizeof(*pfh));
|
pfh = malloc(sizeof(*pfh));
|
||||||
if (pfh == NULL)
|
if (pfh == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
if (path == NULL)
|
if (path == NULL) {
|
||||||
len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
|
dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
|
||||||
"/var/run/%s.pid", getprogname());
|
"/var/run/");
|
||||||
else
|
filenamelen = snprintf(pfh->pf_filename,
|
||||||
len = snprintf(pfh->pf_path, sizeof(pfh->pf_path),
|
sizeof(pfh->pf_filename), "%s.pid", getprogname());
|
||||||
|
} else {
|
||||||
|
dirlen = snprintf(pfh->pf_dir, sizeof(pfh->pf_dir),
|
||||||
"%s", path);
|
"%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);
|
free(pfh);
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return (NULL);
|
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.
|
* Open the PID file and obtain exclusive lock.
|
||||||
* We truncate PID file here only to remove old PID immediately,
|
* We truncate PID file here only to remove old PID immediately,
|
||||||
* PID file will be truncated again in pidfile_write(), so
|
* PID file will be truncated again in pidfile_write(), so
|
||||||
* pidfile_write() can be called multiple times.
|
* 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);
|
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
if (errno == EWOULDBLOCK) {
|
if (errno == EWOULDBLOCK) {
|
||||||
@ -134,8 +155,8 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
|
|||||||
rqtp.tv_sec = 0;
|
rqtp.tv_sec = 0;
|
||||||
rqtp.tv_nsec = 5000000;
|
rqtp.tv_nsec = 5000000;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
errno = pidfile_read(pfh->pf_path,
|
errno = pidfile_read(dirfd,
|
||||||
pidptr);
|
pfh->pf_filename, pidptr);
|
||||||
if (errno != EAGAIN || --count == 0)
|
if (errno != EAGAIN || --count == 0)
|
||||||
break;
|
break;
|
||||||
nanosleep(&rqtp, 0);
|
nanosleep(&rqtp, 0);
|
||||||
@ -146,7 +167,10 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
|
|||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
error = errno;
|
||||||
|
close(dirfd);
|
||||||
free(pfh);
|
free(pfh);
|
||||||
|
errno = error;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,13 +180,15 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
|
|||||||
*/
|
*/
|
||||||
if (fstat(fd, &sb) == -1) {
|
if (fstat(fd, &sb) == -1) {
|
||||||
error = errno;
|
error = errno;
|
||||||
unlink(pfh->pf_path);
|
unlinkat(dirfd, pfh->pf_filename, 0);
|
||||||
|
close(dirfd);
|
||||||
close(fd);
|
close(fd);
|
||||||
free(pfh);
|
free(pfh);
|
||||||
errno = error;
|
errno = error;
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pfh->pf_dirfd = dirfd;
|
||||||
pfh->pf_fd = fd;
|
pfh->pf_fd = fd;
|
||||||
pfh->pf_dev = sb.st_dev;
|
pfh->pf_dev = sb.st_dev;
|
||||||
pfh->pf_ino = sb.st_ino;
|
pfh->pf_ino = sb.st_ino;
|
||||||
@ -223,6 +249,9 @@ pidfile_close(struct pidfh *pfh)
|
|||||||
|
|
||||||
if (close(pfh->pf_fd) == -1)
|
if (close(pfh->pf_fd) == -1)
|
||||||
error = errno;
|
error = errno;
|
||||||
|
if (close(pfh->pf_dirfd) == -1 && error == 0)
|
||||||
|
error = errno;
|
||||||
|
|
||||||
free(pfh);
|
free(pfh);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
errno = error;
|
errno = error;
|
||||||
@ -242,12 +271,12 @@ _pidfile_remove(struct pidfh *pfh, int freeit)
|
|||||||
return (-1);
|
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 && error == 0)
|
||||||
|
error = errno;
|
||||||
|
if (close(pfh->pf_dirfd) == -1 && error == 0)
|
||||||
error = errno;
|
error = errno;
|
||||||
if (close(pfh->pf_fd) == -1) {
|
|
||||||
if (error == 0)
|
|
||||||
error = errno;
|
|
||||||
}
|
|
||||||
if (freeit)
|
if (freeit)
|
||||||
free(pfh);
|
free(pfh);
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user