Kilka sposobów na ogarnięcie pendrive live

Kategoria: Artykuły, etykiety: persistence, pendrive, live-build, live, squashfs

Dodany: 2013-11-05 00:53 (zmodyfikowany: 2014-09-12 10:05)
Przez: morfik

Wyświetleń: 11957

1. Wstęp

W tym tekście zostanie opisanych kilka sposobów na wgranie obrazu live na pendrive bez potrzeby kasowania wszelkich danych na nim zawartych. Jedyne co będzie nam potrzebne to odpowiednio sformatowany pędrak, w moim przypadku jest to staroć 16GB, kupiony ze 2-3 lata temu za 70 zeta. W tym tekście będę operował na obrazach, których rozmiar nie przekroczy 1,5GiB. Oczywiście wielkość obrazu może się wahać od parudziesięciu MiB, do paru ładnych GiB.

Obraz, który zostanie umieszczony na pendrive można, albo zrobić samemu, albo też można go pobrać z netu. W każdym razie jeśli zdecydujemy się na jego zbudowanie, to trzeba wiedzieć, że pakiety live-* potrafią czasem wnerwić człowieka. Generalnie ciężko jest zbudować obraz live oparty o pakiety z repo testing i sid korzystając ze stabilnej wersji live-build. Sporo rzeczy może nie działać, a jak wiadomo, stable jest trochę nieaktualne i dla mnie schodzenie poniżej testinga nie wchodzi w grę, zwłaszcza jeśli chodzi o system live.

2. Przygotowywanie pendrive

Na sam początek musimy odpowiednio przygotować sobie pendrive. Trzeba się zdecydować czy obraz live ma być statyczny, czy też mogą do niego być wprowadzane zmiany. Może nie bezpośrednio do obrazu ale na wyznaczoną do tego celu partycję. Ta partycja może także zostać zaszyfrowana, np. gdy chcemy posiadać tam konfigurację systemu (katalog /etc/) i/lub użytkowników (katalog /home/) ale jednocześnie nie uśmiecha się nam by wszyscy mieli dostęp do tych plików. My zdecydujemy się na najbardziej zaawansowany model, czyli wprowadzanie zmian do obrazu na zaszyfrowanej partycji. Zatem nasz system będzie zajmował dwie partycje -- jedną pod obraz, druga zaś będzie przechowywać zmiany, które normalnie były by dokonywane w systemie plików.

Poniżęj prezentuje się podział partycji na pendrive:

# lsblk /dev/sdb
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sdb      8:16   1  14.5G  0 disk 
├─sdb1   8:17   1     3G  0 part 
├─sdb2   8:18   1     2G  0 part 
└─sdb3   8:19   1   9.5G  0 part 

Niżej, bardziej szczegółowa konfiguracja:

# fdisk -l /dev/sdb
Disk /dev/sdb: 15.5 GB, 15513354240 bytes
64 heads, 32 sectors/track, 14794 cylinders, total 30299520 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0005c7f0

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *        2048     6293503     3145728    b  W95 FAT32
/dev/sdb2         6293504    10487807     2097152   83  Linux
/dev/sdb3        10487808    30298111     9905152   83  Linux

Krótko mówiąc, kroimy pena na trzy partycje -- 3GiB, 2GiB, reszta. Na pierwszej partycji tworzymy system plików fat32 oraz nadajemy jej flagę boot. Drugą partycję pozostawiamy niesformatowaną, a na trzecią dajemy system plików ext4.

Przechodzimy teraz do zaszyfrowania drugiej partycji -- odpalamy terminal i wydajemy kolejno:

# cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 5000 --use-random --verify-passphrase --verbose luksFormat /dev/sdb2
# cryptsetup luksOpen /dev/sdb2 sdb2_crypt
# mkfs.ext4 -m 0 -L data /dev/mapper/sdb2_crypt

Więcej info o powyższych poleceniach można znaleźć tutaj.

