|
|
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 |
|