Skip to content

Conversation

@andyross
Copy link
Contributor

@andyross andyross commented Jun 22, 2023

The handling for SOF_COMP_NONE was extracting a "size" field from a
struct sof_ipc_comp_process command and passing it down into the
module_adapter layer where it was being used as the range for a
memcpy_s().

But that struct is IPC input data from the host! The size can
trivially be wrong and cause an overflow. And needless to say,
fuzzing discovered the hole and blew it up.

Note that the previous behavior when LIBRARY||UNIT_TEST is left
unchanged (fuzz builds as "real" firmware and doesn't use those
features). It turns out that this is still in production use, though
the details of why the code is different are unclear. Drop a note in
to fix this later.

lyakh
lyakh previously requested changes Jun 26, 2023
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, proc->data is an array, so this is perfectly valid

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we handle this differently on host ? Expectation is that ABI should be the same, I ssuspect the testbench is doing something different @singalsu @andrula-song ?

Copy link
Collaborator

@singalsu singalsu Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the data advance to past possible UUID can be done in every build, not just UT and testbench. The kernel is not sending the data bundled to just after comp new IPC like tests do, but in separate binary control IPC, so it has not been needed. If there is no blob the config->process.size is zero and config->process.data is not accessed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not only for NONE, it is for ten component cases, check line :268-278.
Are you sure all above cases all does not need this?

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect UT or testbench is doing something different to runtime FW here and should be fixed to align (alongside this).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we handle this differently on host ? Expectation is that ABI should be the same, I ssuspect the testbench is doing something different @singalsu @andrula-song ?

@andyross
Copy link
Contributor Author

andyross commented Jul 6, 2023

So what's the consensus here? As @lyakh points out, my explanation is wrong. It's not the buffer pointer that is at fault, it's that the resulting transfer is unbounded. Nothing in the current scheme passes a valid size for the buffer, so we don't know how much we can copy.

I can try to fix this (by extracting a size from somewhere up higher in the IPC layer I guess), but it seems like there's confusion about whether or not the unit test stuff needs it?

My assumption had been that this code path would never be hit in practice and was just a fuzzable edge. What's the actual circumstance where you'd get data passed in any testing rig for a COMP_NONE component?

Broadly: what happens if we just turn the COMP_NONE handling into a runtime error instead? That would be even less code.

@lgirdwood
Copy link
Member

@andrula-song what happens if we make the host handling the same as FW handling here ? Does testbench still work as expected ? We need to align handling here.

@andrula-song
Copy link
Contributor

andrula-song commented Jul 7, 2023

@andrula-song what happens if we make the host handling the same as FW handling here ? Does testbench still work as expected ? We need to align handling here.

if we make the host handling the same as FW handling here would lead to those sof_ipc_comp_process components(eq,mux/demux) unit test failed. Checked the code, the comp->ext_data_length is UUID_SIZE.

@lgirdwood
Copy link
Member

@andrula-song what happens if we make the host handling the same as FW handling here ? Does testbench still work as expected ? We need to align handling here.

if we make the host handling the same as FW handling here would lead to those sof_ipc_comp_process components(eq,mux/demux) unit test failed. Checked the code, the comp->ext_data_length is UUID_SIZE.

Thanks it does sound the UT is broken then ? Can the UTs be fixed to use same handling as FW ?

@andrula-song
Copy link
Contributor

hi @lgirdwood
yes, it will break the UT for eq-iir, eq-fir,mux and demux. I tried to remove the 'ext_data_length' segment yesterday, but will get error " get_drv(): driver not found,". Seems needs more effort to remove this segment.

@lgirdwood
Copy link
Member

@andyross we need to fix the length issue first. Seppo is best to look at this when he's back. Not sure why testbench is doing something else.

@lgirdwood lgirdwood added this to the v2.7 milestone Jul 11, 2023
The handling for SOF_COMP_NONE was extracting a "size" field from a
struct sof_ipc_comp_process command and passing it down into the
module_adapter layer where it was being used as the range for a
memcpy_s().

But that struct is IPC input data from the host!  The size can
trivially be wrong and cause an overflow.  And needless to say,
fuzzing discovered the hole and blew it up.

Note that the previous behavior when LIBRARY||UNIT_TEST is left
unchanged (fuzz builds as "real" firmware and doesn't use those
features).  It turns out that this is still in production use, though
the details of why the code is different are unclear.  Drop a note in
to fix this later.