Ważne by zapamiętać jaką wartość ma opcja -L, bo trzeba będzie uzupełnić odpowiedni wpis przy budowaniu systemu live. Można tutaj wpisać cokolwiek, grunt by ten sam ciąg znaków znalazł się w pliku konfiguracyjnym obrazu.

Po stworzeniu systemu plików w zaszyfrowanym kontenerze, musimy jeszcze podmontować ten system plików i utworzyć tam plik, w którym będą zawarte informacje na temat folderów, których zmiana ma zostać zapisana w zaszyfrowanym kontenerze. Zatem montujemy i tworzymy plik persistence.conf :

# mount /dev/mapper/sdb2_crypt /mnt
# touch /mnt/persistence.conf

W zależności od tego jakie zmiany chcemy zachować, możemy zdefiniować albo cały system plików:

/ union

albo określone foldery:

/home union

Ja się ograniczyłem do drugiej opcji, gdyż wgrywanie nowych obrazów, mając przy tym dane ze starego systemu plików może powodować różne problemy, często uniemożliwiając start systemu, przynajmniej u mnie tego typu zjawiska miały miejsce. Konfiguracja użytkownika jest relatywnie bezpieczna. Oczywiście to nie znaczy, że wprowadzanie zmian do całego systemu plików jest złe. Zawsze można wyczyścić zaszyfrowany kontener z plików się tam znajdujących, np. przy ewentualnych problemach ze startem systemu.

Po określeniu pożądanych folderów zamykamy kontener:

# umount /mnt
# cryptsetup luksClose sdb2_crypt

3. Pozyskiwanie obrazu

Obrazy live można pobrać z http://www.debian.org/CD/live/index.pl.html. Można też wykorzystać obrazy live innych dystrybucji, choć trzeba mieć na uwadze, że struktura katalogów może się różnić i trzeba to wziąć pod uwagę przy wprowadzaniu zmian.

Poniżej przedstawię krótkie info w celu zbudowania własnego obrazu. Nie będę opisywał całej procedury, można to przeczytać tu. Można też zajrzeć do manuali, dostepne tu albo tu.

Jeśli jeszcze nie mamy w systemie pakietu live-build, do doinstalujmy go. Dobrze jest korzystać z jak najnowszej wersji tego pakietu -- aktualnie w sidzie jest 4.0~alpha39-1 :

# aptitude -t sid install live-build

Wymagane poniższe wpisy w /etc/apt/sources.list :

 deb     http://ftp.pl.debian.org/debian/ sid main non-free contrib
#   deb-src http://ftp.pl.debian.org/debian/ sid main non-free contrib

Tworzymy pusty katalog i kopiujemy do niego parę plików szkieletowych:

# mkdir live && cd live && lb config
# cp /usr/share/doc/live-build/examples/auto/* auto/

Przechodzimy teraz do edycji pliku live/auto/config i wrzucamy do niego poniższą zawartość:

#!/bin/sh

set -e

lb config noauto \
    --apt aptitude \
    --apt-recommends true \
    --apt-secure true \
    --distribution jessie \
    --binary-image hdd \
    --archive-areas "main contrib non-free" \
    --bootappend-live "\
boot=live \
config \
locales=pl_PL.UTF-8,en_US.UTF-8 \
keyboard-layouts=pl \
timezone=Europe/Warsaw \
persistence \
persistence-encryption=luks \
persistence-media=removable \
persistence-label=data \
nottyautologin \
noeject \
swapon \
hostname=livemor \
" \
    --bootstrap debootstrap \
    --mirror-bootstrap http://ftp.pl.debian.org/debian/ \
    --mirror-binary http://ftp.pl.debian.org/debian/ \
    --architecture amd64 \
    --linux-flavours "amd64" \
    --linux-packages "linux-image linux-headers" \
    --bootloader syslinux \
    --debian-installer-distribution daily \
    "${@}"

