-
Notifications
You must be signed in to change notification settings - Fork 130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ASoC: SOF: Fix buffer copy size error in ext bytes get and add checks #125
ASoC: SOF: Fix buffer copy size error in ext bytes get and add checks #125
Conversation
sound/soc/sof/control.c
Outdated
/* Limit size to prevent read of kernel data */ | ||
if (size > max_length) { | ||
size = max_length; | ||
dev_dbg(sdev->dev, "warning: the copy length was limited\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@singalsu Should this be an error? Does it make sense to copy partial data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The size of copy originates from topology. I agree this should be better to be an error. There's need to fix topology if this happens.
sound/soc/sof/control.c
Outdated
size = max_length; | ||
dev_dbg(sdev->dev, "warning: the copy length was limited\n"); | ||
} | ||
|
||
dev_dbg(sdev->dev, "getting data and command is %d\n", scontrol->cmd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we please remove this line? this was added for debug purposes when working on the demo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, sure.
sound/soc/sof/control.c
Outdated
if (copy_to_user(binary_data + 2, cdata->data->data, | ||
SOF_IPC_MSG_MAX_SIZE - sizeof(struct sof_ipc_ctrl_data))) | ||
|
||
if (copy_to_user(binary_data + 2, cdata->data->data, size)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@singalsu should this be "size" bytes or max_length bytes or the size sent by the FW?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The design problem with ASoC get is that the size should originate from firmware or at least have possibility to return the actual bytes read. Now the request is for the topology specified length but since it varies the request is always the max length. I used as example for this fix the similar ext bytes get function for Skylake.
But it should be acceptable for the user space to get a max length response and then use the uapi headers to get the relevant data. In EQ case the first uint32_t word after the user copy header is the length to use.
So, I'd keep this as is in the patch.
7a64a66
to
171e225
Compare
sound/soc/sof/control.c
Outdated
if (err < 0) | ||
dev_err(sdev->dev, "error: failed to idle %d\n", err); | ||
|
||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@singalsu I see why you have err and ret, but its confusing to see err just above and return "ret" instead. I think we should just use one and return the latest return value from the runtime_put. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question. I need to find out if err means that the operation has failed with incorrect data or is this just something to note into debug trace. Failing with idle doesn't sound like the ext bytes get has failed. I never saw this to happen in my tests though.
There's also the return value from the IPC command that is not stored & checked. That might be the most relevant for return code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@singalsu I think we should skip checking the return value for runtime_put if we arent going to use the value at all.
It is more important to check the return value for runtime_get_sync.
sound/soc/sof/control.c
Outdated
@@ -302,10 +302,13 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, | |||
return -EFAULT; | |||
|
|||
length = header[1]; | |||
dev_dbg(sdev->dev, "size of bytes put data is %d\n", length); | |||
if (max_length > be->max) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably want a dev_warn() here stating that userspace is sending too much data and it has been truncated
sound/soc/sof/control.c
Outdated
* the limit from ext bytes size from topology and SOF IPC | ||
* size limit. | ||
*/ | ||
size -= 2 * sizeof(u32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is 2 * sizeof int32_t ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lgirdwood when sending the bytes from the userspace, the first 2 u32's are actually not part of the actual data to be sent to the firmware. Instead the first uint is a tag and the second is the size of bytes being sent. So we subtract those from the size to be passed to the firmware.
@singalsu can we please update the comment to reflect it and maybe define a macro like BYTE_CTL_HEADER_SIZE instead of 2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets find the C structure that defines this ABI and subtract it's sizeof otherwise this code will break with any ABI update or on another architecture.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, I'll search for struct.
I followed the example in sound/soc/intel/skylake/skl-topology.c function skl_tplg_tlv_control_get(). I'm wondering why the size need to be decremented. It prevents getting the max topology defined length of ext bytes data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I searched in ASoC more examples and found one.
Function wm_coeff_tlv_get() in wm_adsp.c does not place the tag & size into header and does not decrement the size.
That way there would be no need for header struct knowledge but I haven't tested yet if that would work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ranj063 @lgirdwood Based on my quick test the ext bytes get works without placing the header to data[0] and data[1]. I can read back successfully the previously written coefficients to user space. Maybe using this header for get is a misunderstanding.
The header definitely is present in ext bytes put copy_from_user() so this looks different. Any thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@singalsu I would follow any prior art that is upstream on the matter. Lets do the same.
171e225
to
0c7c77a
Compare
@ranj063 @lgirdwood I've updated the PR now. Though I'm not sure if use of struct snd_ctl_tlv was your recommendation or should I use a SOF version of it. In line 385 I set the numid to zero. Also I wasn't sure about that vs. having macro in SOF. And it's not checked in bytes put. Thoughts? |
sound/soc/sof/control.c
Outdated
SOF_IPC_COMP_GET_DATA, | ||
SOF_CTRL_TYPE_DATA_GET, scontrol->cmd); | ||
|
||
header.numid = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should't this be the same ID as passed in binary_data ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean that numid should be set to scontrol->cmd (e.g. SOF_CTRL_CMD_BINARY)? And should we add check to put function that numid == scontrol->cmd?
This patch adds to bytes put a check to not exceed the topology defined bytes control length. The tlv control header is used for retrieving length instead to directly access the header words. In bytes get the size field in the header is set the to the value that is passed to the function minus the header length. It prevents to write past the user space buffer. The size parameter originates from topology. Checks for size violations vs. topology and IPC are added. The other changes add debug prints to kernel log to see the actual size limits and do code cleanup. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
0c7c77a
to
36a50af
Compare
@lgirdwood I just pushed updated version. The numid is now compared to/set to scontrol->cmd. Hope you meant this with your comment. |
…part2 Documentation: teaching: labs: filesystems_part2: Fix typos
MAINTAINERS: update
…ed bind() Syzbot detected a NULL pointer dereference of nfc_llcp_sock->dev pointer (which is a 'struct nfc_dev *') with calls to llcp_sock_sendmsg() after a failed llcp_sock_bind(). The message being sent is a SOCK_DGRAM. KASAN report: BUG: KASAN: null-ptr-deref in nfc_alloc_send_skb+0x2d/0xc0 Read of size 4 at addr 00000000000005c8 by task llcp_sock_nfc_a/899 CPU: 5 PID: 899 Comm: llcp_sock_nfc_a Not tainted 5.16.0-rc6-next-20211224-00001-gc6437fbf18b0 thesofproject#125 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x45/0x59 ? nfc_alloc_send_skb+0x2d/0xc0 __kasan_report.cold+0x117/0x11c ? mark_lock+0x480/0x4f0 ? nfc_alloc_send_skb+0x2d/0xc0 kasan_report+0x38/0x50 nfc_alloc_send_skb+0x2d/0xc0 nfc_llcp_send_ui_frame+0x18c/0x2a0 ? nfc_llcp_send_i_frame+0x230/0x230 ? __local_bh_enable_ip+0x86/0xe0 ? llcp_sock_connect+0x470/0x470 ? llcp_sock_connect+0x470/0x470 sock_sendmsg+0x8e/0xa0 ____sys_sendmsg+0x253/0x3f0 ... The issue was visible only with multiple simultaneous calls to bind() and sendmsg(), which resulted in most of the bind() calls to fail. The bind() was failing on checking if there is available WKS/SDP/SAP (respective bit in 'struct nfc_llcp_local' fields). When there was no available WKS/SDP/SAP, the bind returned error but the sendmsg() to such socket was able to trigger mentioned NULL pointer dereference of nfc_llcp_sock->dev. The code looks simply racy and currently it protects several paths against race with checks for (!nfc_llcp_sock->local) which is NULL-ified in error paths of bind(). The llcp_sock_sendmsg() did not have such check but called function nfc_llcp_send_ui_frame() had, although not protected with lock_sock(). Therefore the race could look like (same socket is used all the time): CPU0 CPU1 ==== ==== llcp_sock_bind() - lock_sock() - success - release_sock() - return 0 llcp_sock_sendmsg() - lock_sock() - release_sock() llcp_sock_bind(), same socket - lock_sock() - error - nfc_llcp_send_ui_frame() - if (!llcp_sock->local) - llcp_sock->local = NULL - nfc_put_device(dev) - dereference llcp_sock->dev - release_sock() - return -ERRNO The nfc_llcp_send_ui_frame() checked llcp_sock->local outside of the lock, which is racy and ineffective check. Instead, its caller llcp_sock_sendmsg(), should perform the check inside lock_sock(). Reported-and-tested-by: syzbot+7f23bcddf626e0593a39@syzkaller.appspotmail.com Fixes: b874dec ("NFC: Implement LLCP connection less Tx path") Cc: <stable@vger.kernel.org> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Like commit 1cf3bfc ("bpf: Support 64-bit pointers to kfuncs") for s390x, add support for 64-bit pointers to kfuncs for LoongArch. Since the infrastructure is already implemented in BPF core, the only thing need to be done is to override bpf_jit_supports_far_kfunc_call(). Before this change, several test_verifier tests failed: # ./test_verifier | grep # | grep FAIL thesofproject#119/p calls: invalid kfunc call: ptr_to_mem to struct with non-scalar FAIL thesofproject#120/p calls: invalid kfunc call: ptr_to_mem to struct with nesting depth > 4 FAIL thesofproject#121/p calls: invalid kfunc call: ptr_to_mem to struct with FAM FAIL thesofproject#122/p calls: invalid kfunc call: reg->type != PTR_TO_CTX FAIL thesofproject#123/p calls: invalid kfunc call: void * not allowed in func proto without mem size arg FAIL thesofproject#124/p calls: trigger reg2btf_ids[reg->type] for reg->type > __BPF_REG_TYPE_MAX FAIL thesofproject#125/p calls: invalid kfunc call: reg->off must be zero when passed to release kfunc FAIL thesofproject#126/p calls: invalid kfunc call: don't match first member type when passed to release kfunc FAIL thesofproject#127/p calls: invalid kfunc call: PTR_TO_BTF_ID with negative offset FAIL thesofproject#128/p calls: invalid kfunc call: PTR_TO_BTF_ID with variable offset FAIL thesofproject#129/p calls: invalid kfunc call: referenced arg needs refcounted PTR_TO_BTF_ID FAIL thesofproject#130/p calls: valid kfunc call: referenced arg needs refcounted PTR_TO_BTF_ID FAIL thesofproject#486/p map_kptr: ref: reference state created and released on xchg FAIL This is because the kfuncs in the loaded module are far away from __bpf_call_base: ffff800002009440 t bpf_kfunc_call_test_fail1 [bpf_testmod] 9000000002e128d8 T __bpf_call_base The offset relative to __bpf_call_base does NOT fit in s32, which breaks the assumption in BPF core. Enable bpf_jit_supports_far_kfunc_call() lifts this limit. Note that to reproduce the above result, tools/testing/selftests/bpf/config should be applied, and run the test with JIT enabled, unpriv BPF enabled. With this change, the test_verifier tests now all passed: # ./test_verifier ... Summary: 777 PASSED, 0 SKIPPED, 0 FAILED Tested-by: Tiezhu Yang <yangtiezhu@loongson.cn> Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This patch replaces the copy_to_user() size with the value that was
passed to the function minus the user data header length. It prevents
to exceed the user space buffer. The size originates from topology. The
compare to topology specified length is also added to ext bytes put.
The other changes add debug prints to kernel log to see the actual size
limits.
Signed-off-by: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com