Skip to content

Commit 830ead5

Browse files
kubalewskidavem330
authored andcommitted
dpll: fix pin dump crash for rebound module
When a kernel module is unbound but the pin resources were not entirely freed (other kernel module instance of the same PCI device have had kept the reference to that pin), and kernel module is again bound, the pin properties would not be updated (the properties are only assigned when memory for the pin is allocated), prop pointer still points to the kernel module memory of the kernel module which was deallocated on the unbind. If the pin dump is invoked in this state, the result is a kernel crash. Prevent the crash by storing persistent pin properties in dpll subsystem, copy the content from the kernel module when pin is allocated, instead of using memory of the kernel module. Fixes: 9431063 ("dpll: core: Add DPLL framework base functions") Fixes: 9d71b54 ("dpll: netlink: Add DPLL framework base functions") Reviewed-by: Jan Glaza <jan.glaza@intel.com> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent b6a11a7 commit 830ead5

File tree

3 files changed

+69
-18
lines changed

3 files changed

+69
-18
lines changed

drivers/dpll/dpll_core.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,53 @@ void dpll_device_unregister(struct dpll_device *dpll,
425425
}
426426
EXPORT_SYMBOL_GPL(dpll_device_unregister);
427427

428+
static void dpll_pin_prop_free(struct dpll_pin_properties *prop)
429+
{
430+
kfree(prop->package_label);
431+
kfree(prop->panel_label);
432+
kfree(prop->board_label);
433+
kfree(prop->freq_supported);
434+
}
435+
436+
static int dpll_pin_prop_dup(const struct dpll_pin_properties *src,
437+
struct dpll_pin_properties *dst)
438+
{
439+
memcpy(dst, src, sizeof(*dst));
440+
if (src->freq_supported && src->freq_supported_num) {
441+
size_t freq_size = src->freq_supported_num *
442+
sizeof(*src->freq_supported);
443+
dst->freq_supported = kmemdup(src->freq_supported,
444+
freq_size, GFP_KERNEL);
445+
if (!src->freq_supported)
446+
return -ENOMEM;
447+
}
448+
if (src->board_label) {
449+
dst->board_label = kstrdup(src->board_label, GFP_KERNEL);
450+
if (!dst->board_label)
451+
goto err_board_label;
452+
}
453+
if (src->panel_label) {
454+
dst->panel_label = kstrdup(src->panel_label, GFP_KERNEL);
455+
if (!dst->panel_label)
456+
goto err_panel_label;
457+
}
458+
if (src->package_label) {
459+
dst->package_label = kstrdup(src->package_label, GFP_KERNEL);
460+
if (!dst->package_label)
461+
goto err_package_label;
462+
}
463+
464+
return 0;
465+
466+
err_package_label:
467+
kfree(dst->panel_label);
468+
err_panel_label:
469+
kfree(dst->board_label);
470+
err_board_label:
471+
kfree(dst->freq_supported);
472+
return -ENOMEM;
473+
}
474+
428475
static struct dpll_pin *
429476
dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
430477
const struct dpll_pin_properties *prop)
@@ -443,7 +490,9 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
443490
ret = -EINVAL;
444491
goto err_pin_prop;
445492
}
446-
pin->prop = prop;
493+
ret = dpll_pin_prop_dup(prop, &pin->prop);
494+
if (ret)
495+
goto err_pin_prop;
447496
refcount_set(&pin->refcount, 1);
448497
xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC);
449498
xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC);
@@ -455,6 +504,7 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module,
455504
err_xa_alloc:
456505
xa_destroy(&pin->dpll_refs);
457506
xa_destroy(&pin->parent_refs);
507+
dpll_pin_prop_free(&pin->prop);
458508
err_pin_prop:
459509
kfree(pin);
460510
return ERR_PTR(ret);
@@ -515,6 +565,7 @@ void dpll_pin_put(struct dpll_pin *pin)
515565
xa_destroy(&pin->dpll_refs);
516566
xa_destroy(&pin->parent_refs);
517567
xa_erase(&dpll_pin_xa, pin->id);
568+
dpll_pin_prop_free(&pin->prop);
518569
kfree(pin);
519570
}
520571
mutex_unlock(&dpll_lock);
@@ -637,7 +688,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
637688
unsigned long i, stop;
638689
int ret;
639690

640-
if (WARN_ON(parent->prop->type != DPLL_PIN_TYPE_MUX))
691+
if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX))
641692
return -EINVAL;
642693