Jeśli jakieś opcje są niezrozumiałe, informacje na temat każdej z nich można znaleźć w manualu.

Dodatkowo tworzymy dwa pliki w config/package-lists/ -- w pliku appsy.list.chroot dopisujemy jeden pod drugim kolejne pakiety, które zostaną dograne do obrazu live. Obowiązkową pozycją jest cryptsetup , bo bez niego nie otworzymy zaszyfrowanej partycji. Oczywiście można tutaj sobie dodać dowolne pakiety. Natomiast metapakiety można dać do osobnego pliku, będzie bardziej czytelnie. Ja stworzyłem plik desktop.list.chroot , w którym dodałem poniższe linijki:

task-gnome-desktop
task-laptop
task-desktop

Zamiast wymieniać setki pakietów jeden pod drugim, można określić jeden metapakiet zadaniowy. Kompletną ich listę możemy zobaczyć po wydaniu polecenia:

$ apt-cache search --names-only ^task-

Natomiast mniejsze metapakiety można sprawdzić posługując się debtags :

$ debtags search role::metapackage

W każdym razie wybieramy co nam potrzeba i dopisujemy do powyższych plików. I to by było generalnie tyle z naszej ingerencji w obraz. Budujemy go:

# lb clean
# lb config
# lb build

4. Przenoszenie obrazu na pendrive

Mając plik obrazu, możemy go przenieść na pena używając dd lub cp :

# cp live-image-i386 /dev/sdb

Ale zanim przeniesiemy obraz .img na pendrive, musimy utworzyć kopię zapasową mbr:

# dd if=/dev/sdb of=mbr bs=512 count=1

Dopiero po skopiowaniu mbr, w którym to znajdują się wpisy z granicami partycji, możemy zacząć kopiować obraz. Ważne jest by schować ten plik, w przeciwnym razie gdy wgramy nowy obraz bezpośrednio na pena, przy braku tego pliku nie będziemy w stanie odzyskać już żadnych danych z pendrive, przynajmniej nie w łatwy sposób. Wszystko oczywiście sprowadza się do wyliczenia granic partycji, które to są przechowywane w mbr, jeśli potrafimy wskazać systemowi, gdzie są partycje, wszystko będzie w porządku. Trzeba tylko pamiętać by wgrywany obraz nie był większy niż pierwsza partycja, czyli, w tym przypadku, mniejszy niż 3GiB.

Po wgraniu obrazu, trzeba odtworzyć wpisy w tablicy partycji, czyli musimy wgrać parę bajtów z uprzednio skopiowanego mbr bezpośrednio na pena, przy czym, unikałbym wgrywania całego mbr -- może to ja mam pecha ale mi po takiej akcji system się nie chciał bootować. W każdym razie by przywrócić tylko tablicę partycji, wydajemy polecenie:

# dd if=mbr of=/dev/sdb bs=1 count=64 skip=446 seek=446

Przy każdej manipulacji z mbr, najlepiej jest wyciągnąć pena z portu usb i wsadzić go ponownie, tak by mieć pewność, że system zaczął korzystać z nowego układu partycji. Niemniej jednak, po wgraniu obrazu i po tej zabawie z mbr, pierwsza partycja będzie zawierać błędy -- rozmiar systemu plików nie będzie pełny i będzie zajmował tyle co obraz live, czyli w moim przypadku to było 1.1GiB ale partycja przecie ma 3GiB i nie chcielibyśmy by prawie 2GiB poszło na zmarnowanie. Trzeba zatem odzyskać jakoś pozostałe miejsce z pierwszej partycji, tak by system plików wypełnił całą dostępną na niej przestrzeń. Można to fixnąć bez problemu w gparted albo posłużyć się w tym celu tekstową wersją -- parted:

# parted /dev/sdb resize 1 1049kB 3222MB

