Skip to content

Commit ff4a313

Browse files
committed
gpiolib: cdev: Fix use after free in lineinfo_changed_notify
jira LE-1907 cve CVE-2024-36899 Rebuild_History Non-Buildable kernel-5.14.0-427.37.1.el9_4 commit-author Zhongqiu Han <quic_zhonhan@quicinc.com> commit 02f6b0e Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-5.14.0-427.37.1.el9_4/02f6b0e1.failed The use-after-free issue occurs as follows: when the GPIO chip device file is being closed by invoking gpio_chrdev_release(), watched_lines is freed by bitmap_free(), but the unregistration of lineinfo_changed_nb notifier chain failed due to waiting write rwsem. Additionally, one of the GPIO chip's lines is also in the release process and holds the notifier chain's read rwsem. Consequently, a race condition leads to the use-after-free of watched_lines. Here is the typical stack when issue happened: [free] gpio_chrdev_release() --> bitmap_free(cdev->watched_lines) <-- freed --> blocking_notifier_chain_unregister() --> down_write(&nh->rwsem) <-- waiting rwsem --> __down_write_common() --> rwsem_down_write_slowpath() --> schedule_preempt_disabled() --> schedule() [use] st54spi_gpio_dev_release() --> gpio_free() --> gpiod_free() --> gpiod_free_commit() --> gpiod_line_state_notify() --> blocking_notifier_call_chain() --> down_read(&nh->rwsem); <-- held rwsem --> notifier_call_chain() --> lineinfo_changed_notify() --> test_bit(xxxx, cdev->watched_lines) <-- use after free The side effect of the use-after-free issue is that a GPIO line event is being generated for userspace where it shouldn't. However, since the chrdev is being closed, userspace won't have the chance to read that event anyway. To fix the issue, call the bitmap_free() function after the unregistration of lineinfo_changed_nb notifier chain. Fixes: 51c1064 ("gpiolib: add new ioctl() for monitoring changes in line info") Signed-off-by: Zhongqiu Han <quic_zhonhan@quicinc.com> Link: https://lore.kernel.org/r/20240505141156.2944912-1-quic_zhonhan@quicinc.com Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> (cherry picked from commit 02f6b0e) Signed-off-by: Jonathan Maple <jmaple@ciq.com> # Conflicts: # drivers/gpio/gpiolib-cdev.c
1 parent 2bb5370 commit ff4a313

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
gpiolib: cdev: Fix use after free in lineinfo_changed_notify
2+
3+
jira LE-1907
4+
cve CVE-2024-36899
5+
Rebuild_History Non-Buildable kernel-5.14.0-427.37.1.el9_4
6+
commit-author Zhongqiu Han <quic_zhonhan@quicinc.com>
7+
commit 02f6b0e1ec7e0e7d059dddc893645816552039da
8+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
9+
Will be included in final tarball splat. Ref for failed cherry-pick at:
10+
ciq/ciq_backports/kernel-5.14.0-427.37.1.el9_4/02f6b0e1.failed
11+
12+
The use-after-free issue occurs as follows: when the GPIO chip device file
13+
is being closed by invoking gpio_chrdev_release(), watched_lines is freed
14+
by bitmap_free(), but the unregistration of lineinfo_changed_nb notifier
15+
chain failed due to waiting write rwsem. Additionally, one of the GPIO
16+
chip's lines is also in the release process and holds the notifier chain's
17+
read rwsem. Consequently, a race condition leads to the use-after-free of
18+
watched_lines.
19+
20+
Here is the typical stack when issue happened:
21+
22+
[free]
23+
gpio_chrdev_release()
24+
--> bitmap_free(cdev->watched_lines) <-- freed
25+
--> blocking_notifier_chain_unregister()
26+
--> down_write(&nh->rwsem) <-- waiting rwsem
27+
--> __down_write_common()
28+
--> rwsem_down_write_slowpath()
29+
--> schedule_preempt_disabled()
30+
--> schedule()
31+
32+
[use]
33+
st54spi_gpio_dev_release()
34+
--> gpio_free()
35+
--> gpiod_free()
36+
--> gpiod_free_commit()
37+
--> gpiod_line_state_notify()
38+
--> blocking_notifier_call_chain()
39+
--> down_read(&nh->rwsem); <-- held rwsem
40+
--> notifier_call_chain()
41+
--> lineinfo_changed_notify()
42+
--> test_bit(xxxx, cdev->watched_lines) <-- use after free
43+
44+
The side effect of the use-after-free issue is that a GPIO line event is
45+
being generated for userspace where it shouldn't. However, since the chrdev
46+
is being closed, userspace won't have the chance to read that event anyway.
47+
48+
To fix the issue, call the bitmap_free() function after the unregistration
49+
of lineinfo_changed_nb notifier chain.
50+
51+
Fixes: 51c1064e82e7 ("gpiolib: add new ioctl() for monitoring changes in line info")
52+
Signed-off-by: Zhongqiu Han <quic_zhonhan@quicinc.com>
53+
Link: https://lore.kernel.org/r/20240505141156.2944912-1-quic_zhonhan@quicinc.com
54+
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
55+
(cherry picked from commit 02f6b0e1ec7e0e7d059dddc893645816552039da)
56+
Signed-off-by: Jonathan Maple <jmaple@ciq.com>
57+
58+
# Conflicts:
59+
# drivers/gpio/gpiolib-cdev.c
60+
diff --cc drivers/gpio/gpiolib-cdev.c
61+
index e81b57db23e3,46a45093d4d0..000000000000
62+
--- a/drivers/gpio/gpiolib-cdev.c
63+
+++ b/drivers/gpio/gpiolib-cdev.c
64+
@@@ -2703,9 -2799,11 +2703,15 @@@ static int gpio_chrdev_release(struct i
65+
struct gpio_chardev_data *cdev = file->private_data;
66+
struct gpio_device *gdev = cdev->gdev;
67+
68+
++<<<<<<< HEAD
69+
+ bitmap_free(cdev->watched_lines);
70+
++=======
71+
+ blocking_notifier_chain_unregister(&gdev->device_notifier,
72+
+ &cdev->device_unregistered_nb);
73+
++>>>>>>> 02f6b0e1ec7e (gpiolib: cdev: Fix use after free in lineinfo_changed_notify)
74+
blocking_notifier_chain_unregister(&gdev->line_state_notifier,
75+
&cdev->lineinfo_changed_nb);
76+
+ bitmap_free(cdev->watched_lines);
77+
gpio_device_put(gdev);
78+
kfree(cdev);
79+
80+
* Unmerged path drivers/gpio/gpiolib-cdev.c

0 commit comments

Comments
 (0)