Skip to content

Commit cd3bbcb

Browse files
jcalvinowensgregkh
authored andcommitted
pps: Fix a use-after-free
commit c79a39d upstream. On a board running ntpd and gpsd, I'm seeing a consistent use-after-free in sys_exit() from gpsd when rebooting: pps pps1: removed ------------[ cut here ]------------ kobject: '(null)' (00000000db4bec24): is not initialized, yet kobject_put() is being called. WARNING: CPU: 2 PID: 440 at lib/kobject.c:734 kobject_put+0x120/0x150 CPU: 2 UID: 299 PID: 440 Comm: gpsd Not tainted 6.11.0-rc6-00308-gb31c44928842 #1 Hardware name: Raspberry Pi 4 Model B Rev 1.1 (DT) pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : kobject_put+0x120/0x150 lr : kobject_put+0x120/0x150 sp : ffffffc0803d3ae0 x29: ffffffc0803d3ae0 x28: ffffff8042dc9738 x27: 0000000000000001 x26: 0000000000000000 x25: ffffff8042dc9040 x24: ffffff8042dc9440 x23: ffffff80402a4620 x22: ffffff8042ef4bd0 x21: ffffff80405cb600 x20: 000000000008001b x19: ffffff8040b3b6e0 x18: 0000000000000000 x17: 0000000000000000 x16: 0000000000000000 x15: 696e6920746f6e20 x14: 7369203a29343263 x13: 205d303434542020 x12: 0000000000000000 x11: 0000000000000000 x10: 0000000000000000 x9 : 0000000000000000 x8 : 0000000000000000 x7 : 0000000000000000 x6 : 0000000000000000 x5 : 0000000000000000 x4 : 0000000000000000 x3 : 0000000000000000 x2 : 0000000000000000 x1 : 0000000000000000 x0 : 0000000000000000 Call trace: kobject_put+0x120/0x150 cdev_put+0x20/0x3c __fput+0x2c4/0x2d8 ____fput+0x1c/0x38 task_work_run+0x70/0xfc do_exit+0x2a0/0x924 do_group_exit+0x34/0x90 get_signal+0x7fc/0x8c0 do_signal+0x128/0x13b4 do_notify_resume+0xdc/0x160 el0_svc+0xd4/0xf8 el0t_64_sync_handler+0x140/0x14c el0t_64_sync+0x190/0x194 ---[ end trace 0000000000000000 ]--- ...followed by more symptoms of corruption, with similar stacks: refcount_t: underflow; use-after-free. kernel BUG at lib/list_debug.c:62! Kernel panic - not syncing: Oops - BUG: Fatal exception This happens because pps_device_destruct() frees the pps_device with the embedded cdev immediately after calling cdev_del(), but, as the comment above cdev_del() notes, fops for previously opened cdevs are still callable even after cdev_del() returns. I think this bug has always been there: I can't explain why it suddenly started happening every time I reboot this particular board. In commit d953e0e ("pps: Fix a use-after free bug when unregistering a source."), George Spelvin suggested removing the embedded cdev. That seems like the simplest way to fix this, so I've implemented his suggestion, using __register_chrdev() with pps_idr becoming the source of truth for which minor corresponds to which device. But now that pps_idr defines userspace visibility instead of cdev_add(), we need to be sure the pps->dev refcount can't reach zero while userspace can still find it again. So, the idr_remove() call moves to pps_unregister_cdev(), and pps_idr now holds a reference to pps->dev. pps_core: source serial1 got cdev (251:1) <...> pps pps1: removed pps_core: unregistering pps1 pps_core: deallocating pps1 Fixes: d953e0e ("pps: Fix a use-after free bug when unregistering a source.") Cc: [email protected] Signed-off-by: Calvin Owens <[email protected]> Reviewed-by: Michal Schmidt <[email protected]> Link: https://lore.kernel.org/r/a17975fd5ae99385791929e563f72564edbcf28f.1731383727.git.calvin@wbinvd.org Signed-off-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6c36dcd commit cd3bbcb

File tree

9 files changed

+87
-83
lines changed

9 files changed

+87
-83
lines changed

drivers/pps/clients/pps-gpio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ static int pps_gpio_probe(struct platform_device *pdev)
214214
return -EINVAL;
215215
}
216216

217-
dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
218-
data->irq);
217+
dev_dbg(&data->pps->dev, "Registered IRQ %d as PPS source\n",
218+
data->irq);
219219

220220
return 0;
221221
}

drivers/pps/clients/pps-ktimer.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static struct pps_source_info pps_ktimer_info = {
5656

5757
static void __exit pps_ktimer_exit(void)
5858
{
59-
dev_info(pps->dev, "ktimer PPS source unregistered\n");
59+
dev_dbg(&pps->dev, "ktimer PPS source unregistered\n");
6060

6161
del_timer_sync(&ktimer);
6262
pps_unregister_source(pps);
@@ -74,7 +74,7 @@ static int __init pps_ktimer_init(void)
7474
timer_setup(&ktimer, pps_ktimer_event, 0);
7575
mod_timer(&ktimer, jiffies + HZ);
7676

77-
dev_info(pps->dev, "ktimer PPS source registered\n");
77+
dev_dbg(&pps->dev, "ktimer PPS source registered\n");
7878

7979
return 0;
8080
}

drivers/pps/clients/pps-ldisc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static void pps_tty_dcd_change(struct tty_struct *tty, bool active)
3232
pps_event(pps, &ts, active ? PPS_CAPTUREASSERT :
3333
PPS_CAPTURECLEAR, NULL);
3434

35-
dev_dbg(pps->dev, "PPS %s at %lu\n",
35+
dev_dbg(&pps->dev, "PPS %s at %lu\n",
3636
active ? "assert" : "clear", jiffies);
3737
}
3838

@@ -69,7 +69,7 @@ static int pps_tty_open(struct tty_struct *tty)
6969
goto err_unregister;
7070
}
7171

