Skip to content

Commit 002ec15

Browse files
committed
Merge tag 'scmi-fixes-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes
Arm SCMI firmware driver fixes for v5.19 Bunch of fixes to address: 1. Issues reported on RK3568 EVB1 and BPI-R2 pro platforms using SCMI. More checks were added to validate the firmware response but that resulted in breaking above platforms, so the checks are relaxed when for cases where there is no potential memory corruption issues. 2. Possible data leak by reading more than required length from the firmware. Recent addition of support for v3.1 extended names used larger buffers in the kernel and used their size to read response from the firmware even for cases where shorter formats are used. While that is mostly harmless except when firmware sends malformed non-NULL terminated buffers. 3. Possible issues sending unsupported commands to the firmware. SENSOR_AXIS_NAME_GET added in v3.1 needs to be used only if the firmware supports it. While the firmware conformant to the spec must return not supported error for any unsupported features, it is always safer to avoid issuing commands that are known to be unsupported. 4. Incorrect error propagation in scmi_voltage_descriptors_get. Since the return value is not reset for each iteration of the loop, the error value in the previous iteration will be carried for the current one. Fix that by not saving the return values into local variable. 5. Some warnings reported by cppcheck * tag 'scmi-fixes-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_scmi: Fix incorrect error propagation in scmi_voltage_descriptors_get firmware: arm_scmi: Avoid using extended string-buffers sizes if not necessary firmware: arm_scmi: Fix SENSOR_AXIS_NAME_GET behaviour when unsupported firmware: arm_scmi: Remove all the unused local variables firmware: arm_scmi: Relax base protocol sanity checks on the protocol list Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 2916bf2 + 44dbdf3 commit 002ec15

File tree

9 files changed

+85
-50
lines changed

9 files changed

+85
-50
lines changed

drivers/firmware/arm_scmi/base.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct scmi_msg_resp_base_attributes {
3636

3737
struct scmi_msg_resp_base_discover_agent {
3838
__le32 agent_id;
39-
u8 name[SCMI_MAX_STR_SIZE];
39+
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
4040
};
4141

4242

@@ -119,7 +119,7 @@ scmi_base_vendor_id_get(const struct scmi_protocol_handle *ph, bool sub_vendor)
119119

120120
ret = ph->xops->do_xfer(ph, t);
121121
if (!ret)
122-
memcpy(vendor_id, t->rx.buf, size);
122+
strscpy(vendor_id, t->rx.buf, size);
123123

124124
ph->xops->xfer_put(ph, t);
125125

@@ -221,11 +221,17 @@ scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
221221
calc_list_sz = (1 + (loop_num_ret - 1) / sizeof(u32)) *
222222
sizeof(u32);
223223
if (calc_list_sz != real_list_sz) {
224-
dev_err(dev,
225-
"Malformed reply - real_sz:%zd calc_sz:%u\n",
226-
real_list_sz, calc_list_sz);
227-
ret = -EPROTO;
228-
break;
224+
dev_warn(dev,
225+
"Malformed reply - real_sz:%zd calc_sz:%u (loop_num_ret:%d)\n",
226+
real_list_sz, calc_list_sz, loop_num_ret);
227+
/*
228+
* Bail out if the expected list size is bigger than the
229+
* total payload size of the received reply.
230+
*/
231+
if (calc_list_sz > real_list_sz) {
232+
ret = -EPROTO;
233+
break;
234+
}
229235
}
230236

231237
for (loop = 0; loop < loop_num_ret; loop++)
@@ -270,7 +276,7 @@ static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
270276
ret = ph->xops->do_xfer(ph, t);
271277
if (!ret) {
272278
agent_info = t->rx.buf;
273-
strlcpy(name, agent_info->name, SCMI_MAX_STR_SIZE);
279+
strscpy(name, agent_info->name, SCMI_SHORT_NAME_MAX_SIZE);
274280
}
275281

276282
ph->xops->xfer_put(ph, t);
@@ -369,7 +375,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
369375
int id, ret;
370376
u8 *prot_imp;
371377
u32 version;
372-
char name[SCMI_MAX_STR_SIZE];
378+
char name[SCMI_SHORT_NAME_MAX_SIZE];
373379
struct device *dev = ph->dev;
374380
struct scmi_revision_info *rev = scmi_revision_area_get(ph);
375381

drivers/firmware/arm_scmi/clock.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
153153
if (!ret) {
154154
u32 latency = 0;
155155
attributes = le32_to_cpu(attr->attributes);
156-
strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
156+
strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
157157
/* clock_enable_latency field is present only since SCMI v3.1 */
158158
if (PROTOCOL_REV_MAJOR(version) >= 0x2)
159159
latency = le32_to_cpu(attr->clock_enable_latency);
@@ -266,9 +266,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
266266
struct scmi_clock_info *clk)
267267
{
268268
int ret;
269-
270269
void *iter;
271-
struct scmi_msg_clock_describe_rates *msg;
272270
struct scmi_iterator_ops ops = {
273271
.prepare_message = iter_clk_describe_prepare_message,
274272
.update_state = iter_clk_describe_update_state,
@@ -281,7 +279,8 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
281279

282280
iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
283281
CLOCK_DESCRIBE_RATES,
284-
sizeof(*msg), &cpriv);
282+
sizeof(struct scmi_msg_clock_describe_rates),
283+
&cpriv);
285284
if (IS_ERR(iter))
286285
return PTR_ERR(iter);
287286

drivers/firmware/arm_scmi/perf.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
252252
dom_info->mult_factor =
253253
(dom_info->sustained_freq_khz * 1000) /
254254
dom_info->sustained_perf_level;
255-
strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
255+
strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
256256
}
257257

