ams and clk fixes#10881
Conversation
The slot copy length came from a macro that adds the message length, which over-read past the payload struct since the message data is referenced by pointer, not stored inline. Copy exactly the struct size, which is what the slot stores and the consumer reads back. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
There was a problem hiding this comment.
Pull request overview
This PR applies two small safety/correctness fixes in core infrastructure code: CPU clock frequency selection and AMS slot payload copying.
Changes:
- Prevent out-of-bounds indexing in
request_freq_change()when the requested frequency exceeds the highest entry in the clock frequency table. - Fix
ams_push_slot()to copy only thestruct ams_message_payloadinto a slot, avoiding an out-of-bounds read caused by usingAMS_MESSAGE_SIZE()with a payload type that contains a pointer (not inline data).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/lib/cpu-clk-manager.c |
Clamps selected_freq_id to the last valid frequency-table entry before indexing, preventing OOB access. |
src/lib/ams.c |
Adjusts slot copy size to sizeof(*msg) to avoid over-reading past struct ams_message_payload. |
kv2019i
left a comment
There was a problem hiding this comment.
Code changes good, commit messages have invalid line wrapping.
| break; | ||
| } | ||
|
|
||
| /* if no entry was larger than the requested frequency the loop runs off |
There was a problem hiding this comment.
Commit message needs fixing.
There was a problem hiding this comment.
Reflowed the commit message body to wrap at <=72 columns (kernel/git convention, under the old checkpatch 75-char limit) and force-pushed.
| err = memcpy_s((__sparse_force void *)ctx_shared->slots[i].u.msg_raw, | ||
| sizeof(ctx_shared->slots[i].u.msg_raw), | ||
| msg, AMS_MESSAGE_SIZE(msg)); | ||
| msg, sizeof(*msg)); |
There was a problem hiding this comment.
I don't know how AMS works, but this looks suspicious - the type of msg is also called "...payload" which seems to suggest that the data is also attached to the header, which would then be dropped by this change?
There was a problem hiding this comment.
The message field is a pointer (uint8_t *message), not inline data — ams_helper_prepare_payload() does payload->message = message, pointing at a caller-owned buffer. So the payload bytes are referenced by the pointer, not appended after the struct.
AMS_MESSAGE_SIZE() = sizeof(*msg) - 1 + message_length therefore reads message_length - 1 bytes past the end of the struct (adjacent memory), not the actual payload. The slot only needs to carry the struct itself (which already includes the message pointer and message_length); ams_process_slot() copies the slot back into a struct ams_message_payload and uses those fields. So copying sizeof(*msg) preserves exactly what the consumer reads back and just removes the over-read — no payload is dropped.
(Whether that message pointer stays valid by the time another core consumes the slot is a separate, pre-existing concern this patch doesn't change.)
There was a problem hiding this comment.
@lgirdwood yes, I saw that comment, and I don't quite understand or follow it. "The message field is a pointer (uint8_t *message), not inline data" - of course it is a pointer - a local variable, containing a pointer. A pointer to a buffer that begins with a header which is followed by data. What's the difference?
There was a problem hiding this comment.
I traced the full path to be sure, and the by-pointer reading holds:
- Producer (
detect_test.c: ams_notify_kpb):ams_helper_prepare_payload()setsmessage = (uint8_t *)&cd->client_data(persistent component data) andmessage_length = sizeof(struct kpb_client). - Consumer (
kpb.c: kpb_ams_kpd_notification):struct kpb_client *cli_data = (struct kpb_client *)payload->message;— it casts themessagepointer and dereferences it; nothing reads inline bytes. - Same-core delivery passes the producer's payload straight to the callback (no slot copy at all).
- Cross-core delivery:
send_message_over_ixc()sends an IDC message carrying only the slot index (size = 0, payload = NULL); the target core reads the slot struct from the shared coherent context and dereferencesmessage(valid across SMP cores).
So the payload is never stored inline — the slot only needs the struct (which holds the message pointer + length). AMS_MESSAGE_SIZE() = sizeof(*msg) - 1 + message_length was reading message_length - 1 bytes past the producer struct and copying bytes the consumer never looks at; sizeof(*msg) copies exactly what's read back. So the fix is correct and no payload is dropped.
It was also the only user of AMS_MESSAGE_SIZE(), and AMS_SLOT_SIZE() had none, so I've removed both as dead/misleading in a follow-up commit.
(Orthogonal, pre-existing: the by-pointer design requires the producer's buffer to outlive async cross-core delivery — current clients point at persistent state, so that's fine; just noting the contract.)
| /* if no entry was larger than the requested frequency the loop runs off | ||
| * the end of the table; clamp to the last valid entry before indexing | ||
| */ | ||
| if (selected_freq_id >= clk->freqs_num) |
There was a problem hiding this comment.
I'd make the condition == for clarity
There was a problem hiding this comment.
Done, changed to ==. After the loop selected_freq_id can only be < freqs_num (loop break) or exactly == freqs_num (ran off the end), so == is precise and reads clearer.
When the requested frequency was at least every table entry, the search index ran off the end of the table and the following access read one element past it. Clamp the index to the last valid entry. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
AMS_MESSAGE_SIZE() and AMS_SLOT_SIZE() assumed the message payload was stored inline after the header, but ams_message_payload.message is a pointer to a caller-owned buffer (set in ams_helper_prepare_payload) and the slot only carries the fixed-size struct. The last use of AMS_MESSAGE_SIZE() was replaced by sizeof(*msg); AMS_SLOT_SIZE() had no users. Remove both as dead and misleading. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Small fixes for AMS and clk manager.