Można oczywiście wstukać samo parted /dev/sdb i wybrać manualnie resize 1, a pozostałe dwie wartości zostaną nam wskazane automatycznie. W ten sposób możemy wgrywać kolejne obrazy, a dane znajdujące się na 2 i 3 partycji będą nietknięte.

5. Spakowany system plików squashfs

Załóżmy na moment, że nie korzystamy z persistence oraz, że zbudowaliśmy lub pozyskaliśmy obraz live, który nam służy jako ostatnia deska ratunku dla głównego systemu -- gdy ten dostanie zawału, odpalamy pędraka i reanimujemy system. Ale po tym jak załadujemy obraz do pamięci, musimy ciągle doinstalowywać jakieś pakiety, których albo nie ma domyślnie w pewnych dystrybucjach albo sami zapomnieliśmy ich wgrać tworząc obraz live. Czy to oznacza, że jesteśmy skazani na ciągłe instalowanie pakietów ilekroć chcemy załadować system live do RAMu lub czy też trzeba robić kolejny obraz od początku? Nie. Poza persistence mamy jeszcze opcję edycji obrazu bezpośrednio przy pomocy chroot.

System live to nic innego jak spakowany system plików jakieś dystrybucji, który podczas startu maszyny jest montowany w trybie tylko do odczytu, a potrzebne jego składniki wędrują do RAMu. Jako, że squashfs jest to system plików tylko do odczytu, nie można go edytować bezpośrednio, trzeba go pierw wypakować. Kopiujemy filesystem.squashfs z pendrive na dysk i wypakowujemy go:

root:/# cd mnt
root:/mnt# cp /media/morfik/DEBIAN_LIVE/live/filesystem.squashfs ./
root:/mnt# unsquashfs filesystem.squashfs
Parallel unsquashfs: Using 2 processors
156637 inodes (163405 blocks) to write

[========|                                     ]   8522/163405   5%

Po wypakowaniu zostanie utworzony katalogu: squashfs-root/ i to jest rozpakowany system plików do którego musimy się chrootnąć, o tym jak to zrobić, można przeczytać min. tutaj. Po zakończeniu prac, pakujemy system plików:

root:/mnt# mksquashfs squashfs-root filesystem.squashfs -b 1024k -comp xz -Xbcj x86

Tak przygotowany system plików można wgrać już na pendrive do katalogu DEBIAN_LIVE/live .

6. Manipulowanie obrazem .img

Obrazy robione przez live-build to nie są zwyczajne obrazy, które można od tak zamontować używając do tego polecenia mount. Posiadają one bowiem mbr, co powoduje, że system plików tego obrazu jest zwyczajnie nie znany, bo czytany jest nie ten sektor co potrzeba. Co nam przyjdzie z zamontowania obrazu img? Będziemy mieli dostęp do plików obrazu live, min. też do filesystem.squashfs , który to będziemy mogli zwyczajnie skopiować na pendriva, bez manipulowania partycjami, od tak po prostu kopiuj/wklej.

Jedyne czego nie możemy skopiować, ani w ogóle ruszać to plik: ldlinux.sys . Jest to bootloader, wgrany zaraz na początku pierwszym partycji. Jeśli zostanie skasowany lub przemieszczony, bootowanie systemu stanie się niemożliwe. Wszystkie pozostałe pliki możemy dowolnie kasować, zmieniać i dodatkowo wgrywać nowe. Limituje nas tylko wielkość partycji. Ja korzystam z tego rozwiązania w celu trzymania dwóch plików filesystem.squashfs . Chodzi o to,że czasami obraz może się zbudować poprawnie, ale nie chce się zabootować. W najgorszym wypadku czekałaby mnie ponowna budowa starego obrazu, a tak, mogę po prostu zmienić nazwę z filesystem.squashfs2 na filesystem.squashfs na pendrive i wracam do działającego obrazu.

Zamontować obraz .img można na dwa sposoby -- albo usuwając z niego mbr i mbr gap:

