What is dm verity
What is dm verity
dm-verityВ¶
Device-Mapper’s “verity” target provides transparent integrity checking of block devices using a cryptographic digest provided by the kernel crypto API. This target is read-only.
Construction ParametersВ¶
This is the type of the on-disk hash format.
0 is the original format used in the Chromium OS.
The salt is appended when hashing, digests are stored continuously and the rest of the block is padded with zeroes.
1 is the current format that should be used for new devices.
The salt is prepended when hashing and each digest is padded with zeroes to the power of two.
This is the device that supplies the hash tree data. It may be specified similarly to the device path and may be the same device. If the same device is used, the hash_start should be outside the configured dm-verity device.
The block size on a data device in bytes. Each block corresponds to one digest on the hash device.
The size of a hash block in bytes.
The cryptographic hash algorithm used for this device. This should be the name of the algorithm, like “sha1”.
The hexadecimal encoding of the cryptographic hash of the root hash block and the salt. This hash should be trusted as there is no other authenticity beyond this point.
The hexadecimal encoding of the salt value.
Number of optional parameters. If there are no optional parameters, the optional parameters section can be skipped or #opt_params can be zero. Otherwise #opt_params is the number of following arguments.
Example of optional parameters section:
Log corrupted blocks, but allow read operations to proceed normally.
Restart the system when a corrupted block is discovered. This option is not compatible with ignore_corruption and requires user space support to avoid restart loops.
Panic the device when a corrupted block is discovered. This option is not compatible with ignore_corruption and restart_on_corruption.
Do not verify blocks that are expected to contain zeroes and always return zeroes instead. This may be useful if the partition contains unused blocks that are not guaranteed to contain zeroes.
Use forward error correction (FEC) to recover from corruption if hash verification fails. Use encoding data from the specified device. This may be the same device where data and hash blocks reside, in which case fec_start must be outside data and hash areas.
If the encoding data covers additional metadata, it must be accessible on the hash device after the hash blocks.
Note: block sizes for data and hash devices must match. Also, if the verity is encrypted the should be too.
Number of generator roots. This equals to the number of parity bytes in the encoding data. For example, in RS(M, N) encoding, the number of roots is M-N.
This is the offset, in blocks, from the start of the FEC device to the beginning of the encoding data.
Verify data blocks only the first time they are read from the data device, rather than every time. This reduces the overhead of dm-verity so that it can be used on systems that are memory and/or CPU constrained. However, it provides a reduced level of security because only offline tampering of the data device’s content will be detected, not online tampering.
Hash blocks are still verified each time they are read from the hash device, since verification of hash blocks is less performance critical than data blocks, and a hash block will not be verified any more after all the data blocks it covers have been verified anyway.
This is the description of the USER_KEY that the kernel will lookup to get the pkcs7 signature of the roothash. The pkcs7 signature is used to validate the root hash during the creation of the device mapper block device. Verification of roothash depends on the config DM_VERITY_VERIFY_ROOTHASH_SIG being set in the kernel. The signatures are checked against the builtin trusted keyring by default, or the secondary trusted keyring if DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING is set. The secondary trusted keyring includes by default the builtin trusted keyring, and it can also gain new certificates at run time if they are signed by a certificate already in the secondary trusted keyring.
Theory of operationВ¶
dm-verity is meant to be set up as part of a verified boot path. This may be anything ranging from a boot using tboot or trustedgrub to just booting from a known-good device (like a USB drive or CD).
When a dm-verity device is configured, it is expected that the caller has been authenticated in some way (cryptographic signatures, etc). After instantiation, all hashes will be verified on-demand during disk access. If they cannot be verified up to the root node of the tree, the root hash, then the I/O will fail. This should detect tampering with any data on the device and the hash data.
Cryptographic hashes are used to assert the integrity of the device on a per-block basis. This allows for a lightweight hash computation on first read into the page cache. Block hashes are stored linearly, aligned to the nearest block size.
If forward error correction (FEC) support is enabled any recovery of corrupted data will be verified using the cryptographic hash of the corresponding data. This is why combining error correction with integrity checking is essential.
Hash TreeВ¶
Each node in the tree is a cryptographic hash. If it is a leaf node, the hash of some data block on disk is calculated. If it is an intermediary node, the hash of a number of child nodes is calculated.
Each entry in the tree is a collection of neighboring nodes that fit in one block. The number is determined based on block_size and the size of the selected cryptographic digest algorithm. The hashes are linearly-ordered in this entry and any unaligned trailing space is ignored but included when calculating the parent node.
The tree looks something like:
alg = sha256, num_blocks = 32768, block_size = 4096
On-disk formatВ¶
The verity kernel code does not read the verity metadata on-disk header. It only reads the hash blocks which directly follow the header. It is expected that a user-space tool will verify the integrity of the verity header.
Alternatively, the header can be omitted and the dmsetup parameters can be passed via the kernel command-line in a rooted chain of trust where the command-line is verified.
Directly following the header (and with sector number padded to the next hash block boundary) are the hash blocks which are stored a depth at a time (starting from the root), sorted in order of increasing index.
The full specification of kernel parameters and on-disk metadata format is available at the cryptsetup project’s wiki page
StatusВ¶
V (for Valid) is returned if every check performed so far was valid. If any check failed, C (for Corruption) is returned.
Отключить DM-Verity или Android Verified Boot без TWRP
В этом руководстве мы покажем вам, как отключить DM-Verity или Android Verified Boot (AVB) без использования TWRP Recovery. Одним из самых больших преимуществ ОС с открытым исходным кодом, такой как Android, является возможность выполнять множество настроек. И если вы относитесь к числу технических энтузиастов, то вы, вероятно, сделаете эти модификации еще на один шаг вперед. Для начала вы можете разблокировать загрузчик устройства, установить пользовательское восстановление, такое как TWRP, LineageOS и т. д., или установить пользовательские ПЗУ, такие как Pixel Experience, LineageOS, AOSP и другие.
Точно так же вы также можете получить root права на свое устройство через Magisk, с TWRP или без TWRP. Но тут начинается самое интересное. Как только вы устанавливаете приложение и предоставляете ему права суперпользователя, оно сразу же получает доступ к системному разделу. Затем он может выполнять задачи административного уровня. И здесь в игру вступает DM Verity. Поскольку ваше устройство теперь рутировано, некоторые потенциально опасные приложения могут проникнуть на ваше устройство и вызвать проблемы.
В результате Google внедрил строгий механизм безопасности под названием Device Mapper Verity. Это не позволяет таким приложениям выполнять свои задачи. Хотя это действительно хороший шаг с точки зрения безопасности, он также не позволяет приложению выполнять все свои функции. Пользователь с root-правами уже знает кое-что о приложениях, которые могут создать проблемы для его устройства, и, следовательно, он не будет устанавливать их в первую очередь.
Таким образом, вместо того, чтобы DM Verity сразу блокировала функции корневых приложений, мы считаем, что конечный пользователь должен действовать в соответствии с запросом. И это то, что мы будем делать в этом руководстве. Мы покажем вам, как отключить DM Verity или Проверенная загрузка Android (AVB) без использования рекавери TWRP. Таким образом, вы можете легко установить все моды и настройки на свое устройство без каких-либо проблем. Итак, на этой ноте давайте продолжим руководство.
Способ 1: отключить DM Verity через Magisk
Первый правильный вопрос, который может прийти вам в голову, — почему мы использовали этот метод. В конце концов, вы можете легко отключить DM Verity, просто прошив пару ZIP-файлов через TWRP. Так что этот вопрос становится тем более оправданным. Дело в том, что не каждое Android-устройство поставляется с TWRP Recovery.
Кроме того, если можно легко получить root права на свое устройство без TWRP и даже установить OTA-обновления на Android-устройство с рутированным доступом, почему мы должны зависеть от TWRP для выполнения вышеупомянутой задачи. Так что всем владельцам устройств, у которых нет работающей сборки TWRP или которые не хотят ее прошивать, этот метод — все, что нужно. Следуйте инструкциям, чтобы отключить DM Verity или Android Verified Boot (AVB) без использования TWRP Recovery.
ШАГ 1: Получите файл стокового загрузочного образа
Для начала вам нужно будет получить стандартный файл boot.img. Для этого скачайте стоковую прошивку, соответствующую вашему устройству, а затем извлеките из нее файл boot.img. если прошивка находится в формате ZIP, вы можете легко извлечь ее с помощью WinZIP или WinRAR. В случае, если он в формате OZIP, обратитесь к нашему руководству о том, как извлечь OZIP Realme и Oppo Stock ROM (прошивка). Точно так же, если он в формате payload.bin, перейдите к руководству: Как извлечь payload.bin и получить стандартный файл загрузочного образа.
OZIP ROM, извлеченный с помощью Python
Если у вас есть устройство Xiaomi, то, возможно, его прошивка будет в формате GZ. Поэтому переименуйте его в TGZ и используйте 7ZIP для его распаковки. У нас также есть файл boot.img для нескольких устройств, если он соответствует вашим требованиям, вы можете загрузить его напрямую без необходимости извлечения. Первый — Poco X3 NFC: Загрузите стоковые ПЗУ Poco X3 NFC | Быстрая загрузка и восстановление.
Далее следует бюджетное предложение OnePlus: загрузите файлы стоковых загрузочных изображений OnePlus Nord. [All Versions]. Если вы не можете получить файл boot.img, сообщите нам об этом в комментариях, мы вам поможем. С учетом сказанного давайте приступим к отключению DM Verity или Android Verified Boot (AVB) без использования TWRP Recovery.
ШАГ 2: Установите ADB | Включить отладку
Прежде всего, вам нужно будет установить Android SDK Platform Tools на свой компьютер. Это предоставит вам необходимые двоичные файлы ADB и Fastboot. После этого установите Magisk Manager на свое устройство. В том же духе мы просим вас также включить отладку по USB. Это сделает ваше устройство узнаваемым вашим ПК в режиме ADB.
Но зачем нам режим ADB? Что ж, это понадобится для загрузки вашего устройства в режим Fastboot. После этого мы будем использовать этот режим Fastboot для прошивки файла. Итак, перейдите в «Настройки»> «О телефоне»> «Семь раз нажмите на номер сборки»> «Вернитесь в «Настройки»> «Система»> «Дополнительно»> «Параметры разработчика»> «Включить отладку по USB». [Don’t Miss: Enable USB Debugging on a Broken Android Device’s Screen? Here’s a Workaround].
ШАГ 3: Отключить сохранение AVB 2.0/dm-verity
ШАГ 4: Исправление файла загрузочного образа
Далее вам нужно будет пропатчить стандартный файл boot.img через Magisk. Вот необходимые инструкции для того же:
ШАГ 5: Загрузочный IMG-файл с исправлением флэш-памяти | Отключить DM-верити
Наконец, теперь вам нужно прошить этот пропатченный файл boot.img с помощью команд Fastboot. Для этого выполните следующие шаги:
На этом мы завершаем руководство о том, как отключить DM-Verity или Android Verified Boot (AVB) через Magisk. Если у вас есть какие-либо вопросы, сообщите нам об этом в разделе комментариев ниже.
Способ 2: отключить DM Verity с помощью команд Fastboot
Вы также можете отключить проверку подлинности на своем устройстве, прошив vbmeta (а в некоторых случаях и файлы vbmeta_system и vbmeta_vendor). Вот как это можно было бы осуществить. Droidwin и его участники не будут нести ответственность в случае термоядерной войны, если ваш будильник не разбудит вас, или если что-то случится с вашим устройством и данными, выполнив следующие шаги.
ШАГ 1. Установите Android SDK
Прежде всего, вам нужно будет установить Android SDK Platform Tools на свой компьютер. Это официальный бинарный файл ADB и Fastboot, предоставленный Google, и единственный рекомендуемый. Поэтому загрузите его, а затем распакуйте в любое удобное место на вашем ПК. Это даст вам папку platform-tools, которая будет использоваться в этом руководстве.
ШАГ 2: Загрузите и извлеките стандартную прошивку
Затем загрузите стандартную прошивку для своего устройства и распакуйте ее в любое удобное место на вашем ПК. После завершения извлечения перенесите указанные ниже файлы в папку platform-tools.
Обратите внимание, что не на каждом устройстве есть файлы dtbo.img, vendor_boot.img, vbmeta_system.img и vbmeta_vendor.img, это совершенно нормально. Однако в вашей стоковой прошивке обязательно должны быть файлы boot.img и vbmeta.img.
ШАГ 3. Включите отладку по USB и разблокировку OEM
Затем вам нужно будет включить отладку по USB и разблокировку OEM на вашем устройстве. Первый сделает ваше устройство узнаваемым ПК в режиме ADB. Это позволит вам загрузить ваше устройство в режиме быстрой загрузки. С другой стороны, разблокировка OEM требуется для выполнения процесса разблокировки загрузчика.
Итак, перейдите в «Настройки»> «О телефоне»> «Семь раз нажмите на номер сборки»> «Вернитесь в «Настройки»> «Система»> «Дополнительно»> «Параметры разработчика»> «Включить отладку по USB и разблокировку OEM».
ШАГ 4: Разблокируйте загрузчик
Далее вам также нужно будет разблокировать загрузчик устройства. Имейте в виду, что это приведет к удалению всех данных с вашего устройства, а также может привести к аннулированию гарантии. Так что, если все в порядке, обратитесь к нашему подробному руководству о том, как разблокировать загрузчик на любом устройстве Android.
ШАГ 5: Загрузите устройство в режим быстрой загрузки
ШАГ 6. Отключите проверку подлинности DM через Fastboot
Теперь вы можете отключить проверку подлинности, перепрограммировав файлы vbmeta (а также vbmeta_system и vbmeta_vendor). Итак, следуйте приведенным ниже инструкциям, чтобы начать процесс:
Итак, это были шаги по отключению DM-Verity или Android Verified Boot (AVB) с помощью команд Fastboot. Если у вас есть какие-либо вопросы относительно вышеупомянутых шагов, сообщите нам об этом в комментариях. Мы вернемся к вам с решением в ближайшее время.
dm-verityВ¶
Device-Mapper’s “verity” target provides transparent integrity checking of block devices using a cryptographic digest provided by the kernel crypto API. This target is read-only.
Construction ParametersВ¶
This is the type of the on-disk hash format.
Number of optional parameters. If there are no optional parameters, the optional paramaters section can be skipped or #opt_params can be zero. Otherwise #opt_params is the number of following arguments.
Example of optional parameters section: 1 ignore_corruption ignore_corruption Log corrupted blocks, but allow read operations to proceed normally. restart_on_corruption Restart the system when a corrupted block is discovered. This option is not compatible with ignore_corruption and requires user space support to avoid restart loops. ignore_zero_blocks Do not verify blocks that are expected to contain zeroes and always return zeroes instead. This may be useful if the partition contains unused blocks that are not guaranteed to contain zeroes. use_fec_from_device
Use forward error correction (FEC) to recover from corruption if hash verification fails. Use encoding data from the specified device. This may be the same device where data and hash blocks reside, in which case fec_start must be outside data and hash areas.
If the encoding data covers additional metadata, it must be accessible on the hash device after the hash blocks.
Note: block sizes for data and hash devices must match. Also, if the verity is encrypted the should be too.
Verify data blocks only the first time they are read from the data device, rather than every time. This reduces the overhead of dm-verity so that it can be used on systems that are memory and/or CPU constrained. However, it provides a reduced level of security because only offline tampering of the data device’s content will be detected, not online tampering.
Hash blocks are still verified each time they are read from the hash device, since verification of hash blocks is less performance critical than data blocks, and a hash block will not be verified any more after all the data blocks it covers have been verified anyway.
root_hash_sig_key_desc This is the description of the USER_KEY that the kernel will lookup to get the pkcs7 signature of the roothash. The pkcs7 signature is used to validate the root hash during the creation of the device mapper block device. Verification of roothash depends on the config DM_VERITY_VERIFY_ROOTHASH_SIG being set in the kernel.
Theory of operationВ¶
dm-verity is meant to be set up as part of a verified boot path. This may be anything ranging from a boot using tboot or trustedgrub to just booting from a known-good device (like a USB drive or CD).
When a dm-verity device is configured, it is expected that the caller has been authenticated in some way (cryptographic signatures, etc). After instantiation, all hashes will be verified on-demand during disk access. If they cannot be verified up to the root node of the tree, the root hash, then the I/O will fail. This should detect tampering with any data on the device and the hash data.
Cryptographic hashes are used to assert the integrity of the device on a per-block basis. This allows for a lightweight hash computation on first read into the page cache. Block hashes are stored linearly, aligned to the nearest block size.
If forward error correction (FEC) support is enabled any recovery of corrupted data will be verified using the cryptographic hash of the corresponding data. This is why combining error correction with integrity checking is essential.
Hash TreeВ¶
Each node in the tree is a cryptographic hash. If it is a leaf node, the hash of some data block on disk is calculated. If it is an intermediary node, the hash of a number of child nodes is calculated.
Each entry in the tree is a collection of neighboring nodes that fit in one block. The number is determined based on block_size and the size of the selected cryptographic digest algorithm. The hashes are linearly-ordered in this entry and any unaligned trailing space is ignored but included when calculating the parent node.
The tree looks something like:
On-disk formatВ¶
The verity kernel code does not read the verity metadata on-disk header. It only reads the hash blocks which directly follow the header. It is expected that a user-space tool will verify the integrity of the verity header.
Alternatively, the header can be omitted and the dmsetup parameters can be passed via the kernel command-line in a rooted chain of trust where the command-line is verified.
Directly following the header (and with sector number padded to the next hash block boundary) are the hash blocks which are stored a depth at a time (starting from the root), sorted in order of increasing index.
The full specification of kernel parameters and on-disk metadata format is available at the cryptsetup project’s wiki page
StatusВ¶
V (for Valid) is returned if every check performed so far was valid. If any check failed, C (for Corruption) is returned.
Dm-verity of Verified Boot in Android
I did a job related to the Verified Boot module before, but only found google’s documentation and a nexus patch on the Internet. Although there is a patch, there may be some bugs in the implementation of different versions of code, so here is the process of debugging this thing. I didn’t find any problem in the previous debugging process. In the final analysis, I still started with this principle without understanding it, so I divided it into principles, interfaces and applications to explain how dm-verity verified boot is implemented. In fact, the interface part is mostly principle. The reason for the interface is because I think it contains some application components. Then this article uses 6.0Android, The kernel code of 4.1.
1. Related principles
Related code
build/tools/releasetools/build_image.py
system/extras/verity/build_verity_tree.cpp
system/extras/verity/build_verity_metadata.py
There are many types of Verified Boot in Android, and here only involves the dm-verity thing, so start directly from dm-verity, as for the bootloader and other things, not much to say.
Why use dm-verity
Due to its large size, the system partition typically cannot be verified similarly to previous parts but must be verified as it’s being accessed instead using the dm-verity kernel driver or a similar solution.
A paragraph on the official Android website illustrates this problem. It can be seen that the speed of dm-verity is very fast.
Dm-verity workflow
There is such a picture on the official Android website that illustrates the process of dm-verity. After verifying the bootloader, enter the verification of the system partition and so on. This is the time when dm-verity comes out. At this point, the problem of start in the figure is reached. First, determine whether dm-verity is in the state of enforcing. If so, scan a partition that requires verity. The specific implementation is to verify the metadata of the corresponding partition. If there is no problem with scanning, ok, mount the system. If there is a problem with scanning, dm-verity will send a reboot signal to the kernel and set the state of dm-verity to loggin. After restarting, go back to the start point. At this time, the state of dm-verity is already loggin, so when you move to the red area, a warning interface will be displayed, allowing the user to choose whether to mount or not to mount. The following work will revolve around this flowchart. Decompose the implementation of this flowchart in different sections.
Dm-verity implementation
After understanding the workflow of dm-verity, let’s take a brief look at the implementation of dm-verity. The key to dm-verity implementation is how metadata is created and stored. The Android official website defines such a series of steps, how to create the steps required for dm-verity.
— Generate an ext4 system image.
— Generate a hash tree for that image.
— Build a dm-verity table for that hash tree.
— Sign that dm-verity table to produce a table signature.
— Bundle the table signature and dm-verity table into verity metadata.
— Concatenate the system image, the verity metadata, and the hash tree.
How to implement Dm-verity
The official website given above explains how to implement these steps, explaining the partial principle. Here is a code to describe how Dm-verity is implemented. These implementation steps are inbuild_image.py In this build script.
Generate an ext4 system image
The file system of ext4 can be generated by RunCommand (build_command) in the build script. As for the friends who are interested in this build_command, you can take a look at build_image.py.
Generate a hash tree for that image
There is a section in the build script that describes how to build a hashtree.In fact, the role of this hash tree is to describe the changes in system.img.
Build a hash tree through the build_verity_tree program, so build a hash treealgorithmRight herebuild_verity_tree.cpp In the file, then how to implement the algorithm, don’t worry about it. a little complicated. As for the reason for using the hash tree, it is also mentioned on the official website. Initially, he used a hash table to achieve it. Later, when the data is too large, the efficiency is not good, so the hash tree is used. The hash tree is very efficient when processing large amounts of data. The structure of the generated hash tree is as follows, there is only one root hash at the end,The leaf node is a small block of the partition of the verify partition required by dm-verity. It specifies that each block is divided by 4k. So for example, if the system partition to be verified has 800M, then there are 2 million blocks. Therefore, the change of system.img is described through the leaf node and his parent hash to the root hash.In this case, using hash table to store the efficiency is very poor, so the use of hash tree to store faster. Finally, the root hash is mainly saved.
Build a dm-verity table for that hash tree
Sign that dm-verity table to produce a table signature.
Bundle the table signature and dm-verity table into verity metadata
Ok, you can see that this code is finally calledbuild_verity_metadata.pyThis script. Take a look at how he built metadata. The three parts above the root of the trilogy correspond to each other.
Take a look at how to build a verity-table. Actually,verity-table is to describe the hash tree generated before.
So the established verity table looks like this.To put it bluntly, verity-table is just a string describing a hashtree, take a look at how he describes a hash tree.The following example is selected fromLinux document, not the verity table of the actual system.img hash tree.
The first parameter is the version, which is only 0 and 1. In most cases, fill in 1 and do not go into details.
The second and third parameters describe the protected partition. In this example, the partition protected by dm-verity is /dev/sda1.
Fourth, the size of each block of the partition described in the fifth parameter, that is, the leaf node of the hash tree, you can see that this is 4k, that is, divided by 4k/ dev/sda1 is a number of areas.
Sixth, the seventh parameter describes how many blocks there are, that is, how many leaf nodes the hash tree has.
The eighth parameter is the hash encryption algorithm, here the sha256 algorithm is used.
The ninth parameter is the root hash of the hash tree.
The tenth parameter is the salt added by the encryption algorithm.
Ok, here we can see that verity-table describes the leaf node and root hash and the hash algorithm. In this way, the shape of the whole tree is depicted by a string.
After the verity table is established, sign him. The format of the signature can be found in the chapter Implementing verify boot. After signing the name, the verity-table, signature information and hash tree are written into the metadata together, and finally returned to the build script.
Concatenate the system image, the verity metadata, and the hash tree.
Finally, append append2img this command metadata.img and metadata_verity.img attached to the back of system.img, so that even if the process of establishing dm-verity metadata is realized.
So far, the realization of the specific flow of the flowchart has not been analyzed, so at the beginning of the next paragraph, we will take a look at the specific implementation of the flowchart.
2. Interface
Related code
/kernel/include/upai/linux/dm-ioctl.h
/kernel/include/linux/device-mapper.h
/kernel/driver/md/dm-verity.c
/kernel/driver/md/dm-table.c
/kernel/dirver/md/dm-ioctl.c
/system/core/fs_mgr/fs_mgr_verity.c
Deveice Mapper framework
To know how to use dm-verity, first need to understand the Device mapeer framework, what is the device mapper? Device mapper is a set of frameworks that allows users to customize strategies for managing block devices. Using this framework to write strategies for managing block devices is definitely easier than directly managing block devices. Not much about the Device Mapper principle here. The following article makes a detailed analysis of Device Mapper. The following is only a brief introduction to some interfaces that need to be used in the realization of verified boot.
Device Mapper mechanism in the Linux kernel
Some important structures
We know that the interface provided by Device Mapper to user controls is the interface of the file system, open, read, write, etc., and the ioctl interface. Here is a list of a few ioctl commands you can take a look at. Others are similar.
So the question is coming, ioctl is sending commands to the device mapper, how to find the specific dm device. At this time another structure appeared. Also defined indm-ioctl.hin.
You can see that he has four fields, the most important thing istarget_type[DM_MAX_TYPE_NAME]This string, device mapper is to find the corresponding dm device from his device table through this string. For example, what we need to find here is dm-verity, then this string is «verity». So this string must be this? No, I will talk about the origin of this string later.
target_type is defined ininclude/linux/device-mapper.h In this structure, this structure represents a real dm device. That is to say, the DM device is finally to implement this interface, then it is very simple to develop a DM device, only need to implement this interface, and register with the device mapper framework.
He listed many fields, here are a few fields. ctr is the create function, dtr: destory, which is exactly the same as oncreate and ondestory in Activity. The name field is the target_type field corresponding to the previous dm_target_spec. That is to say, the origin of the device name is here. You define «a», then target_type is defined as «a» when passing parameters in user space.
Implementation of dm-verity driver under Device mapper framework
Before briefly introducing the use of some structure and ioctl of Device mapper, let’s take a look at how dm-verity is implemented under Device Mapper. In fact, it is enough to implement a target_type interface
/kernel/driver/md/dm-verity.c
Sure enough, the name field in verity_target is set to verity, so when we set the target_type field of dm_target_spec in user space, we set it to verity. An important interface to be mentioned later is ctr. He will call this interface when ioctl load table. Of course, the verity_target object is registered in the device mapper when the kernel module is initialized.
So when does the mode change of dm-verity take place? The first thing to know is that dm-verity has three working modes, as follows:
So let’s not talk about how to control dm-verity in user space, let’s look at the change of dm-verity state in the kernel first. The change of dm-verity state occurs when dm-verity is loaded. When dm-verity loads a dm device, the crt interface of the target type of the device will be called. Sort out the call flow of dm-verity here. Go down to ioctl DM_TABLE_LOAD and call the device mapper. The device mapper finds the dm-verity through the passed parameters and finally calls the ctr interface.
ioctl(fd, DM_TABLE_LOAD, io)—–>Device Mapper—through target_type=“verity”–>dm-verity.ctr()
Take a part of the code and take a look at the implementation of crt interface in dm-verity.
Before the above code,In the crt function, the previously generated verity-table will be processed first to verify its validity, You can refer to the complete code in the source code. Then from the above code, you can see that the change of the dm-verity state v->mode is determined by the specific parameters passed in. Before I mentioned that user space controls dm-verity, three things need to be passed in. One dm- ioctl, one is dm_target_spec, and the other is a specific parameter of a specific device. This specific parameter comes in handy here. So how to define this parameter, we can take a look at the definition in the dm-verity document.
Before opt_params, the verity table generated by the build script mentioned earlier just happens to be right. Take another look at verity-table.
So what is #opt_params, #opt_params represents the number of parameters that need to follow after the verity table, that is, argc, opt_params represents the following parameter, which is argv, there are many kinds of parameters behind,Here is a detailed introduction of optional parameters。
According to the implementation of the crt function in the kernel, dm-verity traverses the opt_params one by one, and then makes corresponding control. The mode of dm-verity is set according to the parameters passed in. In dm-verity, only dct-verity can set the state of dm-verity. Of course, if not set, his default mode is 0, which is EIO mode.
Let’s take a look at how the three state pairs in dm-verity work. When dm-verity scans that the partition is damaged, it will trigger a callback function –verity_handle_err in dm-verity.c. Also intercept part of the code to see how to handle different states in this callback function.
It can be seen that if it is in the default state, it returns 1, and after returning 1, the system’s code on the side of the mount will not mount the damaged partition. If it is DM_VERITY_MODE_LOGGING state 1, it returns 0, then the system will ignore the destruction of the code in the block and continue to mount the partition. If it is DM_VERITY_MODE_RESTART, it is state 2, then restart the system. OK, so far you can see how to deal with the three states in dm-verity.
OK, here explains how the two logics of the flowchart are implementedIn Figure 1, the logic of restarting dm-verity after the occurrence of corruption in restart mode corresponds to
In Figure 2, dm-verity ignores the corruption and continues to mount the system after the corruption occurs in loggin mode.
The default EIO mode is not seen in this flowchart. Obviously Google does not recommend this mode. In fact, I think this mode is really useless. This mode directly chooses not to mount after the corruption occurs, which will cause the system to hang, and it makes no sense.
Use of user space Dm-verity
After knowing the related interface of dm-verity, you can initialize him in user space. In Android, fs_mgr_verity is responsible for controlling Dm-verity in user space. Among them, a function load_verity_table shows how to use dm-verity from user space. Post the code first.
According to what I said before, using a dm device under the device mapper framework first creates a dm-ioctl object and initializes the object. This function isfs_mgr_verity.c Can be found in.
At this time, ioctl dm-verity’s two parts have been completed. The last step is to add specific parameters of specific devices, in this case, the parameters required by dm-verity. Join the value of verity table, opt_params and mode to
verity_params is the parameter of the specific device in the dm-verity kernel mentioned earlier.
I won’t go into details here, so I need to use two parameters later, one is ignore_corruption and one restart_on_corruption, these two values represent the dgin-verity loggin mode and enforcing mode/restart mentioned previously mode. So that we can control the operation mode of dm-verity in user space. These two different parameters can correspond to the corresponding logic in the dm-verity ctr in the previous kernel.
So far, it explains how to set dm-verity in user space, and explains the logic of Setup dm-verity in the flowchart.
3. Realize
Related code
/system/extras/slideshow/slideshow.cpp
/system/core/fs_mgr/fs_mgr_verity.c
/device/(vendor)/init.rc
/device/(vendor)/fstab.vendor
/system/core/init/builtins.c
With the introduction of the previous principles and interfaces, how to implement it becomes very simple. There is a patch in AOSP to enable it. At that time, the patch was used directly, but because the principle was not clear before, and the kernel and android code were not matched, it caused some bugs during debugging, and I don’t know how. Engage, so it is still necessary to look at the documents on the official website, and then it is very simple to implement. Here I will use this patch to describe how this matter is to achieve the flow chart. First post the key code of this patch. The following paragraphs explain the relevant code.
First look at the fstab section in the patch, add it to the fs_mgr_flags in the system partition
verify=/dev/block/platform/msm_sdcc.1/by-name/metadata, so what does this path mean? This location is used to save the mode of dm-verity. That is, in the flowchart, how do you know to enter loggin mode after dm-verity restarts,This value is stored in the metadata partition. The metadata partition is not the metadata.img mentioned before. The metadata.img is appended after the system.img, that is, the metadata.img is under the system partition.。
The working principle of this patch of fstab is very simple. If this address is not added, then dm-verity will always work in the EIO state. In this state, if dm-verity detects that the partition is faulty, he will not mount it. Partition, will not restart and ignore the crashed partition. So let’s take a look at why he will only work in the EIO state if no address is added, so that the process will not follow the established process? This does not belong to the implementation of this patch, but it is actually a very important part of the implementation of the dm-verity flow chart, so it is still analyzed. The code to actually set the dm-verity working mode is in the fs_mgr_setup_verity function in fs_mgr_verity.c. I will not post all the code, only intercept some key codes to analyze.
Take a look at the load_verity_state function
Then call down to read_verity_state, you can see the first parameter fstab->verity_loc, this value is the address behind the verity parsed from fstab before. If there is no verity in fstab or there is a corresponding address after verity, then this value is null.
At this time, after loading mode, you will go to the above code. You can see that the function load_verity_table is finally called. Ok, we mentioned this function in the interface chapter before, to initialize dm_ioctl, dm_target_type two structures, and bind a verity_params and then pass it to the kernel through a load table ioctl command to set the work of dm-verity in the kernel status. In the kernel, dm-verity will make different actions according to different states when handle error. In the previous paragraph, we have analyzed how to implement the dm verity ctr function and handle error function in dm-verity.c according to different modes. Once again explain in detail how to implement this logic of the flowchart in user space.
Then look at the patch in init.rc.
The first paragraph is to call the verity_load_state in the init action. This command will eventually call do_verity_load_state in builtins.cpp to determine whether the mode of dm-verity is loggin. If it is loggin in, it will trigger verity-logging This action. This action calls the slideshow program. Those unfamiliar can take a look at the syntax of init.rc and the principles related to the init process. If not, then go to other processes.
See the code implementation
Then what do_verity_load_state does is call the function in fs_mgr_verity.c. This function is to read and set the working mode of dm-verity based on the address in fstab combined with the status of some pstores. This code is relatively simple, and he will not be analyzed.This code explains the first judgment logic in the flowchart to judge the dm-verity working mode. Putting aside the specific code, look at the purpose of verity_load_state in init.rc is to achieve it
Then I mentioned the action of trigger-verity-logging before, and finally he called the program slideshow, then actually the path when the above judgment box is N is realized. By opening the slideshow app to warn users that the system partition has been destroyed, whether to set the loggin mode to continue mounting.
Then the function of the executed slideshow program is to display two warning pictures, one to remind you to choose whether to continue to mount the file system, and the other to remind you that you have ignored the warning. In fact, this slideshow can only be regarded as a leather bag company. The original code basically does nothing, and two pictures are displayed, but the manufacturer can customize this app to achieve some control effect, or directly replace the slideshow app, directly There is no problem to implement a recovery-like interface. Interested friends can take a look/system/extras/slideshow/slideshow.cpp How to write it is very simple, just a file, the code is more than 100 lines. The final rendering of slideshow is as follows. It corresponds to the specific implementation in the above process.
Dm-verity’s verified boot process has analyzed this, there are many imperfections, and many places have skipped the code analysis. If the main source code is to be analyzed, the length will be too long and too much. Cumbersome, just say that I have roughly analyzed the implementation of the flowchart of dm-verity. Of course, if you really want to understand dm-verity thoroughly, you still need to carefully study the code of dm-verity and fs_mgr. In each paragraph The relevant code file posted at the beginning can be referenced. This is also the only one I have encountered so far from workJavaThe code about Android is now in memory.
Introduction to dm-verity on Android¶
Edited by Roberto Sartori
Introduction: what is dm-verity?¶
Android 4.4 introduced a number of security enhancements, most notably SELinux in enforcing mode and verified boot.
Android’s verified boot implementation is based on the dm-verity device-mapper block integrity checking target. Device-mapper is a Linux kernel framework that provides a generic way to implement virtual block devices. It is used to implement volume management (LVM) and full-disk encryption (dm-crypt). Device-mapper works by essentially mapping a virtual block device to one or more physical block devices, optionally modifying transferred data in transit. For example, dm-crypt decrypts read physical blocks and encrypts written blocks before committing them to disk. Thus disk encryption is transparent to users of the virtual DM-Crypt block device. Device-mapper targets can be stacked on top of each other, making it possible to implement complex data transformations.
In this context, dm-verity is a block integrity checking target: it was initially developed as part of the Google’s Chromium OS project with the purpose to implement a device mapper target capable of validating the data blocks contained in a file system. This means that it verifies the integrity of each device block as it is being read from disk. If the block checks out, the read succeeds, and if not the read generates an I/O error as if the block was physically corrupt. As for dm-crypt, this process is transparent to the applications reading those blocks.
The final purpose of dm-verity is to guarantee the integrity of a volume against corruption or malicious attacks.
How does it work?¶
Under the hood dm-verity is implemented using a pre-calculated hash tree which includes the hashes of all device blocks. The leaf nodes of the tree include hashes of physical device blocks, while intermediate nodes are hashes of their child nodes (hashes of hashes). The root node is called the root hash and is based on all hashes in lower levels.
A change even in a single device block will result in a change of the root hash. Therefore in order to verify a hash tree we only need to verify its root hash.
Like Chrome OS, Android also uses the kernel’s DM-Verity target, but the cryptographic verification of the root hash and mounting of verified partitions are implemented differently from Chrome OS.
The RSA public key used for verification is embedded in the boot partition under the verity_key filename and is used to verify the dm-verity mapping table. This mapping table holds the locations of the target device and the offset of the hash table, as well as the root hash and salt. The mapping table and its signature are part of the verity metablock which is written to disk directly after the last file system block of the target device.
A partition is marked as verifiable by adding the verify flag to the Android-specific fs_mgr flags filed in the device’s fstab file. When Android’s file system manager encounters the verify flag in fstab, it loads the verity metadata from the block device specified in fstab and verifies its signature using the verity_key. If the signature check succeeds, the file system manager parses the dm-verity mapping table and passes it to the Linux device-mapper, which use the information contained in the mapping table in order to create a virtual dm-verity block device. This virtual block device is then mounted at the mount point specified in fstab in place of the corresponding physical device.
As a result, all reads from the underlying physical device are transparently verified against the pre-generated hash tree. Modifying or adding files, or even remounting the partition in read-write mode, results in an integrity verification failure and an I/O error.
The official Google documentation describes the steps required to enable verified boot on Android. Here is a summary of that:
During normal use of the device, every block that is read will be checked against the hashes present in the hash tree: if there are differences, dm-verity will generate an I/O error and it will make the corrupted blocks unreadable.
For performance reasons, when read into memory, the block is hashed in parallel. The hash is then verified up the tree. And since reading the block is such an expensive operation, the latency introduced by this block-level verification is as low as possible.
Forward error correction (FEC)¶
While dm-verity sounds great against malicious attacks, it also means that a detected single byte corruption will result in an entire block becoming inaccessible, leading to the kernel returning I/O errors to userspace on verified partition data access. This could, in theory, also lead to unreadable (safe) files.
For this reason, while everything said until now is valid from Android 4.4 onwards, there are some further changes to how a device behaves when dm-verity is enabled from Android 7.0: one of those is the forward error correction (FEC).
A benefit of the integrity verification already performed by dm-verity, is that it’s possible to tell exactly where the errors are in case of corruption. So, using some error correction codes, it’s technically possible to recover damaged files. If the FEC is enabled, the error-correcting codes (Reed–Solomon in the Android case) are spread over the entire partition, shipping redundant encoding data with the system image: this makes it possible for devices to recover from the loss of up to 16-24 MiB of consecutive blocks anywhere on a typical 2-3 GiB system partition with only 0.8% space overhead and no performance impact unless corruption is detected. This improves both the security and reliability of devices running Android.
Android verified boot¶
As dm-verity is a kernel feature, in order for the integrity protection it provides to be effective, the kernel which the device boots needs to be trusted. On Android, this means verifying the boot partition, which also includes the root file system RAM disk and the verity public key. This process is device-specific and is typically implemented in the device bootloader, usually by using an unmodifiable verification key stored in hardware to verify the boot partition’s signature.
On Android this is called verified boot, the Google implementation of chain of trust: verified boot guarantees the integrity of the device software starting (ideally) from a hardware root of trust up to the system partition. During boot, each stage verifies the integrity and authenticity of the next stage before executing it.