Unverified Commit 002ec157 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'scmi-fixes-5.19' of...

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/20220614100007.1029881-1-sudeep.holla@arm.com


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 2916bf22 44dbdf3b
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ struct scmi_msg_resp_base_attributes {

struct scmi_msg_resp_base_discover_agent {
	__le32 agent_id;
	u8 name[SCMI_MAX_STR_SIZE];
	u8 name[SCMI_SHORT_NAME_MAX_SIZE];
};


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

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

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

@@ -221,12 +221,18 @@ scmi_base_implementation_list_get(const struct scmi_protocol_handle *ph,
		calc_list_sz = (1 + (loop_num_ret - 1) / sizeof(u32)) *
				sizeof(u32);
		if (calc_list_sz != real_list_sz) {
			dev_err(dev,
				"Malformed reply - real_sz:%zd  calc_sz:%u\n",
				real_list_sz, calc_list_sz);
			dev_warn(dev,
				 "Malformed reply - real_sz:%zd  calc_sz:%u  (loop_num_ret:%d)\n",
				 real_list_sz, calc_list_sz, loop_num_ret);
			/*
			 * Bail out if the expected list size is bigger than the
			 * total payload size of the received reply.
			 */
			if (calc_list_sz > real_list_sz) {
				ret = -EPROTO;
				break;
			}
		}

		for (loop = 0; loop < loop_num_ret; loop++)
			protocols_imp[tot_num_ret + loop] = *(list + loop);
@@ -270,7 +276,7 @@ static int scmi_base_discover_agent_get(const struct scmi_protocol_handle *ph,
	ret = ph->xops->do_xfer(ph, t);
	if (!ret) {
		agent_info = t->rx.buf;
		strlcpy(name, agent_info->name, SCMI_MAX_STR_SIZE);
		strscpy(name, agent_info->name, SCMI_SHORT_NAME_MAX_SIZE);
	}

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

+3 −4
Original line number Diff line number Diff line
@@ -153,7 +153,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
	if (!ret) {
		u32 latency = 0;
		attributes = le32_to_cpu(attr->attributes);
		strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
		strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
		/* clock_enable_latency field is present only since SCMI v3.1 */
		if (PROTOCOL_REV_MAJOR(version) >= 0x2)
			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,
			      struct scmi_clock_info *clk)
{
	int ret;

	void *iter;
	struct scmi_msg_clock_describe_rates *msg;
	struct scmi_iterator_ops ops = {
		.prepare_message = iter_clk_describe_prepare_message,
		.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,

	iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
					    CLOCK_DESCRIBE_RATES,
					    sizeof(*msg), &cpriv);
					    sizeof(struct scmi_msg_clock_describe_rates),
					    &cpriv);
	if (IS_ERR(iter))
		return PTR_ERR(iter);

+3 −3
Original line number Diff line number Diff line
@@ -252,7 +252,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
			dom_info->mult_factor =
					(dom_info->sustained_freq_khz * 1000) /
					dom_info->sustained_perf_level;
		strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
		strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
	}

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

	iter = ph->hops->iter_response_init(ph, &ops, MAX_OPPS,
					    PERF_DESCRIBE_LEVELS,
					    sizeof(*msg), &ppriv);
					    sizeof(struct scmi_msg_perf_describe_levels),
					    &ppriv);
	if (IS_ERR(iter))
		return PTR_ERR(iter);

+1 −1
Original line number Diff line number Diff line
@@ -122,7 +122,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
		dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
		dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
		dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
		strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
		strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
	}
	ph->xops->xfer_put(ph, t);

+0 −2
Original line number Diff line number Diff line
@@ -24,8 +24,6 @@

#include <asm/unaligned.h>

#define SCMI_SHORT_NAME_MAX_SIZE	16

#define PROTOCOL_REV_MINOR_MASK	GENMASK(15, 0)
#define PROTOCOL_REV_MAJOR_MASK	GENMASK(31, 16)
#define PROTOCOL_REV_MAJOR(x)	((u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x))))
Loading