# dd if=binary.img of=binary.img.bez.mbr bs=2048 skip=512
# mount -o loop binary.img.bez.mbr /mnt

albo od razu skorzystać z opcji mount -- offset:

# mount -o loop,offset=1048576 binary.img /mnt

Jak wyliczyć offset? 1048576 = 2048x512, zaś 2048 i 512 zostały odczytane z fdiska:

# fdisk -l binary.img

Disk binary.img: 1246 MB, 1246756864 bytes
147 heads, 59 sectors/track, 280 cylinders, total 2435072 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0001fe2e

          Device Boot      Start         End      Blocks   Id  System
binary.img.base1   *        2048     2435071     1216512   83  Linux

512 to rozmiar sektora, zaś 2048 to start pierwszej partycji. Czyli trzeba wykroić/pominąć przestrzeń przed pierwszą partycją by dostać się do systemu plików zauważalnego przez mount. Z tak zamontowanego obrazu swobodnie można już kopiować pliki.

Obraz .img można poddać też edycji, np. zwiększyć rozmiar systemu plików. By dodać trochę miejsca do obrazu .img, musimy dołączyć na jego końcu trochę danych i tak np. by zwiększyć pojemność obrazu o 400MiB, wydajemy polecenie:

# dd if=/dev/zero bs=2M count=200 >> binary.img

A tak wygląda mój nowy obraz zrobiony przez live-build, już rozszerzony o 400MiB:

Disk /media/Server/live/binary.img: 1666MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system  Flags
        16.4kB  1049kB  1032kB           Free Space
 1      1049kB  1247MB  1246MB  primary  fat32        boot
        1247MB  1666MB  419MB            Free Space

Jak widać, system plików pierwszej partycji nie uwzględnia jeszcze dodanego miejsca. Po tym trzeba jeszcze fixnąć partycję w parted:

# parted binary.img
GNU Parted 2.3
Using /media/Server/live/binary.img
Welcome to GNU Parted! Type 'help' to view a list of commands.

(parted) resize 1                                                         
WARNING: you are attempting to use parted to operate on (resize) a file system.
parted's file system manipulation code is not as robust as what you'll find in
dedicated, file-system-specific packages like e2fsprogs.  We recommend
you use parted only to manipulate partition tables, whenever possible.
Support for performing most operations on most types of file systems
will be removed in an upcoming release.
Start?  [1049kB]?                                                         
End?  [1247MB]? 1666MB                                                    

(parted) print free                                                       
Model:  (file)
Disk /media/Server/live/binary.img: 1666MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system  Flags
        16.4kB  1049kB  1032kB           Free Space
 1      1049kB  1666MB  1665MB  primary  fat32        boot

Porównajmy teraz jak prezentuje się zamontowany obraz. Przed:

USAGE
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     vfat  1.2G  1.2G   34M  98% /mnt

oraz po:

USAGE
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0     vfat  1.6G  1.2G  433M  73% /mnt

Oczywiście bawienie się obrazem .img przy posiadaniu powyższego info nie ma sensu ale dobrze jest wiedzieć, że coś takiego można zrobić.

7. Hasło do zaszyfrowanego persistence

Pozostała jeszcze do omówienie kwestia drugiej partycji, czyli tej na której będą przechowywane zmiany, które by normalnie zostały wprowadzone do obrazu live. Jako, że ta partycja jest zaszyfrowana, chronić ją może (i pewnie będzie) hasło. Hasło, jak to hasło, czasem istnieje potrzeba jego zmiany. Oczywiście można utworzyć nowy kontener i przechodzić przez tworzenie drugiej partycji jeszcze raz. Istnieje też prostszy sposób, czyli zmiana hasła do kontenera.

Podejrzyjmy zatem jak się prezentuje nagłówek kontenera:

