Re: [PATCH] iwl: fix crash in iwl_dbg_tlv_alloc_trigger

2020-06-12 Thread Luciano Coelho
On Fri, 2020-06-12 at 10:55 +0300, Kalle Valo wrote:
> Jiri Slaby  writes:
> 
> > The tlv passed to iwl_dbg_tlv_alloc_trigger comes from a loaded firmware
> > file. The memory can be marked as read-only as firmware could be
> > shared. In anyway, writing to this memory is not expected. So,
> > iwl_dbg_tlv_alloc_trigger can crash now:
> > 
> >   BUG: unable to handle page fault for address: ae2c01bfa794
> >   PF: supervisor write access in kernel mode
> >   PF: error_code(0x0003) - permissions violation
> >   PGD 107d51067 P4D 107d51067 PUD 107d52067 PMD 659ad2067 PTE 
> > 800662298161
> >   CPU: 2 PID: 161 Comm: kworker/2:1 Not tainted 5.7.0-3.gad96a07-default #1 
> > openSUSE Tumbleweed (unreleased)
> >   RIP: 0010:iwl_dbg_tlv_alloc_trigger+0x25/0x60 [iwlwifi]
> >   Code: eb f2 0f 1f 00 66 66 66 66 90 83 7e 04 33 48 89 f8 44 8b 46 10 48 
> > 89 f7 76 40 41 8d 50 ff 83 fa 19 77 23 8b 56 20 85 d2 75 07  46 20 ff 
> > ff ff ff 4b 8d 14 40 48 c1 e2 04 48 8d b4 10 00 05 00
> >   RSP: 0018:ae2c00417ce8 EFLAGS: 00010246
> >   RAX: 8f0522334018 RBX: 8f0522334018 RCX: c0fc26c0
> >   RDX:  RSI: ae2c01bfa774 RDI: ae2c01bfa774
> >   RBP:  R08: 0004 R09: 0001
> >   R10: 0034 R11: ae2c01bfa77c R12: 8f0522334230
> >   R13: 0109 R14: 8f0523fdbc00 R15: 8f051f395800
> >   FS:  () GS:8f0527c8() 
> > knlGS:
> >   CS:  0010 DS:  ES:  CR0: 80050033
> >   CR2: ae2c01bfa794 CR3: 000389eba000 CR4: 06e0
> >   Call Trace:
> >iwl_dbg_tlv_alloc+0x79/0x120 [iwlwifi]
> >iwl_parse_tlv_firmware.isra.0+0x57d/0x1550 [iwlwifi]
> >iwl_req_fw_callback+0x3f8/0x6a0 [iwlwifi]
> >request_firmware_work_func+0x47/0x90
> >process_one_work+0x1e3/0x3b0
> >worker_thread+0x46/0x340
> >kthread+0x115/0x140
> >ret_from_fork+0x1f/0x40
> > 
> > As can be seen, write bit is not set in the PTE. Read of
> > trig->occurrences succeeds in iwl_dbg_tlv_alloc_trigger, but
> > trig->occurrences = cpu_to_le32(-1); fails there, obviously.
> > 
> > This is likely because we (at SUSE) use compressed firmware and that is
> > marked as RO after decompression (see fw_map_paged_buf).
> > 
> > Fix it by creating a temporary buffer in case we need to change the
> > memory.
> > 
> > Signed-off-by: Jiri Slaby 
> > Reported-by: Dieter Nützel 
> > Tested-by: Dieter Nützel 
> > Cc: Johannes Berg 
> > Cc: Emmanuel Grumbach 
> > Cc: Luca Coelho 
> > Cc: Intel Linux Wireless 
> > Cc: Kalle Valo 
> > Cc: "David S. Miller" 
> > Cc: Jakub Kicinski 
> > Cc: linux-wirel...@vger.kernel.org
> > Cc: net...@vger.kernel.org
> > ---
> >  drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 16 ++--
> 
> The prefix should be "iwlwifi: ", I can fix that.
> 
> Luca, should I take this to wireless-drivers?

Yeah, this looks good.  Thanks, Jiri!

And yes, Kalle, please apply it directly to w-d.  Thank you!

--
Cheers,
Luca.



