recipes: Preserve warnings flags appending the C flags in some (specific) recipes
[dragora.git] / patches / libaio / 0001-Fix-io_pgetevents-syscall-wrapper-on-32-bit-userland.patch
blobde9d577dd9b4ba5f26df89553585f7a21301398d
1 From 70bed6aad97ad28d3bfc6dc8bf3c8f9aed77282b Mon Sep 17 00:00:00 2001
2 From: Guillem Jover <guillem@hadrons.org>
3 Date: Fri, 16 Aug 2019 02:33:46 +0200
4 Subject: [PATCH libaio] Fix io_pgetevents() syscall wrapper on 32-bit userland
5 on 64-bit kernels
7 The kernel compat syscall in the kernel got introduced with a broken
8 layout, which requires a pointer to the actual sigset_t variable but
9 with the size of the running kernel, not the size of the compat code.
11 This means that when the wrapper sends the expected compat (32-bit)
12 pointer, the kernel reads a 64-bit pointer, eating with it also the
13 sigset size member. And then proceeds to fail the comparison of the
14 sigset_t size and returns EINVAL.
16 This really needs to be fixed in the kernel, as there's no apparent
17 user of the broken compat layout (from codesearch.debian.org, nor a
18 quick github.com search). But we have to workaround it in libaio so
19 that we can use kernels that have not yet been fixed.
21 We do that, by trying the non-broken layout (that would be used with
22 a 32-bit userland on a 32-bit kernel), and if that fails with -EINVAL
23 we retry with a structure padded to what the kernel expects.
25 Signed-off-by: Guillem Jover <guillem@hadrons.org>
26 ---
27 src/io_pgetevents.c | 38 +++++++++++++++++++++++++++++++-------
28 src/libaio.h | 10 ++++++++++
29 2 files changed, 41 insertions(+), 7 deletions(-)
31 diff --git a/src/io_pgetevents.c b/src/io_pgetevents.c
32 index e6b0614..b2515f2 100644
33 --- a/src/io_pgetevents.c
34 +++ b/src/io_pgetevents.c
35 @@ -33,17 +33,41 @@ int io_pgetevents(io_context_t ctx, long min_nr, long nr,
36 struct io_event *events, struct timespec *timeout,
37 sigset_t *sigmask)
39 - struct {
40 - unsigned long ss;
41 - unsigned long ss_len;
42 - } data;
43 + struct io_sigset aio_sigset;
44 +#ifndef __LP64__
45 + struct io_sigset_compat aio_sigset_compat = { 0 };
46 +#endif
47 + int ret;
49 if (aio_ring_is_empty(ctx, timeout))
50 return 0;
52 - data.ss = (unsigned long)sigmask;
53 - data.ss_len = _NSIG / 8;
54 - return __io_pgetevents(ctx, min_nr, nr, events, timeout, &data);
55 + aio_sigset.ss = (unsigned long)sigmask;
56 + aio_sigset.ss_len = _NSIG / 8;
57 + ret = __io_pgetevents(ctx, min_nr, nr, events, timeout, &aio_sigset);
59 +#ifndef __LP64__
60 + /*
61 + * The compat kernel syscall got introduced with an broken layout for
62 + * its sigset argument, expecting it to contain a pointer for the
63 + * non-compat pointer size.
64 + *
65 + * To cope with this on unfixed kernels, in case we are built as a
66 + * 32-bit library (which could run on a kernel with compat code) and
67 + * when the syscall returns EINVAL due to the kernel not finding the
68 + * sigset size member when unpacking the structure, we retry with
69 + * the fixed up compat layout, which requires the padding to be
70 + * zero-filled, otherwise the 64-bit pointer will contain garbage.
71 + */
72 + if (ret != -EINVAL)
73 + return ret;
75 + aio_sigset_compat.ss = (unsigned long)sigmask;
76 + aio_sigset_compat.ss_len = _NSIG / 8;
77 + ret = __io_pgetevents(ctx, min_nr, nr, events, timeout, &aio_sigset_compat);
78 +#endif
80 + return ret;
82 #else
83 int io_pgetevents(io_context_t ctx, long min_nr, long nr,
84 diff --git a/src/libaio.h b/src/libaio.h
85 index ce3aad1..36ab9bc 100644
86 --- a/src/libaio.h
87 +++ b/src/libaio.h
88 @@ -152,6 +152,16 @@ struct io_event {
89 PADDEDul(res2, __pad4);
92 +struct io_sigset {
93 + unsigned long ss;
94 + unsigned long ss_len;
95 +};
97 +struct io_sigset_compat {
98 + PADDEDptr(unsigned long ss, __ss_pad);
99 + unsigned long ss_len;
102 #undef PADDED
103 #undef PADDEDptr
104 #undef PADDEDul
106 2.26.0.292.g33ef6b2f38