# cryptsetup luksDump /dev/sdb2
LUKS header information for /dev/sdb2

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha512
Payload offset: 4096
MK bits:        512
MK digest:      d0 9d 3d b3 34 2d 0c d3 0e 99 59 79 14 71 f3 00 07 b5 b8 76 
MK salt:        d6 9f 77 4f f0 2d c8 07 c9 cf a7 60 c4 6f 3d 90 
                c9 4d 5c ae f4 e5 36 d3 e5 75 b4 5d 3b 83 c9 79 
MK iterations:  18125
UUID:           90ec6f73-8fdb-4c8d-aebd-cadd0f51b412


Key Slot 0: ENABLED
    Iterations:             15685
    Salt:                   95 f7 1b 27 04 c6 87 c8 3c 14 23 5b c7 99 f8 c2 
                            cf ab 1c ed 8c 70 69 b4 da a3 a7 67 97 5e f6 a4 
    Key material offset:    512
    AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

W slocie 0 jest nasze hasło, by je zmienić, trzeba pierw dodać nowe hasło, a następnie usunąć stare:

# cryptsetup luksAddKey /dev/sdb2
Enter any existing passphrase: 
Enter new passphrase for key slot:
# cryptsetup luksKillSlot /dev/sdb2 0
Enter any remaining passphrase:

I jeszcze sprawdzenie czy wszystko jest tak jak być powinno:

# cryptsetup luksDump /dev/sdb2 
LUKS header information for /dev/sdb2

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha512
Payload offset: 4096
MK bits:        512
MK digest:      d0 9d 3d b3 34 2d 0c d3 0e 99 59 79 14 71 f3 00 07 b5 b8 76 
MK salt:        d6 9f 77 4f f0 2d c8 07 c9 cf a7 60 c4 6f 3d 90 
                c9 4d 5c ae f4 e5 36 d3 e5 75 b4 5d 3b 83 c9 79 
MK iterations:  18125
UUID:           90ec6f73-8fdb-4c8d-aebd-cadd0f51b412

Key Slot 0: DISABLED
Key Slot 1: ENABLED
    Iterations:             15685
    Salt:                   95 f7 1b 27 04 c6 87 c8 3c 14 23 5b c7 99 f8 c2 
                            cf ab 1c ed 8c 70 69 b4 da a3 a7 67 97 5e f6 a4 
    Key material offset:    512
    AF stripes:             4000
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

Hasło ze slotu 0 zniknęło i od tej pory by odszyfrować kontener, trzeba podać nowe hasło.

8. Problemy ze startem systemu live

Może się zdarzyć tak, że doświadczymy problemów ze startem systemu podczas bootowania z pendrive. Nie pamiętam dokładnie ale w przypadku posiadania jednej partycji na pendrive ten problem chyba nie występuje. Natomiast w przypadku posiadania dwóch i więcej, starsze biosy mogą nie widzieć pendrive w przypadku ustawienia flagi boot na którejś z jego partycji. Bez flagi boot wszystko jest w porządku -- pendrive jest widoczny ale bez niej nie wskażemy biosowi, która partycja zawiera system live, co wiele nie zmieni, bo i tak nie odpalimy systemu.

Istnieje jednak sztuczka, która potrafi na sztywno wpisać w mbr, z której partycji bios powinien startować system -- czyli możemy nie ustawiać flagi boot i jednocześnie bios zabootuje system live z odpowiedniej partycji pena. Nie wiem czy tego typu akcja może zostać przeprowadzona w oparciu o gruba ale w przypadku {ext,sys}linux mamy do tego specjalny mbr znajdujący się w /usr/lib/syslinux/altmbr.bin i by z niego skorzystać, wskazując przy tym pierwsza partycję na penie, wgrywamy go poniższą linijką:

# printf '\x1' | cat /usr/lib/syslinux/mbr/altmbr.bin - | dd bs=440 count=1 iflag=fullblock conv=notrunc of=/dev/sdb

OSnews Wykop Blip Flaker Kciuk Śledzik Facebook Identi.ca Twitter del.icio.us Google Bookmarks