{"id":6126,"date":"2024-06-25T06:32:08","date_gmt":"2024-06-25T05:32:08","guid":{"rendered":"https:\/\/www.blaess.fr\/christophe\/?p=6126"},"modified":"2024-06-25T06:32:10","modified_gmt":"2024-06-25T05:32:10","slug":"signer-ses-modules-kernel-avec-yocto-project","status":"publish","type":"post","link":"https:\/\/www.blaess.fr\/christophe\/2024\/06\/25\/signer-ses-modules-kernel-avec-yocto-project\/","title":{"rendered":"Signer ses modules kernel avec Yocto Project"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"alignright size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/keys-1.png\"><img loading=\"lazy\" decoding=\"async\" width=\"250\" height=\"250\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/keys-1.png\" alt=\"\" class=\"wp-image-6216\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/keys-1.png 250w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/keys-1-150x150.png 150w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/><\/a><\/figure><\/div>\n\n\n<p>Pour des applications o\u00f9 l&rsquo;aspect s\u00e9curit\u00e9 est particuli\u00e8rement important, on souhaite souvent s&rsquo;assurer de l&rsquo;int\u00e9grit\u00e9 de l&rsquo;espace m\u00e9moire et des activit\u00e9s du noyau Linux. Pour cela on v\u00e9rifie que les modules charg\u00e9s dynamiquement dans le noyau (les fichiers avec l&rsquo;extension <code>.ko<\/code>) sont bien conformes \u00e0 ceux pr\u00e9vus \u00e0 la production du syst\u00e8me en les signant cryptographiquement.<\/p>\n\n\n\n<p>Si cette \u00e9tape est souvent r\u00e9alis\u00e9e automatiquement pour les distributions Linux courantes (voir par exemple <a href=\"https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/module-signing.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.kernel.org\/doc\/html\/latest\/admin-guide\/module-signing.html<\/a>), elle est un peu moins simple \u00e0 mettre en oeuvre pour les syst\u00e8mes embarqu\u00e9s produits avec Yocto.<\/p>\n\n\n\n<p>Lors d&rsquo;une r\u00e9cente session de formation \u00ab\u00a0<a href=\"https:\/\/www.logilin.fr\/formations\/ecriture-de-drivers-pour-linux-formation-a-distance\/\" data-type=\"link\" data-id=\"https:\/\/www.logilin.fr\/formations\/ecriture-de-drivers-pour-linux-formation-a-distance\/\" target=\"_blank\" rel=\"noreferrer noopener\">\u00c9criture de drivers pour Linux<\/a>\u00a0\u00bb que j&rsquo;animais pour Logilin, un participant m&rsquo;a interrog\u00e9 sur les m\u00e9thodes \u00e0 employer pour signer les modules dans un contexte de syst\u00e8me embarqu\u00e9. Nous n&rsquo;avons pas eu le temps de d\u00e9velopper ce sujet durant cette session, mais j&rsquo;ai voulu d\u00e9tailler ce th\u00e8me dans ce petit article.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Installation d&rsquo;un module kernel personnalis\u00e9 avec Yocto Project<\/h2>\n\n\n\n<p>Les fichiers sources pr\u00e9sent\u00e9s ci-dessous sont disponibles ici&nbsp;: <a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>https:\/\/github.com\/cpb-\/meta-signing-modules<\/strong><\/a>.<\/p>\n\n\n\n<p>Commen\u00e7ons par \u00e9crire un module kernel minimal nomm\u00e9 <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/my-module\/my-module\/my-module.c\" target=\"_blank\" rel=\"noreferrer noopener\">my-module.c<\/a><\/strong><\/code> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ SPDX-License-Identifier: GPL-2.0\n\/\/\n\/\/ (c) 2024 Christophe Blaess\n\/\/    https:\/\/www.logilin.fr\/\n\n#include &lt;linux\/module.h&gt;\n\nstatic int __init my_module_init(void)\n{\n    pr_info(\"%s: Hello guys!\\n\", THIS_MODULE-&gt;name);\n    return 0;\n}\n\nstatic void __exit my_module_exit(void)\n{\n    pr_info(\"%s: That's all folk!\\n\", THIS_MODULE-&gt;name);\n}\n\nmodule_init(my_module_init);\nmodule_exit(my_module_exit);\n\nMODULE_DESCRIPTION(\"My custom module.\");\nMODULE_AUTHOR(\"Christophe Blaess &lt;christophe.blaess@logilin.fr&gt;\");\nMODULE_LICENSE(\"GPL v2\");<\/code><\/pre>\n\n\n\n<p>Ce fichier source est accompagn\u00e9 d&rsquo;un fichier <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/my-module\/my-module\/Makefile\" target=\"_blank\" rel=\"noreferrer noopener\">Makefile<\/a><\/strong><\/code> typique d&rsquo;un module du kernel&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># SPDX-License-Identifier: GPL-2.0\n\nifneq ($(KERNELRELEASE),)\n\n    obj-m += my-module.o\nelse\n    KERNEL_DIR ?= \/lib\/modules\/$(shell uname -r)\/build\n    MODULE_DIR := $(shell pwd)\n\n.PHONY: all modules clean\n\nall: modules\n\nmodules:\n    $(MAKE) -C $(KERNEL_DIR) M=$(MODULE_DIR)  modules\n\nclean:\n    rm -f *.o *.ko *.mod.c .*.o .*.o.d .*.ko .*.mod.c .*.cmd *~ *.ko.unsigned *.mod\n    rm -f Module.symvers Module.markers modules.order\n    rm -rf .tmp_versions .cache.mk\nendif<\/code><\/pre>\n\n\n\n<p>Enfin, une recette pour Yocto Project permet de compiler ce module. Ce fichier <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/my-module\/my-module.bb\" target=\"_blank\" rel=\"noreferrer noopener\">my-module.bb<\/a><\/strong><\/code> est plac\u00e9 dans un layer personnalis\u00e9.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>LICENSE = \"GPL-2.0-only\"\nLIC_FILES_CHKSUM = \"file:\/\/${COMMON_LICENSE_DIR}\/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6\"\n\nSRC_URI += \"file:\/\/my-module.c\"\nSRC_URI += \"file:\/\/Makefile\"\n\ninherit module\n\nS = \"${WORKDIR}\"\n\nEXTRA_OEMAKE:append:task-install = \" -C ${STAGING_KERNEL_DIR} M=${S}\"\nEXTRA_OEMAKE += \"KERNEL_DIR=${STAGING_KERNEL_DIR}\"<\/code><\/pre>\n\n\n\n<p>Voici l&rsquo;organisation sommaire de ce layer sp\u00e9cifique&nbsp;:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-01-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"868\" height=\"177\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-01-3.png\" alt=\"\" class=\"wp-image-6143\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-01-3.png 868w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-01-3-300x61.png 300w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-01-3-768x157.png 768w\" sizes=\"auto, (max-width: 868px) 100vw, 868px\" \/><\/a><\/figure>\n\n\n\n<p>Commen\u00e7ons par faire une compilation pour une image minimale (<code><strong>core-image-base<\/strong><\/code>). J&rsquo;ai int\u00e9gr\u00e9 le layer personnalis\u00e9 dans <code><strong>conf\/bblayers.conf<\/strong><\/code> et ajout\u00e9 les deux lignes suivantes dans <code><strong>conf\/local.conf<\/strong><\/code> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IMAGE_INSTALL:append = \" my-module\"\nMACHINE = \"qemuarm\"<\/code><\/pre>\n\n\n\n<p>J&rsquo;ai utilis\u00e9 la version de Yocto Project la plus r\u00e9cente au moment de l&rsquo;\u00e9criture de cet article (branche <em>Scarthgap<\/em> de Poky, <em>release<\/em> 5.0.1), mais ce que nous allons voir ici devrait \u00eatre valable quelque soit la version.<\/p>\n\n\n\n<p>Une fois le <em>build<\/em> termin\u00e9, je d\u00e9marre ma cible Qemu et je teste le chargement du module&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\nPoky (Yocto Project Reference Distro) 5.0.1 qemuarm \/dev\/ttyAMA0\n\nqemuarm login: <strong>root<\/strong>\n\nWARNING: Poky is a reference Yocto Project distribution that should be used for\ntesting and development purposes only. It is recommended that you create your\nown distribution for production use.\n\nroot@qemuarm:~# <strong>cat \/proc\/sys\/kernel\/tainted <\/strong>\n0\nroot@qemuarm:~# <strong>modprobe my-module<\/strong>\n&#91;   25.224565] my_module: loading out-of-tree module taints kernel.\n&#91;   25.227876] my_module: Hello guys!\n\nroot@qemuarm:~# <strong>cat \/proc\/sys\/kernel\/tainted <\/strong>\n4096\n\nroot@qemuarm:~# <strong>rmmod my-module<\/strong>\n&#91;   34.990447] my_module: That's all folk!\n\n\nroot@qemuarm:~# <strong>cat \/proc\/sys\/kernel\/tainted <\/strong>\n4096\n\nroot@qemuarm:~# \n<\/code><\/pre>\n\n\n\n<p>Nous voyons que le module personnalis\u00e9 est bien install\u00e9 et accessible via <code>modprobe<\/code> (il est install\u00e9 sous <code>\/lib\/modules\/<\/code>&lt;<code>kernel-version&gt;\/updates\/<\/code>). Nous pouvons remarquer que le fait de le charger active un <em>flag<\/em> dans le pseudo-fichier <code>\/proc\/sys\/kernel\/tainted<\/code> qui persiste apr\u00e8s le retrait du module.<\/p>\n\n\n\n<p>Dans ce fichier se trouve des indications de l&rsquo;historique du kernel depuis le <em>boot<\/em>, entre autres&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Le noyau a-t-il ex\u00e9cut\u00e9 du code dont les sources ne sont pas disponibles, en chargeant un module sous licence \u00ab\u00a0<em>proprietary<\/em>\u00a0\u00bb ?<\/li>\n\n\n\n<li>A-t-on charg\u00e9 un module maintenu hors des sources officielles du kernel (c&rsquo;est le message \u00ab\u00a0<em>loading out-of-tree module taints kernel<\/em>\u00a0\u00bb que nous apercevons au chargement de notre code)&nbsp;?<\/li>\n\n\n\n<li>A-t-on charg\u00e9 ou d\u00e9charg\u00e9 un module de force (avec l&rsquo;option \u00ab\u00a0<code>-f<\/code>\u00a0\u00bb )&nbsp;?<\/li>\n\n\n\n<li>Le noyau a-t-il d\u00e9clench\u00e9 un \u00ab\u00a0<em>Warning<\/em>\u00a0\u00bb ? un \u00ab\u00a0<em>OOPS<\/em>\u00a0\u00bb ou un \u00ab\u00a0<em>BUG<\/em>\u00a0\u00bb ?<\/li>\n\n\n\n<li>etc.<\/li>\n<\/ul>\n\n\n\n<p>L&rsquo;id\u00e9e du pseudo-fichier <code>\/proc\/sys\/kernel\/tainted<\/code> est un peu la m\u00eame que celle des \u00e9tiquettes \u00ab\u00a0<em>Waranty void if removed<\/em>\u00a0\u00bb qui recouvrent les vis de d\u00e9montage des appareils \u00e9lectroniques du commerce&nbsp;: ne pas offrir de support pour l&rsquo;analyse d&rsquo;un crash si le kernel a ex\u00e9cut\u00e9 pr\u00e9alablement du code dont les sources ne sont pas accessibles.<\/p>\n\n\n\n<p>Pour en savoir plus sur les flags <em>tainted<\/em>, voir&nbsp;: <a href=\"https:\/\/docs.kernel.org\/admin-guide\/tainted-kernels.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.kernel.org\/admin-guide\/tainted-kernels.html<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Signature automatique de tous les modules<\/h2>\n\n\n\n<p>Je vais modifier la configuration du kernel pour demander \u00e0 ce que les fichiers modules soient automatiquement sign\u00e9s lors de leur installation sur la cible.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake -c menuconfig virtual\/kernel<\/strong>\n    &#91;*] Enable loadable module support  ---&gt;\n              &#91;...]\n        <strong>&#91;*]<\/strong>   Module signature verification<\/code><\/pre>\n\n\n\n<p>Je ne modifie que l&rsquo;option <code>CONFIG_MODULE_SIG<\/code>. Toutefois, apr\u00e8s extraction des modifications (avec <code>bitbake -c diffconfig virtual\/kernel<\/code>, j&rsquo;obtiens un fichier <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/linux\/files\/fragment-01.cfg\" target=\"_blank\" rel=\"noreferrer noopener\">fragment-01.cfg<\/a><\/strong><\/code> un peu plus complet&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_SYSTEM_DATA_VERIFICATION=y\nCONFIG_MODULE_SIG_FORMAT=y\nCONFIG_MODULE_SIG=y\n# CONFIG_MODULE_SIG_FORCE is not set\nCONFIG_MODULE_SIG_ALL=y\nCONFIG_MODULE_SIG_SHA1=y\n# CONFIG_MODULE_SIG_SHA224 is not set\n# CONFIG_MODULE_SIG_SHA256 is not set\n# CONFIG_MODULE_SIG_SHA384 is not set\n# CONFIG_MODULE_SIG_SHA512 is not set\nCONFIG_MODULE_SIG_HASH=\"sha1\"\nCONFIG_CRYPTO_HASH_INFO=y\n\nCONFIG_ASYMMETRIC_KEY_TYPE=y\nCONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y\nCONFIG_X509_CERTIFICATE_PARSER=y\n# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set\nCONFIG_PKCS7_MESSAGE_PARSER=y\n# CONFIG_PKCS7_TEST_KEY is not set\n# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set\n# CONFIG_FIPS_SIGNATURE_SELFTEST is not set\nCONFIG_MODULE_SIG_KEY=\"certs\/signing_key.pem\"\nCONFIG_MODULE_SIG_KEY_TYPE_RSA=y\n# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set\nCONFIG_SYSTEM_TRUSTED_KEYRING=y\nCONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set\n# CONFIG_SECONDARY_TRUSTED_KEYRING is not se<\/code><\/pre>\n\n\n\n<p>J&rsquo;ajoute ce fragment et j&rsquo;\u00e9cris une extension de recette pour le kernel&nbsp;: <code><strong>linux-yocto_%.bbappend<\/strong><\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FILESEXTRAPATHS:prepend := \"${THISDIR}\/files:\"\n\nSRC_URI += \"file:\/\/fragment-01.cfg\"<\/code><\/pre>\n\n\n\n<p>Voici le sch\u00e9ma de l&rsquo;installation du fragment et du fichier d&rsquo;extension dans notre layer d\u00e9di\u00e9.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-02-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"871\" height=\"204\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-02-2.png\" alt=\"\" class=\"wp-image-6171\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-02-2.png 871w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-02-2-300x70.png 300w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-02-2-768x180.png 768w\" sizes=\"auto, (max-width: 871px) 100vw, 871px\" \/><\/a><\/figure>\n\n\n\n<p>Avant la re-compilation, il faut forcer l&rsquo;effacement des sources pr\u00e9c\u00e9dentes du kernel et de notre module en utilisant&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake -c clean virtual\/kernel my-module<\/strong><\/code><\/pre>\n\n\n\n<p>Apr\u00e8s recompilation, je d\u00e9marre Qemu. Le chargement du module se d\u00e9roule exactement comme pr\u00e9c\u00e9dement. Petite nouveaut\u00e9, nous pouvons voir que le module est bien sign\u00e9&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@qemuarm:~# <strong>modinfo my-module<\/strong>\nfilename:       \/lib\/modules\/6.6.23-yocto-standard\/updates\/my-module.ko\nlicense:        GPL v2\nauthor:         Christophe Blaess &lt;christophe.blaess@logilin.fr&gt;\ndescription:    My custom module.\ndepends:        \nname:           my_module\nvermagic:       6.6.23-yocto-standard SMP preempt mod_unload ARMv7 p2v8 \nsig_id:         PKCS#7\nsigner:         Build time autogenerated kernel key\nsig_key:        51:AC:FE:8F:23:0A:19:78:1A:BF:14:AA:41:66:89:83:A6:26:07:59\nsig_hashalgo:   sha1\nsignature:      71:ED:24:CD:C5:0A:B8:AE:82:70:62:88:CB:FB:B9:9F:8A:3F:D0:C7:\n\t\tAD:6B:EB:24:E5:9F:BA:A4:15:6E:1C:D4:74:AD:7B:E5:25:1A:96:C2:\n\t\t8A:EF:A1:EC:C2:70:7D:CB:F5:CB:FC:E4:41:36:39:B0:6B:CF:FA:BA:\n\t\tE3:69:52:09:7A:66:6F:A5:34:66:8B:FE:31:20:6A:15:84:7A:2D:6F:\n\t\t37:DA:FD:06:AA:01:A4:45:AB:3A:DC:E2:15:87:14:EE:23:03:2C:57:\n\t\t3D:55:4F:3B:FB:6F:92:06:3C:24:11:79:48:DE:B0:9F:49:5C:BD:E4:\n\t\t24:0E:D6:FE:84:C2:32:03:CB:B7:A6:7A:BC:D5:23:76:B2:4A:57:F4:\n\t\t21:A2:2B:81:A9:42:7B:47:5B:E8:09:A0:BC:1D:47:C4:5A:DB:1A:27:\n\t\t47:68:43:CF:C1:08:11:66:8E:75:7A:9F:86:38:27:63:98:D1:10:5D:\n\t\t8C:17:3D:EE:0A:3C:85:A9:F2:B1:0C:BA:D1:10:E1:D2:13:28:C7:63:\n\t\tC3:8E:8C:29:45:5F:45:2C:8D:46:3B:16:D2:A0:50:80:6B:7C:9D:8B:\n\t\t47:F4:CE:1F:F3:B1:FD:22:4D:48:FB:12:3B:70:77:FC:76:10:6D:14:\n\t\t8E:58:3A:FD:62:E7:3C:C2:23:93:DA:9F:2E:FF:5F:CF:E1:B2:AF:03:\n\t\t14:EB:8B:FD:71:86:20:1E:C1:80:DD:16:EE:87:71:A7:84:C8:BE:6E:\n\t\t2F:DC:71:AC:7D:FD:C5:F4:C5:A9:4B:88:55:C6:CB:62:F5:4D:DF:B1:\n\t\tEC:F1:92:60:4D:05:65:67:E2:2D:91:52:63:8C:68:52:11:23:BC:6F:\n\t\t54:E6:BF:7C:AB:BF:16:88:81:D3:E6:30:DE:C0:61:7D:BF:9E:BE:EE:\n\t\tC1:6C:8A:62:B0:8F:67:93:79:CD:93:9C:CF:20:4D:85:B3:6E:1F:DE:\n\t\tBC:3E:9F:D3:10:C8:99:54:5E:D3:32:49:7B:91:0B:8A:CD:37:79:0E:\n\t\t39:89:71:EF:0D:4B:8E:12:CB:57:37:C3:4A:97:7B:30:7E:84:D2:05:\n\t\t2D:B1:39:C8:86:3B:4F:F1:2E:34:4E:0B:CA:98:86:3B:7E:F9:26:AD:\n\t\t63:3F:51:01:6B:6B:67:C3:FB:DD:0E:CA:DF:BF:A8:2F:CA:B5:57:AF:\n\t\tEF:D2:DB:65:FB:91:CD:68:59:AA:1F:2F:10:2D:53:61:BF:E6:47:9F:\n\t\t11:E7:22:1E:72:02:1B:6E:BA:3D:4D:78:92:BB:3D:26:29:F3:0D:DC:\n\t\t7C:BE:94:32:AC:33:E0:50:15:90:3D:53:9A:E4:62:1C:F1:B1:DE:C0:\n\t\tD5:AC:63:5B:86:88:DD:1E:C4:52:C7:7A\n<\/code><\/pre>\n\n\n\n<p>Il est d&rsquo;ailleur possible de voir qu&rsquo;un module est sign\u00e9 en observant simplement les derniers octets du fichier&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@qemuarm:~# <strong>hexdump -C \/lib\/modules\/6.6.23-yocto-standard\/updates\/my-module.ko | tail <\/strong>\n000194e0 87 67 4b 5c a3 6c 31 31  ee 91 6c 06 8f 1d e6 44 |.gK\\.l11..l....D|\n000194f0 51 0b 95 8c 7f 20 e3 eb  6a 8b f7 85 1b d5 9e 7e |Q.... ..j......~|\n00019500 10 b0 3c 4a a3 2c f0 5b  de c6 f1 ac e1 56 42 df |..&lt;J.,.&#91;.....VB.|\n00019510 a4 00 b8 75 45 e8 1a 6f  cb fd a8 17 8f 8c db 1e |...uE..o........|\n00019520 37 5b d5 29 92 aa 7a aa  b0 4f 01 24 0e b9 a2 90 |7&#91;.)..z..O.$....|\n00019530 a5 64 e4 1a b1 96 8b 60  c9 52 c6 28 6b 11 52 31 |.d.....`.R.(k.R1|\n00019540 66 f1 62 00 00 02 00 00  00 00 00 00 00 01 c3 7e |f.b............~|\n00019550 <strong>4d 6f 64 75 6c 65 20 73<\/strong>  <strong>69 67 6e 61 74 75 72 65<\/strong> |<strong>Module signature<\/strong>|\n00019560 <strong>20 61 70 70 65 6e 64 65<\/strong>  <strong>64<\/strong> 7e 0a                | <strong>appended<\/strong>~.|\n0001956b\n<\/code><\/pre>\n\n\n\n<p>J&rsquo;avais conserv\u00e9 un exemplaire du fichier <code>my-module.ko<\/code> pr\u00e9c\u00e9dent, non sign\u00e9. Lorsque je le charge dans le kernel apr\u00e8s un reboot, j&rsquo;observe&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@qemuarm:~# <strong>insmod my-module.ko<\/strong>\n&#91;   71.294608] my_module: loading out-of-tree module taints kernel.\n&#91;   71.295015] my_module: module verification failed: signature and\/or required key missing - tainting kernel\n&#91;   71.298868] my_module: Hello guys!\n\nroot@qemuarm:~# <strong>cat \/proc\/sys\/kernel\/tainted <\/strong>\n12288\nroot@qemuarm:~# <\/code><\/pre>\n\n\n\n<p>Nous voyons que le chargement d&rsquo;un module non-sign\u00e9, dans un kernel compil\u00e9 avec l&rsquo;option <code>CONFIG_MODULE_SIG<\/code> est possible, mais nous ajoute un flag suppl\u00e9mentaire (8192) dans le pseudo-fichier <code>\/proc\/sys\/kernel\/tainted<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Refus des modules non-sign\u00e9s<\/h2>\n\n\n\n<p>Il est \u00e9galement possible d&rsquo;activer une option suppl\u00e9mentaire  lors de la configuration du kernel&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>bitbake -c menuconfig virtual\/kernel<\/strong>\n    &#91;*] Enable loadable module support  ---&gt;\n              &#91;...]\n        <strong>&#91;*]<\/strong>   Require modules to be validly signed<\/code><\/pre>\n\n\n\n<p>J&rsquo;active cette option (<code>CONFIG_MODULE_SIG_FORCE<\/code>) ce qui me conduit au fichier <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/linux\/files\/fragment-02.cfg\" target=\"_blank\" rel=\"noreferrer noopener\">fragment-02.cfg<\/a><\/strong><\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_SYSTEM_DATA_VERIFICATION=y\nCONFIG_MODULE_SIG_FORMAT=y\nCONFIG_MODULE_SIG=y\nCONFIG_MODULE_SIG_FORCE=y\nCONFIG_MODULE_SIG_ALL=y\nCONFIG_MODULE_SIG_SHA1=y\n# CONFIG_MODULE_SIG_SHA224 is not set\n# CONFIG_MODULE_SIG_SHA256 is not set\n# CONFIG_MODULE_SIG_SHA384 is not set\n# CONFIG_MODULE_SIG_SHA512 is not set\nCONFIG_MODULE_SIG_HASH=\"sha1\"\nCONFIG_CRYPTO_HASH_INFO=y\n\nCONFIG_ASYMMETRIC_KEY_TYPE=y\nCONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y\nCONFIG_X509_CERTIFICATE_PARSER=y\n# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set\nCONFIG_PKCS7_MESSAGE_PARSER=y\n# CONFIG_PKCS7_TEST_KEY is not set\n# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set\n# CONFIG_FIPS_SIGNATURE_SELFTEST is not set\nCONFIG_MODULE_SIG_KEY=\"certs\/signing_key.pem\"\nCONFIG_MODULE_SIG_KEY_TYPE_RSA=y\n# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set\nCONFIG_SYSTEM_TRUSTED_KEYRING=y\nCONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set\n# CONFIG_SECONDARY_TRUSTED_KEYRING is not set<\/code><\/pre>\n\n\n\n<p>Apr\u00e8s recompilation et d\u00e9marrage, le chargement du module sign\u00e9 fonctionne normalement. Toutefois, si j&rsquo;essaye de charger le premier module compil\u00e9 en d\u00e9but d&rsquo;article (non-sign\u00e9),  cela \u00e9choue&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@qemuarm:~# <strong>insmod my-module.ko<\/strong>\n&#91;   81.964006] Loading of unsigned module is rejected\ninsmod: ERROR: could not insert module my-module.ko: Key was rejected by service<\/code><\/pre>\n\n\n\n<p>Nous avons ainsi une configuration o\u00f9 tous les modules (y compris ceux hors sources officielles du noyau) sont sign\u00e9s et  o\u00f9 la pr\u00e9sence de la signature est obligatoire.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Utilisation d&rsquo;une cl\u00e9 de signature personnalis\u00e9e<\/h2>\n\n\n\n<p>Pour signer ses modules, le noyau g\u00e9n\u00e8re une cl\u00e9 nomm\u00e9e <code>signing_key.pem<\/code> qu&rsquo;il place dans le r\u00e9pertoire <code>certs\/<\/code>. Il est possible de la remplacer par notre propre cl\u00e9.<\/p>\n\n\n\n<p>Le fichier <code><strong>signing_key.pem<\/strong><\/code> du kernel est formatt\u00e9 de mani\u00e8re un peu particuli\u00e8re&nbsp;: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>-----BEGIN PRIVATE KEY-----\nMIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDPw19sLbG4swxZ\n&#91;...]\nasYcpnPMyq1gneDqTHB4FSpx55xJ\n-----END PRIVATE KEY-----\n-----BEGIN CERTIFICATE-----\nMIIFKDCCAxCgAwIBAgIUDzBsb9UUtq2PVdUBCQooLqGPyyIwDQYJKoZIhvcNAQEL\n&#91;...]\n1nC1+p60Z+k087MvkqFVKwsBg==\n-----END CERTIFICATE-----<\/code><\/pre>\n\n\n\n<p>La cl\u00e9 priv\u00e9e (utilis\u00e9e pour signer les modules lors de la compilation) et le certificat (embarqu\u00e9 dans le noyau pour v\u00e9rifier les modules au chargement sur la cible) se suivent dans le m\u00eame fichier <code>.pem<\/code>. Pour r\u00e9aliser cette mise en forme, on peut appeler <code>openssl<\/code> en pr\u00e9cisant le m\u00eame fichier de sortie pour la cl\u00e9 et le certificat&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>openssl req -new -x509 -newkey rsa:2048 -nodes -days 36500 -config x509.genkey -keyout my-key.pem -out my-key.pem<\/strong>\n<\/code><\/pre>\n\n\n\n<p>Pour cr\u00e9er le certificat, j&rsquo;ai fourni un fichier de description <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/linux\/files\/x509.genkey\" target=\"_blank\" rel=\"noreferrer noopener\">x509.genkey<\/a><\/strong><\/code> en m&rsquo;inspirant de celui utilis\u00e9 par le kernel&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91; req ]\ndefault_bits = 4096\ndistinguished_name = req_distinguished_name\nprompt = no\nstring_mask = utf8only\nx509_extensions = myexts\n\n&#91; req_distinguished_name ]\n<strong>O = MyCompany\nCN = My Company\nemailAddress = contact@my-company.com<\/strong>\n\n&#91; myexts ]\nbasicConstraints=critical,CA:FALSE\nkeyUsage=digitalSignature\nsubjectKeyIdentifier=hash\nauthorityKeyIdentifier=keyid<\/code><\/pre>\n\n\n\n<p>J&rsquo;ai seulement modifi\u00e9 les trois lignes de la section <code>req_distinguished_name<\/code>. <\/p>\n\n\n\n<p>On peut v\u00e9rifier si la cl\u00e9 et le certificat sont bien pr\u00e9sents dans le fichier <code>.pem<\/code> en les extrayant successivement ainsi&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>openssl pkey -in my-key.pem  -noout -text<\/strong>\nPrivate-Key: (2048 bit, 2 primes)\nmodulus:\n    00:9b:66:dd:dd:ca:e3:1c:32:0f:93:42:11:07:7b:\n    &#91;...]\n    52:9b\npublicExponent: 65537 (0x10001)\nprivateExponent:\n    0b:8f:53:dd:f4:1b:99:6e:a3:7e:90:e4:dc:cc:c2:\n    &#91;...]\n    e9\nprime1:\n    00:ce:b6:87:c7:98:c2:3c:2a:88:16:f5:00:0c:90:\n    &#91;...]\n    e8:f7:24:85:fa:15:66:38:b9\nprime2:\n    00:c0:74:5f:c2:3a:69:23:46:d3:7b:31:4c:c8:c8:\n    &#91;...]\n    ec:60:e2:31:a8:9b:25:d3:f3\nexponent1:\n    20:9a:b7:c5:ea:b9:50:46:21:1b:05:df:d1:1b:76:\n    &#91;...]\n    59:8b:00:3a:d6:df:3d:b9\nexponent2:\n    69:36:f6:27:24:71:d8:54:5f:47:e9:62:f6:1d:d5:\n    &#91;...]\n    3f:83:49:ec:c8:ad:3c:9b\ncoefficient:\n    55:b5:cd:16:75:99:82:2d:bc:a5:2b:10:24:e2:a9:\n    &#91;...]\n    2f:fe:41:16:0c:8f:93:76\n\n$ <strong>openssl x509 -in my-key.pem  -noout -text<\/strong>\nCertificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number:\n            4e:c9:a9:2b:4d:4d:57:ae:72:23:7f:77:bb:11:50:f1:ca:19:89:d3\n        Signature Algorithm: sha256WithRSAEncryption\n        Issuer: <strong>O = MyCompany, CN = My Company, emailAddress = contact@my-company.com<\/strong>\n        Validity\n            Not Before: Jun 17 12:19:17 2024 GMT\n            Not After : May 24 12:19:17 2124 GMT\n        Subject: <strong>O = MyCompany, CN = My Company, emailAddress = contact@my-company.com<\/strong>\n        Subject Public Key Info:\n            Public Key Algorithm: rsaEncryption\n                Public-Key: (2048 bit)\n                Modulus:\n                    00:c6:10:93:36:ca:49:88:f5:7d:10:76:e2:46:79:\n                    &#91;...]\n                    52:9b\n                Exponent: 65537 (0x10001)\n        X509v3 extensions:\n            X509v3 Basic Constraints: critical\n                CA:FALSE\n            X509v3 Key Usage: \n                Digital Signature\n            X509v3 Subject Key Identifier: \n                2F:87:BE:24:8D:A9:45:35:BD:E0:34:DC:82:2E:30:FE:0E:89:35:A2\n    Signature Algorithm: sha256WithRSAEncryption\n    Signature Value:\n        27:e9:fb:f6:16:34:69:8c:1f:ce:92:d3:8c:7c:f8:26:5f:1a:\n        &#91;...]\n        b3:3b:30:22<\/code><\/pre>\n\n\n\n<p>Je place le fichier <code>my-key.pem<\/code> dans le sous-r\u00e9pertoire <code>files\/<\/code> de la recette concernant le kernel. Nous obtenons l&rsquo;organisation suivante&nbsp;:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-03-2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"880\" height=\"176\" src=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-03-2.png\" alt=\"\" class=\"wp-image-6189\" srcset=\"https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-03-2.png 880w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-03-2-300x60.png 300w, https:\/\/www.blaess.fr\/christophe\/wp-content\/uploads\/2024\/06\/signing-modules-03-2-768x154.png 768w\" sizes=\"auto, (max-width: 880px) 100vw, 880px\" \/><\/a><\/figure>\n\n\n\n<p>Stocker la cl\u00e9 priv\u00e9e \u00e0 cet endroit n&rsquo;est pas tr\u00e8s s\u00fbr, il vaudrait mieux g\u00e9n\u00e9rer ce fichier juste avant la compilation (\u00e0 partir d&rsquo;une cl\u00e9 stock\u00e9e de mani\u00e8re plus s\u00e9curis\u00e9e) et l&rsquo;effacer juste apr\u00e8s la compilation. N\u00e9anmoins, dans le cadre de cet article, nous nous contenterons de cette configuration.<\/p>\n\n\n\n<p>Je modifie le fichier <code>fragment-02.cfg<\/code> pr\u00e9c\u00e9dent pour obtenir ainsi <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/linux\/files\/fragment-03.cfg\" target=\"_blank\" rel=\"noreferrer noopener\">fragment-03.cfg<\/a><\/strong><\/code> :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONFIG_SYSTEM_DATA_VERIFICATION=y\nCONFIG_MODULE_SIG_FORMAT=y\nCONFIG_MODULE_SIG=y\nCONFIG_MODULE_SIG_FORCE=y\nCONFIG_MODULE_SIG_ALL=y\nCONFIG_MODULE_SIG_SHA1=y\n# CONFIG_MODULE_SIG_SHA224 is not set\n# CONFIG_MODULE_SIG_SHA256 is not set\n# CONFIG_MODULE_SIG_SHA384 is not set\n# CONFIG_MODULE_SIG_SHA512 is not set\nCONFIG_MODULE_SIG_HASH=\"sha1\"\nCONFIG_CRYPTO_HASH_INFO=y\n\nCONFIG_ASYMMETRIC_KEY_TYPE=y\nCONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y\nCONFIG_X509_CERTIFICATE_PARSER=y\n# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set\nCONFIG_PKCS7_MESSAGE_PARSER=y\n# CONFIG_PKCS7_TEST_KEY is not set\n# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set\n# CONFIG_FIPS_SIGNATURE_SELFTEST is not set\n<strong>CONFIG_MODULE_SIG_KEY=\"certs\/my-key.pem\"<\/strong>\nCONFIG_MODULE_SIG_KEY_TYPE_RSA=y\n# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set\nCONFIG_SYSTEM_TRUSTED_KEYRING=y\nCONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set\n# CONFIG_SECONDARY_TRUSTED_KEYRING is not set\n<\/code><\/pre>\n\n\n\n<p>Je vais ajouter au moment de la compilation mon fichier <code>my-key.pem<\/code> dans le r\u00e9pertoire <code>certs\/<\/code> des sources du kernel. Pour cela je modifie le fichier <code><strong><a href=\"https:\/\/github.com\/cpb-\/meta-signing-modules\/blob\/master\/recipes-kernel\/linux\/linux-yocto_%25.bbappend\" target=\"_blank\" rel=\"noreferrer noopener\">linux-yocto_%.bbappend<\/a><\/strong><\/code> ainsi&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>FILESEXTRAPATHS:prepend := \"${THISDIR}\/files:\"\n\nSRC_URI += \"file:\/\/fragment-03.cfg\"\nSRC_URI += \"file:\/\/my-key.pem\"\n\ndo_compile:prepend() {\n    mv \"${WORKDIR}\/my-key.pem\" ${S}\/certs\/\n}<\/code><\/pre>\n\n\n\n<p>Apr\u00e8s une recompilation et d\u00e9marrage du noyau je peux observer&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@qemuarm:~# <strong>modprobe my-module<\/strong>\n&#91;   20.987736] my_module: loading out-of-tree module taints kernel.\n&#91;   20.991480] my_module: Hello guys!\n\nroot@qemuarm:~# <strong>modinfo my-module<\/strong>\nfilename:       \/lib\/modules\/6.6.23-yocto-standard\/updates\/my-module.ko\nlicense:        GPL v2\nauthor:         Christophe Blaess &lt;christophe.blaess@logilin.fr&gt;\ndescription:    My custom module.\ndepends:        \nname:           my_module\nvermagic:       6.6.23-yocto-standard SMP preempt mod_unload ARMv7 p2v8 \nsig_id:         PKCS#7\n<strong>signer:         My Company<\/strong>\nsig_key:        4E:C9:A9:2B:4D:4D:57:AE:72:23:7F:77:BB:11:50:F1:CA:19:89:D3\nsig_hashalgo:   sha1\nsignature:      1D:59:D9:45:EA:C0:57:D9:5F:44:FD:E6:5C:B7:D9:44:59:EC:1E:9E:\n\t\tDE:93:2A:DF:6B:E7:1E:10:9A:85:45:36:64:A9:47:76:23:CC:91:4D:\n\t\t&#91;...]<\/code><\/pre>\n\n\n\n<p>On peut observer sur la ligne \u00ab\u00a0<code><strong>signer<\/strong>:<\/code>\u00a0\u00bb que la cl\u00e9 de signature utilis\u00e9e est bien celle que nous avons g\u00e9n\u00e9r\u00e9e. La ligne \u00ab\u00a0<code>sig_key<\/code>\u00a0\u00bb affiche \u00e9galement le m\u00eame hachage que la ligne \u00ab\u00a0<code>Serial Number<\/code>\u00a0\u00bb lors de l&rsquo;extraction du certificat avec Openssl plus haut.<\/p>\n\n\n\n<p>Nous pouvons voir que notre cl\u00e9 est bien connue du kernel en regardant&nbsp;:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>root@qemuarm:~# <strong>cat \/proc\/keys <\/strong>\n0da419c0 I------     1 perm 1f030000     0     0 asymmetri <strong>MyCompany: My Company:<\/strong> 2f87be248da94535bde034dc822e30fe0e8935a2: X509.rsa 0e8935a2 &#91;]\n0fcc6f23 I------     1 perm 1f030000     0     0 keyring   .dns_resolver: empty\n232a0295 I--Q---     1 perm 0c030000     0 65534 keyring   .user_reg: 2\n&#91;...]<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Nous avons obtenu avec cet article de signer automatiquement tous les modules kernel que Yocto Project installera dans notre image, en utilisant une cl\u00e9 personnalis\u00e9e. Ce n&rsquo;est qu&rsquo;un premier pas dans la s\u00e9curisation compl\u00e8te d&rsquo;un syst\u00e8me embarqu\u00e9. Il faudra \u00e9galement que le bootloader s&rsquo;assure de l&rsquo;int\u00e9grit\u00e9 du noyau, voire du <em>root filesystem<\/em> complet.<\/p>","protected":false},"excerpt":{"rendered":"<p>Pour des applications o&ugrave; l&rsquo;aspect s&eacute;curit&eacute; est particuli&egrave;rement important, on souhaite souvent s&rsquo;assurer de l&rsquo;int&eacute;grit&eacute; de l&rsquo;espace m&eacute;moire et des activit&eacute;s du noyau Linux. Pour cela on v&eacute;rifie que les modules charg&eacute;s dynamiquement dans le noyau (les fichiers avec l&rsquo;extension .ko) sont bien conformes &agrave; ceux pr&eacute;vus &agrave; la production du syst&egrave;me en les signant [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-6126","post","type-post","status-publish","format-standard","hentry","category-linux-2"],"_links":{"self":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/6126","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/comments?post=6126"}],"version-history":[{"count":52,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/6126\/revisions"}],"predecessor-version":[{"id":6226,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/posts\/6126\/revisions\/6226"}],"wp:attachment":[{"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/media?parent=6126"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/categories?post=6126"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blaess.fr\/christophe\/wp-json\/wp\/v2\/tags?post=6126"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}