Fix the issue that the pid file cannot be rewritten

This commit is contained in:
yang_zhuang_zhuang 2021-12-20 10:03:24 +08:00
parent 27fd1b15ac
commit 280fac351f
2 changed files with 144 additions and 1 deletions

View File

@ -0,0 +1,136 @@
From b177311aee0b3cf17af0e1760e18dfb60d99e024 Mon Sep 17 00:00:00 2001
From: Wayne Davison <wayne@opencoder.net>
Date: Thu, 4 Jun 2020 17:55:20 -0700
Subject: [PATCH] Use a lock to not fail on a left-over pid file.
---
clientserver.c | 62 ++++++++++++++++++++++++++++++++++++++------------
rsyncd.conf.yo | 7 +++---
socket.c | 3 +++
3 files changed, 55 insertions(+), 17 deletions(-)
diff --git a/clientserver.c b/clientserver.c
index 3af97d84..d56f5d52 100644
--- a/clientserver.c
+++ b/clientserver.c
@@ -66,6 +66,7 @@ extern gid_t our_gid;
char *auth_user;
int read_only = 0;
int module_id = -1;
+int pid_file_fd = -1;
struct chmod_mode_struct *daemon_chmod_modes;
/* module_dirlen is the length of the module_dir string when in daemon
@@ -1149,26 +1150,59 @@ int start_daemon(int f_in, int f_out)
static void create_pid_file(void)
{
char *pid_file = lp_pid_file();
- char pidbuf[16];
- pid_t pid = getpid();
- int fd, len;
+ char pidbuf[32];
+ STRUCT_STAT st1, st2;
+ char *fail = NULL;
if (!pid_file || !*pid_file)
return;
- cleanup_set_pid(pid);
- if ((fd = do_open(pid_file, O_WRONLY|O_CREAT|O_EXCL, 0666)) == -1) {
- failure:
- cleanup_set_pid(0);
- fprintf(stderr, "failed to create pid file %s: %s\n", pid_file, strerror(errno));
- rsyserr(FLOG, errno, "failed to create pid file %s", pid_file);
+ /* These tests make sure that a temp-style lock dir is handled safely. */
+ st1.st_mode = 0;
+ if (do_lstat(pid_file, &st1) == 0 && !S_ISREG(st1.st_mode) && unlink(pid_file) < 0)
+ fail = "unlink";
+ else if ((pid_file_fd = do_open(pid_file, O_RDWR|O_CREAT, 0664)) < 0)
+ fail = S_ISREG(st1.st_mode) ? "open" : "create";
+ else if (!lock_range(pid_file_fd, 0, 4))
+ fail = "lock";
+ else if (do_fstat(pid_file_fd, &st1) < 0)
+ fail = "fstat opened";
+ else if (st1.st_size >= (int)sizeof pidbuf)
+ fail = "find small";
+ else if (do_lstat(pid_file, &st2) < 0)
+ fail = "lstat";
+ else if (!S_ISREG(st1.st_mode))
+ fail = "avoid file overwrite race for";
+ else if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
+ fail = "verify stat info for";
+#ifdef HAVE_FTRUNCATE
+ else if (do_ftruncate(pid_file_fd, 0) < 0)
+ fail = "truncate";
+#endif
+ else {
+ pid_t pid = getpid();
+ int len = snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid);
+#ifndef HAVE_FTRUNCATE
+ /* What can we do with a too-long file and no truncate? I guess we'll add extra newlines. */
+ while (len < st1.st_size) /* We already verfified that size+1 chars fits in the buffer. */
+ pidbuf[len++] = '\n';
+ /* We don't need the buffer to end in a '\0' (and we may not have room to add it). */
+#endif
+ if (write(pid_file_fd, pidbuf, len) != len)
+ fail = "write";
+ cleanup_set_pid(pid); /* Mark the file for removal on exit, even if the write failed. */
+ }
+
+ if (fail) {
+ char msg[1024];
+ snprintf(msg, sizeof msg, "failed to %s pid file %s: %s\n",
+ fail, pid_file, strerror(errno));
+ fputs(msg, stderr);
+ rprintf(FLOG, "%s", msg);
exit_cleanup(RERR_FILEIO);
}
- snprintf(pidbuf, sizeof pidbuf, "%d\n", (int)pid);
- len = strlen(pidbuf);
- if (write(fd, pidbuf, len) != len)
- goto failure;
- close(fd);
+
+ /* The file is left open so that the lock remains valid. It is closed in our forked child procs. */
}
/* Become a daemon, discarding the controlling terminal. */
diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
index aac4a7f2..c8338664 100644
--- a/rsyncd.conf.yo
+++ b/rsyncd.conf.yo
@@ -103,9 +103,10 @@ This can be overridden by the bf(--dparam=motdfile=FILE)
command-line option when starting the daemon.
dit(bf(pid file)) This parameter tells the rsync daemon to write
-its process ID to that file. If the file already exists, the rsync
-daemon will abort rather than overwrite the file.
-This can be overridden by the bf(--dparam=pidfile=FILE)
+its process ID to that file. The rsync keeps the file locked so that
+it can know when it is safe to overwrite an existing file.
+
+The filename can be overridden by the bf(--dparam=pidfile=FILE)
command-line option when starting the daemon.
dit(bf(port)) You can override the default port the daemon will listen on
diff --git a/socket.c b/socket.c
index 70fb1695..11ab4a83 100644
--- a/socket.c
+++ b/socket.c
@@ -38,6 +38,7 @@ extern char *bind_address;
extern char *sockopts;
extern int default_af_hint;
extern int connect_timeout;
+extern int pid_file_fd;
#ifdef HAVE_SIGACTION
static struct sigaction sigact;
@@ -609,6 +610,8 @@ void start_accept_loop(int port, int (*fn)(int, int))
if ((pid = fork()) == 0) {
int ret;
+ if (pid_file_fd >= 0)
+ close(pid_file_fd);
for (i = 0; sp[i] >= 0; i++)
close(sp[i]);
/* Re-open log file in child before possibly giving

View File

@ -1,6 +1,6 @@
Name: rsync
Version: 3.1.3
Release: 6
Release: 7
Summary: Fast incremental file transfer utility
License: GPLv3+
URL: http://rsync.samba.org/
@ -32,6 +32,7 @@ Patch6009: Fix-zlib-CVE-2016-9843.patch
Patch6010: Fix-bug-in-try_dests_reg-that-Florian-Zumbiehl-point.patch
Patch6011: Try-to-fix-the-iconv-crash-in-bug-11338.patch
Patch6012: CVE-2017-17433.patch
Patch6013: backport-Use-a-lock-to-not-fail-on-a-left-over-pid-file.patch
%description
Rsync is an open source utility that provides fast incremental file transfer.
@ -90,6 +91,12 @@ install -D -m644 %{SOURCE6} %{buildroot}/%{_unitdir}/rsyncd@.service
%{_mandir}/man5/rsyncd.conf.5*
%changelog
* Mon Dec 20 2021 yangzhuangzhuang<yangzhuangzhuang1@huawei.com> - 3.1.3-7
- Type:bugfix
- ID:NA
- SUG:NA
- DESC:Fix the issue that the pid file cannot be rewritten
* Fri Sep 27 2019 chengquan<chengquan3@huawei.com> - 3.1.3-6
- Type:bugfix
- ID:NA