629b27
From 57aa660de4d1b8375cd56f7b8b5fcaf8ad9a5af7 Mon Sep 17 00:00:00 2001
629b27
From: chantra <chantr4@gmail.com>
629b27
Date: Fri, 25 Mar 2022 08:13:08 -0700
629b27
Subject: [PATCH 28/30] [reflink] remove requirement for executable stack flag
629b27
629b27
reflink was calling `bsearch` with a nested function comparator which
629b27
make GCC require the executable stack flag (see `man execstack`).
629b27
selinux prevents the use of this flag:
629b27
```
629b27
error: Failed to dlopen /usr/lib64/rpm-plugins/reflink.so
629b27
/usr/lib64/rpm-plugins/reflink.so: cannot enable executable stack as
629b27
shared object requires: Permission denied
629b27
```
629b27
629b27
To fix this, either rpm could be granted the correct selinux permission,
629b27
but this would open up execstack for more the whole rpm process.
629b27
Fundamentally, this is happening because there is no re-entrant version
629b27
of `bsearch`. We could probably use a global variable and be done with
629b27
it given that each rpm is processed sequencially, but that contract may
629b27
not hold true for ever.
629b27
Here we are copying stdlib's `bsearch` and making it re-entrant by
629b27
allowing to pass an void * data parameter where we can pass the key
629b27
size.
629b27
629b27
After applying this patch, when reflink.o is installed, it has the executable
629b27
flag cleared:
629b27
```
629b27
- /usr/lib64/rpm-plugins/reflink.so
629b27
```
629b27
---
629b27
 plugins/reflink.c | 60 +++++++++++++++++++++++++++++++++++++----------
629b27
 1 file changed, 48 insertions(+), 12 deletions(-)
629b27
629b27
diff --git a/plugins/reflink.c b/plugins/reflink.c
629b27
index 4fc1d74d1..69e6b51e6 100644
629b27
--- a/plugins/reflink.c
629b27
+++ b/plugins/reflink.c
629b27
@@ -59,6 +59,50 @@ struct reflink_state_s {
629b27
 
629b27
 typedef struct reflink_state_s * reflink_state;
629b27
 
629b27
+/*
629b27
+ * bsearch_r: implements a re-entrant version of stdlib's bsearch.
629b27
+ * code taken and adapted from /usr/include/bits/stdlib-bsearch.h
629b27
+ */
629b27
+inline void *
629b27
+bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size,
629b27
+	 __compar_d_fn_t __compar, void *__arg)
629b27
+{
629b27
+  size_t __l, __u, __idx;
629b27
+  const void *__p;
629b27
+  int __comparison;
629b27
+
629b27
+  __l = 0;
629b27
+  __u = __nmemb;
629b27
+  while (__l < __u)
629b27
+    {
629b27
+      __idx = (__l + __u) / 2;
629b27
+      __p = (const void *) (((const char *) __base) + (__idx * __size));
629b27
+      __comparison = (*__compar) (__key, __p, __arg);
629b27
+      if (__comparison < 0)
629b27
+	__u = __idx;
629b27
+      else if (__comparison > 0)
629b27
+	__l = __idx + 1;
629b27
+      else
629b27
+	{
629b27
+#if __GNUC_PREREQ(4, 6)
629b27
+# pragma GCC diagnostic push
629b27
+# pragma GCC diagnostic ignored "-Wcast-qual"
629b27
+#endif
629b27
+	  return (void *) __p;
629b27
+#if __GNUC_PREREQ(4, 6)
629b27
+# pragma GCC diagnostic pop
629b27
+#endif
629b27
+	}
629b27
+    }
629b27
+
629b27
+  return NULL;
629b27
+}
629b27
+
629b27
+static int cmpdigest(const void *k1, const void *k2, void *data) {
629b27
+    rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
629b27
+    return memcmp(k1, k2, *(int *)data);
629b27
+}
629b27
+
629b27
 static int inodeCmp(rpm_ino_t a, rpm_ino_t b)
629b27
 {
629b27
     return (a != b);
629b27
@@ -198,21 +242,13 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)
629b27
 rpm_loff_t find(const unsigned char *digest, reflink_state state);
629b27
 
629b27
 rpm_loff_t find(const unsigned char *digest, reflink_state state) {
629b27
-# if defined(__GNUC__)
629b27
-    /* GCC nested function because bsearch's comparison function can't access
629b27
-     * state-keysize otherwise
629b27
-     */
629b27
-    int cmpdigest(const void *k1, const void *k2) {
629b27
-	rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
629b27
-	return memcmp(k1, k2, state->keysize);
629b27
-    }
629b27
-# endif
629b27
     rpmlog(RPMLOG_DEBUG,
629b27
-	   _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"),
629b27
+	   _("reflink: bsearch_r(key=%p, base=%p, nmemb=%d, size=%lu)\n"),
629b27
 	   digest, state->table, state->keys,
629b27
 	   state->keysize + sizeof(rpm_loff_t));
629b27
-    char *entry = bsearch(digest, state->table, state->keys,
629b27
-			  state->keysize + sizeof(rpm_loff_t), cmpdigest);
629b27
+    char *entry = bsearch_r(digest, state->table, state->keys,
629b27
+			    state->keysize + sizeof(rpm_loff_t), cmpdigest,
629b27
+			    &state->keysize);
629b27
     if (entry == NULL) {
629b27
 	return NOT_FOUND;
629b27
     }
629b27
-- 
629b27
2.35.1
629b27