2011-06-17 22:31:36

by Rafał Miłecki

[permalink] [raw]
Subject: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

I use attached patch to fake result of read[bwl] performed by closed
source driver (ndiswrapper+bcmwl and wl).

1) It works great on my Sony VAIO with Intel(R) Core(TM)2 Duo CPU P8400
2) It locks up Macbook Pro 8,1 with some 8-cores Intel

Do you have any idea why it causes the lockup? Function causing
problem is "set_ins_reg_val". I've created it as copy of
get_ins_reg_val, it just sets values in struct pt_regs, instead of
reading them).

--
Rafał


Attachments:
mmio.debugging.patch (3.85 kB)

2011-06-18 10:40:14

by Pekka Paalanen

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

On Sat, 18 Jun 2011 00:31:32 +0200
Rafał Miłecki <[email protected]> wrote:

> I use attached patch to fake result of read[bwl] performed by
> closed source driver (ndiswrapper+bcmwl and wl).
>
> 1) It works great on my Sony VAIO with Intel(R) Core(TM)2 Duo CPU
> P8400 2) It locks up Macbook Pro 8,1 with some 8-cores Intel
>
> Do you have any idea why it causes the lockup? Function causing
> problem is "set_ins_reg_val". I've created it as copy of
> get_ins_reg_val, it just sets values in struct pt_regs, instead of
> reading them).

Sorry, I have no insight to that... does unmodified mmiotrace
work properly? Are you tracing the exact same kernel binary blob
on both machines? Maybe it's using some rare instruction
mmiotrace does not decode properly? Maybe with a rep prefix?
Do those CPUs have any differences in their registers or
struct pt_regs?

I'm not even sure how "legal" it is to poke pt_regs there. :-/


Good luck.

--
Pekka Paalanen
http://www.iki.fi/pq/

2011-06-18 11:03:01

by Rafał Miłecki

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

W dniu 18 czerwca 2011 12:39 użytkownik Pekka Paalanen <[email protected]> napisał:
> On Sat, 18 Jun 2011 00:31:32 +0200
> Rafał Miłecki <[email protected]> wrote:
>
>> I use attached patch to fake result of read[bwl] performed by
>> closed source driver (ndiswrapper+bcmwl and wl).
>>
>> 1) It works great on my Sony VAIO with Intel(R) Core(TM)2 Duo CPU
>> P8400 2) It locks up Macbook Pro 8,1 with some 8-cores Intel
>>
>> Do you have any idea why it causes the lockup? Function causing
>> problem is "set_ins_reg_val". I've created it as copy of
>> get_ins_reg_val, it just sets values in struct pt_regs, instead of
>> reading them).
>
> Sorry, I have no insight to that... does unmodified mmiotrace
> work properly? Are you tracing the exact same kernel binary blob
> on both machines? Maybe it's using some rare instruction
> mmiotrace does not decode properly? Maybe with a rep prefix?
> Do those CPUs have any differences in their registers or
> struct pt_regs?
>
> I'm not even sure how "legal" it is to poke pt_regs there. :-/

Not modified MMIO tracing works great on this machine, I've grabbed
dumps 10-20 times without a lock up or anything.

I'm using different drivers on both machines, because Macbook Pro 8,1
has unique BCM4331 card that I can not buy and that is not available
with PCI(e) slot. Is uses some vendor specific, PCIe compatible slot.
Simple commenting out "set_ins_reg_val" work fine on this Macbook, PHY
reads are tracked correctly.

As for differences in struct pt_regs... yeah, I think that happens.
I'm using x86 kernel, while on Macbook we use x86_64 as it's required
to use 64bit driver in ndiswrapper.

I can try to find out, which register we try to overwrite on Macbook.

--
Rafał

2011-06-18 11:26:18

by Rafał Miłecki

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