258258
ph->xops->xfer_put(ph, t);
@@ -332,7 +332,6 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
332332
{
333333
int ret;
334334
void *iter;
335-
struct scmi_msg_perf_describe_levels *msg;
336335
struct scmi_iterator_ops ops = {
337336
.prepare_message = iter_perf_levels_prepare_message,
338337
.update_state = iter_perf_levels_update_state,
@@ -345,7 +344,8 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain,
345344

346345
iter = ph->hops->iter_response_init(ph, &ops, MAX_OPPS,
347346
PERF_DESCRIBE_LEVELS,
348-
sizeof(*msg), &ppriv);
347+
sizeof(struct scmi_msg_perf_describe_levels),
348+
&ppriv);
349349
if (IS_ERR(iter))
350350
return PTR_ERR(iter);
351351

drivers/firmware/arm_scmi/power.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
122122
dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
123123
dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
124124
dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
125-
strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
125+
strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
126126
}
127127
ph->xops->xfer_put(ph, t);
128128

drivers/firmware/arm_scmi/protocols.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424

2525
#include <asm/unaligned.h>
2626

27-
#define SCMI_SHORT_NAME_MAX_SIZE 16
28-
2927
#define PROTOCOL_REV_MINOR_MASK GENMASK(15, 0)
3028
#define PROTOCOL_REV_MAJOR_MASK GENMASK(31, 16)
3129
#define PROTOCOL_REV_MAJOR(x) ((u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))))

drivers/firmware/arm_scmi/reset.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
116116
dom_info->latency_us = le32_to_cpu(attr->latency);
117117
if (dom_info->latency_us == U32_MAX)
118118
dom_info->latency_us = 0;
119-
strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
119+
strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
120120
}
121121

122122
ph->xops->xfer_put(ph, t);

