Skip to content

Commit 7704e6b

Browse files
ausyskingregkh
authored andcommitted
mei: hook mei_device on class device
mei_device lifetime was managed by devm procedure of parent device. But such memory is freed on device_del. Mei_device object is used by client object that may be alive after parent device is removed. It may lead to use-after-free if discrete graphics driver unloads mei_gsc auxiliary device while user-space holds open handle to mei character device. Connect mei_device structure lifteme to mei class device lifetime by adding mei_device free to class device remove callback. Move exising parent device pointer to separate field in mei_device to avoid misuse. Allocate character device dynamically and allow to control its own lifetime as it may outlive mei_device structure while character device closes after parent device is removed from the system. Leave power management on parent device as we overwrite pci runtime pm procedure and user-space is expecting it there. Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14201 Signed-off-by: Alexander Usyskin <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 76254bc commit 7704e6b

File tree

16 files changed

+342
-315
lines changed

16 files changed

+342
-315
lines changed

drivers/misc/mei/bus-fixup.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ static int mei_nfc_if_version(struct mei_cl *cl,
386386
ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(cmd), 0,
387387
MEI_CL_IO_TX_BLOCKING);
388388
if (ret < 0) {
389-
dev_err(bus->dev, "Could not send IF version cmd ret = %d\n", ret);
389+
dev_err(&bus->dev, "Could not send IF version cmd ret = %d\n", ret);
390390
return ret;
391391
}
392392

@@ -401,14 +401,14 @@ static int mei_nfc_if_version(struct mei_cl *cl,
401401
bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, &vtag,
402402
0, 0);
403403
if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) {
404-
dev_err(bus->dev, "Could not read IF version ret = %d\n", bytes_recv);
404+
dev_err(&bus->dev, "Could not read IF version ret = %d\n", bytes_recv);
405405
ret = -EIO;
406406
goto err;
407407
}
408408

409409
memcpy(ver, reply->data, sizeof(*ver));
410410

411-
dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
411+
dev_info(&bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
412412
ver->fw_ivn, ver->vendor_id, ver->radio_type);
413413

414414
err:

drivers/misc/mei/bus.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_enabled);
637637
*/
638638
static bool mei_cl_bus_module_get(struct mei_cl_device *cldev)
639639
{
640-
return try_module_get(cldev->bus->dev->driver->owner);
640+
return try_module_get(cldev->bus->parent->driver->owner);
641641
}
642642

643643
/**
@@ -647,7 +647,7 @@ static bool mei_cl_bus_module_get(struct mei_cl_device *cldev)
647647
*/
648648
static void mei_cl_bus_module_put(struct mei_cl_device *cldev)
649649
{
650-
module_put(cldev->bus->dev->driver->owner);
650+
module_put(cldev->bus->parent->driver->owner);
651651
}
652652

