J’ai un SSD pour lequel le constructeur a sorti une mise à jour du firmware. Il s’agit du modèle M550 de chez Crucial qui passe de la version M01 à la version M02. Ce SSD est au format mSata, dans mon routeur qui est un APU1 de PCEngines. Ce routeur n’a pas de sortie vidéo, ne fonctionne pas sous Windows mais sous Linux, et n’a pas de lecteur CD. Quelque chose me dit que cela ne va pas me prendre 5 minutes…
Pour mettre à niveau le firmware, je dispose de deux possibilités :
- connecter le SSD sur une autre machine plus « standard » et faire la mise à jour depuis cette machine. J’aurais bien opté pour cette solution si j’avais eu un adaptateur SATA > mSATA, et puis cela aurait été moins fun, non ?
- mettre à jour directement le SSD sans utiliser le tournevis
Crucial met à disposition le package de mise à niveau sous la forme d’une image CD. Je pourrais éventuellement brancher un lecteur CD en USB au routeur, voire même modifier le bootloader pour booter directement sur l’iso mais il est fort à parier que le CD n’a pas été prévu pour un contrôle depuis le port série, voie sans issue donc.
CD, dis-moi qui tu es
Explorons un peu le contenu de cette image.
On commence à avoir des choses intéressantes. Le CD contient un noyau linux (vmlinuz) et le bootloader est isolinux, un standard pour booter du linux depuis un CD ou une clé USB. Je serais tombé sur une mise à jour basée sur DOS (Caldera DOS, FreeDOS…), j’aurais été bon pour acheter l’adaptateur.
Examinons le fichier de configuration du bootloader:
DEFAULT sd LABEL sd KERNEL /boot/vmlinuz INITRD /boot/core.gz APPEND quiet base loglevel=3 waitusb=10 superuser rssd-fw-update rssd-fwdir=/opt/firmware rssd-model=M550
On remarque un certain nombre de paramètres non standard, ainsi que le initrd.
Hacking the kernel
Pour continuer l’analyse de l’iso, je redémarre redémarre le routeur sur la sdcard (système de secours si le ssd lache) afin de laisser totalement inutilisé le SSD, puis copier le contenu de l’iso dans disons /tmp/crucial/iso . Qui dit initrd dit cpio. Je décompresse donc core.gz puis extrayons le contenu de l’archive cpio dans /tmp/crucial/root .
Le point d’entrée par défaut est le script /init , vu qu’il n’a pas été redéfini dans les paramètres envoyés au kernel.
Il est d’une extrême simplicité et se résume à :
- monter /proc
- lancer /sbin/init
init , s’il s’agit du bon vieux process racine servant à faire fonctionner Linux, va se servir de /etc/init.d afin d’initialiser les différentes partie du système. Certains de ces scripts sont reconnaissable (rc.shutdown) voir inutile à vue (dhcp.sh, settime.sh…). Il y en a un toutefois qui retient mon attention : msd-config.sh car son nom ne m’est absolument pas familier.
Bingo ! Ce script, simple également, récupère les paramètres envoyés au kernel, via le fichier /proc/cmdline , et lancer le processus msecli avec les paramètres adéquat. Il va notamment utiliser le paramètre kernel rssd-model=M550 , ce qui me conforte que je suis bien sur la bonne piste, le M550 étant pour rappel le modèle de mon SSD.
Au final, le script exécutera la commande suivante : /sbin/msecli -U -i /opt/firmware -m M550 -y .
Allons-y :
apu:/tmp/boot/root# ./sbin/msecli --help -ash: ./sbin/msecli: not found apu:/tmp/boot/root# ll ./sbin/msecli -rwxr-xr-x 1 root root 635.5K Apr 9 14:22 ./sbin/msecli apu:/tmp/boot/root# ldd ./sbin/msecli ldd: ./sbin/msecli: Not a valid dynamic program
Le fichier est bien présent, pourtant il n’est pas possible de l’exécuter. C’est plutôt bizarre…
Go down the rabbit hole
Une analyse sauvage du fichier (sous vim) m’apprend qu’il s’agit d’un exécutable non statique, c’est à dire qu’il utilise des librairies chargées dynamiquement. Sachant que le Linux hôte est Alpine Linux, la libc en vigueur n’est pas l’immonde glibc mais musl. Comme indiqué ci-dessous, la présence de /lib/ld-linux.so.2 trahit le caractère dynamique de l’exécutable. Cela explique également pourquoi le ldd sur l’hôte n’est pas parvenu à parser correctement l’exécutable.
^?ELF^A^A^A^@^@^@^@^@^@^@^@^@^B^@^C^@^A^@^@^@<90>)^E^H4^@^@^@Ì ^@^@^@^@^@4^@ ^@^H^@(^@^]^@^Z^@^F^@^@^@4^@^@^@4<80>^D^H4<80>^D^H^@^A^@^@^@^A^@^@^E^@^@^@^D^@^@^@^C^@^@^@4^A^@^@4<81>^D^H4<81>^D^H^S^@^@^@^S^@^@^@^D^@^@^@^A^@^@^@^A^@^@^@^@^@^@^@^@<80>^D^H^@<80>^D^H^T^U ^@^T^U ^@^E^@^@^@^@^P^@^@^A^@^@^@^T^U ^@^T¥^M^H^T¥^M^H^T^C^@^@t1^@^@^F^@^@^@^@^P^@^@^B^@^@^@(^U ^@(¥^M^H(¥^M^Hà^@^@^@à^@^@^@^F^@^@^@^D^@^@^@^D^@^@^@H^A^@^@H<81>^D^HH<81>^D^H ^@^@^@ ^@^@^@^D^@^@^@^D^@^@^@Påtd^@Ò^H^@^@R^M^H^@R^M^H<84>^N^@^@<84>^N^@^@^D^@^@^@^D^@^@^@Qåtd^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^F^@^@^@^D^@^@^@/lib/ld-linux.so.2^@^@^D^@^@^@^P^@^@^@^A^@^@^@GNU^@^@^@^@^@^B^@^@^@^F^@^@^@ ^@^@^@ ^B^@^@I^@^@^@<80>^@^@^@^L^@^@^@D
Je tente un chroot pour résoudre cela ?
apu:/tmp/boot/root# chroot . sh apu:/# ldd sbin/msecli linux-gate.so.1 (0xe82ba000) libpthread.so.0 => /lib/libpthread.so.0 (0xe82a0000) libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xe81e3000) libm.so.6 => /lib/libm.so.6 (0xe81ac000) libc.so.6 => /lib/libc.so.6 (0xe808f000) /lib/ld-linux.so.2 (0xe82bb000) libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xe8079000) apu:/# msecli --help USAGE: msecli <Main Option> -? Provides the detailed usage information for the specified main option NOTE: All options are not supported by all drives msecli -L [-a] [-d|-P|-f] [-n <device-name>] [-r ] [-s <out-filename>] Lists the basic information for all micron drives available in the system msecli -S [-a] [-e|-d] [-l <log-type[0 | 1 | 2 | 3 | 6 | 7]>] [-t <Self-test type[0 | 1 | 2]>] [-n <device-name>] [-r] [-s <out-filename>] Lists the SMART values for the supported parameters for the micron drives available in the system. msecli -M [-i <value> | -w <state-value> | -p <state-value> ] -n <device-name> [-r] [-s <out-filename>] To manage the Micron PCIe drives. msecli -X [-B | -p <password> | -P -p <PSID> ] -n <device-name> [-r] [-s <out-filename>] Performs Secure Erase, Sanitize Block Erase, or PSID Revert for the specified micron drive msecli -D -n <device-name> [-r] [-s <out-filename>] Displays the Driver and Host Information for the given <device-name> msecli -T <UBI img-file> [ [-n <device-name> [-b] [-o]] [-i <firmware-slot>] | -d ] [-n <device-name>..] [-r] [-s <out-filename>] Updates the UBI image in the specified Micron PCIe drive. msecli -m -n <device-name>[-d <duration>] [-i <interval>] [-r] [-s <out-filename>] Displays the performance data for the specified P320/P420 drive msecli -G [-e|-E|-g] -n <device-name> [-a] [-d <Event/Error Log id> -t <Time Stamp> ][-r] [-s <out-filename>] Displays the firmware event/error logs for the specified P320/P420 drive. msecli -Z -n <device-name> [-r] [-s <out-filename>] Prepares the specified P320/P420 drive for removal. msecli -V [-a] [-r] [-s <out-filename>] Displays the Micron Storage Executive current Version. msecli -P <zip file name> -n <device-name> [-r] [-s <out-filename>] Collects debug data from the system for each micron drive msecli -U -i <fw-folder-path> [ -m <model-number> | -n <device-name> ] [-r] [-s <out-filename>] Performs firmware update with the firmware folder for the specified client drive Copyright (C) 2015 Micron Technology, Inc.
Yeah ! Je tente d’afficher les informations SMART du SSD
apu:/# msecli -S CMD_STATUS : Device Error STATUS_CODE : 5 Copyright (C) 2015 Micron Technology, Inc.
Oops ? Après quelques minutes de réflexion, je me suis aperçu avoir encore fait le sauvage en omettant de monter /proc . Je corrige cela prestement puis affiche les informations sur le SSD à l’aide du cli :
apu:/# msecli -L Drive Id : 0 Device Name : /dev/sda Model No : Crucial_CT128M550SSD3 Serial No : xxxxxxxxxxxx FW-Rev : MU01 Total Size : 128.04GB Drive Status : Drive is in good health Sata Link Speed : Gen3 (6.0 Gbps) Temp(C) : 61 Drive information is retrieved successfully CMD_STATUS : Success STATUS_CODE : 0 Copyright (C) 2015 Micron Technology, Inc.
So far so good. Je lance la mise à jour :
apu:/# msecli -U -i /opt/firmware -m M550 This will update all the M550 drives in the system Are you sure you want to continue(Y|N):Y Upgrading drive /dev/sda [Serial No. XXXXXXXXXXXX] from firmware MU01 to MU02 ............. Device Name : /dev/sda Firmware Update on /dev/sda Succeeded! CMD_STATUS : Success STATUS_CODE : 0 Copyright (C) 2015 Micron Technology, Inc.
Done ! La mise à jour est passé sans soucis. Je reboot sur le SSD pour le réinitialiser et repasser sur le système principal pour confirmer que tout s’est bien passer.
Parce qu’Un script vaut mille mots
Ci-dessous un résumé scripté des étapes que j’ai du suivre pour mettre à jour le SSD depuis Linux et sans booter sur l’iso :
#!/bin/sh ROOT_CRUCIAL_ISO=/tmp/crucial/iso ROOT_CRUCIAL=/tmp/crucial/root mkdir -p "$ROOT_CRUCIAL" gunzip "${ROOT_CRUCIAL_ISO}/boot/core.gz pushd "$ROOT_CRUCIAL" cpio -F "${ROOT_CRUCIAL_ISO}/boot/core" -i popd # mounting /proc is mandatory for the cli to properly work mount -t proc none "${ROOT_CRUCIAL}/proc/" mount --rbind /sys "${ROOT_CRUCIAL}/sys/" # in case where the kernel has grsecurity enabled, we need to allow CAPS in the chroot echo 0 > /proc/sys/kernel/grsecurity/chroot_caps 2> /dev/null chroot "$ROOT_CRUCIAL" sh msecli -U -i /opt/firmware -m M550