Re: [PATCH] iwl: fix crash in iwl_dbg_tlv_alloc_trigger

2020-06-12 Thread Kalle Valo
Jiri Slaby  writes:

> The tlv passed to iwl_dbg_tlv_alloc_trigger comes from a loaded firmware
> file. The memory can be marked as read-only as firmware could be
> shared. In anyway, writing to this memory is not expected. So,
> iwl_dbg_tlv_alloc_trigger can crash now:
>
>   BUG: unable to handle page fault for address: ae2c01bfa794
>   PF: supervisor write access in kernel mode
>   PF: error_code(0x0003) - permissions violation
>   PGD 107d51067 P4D 107d51067 PUD 107d52067 PMD 659ad2067 PTE 800662298161
>   CPU: 2 PID: 161 Comm: kworker/2:1 Not tainted 5.7.0-3.gad96a07-default #1 
> openSUSE Tumbleweed (unreleased)
>   RIP: 0010:iwl_dbg_tlv_alloc_trigger+0x25/0x60 [iwlwifi]
>   Code: eb f2 0f 1f 00 66 66 66 66 90 83 7e 04 33 48 89 f8 44 8b 46 10 48 89 
> f7 76 40 41 8d 50 ff 83 fa 19 77 23 8b 56 20 85 d2 75 07  46 20 ff ff ff 
> ff 4b 8d 14 40 48 c1 e2 04 48 8d b4 10 00 05 00
>   RSP: 0018:ae2c00417ce8 EFLAGS: 00010246
>   RAX: 8f0522334018 RBX: 8f0522334018 RCX: c0fc26c0
>   RDX:  RSI: ae2c01bfa774 RDI: ae2c01bfa774
>   RBP:  R08: 0004 R09: 0001
>   R10: 0034 R11: ae2c01bfa77c R12: 8f0522334230
>   R13: 0109 R14: 8f0523fdbc00 R15: 8f051f395800
>   FS:  () GS:8f0527c8() knlGS:
>   CS:  0010 DS:  ES:  CR0: 80050033
>   CR2: ae2c01bfa794 CR3: 000389eba000 CR4: 06e0
>   Call Trace:
>iwl_dbg_tlv_alloc+0x79/0x120 [iwlwifi]
>iwl_parse_tlv_firmware.isra.0+0x57d/0x1550 [iwlwifi]
>iwl_req_fw_callback+0x3f8/0x6a0 [iwlwifi]
>request_firmware_work_func+0x47/0x90
>process_one_work+0x1e3/0x3b0
>worker_thread+0x46/0x340
>kthread+0x115/0x140
>ret_from_fork+0x1f/0x40
>
> As can be seen, write bit is not set in the PTE. Read of
> trig->occurrences succeeds in iwl_dbg_tlv_alloc_trigger, but
> trig->occurrences = cpu_to_le32(-1); fails there, obviously.
>
> This is likely because we (at SUSE) use compressed firmware and that is
> marked as RO after decompression (see fw_map_paged_buf).
>
> Fix it by creating a temporary buffer in case we need to change the
> memory.
>
> Signed-off-by: Jiri Slaby 
> Reported-by: Dieter Nützel 
> Tested-by: Dieter Nützel 
> Cc: Johannes Berg 
> Cc: Emmanuel Grumbach 
> Cc: Luca Coelho 
> Cc: Intel Linux Wireless 
> Cc: Kalle Valo 
> Cc: "David S. Miller" 
> Cc: Jakub Kicinski 
> Cc: linux-wirel...@vger.kernel.org
> Cc: net...@vger.kernel.org
> ---
>  drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 16 ++--

The prefix should be "iwlwifi: ", I can fix that.

Luca, should I take this to wireless-drivers?

-- 
https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


[PATCH] iwl: fix crash in iwl_dbg_tlv_alloc_trigger

2020-06-12 Thread Jiri Slaby
The tlv passed to iwl_dbg_tlv_alloc_trigger comes from a loaded firmware
file. The memory can be marked as read-only as firmware could be
shared. In anyway, writing to this memory is not expected. So,
iwl_dbg_tlv_alloc_trigger can crash now:

  BUG: unable to handle page fault for address: ae2c01bfa794
  PF: supervisor write access in kernel mode
  PF: error_code(0x0003) - permissions violation
  PGD 107d51067 P4D 107d51067 PUD 107d52067 PMD 659ad2067 PTE 800662298161
  CPU: 2 PID: 161 Comm: kworker/2:1 Not tainted 5.7.0-3.gad96a07-default #1 
