{"id":2718,"date":"2022-01-29T22:17:34","date_gmt":"2022-01-29T20:17:34","guid":{"rendered":"https:\/\/possiblelossofprecision.net\/?p=2718"},"modified":"2022-01-30T01:08:35","modified_gmt":"2022-01-29T23:08:35","slug":"chainloading-patched-ipxe-firmware-with-ipxe","status":"publish","type":"post","link":"https:\/\/possiblelossofprecision.net\/?p=2718","title":{"rendered":"Chainloading (patched) iPXE firmware with iPXE"},"content":{"rendered":"<p>These days, quite a few devices already come with built-in iPXE support: Some hypervisors (qemu, Proxmox, VMWare, VirtulBox, etc.) support iPXE right out of the gate but there&#8217;s also an <a href=\"https:\/\/github.com\/orgs\/ipxe\/repositories?q=vendor\">increasing number of network equipment vendors<\/a> that sell network interface cards with bundled iPXE support.<\/p>\n<p>But what if the bundled iPXE firmware is out of date and\/or lacking a relevant feature? <a href=\"https:\/\/ipxe.org\/appnote\/buildtargets\">Recompiling iPXE<\/a> is not particularly difficult but changing the iPXE rom file on a hypervisor might be. Or it might be inadvisable due to a support contract. And flashing new rom files onto network interface cards is usually cumbersome and very time consuming.<\/p>\n<p>So how about using <a href=\"https:\/\/ipxe.org\/howto\/chainloading\">iPXE chainloading<\/a> to load a patched or otherwise customised iPXE rom?<\/p>\n<p><!--more--><\/p>\n<h2>Chainloading iPXE via ISC DHCP<\/h2>\n<p><a href=\"https:\/\/ipxe.org\/howto\/chainloading\">iPXE chaingloading<\/a> is quite a common technique to dynamically load an iPXE rom onto a device that otherwise would not support iPXE. It&#8217;s usually used to load iPXE from a PXE environment. To <a href=\"https:\/\/ipxe.org\/howto\/dhcpd#pxe_chainloading\">break the resulting infinite loop<\/a> the DHCP server needs to be configured to hand out an iPXE rom to PXE clients but a &#8220;real&#8221; boot configuration to iPXE clients:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nnext-server your-tftp-server;\r\n\r\nif exists user-class and option user-class = &quot;iPXE&quot; {\r\n    filename &quot;http:\/\/your-http-server\/ipxe\/boot.ipxe&quot;;\r\n} elsif option arch = 00:07 {\r\n    # EFI x86-64 (Intel x86 64-bit EFI mode)\r\n    # - most commonly used on newer hardware\r\n    filename &quot;ipxe-x86_64.efi&quot;;\r\n} elsif option arch = 00:06 {\r\n    # EFI IA32 (Intel x86 32-bit EFI mode)\r\n    # - almost never seen in the wild\r\n    filename &quot;ipxe-i386.efi&quot;;\r\n}  else {\r\n    # Intel x86PC (Intel x86 32-bit legacy BIOS mode)\r\n    # - technically option arch = 00:00, but we use it as fallback\r\n    filename &quot;undionly.kpxe&quot;;\r\n}\r\n<\/pre>\n<p>Assuming we&#8217;ve successfully recompiled our iPXE roms with the desired patches or enhancements we can expand on this to hand out a newer iPXE rom even to iPXE client. Making use use of some <a href=\"https:\/\/ipxe.org\/howto\/dhcpd#ipxe-specific_options\">iPXE specific dhcp options<\/a>:<\/p>\n<pre class=\"brush: plain; highlight: [3,4,6,7,9,14,18,22]; title: ; notranslate\" title=\"\">\r\nnext-server your-tftp-server;\r\n\r\n# http:\/\/www.ietf.org\/assignments\/dhcpv6-parameters\/dhcpv6-parameters.txt\r\noption arch code 93 = unsigned integer 16;\r\n\r\noption space ipxe;\r\noption ipxe.version code 235 = string;\r\n\r\nif exists ipxe.version and binary-to-ascii(10, 8, &quot;.&quot;, option ipxe.version) = &quot;1.21.1&quot; {\r\n    filename &quot;http:\/\/your-http-server\/ipxe\/boot.ipxe&quot;;\r\n} elsif option arch = 00:07 {\r\n    # EFI x86-64 (Intel x86 64-bit EFI mode)\r\n    # - most commonly used on newer hardware\r\n    filename &quot;ipxe-x86_64-fixed.efi&quot;;\r\n} elsif option arch = 00:06 {\r\n    # EFI IA32 (Intel x86 32-bit EFI mode)\r\n    # - almost never seen in the wild\r\n    filename &quot;ipxe-i386-fixed.efi&quot;;\r\n}  else {\r\n    # Intel x86PC (Intel x86 32-bit legacy BIOS mode)\r\n    # - technically option arch = 00:00, but we use it as fallback\r\n    filename &quot;undionly-fixed.kpxe&quot;;\r\n}\r\n<\/pre>\n<p>Documentation on ISC DHCP conditional evaluation can be found here: <a href=\"https:\/\/linux.die.net\/man\/5\/dhcpd-eval\">https:\/\/linux.die.net\/man\/5\/dhcpd-eval<\/a><\/p>\n<p>To bump the version number when compiling a new rom:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\n$ git clone https:\/\/github.com\/ipxe\/ipxe\r\n$ cd ipxe\/src\r\n$ make VERSION_PATCH=2\r\n<\/pre>\n<p>On could, of course, also bump <code>VERSION_MAJOR<\/code> or <code>VERSION_MINOR<\/code> or use <code>EXTRAVERSION<\/code><\/p>\n<p><center><a data-rokbox href=\"wordpress\/wp-content\/uploads\/2022\/01\/iPXE-dhcp-chainload.png\" data-rokbox-album=\"p2718\" ><img decoding=\"async\" src=\"wordpress\/wp-content\/uploads\/2022\/01\/iPXE-dhcp-chainload.png\" alt=\"\" \/><\/a><br \/>iPXE chainloading an updated version via dhcp<\/center><\/p>\n<h2>Chainloading iPXE via iPXE script<\/h2>\n<p>Sometimes modifying the dhcp server configuration might not be possible or practical in a real world application, e.g. because you don&#8217;t have control over the dhcp server or because it&#8217;s a <a href=\"https:\/\/ipxe.org\/howto\/msdhcp#pxe_chainloading\">Microsoft Windows DHCP server<\/a>. But we can use iPXE to determine its current version and then potentially handing out an updated iPXE rom.<\/p>\n<p>Let&#8217;s assume the dhcp server is handing out <em>http:\/\/your-http-server\/ipxe\/boot.ipxe<\/em> through the <code>filename<\/code> option and that particular file reads:<\/p>\n<pre class=\"brush: plain; title: boot.ipxe; notranslate\" title=\"boot.ipxe\">\r\n#!ipxe\r\n\r\necho Booting Linux...\r\nkernel your-kernel-image.img\r\ninitrd your-initramfs.img\r\n\r\nboot\r\n<\/pre>\n<p>We can modify this to include an iPXE version check:<\/p>\n<pre class=\"brush: plain; highlight: [3]; title: boot.ipxe; notranslate\" title=\"boot.ipxe\">\r\n#!ipxe\r\n\r\nchain --autofree version_check.ipxe ||\r\n\r\necho Booting Linux...\r\nkernel your-kernel-image.img\r\ninitrd your-initramfs.img\r\n\r\nboot\r\n<\/pre>\n<p>The version check might look like something similar to this (<a href=\"https:\/\/gist.github.com\/robinsmidsrod\/4008017?permalink_comment_id=3384989#gistcomment-3384989\">source<\/a>):<\/p>\n<pre class=\"brush: plain; highlight: [7]; title: version_check.ipxe; notranslate\" title=\"version_check.ipxe\">\r\n#!ipxe\r\n\r\n# Figure out if client is 64-bit capable\r\ncpuid --ext 29 &amp;&amp; set arch x64 || set arch x86\r\ncpuid --ext 29 &amp;&amp; set archl amd64 || set archl i386\r\n\r\nset latest_version 1.21.1+ (g6ba67)\r\necho ${cls}\r\niseq ${version} ${latest_version} &amp;&amp; exit ||\r\necho\r\necho Updated version of iPXE is available:\r\necho\r\necho Running version.....${version}\r\necho Updated version.....${latest_version}\r\necho\r\necho Attempting to chain to latest version...\r\n\r\niseq ${platform} efi &amp;&amp; goto is_efi || goto not_efi\r\n\r\n:is_efi\r\niseq ${archl} amd64 &amp;&amp; chain --autofree ${boot-url}ipxe-x86_64-fixed.efi || chain --autofree ${boot-url}ipxe-i386-fixed.efi\r\n\r\n:not_efi\r\nchain --autofree ${boot-url}undionly-fixed.kpxe ||\r\n<\/pre>\n<p>Of course, one needs to ensure that the server at <code>boot-url<\/code> hands out the fixed versions of the iPXE roms.<\/p>\n<p><center><a data-rokbox href=\"wordpress\/wp-content\/uploads\/2022\/02\/iPXE-iPXE-chainloading.png\" data-rokbox-album=\"p2718\" ><img decoding=\"async\" src=\"wordpress\/wp-content\/uploads\/2022\/02\/iPXE-iPXE-chainloading.png\" alt=\"\" \/><\/a><br \/>iPXE chainloading an updated version via iPXE script<\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>These days, quite a few devices already come with built-in iPXE support: Some hypervisors (qemu, Proxmox, VMWare, VirtulBox, etc.) support iPXE right out of the gate but there&#8217;s also an increasing number of network equipment vendors that sell network interface cards with bundled iPXE support. But what if the bundled iPXE firmware is out of date and\/or lacking a relevant&#8230; <a href=\"https:\/\/possiblelossofprecision.net\/?p=2718\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[58,85],"class_list":["post-2718","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-hardware","tag-pxe"],"_links":{"self":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2718","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2718"}],"version-history":[{"count":23,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2718\/revisions"}],"predecessor-version":[{"id":2743,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=\/wp\/v2\/posts\/2718\/revisions\/2743"}],"wp:attachment":[{"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2718"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2718"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/possiblelossofprecision.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2718"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}