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