Skip to content

Commit 8b2e572

Browse files
jcalvinowensyifei-aws
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]> [ Resolving merge conflict by keeping the original code only changing the reference in dbg_*() calls. ] Signed-off-by: Stanislav Uschakow <[email protected]>
1 parent ff44272 commit 8b2e572

File tree

8 files changed

+85
-79
lines changed

8 files changed

+85
-79
lines changed

drivers/pps/clients/pps-gpio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ static int pps_gpio_probe(struct platform_device *pdev)
174174
}
175175

176176
platform_set_drvdata(pdev, data);
177-
dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
177+
dev_info(&data->pps->dev, "Registered IRQ %d as PPS source\n",
178178
data->irq);
179179

180180
return 0;

drivers/pps/clients/pps-ktimer.c

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

7171
static void __exit pps_ktimer_exit(void)
7272
{
73-
dev_info(pps->dev, "ktimer PPS source unregistered\n");
73+
dev_dbg(&pps->dev, "ktimer PPS source unregistered\n");
7474

7575
del_timer_sync(&ktimer);
7676
pps_unregister_source(pps);
@@ -88,7 +88,7 @@ static int __init pps_ktimer_init(void)
8888
setup_timer(&ktimer, pps_ktimer_event, 0);
8989
mod_timer(&ktimer, jiffies + HZ);
9090

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

9393
return 0;
9494
}

drivers/pps/clients/pps-ldisc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
4848
pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
4949
PPS_CAPTURECLEAR, NULL);
5050

51-
dev_dbg(pps->dev, "PPS %s at %lu\n",
51+
dev_dbg(&pps->dev, "PPS %s at %lu\n",
5252
status ? "assert" : "clear", jiffies);
5353
}
5454

@@ -85,7 +85,7 @@ static int pps_tty_open(struct tty_struct *tty)
8585
goto err_unregister;
8686
}
8787

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

9090
return 0;
9191

@@ -105,7 +105,7 @@ static void pps_tty_close(struct tty_struct *tty)
105105
if (WARN_ON(!pps))
106106
return;
107107

108-
dev_info(pps->dev, "removed\n");
108+
dev_info(&pps->dev, "removed\n");
109109
pps_unregister_source(pps);
110110
}
111111

drivers/pps/clients/pps_parport.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ static void parport_irq(void *handle)
9595
/* check the signal (no signal means the pulse is lost this time) */
9696
if (!signal_is_set(port)) {
9797
local_irq_restore(flags);
98-
dev_err(dev->pps->dev, "lost the signal\n");
98+
dev_err(&dev->pps->dev, "lost the signal\n");
9999
goto out_assert;
100100
}
101101

@@ -112,7 +112,7 @@ static void parport_irq(void *handle)
112112
/* timeout */
113113
dev->cw_err++;
114114
if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
115-
dev_err(dev->pps->dev, "disabled clear edge capture after %d"
115+
dev_err(&dev->pps->dev, "disabled clear edge capture after %d"
116116
" timeouts\n", dev->cw_err);
117117
dev->cw = 0;
118118
dev->cw_err = 0;

drivers/pps/kapi.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
5555
static void pps_echo_client_default(struct pps_device *pps, int event,
5656
void *data)
5757
{
58-
dev_info(pps->dev, "echo %s %s\n",
58+
dev_info(&pps->dev, "echo %s %s\n",
5959
event & PPS_CAPTUREASSERT ? "assert" : "",
6060
event & PPS_CAPTURECLEAR ? "clear" : "");
6161
}
@@ -125,7 +125,7 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
125125
goto kfree_pps;
126126
}
127127

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

130130
return pps;
131131

@@ -179,7 +179,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
179179
/* check event type */
180180
BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
181181

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

185185
timespec_to_pps_ktime(&ts_real, ts->ts_real);
@@ -201,7 +201,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
201201
/* Save the time stamp */
202202
pps->assert_tu = ts_real;
203203
pps->assert_sequence++;
204-
dev_dbg(pps->dev, "capture assert seq #%u\n",
204+
dev_dbg(&pps->dev, "capture assert seq #%u\n",
205205
pps->assert_sequence);
206206

207207
captured = ~0;
@@ -215,7 +215,7 @@ void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
215215
/* Save the time stamp */
216216
pps->clear_tu = ts_real;
217217
pps->clear_sequence++;
218-
dev_dbg(pps->dev, "capture clear seq #%u\n",
218+
dev_dbg(&pps->dev, "capture clear seq #%u\n",
219219
pps->clear_sequence);
220220

221221
captured = ~0;

drivers/pps/kc.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
5656
pps_kc_hardpps_mode = 0;
5757
pps_kc_hardpps_dev = NULL;
5858
spin_unlock_irq(&pps_kc_hardpps_lock);
59-
dev_info(pps->dev, "unbound kernel"
59+
dev_info(&pps->dev, "unbound kernel"
6060
" consumer\n");
6161
} else {
6262
spin_unlock_irq(&pps_kc_hardpps_lock);
63-
dev_err(pps->dev, "selected kernel consumer"
63+
dev_err(&pps->dev, "selected kernel consumer"
6464
" is not bound\n");
6565
return -EINVAL;
6666
}
@@ -70,11 +70,11 @@ int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
7070
pps_kc_hardpps_mode = bind_args->edge;
7171
pps_kc_hardpps_dev = pps;
7272
spin_unlock_irq(&pps_kc_hardpps_lock);
73-
dev_info(pps->dev, "bound kernel consumer: "
73+
dev_info(&pps->dev, "bound kernel consumer: "
7474
"edge=0x%x\n", bind_args->edge);
7575
} else {
7676
spin_unlock_irq(&pps_kc_hardpps_lock);
77-
dev_err(pps->dev, "another kernel consumer"
77+
dev_err(&pps->dev, "another kernel consumer"
7878
" is already bound\n");
7979
return -EINVAL;
8080
}
@@ -96,7 +96,7 @@ void pps_kc_remove(struct pps_device *pps)
9696
pps_kc_hardpps_mode = 0;
9797
pps_kc_hardpps_dev = NULL;
9898
spin_unlock_irq(&pps_kc_hardpps_lock);
99-
dev_info(pps->dev, "unbound kernel consumer"
99+
dev_info(&pps->dev, "unbound kernel consumer"
100100
" on device removal\n");
101101
} else
102102
spin_unlock_irq(&pps_kc_hardpps_lock);

0 commit comments

Comments
 (0)