drivers/firmware/arm_scmi/sensors.c

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,6 @@ static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
338338
struct scmi_sensor_info *s)
339339
{
340340
void *iter;
341-
struct scmi_msg_sensor_list_update_intervals *msg;
342341
struct scmi_iterator_ops ops = {
343342
.prepare_message = iter_intervals_prepare_message,
344343
.update_state = iter_intervals_update_state,
@@ -351,22 +350,28 @@ static int scmi_sensor_update_intervals(const struct scmi_protocol_handle *ph,
351350

352351
iter = ph->hops->iter_response_init(ph, &ops, s->intervals.count,
353352
SENSOR_LIST_UPDATE_INTERVALS,
354-
sizeof(*msg), &upriv);
353+
sizeof(struct scmi_msg_sensor_list_update_intervals),
354+
&upriv);
355355
if (IS_ERR(iter))
356356
return PTR_ERR(iter);
357357

358358
return ph->hops->iter_response_run(iter);
359359
}
360360

361+
struct scmi_apriv {
362+
bool any_axes_support_extended_names;
363+
struct scmi_sensor_info *s;
364+
};
365+
361366
static void iter_axes_desc_prepare_message(void *message,
362367
const unsigned int desc_index,
363368
const void *priv)
364369
{
365370
struct scmi_msg_sensor_axis_description_get *msg = message;
366-
const struct scmi_sensor_info *s = priv;
371+
const struct scmi_apriv *apriv = priv;
367372

368373
/* Set the number of sensors to be skipped/already read */
369-
msg->id = cpu_to_le32(s->id);
374+
msg->id = cpu_to_le32(apriv->s->id);
370375
msg->axis_desc_index = cpu_to_le32(desc_index);
371376
}
372377

@@ -393,19 +398,21 @@ iter_axes_desc_process_response(const struct scmi_protocol_handle *ph,
393398
u32 attrh, attrl;
394399
struct scmi_sensor_axis_info *a;
395400
size_t dsize = SCMI_MSG_RESP_AXIS_DESCR_BASE_SZ;
396-
struct scmi_sensor_info *s = priv;
401+
struct scmi_apriv *apriv = priv;
397402
const struct scmi_axis_descriptor *adesc = st->priv;
398403

399404
attrl = le32_to_cpu(adesc->attributes_low);
405+
if (SUPPORTS_EXTENDED_AXIS_NAMES(attrl))
406+
apriv->any_axes_support_extended_names = true;
400407

401-
a = &s->axis[st->desc_index + st->loop_idx];
408+
a = &apriv->s->axis[st->desc_index + st->loop_idx];
402409
a->id = le32_to_cpu(adesc->id);
403410
a->extended_attrs = SUPPORTS_EXTEND_ATTRS(attrl);
404411

405412
attrh = le32_to_cpu(adesc->attributes_high);
406413
a->scale = S32_EXT(SENSOR_SCALE(attrh));
407414
a->type = SENSOR_TYPE(attrh);
408-
strscpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);
415+
strscpy(a->name, adesc->name, SCMI_SHORT_NAME_MAX_SIZE);
409416

410417
if (a->extended_attrs) {
411418
unsigned int ares = le32_to_cpu(adesc->resolution);
@@ -444,10 +451,19 @@ iter_axes_extended_name_process_response(const struct scmi_protocol_handle *ph,
444451
void *priv)
445452
{
446453
struct scmi_sensor_axis_info *a;
447-
const struct scmi_sensor_info *s = priv;
454+
const struct scmi_apriv *apriv = priv;
448455
struct scmi_sensor_axis_name_descriptor *adesc = st->priv;
456+
u32 axis_id = le32_to_cpu(adesc->axis_id);
449457

450-
a = &s->axis[st->desc_index + st->loop_idx];
458+
if (axis_id >= st->max_resources)
459+
return -EPROTO;
460+
461+
/*
462+
* Pick the corresponding descriptor based on the axis_id embedded
463+
* in the reply since the list of axes supporting extended names
464+
* can be a subset of all the axes.
465+
*/
466+
a = &apriv->s->axis[axis_id];
451467
strscpy(a->name, adesc->name, SCMI_MAX_STR_SIZE);
452468
st->priv = ++adesc;
453469

@@ -458,21 +474,36 @@ static int
458474
scmi_sensor_axis_extended_names_get(const struct scmi_protocol_handle *ph,
459475
struct scmi_sensor_info *s)
460476
{
477+
int ret;
461478
void *iter;
462-
struct scmi_msg_sensor_axis_description_get *msg;
463479
struct scmi_iterator_ops ops = {
464480
.prepare_message = iter_axes_desc_prepare_message,
465481
.update_state = iter_axes_extended_name_update_state,
466482
.process_response = iter_axes_extended_name_process_response,
467483
};
484+
struct scmi_apriv apriv = {
485+
.any_axes_support_extended_names = false,
486+
.s = s,
487+
};
468488

469489
iter = ph->hops->iter_response_init(ph, &ops, s->num_axis,
470490
SENSOR_AXIS_NAME_GET,
471-
sizeof(*msg), s);
491+
sizeof(struct scmi_msg_sensor_axis_description_get),
492+
&apriv);
472493
if (IS_ERR(iter))
473494
return PTR_ERR(iter);
474495

475-
return ph->hops->iter_response_run(iter);
496+
/*
497+
* Do not cause whole protocol initialization failure when failing to
498+
* get extended names for axes.
499+
*/
500+
ret = ph->hops->iter_response_run(iter);
501+
if (ret)
502+
dev_warn(ph->dev,
503+
"Failed to get axes extended names for %s (ret:%d).\n",
504+
s->name, ret);
505+
506+
return 0;
476507
}
477508

478509
static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
@@ -481,12 +512,15 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
481512
{
482513
int ret;
483514
void *iter;
484-
struct scmi_msg_sensor_axis_description_get *msg;
485515
struct scmi_iterator_ops ops = {
486516
.prepare_message = iter_axes_desc_prepare_message,
487517
.update_state = iter_axes_desc_update_state,
488518
.process_response = iter_axes_desc_process_response,
489519
};
520+
struct scmi_apriv apriv = {
521+
.any_axes_support_extended_names = false,
522+
.s = s,
523+
};
490524

491525
s->axis = devm_kcalloc(ph->dev, s->num_axis,
492526
sizeof(*s->axis), GFP_KERNEL);
@@ -495,15 +529,17 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
495529

496530
iter = ph->hops->iter_response_init(ph, &ops, s->num_axis,
497531
SENSOR_AXIS_DESCRIPTION_GET,
498-
sizeof(*msg), s);
532+
sizeof(struct scmi_msg_sensor_axis_description_get),
533+
&apriv);
499534
if (IS_ERR(iter))
500535
return PTR_ERR(iter);
501536

502537
ret = ph->hops->iter_response_run(iter);
503538
if (ret)
504539
return ret;
505540

506-
if (PROTOCOL_REV_MAJOR(version) >= 0x3)
541+
if (PROTOCOL_REV_MAJOR(version) >= 0x3 &&
542+
apriv.any_axes_support_extended_names)
507543
ret = scmi_sensor_axis_extended_names_get(ph, s);
508544

509545
return ret;
@@ -598,7 +634,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
598634
SUPPORTS_AXIS(attrh) ?
599635
SENSOR_AXIS_NUMBER(attrh) : 0,
600636
SCMI_MAX_NUM_SENSOR_AXIS);
601-
strscpy(s->name, sdesc->name, SCMI_MAX_STR_SIZE);
637+
strscpy(s->name, sdesc->name, SCMI_SHORT_NAME_MAX_SIZE);
602638

603639
/*
604640
* If supported overwrite short name with the extended

drivers/firmware/arm_scmi/voltage.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
180180
{
181181
int ret;
182182
void *iter;
183-
struct scmi_msg_cmd_describe_levels *msg;
184183
struct scmi_iterator_ops ops = {
185184
.prepare_message = iter_volt_levels_prepare_message,
186185
.update_state = iter_volt_levels_update_state,
@@ -193,7 +192,8 @@ static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
193192

194193
iter = ph->hops->iter_response_init(ph, &ops, v->num_levels,
195194
VOLTAGE_DESCRIBE_LEVELS,
196-
sizeof(*msg), &vpriv);
195+
sizeof(struct scmi_msg_cmd_describe_levels),
196+
&vpriv);
197197
if (IS_ERR(iter))
198198
return PTR_ERR(iter);
199199

@@ -225,15 +225,14 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
225225

226226
/* Retrieve domain attributes at first ... */
227227
put_unaligned_le32(dom, td->tx.buf);
228-
ret = ph->xops->do_xfer(ph, td);
229228
/* Skip domain on comms error */
230-
if (ret)
229+
if (ph->xops->do_xfer(ph, td))
231230
continue;
232231

233232
v = vinfo->domains + dom;
234233
v->id = dom;
235234
attributes = le32_to_cpu(resp_dom->attr);
236-
strlcpy(v->name, resp_dom->name, SCMI_MAX_STR_SIZE);
235+
strscpy(v->name, resp_dom->name, SCMI_SHORT_NAME_MAX_SIZE);
237236

238237
/*
239238
* If supported overwrite short name with the extended one;
@@ -249,12 +248,8 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
249248
v->async_level_set = true;
250249
}
251250

252-
ret = scmi_voltage_levels_get(ph, v);
253251
/* Skip invalid voltage descriptors */
254-
if (ret)
255-
continue;
256-
257-
ph->xops->reset_rx_to_maxsz(ph, td);
252+
scmi_voltage_levels_get(ph, v);
258253
}
259254

260255
ph->xops->xfer_put(ph, td);

include/linux/scmi_protocol.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@
1313
#include <linux/notifier.h>
1414
#include <linux/types.h>
1515

16-
#define SCMI_MAX_STR_SIZE 64
17-
#define SCMI_MAX_NUM_RATES 16
16+
#define SCMI_MAX_STR_SIZE 64
17+
#define SCMI_SHORT_NAME_MAX_SIZE 16
18+
#define SCMI_MAX_NUM_RATES 16
1819

1920
/**
2021
* struct scmi_revision_info - version information structure
@@ -36,8 +37,8 @@ struct scmi_revision_info {
3637
u8 num_protocols;
3738
u8 num_agents;
3839
u32 impl_ver;
39-
char vendor_id[SCMI_MAX_STR_SIZE];
40-
char sub_vendor_id[SCMI_MAX_STR_SIZE];
40+
char vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
41+
char sub_vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
4142
};
4243

4344
struct scmi_clock_info {

0 commit comments

Comments
 (0)