michal-grzedzicki / rpms / rpm

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