72-
dev_info(pps->dev, "source \"%s\" added\n", info.path);
72+
dev_dbg(&pps->dev, "source \"%s\" added\n", info.path);
7373

7474
return 0;
7575

@@ -89,7 +89,7 @@ static void pps_tty_close(struct tty_struct *tty)
8989
if (WARN_ON(!pps))
9090
return;
9191

92-
dev_info(pps->dev, "removed\n");
92+
dev_info(&pps->dev, "removed\n");
9393
pps_unregister_source(pps);
9494
}
9595

drivers/pps/clients/pps_parport.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static void parport_irq(void *handle)
8181
/* check the signal (no signal means the pulse is lost this time) */
8282
if (!signal_is_set(port)) {
8383
local_irq_restore(flags);
84-
dev_err(dev->pps->dev, "lost the signal\n");
84+
dev_err(&dev->pps->dev, "lost the signal\n");
8585
goto out_assert;
8686
}
8787

@@ -98,7 +98,7 @@ static void parport_irq(void *handle)
9898
/* timeout */
9999
dev->cw_err++;
100100
if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
101-
dev_err(dev->pps->dev, "disabled clear edge capture after %d"
101+
dev_err(&dev->pps->dev, "disabled clear edge capture after %d"
102102
" timeouts\n", dev->cw_err);
103103
dev->cw = 0;
104104
dev->cw_err = 0;

drivers/pps/kapi.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
4141
static void pps_echo_client_default(struct pps_device *pps, int event,
4242
void *data)
4343
{
44-
dev_info(pps->dev, "echo %s %s\n",
44+
dev_info(&pps->dev, "echo %s %s\n",
4545
event & PPS_CAPTUREASSERT ? "assert" : "",
4646
event & PPS_CAPTURECLEAR ? "clear" : "");
4747
}
@@ -112,7 +112,7 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
112112
goto kfree_pps;
113113
}
114114

115-
dev_info(pps->dev, "new PPS source %s\n", info->name);
115+
dev_dbg(&pps->dev, "new PPS source %s\n", info->name);
116116

117117
return pps;
118118

@@ -166,7 +166,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
166166
/* check event type */
167167
BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
168168

169-
dev_dbg(pps->dev, "PPS event at %lld.%09ld\n",
169+
dev_dbg(&pps->dev, "PPS event at %lld.%09ld\n",
170170
(s64)ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
171171

172172
timespec_to_pps_ktime(&ts_real, ts->ts_real);
@@ -188,7 +188,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
188188
/* Save the time stamp */
189189
pps->assert_tu = ts_real;
190190
pps->assert_sequence++;
191-
dev_dbg(pps->dev, "capture assert seq #%u\n",
191+
dev_dbg(&pps->dev, "capture assert seq #%u\n",
192192
pps->assert_sequence);
193193

194194
captured = ~0;
@@ -202,7 +202,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
202202
/* Save the time stamp */
203203
pps->clear_tu = ts_real;
204204
pps->clear_sequence++;
205-
dev_dbg(pps->dev, "capture clear seq #%u\n",
205+
dev_dbg(&pps->dev, "capture clear seq #%u\n",
206206
pps->clear_sequence);
207207

208208
captured = ~0;

drivers/pps/kc.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
4343
pps_kc_hardpps_mode = 0;
4444
pps_kc_hardpps_dev = NULL;
4545
spin_unlock_irq(&pps_kc_hardpps_lock);
46-
dev_info(pps->dev, "unbound kernel"
46+
dev_info(&pps->dev, "unbound kernel"
4747
" consumer\n");
4848
} else {
4949
spin_unlock_irq(&pps_kc_hardpps_lock);
50-
dev_err(pps->dev, "selected kernel consumer"
50+
dev_err(&pps->dev, "selected kernel consumer"
5151
" is not bound\n");
5252
return -EINVAL;
5353
}
@@ -57,11 +57,11 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
5757
pps_kc_hardpps_mode = bind_args->edge;
5858
pps_kc_hardpps_dev = pps;
5959
spin_unlock_irq(&pps_kc_hardpps_lock);
60-
dev_info(pps->dev, "bound kernel consumer: "
60+
dev_info(&pps->dev, "bound kernel consumer: "
6161
"edge=0x%x\n", bind_args->edge);
6262
} else {
6363
spin_unlock_irq(&pps_kc_hardpps_lock);
64-
dev_err(pps->dev, "another kernel consumer"
64+
dev_err(&pps->dev, "another kernel consumer"
6565
" is already bound\n");
6666
return -EINVAL;
6767
}
@@ -83,7 +83,7 @@ void pps_kc_remove(struct pps_device *pps)
8383
pps_kc_hardpps_mode = 0;
8484
pps_kc_hardpps_dev = NULL;
8585
spin_unlock_irq(&pps_kc_hardpps_lock);
86-
dev_info(pps->dev, "unbound kernel consumer"
86+
dev_info(&pps->dev, "unbound kernel consumer"
8787
" on device removal\n");
8888
} else
8989
spin_unlock_irq(&pps_kc_hardpps_lock);

0 commit comments

Comments
 (0)