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