michal-grzedzicki / rpms / rpm

Forked from rpms/rpm 4 months ago
Clone
c2c80e
From 534fd1f0c84b12ba6080a46e07c57ef913c77cba Mon Sep 17 00:00:00 2001
c2c80e
From: Radovan Sroka <rsroka@redhat.com>
c2c80e
Date: Thu, 25 Aug 2022 15:38:01 +0200
c2c80e
Subject: [PATCH] fapolicyd: Make write() nonblocking
c2c80e
c2c80e
- switch to read only and non blocking mode for pipe
c2c80e
- add 1 minute loop to wait for pipe to reappear
c2c80e
c2c80e
Sometimes during the system update/upgrade fapolicyd
c2c80e
get restarted e.g. when systemd gets updated.
c2c80e
That can lead to the situation where fapolicyd pipe
c2c80e
has been removed and created again.
c2c80e
In such cases rpm-plugin-fapolicyd gets stuck on
c2c80e
write() to the pipe which does not exist anymore.
c2c80e
After switching to non blocking file descriptor
c2c80e
we can try to reopen the pipe if there is an error
c2c80e
from write(). Assuming that a new pipe should appear
c2c80e
when fapolicyd daemon starts again.
c2c80e
If not then after 1 minute of waiting we expect
c2c80e
fapolicyd daemon to be not active and we let the
c2c80e
transaction continue.
c2c80e
c2c80e
Signed-off-by: Radovan Sroka <rsroka@redhat.com>
c2c80e
---
c2c80e
 plugins/fapolicyd.c | 74 +++++++++++++++++++++++++++++++++++++++------
c2c80e
 1 file changed, 65 insertions(+), 9 deletions(-)
c2c80e
c2c80e
diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
c2c80e
index 1ff50c30f..6c6322941 100644
c2c80e
--- a/plugins/fapolicyd.c
c2c80e
+++ b/plugins/fapolicyd.c
c2c80e
@@ -27,7 +27,7 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
c2c80e
     int fd = -1;
c2c80e
     struct stat s;
c2c80e
 
c2c80e
-    fd = open(state->fifo_path, O_RDWR);
c2c80e
+    fd = open(state->fifo_path, O_WRONLY|O_NONBLOCK);
c2c80e
     if (fd == -1) {
c2c80e
         rpmlog(RPMLOG_DEBUG, "Open: %s -> %s\n", state->fifo_path, strerror(errno));
c2c80e
         goto bad;
c2c80e
@@ -55,15 +55,26 @@ static rpmRC open_fifo(struct fapolicyd_data* state)
c2c80e
     }
c2c80e
 
c2c80e
     state->fd = fd;
c2c80e
+
c2c80e
     /* considering success */
c2c80e
     return RPMRC_OK;
c2c80e
 
c2c80e
  bad:
c2c80e
     if (fd >= 0)
c2c80e
         close(fd);
c2c80e
+
c2c80e
+    state->fd = -1;
c2c80e
     return RPMRC_FAIL;
c2c80e
 }
c2c80e
 
c2c80e
+static void close_fifo(struct fapolicyd_data* state)
c2c80e
+{
c2c80e
+    if (state->fd > 0)
c2c80e
+        (void) close(state->fd);
c2c80e
+
c2c80e
+    state->fd = -1;
c2c80e
+}
c2c80e
+
c2c80e
 static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
c2c80e
 {
c2c80e
     ssize_t len = strlen(str);
c2c80e
@@ -86,6 +97,54 @@ static rpmRC write_fifo(struct fapolicyd_data* state, const char * str)
c2c80e
     return RPMRC_FAIL;
c2c80e
 }
c2c80e
 
