0001-Fix-io_pgetevents-syscall-wrapper-on-32-bit-userland.patch 3.4 KB

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