michal-grzedzicki / rpms / rpm

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