michal-grzedzicki / rpms / rpm

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