c2c80e
+static void try_to_write_to_fifo(struct fapolicyd_data* state, const char * str)
c2c80e
+{
c2c80e
+    int reload = 0;
c2c80e
+    int printed = 0;
c2c80e
+
c2c80e
+    /* 1min/60s */
c2c80e
+    const int timeout = 60;
c2c80e
+
c2c80e
+    /* wait up to X seconds */
c2c80e
+    for (int i = 0; i < timeout; i++) {
c2c80e
+
c2c80e
+        if (reload) {
c2c80e
+            if (!printed) {
c2c80e
+                rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: waiting for the service connection to resume, it can take up to %d seconds\n", timeout);
c2c80e
+                printed = 1;
c2c80e
+            }
c2c80e
+
c2c80e
+            (void) close_fifo(state);
c2c80e
+            (void) open_fifo(state);
c2c80e
+        }
c2c80e
+
c2c80e
+        if (state->fd >= 0) {
c2c80e
+            if (write_fifo(state, str) == RPMRC_OK) {
c2c80e
+
c2c80e
+                /* write was successful after few reopens */
c2c80e
+                if (reload)
c2c80e
+                    rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has resumed\n");
c2c80e
+
c2c80e
+                break;
c2c80e
+            }
c2c80e
+        }
c2c80e
+
c2c80e
+        /* failed write or reopen */
c2c80e
+        reload = 1;
c2c80e
+        sleep(1);
c2c80e
+
c2c80e
+        /* the last iteration */
c2c80e
+        /* consider failure */
c2c80e
+        if (i == timeout-1) {
c2c80e
+            rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: the service connection has not resumed\n");
c2c80e
+            rpmlog(RPMLOG_WARNING, "rpm-plugin-fapolicyd: continuing without the service\n");
c2c80e
+        }
c2c80e
+
c2c80e
+    }
c2c80e
+
c2c80e
+}
c2c80e
+
c2c80e
+
c2c80e
 static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
c2c80e
 {
c2c80e
     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
c2c80e
@@ -102,10 +161,7 @@ static rpmRC fapolicyd_init(rpmPlugin plugin, rpmts ts)
c2c80e
 
c2c80e
 static void fapolicyd_cleanup(rpmPlugin plugin)
c2c80e
 {
c2c80e
-    if (fapolicyd_state.fd > 0)
c2c80e
-        (void) close(fapolicyd_state.fd);
c2c80e
-
c2c80e
-    fapolicyd_state.fd = -1;
c2c80e
+    (void) close_fifo(&fapolicyd_state);
c2c80e
 }
c2c80e
 
c2c80e
 static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
c2c80e
@@ -116,9 +172,9 @@ static rpmRC fapolicyd_tsm_post(rpmPlugin plugin, rpmts ts, int res)
c2c80e
     /* we are ready */
c2c80e
     if (fapolicyd_state.fd > 0) {
c2c80e
         /* send a signal that transaction is over */
c2c80e
-        (void) write_fifo(&fapolicyd_state, "1\n");
c2c80e
+        (void) try_to_write_to_fifo(&fapolicyd_state, "1\n");
c2c80e
         /* flush cache */
c2c80e
-        (void) write_fifo(&fapolicyd_state, "2\n");
c2c80e
+        (void) try_to_write_to_fifo(&fapolicyd_state, "2\n");
c2c80e
     }
c2c80e
 
c2c80e
  end:
c2c80e
@@ -133,7 +189,7 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
c2c80e
 
c2c80e
     if (fapolicyd_state.changed_files > 0) {
c2c80e
         /* send signal to flush cache */
c2c80e
-        (void) write_fifo(&fapolicyd_state, "2\n");
c2c80e
+        (void) try_to_write_to_fifo(&fapolicyd_state, "2\n");
c2c80e
 
c2c80e
         /* optimize flushing */
c2c80e
         /* flush only when there was an actual change */
c2c80e
@@ -176,7 +232,7 @@ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
c2c80e
     char * sha = rpmfiFDigestHex(fi, NULL);
c2c80e
 
c2c80e
     snprintf(buffer, 4096, "%s %lu %64s\n", dest, size, sha);
c2c80e
-    (void) write_fifo(&fapolicyd_state, buffer);
c2c80e
+    (void) try_to_write_to_fifo(&fapolicyd_state, buffer);
c2c80e
 
c2c80e
     free(sha);
c2c80e
 
c2c80e
-- 
c2c80e
2.37.3
c2c80e