openSUSE Tumbleweed (unreleased)
  RIP: 0010:iwl_dbg_tlv_alloc_trigger+0x25/0x60 [iwlwifi]
  Code: eb f2 0f 1f 00 66 66 66 66 90 83 7e 04 33 48 89 f8 44 8b 46 10 48 89 f7 
76 40 41 8d 50 ff 83 fa 19 77 23 8b 56 20 85 d2 75 07  46 20 ff ff ff ff 4b 
8d 14 40 48 c1 e2 04 48 8d b4 10 00 05 00
  RSP: 0018:ae2c00417ce8 EFLAGS: 00010246
  RAX: 8f0522334018 RBX: 8f0522334018 RCX: c0fc26c0
  RDX:  RSI: ae2c01bfa774 RDI: ae2c01bfa774
  RBP:  R08: 0004 R09: 0001
  R10: 0034 R11: ae2c01bfa77c R12: 8f0522334230
  R13: 0109 R14: 8f0523fdbc00 R15: 8f051f395800
  FS:  () GS:8f0527c8() knlGS:
  CS:  0010 DS:  ES:  CR0: 80050033
  CR2: ae2c01bfa794 CR3: 000389eba000 CR4: 06e0
  Call Trace:
   iwl_dbg_tlv_alloc+0x79/0x120 [iwlwifi]
   iwl_parse_tlv_firmware.isra.0+0x57d/0x1550 [iwlwifi]
   iwl_req_fw_callback+0x3f8/0x6a0 [iwlwifi]
   request_firmware_work_func+0x47/0x90
   process_one_work+0x1e3/0x3b0
   worker_thread+0x46/0x340
   kthread+0x115/0x140
   ret_from_fork+0x1f/0x40

As can be seen, write bit is not set in the PTE. Read of
trig->occurrences succeeds in iwl_dbg_tlv_alloc_trigger, but
trig->occurrences = cpu_to_le32(-1); fails there, obviously.

This is likely because we (at SUSE) use compressed firmware and that is
marked as RO after decompression (see fw_map_paged_buf).

Fix it by creating a temporary buffer in case we need to change the
memory.

Signed-off-by: Jiri Slaby 
Reported-by: Dieter Nützel 
Tested-by: Dieter Nützel 
Cc: Johannes Berg 
Cc: Emmanuel Grumbach 
Cc: Luca Coelho 
Cc: Intel Linux Wireless 
Cc: Kalle Valo 
Cc: "David S. Miller" 
Cc: Jakub Kicinski 
Cc: linux-wirel...@vger.kernel.org
Cc: net...@vger.kernel.org
---
 drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c | 16 ++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c 
b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
index 7987a288917b..27116c7d3f4f 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c
@@ -271,6 +271,8 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans 
*trans,
 {
struct iwl_fw_ini_trigger_tlv *trig = (void *)tlv->data;
u32 tp = le32_to_cpu(trig->time_point);
+   struct iwl_ucode_tlv *dup = NULL;
+   int ret;
 
if (le32_to_cpu(tlv->length) < sizeof(*trig))
return -EINVAL;
@@ -283,10 +285,20 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans 
*trans,
return -EINVAL;
}
 
-   if (!le32_to_cpu(trig->occurrences))
+   if (!le32_to_cpu(trig->occurrences)) {
+   dup = kmemdup(tlv, sizeof(*tlv) + le32_to_cpu(tlv->length),
+   GFP_KERNEL);
+   if (!dup)
+   return -ENOMEM;
+   trig = (void *)dup->data;
trig->occurrences = cpu_to_le32(-1);
+   tlv = dup;
+   }
+
+   ret = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list);
+   kfree(dup);
 
-   return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list);
+   return ret;
 }
 
 static int (*dbg_tlv_alloc[])(struct iwl_trans *trans,
-- 
2.27.0