W dniu 18 czerwca 2011 12:57 użytkownik Rafał Miłecki
<[email protected]> napisał:
> W dniu 18 czerwca 2011 12:39 użytkownik Pekka Paalanen <[email protected]> napisał:
>> On Sat, 18 Jun 2011 00:31:32 +0200
>> Rafał Miłecki <[email protected]> wrote:
>>
>>> I use attached patch to fake result of read[bwl] performed by
>>> closed source driver (ndiswrapper+bcmwl and wl).
>>>
>>> 1) It works great on my Sony VAIO with Intel(R) Core(TM)2 Duo CPU
>>> P8400 2) It locks up Macbook Pro 8,1 with some 8-cores Intel
>>>
>>> Do you have any idea why it causes the lockup? Function causing
>>> problem is "set_ins_reg_val". I've created it as copy of
>>> get_ins_reg_val, it just sets values in struct pt_regs, instead of
>>> reading them).
>>
>> Sorry, I have no insight to that... does unmodified mmiotrace
>> work properly? Are you tracing the exact same kernel binary blob
>> on both machines? Maybe it's using some rare instruction
>> mmiotrace does not decode properly? Maybe with a rep prefix?
>> Do those CPUs have any differences in their registers or
>> struct pt_regs?
>>
>> I'm not even sure how "legal" it is to poke pt_regs there. :-/
>
> Not modified MMIO tracing works great on this machine, I've grabbed
> dumps 10-20 times without a lock up or anything.
>
> I'm using different drivers on both machines, because Macbook Pro 8,1
> has unique BCM4331 card that I can not buy and that is not available
> with PCI(e) slot. Is uses some vendor specific, PCIe compatible slot.
> Simple commenting out "set_ins_reg_val" work fine on this Macbook, PHY
> reads are tracked correctly.
>
> As for differences in struct pt_regs... yeah, I think that happens.
> I'm using x86 kernel, while on Macbook we use x86_64 as it's required
> to use 64bit driver in ndiswrapper.
>
> I can try to find out, which register we try to overwrite on Macbook.

This is what does happen on my machine (working):
[ 122.550991] mmiotrace: ZAJEC: read PHY 0x20
[ 122.550994] mmiotrace: ZAJEC: overwriting 0x20 with 0xFFFF
[ 122.550997] [ZAJEC] setting AX with 0xFFFF
(...)
[ 122.551071] mmiotrace: ZAJEC: read PHY 0x22
[ 122.551074] mmiotrace: ZAJEC: overwriting 0x22 with 0xFFFF
[ 122.551077] [ZAJEC] setting AX with 0xFFFF
(...)
[ 122.551198] mmiotrace: ZAJEC: read PHY 0x27
[ 122.551201] mmiotrace: ZAJEC: overwriting 0x27 with 0xFFFF
[ 122.551204] [ZAJEC] setting AX with 0xFFFF


This is what does happen on Macbook:
[ 166.886438] mmiotrace: ZAJEC: read PHY 0x810
[ 166.886649] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
[ 166.886860] [ZAJEC] setting AX with 0xFFFF
LOCK UP


So on both machines we modify AX register in the same place. My
function set_ins_reg_val is a copy of get_ins_reg_val which works
fine... So no idea what may we be doing wrong on this Macbook
x86_64...


P.S.
You can see I've changed 0x20, 0x22, 0x27 to 0x810 on Macbook. That's
because first 3 registers are not used by BCM4331. I've been testing
them with BCM43225.

--
Rafał

2011-06-18 12:04:07

by Pekka Paalanen

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

On Sat, 18 Jun 2011 13:26:14 +0200
Rafał Miłecki <[email protected]> wrote:

> W dniu 18 czerwca 2011 12:57 użytkownik Rafał Miłecki
> <[email protected]> napisał:
> > Not modified MMIO tracing works great on this machine, I've
> > grabbed dumps 10-20 times without a lock up or anything.
> >
> > I'm using different drivers on both machines, because Macbook
> > Pro 8,1 has unique BCM4331 card that I can not buy and that is
> > not available with PCI(e) slot. Is uses some vendor specific,
> > PCIe compatible slot. Simple commenting out "set_ins_reg_val"
> > work fine on this Macbook, PHY reads are tracked correctly.
> >
> > As for differences in struct pt_regs... yeah, I think that
> > happens. I'm using x86 kernel, while on Macbook we use x86_64
> > as it's required to use 64bit driver in ndiswrapper.
> >
> > I can try to find out, which register we try to overwrite on
> > Macbook.
>
> This is what does happen on my machine (working):
> [ 122.550991] mmiotrace: ZAJEC: read PHY 0x20
> [ 122.550994] mmiotrace: ZAJEC: overwriting 0x20 with 0xFFFF
> [ 122.550997] [ZAJEC] setting AX with 0xFFFF
> (...)
> [ 122.551071] mmiotrace: ZAJEC: read PHY 0x22
> [ 122.551074] mmiotrace: ZAJEC: overwriting 0x22 with 0xFFFF
> [ 122.551077] [ZAJEC] setting AX with 0xFFFF
> (...)
> [ 122.551198] mmiotrace: ZAJEC: read PHY 0x27
> [ 122.551201] mmiotrace: ZAJEC: overwriting 0x27 with 0xFFFF
> [ 122.551204] [ZAJEC] setting AX with 0xFFFF
>
>
> This is what does happen on Macbook:
> [ 166.886438] mmiotrace: ZAJEC: read PHY 0x810
> [ 166.886649] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
> [ 166.886860] [ZAJEC] setting AX with 0xFFFF
> LOCK UP
>
>
> So on both machines we modify AX register in the same place. My
> function set_ins_reg_val is a copy of get_ins_reg_val which works
> fine... So no idea what may we be doing wrong on this Macbook
> x86_64...

