Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ The most up to date release can be found [here](https://github.com/notmarek/Lang
5. Type `;demo` into the Kindle search bar, then press enter to access the Demo Mode Configuration screen.
6. Select the `Sideload Content` option.
7. Connect your Kindle to a PC, then copy the contents of the `LanguageBreak` folder from the [latest release's *.tar.gz file](https://github.com/notmarek/LanguageBreak/releases) to the Kindle's root directory (if prompted, overrwrite the existing files).
- ⚠️ **Do not copy with a graphical file manager.** `.demo` is a *hidden* folder that Finder/Explorer will silently leave behind, and one payload file's *filename* is the exploit itself (it contains `;`, `$`, `(`, `)`, quotes and spaces) and must land byte-identical. Both failures are silent — the jailbreak simply does nothing. Use `rsync`/`cp` from a terminal, or [`troubleshooting/copy-payload.sh`](troubleshooting/copy-payload.sh), which copies and then verifies.
8. Eject, then *unplug your Kindle*, then return to the Demo Configuration Screen (using the method in step 5, if required).
9. Select `Resell Device`, then confirm.
10. As soon as the "Press the Power Button" screen appears, plug your Kindle back into your computer. (This is time sensitive, be quick.)
Expand All @@ -46,10 +47,29 @@ The most up to date release can be found [here](https://github.com/notmarek/Lang
3. Eject your Kindle, then `;dsts` into the Kindle search bar to access the settings page. Locate the `Update your Kindle` option and press it, then confirm.
- Using your phone to translate the menus is helpful if you don't happen to be able to read Chinese.
- If you see an infoscreen that states "Update Error" or similar then try to apply the hotfix again (last three steps)
- **On PW3 the hotfix commonly has to be applied twice.** The first pass can leave the device looking fine (`;log` works, KUAL opens) while actually being broken: no `mkk` folder, permission errors on the rootfs, and KUAL apps that launch and silently die. If `mkk` is missing, apply the hotfix again — you do **not** need to re-enter demo mode, just copy the `.bin` and update. See [#48](https://github.com/notmarek/LanguageBreak/issues/48).

This will reboot the device out of Demo mode. Your device may go into Managed mode after completing these steps. Managed devices have some settings greyed out, and ask the user to contact their system administrator. See below for steps on how to restore functionality (and the correct language) to your device.

## Restoring the Correct Language and Exiting Managed Mode

> **If the `;` commands below do nothing**, the command channel itself is broken
> and neither procedure can work — `;demo`, `;uzb` and `;enter_demo` all fall
> through to an ordinary library search. This is the state reported in
> [#67](https://github.com/notmarek/LanguageBreak/issues/67),
> [#58](https://github.com/notmarek/LanguageBreak/issues/58) and
> [#52](https://github.com/notmarek/LanguageBreak/issues/52), usually alongside
> greyed-out Settings and USB that never mounts.
>
> Two things that recover it:
>
> - **A 40-second power-hold with the cable UNPLUGGED** often restores demo mode
> and the `;` channel. Holding it while connected only powers the device off.
> - **[`troubleshooting/fix-managed-mode.sh`](troubleshooting/fix-managed-mode.sh)**
> resets `/var/local` from root, which is what a factory reset does internally
> — `/opt/var/local` is a read-only squashfs holding the pristine copy. This
> works with Settings locked. **The jailbreak survives**, because
> `bridge.conf` restores `/var/local/mkk` from `/mnt/us/mkk`.

### If your kindle **is not** registered to an Amazon account:
1. Type `;demo` into the Kindle search bar.
Expand All @@ -73,9 +93,12 @@ A: Not a question.. but checkout issue [#48](https://github.com/notmarek/Languag
Q: How do I verify my installation?

A: (before applying hotfix): Install hotfix, if you can do that then it worked.
**Note that `;log` does NOT work yet at this stage** — before the hotfix it falls through to an ordinary library search, and that is *expected*. It is not a sign of failure, and several issues in this tracker are people concluding otherwise.

A: (after applying hotfix): Type `;log` into the Kindle search bar, some text should appear at the top right side of the screen.

A: (either stage, no shell needed): run [`troubleshooting/verify-jailbreak.sh`](troubleshooting/verify-jailbreak.sh). It checks the artefacts the exploit itself writes — `LanguageBreakRan`, `languagebreak_log` ending in `Finished installing jailbreak!`, and whether `mkk` exists — and writes the result to `/mnt/us/verify-jailbreak.txt`, readable over USB.

Q: Where are the hotfix files?

A: The structure of the tarball is as follows
Expand All @@ -94,6 +117,47 @@ LanguageBreak.tar.gz
|-- Update_hotfix_languagebreak-*.bin
```

# Recovering a device you cannot reach

If the `;` commands are dead, Settings is locked and USB will not mount, it can
look like there is no way back in. There is, and it is built into the jailbreak:

```sh
BRIDGE_EMERGENCY="/mnt/us/emergency.sh"
if [ -f "${BRIDGE_EMERGENCY}" ] ; then
[ -x "${BRIDGE_EMERGENCY}" ] || chmod +x "${BRIDGE_EMERGENCY}"
/bin/sh "${BRIDGE_EMERGENCY}"
fi
```

**Any script placed at `/mnt/us/emergency.sh` runs as root at boot** (see
`mkk/bridge.conf`). No KUAL, no MRPI, no USBNetwork. Copy a script there over
USB, reboot, and it runs.

That is the intended route for the scripts here that need a boot-time root
shell — but it is not a universal one, and in particular it cannot work for
`fix-usb-disabled.sh`, whose symptom is that USB never mounts. See the
`HOW TO RUN IT` header in that script for the routes that do apply to it.

Two rules if you write your own:

1. **Rename the script before doing anything destructive.** If it dies partway,
`/mnt/us` (a `fuse.fsp` mount) can go with it, leaving the file in place to
re-run on every boot — a permanent boot loop that is worse than the original
problem.
2. **Call `/var/local/mkk/bridge.sh` at the end** if you are not rebooting, as
the emergency path makes the bridge skip its own setup.

### USB never mounts after demo mode

The host sees the device on the USB bus but no volume ever appears, which looks
exactly like a bad cable. `disableUSBInDemo.sh` creates
`/var/local/system/no_transitions`, and Amazon's own `enableUSBInDemo.sh` only
removes it *if `DEMO_MODE` still exists* — so once the demo flag is cleared the
blocker is stranded permanently.
[`troubleshooting/fix-usb-disabled.sh`](troubleshooting/fix-usb-disabled.sh)
removes it.

# Troubleshooting
Having general issues?

Expand Down
69 changes: 69 additions & 0 deletions troubleshooting/copy-payload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/bin/sh
# copy-payload.sh — copy the LanguageBreak payload to the Kindle correctly.
#
# ADDRESSES: silent jailbreak failures caused by copying with a GUI file
# manager. The README says "copy the contents of the LanguageBreak folder",
# which is easy to do wrongly in two ways that produce no error:
#
# 1. .demo/ is a HIDDEN directory. macOS Finder does not show it and a
# drag-copy leaves it behind entirely.
# 2. One payload file's NAME is the exploit itself:
# a; export SLASH=$(awk 'BEGIN {print substr(ARGV[1], 0, 1)}' ${PWD}); sh ${SLASH}mnt${SLASH}us${SLASH}jb
# containing ; $ ( ) { } quotes and spaces, and it must land byte-identical
# on FAT32.
#
# Also sweeps macOS AppleDouble "._" sidecars, which otherwise litter the
# Kindle root.
#
# USAGE: ./copy-payload.sh /path/to/extracted/LanguageBreak /Volumes/Kindle
#
# Run this at README step 7 AND again at step 11.

set -eu
SRC="${1:?usage: copy-payload.sh <LanguageBreak dir> <kindle mount>}"
DST="${2:?usage: copy-payload.sh <LanguageBreak dir> <kindle mount>}"

[ -d "$SRC" ] || { echo "no such directory: $SRC"; exit 1; }
[ -d "$DST" ] || { echo "Kindle not mounted at: $DST"; exit 1; }

echo "copying payload -> $DST"
# Trailing slash on SRC copies the CONTENTS, not the folder. This matters.
# COPYFILE_DISABLE stops macOS writing ._ sidecars for extended attributes,
# which FAT32 cannot hold.
COPYFILE_DISABLE=1 rsync -rl "$SRC/" "$DST/"
command -v dot_clean >/dev/null 2>&1 && dot_clean -m "$DST" 2>/dev/null || true
sync

echo
echo "verifying — all five must be present:"
rc=0
for f in .demo documents DONT_CHECK_BATTERY jb patchedUks.sqsh; do
if [ -e "$DST/$f" ]; then echo " OK $f"; else echo " MISSING $f"; rc=1; fi
done

echo
echo "verifying the exploit filename survived verbatim:"
# Compared in full, not grepped for a substring: a name that lost its trailing
# characters, gained a space or had a metacharacter rewritten still contains
# "export SLASH" while being useless as an exploit.
EXPLOIT="a; export SLASH=\$(awk 'BEGIN {print substr(ARGV[1], 0, 1)}' \${PWD}); sh \${SLASH}mnt\${SLASH}us\${SLASH}jb"
if [ -e "$DST/documents/dictionaries/$EXPLOIT" ]; then
echo " OK shell-injection dictionary file present, name byte-identical"
else
echo " MISSING exploit filename did not survive the copy"
echo " expected: $EXPLOIT"
echo " found in documents/dictionaries/:"
ls -1 "$DST/documents/dictionaries/" 2>/dev/null | sed 's/^/ /' || echo " (directory missing)"
rc=1
fi

echo
echo "stray AppleDouble sidecars in root:"
ls -1a "$DST" 2>/dev/null | grep '^\._' || echo " (none - clean)"

if [ "$rc" = 0 ]; then
printf '\nPayload copied correctly. Eject before continuing.\n'
else
printf '\n*** COPY INCOMPLETE - do not continue, the jailbreak will fail silently. ***\n'
fi
exit $rc
82 changes: 82 additions & 0 deletions troubleshooting/fix-managed-mode.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/bin/sh
# fix-managed-mode.sh — escape "managed mode" after a LanguageBreak install.
#
# ADDRESSES: LanguageBreak issue #67 ("stuck in managed mode"), and the same
# symptom reported in #58 and #52. The only answer in #67 today is a bare
# "solved with a factory reset", which is unhelpful when Settings is greyed out
# and the factory-reset option is exactly what you cannot reach.
#
# SYMPTOM
# * Settings greyed out, "contact your administrator"
# * USB mass storage unavailable
# * ;log, ;uzb, ;enter_demo all fall through to a library search
# * so the documented exit (;demo -> Resell Device) is unreachable, because
# the ; command channel is itself what is broken
#
# HOW IT WORKS
# /opt/var/local is a READ-ONLY SQUASHFS holding the pristine factory copy of
# /var/local (visible as a /dev/loop mount in `mount`). The system repopulates
# /var/local from it. Wiping /var/local therefore performs the same reset the
# Settings menu would — and root can do it with Settings locked.
#
# THE JAILBREAK SURVIVES, two independent ways:
# 1. this script skips mkk, rp and linkfonts, and
# 2. /etc/upstart/bridge.conf restores /var/local/mkk from /mnt/us/mkk when it
# is missing — the jailbreak authors built that self-heal in already.
#
# HOW TO RUN IT WITHOUT A SHELL
# You almost certainly cannot ssh in at this point. Use the bridge's root
# hook: copy this file to /mnt/us/emergency.sh and reboot. It runs as root at
# boot. It renames itself when done, so it runs exactly once.
#
# *** WARNING: this wipes device state — registration, settings, caches.
# *** It does NOT touch /mnt/us, so your documents and the jailbreak payload
# *** are untouched. Verified on PW3 / 5.16.2.1.1.

LOG=/mnt/us/fix-managed-mode.log
KEEP="mkk rp linkfonts"

# ---- 1. Disarm FIRST, while /mnt/us is definitely writable. ----
# If this script stops the framework or dies partway, /mnt/us (a fuse.fsp mount)
# can disappear, leaving the file in place to re-run on every boot. That failure
# mode produces a permanent boot loop and is much worse than the bug.
mv /mnt/us/emergency.sh /mnt/us/emergency.sh.done 2>/dev/null
sync

{
echo "===== fix-managed-mode $(date) ====="
id
echo
echo "-- factory template present? (must be a read-only squashfs) --"
mount | grep -i "opt/var/local" || echo " WARNING: /opt/var/local not mounted; reset may not repopulate"
echo
echo "-- /var/local before --"
ls -la /var/local 2>/dev/null
echo
echo "-- jailbreak backup on /mnt/us (used by bridge.conf to self-heal) --"
ls -la /mnt/us/mkk/ 2>/dev/null | head
echo
echo "-- wiping /var/local, keeping: $KEEP --"
} > "$LOG" 2>&1

for entry in /var/local/* /var/local/.[!.]* ; do
[ -e "$entry" ] || continue
base=$(basename "$entry")
skip=0
for k in $KEEP; do [ "$base" = "$k" ] && skip=1; done
[ "$skip" = 1 ] && { echo " keep $base" >> "$LOG"; continue; }
chattr -i "$entry" 2>/dev/null
rm -rf "$entry" 2>/dev/null
echo " remove $base" >> "$LOG"
done
sync

echo "" >> "$LOG"
echo "-- rebooting; /var/local repopulates from /opt/var/local --" >> "$LOG"
sync
sleep 2

# On-screen confirmation if fbink is available (LanguageBreak ships it).
[ -x /mnt/us/libkh/bin/fbink ] && /mnt/us/libkh/bin/fbink -y 2 "managed-mode fix applied, rebooting" 2>/dev/null

reboot
61 changes: 61 additions & 0 deletions troubleshooting/fix-usb-disabled.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/sh
# fix-usb-disabled.sh — restore USB mass storage after demo mode.
#
# ADDRESSES: an undocumented dead end. The host enumerates "Amazon Kindle" on
# the USB bus but NO VOLUME EVER MOUNTS, which looks exactly like a bad cable
# and sends people hunting for hardware faults.
#
# CAUSE: /usr/bin/disableUSBInDemo.sh creates
# /var/local/system/no_transitions, which stops volumd mounting userstore.
# Amazon's own /usr/bin/enableUSBInDemo.sh only removes it IF DEMO_MODE still
# exists:
#
# DEMO_MODE_FILE=/var/local/system/DEMO_MODE
# NO_TRANSITIONS=/var/local/system/no_transitions
# [ -e "$DEMO_MODE_FILE" ] && rm -f "$NO_TRANSITIONS"
#
# So once the demo flag is cleared, the blocker is STRANDED with nothing left
# that will ever remove it. This removes it directly.
#
# DIAGNOSIS on the host: `ioreg -p IOUSB` (macOS) or `lsusb` shows the device
# while `diskutil list external` / `lsblk` shows no volume. That is this bug,
# not a cable.
#
# HOW TO RUN IT — read this first, because it cannot bootstrap itself over
# USB: USB not mounting is the symptom. This is a ROOT-SHELL convenience, not
# a rescue tool. If your `;` commands still work you do not need it at all:
#
# `;enter_demo` puts the device back in demo mode, which means DEMO_MODE
# exists again, which re-arms the device's own enableUSBInDemo.sh; `;uzb` —
# the same command the README uses at the hotfix step — then gets you a
# mount. Leaving demo mode afterwards the sanctioned way (`;demo` -> Resell
# Device) runs deleteDemoModeFlagFile.sh, which removes DEMO_MODE and
# no_transitions together, so nothing is stranded a second time.
#
# Use this script when you have root and would rather not do that round trip
# — over ssh if dropbear is installed, from KUAL, or as /mnt/us/emergency.sh
# if you can still reach /mnt/us. It is one `rm` instead of two reboots.
#
# If the `;` channel is dead too (the managed-mode lockout), neither route is
# open. A ~40 second power hold with the cable UNPLUGGED restored demo mode
# and the `;` channel on my PW3; held while plugged in it only powers the
# device off.

LOG=/mnt/us/fix-usb.log
{
echo "===== fix-usb-disabled $(date) ====="
if [ -e /var/local/system/no_transitions ]; then
rm -f /var/local/system/no_transitions
if [ -e /var/local/system/no_transitions ]; then
echo " FAILED to remove no_transitions"
else
echo " removed no_transitions - USB mass storage restored"
fi
else
echo " no_transitions not present; USB is not blocked by this"
fi
echo " DEMO_MODE: $([ -e /var/local/system/DEMO_MODE ] && echo set || echo clear)"
} >> "$LOG" 2>&1
sync
[ -x /mnt/us/libkh/bin/fbink ] && /mnt/us/libkh/bin/fbink -y 2 "usb fix applied" 2>/dev/null
exit 0
40 changes: 40 additions & 0 deletions troubleshooting/go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# lbtool — host-side helpers in Go

Optional. The shell scripts in `../` are the primary path and need no toolchain.

This covers the two jobs that run on **your computer** while the Kindle is
plugged in over USB:

```
go build -o lbtool .

./lbtool verify # did the jailbreak actually take?
./lbtool payload ./LanguageBreak # copy the payload, then prove the copy
```

Both take an optional trailing volume path; without one the Kindle is found by
looking for a mounted volume containing `documents/` and `system/` (the label is
user-changeable and localised, so it is not used for detection).

## Why this exists alongside the shell scripts

One file in the payload has a **name** that is the shell injection carrying the
exploit — semicolons, `$()`, `${}`, and a trailing space. Every hop through a
shell, a GUI file manager, or an archive tool is a chance to alter it, and the
failure is silent: the jailbreak simply does nothing and you are left debugging
the device.

Go moves filenames as bytes. There is no shell in the copy path. `main_test.go`
round-trips that exact name, trailing space included, so a regression fails the
build rather than a stranger's Kindle.

It also drops `._` AppleDouble sidecars (FAT32 cannot hold them) and fsyncs
every file rather than relying on a trailing `sync`, because people unplug the
moment a copy looks finished.

## What is deliberately NOT here

`fix-managed-mode.sh` and `fix-usb-disabled.sh` have no Go equivalent and should
not get one. They delete files under `/var/local` as root and reboot, so they
run **on the device** via `/mnt/us/emergency.sh`. Shell is the right tool there,
and a compiled binary would be the wrong one.
3 changes: 3 additions & 0 deletions troubleshooting/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/notmarek/LanguageBreak/troubleshooting/go

go 1.21
Loading