653653
/**
@@ -1285,16 +1285,20 @@ static const struct bus_type mei_cl_bus_type = {
12851285

12861286
static struct mei_device *mei_dev_bus_get(struct mei_device *bus)
12871287
{
1288-
if (bus)
1289-
get_device(bus->dev);
1288+
if (bus) {
1289+
get_device(&bus->dev);
1290+
get_device(bus->parent);
1291+
}
12901292

12911293
return bus;
12921294
}
12931295

12941296
static void mei_dev_bus_put(struct mei_device *bus)
12951297
{
1296-
if (bus)
1297-
put_device(bus->dev);
1298+
if (bus) {
1299+
put_device(bus->parent);
1300+
put_device(&bus->dev);
1301+
}
12981302
}
12991303

13001304
static void mei_cl_bus_dev_release(struct device *dev)
@@ -1328,7 +1332,7 @@ static const struct device_type mei_cl_device_type = {
13281332
static inline void mei_cl_bus_set_name(struct mei_cl_device *cldev)
13291333
{
13301334
dev_set_name(&cldev->dev, "%s-%pUl",
1331-
dev_name(cldev->bus->dev),
1335+
dev_name(cldev->bus->parent),
13321336
mei_me_cl_uuid(cldev->me_cl));
13331337
}
13341338

@@ -1357,7 +1361,7 @@ static struct mei_cl_device *mei_cl_bus_dev_alloc(struct mei_device *bus,
13571361
}
13581362

13591363
device_initialize(&cldev->dev);
1360-
cldev->dev.parent = bus->dev;
1364+
cldev->dev.parent = bus->parent;
13611365
cldev->dev.bus = &mei_cl_bus_type;
13621366
cldev->dev.type = &mei_cl_device_type;
13631367
cldev->bus = mei_dev_bus_get(bus);
@@ -1492,7 +1496,7 @@ static void mei_cl_bus_dev_init(struct mei_device *bus,
14921496

14931497
WARN_ON(!mutex_is_locked(&bus->cl_bus_lock));
14941498

1495-
dev_dbg(bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl));
1499+
dev_dbg(&bus->dev, "initializing %pUl", mei_me_cl_uuid(me_cl));
14961500

14971501
if (me_cl->bus_added)
14981502
return;
@@ -1543,7 +1547,7 @@ static void mei_cl_bus_rescan(struct mei_device *bus)
15431547
}
15441548
mutex_unlock(&bus->cl_bus_lock);
15451549

1546-
dev_dbg(bus->dev, "rescan end");
1550+
dev_dbg(&bus->dev, "rescan end");
15471551
}
15481552

15491553
void mei_cl_bus_rescan_work(struct work_struct *work)

drivers/misc/mei/client.c

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
262262
{
263263
struct mei_me_client *me_cl;
264264

265-
dev_dbg(dev->dev, "remove %pUl\n", uuid);
265+
dev_dbg(&dev->dev, "remove %pUl\n", uuid);
266266

267267
down_write(&dev->me_clients_rwsem);
268268
me_cl = __mei_me_cl_by_uuid(dev, uuid);
@@ -635,12 +635,12 @@ int mei_cl_link(struct mei_cl *cl)
635635

636636
id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
637637
if (id >= MEI_CLIENTS_MAX) {
638-
dev_err(dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
638+
dev_err(&dev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
639639
return -EMFILE;
640640
}
641641

642642
if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
643-
dev_err(dev->dev, "open_handle_count exceeded %d",
643+
dev_err(&dev->dev, "open_handle_count exceeded %d",
644644
MEI_MAX_OPEN_HANDLE_COUNT);
645645
return -EMFILE;
646646
}
@@ -709,9 +709,9 @@ void mei_host_client_init(struct mei_device *dev)
709709

710710
schedule_work(&dev->bus_rescan_work);
711711

712-
pm_runtime_mark_last_busy(dev->dev);
713-
dev_dbg(dev->dev, "rpm: autosuspend\n");
714-
pm_request_autosuspend(dev->dev);
712+
pm_runtime_mark_last_busy(dev->parent);
713+
dev_dbg(&dev->dev, "rpm: autosuspend\n");
714+
pm_request_autosuspend(dev->parent);
715715
}
716716

717717
/**
@@ -724,12 +724,12 @@ bool mei_hbuf_acquire(struct mei_device *dev)
724724
{
725725
if (mei_pg_state(dev) == MEI_PG_ON ||
726726
mei_pg_in_transition(dev)) {
727-
dev_dbg(dev->dev, "device is in pg\n");
727+
dev_dbg(&dev->dev, "device is in pg\n");
728728
return false;
729729
}
730730

731731
if (!dev->hbuf_is_ready) {
732-
dev_dbg(dev->dev, "hbuf is not ready\n");
732+
dev_dbg(&dev->dev, "hbuf is not ready\n");
733733
return false;
734734
}
735735

@@ -981,18 +981,18 @@ int mei_cl_disconnect(struct mei_cl *cl)
981981
return 0;
982982
}
983983

984-
rets = pm_runtime_get(dev->dev);
984+
rets = pm_runtime_get(dev->parent);
985985
if (rets < 0 && rets != -EINPROGRESS) {
986-
pm_runtime_put_noidle(dev->dev);
986+
pm_runtime_put_noidle(dev->parent);
987987
cl_err(dev, cl, "rpm: get failed %d\n", rets);
988988
return rets;
989989
}
990990

991991
rets = __mei_cl_disconnect(cl);
992992

993993
cl_dbg(dev, cl, "rpm: autosuspend\n");
994-
pm_runtime_mark_last_busy(dev->dev);
995-
pm_runtime_put_autosuspend(dev->dev);
994+
pm_runtime_mark_last_busy(dev->parent);
995+
pm_runtime_put_autosuspend(dev->parent);
996996

997997
return rets;
998998
}
@@ -1118,9 +1118,9 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
11181118
goto nortpm;
11191119
}
11201120

1121-
rets = pm_runtime_get(dev->dev);
1121+
rets = pm_runtime_get(dev->parent);
11221122
if (rets < 0 && rets != -EINPROGRESS) {
1123-
pm_runtime_put_noidle(dev->dev);
1123+
pm_runtime_put_noidle(dev->parent);
11241124
cl_err(dev, cl, "rpm: get failed %d\n", rets);
11251125
goto nortpm;
11261126
}
@@ -1167,8 +1167,8 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
11671167
rets = cl->status;
11681168
out:
11691169
cl_dbg(dev, cl, "rpm: autosuspend\n");
1170-
pm_runtime_mark_last_busy(dev->dev);
1171-
pm_runtime_put_autosuspend(dev->dev);
1170+
pm_runtime_mark_last_busy(dev->parent);
1171+
pm_runtime_put_autosuspend(dev->parent);
11721172

11731173
mei_io_cb_free(cb);
11741174

@@ -1517,9 +1517,9 @@ int mei_cl_notify_request(struct mei_cl *cl,
15171517
if (!mei_cl_is_connected(cl))
15181518
return -ENODEV;
15191519

1520-
rets = pm_runtime_get(dev->dev);
1520+
rets = pm_runtime_get(dev->parent);
15211521
if (rets < 0 && rets != -EINPROGRESS) {
1522-
pm_runtime_put_noidle(dev->dev);
1522+
pm_runtime_put_noidle(dev->parent);
15231523
cl_err(dev, cl, "rpm: get failed %d\n", rets);
15241524
return rets;
15251525
}
@@ -1554,8 +1554,8 @@ int mei_cl_notify_request(struct mei_cl *cl,
15541554

15551555
out:
15561556
cl_dbg(dev, cl, "rpm: autosuspend\n");
1557-
pm_runtime_mark_last_busy(dev->dev);
1558-
pm_runtime_put_autosuspend(dev->dev);
1557+
pm_runtime_mark_last_busy(dev->parent);
1558+
pm_runtime_put_autosuspend(dev->parent);
15591559

15601560
mei_io_cb_free(cb);
15611561
return rets;
@@ -1683,9 +1683,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
16831683

16841684
mei_cl_set_read_by_fp(cl, fp);
16851685

1686-
rets = pm_runtime_get(dev->dev);
1686+
rets = pm_runtime_get(dev->parent);
16871687
if (rets < 0 && rets != -EINPROGRESS) {
1688-
pm_runtime_put_noidle(dev->dev);
1688+
pm_runtime_put_noidle(dev->parent);
16891689
cl_err(dev, cl, "rpm: get failed %d\n", rets);
16901690
goto nortpm;
16911691
}
@@ -1702,8 +1702,8 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
17021702

17031703
out:
17041704
cl_dbg(dev, cl, "rpm: autosuspend\n");
1705-
pm_runtime_mark_last_busy(dev->dev);
1706-
pm_runtime_put_autosuspend(dev->dev);
1705+
pm_runtime_mark_last_busy(dev->parent);
1706+
pm_runtime_put_autosuspend(dev->parent);
17071707
nortpm:
17081708
if (rets)
17091709
mei_io_cb_free(cb);
@@ -1972,9 +1972,9 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, unsigned long time
19721972
blocking = cb->blocking;
19731973
data = buf->data;
19741974

1975-
rets = pm_runtime_get(dev->dev);
1975+
rets = pm_runtime_get(dev->parent);
19761976
if (rets < 0 && rets != -EINPROGRESS) {
1977-
pm_runtime_put_noidle(dev->dev);
1977+
pm_runtime_put_noidle(dev->parent);
19781978
cl_err(dev, cl, "rpm: get failed %zd\n", rets);
19791979
goto free;
19801980
}
@@ -2092,8 +2092,8 @@ ssize_t mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, unsigned long time
20922092
rets = buf_len;
20932093
err:
20942094
cl_dbg(dev, cl, "rpm: autosuspend\n");
2095-
pm_runtime_mark_last_busy(dev->dev);
2096-
pm_runtime_put_autosuspend(dev->dev);
2095+
pm_runtime_mark_last_busy(dev->parent);
2096+
pm_runtime_put_autosuspend(dev->parent);
20972097
free:
20982098
mei_io_cb_free(cb);
20992099

@@ -2119,8 +2119,8 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
21192119
if (waitqueue_active(&cl->tx_wait)) {
21202120
wake_up_interruptible(&cl->tx_wait);
21212121
} else {
2122-
pm_runtime_mark_last_busy(dev->dev);
2123-
pm_request_autosuspend(dev->dev);
2122+
pm_runtime_mark_last_busy(dev->parent);
2123+
pm_request_autosuspend(dev->parent);
21242124
}
21252125
break;
21262126

@@ -2251,7 +2251,7 @@ int mei_cl_irq_dma_unmap(struct mei_cl *cl, struct mei_cl_cb *cb,
22512251

22522252
static int mei_cl_dma_alloc(struct mei_cl *cl, u8 buf_id, size_t size)
22532253
{
2254-
cl->dma.vaddr = dmam_alloc_coherent(cl->dev->dev, size,
2254+
cl->dma.vaddr = dmam_alloc_coherent(&cl->dev->dev, size,
22552255
&cl->dma.daddr, GFP_KERNEL);
22562256
if (!cl->dma.vaddr)
22572257
return -ENOMEM;
@@ -2265,7 +2265,7 @@ static int mei_cl_dma_alloc(struct mei_cl *cl, u8 buf_id, size_t size)
22652265
static void mei_cl_dma_free(struct mei_cl *cl)
22662266
{
22672267
cl->dma.buffer_id = 0;
2268-
dmam_free_coherent(cl->dev->dev,
2268+
dmam_free_coherent(&cl->dev->dev,
22692269
cl->dma.size, cl->dma.vaddr, cl->dma.daddr);
22702270
cl->dma.size = 0;
22712271
cl->dma.vaddr = NULL;
@@ -2321,16 +2321,16 @@ int mei_cl_dma_alloc_and_map(struct mei_cl *cl, const struct file *fp,
23212321
return -EPROTO;
23222322
}
23232323

2324-
rets = pm_runtime_get(dev->dev);
2324+
rets = pm_runtime_get(dev->parent);
23252325
if (rets < 0 && rets != -EINPROGRESS) {
2326-
pm_runtime_put_noidle(dev->dev);
2326+
pm_runtime_put_noidle(dev->parent);
23272327
cl_err(dev, cl, "rpm: get failed %d\n", rets);
23282328
return rets;
23292329
}
23302330

23312331
rets = mei_cl_dma_alloc(cl, buffer_id, size);
23322332
if (rets) {
2333-
pm_runtime_put_noidle(dev->dev);
2333+
pm_runtime_put_noidle(dev->parent);
23342334
return rets;
23352335
}
23362336

@@ -2366,8 +2366,8 @@ int mei_cl_dma_alloc_and_map(struct mei_cl *cl, const struct file *fp,
23662366
mei_cl_dma_free(cl);
23672367

23682368
cl_dbg(dev, cl, "rpm: autosuspend\n");
2369-
pm_runtime_mark_last_busy(dev->dev);
2370-
pm_runtime_put_autosuspend(dev->dev);
2369+
pm_runtime_mark_last_busy(dev->parent);
2370+
pm_runtime_put_autosuspend(dev->parent);
23712371

23722372
mei_io_cb_free(cb);
23732373
return rets;
@@ -2406,9 +2406,9 @@ int mei_cl_dma_unmap(struct mei_cl *cl, const struct file *fp)
24062406
if (!cl->dma_mapped)
24072407
return -EPROTO;
24082408

2409-
rets = pm_runtime_get(dev->dev);
2409+
rets = pm_runtime_get(dev->parent);
24102410
if (rets < 0 && rets != -EINPROGRESS) {
2411-
pm_runtime_put_noidle(dev->dev);
2411+
pm_runtime_put_noidle(dev->parent);
24122412
cl_err(dev, cl, "rpm: get failed %d\n", rets);
24132413
return rets;
24142414
}
@@ -2444,8 +2444,8 @@ int mei_cl_dma_unmap(struct mei_cl *cl, const struct file *fp)
24442444
mei_cl_dma_free(cl);
24452445
out:
24462446
cl_dbg(dev, cl, "rpm: autosuspend\n");
2447-
pm_runtime_mark_last_busy(dev->dev);
2448-
pm_runtime_put_autosuspend(dev->dev);
2447+
pm_runtime_mark_last_busy(dev->parent);
2448+
pm_runtime_put_autosuspend(dev->parent);
24492449

24502450
mei_io_cb_free(cb);
24512451
return rets;

drivers/misc/mei/client.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,12 @@ int mei_cl_dma_unmap(struct mei_cl *cl, const struct file *fp);
275275
#define MEI_CL_PRM(cl) (cl)->host_client_id, mei_cl_me_id(cl)
276276

277277
#define cl_dbg(dev, cl, format, arg...) \
278-
dev_dbg((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
278+
dev_dbg(&(dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
279279

280280
#define cl_warn(dev, cl, format, arg...) \
281-
dev_warn((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
281+
dev_warn(&(dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
282282

283283
#define cl_err(dev, cl, format, arg...) \
284-
dev_err((dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
284+
dev_err(&(dev)->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg)
285285

286286
#endif /* _MEI_CLIENT_H_ */

0 commit comments

Comments
 (0)