643694
if (WARN_ON(!ops) ||

drivers/dpll/dpll_core.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct dpll_device {
4444
* @module: module of creator
4545
* @dpll_refs: hold referencees to dplls pin was registered with
4646
* @parent_refs: hold references to parent pins pin was registered with
47-
* @prop: pointer to pin properties given by registerer
47+
* @prop: pin properties copied from the registerer
4848
* @rclk_dev_name: holds name of device when pin can recover clock from it
4949
* @refcount: refcount
5050
**/
@@ -55,7 +55,7 @@ struct dpll_pin {
5555
struct module *module;
5656
struct xarray dpll_refs;
5757
struct xarray parent_refs;
58-
const struct dpll_pin_properties *prop;
58+
struct dpll_pin_properties prop;
5959
refcount_t refcount;
6060
};
6161

drivers/dpll/dpll_netlink.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,17 +303,17 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin,
303303
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq,
304304
DPLL_A_PIN_PAD))
305305
return -EMSGSIZE;
306-
for (fs = 0; fs < pin->prop->freq_supported_num; fs++) {
306+
for (fs = 0; fs < pin->prop.freq_supported_num; fs++) {
307307
nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED);
308308
if (!nest)
309309
return -EMSGSIZE;
310-
freq = pin->prop->freq_supported[fs].min;
310+
freq = pin->prop.freq_supported[fs].min;
311311
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq),
312312
&freq, DPLL_A_PIN_PAD)) {
313313
nla_nest_cancel(msg, nest);
314314
return -EMSGSIZE;
315315
}
316-
freq = pin->prop->freq_supported[fs].max;
316+
freq = pin->prop.freq_supported[fs].max;
317317
if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq),
318318
&freq, DPLL_A_PIN_PAD)) {
319319
nla_nest_cancel(msg, nest);
@@ -329,9 +329,9 @@ static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq)
329329
{
330330
int fs;
331331

332-
for (fs = 0; fs < pin->prop->freq_supported_num; fs++)
333-
if (freq >= pin->prop->freq_supported[fs].min &&
334-
freq <= pin->prop->freq_supported[fs].max)
332+
for (fs = 0; fs < pin->prop.freq_supported_num; fs++)
333+
if (freq >= pin->prop.freq_supported[fs].min &&
334+
freq <= pin->prop.freq_supported[fs].max)
335335
return true;
336336
return false;
337337
}
@@ -421,7 +421,7 @@ static int
421421
dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin,
422422
struct netlink_ext_ack *extack)
423423
{
424-
const struct dpll_pin_properties *prop = pin->prop;
424+
const struct dpll_pin_properties *prop = &pin->prop;
425425
struct dpll_pin_ref *ref;
426426
int ret;
427427

@@ -717,7 +717,7 @@ dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx,
717717
int ret;
718718

719719
if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
720-
pin->prop->capabilities)) {
720+
pin->prop.capabilities)) {
721721
NL_SET_ERR_MSG(extack, "state changing is not allowed");
722722
return -EOPNOTSUPP;
723723
}
@@ -753,7 +753,7 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin,
753753
int ret;
754754

755755
if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE &
756-
pin->prop->capabilities)) {
756+
pin->prop.capabilities)) {
757757
NL_SET_ERR_MSG(extack, "state changing is not allowed");
758758
return -EOPNOTSUPP;
759759
}
@@ -780,7 +780,7 @@ dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin,
780780
int ret;
781781

782782
if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE &
783-
pin->prop->capabilities)) {
783+
pin->prop.capabilities)) {
784784
NL_SET_ERR_MSG(extack, "prio changing is not allowed");
785785
return -EOPNOTSUPP;
786786
}
@@ -808,7 +808,7 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll,
808808
int ret;
809809

810810
if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE &
811-
pin->prop->capabilities)) {
811+
pin->prop.capabilities)) {
812812
NL_SET_ERR_MSG(extack, "direction changing is not allowed");
813813
return -EOPNOTSUPP;
814814
}
@@ -838,8 +838,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr,
838838
int ret;
839839

840840
phase_adj = nla_get_s32(phase_adj_attr);
841-
if (phase_adj > pin->prop->phase_range.max ||
842-
phase_adj < pin->prop->phase_range.min) {
841+
if (phase_adj > pin->prop.phase_range.max ||
842+
phase_adj < pin->prop.phase_range.min) {
843843
NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr,
844844
"phase adjust value not supported");
845845
return -EINVAL;
@@ -1023,7 +1023,7 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr,
10231023
unsigned long i;
10241024

10251025
xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) {
1026-
prop = pin->prop;
1026+
prop = &pin->prop;
10271027
cid_match = clock_id ? pin->clock_id == clock_id : true;
10281028
mod_match = mod_name_attr && module_name(pin->module) ?
10291029
!nla_strcmp(mod_name_attr,

0 commit comments

Comments
 (0)