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