Ok, so it is a 32 vs. 64 bit arch difference, or difference in
driver binary. AX on 64-bit is actually RAX... well, depending
on data width.

I actually missed you patch attachment before, sorry.

I have minor notes, but I cannot see them being a reason for a
lockup:

- instead of set_reg_w32(), you should be able to simply
*get_reg_w32() = (unsigned long)value; or equivalent since
it returns a pointer.

- you are not checking the data access width, but you assume
it is 32 bits. Maybe you should verify that? get_reg_w8() is
very different. I think you should reproduce the switch on
get_ins_reg_width() statement from get_ins_reg_val() in
your set_ins_reg_val(), and use unsigned long instead of u32
to account for 64-bitness.

Yes, get_reg_w32() is a little badly named.

Maybe the driver is doing a 16-bit wide access, and happens to
store something else in the other 16/48 bits of RAX?

I assume the lockup is silent, since you have not shown
anything. Have you tried a serial console, if you have one?


HTH.

--
Pekka Paalanen
http://www.iki.fi/pq/

2011-06-18 13:11:28

by Rafał Miłecki

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

W dniu 18 czerwca 2011 14:03 użytkownik Pekka Paalanen <[email protected]> napisał:
> On Sat, 18 Jun 2011 13:26:14 +0200
> Rafał Miłecki <[email protected]> wrote:
>
>> W dniu 18 czerwca 2011 12:57 użytkownik Rafał Miłecki
>> <[email protected]> napisał:
>> > Not modified MMIO tracing works great on this machine, I've
>> > grabbed dumps 10-20 times without a lock up or anything.
>> >
>> > I'm using different drivers on both machines, because Macbook
>> > Pro 8,1 has unique BCM4331 card that I can not buy and that is
>> > not available with PCI(e) slot. Is uses some vendor specific,
>> > PCIe compatible slot. Simple commenting out "set_ins_reg_val"
>> > work fine on this Macbook, PHY reads are tracked correctly.
>> >
>> > As for differences in struct pt_regs... yeah, I think that
>> > happens. I'm using x86 kernel, while on Macbook we use x86_64
>> > as it's required to use 64bit driver in ndiswrapper.
>> >
>> > I can try to find out, which register we try to overwrite on
>> > Macbook.
>>
>> This is what does happen on my machine (working):
>> [  122.550991] mmiotrace: ZAJEC: read PHY 0x20
>> [  122.550994] mmiotrace: ZAJEC: overwriting 0x20 with 0xFFFF
>> [  122.550997] [ZAJEC] setting AX with 0xFFFF
>> (...)
>> [  122.551071] mmiotrace: ZAJEC: read PHY 0x22
>> [  122.551074] mmiotrace: ZAJEC: overwriting 0x22 with 0xFFFF
>> [  122.551077] [ZAJEC] setting AX with 0xFFFF
>> (...)
>> [  122.551198] mmiotrace: ZAJEC: read PHY 0x27
>> [  122.551201] mmiotrace: ZAJEC: overwriting 0x27 with 0xFFFF
>> [  122.551204] [ZAJEC] setting AX with 0xFFFF
>>
>>
>> This is what does happen on Macbook:
>> [  166.886438] mmiotrace: ZAJEC: read PHY 0x810
>> [  166.886649] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
>> [  166.886860] [ZAJEC] setting AX with 0xFFFF
>> LOCK UP
>>
>>
>> So on both machines we modify AX register in the same place. My
>> function set_ins_reg_val is a copy of get_ins_reg_val which works
>> fine... So no idea what may we be doing wrong on this Macbook
>> x86_64...
>
> Ok, so it is a 32 vs. 64 bit arch difference, or difference in
> driver binary. AX on 64-bit is actually RAX... well, depending
> on data width.
>
> I actually missed you patch attachment before, sorry.
>
> I have minor notes, but I cannot see them being a reason for a
> lockup:

