Blame SOURCES/rpm-4.16.1.3-fapolicyd-make-write-nonblocking.patch

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