blob: 9f71fecddbc13148645dd959890ec0002769848b [file] [log] [blame]
Andrew Geisslerd159c7f2021-09-02 21:05:58 -05001From 4cc79c217744743077bf7a0ec5e0a4318f1e6641 Mon Sep 17 00:00:00 2001
2From: Nikita Popov <npv1310@gmail.com>
3Date: Thu, 12 Aug 2021 16:09:50 +0530
4Subject: [PATCH] librt: add test (bug 28213)
5
6This test implements following logic:
71) Create POSIX message queue.
8 Register a notification with mq_notify (using NULL attributes).
9 Then immediately unregister the notification with mq_notify.
10 Helper thread in a vulnerable version of glibc
11 should cause NULL pointer dereference after these steps.
122) Once again, register the same notification.
13 Try to send a dummy message.
14 Test is considered successfulif the dummy message
15 is successfully received by the callback function.
16
17Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=commit;h=4cc79c217744743077bf7a0ec5e0a4318f1e6641]
18CVE: CVE-2021-38604
19
20Signed-off-by: Nikita Popov <npv1310@gmail.com>
21Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
22Signed-off-by: Vinay Kumar <vinay.m.engg@gmail.com>
23---
24 rt/Makefile | 1 +
25 rt/tst-bz28213.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++
26 2 files changed, 102 insertions(+)
27 create mode 100644 rt/tst-bz28213.c
28
29diff --git a/rt/Makefile b/rt/Makefile
30index 113cea03a5..910e775995 100644
31--- a/rt/Makefile
32+++ b/rt/Makefile
33@@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \
34 tst-aio7 tst-aio8 tst-aio9 tst-aio10 \
35 tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
36 tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
37+ tst-bz28213 \
38 tst-timer3 tst-timer4 tst-timer5 \
39 tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \
40 tst-shm-cancel \
41diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c
42new file mode 100644
43index 0000000000..0c096b5a0a
44--- /dev/null
45+++ b/rt/tst-bz28213.c
46@@ -0,0 +1,101 @@
47+/* Bug 28213: test for NULL pointer dereference in mq_notify.
48+ Copyright (C) The GNU Toolchain Authors.
49+ This file is part of the GNU C Library.
50+
51+ The GNU C Library is free software; you can redistribute it and/or
52+ modify it under the terms of the GNU Lesser General Public
53+ License as published by the Free Software Foundation; either
54+ version 2.1 of the License, or (at your option) any later version.
55+
56+ The GNU C Library is distributed in the hope that it will be useful,
57+ but WITHOUT ANY WARRANTY; without even the implied warranty of
58+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
59+ Lesser General Public License for more details.
60+
61+ You should have received a copy of the GNU Lesser General Public
62+ License along with the GNU C Library; if not, see
63+ <https://www.gnu.org/licenses/>. */
64+
65+#include <errno.h>
66+#include <sys/types.h>
67+#include <sys/stat.h>
68+#include <fcntl.h>
69+#include <unistd.h>
70+#include <mqueue.h>
71+#include <signal.h>
72+#include <stdlib.h>
73+#include <string.h>
74+#include <support/check.h>
75+
76+static mqd_t m = -1;
77+static const char msg[] = "hello";
78+
79+static void
80+check_bz28213_cb (union sigval sv)
81+{
82+ char buf[sizeof (msg)];
83+
84+ (void) sv;
85+
86+ TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL)
87+ == sizeof (buf));
88+ TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0);
89+
90+ exit (0);
91+}
92+
93+static void
94+check_bz28213 (void)
95+{
96+ struct sigevent sev;
97+
98+ memset (&sev, '\0', sizeof (sev));
99+ sev.sigev_notify = SIGEV_THREAD;
100+ sev.sigev_notify_function = check_bz28213_cb;
101+
102+ /* Step 1: Register & unregister notifier.
103+ Helper thread should receive NOTIFY_REMOVED notification.
104+ In a vulnerable version of glibc, NULL pointer dereference follows. */
105+ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
106+ TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0);
107+
108+ /* Step 2: Once again, register notification.
109+ Try to send one message.
110+ Test is considered successful, if the callback does exit (0). */
111+ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
112+ TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0);
113+
114+ /* Wait... */
115+ pause ();
116+}
117+
118+static int
119+do_test (void)
120+{
121+ static const char m_name[] = "/bz28213_queue";
122+ struct mq_attr m_attr;
123+
124+ memset (&m_attr, '\0', sizeof (m_attr));
125+ m_attr.mq_maxmsg = 1;
126+ m_attr.mq_msgsize = sizeof (msg);
127+
128+ m = mq_open (m_name,
129+ O_RDWR | O_CREAT | O_EXCL,
130+ 0600,
131+ &m_attr);
132+
133+ if (m < 0)
134+ {
135+ if (errno == ENOSYS)
136+ FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n");
137+ FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n");
138+ }
139+
140+ TEST_VERIFY_EXIT (mq_unlink (m_name) == 0);
141+
142+ check_bz28213 ();
143+
144+ return 0;
145+}
146+
147+#include <support/test-driver.c>
148--
1492.31.1
150