Thanks for answer!


> - instead of set_reg_w32(), you should be able to simply
> *get_reg_w32() = (unsigned long)value; or equivalent since
> it returns a pointer.

Agree.


> - you are not checking the data access width, but you assume
> it is 32 bits. Maybe you should verify that? get_reg_w8() is
> very different. I think you should reproduce the switch on
> get_ins_reg_width() statement from get_ins_reg_val() in
> your set_ins_reg_val(), and use unsigned long instead of u32
> to account for 64-bitness.
>
> Yes, get_reg_w32() is a little badly named.
>
> Maybe the driver is doing a 16-bit wide access, and happens to
> store something else in the other 16/48 bits of RAX?

Nice comment, thanks! I've decided to print info about planned
overwrite, instead of really doing it. Plus few more debugging
messages suggested by David:
[ 293.682242] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
[ 293.687929] mmiotrace: [ZAJEC] ins at ffffc90010503b60: 0f b7 81 fe 03 00
[ 293.693651] mmiotrace: [ZAJEC] p = (unsigned char *)ins_addr;
p == 0xf
[ 293.699379] mmiotrace: [ZAJEC] p += skip_prefix(p, &prf);
p == 0xf
[ 293.705116] mmiotrace: [ZAJEC] p += get_opcode(p, &opcode);
p == 0x81
[ 293.710815] mmiotrace: [ZAJEC] opcode is 0xb70f
[ 293.716411] mmiotrace: [ZAJEC] prf info: shorted:0; enlarged:0, rexr:0, rex:0
[ 293.722062] mmiotrace: [ZAJEC] after checing opcode we decided to use reg 0x0
[ 293.727698] mmiotrace: [ZAJEC] width is 4
[ 293.733219] [ZAJEC] (not) setting AX with 0xFFFF

So the read's width is 4, that's 32bit. If this is 64bit arch we could
be overwritting another 32bits in AX register, right? Can this be our
issue?


> I assume the lockup is silent, since you have not shown
> anything. Have you tried a serial console, if you have one?

I think David has some USB debugging (what ever it means...). Using
console mode just printed commands done right before overwritting
register.

--
Rafał

2011-06-18 14:43:36

by Rafał Miłecki

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

W dniu 18 czerwca 2011 14:03 użytkownik Pekka Paalanen <[email protected]> napisał:
> Maybe the driver is doing a 16-bit wide access, and happens to
> store something else in the other 16/48 bits of RAX?

OK, attached is updated version of my patch. I think we can get some
clue from dmesgs with this patch applied.


My system (working):
[ 74.472502] mmiotrace: ZAJEC: overwriting 0x27 with 0xFFFF
[ 74.472511] mmiotrace: [ZAJEC] opcode is 0x8B
[ 74.472515] mmiotrace: [ZAJEC] prf info: shorted:1; enlarged:0, rexr:0, rex:0
[ 74.472517] mmiotrace: [ZAJEC] register is 0x0
[ 74.472520] mmiotrace: [ZAJEC] overwritting 2-byte value 0x0514 with 0xFFFF
[ 74.472523] mmiotrace: [ZAJEC] overwritting resulted in 0xFFFF

[ 74.487081] mmiotrace: ZAJEC: overwriting 0x20 with 0xFFFF
[ 74.487086] mmiotrace: [ZAJEC] opcode is 0x8B
[ 74.487089] mmiotrace: [ZAJEC] prf info: shorted:1; enlarged:0, rexr:0, rex:0
[ 74.487092] mmiotrace: [ZAJEC] register is 0x0
[ 74.487095] mmiotrace: [ZAJEC] overwritting 2-byte value 0x427E with 0xFFFF
[ 74.487097] mmiotrace: [ZAJEC] overwritting resulted in 0xFFFF


MacBook (with real overwritting commenet out!):
[ 228.248715] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
[ 228.254227] mmiotrace: [ZAJEC] opcode is 0xB70F
[ 228.259784] mmiotrace: [ZAJEC] prf info: shorted:0; enlarged:0, rexr:0, rex:0
[ 228.265399] mmiotrace: [ZAJEC] register is 0x0
[ 228.270955] mmiotrace: [ZAJEC] overwritting 4-byte value 0x00000000
with 0xFFFF
[ 228.276597] mmiotrace: [ZAJEC] overwritting resulted in 0x00000000

[ 228.284284] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
[ 228.289818] mmiotrace: [ZAJEC] opcode is 0xB70F
[ 228.295250] mmiotrace: [ZAJEC] prf info: shorted:0; enlarged:0, rexr:0, rex:0
[ 228.300838] mmiotrace: [ZAJEC] register is 0x0
[ 228.306339] mmiotrace: [ZAJEC] overwritting 4-byte value 0x00000000
with 0xFFFF
[ 228.311905] mmiotrace: [ZAJEC] overwritting resulted in 0x00000000


It's 2-byte vs. 4-byte. I suspect this can be the source of our
problem. Writing u16 0xFFFF value as u32 write.

--
Rafał


Attachments:
mmio.debugging.patch (4.34 kB)

2011-06-18 20:52:10

by Rafał Miłecki

[permalink] [raw]
Subject: Re: Lock up when faking MMIO read[bwl] on some machines [WAS: Faking MMIO ops? Fooling a driver]

W dniu 18 czerwca 2011 16:43 użytkownik Rafał Miłecki
<[email protected]> napisał:
> W dniu 18 czerwca 2011 14:03 użytkownik Pekka Paalanen <[email protected]> napisał:
>> Maybe the driver is doing a 16-bit wide access, and happens to
>> store something else in the other 16/48 bits of RAX?
>
> OK, attached is updated version of my patch. I think we can get some
> clue from dmesgs with this patch applied.
>
>
> My system (working):
> [   74.472502] mmiotrace: ZAJEC: overwriting 0x27 with 0xFFFF
> [   74.472511] mmiotrace: [ZAJEC] opcode is 0x8B
> [   74.472515] mmiotrace: [ZAJEC] prf info: shorted:1; enlarged:0, rexr:0, rex:0
> [   74.472517] mmiotrace: [ZAJEC] register is 0x0
> [   74.472520] mmiotrace: [ZAJEC] overwritting 2-byte value 0x0514 with 0xFFFF
> [   74.472523] mmiotrace: [ZAJEC] overwritting resulted in 0xFFFF
>
> [   74.487081] mmiotrace: ZAJEC: overwriting 0x20 with 0xFFFF
> [   74.487086] mmiotrace: [ZAJEC] opcode is 0x8B
> [   74.487089] mmiotrace: [ZAJEC] prf info: shorted:1; enlarged:0, rexr:0, rex:0
> [   74.487092] mmiotrace: [ZAJEC] register is 0x0
> [   74.487095] mmiotrace: [ZAJEC] overwritting 2-byte value 0x427E with 0xFFFF
> [   74.487097] mmiotrace: [ZAJEC] overwritting resulted in 0xFFFF
>
>
> MacBook (with real overwritting commenet out!):
> [  228.248715] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
> [  228.254227] mmiotrace: [ZAJEC] opcode is 0xB70F
> [  228.259784] mmiotrace: [ZAJEC] prf info: shorted:0; enlarged:0, rexr:0, rex:0
> [  228.265399] mmiotrace: [ZAJEC] register is 0x0
> [  228.270955] mmiotrace: [ZAJEC] overwritting 4-byte value 0x00000000
> with 0xFFFF
> [  228.276597] mmiotrace: [ZAJEC] overwritting resulted in 0x00000000
>
> [  228.284284] mmiotrace: ZAJEC: overwriting 0x810 with 0xFFFF
> [  228.289818] mmiotrace: [ZAJEC] opcode is 0xB70F
> [  228.295250] mmiotrace: [ZAJEC] prf info: shorted:0; enlarged:0, rexr:0, rex:0
> [  228.300838] mmiotrace: [ZAJEC] register is 0x0
> [  228.306339] mmiotrace: [ZAJEC] overwritting 4-byte value 0x00000000
> with 0xFFFF
> [  228.311905] mmiotrace: [ZAJEC] overwritting resulted in 0x00000000
>
>
> It's 2-byte vs. 4-byte. I suspect this can be the source of our
> problem. Writing u16 0xFFFF value as u32 write.

Ohh, that was so stupid...

Writing 0xFFFF to PHY register 0x810 causes lockup on BCM4331! That's
all! My code is working fine, just some bits in 0xFFFF value are
really not friendly for the hardware.

--
Rafał