Signed-off-by: Andy Ross <andyross@google.com>
@andyross
Copy link
Contributor Author

OK. This version leaves the UNIT_TEST/LIBRARY path unchanged (with a FIXME note). It will have the same bug on bad input, but that isn't involved in either production firmware nor fuzzing, so nothing is getting worse at least.

Also, instead of nulling the pointer out with the bad explanation, this does a slightly more sophisticated trick where it clamps the protocol-provided garbage size value (which was the real root cause) to the known size of the IPC command buffer. I still argue we should remove this whole switch case and replace it with an error, but I guess that will need to wait for the test updates?

@andyross andyross changed the title ipc3: Don't exract local pointer values from input data ipc3: Don't trust size values in protocol input Jul 11, 2023
Copy link
Collaborator

@lyakh lyakh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now handling the same fuzzing detected problem as #7830 and as I commented there in #7830 (comment) I think this function should return an error in case of invalid input data

@singalsu
Copy link
Collaborator

singalsu commented Jul 27, 2023

What do you think of this fix approach?

diff --git a/src/include/ipc/header.h b/src/include/ipc/header.h
index 04b97bb80..0ea1d9f80 100644
--- a/src/include/ipc/header.h
+++ b/src/include/ipc/header.h
@@ -329,7 +329,11 @@ struct ipc_cmd_hdr;
 #define SOF_IPC_MESSAGE_ID(x)			((x) & 0xffff)
 
 /** Maximum message size for mailbox Tx/Rx */
+#if CONFIG_LIBRARY || UNIT_TEST
+#define SOF_IPC_MSG_MAX_SIZE			1024
+#else
 #define SOF_IPC_MSG_MAX_SIZE			384
+#endif
 
 /** @} */
 
diff --git a/src/ipc/ipc3/helper.c b/src/ipc/ipc3/helper.c
index 96124538d..9d7527dae 100644
--- a/src/ipc/ipc3/helper.c
+++ b/src/ipc/ipc3/helper.c
@@ -276,13 +276,14 @@ static int comp_specific_builder(struct sof_ipc_comp *comp,
 	case SOF_COMP_SMART_AMP:
 	case SOF_COMP_MODULE_ADAPTER:
 	case SOF_COMP_NONE:
+		if (proc->size + comp->ext_data_length > SOF_IPC_MSG_MAX_SIZE - sizeof(*proc)) {
+			tr_err(&comp_tr, "comp_specific_builder(): Illegal process IPC size");
+			return -ENOMEM;
+		}
+
 		config->process.type = proc->type;
 		config->process.size = proc->size;
-#if CONFIG_LIBRARY || UNIT_TEST
-		config->process.data = proc->data + comp->ext_data_length;
-#else
-		config->process.data = proc->data;
-#endif
+		config->process.data = proc->data + comp->ext_data_length; /* Skip possible UUID */
 		break;
 	case SOF_COMP_MIXER:
 		break;

There are some unit tests with large blobs, so with this check in place the IPC max size needs an increase for CONFIG_LIBRARY and UNIT_TEST. Testbench could send the multi-part IPC but it would be a quite big change for unit tests, so proposing this way now.

Copy link
Collaborator

@singalsu singalsu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to error the exceed, not limit. Also limiting would break FIR UT.

@lyakh lyakh dismissed their stale review July 28, 2023 08:22

the comment, triggering the change request has been resolved. Now just a specific has to be agreed upon

@singalsu singalsu self-requested a review July 28, 2023 10:21
@singalsu
Copy link
Collaborator

I removed my reject to not block this while I'm one week OOO. But I don't agree with this (no error, cut end of too long IPC) fix approach.

@lgirdwood
Copy link
Member

I removed my reject to not block this while I'm one week OOO. But I don't agree with this (no error, cut end of too long IPC) fix approach.

ack, it seems the best course is to return an error up the stack and add some error message in the logs.

@andyross
Copy link
Contributor Author

andyross commented Aug 8, 2023

Sorry, this got left stale. I'm going to close this, as AFAICT the error it addresses isn't repeating post- #7830 The side question about why unit testing is using a variant protocol can be addressed elsewhere.

@andyross andyross closed this Aug 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants