From e8e355c8668a9c89b308aafda491efd66a8d601c Mon Sep 17 00:00:00 2001 From: MSVSphere Packaging Team Date: Tue, 26 Nov 2024 16:17:08 +0300 Subject: [PATCH] import grub2-2.06-127.el10 --- .gitignore | 4 + .grub2.metadata | 4 + ...-Fix-user-facing-typo-with-an-incorr.patch | 24 + ...-Properly-disable-the-os-prober-by-d.patch | 71 + ...tes-Disable-the-os-prober-by-default.patch | 70 + ...d-support-for-Linux-EFI-stub-loading.patch | 983 ++ SOURCES/0005-Rework-linux-command.patch | 109 + SOURCES/0006-Rework-linux16-command.patch | 99 + ...ecureboot-support-on-efi-chainloader.patch | 1401 +++ ...loaders-that-link-in-efi-mode-honor-.patch | 390 + ...rch-64-on-32-boot-in-linuxefi-loader.patch | 264 + SOURCES/0010-re-write-.gitignore.patch | 246 + ...ient-architecture-CAS-reboot-support.patch | 176 + ...nsole-display-attr-when-clear-screen.patch | 31 + ...video-support-for-IBM-power-machines.patch | 65 + ...4-Move-bash-completion-script-922997.patch | 52 + ...o-include-entries-by-title-not-just-.patch | 140 + .../0016-Make-exit-take-a-return-code.patch | 267 + ...es-load-an-env-block-from-a-variable.patch | 89 + ...018-Migrate-PPC-from-Yaboot-to-Grub2.patch | 154 + .../0019-Add-fw_path-variable-revised.patch | 81 + ...-hex-hex-straight-through-unmolested.patch | 173 + ...g-module-to-parse-Boot-Loader-Specif.patch | 1609 +++ SOURCES/0022-Add-devicetree-loading.patch | 68 + ...0023-Enable-pager-by-default.-985860.patch | 23 + ...n-t-say-GNU-Linux-in-generated-menus.patch | 85 + ...rame-to-list-of-relocations-stripped.patch | 22 + ...password-to-boot-entries-generated-b.patch | 28 + ...ix-when-fallback-searching-for-grub-.patch | 41 + ...-before-grub.cfg-on-tftp-config-file.patch | 127 + ...CLASS-in-10_linux-from-etc-os-releas.patch | 29 + ...t-ordering-for-.debug-and-rescue-ker.patch | 30 + ...1-Try-prefix-if-fw_path-doesn-t-work.patch | 222 + ...fig-construct-titles-that-look-like-.patch | 69 + ...ly-grub2-password-config-tool-985962.patch | 245 + .../0034-tcp-add-window-scaling-support.patch | 87 + ...net-and-bootp-add-support-for-dhcpv6.patch | 651 ++ ...rnel-settings-and-use-it-in-10_linux.patch | 271 + ...1374141-fix-incorrect-mask-for-ppc64.patch | 48 + .../0038-Make-grub_fatal-also-backtrace.patch | 172 + ...fo-pages-say-grub2-where-appropriate.patch | 1008 ++ ...-chainloader-entries-don-t-try-any-x.patch | 124 + ...-Add-ability-to-boot-from-subvolumes.patch | 703 ++ ...port-btrfs_subvol-and-btrfs_subvolid.patch | 26 + .../0043-grub2-btrfs-03-follow_default.patch | 198 + .../0044-grub2-btrfs-04-grub2-install.patch | 176 + .../0045-grub2-btrfs-05-grub2-mkconfig.patch | 129 + .../0046-grub2-btrfs-06-subvol-mount.patch | 539 + ...subvol-name-scheme-to-support-old-sn.patch | 58 + ...-correctly-with-btrfs-snapshots-bsc-.patch | 274 + ...ocate_pool-and-grub_efi_free_pool-wr.patch | 72 + ...fi_.-memory-helpers-where-reasonable.patch | 106 + ...1-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch | 48 + .../0052-don-t-use-int-for-efi-status.patch | 22 + ...INIT-declare-its-function-prototypes.patch | 29 + ...-efi-as-HFS-on-ppc-machines-in-grub-.patch | 41 + ...d-xen-or-multiboot-2-modules-as-need.patch | 47 + ...-calibration-not-take-51-seconds-to-.patch | 211 + ...057-align-struct-efi_variable-better.patch | 33 + ...058-Add-BLS-support-to-grub-mkconfig.patch | 382 + ...-backtrace-on-grub_abort-for-grub-em.patch | 26 + SOURCES/0060-Add-grub2-switch-to-blscfg.patch | 395 + SOURCES/0061-make-better-backtraces.patch | 910 ++ ...w-our-startup-message-if-debug-is-se.patch | 23 + ...-some-minor-include-path-weirdnesses.patch | 137 + ...it-possible-to-enabled-build-id-sha1.patch | 61 + ...f-grub_dprintf-without-the-file-line.patch | 56 + ...dprintf-that-tells-us-load-addresses.patch | 178 + SOURCES/0067-Fixup-for-newer-compiler.patch | 36 + ...-export-the-start-and-_start-symbols.patch | 42 + SOURCES/0069-Fixup-for-newer-compiler.patch | 22 + ...pport-for-non-Ethernet-network-cards.patch | 766 ++ ...racketed-ipv6-addrs-and-port-numbers.patch | 270 + .../0072-bootp-New-net_bootp6-command.patch | 1368 +++ .../0073-efinet-UEFI-IPv6-PXE-support.patch | 126 + ...074-grub.texi-Add-net_bootp6-doument.patch | 48 + ...essing-DHCPACK-packet-from-HTTP-Boot.patch | 108 + ...etting-network-from-UEFI-device-path.patch | 405 + ...etting-DNS-server-from-UEFI-protocol.patch | 336 + ...78-Support-UEFI-networking-protocols.patch | 5053 ++++++++++ .../0079-AUDIT-0-http-boot-tracker-bug.patch | 62 + ...-incr-command-to-increment-integer-v.patch | 93 + SOURCES/0081-Add-auto-hide-menu-support.patch | 183 + .../0082-Add-grub-set-bootflag-utility.patch | 290 + ...b-boot-indeterminate.service-example.patch | 33 + SOURCES/0084-gentpl-add-disable-support.patch | 46 + .../0085-gentpl-add-pc-firmware-type.patch | 22 + ...e-the-firmware-acceleration-for-http.patch | 25 + ...ot_url-reflect-the-protocol-hostname.patch | 50 + ...n-tell-configure-which-cflags-utils-.patch | 149 + ...make-it-possible-to-run-checkers-on-.patch | 58 + ...90-Rework-how-the-fdt-command-builds.patch | 123 + ...able-non-wordsize-allocations-on-arm.patch | 41 + ...nd-prefix-when-HTTP-path-is-relative.patch | 152 + .../0093-Make-grub_error-more-verbose.patch | 61 + ...eset-an-alias-for-the-reboot-command.patch | 40 + SOURCES/0095-Add-a-version-command.patch | 134 + ...dprintf-and-nerf-dprintf-in-script.c.patch | 74 + ...-Better-memory-allocation-and-error-.patch | 279 + ...tter-locations-for-kernel-and-initrd.patch | 211 + ...p-all-the-places-Wsign-compare-error.patch | 199 + ...gn-compare-Wno-conversion-Wno-error-.patch | 59 + ...ce-buffers-for-reading-to-addresses-.patch | 101 + ...-arrange-grub_cmd_linux-a-little-bit.patch | 133 + ...e-our-own-allocator-for-kernel-stuff.patch | 258 + ...itrd-params-cmdline-allocations-abov.patch | 171 + .../0105-Fix-getroot.c-s-trampolines.patch | 47 + ...not-allow-stack-trampolines-anywhere.patch | 38 + SOURCES/0107-Reimplement-boot_counter.patch | 196 + ...ntry-selection-based-on-ID-and-title.patch | 233 + ...try-users-option-argument-to-be-opti.patch | 46 + ...export-env-and-efi-load-env-commands.patch | 346 + ...le-to-subtract-conditions-from-debug.patch | 45 + ...bles-from-the-initial-context-when-c.patch | 44 + ...-boot-success-reset-from-menu-auto-h.patch | 168 + ...t-boot-commands-will-only-return-on-.patch | 97 + ...g-Update-comment-about-running-as-ro.patch | 27 + ...g-Write-new-env-to-tmpfile-and-then-.patch | 152 + ...indeterminate-getting-set-on-boot_su.patch | 81 + .../0118-Add-start-symbol-for-RISC-V.patch | 28 + ...conf-Force-autogen.sh-to-use-python3.patch | 33 + ...fw-http-_path-variables-to-make-them.patch | 50 + ...-literal-IPv6-addresses-in-square-br.patch | 114 + ...o-specify-a-port-number-in-addresses.patch | 48 + ...mprove-check-to-detect-literal-IPv6-.patch | 48 + ...debug-message-if-parsing-the-address.patch | 68 + ...so-accept-F8-as-a-user-interrupt-key.patch | 30 + ...se-address-before-jumping-to-the-PE-.patch | 62 + ...ate-TPM-measurement-errors-to-the-ve.patch | 62 + ...maximum-bounce-buffer-size-to-16-MiB.patch | 40 + ...fix-when-the-HTTP-path-is-relative-a.patch | 47 + ...turn-in-efi-export-env-and-efi-load-.patch | 27 + ...p-fix-some-allocation-error-checking.patch | 37 + ...p-fix-some-allocation-error-checking.patch | 39 + ...g.c-fix-some-potential-allocation-ov.patch | 127 + ...integer-overflows-in-grub_cmd_initrd.patch | 49 + ...rnel-validation-without-shim-protoco.patch | 130 + ...ar-pointers-in-grub-core-net-bootp.c.patch | 37 + ...ointers-in-grub-core-net-efi-ip4_con.patch | 38 + ...ointers-in-grub-core-net-efi-ip6_con.patch | 28 + ...-pointers-in-grub-core-net-efi-net.c.patch | 37 + ...-pointers-in-grub-core-net-efi-pxe.c.patch | 46 + ...gration-scripts-to-make-systemctl-re.patch | 190 + ...ion.sh-Also-set-old-menu_show_once-g.patch | 32 + ...set-1-when-keyboard-is-in-Translate-.patch | 121 + ...ll-disable-support-for-EFI-platforms.patch | 101 + ...imestamps-configure-flag-to-prepend-.patch | 112 + ...ements-to-grub_disk_open-and-grub_di.patch | 47 + ...on-grub_debug_is_enabled-void-return.patch | 51 + ...ear-screen-when-debugging-is-enabled.patch | 31 + ...Fix-error-handling-in-grub_file_open.patch | 34 + ..._-instrumentation-new-file-debug-tag.patch | 71 + ...-Avoiding-many-unecessary-open-close.patch | 136 + ...-implements-fibre-channel-discovery-.patch | 90 + ...erpc-enables-device-mapper-discovery.patch | 106 + ...fallback_set-var-to-force-the-set-ma.patch | 245 + ...igning-grub-with-an-appended-signatu.patch | 309 + ...rub-Document-signing-grub-under-UEFI.patch | 61 + ...nt-signing-grub-with-an-appended-sig.patch | 67 + ...e-grub_dl_set_persistent-for-the-emu.patch | 44 + SOURCES/0159-pgp-factor-out-rsa_pad.patch | 191 + ...rage-for-grub_crypto_pk_-to-crypto.c.patch | 71 + ...p-tweaks-in-preparation-for-libtasn1.patch | 64 + ...0162-libtasn1-import-libtasn1-4.16.0.patch | 8934 +++++++++++++++++ ...asn1-disable-code-not-needed-in-grub.patch | 307 + ...tasn1-changes-for-grub-compatibility.patch | 202 + ...65-libtasn1-compile-into-asn1-module.patch | 70 + ...6-test_asn1-test-module-for-libtasn1.patch | 1457 +++ ...-support-embedding-x509-certificates.patch | 253 + ...res-import-GNUTLS-s-ASN.1-descriptio.patch | 639 ++ ...res-parse-PKCS-7-signedData-and-X.50.patch | 1528 +++ ...res-support-verifying-appended-signa.patch | 718 ++ ...pended-signatures-verification-tests.patch | 897 ++ ...72-appended-signatures-documentation.patch | 341 + ...er-lockdown-based-on-ibm-secure-boot.patch | 109 + ...275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch | 75 + ...-Also-handle-the-Extended-Key-Usage-.patch | 315 + ...eee1275-ofdisk-retry-on-open-failure.patch | 103 + ...ainloading-EFI-apps-from-loop-mounts.patch | 138 + .../0178-efinet-Add-DHCP-proxy-support.patch | 53 + ...gnore-checksum-seed-incompat-feature.patch | 54 + ...-cmdline-when-generating-legacy-menu.patch | 36 + .../0181-Suppress-gettext-error-message.patch | 33 + ...d-Always-use-boot-grub2-user.cfg-as-.patch | 42 + ...for-EFI-at-runtime-instead-of-config.patch | 63 + ...or-if-boot-to-firmware-setup-is-not-.patch | 92 + ...x-EFI-loader-kernel-image-allocation.patch | 218 + ...over-the-device-to-read-the-config-f.patch | 123 + ...etting-of-prefix-for-signed-binary-c.patch | 88 + ...adable-filesystem-with-v4-superblock.patch | 118 + ...module-name-on-license-check-failure.patch | 48 + ...pc-ieee1275-load-grub-at-4MB-not-2MB.patch | 106 + ...-mkconfig-restore-umask-for-grub.cfg.patch | 40 + ...btrfs-Use-full-btrfs-bootloader-area.patch | 160 + ...-Fedora-location-of-DejaVu-SANS-font.patch | 30 + ...t-show-Booting-s-msg-when-auto-booti.patch | 90 + ...-Welcome-to-GRUB-message-in-EFI-buil.patch | 41 + ...ot-set-colorstate-until-the-first-te.patch | 51 + ...ot-set-cursor-until-the-first-text-o.patch | 71 + ...se-visual-indentation-in-config.h.in.patch | 93 + ...sure-config-util.h-precedes-config.h.patch | 275 + .../0200-Drop-gnulib-fix-base64.patch.patch | 140 + SOURCES/0201-Drop-gnulib-no-abort.patch.patch | 97 + ...version-and-drop-most-gnulib-patches.patch | 832 ++ ...Fix-bug-stopping-iteration-when-no-f.patch | 33 + ...w-efidisk-only-option-on-EFI-systems.patch | 168 + SOURCES/0205-efi-new-connectefi-command.patch | 395 + ...-i386-efi-linux.c-do-not-validate-ke.patch | 73 + ...-arm64-linux.c-do-not-validate-kerne.patch | 58 + ...-efi-chainloader.c-do-not-validate-c.patch | 80 + ...-efi-linux.c-drop-now-unused-grub_li.patch | 83 + ...etection-support-device-names-with-c.patch | 71 + .../0211-make-ofdisk_retries-optional.patch | 43 + ...loader-grub_load_and_start_image-doe.patch | 69 + ...hainloader-simplify-the-loader-state.patch | 330 + ...ot-Add-API-to-pass-context-to-loader.patch | 158 + ...i-chainloader-Use-grub_loader_set_ex.patch | 147 + ...linux-Avoid-a-use-after-free-in-the-.patch | 41 + ...386-efi-linux-Use-grub_loader_set_ex.patch | 296 + ...linux-Fix-a-memory-leak-in-the-initr.patch | 75 + ...ct-non-kernel-files-in-the-shim_lock.patch | 101 + ...-leak-device_name-on-error-in-grub_f.patch | 39 + ...g-Abort-sooner-if-a-read-operation-f.patch | 198 + ...g-Refuse-to-handle-multiple-image-he.patch | 28 + ...g-Drop-greyscale-support-to-fix-heap.patch | 170 + ...g-Avoid-heap-OOB-R-W-inserting-huff-.patch | 40 + ...-png-Sanity-check-some-huffman-codes.patch | 40 + ...eg-Abort-sooner-if-a-read-operation-.patch | 255 + ...eg-Do-not-reallocate-a-given-huff-ta.patch | 29 + ...eg-Refuse-to-handle-multiple-start-o.patch | 44 + ...eg-Block-int-underflow-wild-pointer-.patch | 53 + ...ix-array-out-of-bounds-formatting-un.patch | 34 + ...ff-Block-overly-large-netbuff-allocs.patch | 46 + ...2-net-ip-Do-IP-fragment-maths-safely.patch | 44 + ...le-free-addresses-on-corrupt-DNS-res.patch | 56 + ...ad-past-the-end-of-the-string-we-re-.patch | 71 + ...-a-UAF-and-double-free-from-a-failed.patch | 112 + .../0236-net-tftp-Avoid-a-trivial-UAF.patch | 35 + ...tear-down-socket-if-it-s-already-bee.patch | 42 + ...Fix-OOB-write-for-split-http-headers.patch | 46 + ...or-out-on-headers-with-LF-without-CR.patch | 48 + ...ead-past-the-end-of-nat-journal-entr.patch | 72 + ...-not-read-past-the-end-of-nat-bitmap.patch | 132 + ...ot-copy-file-names-that-are-too-long.patch | 38 + ...eral-fuzz-issues-with-invalid-dir-it.patch | 79 + ...e-ASAN-and-SEGV-issues-found-with-fu.patch | 134 + ...x-more-fuzz-issues-related-to-chunks.patch | 75 + ...grub_min-and-grub_max-more-resilient.patch | 83 + ...FS-switch-to-using-grub_min-grub_max.patch | 92 + ...oot_time-also-call-grub_dprintf-boot.patch | 46 + ...dules-make-.module_license-read-only.patch | 30 + ...p-.llvm_addrsig-sections-and-similar.patch | 39 + ...locate-space-for-non-allocable-secti.patch | 35 + ...eader-struct-and-fix-some-bad-naming.patch | 81 + ...nel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch | 85 + ...ule-sections-at-page-aligned-address.patch | 378 + ...-nx-add-memory-attribute-get-set-API.patch | 317 + ...-page-permissions-for-loaded-modules.patch | 263 + ...7-nx-set-attrs-in-our-kernel-loaders.patch | 565 ++ ...x-compatible-flag-in-EFI-grub-images.patch | 34 + ...-document-the-behavior-of-multiple-v.patch | 25 + ...probe-dprint-errors-from-filesystems.patch | 43 + ...1-fs-fat-don-t-error-when-mtime-is-0.patch | 64 + ...file-show-which-file-filters-get-run.patch | 45 + ...ed-array-positions-for-our-allocatio.patch | 81 + ...tion-policy-for-kernel-vs-initrd-mem.patch | 127 + ...-initrd-within-the-bounds-expressed-.patch | 57 + ...ER_-CODE-DATA-for-kernel-and-initrd-.patch | 61 + ...e-etc-kernel-cmdline-during-mkconfig.patch | 27 + ...sh-don-t-dup-rhgb-quiet-check-mtimes.patch | 35 + .../0269-squish-give-up-on-rhgb-quiet.patch | 25 + ...write-etc-kernel-cmdline-if-writable.patch | 57 + ...scfg-Don-t-root-device-in-emu-builds.patch | 27 + ...ux-Remove-magic-number-header-field-.patch | 43 + .../0273-Correct-BSS-zeroing-on-aarch64.patch | 95 + ...ate-i-cache-before-starting-the-kern.patch | 39 + ...ncorrect-array-size-in-kernel-alloca.patch | 36 + ...i-tpm-Refine-the-status-of-log-event.patch | 42 + ...-Use-grub_strcpy-instead-of-grub_mem.patch | 37 + ...-EFI_CC_MEASUREMENT_PROTOCOL-support.patch | 258 + ...hs-exceeds-font-max_glyph_width-or-f.patch | 31 + ...erflow-in-grub_font_get_glyph_intern.patch | 110 + ...-integer-overflows-in-grub_font_cons.patch | 79 + ...0282-font-Remove-grub_font_dup_glyph.patch | 40 + ...nteger-overflow-in-ensure_comb_space.patch | 46 + ...nt-Fix-integer-overflow-in-BMP-index.patch | 63 + ...-underflow-in-binary-search-of-char-.patch | 83 + ...b-Enforce-verification-of-font-files.patch | 52 + .../0287-fbutil-Fix-integer-overflow.patch | 83 + ...ix-an-integer-underflow-in-blit_comb.patch | 89 + ..._font_blit_glyph-and-grub_font_blit_.patch | 73 + ...l_font-to-glyphs-in-ascii_font_glyph.patch | 34 + ...ix-an-integer-overflow-in-grub_unico.patch | 53 + ...ening-fonts-from-the-bundled-memdisk.patch | 78 + .../0293-mm-Clarify-grub_real_malloc.patch | 183 + ...loc-Make-small-allocs-comment-match-.patch | 32 + SOURCES/0295-mm-Document-grub_free.patch | 120 + ...0296-mm-Document-grub_mm_init_region.patch | 73 + ...-internal-memory-management-structur.patch | 78 + ...e-preserve-header-vs-region-alignmen.patch | 56 + ...-region-merge-with-region-after-as-w.patch | 203 + ...-Debug-support-for-region-operations.patch | 71 + ...p-unused-unloading-of-modules-on-OOM.patch | 80 + ...ally-requesting-additional-memory-re.patch | 130 + ...ys-request-a-fixed-number-of-pages-o.patch | 103 + ...tract-function-to-add-memory-regions.patch | 85 + ...ss-up-errors-from-add_memory_regions.patch | 87 + ...-Implement-runtime-addition-of-pages.patch | 75 + ...-default-memory-allocation-to-32-MiB.patch | 31 + ...e-disk-caches-last-when-out-of-memor.patch | 57 + ...09-ppc64le-signed-boot-media-changes.patch | 125 + ...veral-implicit-function-declarations.patch | 54 + ...rt-for-grub-emu-to-kexec-Linux-menu-.patch | 431 + ...n-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch | 111 + ...-memory-with-ibm-client-architecture.patch | 308 + ...ee1275-drop-len-1-quirk-in-heap_init.patch | 36 + ...1275-support-runtime-memory-claiming.patch | 435 + ...5-implement-vec5-for-cas-negotiation.patch | 74 + ...ort-for-trusted-boot-using-a-vTPM-2..patch | 246 + .../0318-powerpc-Drop-Open-Hack-Ware.patch | 69 + ...disk-Modify-sector-by-sysfs-as-disk-.patch | 70 + ...gion-size-to-take-management-overhea.patch | 145 + ...e-some-space-when-adding-new-regions.patch | 53 + ...complex-heap-growth-math-in-hot-path.patch | 72 + ...-work-around-proc-not-reporting-size.patch | 93 + ...blscfg-check-for-mounted-boot-in-emu.patch | 118 + ...ork-around-systemctl-kexec-returning.patch | 41 + ...it-Convert-plain-numbers-to-constant.patch | 48 + ...ee1275-init-Extended-support-in-Vec5.patch | 127 + ...tpm-verifier-if-the-TPM-device-is-no.patch | 156 + ...b_dl_set_mem_attrs-fix-format-string.patch | 38 + ...attrs-add-self-check-for-the-tramp-G.patch | 140 + ...ments-page-align-the-tramp-GOT-areas.patch | 70 + ...0332-emu-Add-switch-root-to-grub-emu.patch | 330 + ...il-Enable-default-kernel-for-updates.patch | 34 + ...-efi-http-change-uint32_t-to-uintn_t.patch | 30 + ...Install-section-to-aux-systemd-units.patch | 52 + ...er-memory-type-for-kernel-allocation.patch | 44 + ...0337-Fix-missing-include-in-ofdisk.c.patch | 28 + ...it-ppc64-Restrict-high-memory-in-pre.patch | 226 + .../0339-grub-install-on-EFI-if-forced.patch | 77 + ...stall-section-from-aux-systemd-units.patch | 33 + .../0341-fs-Remove-trailing-whitespaces.patch | 1681 ++++ ...s-xfs-Fix-memory-leaks-in-XFS-module.patch | 47 + ...s-found-while-fuzzing-the-XFS-filesy.patch | 106 + ...-short-form-directory-data-boundary-.patch | 47 + ...-extent-counters-incompat-feature-su.patch | 115 + ...der-remove-device-path-debug-message.patch | 28 + ...ub_env_set-prefix-in-grub_try_normal.patch | 27 + ...348-add-flag-to-only-search-root-dev.patch | 160 + ...nore-warnings-for-incompatible-types.patch | 28 + ...xfs-Fix-XFS-directory-extent-parsing.patch | 168 + ...nsure-grub-cfg-stub-is-not-overwritt.patch | 40 + ...-mkconfig-Simplify-os_name-detection.patch | 30 + ...move-check-for-mount-point-for-grub-.patch | 29 + ...dont-overwrite-BLS-cmdline-if-BLSCFG.patch | 72 + ...ass-all-boot-params-when-used-by-ana.patch | 32 + ...g-Conservative-partial-fix-for-CVE-2.patch | 146 + ...g-More-complete-fix-for-CVE-2024-104.patch | 187 + ...g-Exit-calmly-when-not-running-as-ro.patch | 36 + ...OB-write-when-parsing-the-ATTRIBUTE_.patch | 90 + ...OB-read-when-reading-data-from-the-r.patch | 55 + ...OB-read-when-parsing-directory-entri.patch | 70 + ...OB-read-when-parsing-bitmaps-for-ind.patch | 48 + ...OOB-read-when-parsing-a-volume-label.patch | 58 + ...0364-fs-ntfs-Make-code-more-readable.patch | 156 + ...d-search-Rework-of-CVE-2023-4001-fix.patch | 182 + ...fig.in-turn-off-executable-owner-bit.patch | 29 + SOURCES/20-grub.install | 211 + SOURCES/99-grub-mkconfig.install | 59 + SOURCES/bootstrap | 1073 ++ SOURCES/bootstrap.conf | 101 + SOURCES/gitignore | 277 + SOURCES/grub.macros | 739 ++ SOURCES/grub.patches | 366 + SOURCES/sbat.csv.in | 3 + SOURCES/strtoull_test.c | 63 + SPECS/grub2.spec | 2195 ++++ 378 files changed, 72857 insertions(+) create mode 100644 .gitignore create mode 100644 .grub2.metadata create mode 100644 SOURCES/0001-Revert-templates-Fix-user-facing-typo-with-an-incorr.patch create mode 100644 SOURCES/0002-Revert-templates-Properly-disable-the-os-prober-by-d.patch create mode 100644 SOURCES/0003-Revert-templates-Disable-the-os-prober-by-default.patch create mode 100644 SOURCES/0004-Add-support-for-Linux-EFI-stub-loading.patch create mode 100644 SOURCES/0005-Rework-linux-command.patch create mode 100644 SOURCES/0006-Rework-linux16-command.patch create mode 100644 SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch create mode 100644 SOURCES/0008-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch create mode 100644 SOURCES/0009-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch create mode 100644 SOURCES/0010-re-write-.gitignore.patch create mode 100644 SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch create mode 100644 SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch create mode 100644 SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch create mode 100644 SOURCES/0014-Move-bash-completion-script-922997.patch create mode 100644 SOURCES/0015-Allow-fallback-to-include-entries-by-title-not-just-.patch create mode 100644 SOURCES/0016-Make-exit-take-a-return-code.patch create mode 100644 SOURCES/0017-Make-efi-machines-load-an-env-block-from-a-variable.patch create mode 100644 SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch create mode 100644 SOURCES/0019-Add-fw_path-variable-revised.patch create mode 100644 SOURCES/0020-Pass-x-hex-hex-straight-through-unmolested.patch create mode 100644 SOURCES/0021-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch create mode 100644 SOURCES/0022-Add-devicetree-loading.patch create mode 100644 SOURCES/0023-Enable-pager-by-default.-985860.patch create mode 100644 SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch create mode 100644 SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch create mode 100644 SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch create mode 100644 SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch create mode 100644 SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch create mode 100644 SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch create mode 100644 SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch create mode 100644 SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch create mode 100644 SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch create mode 100644 SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch create mode 100644 SOURCES/0034-tcp-add-window-scaling-support.patch create mode 100644 SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch create mode 100644 SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch create mode 100644 SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch create mode 100644 SOURCES/0038-Make-grub_fatal-also-backtrace.patch create mode 100644 SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch create mode 100644 SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch create mode 100644 SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch create mode 100644 SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch create mode 100644 SOURCES/0043-grub2-btrfs-03-follow_default.patch create mode 100644 SOURCES/0044-grub2-btrfs-04-grub2-install.patch create mode 100644 SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch create mode 100644 SOURCES/0046-grub2-btrfs-06-subvol-mount.patch create mode 100644 SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch create mode 100644 SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch create mode 100644 SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch create mode 100644 SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch create mode 100644 SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch create mode 100644 SOURCES/0052-don-t-use-int-for-efi-status.patch create mode 100644 SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch create mode 100644 SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch create mode 100644 SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch create mode 100644 SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch create mode 100644 SOURCES/0057-align-struct-efi_variable-better.patch create mode 100644 SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch create mode 100644 SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch create mode 100644 SOURCES/0060-Add-grub2-switch-to-blscfg.patch create mode 100644 SOURCES/0061-make-better-backtraces.patch create mode 100644 SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch create mode 100644 SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch create mode 100644 SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch create mode 100644 SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch create mode 100644 SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch create mode 100644 SOURCES/0067-Fixup-for-newer-compiler.patch create mode 100644 SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch create mode 100644 SOURCES/0069-Fixup-for-newer-compiler.patch create mode 100644 SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch create mode 100644 SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch create mode 100644 SOURCES/0072-bootp-New-net_bootp6-command.patch create mode 100644 SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch create mode 100644 SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch create mode 100644 SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch create mode 100644 SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch create mode 100644 SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch create mode 100644 SOURCES/0078-Support-UEFI-networking-protocols.patch create mode 100644 SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch create mode 100644 SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch create mode 100644 SOURCES/0081-Add-auto-hide-menu-support.patch create mode 100644 SOURCES/0082-Add-grub-set-bootflag-utility.patch create mode 100644 SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch create mode 100644 SOURCES/0084-gentpl-add-disable-support.patch create mode 100644 SOURCES/0085-gentpl-add-pc-firmware-type.patch create mode 100644 SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch create mode 100644 SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch create mode 100644 SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch create mode 100644 SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch create mode 100644 SOURCES/0090-Rework-how-the-fdt-command-builds.patch create mode 100644 SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch create mode 100644 SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch create mode 100644 SOURCES/0093-Make-grub_error-more-verbose.patch create mode 100644 SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch create mode 100644 SOURCES/0095-Add-a-version-command.patch create mode 100644 SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch create mode 100644 SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch create mode 100644 SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch create mode 100644 SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch create mode 100644 SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch create mode 100644 SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch create mode 100644 SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch create mode 100644 SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch create mode 100644 SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch create mode 100644 SOURCES/0105-Fix-getroot.c-s-trampolines.patch create mode 100644 SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch create mode 100644 SOURCES/0107-Reimplement-boot_counter.patch create mode 100644 SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch create mode 100644 SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch create mode 100644 SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch create mode 100644 SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch create mode 100644 SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch create mode 100644 SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch create mode 100644 SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch create mode 100644 SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch create mode 100644 SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch create mode 100644 SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch create mode 100644 SOURCES/0118-Add-start-symbol-for-RISC-V.patch create mode 100644 SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch create mode 100644 SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch create mode 100644 SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch create mode 100644 SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch create mode 100644 SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch create mode 100644 SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch create mode 100644 SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch create mode 100644 SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch create mode 100644 SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch create mode 100644 SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch create mode 100644 SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch create mode 100644 SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch create mode 100644 SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch create mode 100644 SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch create mode 100644 SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch create mode 100644 SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch create mode 100644 SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch create mode 100644 SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch create mode 100644 SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch create mode 100644 SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch create mode 100644 SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch create mode 100644 SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch create mode 100644 SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch create mode 100644 SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch create mode 100644 SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch create mode 100644 SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch create mode 100644 SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch create mode 100644 SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch create mode 100644 SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch create mode 100644 SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch create mode 100644 SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch create mode 100644 SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch create mode 100644 SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch create mode 100644 SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch create mode 100644 SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch create mode 100644 SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch create mode 100644 SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch create mode 100644 SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch create mode 100644 SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch create mode 100644 SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch create mode 100644 SOURCES/0159-pgp-factor-out-rsa_pad.patch create mode 100644 SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch create mode 100644 SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch create mode 100644 SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch create mode 100644 SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch create mode 100644 SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch create mode 100644 SOURCES/0165-libtasn1-compile-into-asn1-module.patch create mode 100644 SOURCES/0166-test_asn1-test-module-for-libtasn1.patch create mode 100644 SOURCES/0167-grub-install-support-embedding-x509-certificates.patch create mode 100644 SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch create mode 100644 SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch create mode 100644 SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch create mode 100644 SOURCES/0171-appended-signatures-verification-tests.patch create mode 100644 SOURCES/0172-appended-signatures-documentation.patch create mode 100644 SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch create mode 100644 SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch create mode 100644 SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch create mode 100644 SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch create mode 100644 SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch create mode 100644 SOURCES/0178-efinet-Add-DHCP-proxy-support.patch create mode 100644 SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch create mode 100644 SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch create mode 100644 SOURCES/0181-Suppress-gettext-error-message.patch create mode 100644 SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch create mode 100644 SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch create mode 100644 SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch create mode 100644 SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch create mode 100644 SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch create mode 100644 SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch create mode 100644 SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch create mode 100644 SOURCES/0189-Print-module-name-on-license-check-failure.patch create mode 100644 SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch create mode 100644 SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch create mode 100644 SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch create mode 100644 SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch create mode 100644 SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch create mode 100644 SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch create mode 100644 SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch create mode 100644 SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch create mode 100644 SOURCES/0198-Use-visual-indentation-in-config.h.in.patch create mode 100644 SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch create mode 100644 SOURCES/0200-Drop-gnulib-fix-base64.patch.patch create mode 100644 SOURCES/0201-Drop-gnulib-no-abort.patch.patch create mode 100644 SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch create mode 100644 SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch create mode 100644 SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch create mode 100644 SOURCES/0205-efi-new-connectefi-command.patch create mode 100644 SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch create mode 100644 SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch create mode 100644 SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch create mode 100644 SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch create mode 100644 SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch create mode 100644 SOURCES/0211-make-ofdisk_retries-optional.patch create mode 100644 SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch create mode 100644 SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch create mode 100644 SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch create mode 100644 SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch create mode 100644 SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch create mode 100644 SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch create mode 100644 SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch create mode 100644 SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch create mode 100644 SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch create mode 100644 SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch create mode 100644 SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch create mode 100644 SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch create mode 100644 SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch create mode 100644 SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch create mode 100644 SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch create mode 100644 SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch create mode 100644 SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch create mode 100644 SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch create mode 100644 SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch create mode 100644 SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch create mode 100644 SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch create mode 100644 SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch create mode 100644 SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch create mode 100644 SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch create mode 100644 SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch create mode 100644 SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch create mode 100644 SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch create mode 100644 SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch create mode 100644 SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch create mode 100644 SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch create mode 100644 SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch create mode 100644 SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch create mode 100644 SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch create mode 100644 SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch create mode 100644 SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch create mode 100644 SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch create mode 100644 SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch create mode 100644 SOURCES/0249-modules-make-.module_license-read-only.patch create mode 100644 SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch create mode 100644 SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch create mode 100644 SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch create mode 100644 SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch create mode 100644 SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch create mode 100644 SOURCES/0255-nx-add-memory-attribute-get-set-API.patch create mode 100644 SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch create mode 100644 SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch create mode 100644 SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch create mode 100644 SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch create mode 100644 SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch create mode 100644 SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch create mode 100644 SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch create mode 100644 SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch create mode 100644 SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch create mode 100644 SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch create mode 100644 SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch create mode 100644 SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch create mode 100644 SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch create mode 100644 SOURCES/0269-squish-give-up-on-rhgb-quiet.patch create mode 100644 SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch create mode 100644 SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch create mode 100644 SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch create mode 100644 SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch create mode 100644 SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch create mode 100644 SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch create mode 100644 SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch create mode 100644 SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch create mode 100644 SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch create mode 100644 SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch create mode 100644 SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch create mode 100644 SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch create mode 100644 SOURCES/0282-font-Remove-grub_font_dup_glyph.patch create mode 100644 SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch create mode 100644 SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch create mode 100644 SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch create mode 100644 SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch create mode 100644 SOURCES/0287-fbutil-Fix-integer-overflow.patch create mode 100644 SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch create mode 100644 SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch create mode 100644 SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch create mode 100644 SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch create mode 100644 SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch create mode 100644 SOURCES/0293-mm-Clarify-grub_real_malloc.patch create mode 100644 SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch create mode 100644 SOURCES/0295-mm-Document-grub_free.patch create mode 100644 SOURCES/0296-mm-Document-grub_mm_init_region.patch create mode 100644 SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch create mode 100644 SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch create mode 100644 SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch create mode 100644 SOURCES/0300-mm-Debug-support-for-region-operations.patch create mode 100644 SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch create mode 100644 SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch create mode 100644 SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch create mode 100644 SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch create mode 100644 SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch create mode 100644 SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch create mode 100644 SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch create mode 100644 SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch create mode 100644 SOURCES/0309-ppc64le-signed-boot-media-changes.patch create mode 100644 SOURCES/0310-core-Fix-several-implicit-function-declarations.patch create mode 100644 SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch create mode 100644 SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch create mode 100644 SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch create mode 100644 SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch create mode 100644 SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch create mode 100644 SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch create mode 100644 SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch create mode 100644 SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch create mode 100644 SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch create mode 100644 SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch create mode 100644 SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch create mode 100644 SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch create mode 100644 SOURCES/0323-hostdisk-work-around-proc-not-reporting-size.patch create mode 100644 SOURCES/0324-blscfg-check-for-mounted-boot-in-emu.patch create mode 100644 SOURCES/0325-emu-linux-work-around-systemctl-kexec-returning.patch create mode 100644 SOURCES/0326-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch create mode 100644 SOURCES/0327-kern-ieee1275-init-Extended-support-in-Vec5.patch create mode 100644 SOURCES/0328-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch create mode 100644 SOURCES/0329-grub_dl_set_mem_attrs-fix-format-string.patch create mode 100644 SOURCES/0330-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch create mode 100644 SOURCES/0331-grub_dl_load_segments-page-align-the-tramp-GOT-areas.patch create mode 100644 SOURCES/0332-emu-Add-switch-root-to-grub-emu.patch create mode 100644 SOURCES/0333-util-Enable-default-kernel-for-updates.patch create mode 100644 SOURCES/0334-efi-http-change-uint32_t-to-uintn_t.patch create mode 100644 SOURCES/0335-Add-Install-section-to-aux-systemd-units.patch create mode 100644 SOURCES/0336-arm64-Use-proper-memory-type-for-kernel-allocation.patch create mode 100644 SOURCES/0337-Fix-missing-include-in-ofdisk.c.patch create mode 100644 SOURCES/0338-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch create mode 100644 SOURCES/0339-grub-install-on-EFI-if-forced.patch create mode 100644 SOURCES/0340-Remove-Install-section-from-aux-systemd-units.patch create mode 100644 SOURCES/0341-fs-Remove-trailing-whitespaces.patch create mode 100644 SOURCES/0342-fs-xfs-Fix-memory-leaks-in-XFS-module.patch create mode 100644 SOURCES/0343-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch create mode 100644 SOURCES/0344-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch create mode 100644 SOURCES/0345-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch create mode 100644 SOURCES/0346-chainloader-remove-device-path-debug-message.patch create mode 100644 SOURCES/0347-normal-Remove-grub_env_set-prefix-in-grub_try_normal.patch create mode 100644 SOURCES/0348-add-flag-to-only-search-root-dev.patch create mode 100644 SOURCES/0349-Ignore-warnings-for-incompatible-types.patch create mode 100644 SOURCES/0350-fs-xfs-Fix-XFS-directory-extent-parsing.patch create mode 100644 SOURCES/0351-grub2-mkconfig-Ensure-grub-cfg-stub-is-not-overwritt.patch create mode 100644 SOURCES/0352-grub2-mkconfig-Simplify-os_name-detection.patch create mode 100644 SOURCES/0353-grub-mkconfig-Remove-check-for-mount-point-for-grub-.patch create mode 100644 SOURCES/0354-grub-mkconfig-dont-overwrite-BLS-cmdline-if-BLSCFG.patch create mode 100644 SOURCES/0355-grub2-mkconfig-Pass-all-boot-params-when-used-by-ana.patch create mode 100644 SOURCES/0356-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch create mode 100644 SOURCES/0357-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch create mode 100644 SOURCES/0358-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch create mode 100644 SOURCES/0359-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch create mode 100644 SOURCES/0360-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch create mode 100644 SOURCES/0361-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch create mode 100644 SOURCES/0362-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch create mode 100644 SOURCES/0363-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch create mode 100644 SOURCES/0364-fs-ntfs-Make-code-more-readable.patch create mode 100644 SOURCES/0365-cmd-search-Rework-of-CVE-2023-4001-fix.patch create mode 100644 SOURCES/0366-grub-mkconfig.in-turn-off-executable-owner-bit.patch create mode 100755 SOURCES/20-grub.install create mode 100755 SOURCES/99-grub-mkconfig.install create mode 100755 SOURCES/bootstrap create mode 100644 SOURCES/bootstrap.conf create mode 100644 SOURCES/gitignore create mode 100644 SOURCES/grub.macros create mode 100644 SOURCES/grub.patches create mode 100755 SOURCES/sbat.csv.in create mode 100644 SOURCES/strtoull_test.c create mode 100644 SPECS/grub2.spec diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dca6c5b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +SOURCES/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz +SOURCES/grub-2.06.tar.xz +SOURCES/theme.tar.bz2 +SOURCES/unifont-13.0.06.pcf.gz diff --git a/.grub2.metadata b/.grub2.metadata new file mode 100644 index 0000000..3b87954 --- /dev/null +++ b/.grub2.metadata @@ -0,0 +1,4 @@ +d08376d97163f99ce0d61fce160d6f7667c5c944 SOURCES/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz +c9f93f1e195ec7a5a21d36a13b469788c0b29f0f SOURCES/grub-2.06.tar.xz +cf0b7763c528902da7e8b05cfa248f20c8825ce5 SOURCES/theme.tar.bz2 +3b39cb0830367171760ec536cab805abdbe08bc5 SOURCES/unifont-13.0.06.pcf.gz diff --git a/SOURCES/0001-Revert-templates-Fix-user-facing-typo-with-an-incorr.patch b/SOURCES/0001-Revert-templates-Fix-user-facing-typo-with-an-incorr.patch new file mode 100644 index 0000000..4824aa1 --- /dev/null +++ b/SOURCES/0001-Revert-templates-Fix-user-facing-typo-with-an-incorr.patch @@ -0,0 +1,24 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Jun 2021 12:10:45 +0200 +Subject: [PATCH] Revert "templates: Fix user-facing typo with an incorrect use + of "it's"" + +This reverts commit 722737630889607c3b5761f1f5a48f1674cd2821. +--- + util/grub.d/30_os-prober.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 5984e92d29..9462248128 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -36,7 +36,7 @@ if ! command -v os-prober > /dev/null || ! command -v linux-boot-prober > /dev/n + exit 0 + fi + +-grub_warn "$(gettext_printf "os-prober will be executed to detect other bootable partitions.\nIts output will be used to detect bootable binaries on them and create new boot entries.")" ++grub_warn "$(gettext_printf "os-prober will be executed to detect other bootable partitions.\nIt's output will be used to detect bootable binaries on them and create new boot entries.")" + + OSPROBED="`os-prober | tr ' ' '^' | paste -s -d ' '`" + if [ -z "${OSPROBED}" ] ; then diff --git a/SOURCES/0002-Revert-templates-Properly-disable-the-os-prober-by-d.patch b/SOURCES/0002-Revert-templates-Properly-disable-the-os-prober-by-d.patch new file mode 100644 index 0000000..05ac0f8 --- /dev/null +++ b/SOURCES/0002-Revert-templates-Properly-disable-the-os-prober-by-d.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Jun 2021 12:10:54 +0200 +Subject: [PATCH] Revert "templates: Properly disable the os-prober by default" + +This reverts commit 54e0a1bbf1e9106901a557195bb35e5e20fb3925. +--- + util/grub-mkconfig.in | 5 +---- + util/grub.d/30_os-prober.in | 8 ++++---- + 2 files changed, 5 insertions(+), 8 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index f8cbb8d7a2..d3e879b8e5 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -140,9 +140,6 @@ GRUB_DEVICE_PARTUUID="`${grub_probe} --device ${GRUB_DEVICE} --target=partuuid 2 + GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`" + GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true + +-# Disable os-prober by default due to security reasons. +-GRUB_DISABLE_OS_PROBER="true" +- + # Filesystem for the device containing our userland. Used for stuff like + # choosing Hurd filesystem module. + GRUB_FS="`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2> /dev/null || echo unknown`" +@@ -204,7 +201,6 @@ export GRUB_DEVICE \ + GRUB_DEVICE_PARTUUID \ + GRUB_DEVICE_BOOT \ + GRUB_DEVICE_BOOT_UUID \ +- GRUB_DISABLE_OS_PROBER \ + GRUB_FS \ + GRUB_FONT \ + GRUB_PRELOAD_MODULES \ +@@ -246,6 +242,7 @@ export GRUB_DEFAULT \ + GRUB_BACKGROUND \ + GRUB_THEME \ + GRUB_GFXPAYLOAD_LINUX \ ++ GRUB_DISABLE_OS_PROBER \ + GRUB_INIT_TUNE \ + GRUB_SAVEDEFAULT \ + GRUB_ENABLE_CRYPTODISK \ +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 9462248128..80685b15f4 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -26,8 +26,8 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + +-if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then +- grub_warn "$(gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.")" ++if [ "x${GRUB_DISABLE_OS_PROBER}" = "xfalse" ]; then ++ gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.\n" + exit 0 + fi + +@@ -36,12 +36,12 @@ if ! command -v os-prober > /dev/null || ! command -v linux-boot-prober > /dev/n + exit 0 + fi + +-grub_warn "$(gettext_printf "os-prober will be executed to detect other bootable partitions.\nIt's output will be used to detect bootable binaries on them and create new boot entries.")" +- + OSPROBED="`os-prober | tr ' ' '^' | paste -s -d ' '`" + if [ -z "${OSPROBED}" ] ; then + # empty os-prober output, nothing doing + exit 0 ++else ++ grub_warn "$(gettext_printf "os-prober was executed to detect other bootable partitions.\nIt's output will be used to detect bootable binaries on them and create new boot entries.")" + fi + + osx_entry() { diff --git a/SOURCES/0003-Revert-templates-Disable-the-os-prober-by-default.patch b/SOURCES/0003-Revert-templates-Disable-the-os-prober-by-default.patch new file mode 100644 index 0000000..9492795 --- /dev/null +++ b/SOURCES/0003-Revert-templates-Disable-the-os-prober-by-default.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Jun 2021 12:10:58 +0200 +Subject: [PATCH] Revert "templates: Disable the os-prober by default" + +This reverts commit e346414725a70e5c74ee87ca14e580c66f517666. +--- + docs/grub.texi | 18 ++++++++---------- + util/grub.d/30_os-prober.in | 5 +---- + 2 files changed, 9 insertions(+), 14 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index f8b4b3b21a..69f08d289f 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1519,13 +1519,10 @@ boot sequence. If you have problems, set this option to @samp{text} and + GRUB will tell Linux to boot in normal text mode. + + @item GRUB_DISABLE_OS_PROBER +-The @command{grub-mkconfig} has a feature to use the external +-@command{os-prober} program to discover other operating systems installed on +-the same machine and generate appropriate menu entries for them. It is disabled +-by default since automatic and silent execution of @command{os-prober}, and +-creating boot entries based on that data, is a potential attack vector. Set +-this option to @samp{false} to enable this feature in the +-@command{grub-mkconfig} command. ++Normally, @command{grub-mkconfig} will try to use the external ++@command{os-prober} program, if installed, to discover other operating ++systems installed on the same system and generate appropriate menu entries ++for them. Set this option to @samp{true} to disable this. + + @item GRUB_OS_PROBER_SKIP_LIST + List of space-separated FS UUIDs of filesystems to be ignored from os-prober +@@ -1853,9 +1850,10 @@ than zero; otherwise 0. + @section Multi-boot manual config + + Currently autogenerating config files for multi-boot environments depends on +-os-prober and has several shortcomings. Due to that it is disabled by default. +-It is advised to use the power of GRUB syntax and do it yourself. A possible +-configuration is detailed here, feel free to adjust to your needs. ++os-prober and has several shortcomings. While fixing it is scheduled for the ++next release, meanwhile you can make use of the power of GRUB syntax and do it ++yourself. A possible configuration is detailed here, feel free to adjust to your ++needs. + + First create a separate GRUB partition, big enough to hold GRUB. Some of the + following entries show how to load OS installer images from this same partition, +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 80685b15f4..1b91c102f3 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -26,8 +26,7 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + +-if [ "x${GRUB_DISABLE_OS_PROBER}" = "xfalse" ]; then +- gettext_printf "os-prober will not be executed to detect other bootable partitions.\nSystems on them will not be added to the GRUB boot configuration.\nCheck GRUB_DISABLE_OS_PROBER documentation entry.\n" ++if [ "x${GRUB_DISABLE_OS_PROBER}" = "xtrue" ]; then + exit 0 + fi + +@@ -40,8 +39,6 @@ OSPROBED="`os-prober | tr ' ' '^' | paste -s -d ' '`" + if [ -z "${OSPROBED}" ] ; then + # empty os-prober output, nothing doing + exit 0 +-else +- grub_warn "$(gettext_printf "os-prober was executed to detect other bootable partitions.\nIt's output will be used to detect bootable binaries on them and create new boot entries.")" + fi + + osx_entry() { diff --git a/SOURCES/0004-Add-support-for-Linux-EFI-stub-loading.patch b/SOURCES/0004-Add-support-for-Linux-EFI-stub-loading.patch new file mode 100644 index 0000000..745973e --- /dev/null +++ b/SOURCES/0004-Add-support-for-Linux-EFI-stub-loading.patch @@ -0,0 +1,983 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Tue, 10 Jul 2012 11:58:52 -0400 +Subject: [PATCH] Add support for Linux EFI stub loading. + +Also: + +commit 71c843745f22f81e16d259e2e19c99bf3c1855c1 +Author: Colin Watson +Date: Tue Oct 23 10:40:49 2012 -0400 + +Don't allow insmod when secure boot is enabled. + +Hi, + +Fedora's patch to forbid insmod in UEFI Secure Boot environments is fine +as far as it goes. However, the insmod command is not the only way that +modules can be loaded. In particular, the 'normal' command, which +implements the usual GRUB menu and the fully-featured command prompt, +will implicitly load commands not currently loaded into memory. This +permits trivial Secure Boot violations by writing commands implementing +whatever you want to do and pointing $prefix at the malicious code. + +I'm currently test-building this patch (replacing your current +grub-2.00-no-insmod-on-sb.patch), but this should be more correct. It +moves the check into grub_dl_load_file. +--- + grub-core/Makefile.core.def | 16 +- + grub-core/kern/dl.c | 21 +++ + grub-core/kern/efi/efi.c | 28 ++++ + grub-core/kern/efi/mm.c | 32 ++++ + grub-core/loader/arm64/linux.c | 118 +++++++------- + grub-core/loader/arm64/xen_boot.c | 1 - + grub-core/loader/efi/linux.c | 70 ++++++++ + grub-core/loader/i386/efi/linux.c | 335 ++++++++++++++++++++++++++++++++++++++ + grub-core/loader/i386/pc/linux.c | 10 +- + include/grub/arm/linux.h | 9 + + include/grub/arm64/linux.h | 9 + + include/grub/efi/efi.h | 7 +- + include/grub/efi/linux.h | 31 ++++ + 13 files changed, 618 insertions(+), 69 deletions(-) + create mode 100644 grub-core/loader/efi/linux.c + create mode 100644 grub-core/loader/i386/efi/linux.c + create mode 100644 include/grub/efi/linux.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 8022e1c0a7..45d3edaa4d 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1734,13 +1734,6 @@ module = { + enable = i386_pc; + }; + +- +-module = { +- name = linux16; +- common = loader/i386/pc/linux.c; +- enable = x86; +-}; +- + module = { + name = ntldr; + i386_pc = loader/i386/pc/ntldr.c; +@@ -1796,7 +1789,9 @@ module = { + + module = { + name = linux; +- x86 = loader/i386/linux.c; ++ i386_pc = loader/i386/pc/linux.c; ++ x86_64_efi = loader/i386/efi/linux.c; ++ i386_efi = loader/i386/efi/linux.c; + i386_xen_pvh = loader/i386/linux.c; + xen = loader/i386/xen.c; + i386_pc = lib/i386/pc/vesa_modes_table.c; +@@ -1811,9 +1806,14 @@ module = { + arm64 = loader/arm64/linux.c; + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; ++ emu = loader/emu/linux.c; ++ fdt = lib/fdt.c; ++ + common = loader/linux.c; + common = lib/cmdline.c; + enable = noemu; ++ ++ efi = loader/efi/linux.c; + }; + + module = { +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 48f8a79073..b714937095 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -38,6 +38,14 @@ + #define GRUB_MODULES_MACHINE_READONLY + #endif + ++#ifdef GRUB_MACHINE_EMU ++#include ++#endif ++ ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif ++ + + + #pragma GCC diagnostic ignored "-Wcast-align" +@@ -695,6 +703,19 @@ grub_dl_load_file (const char *filename) + void *core = 0; + grub_dl_t mod = 0; + ++#ifdef GRUB_MACHINE_EFI ++ if (grub_efi_secure_boot ()) ++ { ++#if 0 ++ /* This is an error, but grub2-mkconfig still generates a pile of ++ * insmod commands, so emitting it would be mostly just obnoxious. */ ++ grub_error (GRUB_ERR_ACCESS_DENIED, ++ "Secure Boot forbids loading module from %s", filename); ++#endif ++ return 0; ++ } ++#endif ++ + grub_boot_time ("Loading module %s", filename); + + file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE); +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 8cff7be028..35b8f67060 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -286,6 +286,34 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + return grub_efi_get_variable_with_attributes (var, guid, datasize_out, data_out, NULL); + } + ++grub_efi_boolean_t ++grub_efi_secure_boot (void) ++{ ++ grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; ++ grub_size_t datasize; ++ char *secure_boot = NULL; ++ char *setup_mode = NULL; ++ grub_efi_boolean_t ret = 0; ++ ++ secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize); ++ ++ if (datasize != 1 || !secure_boot) ++ goto out; ++ ++ setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize); ++ ++ if (datasize != 1 || !setup_mode) ++ goto out; ++ ++ if (*secure_boot && !*setup_mode) ++ ret = 1; ++ ++ out: ++ grub_free (secure_boot); ++ grub_free (setup_mode); ++ return ret; ++} ++ + #pragma GCC diagnostic ignored "-Wcast-align" + + /* Search the mods section from the PE32/PE32+ image. This code uses +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 9838fb2f50..f6aef0ef64 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -113,6 +113,38 @@ grub_efi_drop_alloc (grub_efi_physical_address_t address, + } + } + ++/* Allocate pages below a specified address */ ++void * ++grub_efi_allocate_pages_max (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages) ++{ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t address = max; ++ ++ if (max > 0xffffffff) ++ return 0; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (address == 0) ++ { ++ /* Uggh, the address 0 was allocated... This is too annoying, ++ so reallocate another one. */ ++ address = max; ++ status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, GRUB_EFI_LOADER_DATA, pages, &address); ++ grub_efi_free_pages (0, pages); ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ } ++ ++ return (void *) ((grub_addr_t) address); ++} ++ + /* Allocate pages. Return the pointer to the first of allocated pages. */ + void * + grub_efi_allocate_pages_real (grub_efi_physical_address_t address, +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index ef3e9f9444..a312c66868 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,6 +42,7 @@ static int loaded; + + static void *kernel_addr; + static grub_uint64_t kernel_size; ++static grub_uint32_t handover_offset; + + static char *linux_args; + static grub_uint32_t cmdline_size; +@@ -67,7 +69,8 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + static grub_err_t + finalize_params_linux (void) + { +- int node, retval; ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ int node, retval, len; + + void *fdt; + +@@ -102,79 +105,70 @@ finalize_params_linux (void) + if (grub_fdt_install() != GRUB_ERR_NONE) + goto failure; + +- return GRUB_ERR_NONE; +- +-failure: +- grub_fdt_unload(); +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); +-} +- +-grub_err_t +-grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) +-{ +- grub_efi_memory_mapped_device_path_t *mempath; +- grub_efi_handle_t image_handle; +- grub_efi_boot_services_t *b; +- grub_efi_status_t status; +- grub_efi_loaded_image_t *loaded_image; +- int len; +- +- mempath = grub_malloc (2 * sizeof (grub_efi_memory_mapped_device_path_t)); +- if (!mempath) +- return grub_errno; +- +- mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE; +- mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE; +- mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath)); +- mempath[0].memory_type = GRUB_EFI_LOADER_DATA; +- mempath[0].start_address = addr; +- mempath[0].end_address = addr + size; +- +- mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE; +- mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +- mempath[1].header.length = sizeof (grub_efi_device_path_t); +- +- b = grub_efi_system_table->boot_services; +- status = b->load_image (0, grub_efi_image_handle, +- (grub_efi_device_path_t *) mempath, +- (void *) addr, size, &image_handle); +- if (status != GRUB_EFI_SUCCESS) +- return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); +- +- grub_dprintf ("linux", "linux command line: '%s'\n", args); ++ grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", ++ fdt); + + /* Convert command line to UCS-2 */ +- loaded_image = grub_efi_get_loaded_image (image_handle); ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!loaded_image) ++ goto failure; ++ + loaded_image->load_options_size = len = +- (grub_strlen (args) + 1) * sizeof (grub_efi_char16_t); ++ (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); + loaded_image->load_options = + grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + if (!loaded_image->load_options) +- return grub_errno; ++ return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); + + loaded_image->load_options_size = + 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, +- (grub_uint8_t *) args, len, NULL); ++ (grub_uint8_t *) linux_args, len, NULL); + +- grub_dprintf ("linux", "starting image %p\n", image_handle); +- status = b->start_image (image_handle, 0, NULL); ++ return GRUB_ERR_NONE; + +- /* When successful, not reached */ +- b->unload_image (image_handle); +- grub_efi_free_pages ((grub_addr_t) loaded_image->load_options, +- GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++failure: ++ grub_fdt_unload(); ++ return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++} + +- return grub_errno; ++static void ++free_params (void) ++{ ++ grub_efi_loaded_image_t *loaded_image = NULL; ++ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ { ++ if (loaded_image->load_options) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_efi_uintn_t)loaded_image->load_options, ++ GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); ++ loaded_image->load_options = NULL; ++ loaded_image->load_options_size = 0; ++ } ++} ++ ++grub_err_t ++grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) ++{ ++ grub_err_t retval; ++ ++ retval = finalize_params_linux (); ++ if (retval != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ grub_dprintf ("linux", "linux command line: '%s'\n", args); ++ ++ retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr); ++ ++ /* Never reached... */ ++ free_params(); ++ return retval; + } + + static grub_err_t + grub_linux_boot (void) + { +- if (finalize_params_linux () != GRUB_ERR_NONE) +- return grub_errno; +- +- return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, +- kernel_size, linux_args)); ++ return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args)); + } + + static grub_err_t +@@ -288,6 +282,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + { + grub_file_t file = 0; + struct linux_arch_kernel_header lh; ++ struct grub_armxx_linux_pe_header *pe; + grub_err_t err; + + grub_dl_ref (my_mod); +@@ -333,6 +328,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + ++ if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size)) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); ++ goto fail; ++ } ++ ++ pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); ++ handover_offset = pe->opt.entry_addr; ++ + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + linux_args = grub_malloc (cmdline_size); + if (!linux_args) +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index 22cc25eccd..d9b7a9ba40 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -266,7 +266,6 @@ xen_boot (void) + return err; + + return grub_arch_efi_linux_boot_image (xen_hypervisor->start, +- xen_hypervisor->size, + xen_hypervisor->cmdline); + } + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +new file mode 100644 +index 0000000000..c24202a5dd +--- /dev/null ++++ b/grub-core/loader/efi/linux.c +@@ -0,0 +1,70 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } ++ ++struct grub_efi_shim_lock ++{ ++ grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); ++}; ++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; ++ ++grub_efi_boolean_t ++grub_linuxefi_secure_validate (void *data, grub_uint32_t size) ++{ ++ grub_efi_guid_t guid = SHIM_LOCK_GUID; ++ grub_efi_shim_lock_t *shim_lock; ++ ++ shim_lock = grub_efi_locate_protocol(&guid, NULL); ++ ++ if (!shim_lock) ++ return 1; ++ ++ if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS) ++ return 1; ++ ++ return 0; ++} ++ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); ++ ++grub_err_t ++grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, ++ void *kernel_params) ++{ ++ handover_func hf; ++ ++ hf = (handover_func)((char *)kernel_addr + offset); ++ hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); ++ ++ return GRUB_ERR_BUG; ++} ++ ++#pragma GCC diagnostic pop +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +new file mode 100644 +index 0000000000..bb2616a809 +--- /dev/null ++++ b/grub-core/loader/i386/efi/linux.c +@@ -0,0 +1,335 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++static int loaded; ++static void *kernel_mem; ++static grub_uint64_t kernel_size; ++static grub_uint8_t *initrd_mem; ++static grub_uint32_t handover_offset; ++struct linux_kernel_params *params; ++static char *linux_cmdline; ++ ++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) ++ ++static grub_err_t ++grub_linuxefi_boot (void) ++{ ++ int offset = 0; ++ ++#ifdef __x86_64__ ++ offset = 512; ++#endif ++ asm volatile ("cli"); ++ ++ return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset, ++ params); ++} ++ ++static grub_err_t ++grub_linuxefi_unload (void) ++{ ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ if (initrd_mem) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, ++ BYTES_TO_PAGES(params->ramdisk_size)); ++ if (linux_cmdline) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) ++ linux_cmdline, ++ BYTES_TO_PAGES(params->cmdline_size + 1)); ++ if (kernel_mem) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, ++ BYTES_TO_PAGES(kernel_size)); ++ if (params) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, ++ BYTES_TO_PAGES(16384)); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t *files = 0; ++ int i, nfiles = 0; ++ grub_size_t size = 0; ++ grub_uint8_t *ptr; ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ if (!loaded) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); ++ goto fail; ++ } ++ ++ files = grub_zalloc (argc * sizeof (files[0])); ++ if (!files) ++ goto fail; ++ ++ for (i = 0; i < argc; i++) ++ { ++ files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (! files[i]) ++ goto fail; ++ nfiles++; ++ size += ALIGN_UP (grub_file_size (files[i]), 4); ++ } ++ ++ initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); ++ if (!initrd_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); ++ goto fail; ++ } ++ ++ params->ramdisk_size = size; ++ params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ ++ ptr = initrd_mem; ++ ++ for (i = 0; i < nfiles; i++) ++ { ++ grub_ssize_t cursize = grub_file_size (files[i]); ++ if (grub_file_read (files[i], ptr, cursize) != cursize) ++ { ++ if (!grub_errno) ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), ++ argv[i]); ++ goto fail; ++ } ++ ptr += cursize; ++ grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4)); ++ ptr += ALIGN_UP_OVERHEAD (cursize, 4); ++ } ++ ++ params->ramdisk_size = size; ++ ++ fail: ++ for (i = 0; i < nfiles; i++) ++ grub_file_close (files[i]); ++ grub_free (files); ++ ++ if (initrd_mem && grub_errno) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, ++ BYTES_TO_PAGES(size)); ++ ++ return grub_errno; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_file_t file = 0; ++ struct linux_i386_kernel_header lh; ++ grub_ssize_t len, start, filelen; ++ void *kernel = NULL; ++ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ goto fail; ++ } ++ ++ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (! file) ++ goto fail; ++ ++ filelen = grub_file_size (file); ++ ++ kernel = grub_malloc(filelen); ++ ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, filelen) != filelen) ++ { ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); ++ goto fail; ++ } ++ ++ if (! grub_linuxefi_secure_validate (kernel, filelen)) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), ++ argv[0]); ++ goto fail; ++ } ++ ++ params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); ++ ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_memset (params, 0, 16384); ++ ++ grub_memcpy (&lh, kernel, sizeof (lh)); ++ ++ if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); ++ goto fail; ++ } ++ ++ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); ++ goto fail; ++ } ++ ++ if (lh.version < grub_cpu_to_le16 (0x020b)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); ++ goto fail; ++ } ++ ++ if (!lh.handover_offset) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "setting up cmdline\n"); ++ linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ ++ if (!linux_cmdline) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); ++ goto fail; ++ } ++ ++ grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ grub_create_loader_cmdline (argc, argv, ++ linux_cmdline + sizeof (LINUX_IMAGE) - 1, ++ lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1), ++ GRUB_VERIFY_KERNEL_CMDLINE); ++ ++ lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ ++ handover_offset = lh.handover_offset; ++ ++ start = (lh.setup_sects + 1) * 512; ++ len = grub_file_size(file) - start; ++ ++ kernel_mem = grub_efi_allocate_pages_max(lh.pref_address, ++ BYTES_TO_PAGES(lh.init_size)); ++ ++ if (!kernel_mem) ++ kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ BYTES_TO_PAGES(lh.init_size)); ++ ++ if (!kernel_mem) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); ++ goto fail; ++ } ++ ++ grub_memcpy (kernel_mem, (char *)kernel + start, len); ++ grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); ++ loaded=1; ++ ++ lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; ++ grub_memcpy (params, &lh, 2 * 512); ++ ++ params->type_of_loader = 0x21; ++ ++ fail: ++ ++ if (file) ++ grub_file_close (file); ++ ++ if (kernel) ++ grub_free (kernel); ++ ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_dl_unref (my_mod); ++ loaded = 0; ++ } ++ ++ if (linux_cmdline && !loaded) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) ++ linux_cmdline, ++ BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ ++ if (kernel_mem && !loaded) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, ++ BYTES_TO_PAGES(kernel_size)); ++ ++ if (params && !loaded) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, ++ BYTES_TO_PAGES(16384)); ++ ++ return grub_errno; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linuxefi, cmd_initrdefi; ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = ++ grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_linuxefi = ++ grub_register_command ("linuxefi", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = ++ grub_register_command ("initrd", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ cmd_initrdefi = ++ grub_register_command ("initrdefi", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI(linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_linuxefi); ++ grub_unregister_command (cmd_initrd); ++ grub_unregister_command (cmd_initrdefi); ++} +diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +index 2a29952016..8be4c3b3f4 100644 +--- a/grub-core/loader/i386/pc/linux.c ++++ b/grub-core/loader/i386/pc/linux.c +@@ -474,14 +474,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +-static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linux, cmd_linux16, cmd_initrd, cmd_initrd16; + + GRUB_MOD_INIT(linux16) + { + cmd_linux = ++ grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_linux16 = + grub_register_command ("linux16", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = ++ grub_register_command ("initrd", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ cmd_initrd16 = + grub_register_command ("initrd16", grub_cmd_initrd, + 0, N_("Load initrd.")); + my_mod = mod; +@@ -490,5 +496,7 @@ GRUB_MOD_INIT(linux16) + GRUB_MOD_FINI(linux16) + { + grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_linux16); + grub_unregister_command (cmd_initrd); ++ grub_unregister_command (cmd_initrd16); + } +diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h +index bcd5a7eb18..b582f67f66 100644 +--- a/include/grub/arm/linux.h ++++ b/include/grub/arm/linux.h +@@ -20,6 +20,7 @@ + #ifndef GRUB_ARM_LINUX_HEADER + #define GRUB_ARM_LINUX_HEADER 1 + ++#include + #include "system.h" + + #define GRUB_LINUX_ARM_MAGIC_SIGNATURE 0x016f2818 +@@ -34,9 +35,17 @@ struct linux_arm_kernel_header { + grub_uint32_t hdr_offset; + }; + ++struct grub_arm_linux_pe_header ++{ ++ grub_uint32_t magic; ++ struct grub_pe32_coff_header coff; ++ struct grub_pe32_optional_header opt; ++}; ++ + #if defined(__arm__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE + # define linux_arch_kernel_header linux_arm_kernel_header ++# define grub_armxx_linux_pe_header grub_arm_linux_pe_header + #endif + + #if defined GRUB_MACHINE_UBOOT +diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h +index 7e22b4ab69..ea030312df 100644 +--- a/include/grub/arm64/linux.h ++++ b/include/grub/arm64/linux.h +@@ -19,6 +19,7 @@ + #ifndef GRUB_ARM64_LINUX_HEADER + #define GRUB_ARM64_LINUX_HEADER 1 + ++#include + #include + + #define GRUB_LINUX_ARM64_MAGIC_SIGNATURE 0x644d5241 /* 'ARM\x64' */ +@@ -38,9 +39,17 @@ struct linux_arm64_kernel_header + grub_uint32_t hdr_offset; /* Offset of PE/COFF header */ + }; + ++struct grub_arm64_linux_pe_header ++{ ++ grub_uint32_t magic; ++ struct grub_pe32_coff_header coff; ++ struct grub_pe64_optional_header opt; ++}; ++ + #if defined(__aarch64__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE + # define linux_arch_kernel_header linux_arm64_kernel_header ++# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header + #endif + + #endif /* ! GRUB_ARM64_LINUX_HEADER */ +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 83d958f994..6295df85f3 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -47,6 +47,9 @@ EXPORT_FUNC(grub_efi_allocate_fixed) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + void * + EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages); ++void * ++EXPORT_FUNC(grub_efi_allocate_pages_max) (grub_efi_physical_address_t max, ++ grub_efi_uintn_t pages); + void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address, + grub_efi_uintn_t pages); + grub_efi_uintn_t EXPORT_FUNC(grub_efi_find_mmap_size) (void); +@@ -88,6 +91,7 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, + void *data, + grub_size_t datasize); ++grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void); + int + EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2); +@@ -101,8 +105,7 @@ void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); + grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); + #include + grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); +-grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, +- char *args); ++grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); + #endif + + grub_addr_t grub_efi_modules_addr (void); +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +new file mode 100644 +index 0000000000..d9ede36773 +--- /dev/null ++++ b/include/grub/efi/linux.h +@@ -0,0 +1,31 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#ifndef GRUB_EFI_LINUX_HEADER ++#define GRUB_EFI_LINUX_HEADER 1 ++ ++#include ++#include ++#include ++ ++grub_efi_boolean_t ++EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size); ++grub_err_t ++EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, ++ void *kernel_param); ++ ++#endif /* ! GRUB_EFI_LINUX_HEADER */ diff --git a/SOURCES/0005-Rework-linux-command.patch b/SOURCES/0005-Rework-linux-command.patch new file mode 100644 index 0000000..694e423 --- /dev/null +++ b/SOURCES/0005-Rework-linux-command.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Sun, 9 Aug 2015 16:12:39 -0700 +Subject: [PATCH] Rework linux command + +We want a single buffer that contains the entire kernel image in order to +perform a TPM measurement. Allocate one and copy the entire kernel into it +before pulling out the individual blocks later on. + +Signed-off-by: Matthew Garrett +--- + grub-core/loader/i386/linux.c | 35 +++++++++++++++++++++++------------ + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 9f74a96b19..dccf3bb300 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -649,13 +649,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + { + grub_file_t file = 0; + struct linux_i386_kernel_header lh; ++ grub_uint8_t *linux_params_ptr; + grub_uint8_t setup_sects; +- grub_size_t real_size, prot_size, prot_file_size; ++ grub_size_t real_size, prot_size, prot_file_size, kernel_offset; + grub_ssize_t len; + int i; + grub_size_t align, min_align; + int relocatable; + grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR; ++ grub_uint8_t *kernel = NULL; + + grub_dl_ref (my_mod); + +@@ -669,7 +671,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (! file) + goto fail; + +- if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) ++ len = grub_file_size (file); ++ kernel = grub_malloc (len); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, len) != len) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -677,6 +687,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_memcpy (&lh, kernel, sizeof (lh)); ++ kernel_offset = sizeof (lh); ++ + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); +@@ -784,13 +797,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + /* We've already read lh so there is no need to read it second time. */ + len -= sizeof(lh); + +- if ((len > 0) && +- (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)) ++ linux_params_ptr = (void *)&linux_params; ++ if (len > 0) + { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; ++ grub_memcpy (linux_params_ptr + sizeof (lh), kernel + kernel_offset, len); ++ kernel_offset += len; + } + + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; +@@ -853,7 +864,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + /* The other parameters are filled when booting. */ + +- grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); ++ kernel_offset = real_size + GRUB_DISK_SECTOR_SIZE; + + grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n", + (unsigned) real_size, (unsigned) prot_size); +@@ -1007,9 +1018,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + len = prot_file_size; +- if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); ++ grub_memcpy (prot_mode_mem, kernel + kernel_offset, len); + + if (grub_errno == GRUB_ERR_NONE) + { +@@ -1020,6 +1029,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + fail: + ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + diff --git a/SOURCES/0006-Rework-linux16-command.patch b/SOURCES/0006-Rework-linux16-command.patch new file mode 100644 index 0000000..5adaaba --- /dev/null +++ b/SOURCES/0006-Rework-linux16-command.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Sun, 9 Aug 2015 16:20:58 -0700 +Subject: [PATCH] Rework linux16 command + +We want a single buffer that contains the entire kernel image in order to +perform a TPM measurement. Allocate one and copy the entire kernel int it +before pulling out the individual blocks later on. + +Signed-off-by: Matthew Garrett +--- + grub-core/loader/i386/pc/linux.c | 33 +++++++++++++++++++++------------ + 1 file changed, 21 insertions(+), 12 deletions(-) + +diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +index 8be4c3b3f4..4b1750e360 100644 +--- a/grub-core/loader/i386/pc/linux.c ++++ b/grub-core/loader/i386/pc/linux.c +@@ -124,13 +124,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_file_t file = 0; + struct linux_i386_kernel_header lh; + grub_uint8_t setup_sects; +- grub_size_t real_size; ++ grub_size_t real_size, kernel_offset = 0; + grub_ssize_t len; + int i; + char *grub_linux_prot_chunk; + int grub_linux_is_bzimage; + grub_addr_t grub_linux_prot_target; + grub_err_t err; ++ grub_uint8_t *kernel = NULL; + + grub_dl_ref (my_mod); + +@@ -144,7 +145,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (! file) + goto fail; + +- if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) ++ len = grub_file_size (file); ++ kernel = grub_malloc (len); ++ if (!kernel) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); ++ goto fail; ++ } ++ ++ if (grub_file_read (file, kernel, len) != len) + { + if (!grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -152,6 +161,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_memcpy (&lh, kernel, sizeof (lh)); ++ kernel_offset = sizeof (lh); ++ + if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, "invalid magic number"); +@@ -320,13 +332,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memmove (grub_linux_real_chunk, &lh, sizeof (lh)); + + len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); +- if (grub_file_read (file, grub_linux_real_chunk + sizeof (lh), len) != len) +- { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); +- goto fail; +- } ++ grub_memcpy (grub_linux_real_chunk + sizeof (lh), kernel + kernel_offset, ++ len); ++ kernel_offset += len; + + if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE) + || grub_le_to_cpu16 (lh.version) < 0x0200) +@@ -364,9 +372,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + len = grub_linux16_prot_size; +- if (grub_file_read (file, grub_linux_prot_chunk, len) != len && !grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +- argv[0]); ++ grub_memcpy (grub_linux_prot_chunk, kernel + kernel_offset, len); ++ kernel_offset += len; + + if (grub_errno == GRUB_ERR_NONE) + { +@@ -376,6 +383,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + fail: + ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + diff --git a/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch b/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch new file mode 100644 index 0000000..34ead63 --- /dev/null +++ b/SOURCES/0007-Add-secureboot-support-on-efi-chainloader.patch @@ -0,0 +1,1401 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Raymund Will +Date: Mon, 8 Jul 2019 11:55:18 +0200 +Subject: [PATCH] Add secureboot support on efi chainloader + +Expand the chainloader to be able to verify the image by means of shim +lock protocol. The PE/COFF image is loaded and relocated by the +chainloader instead of calling LoadImage and StartImage UEFI boot +Service as they require positive verification result from keys enrolled +in KEK or DB. The shim will use MOK in addition to firmware enrolled +keys to verify the image. + +The chainloader module could be used to load other UEFI bootloaders, +such as xen.efi, and could be signed by any of MOK, KEK or DB. + +Based on https://build.opensuse.org/package/view_file/openSUSE:Factory/grub2/grub2-secureboot-chainloader.patch + +Signed-off-by: Peter Jones + +Also: + +commit cd7a8984d4fda905877b5bfe466339100156b3bc +Author: Raymund Will +Date: Fri Apr 10 01:45:02 2015 -0400 + +Use device part of chainloader target, if present. + +Otherwise chainloading is restricted to '$root', which might not even +be readable by EFI! + +v1. use grub_file_get_device_name() to get device name + +Signed-off-by: Michael Chang +Signed-off-by: Peter Jones + +Also: + +commit 0872a2310a0eeac4ecfe9e1b49dd2d72ab373039 +Author: Peter Jones +Date: Fri Jun 10 14:06:15 2016 -0400 + +Rework even more of efi chainload so non-sb cases work right. + +This ensures that if shim protocol is not loaded, or is loaded but shim +is disabled, we will fall back to a correct load method for the efi +chain loader. + +Here's what I tested with this version: + +results expected actual +------------------------------------------------------------ +sb + enabled + shim + fedora success success +sb + enabled + shim + win success success +sb + enabled + grub + fedora fail fail +sb + enabled + grub + win fail fail + +sb + mokdisabled + shim + fedora success success +sb + mokdisabled + shim + win success success +sb + mokdisabled + grub + fedora fail fail +sb + mokdisabled + grub + win fail fail + +sb disabled + shim + fedora success success* +sb disabled + shim + win success success* +sb disabled + grub + fedora success success +sb disabled + grub + win success success + +nosb + shim + fedora success success* +nosb + shim + win success success* +nosb + grub + fedora success success +nosb + grub + win success success + +* for some reason shim protocol is being installed in these cases, and I + can't see why, but I think it may be this firmware build returning an + erroneous value. But this effectively falls back to the mokdisabled + behavior, which works correctly, and the presence of the "grub" (i.e. + no shim) tests effectively tests the desired behavior here. + +Resolves: rhbz#1344512 + +Signed-off-by: Peter Jones + +Also: + +commit ff7b1cb7f69487870211aeb69ff4f54470fbcb58 +Author: Laszlo Ersek +Date: Mon Nov 21 15:34:00 2016 +0100 + +efi/chainloader: fix wrong sanity check in relocate_coff() + +In relocate_coff(), the relocation entries are parsed from the original +image (not the section-wise copied image). The original image is +pointed-to by the "orig" pointer. The current check + + (void *)reloc_end < data + +compares the addresses of independent memory allocations. "data" is a typo +here, it should be "orig". + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291 +Signed-off-by: Laszlo Ersek +Tested-by: Bogdan Costescu +Tested-by: Juan Orti + +Also: + +commit ab4ba9997ad4832449e54d930fa2aac6a160d0e9 +Author: Laszlo Ersek +Date: Wed Nov 23 06:27:09 2016 +0100 + +efi/chainloader: truncate overlong relocation section + +The UEFI Windows 7 boot loader ("EFI/Microsoft/Boot/bootmgfw.efi", SHA1 +31b410e029bba87d2068c65a80b88882f9f8ea25) has inconsistent headers. + +Compare: + +> The Data Directory +> ... +> Entry 5 00000000000d9000 00000574 Base Relocation Directory [.reloc] + +Versus: + +> Sections: +> Idx Name Size VMA LMA File off ... +> ... +> 10 .reloc 00000e22 00000000100d9000 00000000100d9000 000a1800 ... + +That is, the size reported by the RelocDir entry (0x574) is smaller than +the virtual size of the .reloc section (0xe22). + +Quoting the grub2 debug log for the same: + +> chainloader.c:595: reloc_dir: 0xd9000 reloc_size: 0x00000574 +> chainloader.c:603: reloc_base: 0x7d208000 reloc_base_end: 0x7d208573 +> ... +> chainloader.c:620: Section 10 ".reloc" at 0x7d208000..0x7d208e21 +> chainloader.c:661: section is not reloc section? +> chainloader.c:663: rds: 0x00001000, vs: 00000e22 +> chainloader.c:664: base: 0x7d208000 end: 0x7d208e21 +> chainloader.c:666: reloc_base: 0x7d208000 reloc_base_end: 0x7d208573 +> chainloader.c:671: Section characteristics are 42000040 +> chainloader.c:673: Section virtual size: 00000e22 +> chainloader.c:675: Section raw_data size: 00001000 +> chainloader.c:678: Discarding section + +After hexdumping "bootmgfw.efi" and manually walking its relocation blocks +(yes, really), I determined that the (smaller) RelocDir value is correct. +The remaining area that extends up to the .reloc section size (== 0xe22 - +0x574 == 0x8ae bytes) exists as zero padding in the file. + +This zero padding shouldn't be passed to relocate_coff() for parsing. In +order to cope with it, split the handling of .reloc sections into the +following branches: + +- original case (equal size): original behavior (--> relocation + attempted), + +- overlong .reloc section (longer than reported by RelocDir): truncate the + section to the RelocDir size for the purposes of relocate_coff(), and + attempt relocation, + +- .reloc section is too short, or other checks fail: original behavior + (--> relocation not attempted). + +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1347291 +Signed-off-by: Laszlo Ersek + +Also: + +commit cc06f149fbd2d8c1da1e83173d21629ba97e0d92 +Author: Raymund Will + +chainloader: Define machine types for RISC-V + +The commit "Add secureboot support on efi chainloader" didn't add machine +types for RISC-V, so this patch adds them. + +Note, that grub-core/loader/riscv/linux.c is skipped because Linux is not +supported yet. This patch might need a new revision once that's the case. + +Signed-off-by: David Abdurachmanov +--- + grub-core/kern/efi/efi.c | 14 +- + grub-core/loader/arm64/linux.c | 4 +- + grub-core/loader/efi/chainloader.c | 820 +++++++++++++++++++++++++++++++++---- + grub-core/loader/efi/linux.c | 25 +- + grub-core/loader/i386/efi/linux.c | 17 +- + include/grub/efi/linux.h | 2 +- + include/grub/efi/pe32.h | 52 ++- + 7 files changed, 844 insertions(+), 90 deletions(-) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 35b8f67060..4a2259aa1c 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -296,14 +296,20 @@ grub_efi_secure_boot (void) + grub_efi_boolean_t ret = 0; + + secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize); +- + if (datasize != 1 || !secure_boot) +- goto out; ++ { ++ grub_dprintf ("secureboot", "No SecureBoot variable\n"); ++ goto out; ++ } ++ grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot); + + setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize); +- + if (datasize != 1 || !setup_mode) +- goto out; ++ { ++ grub_dprintf ("secureboot", "No SetupMode variable\n"); ++ goto out; ++ } ++ grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode); + + if (*secure_boot && !*setup_mode) + ret = 1; +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index a312c66868..04994d5c67 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -284,6 +284,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + struct linux_arch_kernel_header lh; + struct grub_armxx_linux_pe_header *pe; + grub_err_t err; ++ int rc; + + grub_dl_ref (my_mod); + +@@ -328,7 +329,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + +- if (!grub_linuxefi_secure_validate (kernel_addr, kernel_size)) ++ rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); ++ if (rc < 0) + { + grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); + goto fail; +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 2bd80f4db3..e6a8d4ad0e 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -46,9 +48,14 @@ static grub_dl_t my_mod; + + static grub_efi_physical_address_t address; + static grub_efi_uintn_t pages; ++static grub_ssize_t fsize; + static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; + static grub_efi_char16_t *cmdline; ++static grub_ssize_t cmdline_len; ++static grub_efi_handle_t dev_handle; ++ ++static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); + + static grub_err_t + grub_chainloader_unload (void) +@@ -63,6 +70,7 @@ grub_chainloader_unload (void) + grub_free (cmdline); + cmdline = 0; + file_path = 0; ++ dev_handle = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; +@@ -213,20 +221,694 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + return file_path; + } + ++#define SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, { 0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23 } } ++ ++typedef union ++{ ++ struct grub_pe32_header_32 pe32; ++ struct grub_pe32_header_64 pe32plus; ++} grub_pe_header_t; ++ ++struct pe_coff_loader_image_context ++{ ++ grub_efi_uint64_t image_address; ++ grub_efi_uint64_t image_size; ++ grub_efi_uint64_t entry_point; ++ grub_efi_uintn_t size_of_headers; ++ grub_efi_uint16_t image_type; ++ grub_efi_uint16_t number_of_sections; ++ grub_efi_uint32_t section_alignment; ++ struct grub_pe32_section_table *first_section; ++ struct grub_pe32_data_directory *reloc_dir; ++ struct grub_pe32_data_directory *sec_dir; ++ grub_efi_uint64_t number_of_rva_and_sizes; ++ grub_pe_header_t *pe_hdr; ++}; ++ ++typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t; ++ ++struct grub_efi_shim_lock ++{ ++ grub_efi_status_t (*verify)(void *buffer, ++ grub_efi_uint32_t size); ++ grub_efi_status_t (*hash)(void *data, ++ grub_efi_int32_t datasize, ++ pe_coff_loader_image_context_t *context, ++ grub_efi_uint8_t *sha256hash, ++ grub_efi_uint8_t *sha1hash); ++ grub_efi_status_t (*context)(void *data, ++ grub_efi_uint32_t size, ++ pe_coff_loader_image_context_t *context); ++}; ++ ++typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; ++ ++static grub_efi_boolean_t ++read_header (void *data, grub_efi_uint32_t size, ++ pe_coff_loader_image_context_t *context) ++{ ++ grub_efi_guid_t guid = SHIM_LOCK_GUID; ++ grub_efi_shim_lock_t *shim_lock; ++ grub_efi_status_t status; ++ ++ shim_lock = grub_efi_locate_protocol (&guid, NULL); ++ if (!shim_lock) ++ { ++ grub_dprintf ("chain", "no shim lock protocol"); ++ return 0; ++ } ++ ++ status = shim_lock->context (data, size, context); ++ ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("chain", "context success\n"); ++ return 1; ++ } ++ ++ switch (status) ++ { ++ case GRUB_EFI_UNSUPPORTED: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error unsupported"); ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error invalid parameter"); ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "context error code"); ++ break; ++ } ++ ++ return -1; ++} ++ ++static void* ++image_address (void *image, grub_efi_uint64_t sz, grub_efi_uint64_t adr) ++{ ++ if (adr > sz) ++ return NULL; ++ ++ return ((grub_uint8_t*)image + adr); ++} ++ ++static int ++image_is_64_bit (grub_pe_header_t *pe_hdr) ++{ ++ /* .Magic is the same offset in all cases */ ++ if (pe_hdr->pe32plus.optional_header.magic == GRUB_PE32_PE64_MAGIC) ++ return 1; ++ return 0; ++} ++ ++static const grub_uint16_t machine_type __attribute__((__unused__)) = ++#if defined(__x86_64__) ++ GRUB_PE32_MACHINE_X86_64; ++#elif defined(__aarch64__) ++ GRUB_PE32_MACHINE_ARM64; ++#elif defined(__arm__) ++ GRUB_PE32_MACHINE_ARMTHUMB_MIXED; ++#elif defined(__i386__) || defined(__i486__) || defined(__i686__) ++ GRUB_PE32_MACHINE_I386; ++#elif defined(__ia64__) ++ GRUB_PE32_MACHINE_IA64; ++#elif defined(__riscv) && (__riscv_xlen == 32) ++ GRUB_PE32_MACHINE_RISCV32; ++#elif defined(__riscv) && (__riscv_xlen == 64) ++ GRUB_PE32_MACHINE_RISCV64; ++#else ++#error this architecture is not supported by grub2 ++#endif ++ ++static grub_efi_status_t ++relocate_coff (pe_coff_loader_image_context_t *context, ++ struct grub_pe32_section_table *section, ++ void *orig, void *data) ++{ ++ struct grub_pe32_data_directory *reloc_base, *reloc_base_end; ++ grub_efi_uint64_t adjust; ++ struct grub_pe32_fixup_block *reloc, *reloc_end; ++ char *fixup, *fixup_base, *fixup_data = NULL; ++ grub_efi_uint16_t *fixup_16; ++ grub_efi_uint32_t *fixup_32; ++ grub_efi_uint64_t *fixup_64; ++ grub_efi_uint64_t size = context->image_size; ++ void *image_end = (char *)orig + size; ++ int n = 0; ++ ++ if (image_is_64_bit (context->pe_hdr)) ++ context->pe_hdr->pe32plus.optional_header.image_base = ++ (grub_uint64_t)(unsigned long)data; ++ else ++ context->pe_hdr->pe32.optional_header.image_base = ++ (grub_uint32_t)(unsigned long)data; ++ ++ /* Alright, so here's how this works: ++ * ++ * context->reloc_dir gives us two things: ++ * - the VA the table of base relocation blocks are (maybe) to be ++ * mapped at (reloc_dir->rva) ++ * - the virtual size (reloc_dir->size) ++ * ++ * The .reloc section (section here) gives us some other things: ++ * - the name! kind of. (section->name) ++ * - the virtual size (section->virtual_size), which should be the same ++ * as RelocDir->Size ++ * - the virtual address (section->virtual_address) ++ * - the file section size (section->raw_data_size), which is ++ * a multiple of optional_header->file_alignment. Only useful for image ++ * validation, not really useful for iteration bounds. ++ * - the file address (section->raw_data_offset) ++ * - a bunch of stuff we don't use that's 0 in our binaries usually ++ * - Flags (section->characteristics) ++ * ++ * and then the thing that's actually at the file address is an array ++ * of struct grub_pe32_fixup_block structs with some values packed behind ++ * them. The block_size field of this structure includes the ++ * structure itself, and adding it to that structure's address will ++ * yield the next entry in the array. ++ */ ++ ++ reloc_base = image_address (orig, size, section->raw_data_offset); ++ reloc_base_end = image_address (orig, size, section->raw_data_offset ++ + section->virtual_size); ++ ++ grub_dprintf ("chain", "relocate_coff(): reloc_base %p reloc_base_end %p\n", ++ reloc_base, reloc_base_end); ++ ++ if (!reloc_base && !reloc_base_end) ++ return GRUB_EFI_SUCCESS; ++ ++ if (!reloc_base || !reloc_base_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ adjust = (grub_uint64_t)(grub_efi_uintn_t)data - context->image_address; ++ if (adjust == 0) ++ return GRUB_EFI_SUCCESS; ++ ++ while (reloc_base < reloc_base_end) ++ { ++ grub_uint16_t *entry; ++ reloc = (struct grub_pe32_fixup_block *)((char*)reloc_base); ++ ++ if ((reloc_base->size == 0) || ++ (reloc_base->size > context->reloc_dir->size)) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Reloc %d block size %d is invalid\n", n, ++ reloc_base->size); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ entry = &reloc->entries[0]; ++ reloc_end = (struct grub_pe32_fixup_block *) ++ ((char *)reloc_base + reloc_base->size); ++ ++ if ((void *)reloc_end < orig || (void *)reloc_end > image_end) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc entry %d overflows binary", ++ n); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ fixup_base = image_address(data, size, reloc_base->rva); ++ ++ if (!fixup_base) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc %d Invalid fixupbase", n); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ ++ while ((void *)entry < (void *)reloc_end) ++ { ++ fixup = fixup_base + (*entry & 0xFFF); ++ switch ((*entry) >> 12) ++ { ++ case GRUB_PE32_REL_BASED_ABSOLUTE: ++ break; ++ case GRUB_PE32_REL_BASED_HIGH: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) ++ (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 16))); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_LOW: ++ fixup_16 = (grub_uint16_t *)fixup; ++ *fixup_16 = (grub_uint16_t) (*fixup_16 + (grub_uint16_t)adjust); ++ if (fixup_data != NULL) ++ { ++ *(grub_uint16_t *) fixup_data = *fixup_16; ++ fixup_data = fixup_data + sizeof (grub_uint16_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_HIGHLOW: ++ fixup_32 = (grub_uint32_t *)fixup; ++ *fixup_32 = *fixup_32 + (grub_uint32_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint32_t)); ++ *(grub_uint32_t *) fixup_data = *fixup_32; ++ fixup_data += sizeof (grub_uint32_t); ++ } ++ break; ++ case GRUB_PE32_REL_BASED_DIR64: ++ fixup_64 = (grub_uint64_t *)fixup; ++ *fixup_64 = *fixup_64 + (grub_uint64_t)adjust; ++ if (fixup_data != NULL) ++ { ++ fixup_data = (char *)ALIGN_UP ((grub_addr_t)fixup_data, sizeof (grub_uint64_t)); ++ *(grub_uint64_t *) fixup_data = *fixup_64; ++ fixup_data += sizeof (grub_uint64_t); ++ } ++ break; ++ default: ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Reloc %d unknown relocation type %d", ++ n, (*entry) >> 12); ++ return GRUB_EFI_UNSUPPORTED; ++ } ++ entry += 1; ++ } ++ reloc_base = (struct grub_pe32_data_directory *)reloc_end; ++ n++; ++ } ++ ++ return GRUB_EFI_SUCCESS; ++} ++ ++static grub_efi_device_path_t * ++grub_efi_get_media_file_path (grub_efi_device_path_t *dp) ++{ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ ++ if (type == GRUB_EFI_END_DEVICE_PATH_TYPE) ++ break; ++ else if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE ++ && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE) ++ return dp; ++ ++ dp = GRUB_EFI_NEXT_DEVICE_PATH (dp); ++ } ++ ++ return NULL; ++} ++ ++static grub_efi_boolean_t ++handle_image (void *data, grub_efi_uint32_t datasize) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_loaded_image_t *li, li_bak; ++ grub_efi_status_t efi_status; ++ char *buffer = NULL; ++ char *buffer_aligned = NULL; ++ grub_efi_uint32_t i; ++ struct grub_pe32_section_table *section; ++ char *base, *end; ++ pe_coff_loader_image_context_t context; ++ grub_uint32_t section_alignment; ++ grub_uint32_t buffer_size; ++ int found_entry_point = 0; ++ int rc; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ rc = read_header (data, datasize, &context); ++ if (rc < 0) ++ { ++ grub_dprintf ("chain", "Failed to read header\n"); ++ goto error_exit; ++ } ++ else if (rc == 0) ++ { ++ grub_dprintf ("chain", "Secure Boot is not enabled\n"); ++ return 0; ++ } ++ else ++ { ++ grub_dprintf ("chain", "Header read without error\n"); ++ } ++ ++ /* ++ * The spec says, uselessly, of SectionAlignment: ++ * ===== ++ * The alignment (in bytes) of sections when they are loaded into ++ * memory. It must be greater than or equal to FileAlignment. The ++ * default is the page size for the architecture. ++ * ===== ++ * Which doesn't tell you whose responsibility it is to enforce the ++ * "default", or when. It implies that the value in the field must ++ * be > FileAlignment (also poorly defined), but it appears visual ++ * studio will happily write 512 for FileAlignment (its default) and ++ * 0 for SectionAlignment, intending to imply PAGE_SIZE. ++ * ++ * We only support one page size, so if it's zero, nerf it to 4096. ++ */ ++ section_alignment = context.section_alignment; ++ if (section_alignment == 0) ++ section_alignment = 4096; ++ ++ buffer_size = context.image_size + section_alignment; ++ grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n", ++ context.image_size, datasize); ++ ++ efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, ++ buffer_size, &buffer); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto error_exit; ++ } ++ ++ buffer_aligned = (char *)ALIGN_UP ((grub_addr_t)buffer, section_alignment); ++ if (!buffer_aligned) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto error_exit; ++ } ++ ++ grub_memcpy (buffer_aligned, data, context.size_of_headers); ++ ++ entry_point = image_address (buffer_aligned, context.image_size, ++ context.entry_point); ++ ++ grub_dprintf ("chain", "entry_point: %p\n", entry_point); ++ if (!entry_point) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point"); ++ goto error_exit; ++ } ++ ++ char *reloc_base, *reloc_base_end; ++ grub_dprintf ("chain", "reloc_dir: %p reloc_size: 0x%08x\n", ++ (void *)(unsigned long)context.reloc_dir->rva, ++ context.reloc_dir->size); ++ reloc_base = image_address (buffer_aligned, context.image_size, ++ context.reloc_dir->rva); ++ /* RelocBaseEnd here is the address of the last byte of the table */ ++ reloc_base_end = image_address (buffer_aligned, context.image_size, ++ context.reloc_dir->rva ++ + context.reloc_dir->size - 1); ++ grub_dprintf ("chain", "reloc_base: %p reloc_base_end: %p\n", ++ reloc_base, reloc_base_end); ++ ++ struct grub_pe32_section_table *reloc_section = NULL, fake_reloc_section; ++ ++ section = context.first_section; ++ for (i = 0; i < context.number_of_sections; i++, section++) ++ { ++ char name[9]; ++ ++ base = image_address (buffer_aligned, context.image_size, ++ section->virtual_address); ++ end = image_address (buffer_aligned, context.image_size, ++ section->virtual_address + section->virtual_size -1); ++ ++ grub_strncpy(name, section->name, 9); ++ name[8] = '\0'; ++ grub_dprintf ("chain", "Section %d \"%s\" at %p..%p\n", i, ++ name, base, end); ++ ++ if (end < base) ++ { ++ grub_dprintf ("chain", " base is %p but end is %p... bad.\n", ++ base, end); ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Image has invalid negative size"); ++ goto error_exit; ++ } ++ ++ if (section->virtual_address <= context.entry_point && ++ (section->virtual_address + section->raw_data_size - 1) ++ > context.entry_point) ++ { ++ found_entry_point++; ++ grub_dprintf ("chain", " section contains entry point\n"); ++ } ++ ++ /* We do want to process .reloc, but it's often marked ++ * discardable, so we don't want to memcpy it. */ ++ if (grub_memcmp (section->name, ".reloc\0\0", 8) == 0) ++ { ++ if (reloc_section) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Image has multiple relocation sections"); ++ goto error_exit; ++ } ++ ++ /* If it has nonzero sizes, and our bounds check ++ * made sense, and the VA and size match RelocDir's ++ * versions, then we believe in this section table. */ ++ if (section->raw_data_size && section->virtual_size && ++ base && end && reloc_base == base) ++ { ++ if (reloc_base_end == end) ++ { ++ grub_dprintf ("chain", " section is relocation section\n"); ++ reloc_section = section; ++ } ++ else if (reloc_base_end && reloc_base_end < end) ++ { ++ /* Bogus virtual size in the reloc section -- RelocDir ++ * reported a smaller Base Relocation Directory. Decrease ++ * the section's virtual size so that it equal RelocDir's ++ * idea, but only for the purposes of relocate_coff(). */ ++ grub_dprintf ("chain", ++ " section is (overlong) relocation section\n"); ++ grub_memcpy (&fake_reloc_section, section, sizeof *section); ++ fake_reloc_section.virtual_size -= (end - reloc_base_end); ++ reloc_section = &fake_reloc_section; ++ } ++ } ++ ++ if (!reloc_section) ++ { ++ grub_dprintf ("chain", " section is not reloc section?\n"); ++ grub_dprintf ("chain", " rds: 0x%08x, vs: %08x\n", ++ section->raw_data_size, section->virtual_size); ++ grub_dprintf ("chain", " base: %p end: %p\n", base, end); ++ grub_dprintf ("chain", " reloc_base: %p reloc_base_end: %p\n", ++ reloc_base, reloc_base_end); ++ } ++ } ++ ++ grub_dprintf ("chain", " Section characteristics are %08x\n", ++ section->characteristics); ++ grub_dprintf ("chain", " Section virtual size: %08x\n", ++ section->virtual_size); ++ grub_dprintf ("chain", " Section raw_data size: %08x\n", ++ section->raw_data_size); ++ if (section->characteristics & GRUB_PE32_SCN_MEM_DISCARDABLE) ++ { ++ grub_dprintf ("chain", " Discarding section\n"); ++ continue; ++ } ++ ++ if (!base || !end) ++ { ++ grub_dprintf ("chain", " section is invalid\n"); ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size"); ++ goto error_exit; ++ } ++ ++ if (section->characteristics & GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA) ++ { ++ if (section->raw_data_size != 0) ++ grub_dprintf ("chain", " UNINITIALIZED_DATA section has data?\n"); ++ } ++ else if (section->virtual_address < context.size_of_headers || ++ section->raw_data_offset < context.size_of_headers) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, ++ "Section %d is inside image headers", i); ++ goto error_exit; ++ } ++ ++ if (section->raw_data_size > 0) ++ { ++ grub_dprintf ("chain", " copying 0x%08x bytes to %p\n", ++ section->raw_data_size, base); ++ grub_memcpy (base, ++ (grub_efi_uint8_t*)data + section->raw_data_offset, ++ section->raw_data_size); ++ } ++ ++ if (section->raw_data_size < section->virtual_size) ++ { ++ grub_dprintf ("chain", " padding with 0x%08x bytes at %p\n", ++ section->virtual_size - section->raw_data_size, ++ base + section->raw_data_size); ++ grub_memset (base + section->raw_data_size, 0, ++ section->virtual_size - section->raw_data_size); ++ } ++ ++ grub_dprintf ("chain", " finished section %s\n", name); ++ } ++ ++ /* 5 == EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC */ ++ if (context.number_of_rva_and_sizes <= 5) ++ { ++ grub_dprintf ("chain", "image has no relocation entry\n"); ++ goto error_exit; ++ } ++ ++ if (context.reloc_dir->size && reloc_section) ++ { ++ /* run the relocation fixups */ ++ efi_status = relocate_coff (&context, reloc_section, data, ++ buffer_aligned); ++ ++ if (efi_status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed"); ++ goto error_exit; ++ } ++ } ++ ++ if (!found_entry_point) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "entry point is not within sections"); ++ goto error_exit; ++ } ++ if (found_entry_point > 1) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "%d sections contain entry point", ++ found_entry_point); ++ goto error_exit; ++ } ++ ++ li = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!li) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "no loaded image available"); ++ goto error_exit; ++ } ++ ++ grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); ++ li->image_base = buffer_aligned; ++ li->image_size = context.image_size; ++ li->load_options = cmdline; ++ li->load_options_size = cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (file_path); ++ li->device_handle = dev_handle; ++ if (!li->file_path) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); ++ goto error_exit; ++ } ++ ++ grub_dprintf ("chain", "booting via entry point\n"); ++ efi_status = efi_call_2 (entry_point, grub_efi_image_handle, ++ grub_efi_system_table); ++ ++ grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); ++ grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); ++ efi_status = efi_call_1 (b->free_pool, buffer); ++ ++ return 1; ++ ++error_exit: ++ grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno); ++ if (buffer) ++ efi_call_1 (b->free_pool, buffer); ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_unload (void) ++{ ++ grub_efi_boot_services_t *b; ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ grub_free (cmdline); ++ cmdline = 0; ++ file_path = 0; ++ dev_handle = 0; ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_load_and_start_image(void *boot_image) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ grub_efi_loaded_image_t *loaded_image; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, ++ boot_image, fsize, &image_handle); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (status == GRUB_EFI_OUT_OF_RESOURCES) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources"); ++ else ++ grub_error (GRUB_ERR_BAD_OS, "cannot load image"); ++ return -1; ++ } ++ ++ /* LoadImage does not set a device handler when the image is ++ loaded from memory, so it is necessary to set it explicitly here. ++ This is a mess. */ ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (! loaded_image) ++ { ++ grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); ++ return -1; ++ } ++ loaded_image->device_handle = dev_handle; ++ ++ if (cmdline) ++ { ++ loaded_image->load_options = cmdline; ++ loaded_image->load_options_size = cmdline_len; ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_secureboot_chainloader_boot (void) ++{ ++ int rc; ++ rc = handle_image ((void *)(unsigned long)address, fsize); ++ if (rc == 0) ++ { ++ grub_load_and_start_image((void *)(unsigned long)address); ++ } ++ ++ grub_loader_unset (); ++ return grub_errno; ++} ++ + static grub_err_t + grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- grub_ssize_t size; + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; + grub_efi_device_path_t *dp = 0; +- grub_efi_loaded_image_t *loaded_image; + char *filename; + void *boot_image = 0; +- grub_efi_handle_t dev_handle = 0; ++ int rc; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -238,15 +920,45 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + address = 0; + image_handle = 0; + file_path = 0; ++ dev_handle = 0; + + b = grub_efi_system_table->boot_services; + ++ if (argc > 1) ++ { ++ int i; ++ grub_efi_char16_t *p16; ++ ++ for (i = 1, cmdline_len = 0; i < argc; i++) ++ cmdline_len += grub_strlen (argv[i]) + 1; ++ ++ cmdline_len *= sizeof (grub_efi_char16_t); ++ cmdline = p16 = grub_malloc (cmdline_len); ++ if (! cmdline) ++ goto fail; ++ ++ for (i = 1; i < argc; i++) ++ { ++ char *p8; ++ ++ p8 = argv[i]; ++ while (*p8) ++ *(p16++) = *(p8++); ++ ++ *(p16++) = ' '; ++ } ++ *(--p16) = 0; ++ } ++ + file = grub_file_open (filename, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE); + if (! file) + goto fail; + +- /* Get the root device's device path. */ +- dev = grub_device_open (0); ++ /* Get the device path from filename. */ ++ char *devname = grub_file_get_device_name (filename); ++ dev = grub_device_open (devname); ++ if (devname) ++ grub_free (devname); + if (! dev) + goto fail; + +@@ -283,17 +995,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (! file_path) + goto fail; + +- grub_printf ("file path: "); +- grub_efi_print_device_path (file_path); +- +- size = grub_file_size (file); +- if (!size) ++ fsize = grub_file_size (file); ++ if (!fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } +- pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); ++ pages = (((grub_efi_uintn_t) fsize + ((1 << 12) - 1)) >> 12); + + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, + GRUB_EFI_LOADER_CODE, +@@ -307,7 +1016,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + + boot_image = (void *) ((grub_addr_t) address); +- if (grub_file_read (file, boot_image, size) != size) ++ if (grub_file_read (file, boot_image, fsize) != fsize) + { + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +@@ -317,7 +1026,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + + #if defined (__i386__) || defined (__x86_64__) +- if (size >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) ++ if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { + struct grub_macho_fat_header *head = boot_image; + if (head->magic +@@ -326,6 +1035,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_uint32_t i; + struct grub_macho_fat_arch *archs + = (struct grub_macho_fat_arch *) (head + 1); ++ ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ { ++ grub_error (GRUB_ERR_BAD_OS, ++ "MACHO binaries are forbidden with Secure Boot"); ++ goto fail; ++ } ++ + for (i = 0; i < grub_cpu_to_le32 (head->nfat_arch); i++) + { + if (GRUB_MACHO_CPUTYPE_IS_HOST_CURRENT (archs[i].cputype)) +@@ -340,79 +1057,39 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + > ~grub_cpu_to_le32 (archs[i].size) + || grub_cpu_to_le32 (archs[i].offset) + + grub_cpu_to_le32 (archs[i].size) +- > (grub_size_t) size) ++ > (grub_size_t) fsize) + { + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), + filename); + goto fail; + } + boot_image = (char *) boot_image + grub_cpu_to_le32 (archs[i].offset); +- size = grub_cpu_to_le32 (archs[i].size); ++ fsize = grub_cpu_to_le32 (archs[i].size); + } + } + #endif + +- status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- boot_image, size, +- &image_handle); +- if (status != GRUB_EFI_SUCCESS) ++ rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); ++ grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); ++ if (rc > 0) + { +- if (status == GRUB_EFI_OUT_OF_RESOURCES) +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of resources"); +- else +- grub_error (GRUB_ERR_BAD_OS, "cannot load image"); +- +- goto fail; ++ grub_file_close (file); ++ grub_device_close (dev); ++ grub_loader_set (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, 0); ++ return 0; + } +- +- /* LoadImage does not set a device handler when the image is +- loaded from memory, so it is necessary to set it explicitly here. +- This is a mess. */ +- loaded_image = grub_efi_get_loaded_image (image_handle); +- if (! loaded_image) ++ else if (rc == 0) + { +- grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); +- goto fail; +- } +- loaded_image->device_handle = dev_handle; +- +- if (argc > 1) +- { +- int i, len; +- grub_efi_char16_t *p16; +- +- for (i = 1, len = 0; i < argc; i++) +- len += grub_strlen (argv[i]) + 1; +- +- len *= sizeof (grub_efi_char16_t); +- cmdline = p16 = grub_malloc (len); +- if (! cmdline) +- goto fail; ++ grub_load_and_start_image(boot_image); ++ grub_file_close (file); ++ grub_device_close (dev); ++ grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + +- for (i = 1; i < argc; i++) +- { +- char *p8; +- +- p8 = argv[i]; +- while (*p8) +- *(p16++) = *(p8++); +- +- *(p16++) = ' '; +- } +- *(--p16) = 0; +- +- loaded_image->load_options = cmdline; +- loaded_image->load_options_size = len; ++ return 0; + } + +- grub_file_close (file); +- grub_device_close (dev); +- +- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); +- return 0; +- +- fail: +- ++fail: + if (dev) + grub_device_close (dev); + +@@ -424,6 +1101,9 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (address) + efi_call_2 (b->free_pages, address, pages); + ++ if (cmdline) ++ grub_free (cmdline); ++ + grub_dl_unref (my_mod); + + return grub_errno; +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index c24202a5dd..c8ecce6dfd 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -33,21 +33,34 @@ struct grub_efi_shim_lock + }; + typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; + +-grub_efi_boolean_t ++int + grub_linuxefi_secure_validate (void *data, grub_uint32_t size) + { + grub_efi_guid_t guid = SHIM_LOCK_GUID; + grub_efi_shim_lock_t *shim_lock; ++ grub_efi_status_t status; + + shim_lock = grub_efi_locate_protocol(&guid, NULL); +- ++ grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock); + if (!shim_lock) +- return 1; ++ { ++ grub_dprintf ("secureboot", "shim not available\n"); ++ return 0; ++ } + +- if (shim_lock->verify(data, size) == GRUB_EFI_SUCCESS) +- return 1; ++ grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n"); ++ status = shim_lock->verify (data, size); ++ grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status); ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ grub_dprintf ("secureboot", "Kernel signature verification passed\n"); ++ return 1; ++ } + +- return 0; ++ grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n", ++ (unsigned long) status); ++ ++ return -1; + } + + #pragma GCC diagnostic push +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index bb2616a809..6b24cbb948 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -117,6 +117,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem); ++ + params->ramdisk_size = size; + params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; + +@@ -159,6 +161,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + struct linux_i386_kernel_header lh; + grub_ssize_t len, start, filelen; + void *kernel = NULL; ++ int rc; + + grub_dl_ref (my_mod); + +@@ -184,11 +187,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + if (grub_file_read (file, kernel, filelen) != filelen) + { +- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), ++ argv[0]); + goto fail; + } + +- if (! grub_linuxefi_secure_validate (kernel, filelen)) ++ rc = grub_linuxefi_secure_validate (kernel, filelen); ++ if (rc < 0) + { + grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), + argv[0]); +@@ -203,6 +208,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_dprintf ("linux", "params = %lx\n", (unsigned long) params); ++ + grub_memset (params, 0, 16384); + + grub_memcpy (&lh, kernel, sizeof (lh)); +@@ -241,6 +248,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_dprintf ("linux", "linux_cmdline = %lx\n", ++ (unsigned long)linux_cmdline); ++ + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, + linux_cmdline + sizeof (LINUX_IMAGE) - 1, +@@ -275,9 +285,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memcpy (params, &lh, 2 * 512); + + params->type_of_loader = 0x21; ++ grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", ++ kernel_mem, handover_offset); + + fail: +- + if (file) + grub_file_close (file); + +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index d9ede36773..0033d9305a 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -22,7 +22,7 @@ + #include + #include + +-grub_efi_boolean_t ++int + EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size); + grub_err_t + EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index 0ed8781f03..a43adf2746 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -223,7 +223,11 @@ struct grub_pe64_optional_header + struct grub_pe32_section_table + { + char name[8]; +- grub_uint32_t virtual_size; ++ union ++ { ++ grub_uint32_t physical_address; ++ grub_uint32_t virtual_size; ++ }; + grub_uint32_t virtual_address; + grub_uint32_t raw_data_size; + grub_uint32_t raw_data_offset; +@@ -234,12 +238,18 @@ struct grub_pe32_section_table + grub_uint32_t characteristics; + }; + ++#define GRUB_PE32_SCN_TYPE_NO_PAD 0x00000008 + #define GRUB_PE32_SCN_CNT_CODE 0x00000020 + #define GRUB_PE32_SCN_CNT_INITIALIZED_DATA 0x00000040 +-#define GRUB_PE32_SCN_MEM_DISCARDABLE 0x02000000 +-#define GRUB_PE32_SCN_MEM_EXECUTE 0x20000000 +-#define GRUB_PE32_SCN_MEM_READ 0x40000000 +-#define GRUB_PE32_SCN_MEM_WRITE 0x80000000 ++#define GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA 0x00000080 ++#define GRUB_PE32_SCN_LNK_OTHER 0x00000100 ++#define GRUB_PE32_SCN_LNK_INFO 0x00000200 ++#define GRUB_PE32_SCN_LNK_REMOVE 0x00000800 ++#define GRUB_PE32_SCN_LNK_COMDAT 0x00001000 ++#define GRUB_PE32_SCN_GPREL 0x00008000 ++#define GRUB_PE32_SCN_MEM_16BIT 0x00020000 ++#define GRUB_PE32_SCN_MEM_LOCKED 0x00040000 ++#define GRUB_PE32_SCN_MEM_PRELOAD 0x00080000 + + #define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 + #define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +@@ -248,10 +258,28 @@ struct grub_pe32_section_table + #define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 + #define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 + #define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 ++#define GRUB_PE32_SCN_ALIGN_128BYTES 0x00800000 ++#define GRUB_PE32_SCN_ALIGN_256BYTES 0x00900000 ++#define GRUB_PE32_SCN_ALIGN_512BYTES 0x00A00000 ++#define GRUB_PE32_SCN_ALIGN_1024BYTES 0x00B00000 ++#define GRUB_PE32_SCN_ALIGN_2048BYTES 0x00C00000 ++#define GRUB_PE32_SCN_ALIGN_4096BYTES 0x00D00000 ++#define GRUB_PE32_SCN_ALIGN_8192BYTES 0x00E00000 + + #define GRUB_PE32_SCN_ALIGN_SHIFT 20 + #define GRUB_PE32_SCN_ALIGN_MASK 7 + ++#define GRUB_PE32_SCN_LNK_NRELOC_OVFL 0x01000000 ++#define GRUB_PE32_SCN_MEM_DISCARDABLE 0x02000000 ++#define GRUB_PE32_SCN_MEM_NOT_CACHED 0x04000000 ++#define GRUB_PE32_SCN_MEM_NOT_PAGED 0x08000000 ++#define GRUB_PE32_SCN_MEM_SHARED 0x10000000 ++#define GRUB_PE32_SCN_MEM_EXECUTE 0x20000000 ++#define GRUB_PE32_SCN_MEM_READ 0x40000000 ++#define GRUB_PE32_SCN_MEM_WRITE 0x80000000 ++ ++ ++ + #define GRUB_PE32_SIGNATURE_SIZE 4 + + struct grub_pe32_header +@@ -274,6 +302,20 @@ struct grub_pe32_header + #endif + }; + ++struct grub_pe32_header_32 ++{ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ struct grub_pe32_coff_header coff_header; ++ struct grub_pe32_optional_header optional_header; ++}; ++ ++struct grub_pe32_header_64 ++{ ++ char signature[GRUB_PE32_SIGNATURE_SIZE]; ++ struct grub_pe32_coff_header coff_header; ++ struct grub_pe64_optional_header optional_header; ++}; ++ + struct grub_pe32_fixup_block + { + grub_uint32_t page_rva; diff --git a/SOURCES/0008-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch b/SOURCES/0008-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch new file mode 100644 index 0000000..487d5c0 --- /dev/null +++ b/SOURCES/0008-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch @@ -0,0 +1,390 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 6 Oct 2015 16:09:25 -0400 +Subject: [PATCH] Make any of the loaders that link in efi mode honor secure + boot. + +And in this case "honor" means "even if somebody does link this in, they +won't register commands if SB is enabled." + +Signed-off-by: Peter Jones +--- + grub-core/commands/iorw.c | 7 +++++++ + grub-core/commands/memrw.c | 7 +++++++ + grub-core/kern/dl.c | 3 ++- + grub-core/kern/efi/efi.c | 34 ---------------------------------- + grub-core/loader/efi/appleloader.c | 7 +++++++ + grub-core/loader/efi/chainloader.c | 1 + + grub-core/loader/i386/bsd.c | 7 +++++++ + grub-core/loader/i386/linux.c | 7 +++++++ + grub-core/loader/i386/pc/linux.c | 7 +++++++ + grub-core/loader/multiboot.c | 7 +++++++ + grub-core/loader/xnu.c | 7 +++++++ + include/grub/efi/efi.h | 1 - + include/grub/ia64/linux.h | 0 + include/grub/mips/linux.h | 0 + include/grub/powerpc/linux.h | 0 + include/grub/sparc64/linux.h | 0 + 16 files changed, 59 insertions(+), 36 deletions(-) + create mode 100644 include/grub/ia64/linux.h + create mode 100644 include/grub/mips/linux.h + create mode 100644 include/grub/powerpc/linux.h + create mode 100644 include/grub/sparc64/linux.h + +diff --git a/grub-core/commands/iorw.c b/grub-core/commands/iorw.c +index 584baec8f9..7b2999b14b 100644 +--- a/grub-core/commands/iorw.c ++++ b/grub-core/commands/iorw.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -119,6 +120,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) + + GRUB_MOD_INIT(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_read_byte = + grub_register_extcmd ("inb", grub_cmd_read, 0, + N_("PORT"), N_("Read 8-bit value from PORT."), +@@ -147,6 +151,9 @@ GRUB_MOD_INIT(memrw) + + GRUB_MOD_FINI(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); +diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c +index d401a6db0e..39cf3a06db 100644 +--- a/grub-core/commands/memrw.c ++++ b/grub-core/commands/memrw.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -121,6 +122,9 @@ grub_cmd_write (grub_command_t cmd, int argc, char **argv) + + GRUB_MOD_INIT(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_read_byte = + grub_register_extcmd ("read_byte", grub_cmd_read, 0, + N_("ADDR"), N_("Read 8-bit value from ADDR."), +@@ -149,6 +153,9 @@ GRUB_MOD_INIT(memrw) + + GRUB_MOD_FINI(memrw) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_extcmd (cmd_read_byte); + grub_unregister_extcmd (cmd_read_word); + grub_unregister_extcmd (cmd_read_dword); +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index b714937095..7afb9e6f72 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + /* Platforms where modules are in a readonly area of memory. */ + #if defined(GRUB_MACHINE_QEMU) +@@ -704,7 +705,7 @@ grub_dl_load_file (const char *filename) + grub_dl_t mod = 0; + + #ifdef GRUB_MACHINE_EFI +- if (grub_efi_secure_boot ()) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { + #if 0 + /* This is an error, but grub2-mkconfig still generates a pile of +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 4a2259aa1c..8cff7be028 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -286,40 +286,6 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + return grub_efi_get_variable_with_attributes (var, guid, datasize_out, data_out, NULL); + } + +-grub_efi_boolean_t +-grub_efi_secure_boot (void) +-{ +- grub_efi_guid_t efi_var_guid = GRUB_EFI_GLOBAL_VARIABLE_GUID; +- grub_size_t datasize; +- char *secure_boot = NULL; +- char *setup_mode = NULL; +- grub_efi_boolean_t ret = 0; +- +- secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize); +- if (datasize != 1 || !secure_boot) +- { +- grub_dprintf ("secureboot", "No SecureBoot variable\n"); +- goto out; +- } +- grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot); +- +- setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize); +- if (datasize != 1 || !setup_mode) +- { +- grub_dprintf ("secureboot", "No SetupMode variable\n"); +- goto out; +- } +- grub_dprintf ("secureboot", "SetupMode: %d\n", *setup_mode); +- +- if (*secure_boot && !*setup_mode) +- ret = 1; +- +- out: +- grub_free (secure_boot); +- grub_free (setup_mode); +- return ret; +-} +- + #pragma GCC diagnostic ignored "-Wcast-align" + + /* Search the mods section from the PE32/PE32+ image. This code uses +diff --git a/grub-core/loader/efi/appleloader.c b/grub-core/loader/efi/appleloader.c +index 74888c463b..585f2b5738 100644 +--- a/grub-core/loader/efi/appleloader.c ++++ b/grub-core/loader/efi/appleloader.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -227,6 +228,9 @@ static grub_command_t cmd; + + GRUB_MOD_INIT(appleloader) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd = grub_register_command ("appleloader", grub_cmd_appleloader, + N_("[OPTS]"), + /* TRANSLATORS: This command is used on EFI to +@@ -238,5 +242,8 @@ GRUB_MOD_INIT(appleloader) + + GRUB_MOD_FINI(appleloader) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd); + } +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index e6a8d4ad0e..07c4937898 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c +index 5f3290ce17..54befc2662 100644 +--- a/grub-core/loader/i386/bsd.c ++++ b/grub-core/loader/i386/bsd.c +@@ -40,6 +40,7 @@ + #ifdef GRUB_MACHINE_PCBIOS + #include + #endif ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -2137,6 +2138,9 @@ static grub_command_t cmd_netbsd_module_elf, cmd_openbsd_ramdisk; + + GRUB_MOD_INIT (bsd) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + /* Net and OpenBSD kernels are often compressed. */ + grub_dl_load ("gzio"); + +@@ -2176,6 +2180,9 @@ GRUB_MOD_INIT (bsd) + + GRUB_MOD_FINI (bsd) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_extcmd (cmd_freebsd); + grub_unregister_extcmd (cmd_openbsd); + grub_unregister_extcmd (cmd_netbsd); +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index dccf3bb300..4aeb0e4b9a 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1138,6 +1139,9 @@ static grub_command_t cmd_linux, cmd_initrd; + + GRUB_MOD_INIT(linux) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_linux = grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); + cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, +@@ -1147,6 +1151,9 @@ GRUB_MOD_INIT(linux) + + GRUB_MOD_FINI(linux) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_initrd); + } +diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c +index 4b1750e360..e3fa1221e8 100644 +--- a/grub-core/loader/i386/pc/linux.c ++++ b/grub-core/loader/i386/pc/linux.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -487,6 +488,9 @@ static grub_command_t cmd_linux, cmd_linux16, cmd_initrd, cmd_initrd16; + + GRUB_MOD_INIT(linux16) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_linux = + grub_register_command ("linux", grub_cmd_linux, + 0, N_("Load Linux.")); +@@ -504,6 +508,9 @@ GRUB_MOD_INIT(linux16) + + GRUB_MOD_FINI(linux16) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd_linux); + grub_unregister_command (cmd_linux16); + grub_unregister_command (cmd_initrd); +diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c +index facb13f3d3..47e481f457 100644 +--- a/grub-core/loader/multiboot.c ++++ b/grub-core/loader/multiboot.c +@@ -50,6 +50,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -444,6 +445,9 @@ static grub_command_t cmd_multiboot, cmd_module; + + GRUB_MOD_INIT(multiboot) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_multiboot = + #ifdef GRUB_USE_MULTIBOOT2 + grub_register_command ("multiboot2", grub_cmd_multiboot, +@@ -464,6 +468,9 @@ GRUB_MOD_INIT(multiboot) + + GRUB_MOD_FINI(multiboot) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + grub_unregister_command (cmd_multiboot); + grub_unregister_command (cmd_module); + } +diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c +index 1c0cf6a430..baa54e652a 100644 +--- a/grub-core/loader/xnu.c ++++ b/grub-core/loader/xnu.c +@@ -35,6 +35,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -1497,6 +1498,9 @@ static grub_extcmd_t cmd_splash; + + GRUB_MOD_INIT(xnu) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + cmd_kernel = grub_register_command ("xnu_kernel", grub_cmd_xnu_kernel, 0, + N_("Load XNU image.")); + cmd_kernel64 = grub_register_command ("xnu_kernel64", grub_cmd_xnu_kernel64, +@@ -1540,6 +1544,9 @@ GRUB_MOD_INIT(xnu) + + GRUB_MOD_FINI(xnu) + { ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) ++ return; ++ + #ifndef GRUB_MACHINE_EMU + grub_unregister_command (cmd_resume); + #endif +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 6295df85f3..585fa6662b 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -91,7 +91,6 @@ EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, + void *data, + grub_size_t datasize); +-grub_efi_boolean_t EXPORT_FUNC (grub_efi_secure_boot) (void); + int + EXPORT_FUNC (grub_efi_compare_device_paths) (const grub_efi_device_path_t *dp1, + const grub_efi_device_path_t *dp2); +diff --git a/include/grub/ia64/linux.h b/include/grub/ia64/linux.h +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/include/grub/mips/linux.h b/include/grub/mips/linux.h +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/include/grub/powerpc/linux.h b/include/grub/powerpc/linux.h +new file mode 100644 +index 0000000000..e69de29bb2 +diff --git a/include/grub/sparc64/linux.h b/include/grub/sparc64/linux.h +new file mode 100644 +index 0000000000..e69de29bb2 diff --git a/SOURCES/0009-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch b/SOURCES/0009-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch new file mode 100644 index 0000000..452f43c --- /dev/null +++ b/SOURCES/0009-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch @@ -0,0 +1,264 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 8 Jul 2019 12:32:37 +0200 +Subject: [PATCH] Handle multi-arch (64-on-32) boot in linuxefi loader. + +Allow booting 64-bit kernels on 32-bit EFI on x86. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/linux.c | 9 +++- + grub-core/loader/i386/efi/linux.c | 110 ++++++++++++++++++++++++++------------ + include/grub/i386/linux.h | 7 ++- + 3 files changed, 89 insertions(+), 37 deletions(-) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index c8ecce6dfd..0622dfa48d 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -69,12 +69,17 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size) + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (void *kernel_addr, grub_off_t offset, ++grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + void *kernel_params) + { + handover_func hf; ++ int offset = 0; + +- hf = (handover_func)((char *)kernel_addr + offset); ++#ifdef __x86_64__ ++ offset = 512; ++#endif ++ ++ hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + + return GRUB_ERR_BUG; +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 6b24cbb948..3017d0f3e5 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -44,14 +44,10 @@ static char *linux_cmdline; + static grub_err_t + grub_linuxefi_boot (void) + { +- int offset = 0; +- +-#ifdef __x86_64__ +- offset = 512; +-#endif + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)kernel_mem, handover_offset + offset, ++ return grub_efi_linux_boot ((char *)kernel_mem, ++ handover_offset, + params); + } + +@@ -153,14 +149,20 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- struct linux_i386_kernel_header lh; +- grub_ssize_t len, start, filelen; ++ struct linux_i386_kernel_header *lh = NULL; ++ grub_ssize_t start, filelen; + void *kernel = NULL; ++ int setup_header_end_offset; + int rc; + + grub_dl_ref (my_mod); +@@ -200,48 +202,79 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); +- ++ params = grub_efi_allocate_pages_max (0x3fffffff, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); + goto fail; + } + +- grub_dprintf ("linux", "params = %lx\n", (unsigned long) params); ++ grub_dprintf ("linux", "params = %p\n", params); + +- grub_memset (params, 0, 16384); ++ grub_memset (params, 0, sizeof(*params)); + +- grub_memcpy (&lh, kernel, sizeof (lh)); +- +- if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "lh is at %p\n", lh); ++ grub_dprintf ("linux", "checking lh->boot_flag\n"); ++ if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { + grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); + goto fail; + } + +- if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) ++ grub_dprintf ("linux", "checking lh->setup_sects\n"); ++ if (lh->setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) + { + grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); + goto fail; + } + +- if (lh.version < grub_cpu_to_le16 (0x020b)) ++ grub_dprintf ("linux", "checking lh->version\n"); ++ if (lh->version < grub_cpu_to_le16 (0x020b)) + { + grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); + goto fail; + } + +- if (!lh.handover_offset) ++ grub_dprintf ("linux", "checking lh->handover_offset\n"); ++ if (!lh->handover_offset) + { + grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); + goto fail; + } + ++#if defined(__x86_64__) || defined(__aarch64__) ++ grub_dprintf ("linux", "checking lh->xloadflags\n"); ++ if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support 64-bit CPUs")); ++ goto fail; ++ } ++#endif ++ ++#if defined(__i386__) ++ if ((lh->xloadflags & LINUX_XLF_KERNEL_64) && ++ !(lh->xloadflags & LINUX_XLF_EFI_HANDOVER_32)) ++ { ++ grub_error (GRUB_ERR_BAD_OS, ++ N_("kernel doesn't support 32-bit handover")); ++ goto fail; ++ } ++#endif ++ + grub_dprintf ("linux", "setting up cmdline\n"); + linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh.cmdline_size + 1)); +- ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -254,22 +287,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, + linux_cmdline + sizeof (LINUX_IMAGE) - 1, +- lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1), ++ lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + +- lh.cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); ++ lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- handover_offset = lh.handover_offset; ++ grub_dprintf ("linux", "computing handover offset\n"); ++ handover_offset = lh->handover_offset; + +- start = (lh.setup_sects + 1) * 512; +- len = grub_file_size(file) - start; ++ start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_pages_max(lh.pref_address, +- BYTES_TO_PAGES(lh.init_size)); ++ kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, ++ BYTES_TO_PAGES(lh->init_size)); + + if (!kernel_mem) + kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh.init_size)); ++ BYTES_TO_PAGES(lh->init_size)); + + if (!kernel_mem) + { +@@ -277,14 +312,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- grub_memcpy (kernel_mem, (char *)kernel + start, len); ++ grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); + loaded=1; ++ grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); ++ lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + +- lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; +- grub_memcpy (params, &lh, 2 * 512); ++ grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- params->type_of_loader = 0x21; ++ grub_dprintf ("linux", "setting lh->type_of_loader\n"); ++ lh->type_of_loader = 0x6; ++ ++ grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); ++ params->ext_loader_type = 0; ++ params->ext_loader_ver = 2; + grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", + kernel_mem, handover_offset); + +@@ -301,10 +343,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + loaded = 0; + } + +- if (linux_cmdline && !loaded) ++ if (linux_cmdline && lh && !loaded) + grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) + linux_cmdline, +- BYTES_TO_PAGES(lh.cmdline_size + 1)); ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + + if (kernel_mem && !loaded) + grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index eddf9251d9..25ef52c04e 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -138,7 +138,12 @@ struct linux_i386_kernel_header + grub_uint32_t kernel_alignment; + grub_uint8_t relocatable; + grub_uint8_t min_alignment; +- grub_uint8_t pad[2]; ++#define LINUX_XLF_KERNEL_64 (1<<0) ++#define LINUX_XLF_CAN_BE_LOADED_ABOVE_4G (1<<1) ++#define LINUX_XLF_EFI_HANDOVER_32 (1<<2) ++#define LINUX_XLF_EFI_HANDOVER_64 (1<<3) ++#define LINUX_XLF_EFI_KEXEC (1<<4) ++ grub_uint16_t xloadflags; + grub_uint32_t cmdline_size; + grub_uint32_t hardware_subarch; + grub_uint64_t hardware_subarch_data; diff --git a/SOURCES/0010-re-write-.gitignore.patch b/SOURCES/0010-re-write-.gitignore.patch new file mode 100644 index 0000000..b6fa0be --- /dev/null +++ b/SOURCES/0010-re-write-.gitignore.patch @@ -0,0 +1,246 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 8 Jul 2019 12:55:29 +0200 +Subject: [PATCH] re-write .gitignore + +--- + .gitignore | 150 ++++++++++++++++++++++++++++++++++++++ + docs/.gitignore | 5 ++ + grub-core/.gitignore | 16 ++++ + grub-core/lib/.gitignore | 1 + + include/grub/gcrypt/.gitignore | 2 + + po/.gitignore | 5 ++ + util/bash-completion.d/.gitignore | 2 + + 7 files changed, 181 insertions(+) + create mode 100644 docs/.gitignore + create mode 100644 grub-core/.gitignore + create mode 100644 grub-core/lib/.gitignore + create mode 100644 include/grub/gcrypt/.gitignore + create mode 100644 po/.gitignore + create mode 100644 util/bash-completion.d/.gitignore + +diff --git a/.gitignore b/.gitignore +index f6a1bd0517..208d1d2325 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -275,3 +275,153 @@ widthspec.bin + /xfs_test + /xzcompress_test + /zfs_test ++======= ++# things ./autogen.sh will create ++/Makefile.utilgcry.def ++/ABOUT-NLS ++/aclocal.m4 ++/autom4te.cache ++/build-aux ++/configure ++/gnulib ++/grub-core/lib/gnulib/ ++/Makefile ++ ++# things very common editors create that we never want ++*~ ++.*.sw? ++*.patch ++ ++# stuff you're likely to make while building test trees ++grub.cfg ++/build*/ ++ ++# built objects across the whole tree ++Makefile.in ++*.a ++*.am ++*.efi ++*.exec ++*.image ++*.img ++*.info ++*.lst ++*.marker ++/m4 ++*.mod ++*.module ++*.o ++*.pf2 ++*.yy.[ch] ++.deps/ ++.deps-core/ ++.deps-util/ ++.dirstamp ++ ++# next are things you get if you do ./configure in the topdir (for e.g. ++# "make dist" invocation. ++/config-util.h ++/config.h ++/include/grub/cpu ++/include/grub/machine ++/INSTALL ++/INSTALL.grub ++/po/Makefile.in.in ++/po/Makevars ++/po/Makevars.template ++/po/POTFILES ++/po/Rules-quot ++/stamp-h ++/stamp-h1 ++bootstrap.log ++config.log ++config.status ++ ++# stuff "make dist" creates ++ChangeLog ++grub-*.tar ++grub-*.tar.* ++ ++# stuff "make" creates ++/[[:digit:]][[:digit:]]_?* ++/ascii.h ++/build-grub-gen-asciih ++/build-grub-gen-widthspec ++/build-grub-mkfont ++/config-util.h.in ++/garbage-gen ++/grub*-bios-setup ++/grub*-bios-setup.8 ++/grub*-editenv ++/grub*-editenv.1 ++/grub*-file ++/grub*-file.1 ++/grub*-fs-tester ++/grub*-fstest ++/grub*-fstest.1 ++/grub*-get-kernel-settings ++/grub*-get-kernel-settings.3 ++/grub*-glue-efi ++/grub*-glue-efi.1 ++/grub*-install ++/grub*-install.8 ++/grub*-kbdcomp ++/grub*-kbdcomp.1 ++/grub*-macbless ++/grub*-macbless.8 ++/grub*-menulst2cfg ++/grub*-menulst2cfg.1 ++/grub*-mount ++/grub*-mount.1 ++/grub*-mkconfig ++/grub*-mkconfig.8 ++/grub*-mkconfig_lib ++/grub*-mkfont ++/grub*-mkfont.1 ++/grub*-mkimage ++/grub*-mkimage.1 ++/grub*-mklayout ++/grub*-mklayout.1 ++/grub*-mknetdir ++/grub*-mknetdir.1 ++/grub*-mkpasswd-pbkdf2 ++/grub*-mkpasswd-pbkdf2.1 ++/grub*-mkrelpath ++/grub*-mkrelpath.1 ++/grub*-mkrescue ++/grub*-mkrescue.1 ++/grub*-mkstandalone ++/grub*-mkstandalone.1 ++/grub*-ofpathname ++/grub*-ofpathname.8 ++/grub*-probe ++/grub*-probe.8 ++/grub*-reboot ++/grub*-reboot.8 ++/grub*-render-label ++/grub*-render-label.1 ++/grub*-script-check ++/grub*-script-check.1 ++/grub*-set-bootflag ++/grub*-set-bootflag.1 ++/grub*-set-default ++/grub*-set-default.8 ++/grub*-set-password ++/grub*-set-password.8 ++/grub*-shell ++/grub*-shell-tester ++/grub*-sparc64-setup ++/grub*-sparc64-setup.8 ++/grub*-syslinux2cfg ++/grub*-syslinux2cfg.1 ++/grub*-switch-to-blscfg ++/grub*-switch-to-blscfg.8 ++/grub_fstest.pp ++/grub_fstest_init.c ++/grub_fstest_init.lst ++/grub_script.tab.[ch] ++/libgrub.pp ++/libgrub_a_init.c ++/libgrub_a_init.lst ++/stamp-h.in ++/widthspec.h +diff --git a/docs/.gitignore b/docs/.gitignore +new file mode 100644 +index 0000000000..e1d849ef95 +--- /dev/null ++++ b/docs/.gitignore +@@ -0,0 +1,5 @@ ++/*.in ++/Makefile ++/stamp-1 ++/stamp-vti ++/version*.texi +diff --git a/grub-core/.gitignore b/grub-core/.gitignore +new file mode 100644 +index 0000000000..2acce28115 +--- /dev/null ++++ b/grub-core/.gitignore +@@ -0,0 +1,16 @@ ++/*.lst ++/Makefile ++/Makefile.gcry.def ++/unidata.c ++/build-grub-module-verifier ++/gdb_grub ++/genmod.sh ++/gensyminfo.sh ++/gentrigtables ++/gmodule.pl ++/grub_script.tab.[ch] ++/modinfo.sh ++/rs_decoder.h ++/symlist.c ++/symlist.h ++/trigtables.c +diff --git a/grub-core/lib/.gitignore b/grub-core/lib/.gitignore +new file mode 100644 +index 0000000000..6815459140 +--- /dev/null ++++ b/grub-core/lib/.gitignore +@@ -0,0 +1 @@ ++/libgcrypt-grub/ +diff --git a/include/grub/gcrypt/.gitignore b/include/grub/gcrypt/.gitignore +new file mode 100644 +index 0000000000..8fbf564624 +--- /dev/null ++++ b/include/grub/gcrypt/.gitignore +@@ -0,0 +1,2 @@ ++g10lib.h ++gcrypt.h +diff --git a/po/.gitignore b/po/.gitignore +new file mode 100644 +index 0000000000..f507e7741e +--- /dev/null ++++ b/po/.gitignore +@@ -0,0 +1,5 @@ ++/Makefile ++/POTFILES*.in ++/grub.pot ++/remove-potcdate.sed ++/stamp-po +diff --git a/util/bash-completion.d/.gitignore b/util/bash-completion.d/.gitignore +new file mode 100644 +index 0000000000..6813a527ad +--- /dev/null ++++ b/util/bash-completion.d/.gitignore +@@ -0,0 +1,2 @@ ++Makefile ++grub diff --git a/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch b/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch new file mode 100644 index 0000000..316b9eb --- /dev/null +++ b/SOURCES/0011-IBM-client-architecture-CAS-reboot-support.patch @@ -0,0 +1,176 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Thu, 20 Sep 2012 18:07:39 -0300 +Subject: [PATCH] IBM client architecture (CAS) reboot support + +This is an implementation of IBM client architecture (CAS) reboot for GRUB. + +There are cases where the POWER firmware must reboot in order to support +specific features requested by a kernel. The kernel calls +ibm,client-architecture-support and it may either return or reboot with +the new feature set. eg: + +Calling ibm,client-architecture-support.../ +Elapsed time since release of system processors: 70959 mins 50 secs +Welcome to GRUB! + +Instead of return to the GRUB menu, it will check if the flag for CAS +reboot is set. If so, grub will automatically boot the last booted +kernel using the same parameters + +Signed-off-by: Paulo Flabiano Smorigo +[rharwood@redhat.com: commit message rewrap] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/ieee1275/openfw.c | 63 ++++++++++++++++++++++++++++++++++++++++ + grub-core/normal/main.c | 19 ++++++++++++ + grub-core/script/execute.c | 7 +++++ + include/grub/ieee1275/ieee1275.h | 2 ++ + 4 files changed, 91 insertions(+) + +diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c +index 4d493ab766..3a6689abb1 100644 +--- a/grub-core/kern/ieee1275/openfw.c ++++ b/grub-core/kern/ieee1275/openfw.c +@@ -591,3 +591,66 @@ grub_ieee1275_get_boot_dev (void) + + return bootpath; + } ++ ++/* Check if it's a CAS reboot. If so, set the script to be executed. */ ++int ++grub_ieee1275_cas_reboot (char *script) ++{ ++ grub_uint32_t ibm_ca_support_reboot; ++ grub_uint32_t ibm_fw_nbr_reboots; ++ char property_value[10]; ++ grub_ssize_t actual; ++ grub_ieee1275_ihandle_t options; ++ ++ if (grub_ieee1275_finddevice ("/options", &options) < 0) ++ return -1; ++ ++ /* Check two properties, one is enough to get cas reboot value */ ++ ibm_ca_support_reboot = 0; ++ if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen, ++ "ibm,client-architecture-support-reboot", ++ &ibm_ca_support_reboot, ++ sizeof (ibm_ca_support_reboot), ++ &actual) >= 0) ++ grub_dprintf("ieee1275", "ibm,client-architecture-support-reboot: %u\n", ++ ibm_ca_support_reboot); ++ ++ ibm_fw_nbr_reboots = 0; ++ if (grub_ieee1275_get_property (options, "ibm,fw-nbr-reboots", ++ property_value, sizeof (property_value), ++ &actual) >= 0) ++ { ++ property_value[sizeof (property_value) - 1] = 0; ++ ibm_fw_nbr_reboots = (grub_uint8_t) grub_strtoul (property_value, 0, 10); ++ grub_dprintf("ieee1275", "ibm,fw-nbr-reboots: %u\n", ibm_fw_nbr_reboots); ++ } ++ ++ if (ibm_ca_support_reboot || ibm_fw_nbr_reboots) ++ { ++ if (! grub_ieee1275_get_property_length (options, "boot-last-label", &actual)) ++ { ++ if (actual > 1024) ++ script = grub_realloc (script, actual + 1); ++ grub_ieee1275_get_property (options, "boot-last-label", script, actual, ++ &actual); ++ return 0; ++ } ++ } ++ ++ grub_ieee1275_set_boot_last_label (""); ++ ++ return -1; ++} ++ ++int grub_ieee1275_set_boot_last_label (const char *text) ++{ ++ grub_ieee1275_ihandle_t options; ++ grub_ssize_t actual; ++ ++ grub_dprintf("ieee1275", "set boot_last_label (size: %u)\n", grub_strlen(text)); ++ if (! grub_ieee1275_finddevice ("/options", &options) && ++ options != (grub_ieee1275_ihandle_t) -1) ++ grub_ieee1275_set_property (options, "boot-last-label", text, ++ grub_strlen (text), &actual); ++ return 0; ++} +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index c4ebe9e22a..70614de156 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -34,6 +34,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_IEEE1275 ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -276,6 +279,22 @@ grub_normal_execute (const char *config, int nested, int batch) + { + menu = read_config_file (config); + ++#ifdef GRUB_MACHINE_IEEE1275 ++ int boot; ++ boot = 0; ++ char *script; ++ script = grub_malloc (1024); ++ if (! grub_ieee1275_cas_reboot (script)) ++ { ++ char *dummy[1] = { NULL }; ++ if (! grub_script_execute_sourcecode (script)) ++ boot = 1; ++ } ++ grub_free (script); ++ if (boot) ++ grub_command_execute ("boot", 0, 0); ++#endif ++ + /* Ignore any error. */ + grub_errno = GRUB_ERR_NONE; + } +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index 25158407dd..ad80399246 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -28,6 +28,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_IEEE1275 ++#include ++#endif + + /* Max digits for a char is 3 (0xFF is 255), similarly for an int it + is sizeof (int) * 3, and one extra for a possible -ve sign. */ +@@ -883,6 +886,10 @@ grub_script_execute_sourcecode (const char *source) + grub_err_t ret = 0; + struct grub_script *parsed_script; + ++#ifdef GRUB_MACHINE_IEEE1275 ++ grub_ieee1275_set_boot_last_label (source); ++#endif ++ + while (source) + { + char *line; +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index 73e2f46447..0a599607f3 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -254,6 +254,8 @@ int EXPORT_FUNC(grub_ieee1275_devalias_next) (struct grub_ieee1275_devalias *ali + void EXPORT_FUNC(grub_ieee1275_children_peer) (struct grub_ieee1275_devalias *alias); + void EXPORT_FUNC(grub_ieee1275_children_first) (const char *devpath, + struct grub_ieee1275_devalias *alias); ++int EXPORT_FUNC(grub_ieee1275_cas_reboot) (char *script); ++int EXPORT_FUNC(grub_ieee1275_set_boot_last_label) (const char *text); + + char *EXPORT_FUNC(grub_ieee1275_get_boot_dev) (void); + diff --git a/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch b/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch new file mode 100644 index 0000000..121af84 --- /dev/null +++ b/SOURCES/0012-for-ppc-reset-console-display-attr-when-clear-screen.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Wed, 24 Apr 2013 10:51:48 -0300 +Subject: [PATCH] for ppc, reset console display attr when clear screen + +v2: Also use \x0c instead of a literal ^L to make future patches less +awkward. + +This should fix this bugzilla: +https://bugzilla.redhat.com/show_bug.cgi?id=908519 + +Signed-off-by: Peter Jones +Signed-off-by: Paulo Flabiano Smorigo +Signed-off-by: Robbie Harwood +--- + grub-core/term/terminfo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/term/terminfo.c b/grub-core/term/terminfo.c +index 85ecf06b4d..05c88dcf49 100644 +--- a/grub-core/term/terminfo.c ++++ b/grub-core/term/terminfo.c +@@ -151,7 +151,7 @@ grub_terminfo_set_current (struct grub_term_output *term, + /* Clear the screen. Using serial console, screen(1) only recognizes the + * ANSI escape sequence. Using video console, Apple Open Firmware + * (version 3.1.1) only recognizes the literal ^L. So use both. */ +- data->cls = grub_strdup (" \e[2J"); ++ data->cls = grub_strdup ("\x0c\e[2J\e[m"); + data->reverse_video_on = grub_strdup ("\e[7m"); + data->reverse_video_off = grub_strdup ("\e[m"); + if (grub_strcmp ("ieee1275", str) == 0) diff --git a/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch b/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch new file mode 100644 index 0000000..917943f --- /dev/null +++ b/SOURCES/0013-Disable-GRUB-video-support-for-IBM-power-machines.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Tue, 11 Jun 2013 15:14:05 -0300 +Subject: [PATCH] Disable GRUB video support for IBM power machines + +Should fix the problem in bugzilla: +https://bugzilla.redhat.com/show_bug.cgi?id=973205 + +Signed-off-by: Paulo Flabiano Smorigo +Signed-off-by: Robbie Harwood +--- + grub-core/kern/ieee1275/cmain.c | 5 ++++- + grub-core/video/ieee1275.c | 9 ++++++--- + include/grub/ieee1275/ieee1275.h | 2 ++ + 3 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c +index 20cbbd761e..04df9d2c66 100644 +--- a/grub-core/kern/ieee1275/cmain.c ++++ b/grub-core/kern/ieee1275/cmain.c +@@ -90,7 +90,10 @@ grub_ieee1275_find_options (void) + } + + if (rc >= 0 && grub_strncmp (tmp, "IBM", 3) == 0) +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); ++ { ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_TREE_SCANNING_FOR_DISKS); ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT); ++ } + + /* Old Macs have no key repeat, newer ones have fully working one. + The ones inbetween when repeated key generates an escaoe sequence +diff --git a/grub-core/video/ieee1275.c b/grub-core/video/ieee1275.c +index 17a3dbbb57..b8e4b3feb3 100644 +--- a/grub-core/video/ieee1275.c ++++ b/grub-core/video/ieee1275.c +@@ -352,9 +352,12 @@ static struct grub_video_adapter grub_video_ieee1275_adapter = + + GRUB_MOD_INIT(ieee1275_fb) + { +- find_display (); +- if (display) +- grub_video_register (&grub_video_ieee1275_adapter); ++ if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT)) ++ { ++ find_display (); ++ if (display) ++ grub_video_register (&grub_video_ieee1275_adapter); ++ } + } + + GRUB_MOD_FINI(ieee1275_fb) +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index 0a599607f3..b5a1d49bbc 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -148,6 +148,8 @@ enum grub_ieee1275_flag + GRUB_IEEE1275_FLAG_CURSORONOFF_ANSI_BROKEN, + + GRUB_IEEE1275_FLAG_RAW_DEVNAMES, ++ ++ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT + }; + + extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); diff --git a/SOURCES/0014-Move-bash-completion-script-922997.patch b/SOURCES/0014-Move-bash-completion-script-922997.patch new file mode 100644 index 0000000..a84d66e --- /dev/null +++ b/SOURCES/0014-Move-bash-completion-script-922997.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 3 Apr 2013 14:35:34 -0400 +Subject: [PATCH] Move bash completion script (#922997) + +Apparently these go in a new place now. +--- + configure.ac | 11 +++++++++++ + util/bash-completion.d/Makefile.am | 1 - + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 7517fc49d9..8331f95b64 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -314,6 +314,14 @@ AC_SUBST(grubdirname) + AC_DEFINE_UNQUOTED(GRUB_DIR_NAME, "$grubdirname", + [Default grub directory name]) + ++PKG_PROG_PKG_CONFIG ++AS_IF([$($PKG_CONFIG --exists bash-completion)], [ ++ bashcompletiondir=$($PKG_CONFIG --variable=completionsdir bash-completion) ++] , [ ++ bashcompletiondir=${datadir}/bash-completion/completions ++]) ++AC_SUBST(bashcompletiondir) ++ + # + # Checks for build programs. + # +@@ -525,6 +533,9 @@ HOST_CFLAGS="$HOST_CFLAGS $grub_cv_cc_w_extra_flags" + # Check for target programs. + # + ++# This makes sure pkg.m4 is available. ++m4_pattern_forbid([^_?PKG_[A-Z_]+$],[*** pkg.m4 missing, please install pkg-config]) ++ + # Find tools for the target. + if test "x$target_alias" != x && test "x$host_alias" != "x$target_alias"; then + tmp_ac_tool_prefix="$ac_tool_prefix" +diff --git a/util/bash-completion.d/Makefile.am b/util/bash-completion.d/Makefile.am +index 136287cf1b..61108f0542 100644 +--- a/util/bash-completion.d/Makefile.am ++++ b/util/bash-completion.d/Makefile.am +@@ -6,7 +6,6 @@ EXTRA_DIST = $(bash_completion_source) + + CLEANFILES = $(bash_completion_script) config.log + +-bashcompletiondir = $(sysconfdir)/bash_completion.d + bashcompletion_DATA = $(bash_completion_script) + + $(bash_completion_script): $(bash_completion_source) $(top_builddir)/config.status diff --git a/SOURCES/0015-Allow-fallback-to-include-entries-by-title-not-just-.patch b/SOURCES/0015-Allow-fallback-to-include-entries-by-title-not-just-.patch new file mode 100644 index 0000000..6450a54 --- /dev/null +++ b/SOURCES/0015-Allow-fallback-to-include-entries-by-title-not-just-.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 5 Sep 2014 10:07:04 -0400 +Subject: [PATCH] Allow "fallback" to include entries by title, not just + number. + +Resolves: rhbz#1026084 + +Signed-off-by: Peter Jones +--- + grub-core/normal/menu.c | 85 +++++++++++++++++++++++++++++++++---------------- + 1 file changed, 58 insertions(+), 27 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 8397886fa0..d7a222e681 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -163,15 +163,40 @@ grub_menu_set_timeout (int timeout) + } + } + ++static int ++menuentry_eq (const char *id, const char *spec) ++{ ++ const char *ptr1, *ptr2; ++ ptr1 = id; ++ ptr2 = spec; ++ while (1) ++ { ++ if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) ++ return ptr2 - spec; ++ if (*ptr2 == '>' && ptr2[1] != '>') ++ return 0; ++ if (*ptr2 == '>') ++ ptr2++; ++ if (*ptr1 != *ptr2) ++ return 0; ++ if (*ptr1 == 0) ++ return ptr1 - id; ++ ptr1++; ++ ptr2++; ++ } ++ return 0; ++} ++ + /* Get the first entry number from the value of the environment variable NAME, + which is a space-separated list of non-negative integers. The entry number + which is returned is stripped from the value of NAME. If no entry number + can be found, -1 is returned. */ + static int +-get_and_remove_first_entry_number (const char *name) ++get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + { + const char *val, *tail; + int entry; ++ int sz = 0; + + val = grub_env_get (name); + if (! val) +@@ -181,9 +206,39 @@ get_and_remove_first_entry_number (const char *name) + + entry = (int) grub_strtoul (val, &tail, 0); + ++ if (grub_errno == GRUB_ERR_BAD_NUMBER) ++ { ++ /* See if the variable matches the title of a menu entry. */ ++ grub_menu_entry_t e = menu->entry_list; ++ int i; ++ ++ for (i = 0; e; i++) ++ { ++ sz = menuentry_eq (e->title, val); ++ if (sz < 1) ++ sz = menuentry_eq (e->id, val); ++ ++ if (sz >= 1) ++ { ++ entry = i; ++ break; ++ } ++ e = e->next; ++ } ++ ++ if (sz > 0) ++ grub_errno = GRUB_ERR_NONE; ++ ++ if (! e) ++ entry = -1; ++ } ++ + if (grub_errno == GRUB_ERR_NONE) + { +- /* Skip whitespace to find the next digit. */ ++ if (sz > 0) ++ tail += sz; ++ ++ /* Skip whitespace to find the next entry. */ + while (*tail && grub_isspace (*tail)) + tail++; + grub_env_set (name, tail); +@@ -346,7 +401,7 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + grub_menu_execute_entry (entry, 1); + + /* Deal with fallback entries. */ +- while ((fallback_entry = get_and_remove_first_entry_number ("fallback")) ++ while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback")) + >= 0) + { + grub_print_error (); +@@ -464,30 +519,6 @@ grub_menu_register_viewer (struct grub_menu_viewer *viewer) + viewers = viewer; + } + +-static int +-menuentry_eq (const char *id, const char *spec) +-{ +- const char *ptr1, *ptr2; +- ptr1 = id; +- ptr2 = spec; +- while (1) +- { +- if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) +- return 1; +- if (*ptr2 == '>' && ptr2[1] != '>') +- return 0; +- if (*ptr2 == '>') +- ptr2++; +- if (*ptr1 != *ptr2) +- return 0; +- if (*ptr1 == 0) +- return 1; +- ptr1++; +- ptr2++; +- } +-} +- +- + /* Get the entry number from the variable NAME. */ + static int + get_entry_number (grub_menu_t menu, const char *name) diff --git a/SOURCES/0016-Make-exit-take-a-return-code.patch b/SOURCES/0016-Make-exit-take-a-return-code.patch new file mode 100644 index 0000000..654ef73 --- /dev/null +++ b/SOURCES/0016-Make-exit-take-a-return-code.patch @@ -0,0 +1,267 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 26 Feb 2014 21:49:12 -0500 +Subject: [PATCH] Make "exit" take a return code. + +This adds "exit" with a return code. With this patch, any "exit" +command /may/ include a return code, and on platforms that support +returning with an exit status, we will do so. By default we return the +same exit status we did before this patch. + +Signed-off-by: Peter Jones +--- + grub-core/commands/minicmd.c | 20 ++++++++++++++++---- + grub-core/kern/efi/efi.c | 9 +++++++-- + grub-core/kern/emu/main.c | 2 +- + grub-core/kern/emu/misc.c | 5 +++-- + grub-core/kern/i386/coreboot/init.c | 2 +- + grub-core/kern/i386/qemu/init.c | 2 +- + grub-core/kern/ieee1275/init.c | 2 +- + grub-core/kern/mips/arc/init.c | 2 +- + grub-core/kern/mips/loongson/init.c | 2 +- + grub-core/kern/mips/qemu_mips/init.c | 2 +- + grub-core/kern/misc.c | 11 ++++++++++- + grub-core/kern/uboot/init.c | 6 +++--- + grub-core/kern/xen/init.c | 2 +- + include/grub/misc.h | 2 +- + 14 files changed, 48 insertions(+), 21 deletions(-) + +diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c +index fa498931ed..2bd3ac76f2 100644 +--- a/grub-core/commands/minicmd.c ++++ b/grub-core/commands/minicmd.c +@@ -182,12 +182,24 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), + } + + /* exit */ +-static grub_err_t __attribute__ ((noreturn)) ++static grub_err_t + grub_mini_cmd_exit (struct grub_command *cmd __attribute__ ((unused)), +- int argc __attribute__ ((unused)), +- char *argv[] __attribute__ ((unused))) ++ int argc, char *argv[]) + { +- grub_exit (); ++ int retval = -1; ++ unsigned long n; ++ ++ if (argc < 0 || argc > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ if (argc == 1) ++ { ++ n = grub_strtoul (argv[0], 0, 10); ++ if (n != ~0UL) ++ retval = n; ++ } ++ ++ grub_exit (retval); + /* Not reached. */ + } + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 8cff7be028..05d8237a9b 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -165,11 +165,16 @@ grub_reboot (void) + } + + void +-grub_exit (void) ++grub_exit (int retval) + { ++ int rc = GRUB_EFI_LOAD_ERROR; ++ ++ if (retval == 0) ++ rc = GRUB_EFI_SUCCESS; ++ + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + efi_call_4 (grub_efi_system_table->boot_services->exit, +- grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0); ++ grub_efi_image_handle, rc, 0, 0); + for (;;) ; + } + +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 425bb96034..55ea5a11cc 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -67,7 +67,7 @@ grub_reboot (void) + } + + void +-grub_exit (void) ++grub_exit (int retval __attribute__((unused))) + { + grub_reboot (); + } +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index dfd8a8ec48..0ff13bcaf8 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -151,9 +151,10 @@ xasprintf (const char *fmt, ...) + + #if !defined (GRUB_MACHINE_EMU) || defined (GRUB_UTIL) + void +-grub_exit (void) ++__attribute__ ((noreturn)) ++grub_exit (int rc) + { +- exit (1); ++ exit (rc < 0 ? 1 : rc); + } + #endif + +diff --git a/grub-core/kern/i386/coreboot/init.c b/grub-core/kern/i386/coreboot/init.c +index 3314f027fe..36f9134b7b 100644 +--- a/grub-core/kern/i386/coreboot/init.c ++++ b/grub-core/kern/i386/coreboot/init.c +@@ -41,7 +41,7 @@ extern grub_uint8_t _end[]; + extern grub_uint8_t _edata[]; + + void __attribute__ ((noreturn)) +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + /* We can't use grub_fatal() in this function. This would create an infinite + loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */ +diff --git a/grub-core/kern/i386/qemu/init.c b/grub-core/kern/i386/qemu/init.c +index 271b6fbfab..9fafe98f01 100644 +--- a/grub-core/kern/i386/qemu/init.c ++++ b/grub-core/kern/i386/qemu/init.c +@@ -42,7 +42,7 @@ extern grub_uint8_t _end[]; + extern grub_uint8_t _edata[]; + + void __attribute__ ((noreturn)) +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + /* We can't use grub_fatal() in this function. This would create an infinite + loop, since grub_fatal() calls grub_abort() which in turn calls grub_exit(). */ +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index d483e35eed..e71d158416 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -71,7 +71,7 @@ grub_addr_t grub_ieee1275_original_stack; + #endif + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + grub_ieee1275_exit (); + } +diff --git a/grub-core/kern/mips/arc/init.c b/grub-core/kern/mips/arc/init.c +index 2ed3ff3191..5c40c34078 100644 +--- a/grub-core/kern/mips/arc/init.c ++++ b/grub-core/kern/mips/arc/init.c +@@ -276,7 +276,7 @@ grub_halt (void) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + GRUB_ARC_FIRMWARE_VECTOR->exit (); + +diff --git a/grub-core/kern/mips/loongson/init.c b/grub-core/kern/mips/loongson/init.c +index 7b96531b98..dff598ca7b 100644 +--- a/grub-core/kern/mips/loongson/init.c ++++ b/grub-core/kern/mips/loongson/init.c +@@ -304,7 +304,7 @@ grub_halt (void) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + grub_halt (); + } +diff --git a/grub-core/kern/mips/qemu_mips/init.c b/grub-core/kern/mips/qemu_mips/init.c +index be88b77d22..8b6c55ffc0 100644 +--- a/grub-core/kern/mips/qemu_mips/init.c ++++ b/grub-core/kern/mips/qemu_mips/init.c +@@ -75,7 +75,7 @@ grub_machine_fini (int flags __attribute__ ((unused))) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + grub_halt (); + } +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 3af336ee22..63b586d09c 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1209,9 +1209,18 @@ grub_abort (void) + grub_getkey (); + } + +- grub_exit (); ++ grub_exit (1); + } + ++#if defined (__clang__) && !defined (GRUB_UTIL) ++/* clang emits references to abort(). */ ++void __attribute__ ((noreturn)) ++abort (void) ++{ ++ grub_abort (); ++} ++#endif ++ + void + grub_fatal (const char *fmt, ...) + { +diff --git a/grub-core/kern/uboot/init.c b/grub-core/kern/uboot/init.c +index 3e338645c5..be2a5be1d0 100644 +--- a/grub-core/kern/uboot/init.c ++++ b/grub-core/kern/uboot/init.c +@@ -39,9 +39,9 @@ extern grub_size_t grub_total_module_size; + static unsigned long timer_start; + + void +-grub_exit (void) ++grub_exit (int rc) + { +- grub_uboot_return (0); ++ grub_uboot_return (rc < 0 ? 1 : rc); + } + + static grub_uint64_t +@@ -78,7 +78,7 @@ grub_machine_init (void) + if (!ver) + { + /* Don't even have a console to log errors to... */ +- grub_exit (); ++ grub_exit (-1); + } + else if (ver > API_SIG_VERSION) + { +diff --git a/grub-core/kern/xen/init.c b/grub-core/kern/xen/init.c +index 782ca72952..708b060f32 100644 +--- a/grub-core/kern/xen/init.c ++++ b/grub-core/kern/xen/init.c +@@ -584,7 +584,7 @@ grub_machine_init (void) + } + + void +-grub_exit (void) ++grub_exit (int rc __attribute__((unused))) + { + struct sched_shutdown arg; + +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 7d2b551969..fd18e6320b 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -353,7 +353,7 @@ int EXPORT_FUNC(grub_vsnprintf) (char *str, grub_size_t n, const char *fmt, + char *EXPORT_FUNC(grub_xasprintf) (const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 1, 2))) WARN_UNUSED_RESULT; + char *EXPORT_FUNC(grub_xvasprintf) (const char *fmt, va_list args) WARN_UNUSED_RESULT; +-void EXPORT_FUNC(grub_exit) (void) __attribute__ ((noreturn)); ++void EXPORT_FUNC(grub_exit) (int rc) __attribute__ ((noreturn)); + grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, + grub_uint64_t d, + grub_uint64_t *r); diff --git a/SOURCES/0017-Make-efi-machines-load-an-env-block-from-a-variable.patch b/SOURCES/0017-Make-efi-machines-load-an-env-block-from-a-variable.patch new file mode 100644 index 0000000..ecfab5a --- /dev/null +++ b/SOURCES/0017-Make-efi-machines-load-an-env-block-from-a-variable.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 7 Dec 2015 14:20:49 -0500 +Subject: [PATCH] Make efi machines load an env block from a variable + +Signed-off-by: Peter Jones +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/efi/init.c | 36 +++++++++++++++++++++++++++++++++++- + 2 files changed, 36 insertions(+), 1 deletion(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 45d3edaa4d..c865a08b02 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -207,6 +207,7 @@ kernel = { + efi = kern/efi/acpi.c; + efi = kern/efi/sb.c; + efi = kern/lockdown.c; ++ efi = lib/envblk.c; + i386_coreboot = kern/i386/pc/acpi.c; + i386_multiboot = kern/i386/pc/acpi.c; + i386_coreboot = kern/acpi.c; +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 7facacf09c..6d39bd3ad2 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -27,8 +27,11 @@ + #include + #include + #include ++ + #include + ++#include ++ + #ifdef GRUB_STACK_PROTECTOR + + static grub_efi_guid_t rng_protocol_guid = GRUB_EFI_RNG_PROTOCOL_GUID; +@@ -82,6 +85,36 @@ stack_protector_init (void) + + grub_addr_t grub_modbase; + ++#define GRUB_EFI_GRUB_VARIABLE_GUID \ ++ { 0x91376aff, 0xcba6, 0x42be, \ ++ { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ ++ } ++ ++/* Helper for grub_efi_env_init */ ++static int ++set_var (const char *name, const char *value, ++ void *whitelist __attribute__((__unused__))) ++{ ++ grub_env_set (name, value); ++ return 0; ++} ++ ++static void ++grub_efi_env_init (void) ++{ ++ grub_efi_guid_t efi_grub_guid = GRUB_EFI_GRUB_VARIABLE_GUID; ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ ++ grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ return; ++ ++ grub_envblk_iterate (envblk, NULL, set_var); ++ grub_free (envblk_s.buf); ++} ++ + void + grub_efi_init (void) + { +@@ -108,10 +141,11 @@ grub_efi_init (void) + efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer, + 0, 0, 0, NULL); + ++ grub_efi_env_init (); + grub_efidisk_init (); + } + +-void (*grub_efi_net_config) (grub_efi_handle_t hnd, ++void (*grub_efi_net_config) (grub_efi_handle_t hnd, + char **device, + char **path); + diff --git a/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch b/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch new file mode 100644 index 0000000..1e310e9 --- /dev/null +++ b/SOURCES/0018-Migrate-PPC-from-Yaboot-to-Grub2.patch @@ -0,0 +1,154 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Hamzy +Date: Wed, 28 Mar 2012 14:46:41 -0500 +Subject: [PATCH] Migrate PPC from Yaboot to Grub2 + +Add configuration support for serial terminal consoles. This will set +the maximum screen size so that text is not overwritten. + +Signed-off-by: Mark Hamzy +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 7 +++ + util/grub.d/20_ppc_terminfo.in | 114 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 121 insertions(+) + create mode 100644 util/grub.d/20_ppc_terminfo.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index f8b356cc1f..2c9b283a23 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -508,6 +508,13 @@ script = { + condition = COND_HOST_LINUX; + }; + ++script = { ++ name = '20_ppc_terminfo'; ++ common = util/grub.d/20_ppc_terminfo.in; ++ installdir = grubconf; ++ condition = COND_HOST_LINUX; ++}; ++ + script = { + name = '30_os-prober'; + common = util/grub.d/30_os-prober.in; +diff --git a/util/grub.d/20_ppc_terminfo.in b/util/grub.d/20_ppc_terminfo.in +new file mode 100644 +index 0000000000..10d6658682 +--- /dev/null ++++ b/util/grub.d/20_ppc_terminfo.in +@@ -0,0 +1,114 @@ ++#! /bin/sh ++set -e ++ ++# grub-mkconfig helper script. ++# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++bindir=@bindir@ ++libdir=@libdir@ ++. "@datadir@/@PACKAGE@/grub-mkconfig_lib" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR=@localedir@ ++ ++X=80 ++Y=24 ++TERMINAL=ofconsole ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ echo "$0: option requires an argument -- '$opt'" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++check_terminfo () { ++ ++ while test $# -gt 0 ++ do ++ option=$1 ++ shift ++ ++ case "$option" in ++ terminfo | TERMINFO) ++ ;; ++ ++ -g) ++ NEWXY=`argument $option "$@"` ++ NEWX=`echo $NEWXY | cut -d x -f 1` ++ NEWY=`echo $NEWXY | cut -d x -f 2` ++ ++ if [ ${NEWX} -ge 80 ] ; then ++ X=${NEWX} ++ else ++ echo "Warning: ${NEWX} is less than the minimum size of 80" ++ fi ++ ++ if [ ${NEWY} -ge 24 ] ; then ++ Y=${NEWY} ++ else ++ echo "Warning: ${NEWY} is less than the minimum size of 24" ++ fi ++ ++ shift ++ ;; ++ ++ *) ++# # accept console or ofconsole ++# if [ "$option" != "console" -a "$option" != "ofconsole" ] ; then ++# echo "Error: GRUB_TERMINFO unknown console: $option" ++# exit 1 ++# fi ++# # perfer console ++# TERMINAL=console ++ # accept ofconsole ++ if [ "$option" != "ofconsole" ] ; then ++ echo "Error: GRUB_TERMINFO unknown console: $option" ++ exit 1 ++ fi ++ # perfer console ++ TERMINAL=ofconsole ++ ;; ++ esac ++ ++ done ++ ++} ++ ++if ! uname -m | grep -q ppc ; then ++ exit 0 ++fi ++ ++if [ "x${GRUB_TERMINFO}" != "x" ] ; then ++ F1=`echo ${GRUB_TERMINFO} | cut -d " " -f 1` ++ ++ if [ "${F1}" != "terminfo" ] ; then ++ echo "Error: GRUB_TERMINFO is set to \"${GRUB_TERMINFO}\" The first word should be terminfo." ++ exit 1 ++ fi ++ ++ check_terminfo ${GRUB_TERMINFO} ++fi ++ ++cat << EOF ++ terminfo -g ${X}x${Y} ${TERMINAL} ++EOF diff --git a/SOURCES/0019-Add-fw_path-variable-revised.patch b/SOURCES/0019-Add-fw_path-variable-revised.patch new file mode 100644 index 0000000..804938b --- /dev/null +++ b/SOURCES/0019-Add-fw_path-variable-revised.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Wed, 19 Sep 2012 21:22:55 -0300 +Subject: [PATCH] Add fw_path variable (revised) + +This patch makes grub look for its config file on efi where the app was +found. It was originally written by Matthew Garrett, and adapted to fix the +"No modules are loaded on grub2 network boot" issue: + +https://bugzilla.redhat.com/show_bug.cgi?id=857936 + +Signed-off-by: Paulo Flabiano Smorigo +Signed-off-by: Robbie Harwood +--- + grub-core/kern/main.c | 13 ++++++------- + grub-core/normal/main.c | 25 ++++++++++++++++++++++++- + 2 files changed, 30 insertions(+), 8 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 73967e2f5b..d1de9fa687 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -128,16 +128,15 @@ grub_set_prefix_and_root (void) + + grub_machine_get_bootlocation (&fwdevice, &fwpath); + +- if (fwdevice) ++ if (fwdevice && fwpath) + { +- char *cmdpath; ++ char *fw_path; + +- cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : ""); +- if (cmdpath) ++ fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath); ++ if (fw_path) + { +- grub_env_set ("cmdpath", cmdpath); +- grub_env_export ("cmdpath"); +- grub_free (cmdpath); ++ grub_env_set ("fw_path", fw_path); ++ grub_free (fw_path); + } + } + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 70614de156..62571e6dfc 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -339,7 +339,30 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + /* Guess the config filename. It is necessary to make CONFIG static, + so that it won't get broken by longjmp. */ + char *config; +- const char *prefix; ++ const char *prefix, *fw_path; ++ ++ fw_path = grub_env_get ("fw_path"); ++ if (fw_path) ++ { ++ config = grub_xasprintf ("%s/grub.cfg", fw_path); ++ if (config) ++ { ++ grub_file_t file; ++ ++ file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); ++ if (file) ++ { ++ grub_file_close (file); ++ grub_enter_normal_mode (config); ++ } ++ else ++ { ++ /* Ignore all errors. */ ++ grub_errno = 0; ++ } ++ grub_free (config); ++ } ++ } + + prefix = grub_env_get ("prefix"); + if (prefix) diff --git a/SOURCES/0020-Pass-x-hex-hex-straight-through-unmolested.patch b/SOURCES/0020-Pass-x-hex-hex-straight-through-unmolested.patch new file mode 100644 index 0000000..c2623ac --- /dev/null +++ b/SOURCES/0020-Pass-x-hex-hex-straight-through-unmolested.patch @@ -0,0 +1,173 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Oct 2012 13:24:37 -0400 +Subject: [PATCH] Pass "\x[[:hex:]][[:hex:]]" straight through unmolested. + +Don't munge raw spaces when we're doing our cmdline escaping (#923374) + +Signed-off-by: Peter Jones +--- + grub-core/commands/wildcard.c | 16 +++++++++++++++- + grub-core/lib/cmdline.c | 25 +++++++++++++++++++++++-- + grub-core/script/execute.c | 43 +++++++++++++++++++++++++++++++++++++------ + 3 files changed, 75 insertions(+), 9 deletions(-) + +diff --git a/grub-core/commands/wildcard.c b/grub-core/commands/wildcard.c +index cc3290311f..8f67a4be7f 100644 +--- a/grub-core/commands/wildcard.c ++++ b/grub-core/commands/wildcard.c +@@ -488,6 +488,12 @@ check_file (const char *dir, const char *basename) + return ctx.found; + } + ++static int ++is_hex(char c) ++{ ++ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ++} ++ + static void + unescape (char *out, const char *in, const char *end) + { +@@ -496,7 +502,15 @@ unescape (char *out, const char *in, const char *end) + + for (optr = out, iptr = in; iptr < end;) + { +- if (*iptr == '\\' && iptr + 1 < end) ++ if (*iptr == '\\' && iptr + 3 < end && iptr[1] == 'x' && is_hex(iptr[2]) && is_hex(iptr[3])) ++ { ++ *optr++ = *iptr++; ++ *optr++ = *iptr++; ++ *optr++ = *iptr++; ++ *optr++ = *iptr++; ++ continue; ++ } ++ else if (*iptr == '\\' && iptr + 1 < end) + { + *optr++ = iptr[1]; + iptr += 2; +diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c +index ed0b149dca..8e2294d8ff 100644 +--- a/grub-core/lib/cmdline.c ++++ b/grub-core/lib/cmdline.c +@@ -20,6 +20,12 @@ + #include + #include + ++static int ++is_hex(char c) ++{ ++ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ++} ++ + static unsigned int check_arg (char *c, int *has_space) + { + int space = 0; +@@ -27,7 +33,13 @@ static unsigned int check_arg (char *c, int *has_space) + + while (*c) + { +- if (*c == '\\' || *c == '\'' || *c == '"') ++ if (*c == '\\' && *(c+1) == 'x' && is_hex(*(c+2)) && is_hex(*(c+3))) ++ { ++ size += 4; ++ c += 4; ++ continue; ++ } ++ else if (*c == '\\' || *c == '\'' || *c == '"') + size++; + else if (*c == ' ') + space = 1; +@@ -86,7 +98,16 @@ grub_create_loader_cmdline (int argc, char *argv[], char *buf, + + while (*c) + { +- if (*c == '\\' || *c == '\'' || *c == '"') ++ if (*c == '\\' && *(c+1) == 'x' && ++ is_hex(*(c+2)) && is_hex(*(c+3))) ++ { ++ *buf++ = *c++; ++ *buf++ = *c++; ++ *buf++ = *c++; ++ *buf++ = *c++; ++ continue; ++ } ++ else if (*c == '\\' || *c == '\'' || *c == '"') + *buf++ = '\\'; + + *buf++ = *c; +diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c +index ad80399246..0c6dd9c520 100644 +--- a/grub-core/script/execute.c ++++ b/grub-core/script/execute.c +@@ -56,6 +56,12 @@ static struct grub_script_scope *scope = 0; + /* Wildcard translator for GRUB script. */ + struct grub_script_wildcard_translator *grub_wildcard_translator; + ++static int ++is_hex(char c) ++{ ++ return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); ++} ++ + static char* + wildcard_escape (const char *s) + { +@@ -72,7 +78,15 @@ wildcard_escape (const char *s) + i = 0; + while ((ch = *s++)) + { +- if (ch == '*' || ch == '\\' || ch == '?') ++ if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2])) ++ { ++ p[i++] = ch; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ continue; ++ } ++ else if (ch == '*' || ch == '\\' || ch == '?') + p[i++] = '\\'; + p[i++] = ch; + } +@@ -96,7 +110,14 @@ wildcard_unescape (const char *s) + i = 0; + while ((ch = *s++)) + { +- if (ch == '\\') ++ if (ch == '\\' && s[0] == 'x' && is_hex(s[1]) && is_hex(s[2])) ++ { ++ p[i++] = '\\'; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ p[i++] = *s++; ++ } ++ else if (ch == '\\') + p[i++] = *s++; + else + p[i++] = ch; +@@ -398,10 +419,20 @@ parse_string (const char *str, + switch (*ptr) + { + case '\\': +- escaped = !escaped; +- if (!escaped && put) +- *(put++) = '\\'; +- ptr++; ++ if (!escaped && put && *(ptr+1) == 'x' && is_hex(*(ptr+2)) && is_hex(*(ptr+3))) ++ { ++ *(put++) = *ptr++; ++ *(put++) = *ptr++; ++ *(put++) = *ptr++; ++ *(put++) = *ptr++; ++ } ++ else ++ { ++ escaped = !escaped; ++ if (!escaped && put) ++ *(put++) = '\\'; ++ ptr++; ++ } + break; + case '$': + if (escaped) diff --git a/SOURCES/0021-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch b/SOURCES/0021-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch new file mode 100644 index 0000000..c452b5f --- /dev/null +++ b/SOURCES/0021-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch @@ -0,0 +1,1609 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Jan 2013 06:31:38 +0100 +Subject: [PATCH] blscfg: add blscfg module to parse Boot Loader Specification + snippets + +The BootLoaderSpec (BLS) defines a scheme where different bootloaders can +share a format for boot items and a configuration directory that accepts +these common configurations as drop-in files. + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +[wjt: some cleanups and fixes] +Signed-off-by: Will Thompson +--- + grub-core/Makefile.core.def | 11 + + grub-core/commands/blscfg.c | 1177 ++++++++++++++++++++++++++++++++++++++++ + grub-core/commands/legacycfg.c | 5 +- + grub-core/commands/loadenv.c | 77 +-- + grub-core/commands/menuentry.c | 20 +- + grub-core/normal/main.c | 6 + + grub-core/commands/loadenv.h | 93 ++++ + include/grub/compiler.h | 2 + + include/grub/menu.h | 13 + + include/grub/normal.h | 2 +- + 10 files changed, 1324 insertions(+), 82 deletions(-) + create mode 100644 grub-core/commands/blscfg.c + create mode 100644 grub-core/commands/loadenv.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index c865a08b02..c15e91943b 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -814,6 +814,16 @@ module = { + common = commands/blocklist.c; + }; + ++module = { ++ name = blscfg; ++ common = commands/blscfg.c; ++ common = commands/loadenv.h; ++ enable = powerpc_ieee1275; ++ enable = efi; ++ enable = i386_pc; ++ enable = emu; ++}; ++ + module = { + name = boot; + common = commands/boot.c; +@@ -980,6 +990,7 @@ module = { + module = { + name = loadenv; + common = commands/loadenv.c; ++ common = commands/loadenv.h; + common = lib/envblk.c; + }; + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +new file mode 100644 +index 0000000000..e907a6a5d2 +--- /dev/null ++++ b/grub-core/commands/blscfg.c +@@ -0,0 +1,1177 @@ ++/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/ ++ ++/* bls.c - implementation of the boot loader spec */ ++ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#include "loadenv.h" ++ ++#define GRUB_BLS_CONFIG_PATH "/loader/entries/" ++#ifdef GRUB_MACHINE_EMU ++#define GRUB_BOOT_DEVICE "/boot" ++#else ++#define GRUB_BOOT_DEVICE "($root)" ++#endif ++ ++struct keyval ++{ ++ const char *key; ++ char *val; ++}; ++ ++static struct bls_entry *entries = NULL; ++ ++#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) ++ ++static int bls_add_keyval(struct bls_entry *entry, char *key, char *val) ++{ ++ char *k, *v; ++ struct keyval **kvs, *kv; ++ int new_n = entry->nkeyvals + 1; ++ ++ kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *)); ++ if (!kvs) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ entry->keyvals = kvs; ++ ++ kv = grub_malloc (sizeof (struct keyval)); ++ if (!kv) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ ++ k = grub_strdup (key); ++ if (!k) ++ { ++ grub_free (kv); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ } ++ ++ v = grub_strdup (val); ++ if (!v) ++ { ++ grub_free (k); ++ grub_free (kv); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't find space for BLS entry"); ++ } ++ ++ kv->key = k; ++ kv->val = v; ++ ++ entry->keyvals[entry->nkeyvals] = kv; ++ grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v); ++ entry->nkeyvals = new_n; ++ ++ return 0; ++} ++ ++/* Find they value of the key named by keyname. If there are allowed to be ++ * more than one, pass a pointer to an int set to -1 the first time, and pass ++ * the same pointer through each time after, and it'll return them in sorted ++ * order as defined in the BLS fragment file */ ++static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last) ++{ ++ int idx, start = 0; ++ struct keyval *kv = NULL; ++ ++ if (last) ++ start = *last + 1; ++ ++ for (idx = start; idx < entry->nkeyvals; idx++) { ++ kv = entry->keyvals[idx]; ++ ++ if (!grub_strcmp (keyname, kv->key)) ++ break; ++ } ++ ++ if (idx == entry->nkeyvals) { ++ if (last) ++ *last = -1; ++ return NULL; ++ } ++ ++ if (last) ++ *last = idx; ++ ++ return kv->val; ++} ++ ++#define goto_return(x) ({ ret = (x); goto finish; }) ++ ++/* compare alpha and numeric segments of two versions */ ++/* return 1: a is newer than b */ ++/* 0: a and b are the same version */ ++/* -1: b is newer than a */ ++static int vercmp(const char * a, const char * b) ++{ ++ char oldch1, oldch2; ++ char *abuf, *bbuf; ++ char *str1, *str2; ++ char * one, * two; ++ int rc; ++ int isnum; ++ int ret = 0; ++ ++ grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b); ++ if (!grub_strcmp(a, b)) ++ return 0; ++ ++ abuf = grub_malloc(grub_strlen(a) + 1); ++ bbuf = grub_malloc(grub_strlen(b) + 1); ++ str1 = abuf; ++ str2 = bbuf; ++ grub_strcpy(str1, a); ++ grub_strcpy(str2, b); ++ ++ one = str1; ++ two = str2; ++ ++ /* loop through each version segment of str1 and str2 and compare them */ ++ while (*one || *two) { ++ while (*one && !grub_isalnum(*one) && *one != '~' && *one != '+') one++; ++ while (*two && !grub_isalnum(*two) && *two != '~' && *two != '+') two++; ++ ++ /* handle the tilde separator, it sorts before everything else */ ++ if (*one == '~' || *two == '~') { ++ if (*one != '~') goto_return (1); ++ if (*two != '~') goto_return (-1); ++ one++; ++ two++; ++ continue; ++ } ++ ++ /* ++ * Handle plus separator. Concept is the same as tilde, ++ * except that if one of the strings ends (base version), ++ * the other is considered as higher version. ++ */ ++ if (*one == '+' || *two == '+') { ++ if (!*one) return -1; ++ if (!*two) return 1; ++ if (*one != '+') goto_return (1); ++ if (*two != '+') goto_return (-1); ++ one++; ++ two++; ++ continue; ++ } ++ ++ /* If we ran to the end of either, we are finished with the loop */ ++ if (!(*one && *two)) break; ++ ++ str1 = one; ++ str2 = two; ++ ++ /* grab first completely alpha or completely numeric segment */ ++ /* leave one and two pointing to the start of the alpha or numeric */ ++ /* segment and walk str1 and str2 to end of segment */ ++ if (grub_isdigit(*str1)) { ++ while (*str1 && grub_isdigit(*str1)) str1++; ++ while (*str2 && grub_isdigit(*str2)) str2++; ++ isnum = 1; ++ } else { ++ while (*str1 && grub_isalpha(*str1)) str1++; ++ while (*str2 && grub_isalpha(*str2)) str2++; ++ isnum = 0; ++ } ++ ++ /* save character at the end of the alpha or numeric segment */ ++ /* so that they can be restored after the comparison */ ++ oldch1 = *str1; ++ *str1 = '\0'; ++ oldch2 = *str2; ++ *str2 = '\0'; ++ ++ /* this cannot happen, as we previously tested to make sure that */ ++ /* the first string has a non-null segment */ ++ if (one == str1) goto_return(-1); /* arbitrary */ ++ ++ /* take care of the case where the two version segments are */ ++ /* different types: one numeric, the other alpha (i.e. empty) */ ++ /* numeric segments are always newer than alpha segments */ ++ /* XXX See patch #60884 (and details) from bugzilla #50977. */ ++ if (two == str2) goto_return (isnum ? 1 : -1); ++ ++ if (isnum) { ++ grub_size_t onelen, twolen; ++ /* this used to be done by converting the digit segments */ ++ /* to ints using atoi() - it's changed because long */ ++ /* digit segments can overflow an int - this should fix that. */ ++ ++ /* throw away any leading zeros - it's a number, right? */ ++ while (*one == '0') one++; ++ while (*two == '0') two++; ++ ++ /* whichever number has more digits wins */ ++ onelen = grub_strlen(one); ++ twolen = grub_strlen(two); ++ if (onelen > twolen) goto_return (1); ++ if (twolen > onelen) goto_return (-1); ++ } ++ ++ /* grub_strcmp will return which one is greater - even if the two */ ++ /* segments are alpha or if they are numeric. don't return */ ++ /* if they are equal because there might be more segments to */ ++ /* compare */ ++ rc = grub_strcmp(one, two); ++ if (rc) goto_return (rc < 1 ? -1 : 1); ++ ++ /* restore character that was replaced by null above */ ++ *str1 = oldch1; ++ one = str1; ++ *str2 = oldch2; ++ two = str2; ++ } ++ ++ /* this catches the case where all numeric and alpha segments have */ ++ /* compared identically but the segment sepparating characters were */ ++ /* different */ ++ if ((!*one) && (!*two)) goto_return (0); ++ ++ /* whichever version still has characters left over wins */ ++ if (!*one) goto_return (-1); else goto_return (1); ++ ++finish: ++ grub_free (abuf); ++ grub_free (bbuf); ++ return ret; ++} ++ ++/* returns name/version/release */ ++/* NULL string pointer returned if nothing found */ ++static void ++split_package_string (char *package_string, char **name, ++ char **version, char **release) ++{ ++ char *package_version, *package_release; ++ ++ /* Release */ ++ package_release = grub_strrchr (package_string, '-'); ++ ++ if (package_release != NULL) ++ *package_release++ = '\0'; ++ ++ *release = package_release; ++ ++ if (name == NULL) ++ { ++ *version = package_string; ++ } ++ else ++ { ++ /* Version */ ++ package_version = grub_strrchr(package_string, '-'); ++ ++ if (package_version != NULL) ++ *package_version++ = '\0'; ++ ++ *version = package_version; ++ /* Name */ ++ *name = package_string; ++ } ++ ++ /* Bubble up non-null values from release to name */ ++ if (name != NULL && *name == NULL) ++ { ++ *name = (*version == NULL ? *release : *version); ++ *version = *release; ++ *release = NULL; ++ } ++ if (*version == NULL) ++ { ++ *version = *release; ++ *release = NULL; ++ } ++} ++ ++static int ++split_cmp(char *nvr0, char *nvr1, int has_name) ++{ ++ int ret = 0; ++ char *name0, *version0, *release0; ++ char *name1, *version1, *release1; ++ ++ split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0); ++ split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1); ++ ++ if (has_name) ++ { ++ ret = vercmp(name0 == NULL ? "" : name0, ++ name1 == NULL ? "" : name1); ++ if (ret != 0) ++ return ret; ++ } ++ ++ ret = vercmp(version0 == NULL ? "" : version0, ++ version1 == NULL ? "" : version1); ++ if (ret != 0) ++ return ret; ++ ++ ret = vercmp(release0 == NULL ? "" : release0, ++ release1 == NULL ? "" : release1); ++ return ret; ++} ++ ++/* return 1: e0 is newer than e1 */ ++/* 0: e0 and e1 are the same version */ ++/* -1: e1 is newer than e0 */ ++static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1) ++{ ++ char *id0, *id1; ++ int r; ++ ++ id0 = grub_strdup(e0->filename); ++ id1 = grub_strdup(e1->filename); ++ ++ r = split_cmp(id0, id1, 1); ++ ++ grub_free(id0); ++ grub_free(id1); ++ ++ return r; ++} ++ ++static void list_add_tail(struct bls_entry *head, struct bls_entry *item) ++{ ++ item->next = head; ++ if (head->prev) ++ head->prev->next = item; ++ item->prev = head->prev; ++ head->prev = item; ++} ++ ++static int bls_add_entry(struct bls_entry *entry) ++{ ++ struct bls_entry *e, *last = NULL; ++ int rc; ++ ++ if (!entries) { ++ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); ++ entries = entry; ++ return 0; ++ } ++ ++ FOR_BLS_ENTRIES(e) { ++ rc = bls_cmp(entry, e); ++ ++ if (!rc) ++ return GRUB_ERR_BAD_ARGUMENT; ++ ++ if (rc == 1) { ++ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); ++ list_add_tail (e, entry); ++ if (e == entries) { ++ entries = entry; ++ entry->prev = NULL; ++ } ++ return 0; ++ } ++ last = e; ++ } ++ ++ if (last) { ++ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename); ++ last->next = entry; ++ entry->prev = last; ++ } ++ ++ return 0; ++} ++ ++struct read_entry_info { ++ const char *devid; ++ const char *dirname; ++ grub_file_t file; ++}; ++ ++static int read_entry ( ++ const char *filename, ++ const struct grub_dirhook_info *dirhook_info UNUSED, ++ void *data) ++{ ++ grub_size_t m = 0, n, clip = 0; ++ int rc = 0; ++ char *p = NULL; ++ grub_file_t f = NULL; ++ struct bls_entry *entry; ++ struct read_entry_info *info = (struct read_entry_info *)data; ++ ++ grub_dprintf ("blscfg", "filename: \"%s\"\n", filename); ++ ++ n = grub_strlen (filename); ++ ++ if (info->file) ++ { ++ f = info->file; ++ } ++ else ++ { ++ if (filename[0] == '.') ++ return 0; ++ ++ if (n <= 5) ++ return 0; ++ ++ if (grub_strcmp (filename + n - 5, ".conf") != 0) ++ return 0; ++ ++ p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename); ++ ++ f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG); ++ if (!f) ++ goto finish; ++ } ++ ++ entry = grub_zalloc (sizeof (*entry)); ++ if (!entry) ++ goto finish; ++ ++ if (info->file) ++ { ++ char *slash; ++ ++ if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0) ++ clip = 5; ++ ++ slash = grub_strrchr (filename, '/'); ++ if (!slash) ++ slash = grub_strrchr (filename, '\\'); ++ ++ while (*slash == '/' || *slash == '\\') ++ slash++; ++ ++ m = slash ? slash - filename : 0; ++ } ++ else ++ { ++ m = 0; ++ clip = 5; ++ } ++ n -= m; ++ ++ entry->filename = grub_strndup(filename + m, n - clip); ++ if (!entry->filename) ++ goto finish; ++ ++ entry->filename[n - 5] = '\0'; ++ ++ for (;;) ++ { ++ char *buf; ++ char *separator; ++ ++ buf = grub_file_getline (f); ++ if (!buf) ++ break; ++ ++ while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t')) ++ buf++; ++ if (buf[0] == '#') ++ continue; ++ ++ separator = grub_strchr (buf, ' '); ++ ++ if (!separator) ++ separator = grub_strchr (buf, '\t'); ++ ++ if (!separator || separator[1] == '\0') ++ { ++ grub_free (buf); ++ break; ++ } ++ ++ separator[0] = '\0'; ++ ++ do { ++ separator++; ++ } while (*separator == ' ' || *separator == '\t'); ++ ++ rc = bls_add_keyval (entry, buf, separator); ++ grub_free (buf); ++ if (rc < 0) ++ break; ++ } ++ ++ if (!rc) ++ bls_add_entry(entry); ++ ++finish: ++ if (p) ++ grub_free (p); ++ ++ if (f) ++ grub_file_close (f); ++ ++ return 0; ++} ++ ++static grub_envblk_t saved_env = NULL; ++ ++static int UNUSED ++save_var (const char *name, const char *value, void *whitelist UNUSED) ++{ ++ const char *val = grub_env_get (name); ++ grub_dprintf("blscfg", "saving \"%s\"\n", name); ++ ++ if (val) ++ grub_envblk_set (saved_env, name, value); ++ ++ return 0; ++} ++ ++static int UNUSED ++unset_var (const char *name, const char *value UNUSED, void *whitelist) ++{ ++ grub_dprintf("blscfg", "restoring \"%s\"\n", name); ++ if (! whitelist) ++ { ++ grub_env_unset (name); ++ return 0; ++ } ++ ++ if (test_whitelist_membership (name, ++ (const grub_env_whitelist_t *) whitelist)) ++ grub_env_unset (name); ++ ++ return 0; ++} ++ ++static char **bls_make_list (struct bls_entry *entry, const char *key, int *num) ++{ ++ int last = -1; ++ char *val; ++ ++ int nlist = 0; ++ char **list = NULL; ++ ++ list = grub_malloc (sizeof (char *)); ++ if (!list) ++ return NULL; ++ list[0] = NULL; ++ ++ while (1) ++ { ++ char **new; ++ ++ val = bls_get_val (entry, key, &last); ++ if (!val) ++ break; ++ ++ new = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (!new) ++ break; ++ ++ list = new; ++ list[nlist++] = val; ++ list[nlist] = NULL; ++ } ++ ++ if (!nlist) ++ { ++ grub_free (list); ++ return NULL; ++ } ++ ++ if (num) ++ *num = nlist; ++ ++ return list; ++} ++ ++static char *field_append(bool is_var, char *buffer, const char *start, const char *end) ++{ ++ char *tmp = grub_strndup(start, end - start + 1); ++ const char *field = tmp; ++ int term = is_var ? 2 : 1; ++ ++ if (is_var) { ++ field = grub_env_get (tmp); ++ if (!field) ++ return buffer; ++ } ++ ++ if (!buffer) ++ buffer = grub_zalloc (grub_strlen(field) + term); ++ else ++ buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field) + term); ++ ++ if (!buffer) ++ return NULL; ++ ++ tmp = buffer + grub_strlen(buffer); ++ tmp = grub_stpcpy (tmp, field); ++ ++ if (is_var) ++ tmp = grub_stpcpy (tmp, " "); ++ ++ return buffer; ++} ++ ++static char *expand_val(const char *value) ++{ ++ char *buffer = NULL; ++ const char *start = value; ++ const char *end = value; ++ bool is_var = false; ++ ++ if (!value) ++ return NULL; ++ ++ while (*value) { ++ if (*value == '$') { ++ if (start != end) { ++ buffer = field_append(is_var, buffer, start, end); ++ if (!buffer) ++ return NULL; ++ } ++ ++ is_var = true; ++ start = value + 1; ++ } else if (is_var) { ++ if (!grub_isalnum(*value) && *value != '_') { ++ buffer = field_append(is_var, buffer, start, end); ++ is_var = false; ++ start = value; ++ if (*start == ' ') ++ start++; ++ } ++ } ++ ++ end = value; ++ value++; ++ } ++ ++ if (start != end) { ++ buffer = field_append(is_var, buffer, start, end); ++ if (!buffer) ++ return NULL; ++ } ++ ++ return buffer; ++} ++ ++static char **early_initrd_list (const char *initrd) ++{ ++ int nlist = 0; ++ char **list = NULL; ++ char *separator; ++ ++ while ((separator = grub_strchr (initrd, ' '))) ++ { ++ list = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (!list) ++ return NULL; ++ ++ list[nlist++] = grub_strndup(initrd, separator - initrd); ++ list[nlist] = NULL; ++ initrd = separator + 1; ++ } ++ ++ list = grub_realloc (list, (nlist + 2) * sizeof (char *)); ++ if (!list) ++ return NULL; ++ ++ list[nlist++] = grub_strndup(initrd, grub_strlen(initrd)); ++ list[nlist] = NULL; ++ ++ return list; ++} ++ ++static void create_entry (struct bls_entry *entry) ++{ ++ int argc = 0; ++ const char **argv = NULL; ++ ++ char *title = NULL; ++ char *clinux = NULL; ++ char *options = NULL; ++ char **initrds = NULL; ++ char *initrd = NULL; ++ const char *early_initrd = NULL; ++ char **early_initrds = NULL; ++ char *initrd_prefix = NULL; ++ char *devicetree = NULL; ++ char *dt = NULL; ++ char *id = entry->filename; ++ char *dotconf = id; ++ char *hotkey = NULL; ++ ++ char *users = NULL; ++ char **classes = NULL; ++ ++ char **args = NULL; ++ ++ char *src = NULL; ++ int i, index; ++ bool add_dt_prefix = false; ++ ++ grub_dprintf("blscfg", "%s got here\n", __func__); ++ clinux = bls_get_val (entry, "linux", NULL); ++ if (!clinux) ++ { ++ grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename); ++ goto finish; ++ } ++ ++ /* ++ * strip the ".conf" off the end before we make it our "id" field. ++ */ ++ do ++ { ++ dotconf = grub_strstr(dotconf, ".conf"); ++ } while (dotconf != NULL && dotconf[5] != '\0'); ++ if (dotconf) ++ dotconf[0] = '\0'; ++ ++ title = bls_get_val (entry, "title", NULL); ++ options = expand_val (bls_get_val (entry, "options", NULL)); ++ ++ if (!options) ++ options = expand_val (grub_env_get("default_kernelopts")); ++ ++ initrds = bls_make_list (entry, "initrd", NULL); ++ ++ devicetree = expand_val (bls_get_val (entry, "devicetree", NULL)); ++ ++ if (!devicetree) ++ { ++ devicetree = expand_val (grub_env_get("devicetree")); ++ add_dt_prefix = true; ++ } ++ ++ hotkey = bls_get_val (entry, "grub_hotkey", NULL); ++ users = expand_val (bls_get_val (entry, "grub_users", NULL)); ++ classes = bls_make_list (entry, "grub_class", NULL); ++ args = bls_make_list (entry, "grub_arg", &argc); ++ ++ argc += 1; ++ argv = grub_malloc ((argc + 1) * sizeof (char *)); ++ argv[0] = title ? title : clinux; ++ for (i = 1; i < argc; i++) ++ argv[i] = args[i-1]; ++ argv[argc] = NULL; ++ ++ early_initrd = grub_env_get("early_initrd"); ++ ++ grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n", ++ title, id); ++ if (early_initrd) ++ { ++ early_initrds = early_initrd_list(early_initrd); ++ if (!early_initrds) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ ++ if (initrds != NULL && initrds[0] != NULL) ++ { ++ initrd_prefix = grub_strrchr (initrds[0], '/'); ++ initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1); ++ } ++ else ++ { ++ initrd_prefix = grub_strrchr (clinux, '/'); ++ initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1); ++ } ++ ++ if (!initrd_prefix) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ } ++ ++ if (early_initrds || initrds) ++ { ++ int initrd_size = sizeof ("initrd"); ++ char *tmp; ++ ++ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) ++ initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ ++ + grub_strlen(initrd_prefix) \ ++ + grub_strlen (early_initrds[i]) + 1; ++ ++ for (i = 0; initrds != NULL && initrds[i] != NULL; i++) ++ initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \ ++ + grub_strlen (initrds[i]) + 1; ++ initrd_size += 1; ++ ++ initrd = grub_malloc (initrd_size); ++ if (!initrd) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ ++ tmp = grub_stpcpy(initrd, "initrd"); ++ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) ++ { ++ grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]); ++ tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++ tmp = grub_stpcpy (tmp, initrd_prefix); ++ tmp = grub_stpcpy (tmp, early_initrds[i]); ++ grub_free(early_initrds[i]); ++ } ++ ++ for (i = 0; initrds != NULL && initrds[i] != NULL; i++) ++ { ++ grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); ++ tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++ tmp = grub_stpcpy (tmp, initrds[i]); ++ } ++ tmp = grub_stpcpy (tmp, "\n"); ++ } ++ ++ if (devicetree) ++ { ++ char *prefix = NULL; ++ int dt_size; ++ ++ if (add_dt_prefix) ++ { ++ prefix = grub_strrchr (clinux, '/'); ++ prefix = grub_strndup(clinux, prefix - clinux + 1); ++ if (!prefix) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ } ++ ++ dt_size = sizeof("devicetree " GRUB_BOOT_DEVICE) + grub_strlen(devicetree) + 1; ++ ++ if (add_dt_prefix) ++ { ++ dt_size += grub_strlen(prefix); ++ } ++ ++ dt = grub_malloc (dt_size); ++ if (!dt) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto finish; ++ } ++ char *tmp = dt; ++ tmp = grub_stpcpy (dt, "devicetree"); ++ tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++ if (add_dt_prefix) ++ tmp = grub_stpcpy (tmp, prefix); ++ tmp = grub_stpcpy (tmp, devicetree); ++ tmp = grub_stpcpy (tmp, "\n"); ++ ++ grub_free(prefix); ++ } ++ ++ grub_dprintf ("blscfg2", "devicetree %s for id:\"%s\"\n", dt, id); ++ ++ const char *sdval = grub_env_get("save_default"); ++ bool savedefault = ((NULL != sdval) && (grub_strcmp(sdval, "true") == 0)); ++ src = grub_xasprintf ("%sload_video\n" ++ "set gfxpayload=keep\n" ++ "insmod gzio\n" ++ "linux %s%s%s%s\n" ++ "%s%s", ++ savedefault ? "savedefault\n" : "", ++ GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "", ++ initrd ? initrd : "", dt ? dt : ""); ++ ++ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry); ++ grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id); ++ ++finish: ++ grub_free (dt); ++ grub_free (initrd); ++ grub_free (initrd_prefix); ++ grub_free (early_initrds); ++ grub_free (devicetree); ++ grub_free (initrds); ++ grub_free (options); ++ grub_free (classes); ++ grub_free (args); ++ grub_free (argv); ++ grub_free (src); ++} ++ ++struct find_entry_info { ++ const char *dirname; ++ const char *devid; ++ grub_device_t dev; ++ grub_fs_t fs; ++}; ++ ++/* ++ * info: the filesystem object the file is on. ++ */ ++static int find_entry (struct find_entry_info *info) ++{ ++ struct read_entry_info read_entry_info; ++ grub_fs_t blsdir_fs = NULL; ++ grub_device_t blsdir_dev = NULL; ++ const char *blsdir = info->dirname; ++ int fallback = 0; ++ int r = 0; ++ ++ if (!blsdir) { ++ blsdir = grub_env_get ("blsdir"); ++ if (!blsdir) ++ blsdir = GRUB_BLS_CONFIG_PATH; ++ } ++ ++ read_entry_info.file = NULL; ++ read_entry_info.dirname = blsdir; ++ ++ grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir); ++ ++ blsdir_dev = info->dev; ++ blsdir_fs = info->fs; ++ read_entry_info.devid = info->devid; ++ ++read_fallback: ++ r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry, ++ &read_entry_info); ++ if (r != 0) { ++ grub_dprintf ("blscfg", "read_entry returned error\n"); ++ grub_err_t e; ++ do ++ { ++ e = grub_error_pop(); ++ } while (e); ++ } ++ ++ if (r && !info->dirname && !fallback) { ++ read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH; ++ grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n", ++ blsdir, read_entry_info.dirname); ++ fallback = 1; ++ goto read_fallback; ++ } ++ ++ return 0; ++} ++ ++static grub_err_t ++bls_load_entries (const char *path) ++{ ++ grub_size_t len; ++ grub_fs_t fs; ++ grub_device_t dev; ++ static grub_err_t r; ++ const char *devid = NULL; ++ char *blsdir = NULL; ++ struct find_entry_info info = { ++ .dev = NULL, ++ .fs = NULL, ++ .dirname = NULL, ++ }; ++ struct read_entry_info rei = { ++ .devid = NULL, ++ .dirname = NULL, ++ }; ++ ++ if (path) { ++ len = grub_strlen (path); ++ if (grub_strcmp (path + len - 5, ".conf") == 0) { ++ rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG); ++ if (!rei.file) ++ return grub_errno; ++ /* ++ * read_entry() closes the file ++ */ ++ return read_entry(path, NULL, &rei); ++ } else if (path[0] == '(') { ++ devid = path + 1; ++ ++ blsdir = grub_strchr (path, ')'); ++ if (!blsdir) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct")); ++ ++ *blsdir = '\0'; ++ blsdir = blsdir + 1; ++ } ++ } ++ ++ if (!devid) { ++#ifdef GRUB_MACHINE_EMU ++ devid = "host"; ++#else ++ devid = grub_env_get ("root"); ++#endif ++ if (!devid) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("variable `%s' isn't set"), "root"); ++ } ++ ++ grub_dprintf ("blscfg", "opening %s\n", devid); ++ dev = grub_device_open (devid); ++ if (!dev) ++ return grub_errno; ++ ++ grub_dprintf ("blscfg", "probing fs\n"); ++ fs = grub_fs_probe (dev); ++ if (!fs) ++ { ++ r = grub_errno; ++ goto finish; ++ } ++ ++ info.dirname = blsdir; ++ info.devid = devid; ++ info.dev = dev; ++ info.fs = fs; ++ find_entry(&info); ++ ++finish: ++ if (dev) ++ grub_device_close (dev); ++ ++ return r; ++} ++ ++static bool ++is_default_entry(const char *def_entry, struct bls_entry *entry, int idx) ++{ ++ const char *title; ++ int def_idx; ++ ++ if (!def_entry) ++ return false; ++ ++ if (grub_strcmp(def_entry, entry->filename) == 0) ++ return true; ++ ++ title = bls_get_val(entry, "title", NULL); ++ ++ if (title && grub_strcmp(def_entry, title) == 0) ++ return true; ++ ++ def_idx = (int)grub_strtol(def_entry, NULL, 0); ++ if (grub_errno == GRUB_ERR_BAD_NUMBER) { ++ grub_errno = GRUB_ERR_NONE; ++ return false; ++ } ++ ++ if (def_idx == idx) ++ return true; ++ ++ return false; ++} ++ ++static grub_err_t ++bls_create_entries (bool show_default, bool show_non_default, char *entry_id) ++{ ++ const char *def_entry = NULL; ++ struct bls_entry *entry = NULL; ++ int idx = 0; ++ ++ def_entry = grub_env_get("default"); ++ ++ grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__); ++ FOR_BLS_ENTRIES(entry) { ++ if (entry->visible) { ++ idx++; ++ continue; ++ } ++ ++ if ((show_default && is_default_entry(def_entry, entry, idx)) || ++ (show_non_default && !is_default_entry(def_entry, entry, idx)) || ++ (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) { ++ create_entry(entry); ++ entry->visible = 1; ++ } ++ idx++; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED, ++ int argc, char **args) ++{ ++ grub_err_t r; ++ char *path = NULL; ++ char *entry_id = NULL; ++ bool show_default = true; ++ bool show_non_default = true; ++ ++ if (argc == 1) { ++ if (grub_strcmp (args[0], "default") == 0) { ++ show_non_default = false; ++ } else if (grub_strcmp (args[0], "non-default") == 0) { ++ show_default = false; ++ } else if (args[0][0] == '(') { ++ path = args[0]; ++ } else { ++ entry_id = args[0]; ++ show_default = false; ++ show_non_default = false; ++ } ++ } ++ ++ r = bls_load_entries(path); ++ if (r) ++ return r; ++ ++ return bls_create_entries(show_default, show_non_default, entry_id); ++} ++ ++static grub_extcmd_t cmd; ++static grub_extcmd_t oldcmd; ++ ++GRUB_MOD_INIT(blscfg) ++{ ++ grub_dprintf("blscfg", "%s got here\n", __func__); ++ cmd = grub_register_extcmd ("blscfg", ++ grub_cmd_blscfg, ++ 0, ++ NULL, ++ N_("Import Boot Loader Specification snippets."), ++ NULL); ++ oldcmd = grub_register_extcmd ("bls_import", ++ grub_cmd_blscfg, ++ 0, ++ NULL, ++ N_("Import Boot Loader Specification snippets."), ++ NULL); ++} ++ ++GRUB_MOD_FINI(blscfg) ++{ ++ grub_unregister_extcmd (cmd); ++ grub_unregister_extcmd (oldcmd); ++} +diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c +index cc5971f4db..782761c31a 100644 +--- a/grub-core/commands/legacycfg.c ++++ b/grub-core/commands/legacycfg.c +@@ -143,7 +143,7 @@ legacy_file (const char *filename) + args[0] = oldname; + grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy", + NULL, NULL, +- entrysrc, 0); ++ entrysrc, 0, NULL, NULL); + grub_free (args); + entrysrc[0] = 0; + grub_free (oldname); +@@ -205,7 +205,8 @@ legacy_file (const char *filename) + } + args[0] = entryname; + grub_normal_add_menu_entry (1, args, NULL, NULL, NULL, +- NULL, NULL, entrysrc, 0); ++ NULL, NULL, entrysrc, 0, NULL, ++ NULL); + grub_free (args); + } + +diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c +index 3fd664aac3..163b9a0904 100644 +--- a/grub-core/commands/loadenv.c ++++ b/grub-core/commands/loadenv.c +@@ -28,6 +28,8 @@ + #include + #include + ++#include "loadenv.h" ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + static const struct grub_arg_option options[] = +@@ -79,81 +81,6 @@ open_envblk_file (char *filename, + return file; + } + +-static grub_envblk_t +-read_envblk_file (grub_file_t file) +-{ +- grub_off_t offset = 0; +- char *buf; +- grub_size_t size = grub_file_size (file); +- grub_envblk_t envblk; +- +- buf = grub_malloc (size); +- if (! buf) +- return 0; +- +- while (size > 0) +- { +- grub_ssize_t ret; +- +- ret = grub_file_read (file, buf + offset, size); +- if (ret <= 0) +- { +- grub_free (buf); +- return 0; +- } +- +- size -= ret; +- offset += ret; +- } +- +- envblk = grub_envblk_open (buf, offset); +- if (! envblk) +- { +- grub_free (buf); +- grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); +- return 0; +- } +- +- return envblk; +-} +- +-struct grub_env_whitelist +-{ +- grub_size_t len; +- char **list; +-}; +-typedef struct grub_env_whitelist grub_env_whitelist_t; +- +-static int +-test_whitelist_membership (const char* name, +- const grub_env_whitelist_t* whitelist) +-{ +- grub_size_t i; +- +- for (i = 0; i < whitelist->len; i++) +- if (grub_strcmp (name, whitelist->list[i]) == 0) +- return 1; /* found it */ +- +- return 0; /* not found */ +-} +- +-/* Helper for grub_cmd_load_env. */ +-static int +-set_var (const char *name, const char *value, void *whitelist) +-{ +- if (! whitelist) +- { +- grub_env_set (name, value); +- return 0; +- } +- +- if (test_whitelist_membership (name, +- (const grub_env_whitelist_t *) whitelist)) +- grub_env_set (name, value); +- +- return 0; +-} +- + static grub_err_t + grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args) + { +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index 720e6d8ea3..b194123eb6 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args, + char **classes, const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, +- int submenu) ++ int submenu, int *index, struct bls_entry *bls) + { + int menu_hotkey = 0; + char **menu_args = NULL; +@@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char **args, + if (! menu_title) + goto fail; + ++ grub_dprintf ("menu", "id:\"%s\"\n", id); ++ grub_dprintf ("menu", "title:\"%s\"\n", menu_title); + menu_id = grub_strdup (id ? : menu_title); + if (! menu_id) + goto fail; ++ grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id); + + /* Save argc, args to pass as parameters to block arg later. */ + menu_args = grub_calloc (argc + 1, sizeof (char *)); +@@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char **args, + } + + /* Add the menu entry at the end of the list. */ ++ int ind=0; + while (*last) +- last = &(*last)->next; ++ { ++ ind++; ++ last = &(*last)->next; ++ } + + *last = grub_zalloc (sizeof (**last)); + if (! *last) +@@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char **args, + (*last)->args = menu_args; + (*last)->sourcecode = menu_sourcecode; + (*last)->submenu = submenu; ++ (*last)->bls = bls; + + menu->size++; ++ if (index) ++ *index = ind; + return GRUB_ERR_NONE; + + fail: +@@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + users, + ctxt->state[2].arg, 0, + ctxt->state[3].arg, +- ctxt->extcmd->cmd->name[0] == 's'); ++ ctxt->extcmd->cmd->name[0] == 's', ++ NULL, NULL); + + src = args[argc - 1]; + args[argc - 1] = NULL; +@@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + ctxt->state[0].args, ctxt->state[4].arg, + users, + ctxt->state[2].arg, prefix, src + 1, +- ctxt->extcmd->cmd->name[0] == 's'); ++ ctxt->extcmd->cmd->name[0] == 's', NULL, ++ NULL); + + src[len - 1] = ch; + args[argc - 1] = src; +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 62571e6dfc..7ca2e5400b 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -70,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu) + grub_free (entry->args); + } + ++ if (entry->bls) ++ { ++ entry->bls->visible = 0; ++ } ++ + grub_free ((void *) entry->id); + grub_free ((void *) entry->users); + grub_free ((void *) entry->title); +diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h +new file mode 100644 +index 0000000000..952f46121b +--- /dev/null ++++ b/grub-core/commands/loadenv.h +@@ -0,0 +1,93 @@ ++/* loadenv.c - command to load/save environment variable. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++static grub_envblk_t UNUSED ++read_envblk_file (grub_file_t file) ++{ ++ grub_off_t offset = 0; ++ char *buf; ++ grub_size_t size = grub_file_size (file); ++ grub_envblk_t envblk; ++ ++ buf = grub_malloc (size); ++ if (! buf) ++ return 0; ++ ++ while (size > 0) ++ { ++ grub_ssize_t ret; ++ ++ ret = grub_file_read (file, buf + offset, size); ++ if (ret <= 0) ++ { ++ grub_free (buf); ++ return 0; ++ } ++ ++ size -= ret; ++ offset += ret; ++ } ++ ++ envblk = grub_envblk_open (buf, offset); ++ if (! envblk) ++ { ++ grub_free (buf); ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block"); ++ return 0; ++ } ++ ++ return envblk; ++} ++ ++struct grub_env_whitelist ++{ ++ grub_size_t len; ++ char **list; ++}; ++typedef struct grub_env_whitelist grub_env_whitelist_t; ++ ++static int UNUSED ++test_whitelist_membership (const char* name, ++ const grub_env_whitelist_t* whitelist) ++{ ++ grub_size_t i; ++ ++ for (i = 0; i < whitelist->len; i++) ++ if (grub_strcmp (name, whitelist->list[i]) == 0) ++ return 1; /* found it */ ++ ++ return 0; /* not found */ ++} ++ ++/* Helper for grub_cmd_load_env. */ ++static int UNUSED ++set_var (const char *name, const char *value, void *whitelist) ++{ ++ if (! whitelist) ++ { ++ grub_env_set (name, value); ++ return 0; ++ } ++ ++ if (test_whitelist_membership (name, ++ (const grub_env_whitelist_t *) whitelist)) ++ grub_env_set (name, value); ++ ++ return 0; ++} +diff --git a/include/grub/compiler.h b/include/grub/compiler.h +index 8f3be3ae70..ebafec6895 100644 +--- a/include/grub/compiler.h ++++ b/include/grub/compiler.h +@@ -56,4 +56,6 @@ + # define CLANG_PREREQ(maj,min) 0 + #endif + ++#define UNUSED __attribute__((__unused__)) ++ + #endif /* ! GRUB_COMPILER_HEADER */ +diff --git a/include/grub/menu.h b/include/grub/menu.h +index ee2b5e9104..0acdc2aa6b 100644 +--- a/include/grub/menu.h ++++ b/include/grub/menu.h +@@ -20,6 +20,16 @@ + #ifndef GRUB_MENU_HEADER + #define GRUB_MENU_HEADER 1 + ++struct bls_entry ++{ ++ struct bls_entry *next; ++ struct bls_entry *prev; ++ struct keyval **keyvals; ++ int nkeyvals; ++ char *filename; ++ int visible; ++}; ++ + struct grub_menu_entry_class + { + char *name; +@@ -60,6 +70,9 @@ struct grub_menu_entry + + /* The next element. */ + struct grub_menu_entry *next; ++ ++ /* BLS used to populate the entry */ ++ struct bls_entry *bls; + }; + typedef struct grub_menu_entry *grub_menu_entry_t; + +diff --git a/include/grub/normal.h b/include/grub/normal.h +index 218cbabcca..8839ad85a1 100644 +--- a/include/grub/normal.h ++++ b/include/grub/normal.h +@@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes, + const char *id, + const char *users, const char *hotkey, + const char *prefix, const char *sourcecode, +- int submenu); ++ int submenu, int *index, struct bls_entry *bls); + + grub_err_t + grub_normal_set_password (const char *user, const char *password); diff --git a/SOURCES/0022-Add-devicetree-loading.patch b/SOURCES/0022-Add-devicetree-loading.patch new file mode 100644 index 0000000..466ddba --- /dev/null +++ b/SOURCES/0022-Add-devicetree-loading.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 14 Jan 2014 13:12:23 -0500 +Subject: [PATCH] Add devicetree loading + +Signed-off-by: Peter Jones + +Switch to use APM Mustang device tree, for hardware testing. + +Signed-off-by: David A. Marlin + +Use the default device tree from the grub default file + +instead of hardcoding a value. + +Signed-off-by: David A. Marlin +--- + util/grub-mkconfig.in | 3 ++- + util/grub.d/10_linux.in | 15 +++++++++++++++ + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index d3e879b8e5..8ea2315ebc 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -248,7 +248,8 @@ export GRUB_DEFAULT \ + GRUB_ENABLE_CRYPTODISK \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ +- GRUB_DISABLE_SUBMENU ++ GRUB_DISABLE_SUBMENU \ ++ GRUB_DEFAULT_DTB + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index e8b01c0d0c..dc75a1c30b 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -153,6 +153,13 @@ EOF + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' + initrd $(echo $initrd_path) ++EOF ++ fi ++ if test -n "${fdt}" ; then ++ message="$(gettext_printf "Loading fdt ...")" ++ sed "s/^/$submenu_indentation/" << EOF ++ echo '$(echo "$message" | grub_quote)' ++ devicetree ${rel_dirname}/${fdt} + EOF + fi + sed "s/^/$submenu_indentation/" << EOF +@@ -236,6 +243,14 @@ while [ "x$list" != "x" ] ; do + gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 + fi + ++ fdt= ++ for i in "dtb-${version}" "dtb-${alt_version}"; do ++ if test -f "${dirname}/${i}/${GRUB_DEFAULT_DTB}" ; then ++ fdt="${i}/${GRUB_DEFAULT_DTB}" ++ break ++ fi ++ done ++ + config= + for i in "${dirname}/config-${version}" "${dirname}/config-${alt_version}" "/etc/kernels/kernel-config-${version}" ; do + if test -e "${i}" ; then diff --git a/SOURCES/0023-Enable-pager-by-default.-985860.patch b/SOURCES/0023-Enable-pager-by-default.-985860.patch new file mode 100644 index 0000000..63cf787 --- /dev/null +++ b/SOURCES/0023-Enable-pager-by-default.-985860.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 28 Oct 2013 10:09:27 -0400 +Subject: [PATCH] Enable pager by default. (#985860) + +Signed-off-by: Peter Jones +--- + util/grub.d/00_header.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 93a90233ea..858b526c92 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -43,6 +43,8 @@ if [ "x${GRUB_DEFAULT_BUTTON}" = "xsaved" ] ; then GRUB_DEFAULT_BUTTON='${saved_ + if [ "x${GRUB_TIMEOUT_BUTTON}" = "x" ] ; then GRUB_TIMEOUT_BUTTON="$GRUB_TIMEOUT" ; fi + + cat << EOF ++set pager=1 ++ + if [ -s \$prefix/grubenv ]; then + load_env + fi diff --git a/SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch b/SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch new file mode 100644 index 0000000..5b96784 --- /dev/null +++ b/SOURCES/0024-Don-t-say-GNU-Linux-in-generated-menus.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 14 Mar 2011 14:27:42 -0400 +Subject: [PATCH] Don't say "GNU/Linux" in generated menus. + +[rharwood: say it even less] +--- + grub-core/normal/main.c | 2 +- + tests/util/grub-shell-tester.in | 2 +- + tests/util/grub-shell.in | 2 +- + util/grub.d/10_linux.in | 4 ++-- + util/grub.d/20_linux_xen.in | 4 ++-- + 5 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 7ca2e5400b..98372217ad 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -218,7 +218,7 @@ grub_normal_init_page (struct grub_term_output *term, + + grub_term_cls (term); + +- msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION); ++ msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION); + if (!msg_formatted) + return; + +diff --git a/tests/util/grub-shell-tester.in b/tests/util/grub-shell-tester.in +index 8a87109b15..9a4319d4f4 100644 +--- a/tests/util/grub-shell-tester.in ++++ b/tests/util/grub-shell-tester.in +@@ -56,7 +56,7 @@ for option in "$@"; do + usage + exit 0 ;; + -v | --version) +- echo "$0 (GNU GRUB ${PACKAGE_VERSION})" ++ echo "$0 (GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --modules=*) + ms=`echo "$option" | sed -e 's/--modules=//'` +diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in +index 93e9f51484..ec1182bf93 100644 +--- a/tests/util/grub-shell.in ++++ b/tests/util/grub-shell.in +@@ -209,7 +209,7 @@ for option in "$@"; do + usage + exit 0 ;; + -v | --version) +- echo "$0 (GNU GRUB ${PACKAGE_VERSION})" ++ echo "$0 (GRUB ${PACKAGE_VERSION})" + exit 0 ;; + --trim) + trim=1 +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index dc75a1c30b..4a499c53a6 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@" + CLASS="--class gnu-linux --class gnu --class os" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then +- OS=GNU/Linux ++ OS="$(sed 's, release .*$,,g' /etc/system-release)" + else +- OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ OS="${GRUB_DISTRIBUTOR}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" + fi + +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index 3b1f470492..ada20775a1 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -29,9 +29,9 @@ export TEXTDOMAINDIR="@localedir@" + CLASS="--class gnu-linux --class gnu --class os --class xen" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then +- OS=GNU/Linux ++ OS="$(sed 's, release .*$,,g' /etc/system-release)" + else +- OS="${GRUB_DISTRIBUTOR} GNU/Linux" ++ OS="${GRUB_DISTRIBUTOR}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" + fi + diff --git a/SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch b/SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch new file mode 100644 index 0000000..0532a04 --- /dev/null +++ b/SOURCES/0025-Add-.eh_frame-to-list-of-relocations-stripped.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Mon, 13 Jan 2014 21:50:59 -0500 +Subject: [PATCH] Add .eh_frame to list of relocations stripped + +--- + conf/Makefile.common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 2a1a886f6d..191b1a70c6 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) + CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 + CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) +-STRIPFLAGS_KERNEL = -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx ++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx + + CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d diff --git a/SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch b/SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch new file mode 100644 index 0000000..89887c1 --- /dev/null +++ b/SOURCES/0026-Don-t-require-a-password-to-boot-entries-generated-b.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Feb 2014 11:14:50 -0500 +Subject: [PATCH] Don't require a password to boot entries generated by + grub-mkconfig. + +When we set a password, we just want that to mean you can't /edit/ an entry. + +Resolves: rhbz#1030176 + +Signed-off-by: Peter Jones +--- + util/grub.d/10_linux.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 4a499c53a6..cf8d118698 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -26,7 +26,7 @@ datarootdir="@datarootdir@" + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + +-CLASS="--class gnu-linux --class gnu --class os" ++CLASS="--class gnu-linux --class gnu --class os --unrestricted" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS="$(sed 's, release .*$,,g' /etc/system-release)" diff --git a/SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch b/SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch new file mode 100644 index 0000000..1da91e1 --- /dev/null +++ b/SOURCES/0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Wed, 19 Feb 2014 15:58:43 -0500 +Subject: [PATCH] use fw_path prefix when fallback searching for grub config + +When PXE booting via UEFI firmware, grub was searching for grub.cfg +in the fw_path directory where the grub application was found. If +that didn't exist, a fallback search would look for config file names +based on MAC and IP address. However, the search would look in the +prefix directory which may not be the same fw_path. This patch +changes that behavior to use the fw_path directory for the fallback +search. Only if fw_path is NULL will the prefix directory be searched. + +Signed-off-by: Mark Salter +--- + grub-core/normal/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 98372217ad..bf24e65713 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -347,7 +347,7 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + char *config; + const char *prefix, *fw_path; + +- fw_path = grub_env_get ("fw_path"); ++ prefix = fw_path = grub_env_get ("fw_path"); + if (fw_path) + { + config = grub_xasprintf ("%s/grub.cfg", fw_path); +@@ -370,7 +370,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + } + } + +- prefix = grub_env_get ("prefix"); ++ if (! prefix) ++ prefix = grub_env_get ("prefix"); + if (prefix) + { + grub_size_t config_len; diff --git a/SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch b/SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch new file mode 100644 index 0000000..0d77281 --- /dev/null +++ b/SOURCES/0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 8 Jul 2019 17:33:22 +0200 +Subject: [PATCH] Try mac/guid/etc before grub.cfg on tftp config files. + +Signed-off-by: Peter Jones +--- + grub-core/normal/main.c | 97 ++++++++++++++++++++++++++----------------------- + 1 file changed, 51 insertions(+), 46 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index bf24e65713..0a99768f75 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -345,61 +345,66 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + /* Guess the config filename. It is necessary to make CONFIG static, + so that it won't get broken by longjmp. */ + char *config; +- const char *prefix, *fw_path; +- +- prefix = fw_path = grub_env_get ("fw_path"); +- if (fw_path) +- { +- config = grub_xasprintf ("%s/grub.cfg", fw_path); +- if (config) +- { +- grub_file_t file; +- +- file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); +- if (file) +- { +- grub_file_close (file); +- grub_enter_normal_mode (config); +- } +- else +- { +- /* Ignore all errors. */ +- grub_errno = 0; +- } +- grub_free (config); +- } +- } ++ const char *prefix; ++ const char *net_search_cfg; ++ int disable_net_search = 0; + ++ prefix = grub_env_get ("fw_path"); + if (! prefix) + prefix = grub_env_get ("prefix"); ++ ++ net_search_cfg = grub_env_get ("feature_net_search_cfg"); ++ if (net_search_cfg && net_search_cfg[0] == 'n') ++ disable_net_search = 1; ++ + if (prefix) + { +- grub_size_t config_len; +- int disable_net_search = 0; +- const char *net_search_cfg; +- +- config_len = grub_strlen (prefix) + +- sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); +- config = grub_malloc (config_len); +- +- if (!config) +- goto quit; +- +- grub_snprintf (config, config_len, "%s/grub.cfg", prefix); +- +- net_search_cfg = grub_env_get ("feature_net_search_cfg"); +- if (net_search_cfg && net_search_cfg[0] == 'n') +- disable_net_search = 1; +- + if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 && + !disable_net_search) +- grub_net_search_config_file (config); ++ { ++ grub_size_t config_len; ++ config_len = grub_strlen (prefix) + ++ sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); ++ config = grub_malloc (config_len); + +- grub_enter_normal_mode (config); +- grub_free (config); +- } ++ if (! config) ++ goto quit; ++ ++ grub_snprintf (config, config_len, "%s/grub.cfg", prefix); ++ ++ grub_net_search_configfile (config); ++ ++ grub_enter_normal_mode (config); ++ grub_free (config); ++ config = NULL; ++ } ++ ++ if (!config) ++ { ++ config = grub_xasprintf ("%s/grub.cfg", prefix); ++ if (config) ++ { ++ grub_file_t file; ++ ++ file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); ++ if (file) ++ { ++ grub_file_close (file); ++ grub_enter_normal_mode (config); ++ } ++ else ++ { ++ /* Ignore all errors. */ ++ grub_errno = 0; ++ } ++ grub_free (config); ++ } ++ } ++ } + else +- grub_enter_normal_mode (0); ++ { ++ grub_enter_normal_mode (0); ++ } + } + else + grub_enter_normal_mode (argv[0]); diff --git a/SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch b/SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch new file mode 100644 index 0000000..f22e6f9 --- /dev/null +++ b/SOURCES/0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 4 Sep 2014 14:23:23 -0400 +Subject: [PATCH] Generate OS and CLASS in 10_linux from /etc/os-release + +This makes us use pretty names in the titles we generate in +grub2-mkconfig when GRUB_DISTRIBUTOR isn't set. + +Resolves: rhbz#996794 + +Signed-off-by: Peter Jones +--- + util/grub.d/10_linux.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index cf8d118698..5f6d3c8d52 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -29,7 +29,8 @@ export TEXTDOMAINDIR="@localedir@" + CLASS="--class gnu-linux --class gnu --class os --unrestricted" + + if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then +- OS="$(sed 's, release .*$,,g' /etc/system-release)" ++ OS="$(eval $(grep PRETTY_NAME /etc/os-release) ; echo ${PRETTY_NAME})" ++ CLASS="--class $(eval $(grep '^ID_LIKE=\|^ID=' /etc/os-release) ; [ -n "${ID_LIKE}" ] && echo ${ID_LIKE} || echo ${ID}) ${CLASS}" + else + OS="${GRUB_DISTRIBUTOR}" + CLASS="--class $(echo ${GRUB_DISTRIBUTOR} | tr 'A-Z' 'a-z' | cut -d' ' -f1|LC_ALL=C sed 's,[^[:alnum:]_],_,g') ${CLASS}" diff --git a/SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch b/SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch new file mode 100644 index 0000000..f4d83da --- /dev/null +++ b/SOURCES/0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 4 Sep 2014 15:52:08 -0400 +Subject: [PATCH] Minimize the sort ordering for .debug and -rescue- kernels. + +Resolves: rhbz#1065360 +Signed-off-by: Peter Jones +--- + util/grub-mkconfig_lib.in | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 301d1ac229..0f6505bf3b 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -253,6 +253,14 @@ version_test_gt () + *.old:*.old) ;; + *.old:*) version_test_gt_a="`echo "$version_test_gt_a" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=gt ;; + *:*.old) version_test_gt_b="`echo "$version_test_gt_b" | sed -e 's/\.old$//'`" ; version_test_gt_cmp=ge ;; ++ *-rescue*:*-rescue*) ;; ++ *?debug:*?debug) ;; ++ *-rescue*:*?debug) return 1 ;; ++ *?debug:*-rescue*) return 0 ;; ++ *-rescue*:*) return 1 ;; ++ *:*-rescue*) return 0 ;; ++ *?debug:*) return 1 ;; ++ *:*?debug) return 0 ;; + esac + version_test_numeric "$version_test_gt_a" "$version_test_gt_cmp" "$version_test_gt_b" + return "$?" diff --git a/SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch b/SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch new file mode 100644 index 0000000..a1c0d9e --- /dev/null +++ b/SOURCES/0031-Try-prefix-if-fw_path-doesn-t-work.patch @@ -0,0 +1,222 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 10:35:16 +0200 +Subject: [PATCH] Try $prefix if $fw_path doesn't work. + +Related: rhbz#1148652 + +Signed-off-by: Peter Jones +--- + grub-core/kern/ieee1275/init.c | 28 +++++---- + grub-core/net/net.c | 2 +- + grub-core/normal/main.c | 134 ++++++++++++++++++++--------------------- + 3 files changed, 82 insertions(+), 82 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index e71d158416..0cd2a62723 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -127,23 +127,25 @@ grub_machine_get_bootlocation (char **device, char **path) + grub_free (canon); + } + else +- *device = grub_ieee1275_encode_devname (bootpath); +- grub_free (type); +- +- filename = grub_ieee1275_get_filename (bootpath); +- if (filename) + { +- char *lastslash = grub_strrchr (filename, '\\'); +- +- /* Truncate at last directory. */ +- if (lastslash) ++ filename = grub_ieee1275_get_filename (bootpath); ++ if (filename) + { +- *lastslash = '\0'; +- grub_translate_ieee1275_path (filename); ++ char *lastslash = grub_strrchr (filename, '\\'); + +- *path = filename; +- } ++ /* Truncate at last directory. */ ++ if (lastslash) ++ { ++ *lastslash = '\0'; ++ grub_translate_ieee1275_path (filename); ++ ++ *path = filename; ++ } ++ } ++ *device = grub_ieee1275_encode_devname (bootpath); + } ++ ++ grub_free (type); + grub_free (bootpath); + } + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 4d3eb5c1a5..0ef148f4ad 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1869,7 +1869,7 @@ grub_net_search_config_file (char *config) + /* Remove the remaining minus sign at the end. */ + config[config_len] = '\0'; + +- return GRUB_ERR_NONE; ++ return GRUB_ERR_FILE_NOT_FOUND; + } + + static struct grub_preboot *fini_hnd; +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 0a99768f75..55558cc0b9 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -335,81 +335,79 @@ grub_enter_normal_mode (const char *config) + grub_boot_time ("Exiting normal mode"); + } + ++static grub_err_t ++grub_try_normal (const char *variable) ++{ ++ char *config; ++ const char *prefix; ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ const char *net_search_cfg; ++ int disable_net_search = 0; ++ ++ prefix = grub_env_get (variable); ++ if (!prefix) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ net_search_cfg = grub_env_get ("feature_net_search_cfg"); ++ if (net_search_cfg && net_search_cfg[0] == 'n') ++ disable_net_search = 1; ++ ++ if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 && ++ !disable_net_search) ++ { ++ grub_size_t config_len; ++ config_len = grub_strlen (prefix) + ++ sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); ++ config = grub_malloc (config_len); ++ ++ if (! config) ++ return GRUB_ERR_FILE_NOT_FOUND; ++ ++ grub_snprintf (config, config_len, "%s/grub.cfg", prefix); ++ err = grub_net_search_config_file (config); ++ } ++ ++ if (err != GRUB_ERR_NONE) ++ { ++ config = grub_xasprintf ("%s/grub.cfg", prefix); ++ if (config) ++ { ++ grub_file_t file; ++ file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); ++ if (file) ++ { ++ grub_file_close (file); ++ err = GRUB_ERR_NONE; ++ } ++ } ++ } ++ ++ if (err == GRUB_ERR_NONE) ++ grub_enter_normal_mode (config); ++ ++ grub_errno = 0; ++ grub_free (config); ++ return err; ++} ++ + /* Enter normal mode from rescue mode. */ + static grub_err_t + grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + int argc, char *argv[]) + { +- if (argc == 0) +- { +- /* Guess the config filename. It is necessary to make CONFIG static, +- so that it won't get broken by longjmp. */ +- char *config; +- const char *prefix; +- const char *net_search_cfg; +- int disable_net_search = 0; +- +- prefix = grub_env_get ("fw_path"); +- if (! prefix) +- prefix = grub_env_get ("prefix"); +- +- net_search_cfg = grub_env_get ("feature_net_search_cfg"); +- if (net_search_cfg && net_search_cfg[0] == 'n') +- disable_net_search = 1; +- +- if (prefix) +- { +- if (grub_strncmp (prefix + 1, "tftp", sizeof ("tftp") - 1) == 0 && +- !disable_net_search) +- { +- grub_size_t config_len; +- config_len = grub_strlen (prefix) + +- sizeof ("/grub.cfg-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"); +- config = grub_malloc (config_len); +- +- if (! config) +- goto quit; +- +- grub_snprintf (config, config_len, "%s/grub.cfg", prefix); +- +- grub_net_search_configfile (config); +- +- grub_enter_normal_mode (config); +- grub_free (config); +- config = NULL; +- } +- +- if (!config) +- { +- config = grub_xasprintf ("%s/grub.cfg", prefix); +- if (config) +- { +- grub_file_t file; +- +- file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); +- if (file) +- { +- grub_file_close (file); +- grub_enter_normal_mode (config); +- } +- else +- { +- /* Ignore all errors. */ +- grub_errno = 0; +- } +- grub_free (config); +- } +- } +- } +- else +- { +- grub_enter_normal_mode (0); +- } +- } +- else ++ if (argc) + grub_enter_normal_mode (argv[0]); ++ else ++ { ++ /* Guess the config filename. */ ++ grub_err_t err; ++ err = grub_try_normal ("fw_path"); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal ("prefix"); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ grub_enter_normal_mode (0); ++ } + +-quit: + return 0; + } + diff --git a/SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch b/SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch new file mode 100644 index 0000000..db101c0 --- /dev/null +++ b/SOURCES/0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 28 Apr 2015 11:15:03 -0400 +Subject: [PATCH] Make grub2-mkconfig construct titles that look like the ones + we want elsewhere. + +Resolves: rhbz#1215839 + +Signed-off-by: Peter Jones +--- + util/grub.d/10_linux.in | 34 +++++++++++++++++++++++++++------- + 1 file changed, 27 insertions(+), 7 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 5f6d3c8d52..786dbabb4a 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -78,6 +78,32 @@ case x"$GRUB_FS" in + ;; + esac + ++mktitle () ++{ ++ local title_type ++ local version ++ local OS_NAME ++ local OS_VERS ++ ++ title_type=$1 && shift ++ version=$1 && shift ++ ++ OS_NAME="$(eval $(grep ^NAME= /etc/os-release) ; echo ${NAME})" ++ OS_VERS="$(eval $(grep ^VERSION= /etc/os-release) ; echo ${VERSION})" ++ ++ case $title_type in ++ recovery) ++ title=$(printf '%s (%s) %s (recovery mode)' \ ++ "${OS_NAME}" "${version}" "${OS_VERS}") ++ ;; ++ *) ++ title=$(printf '%s (%s) %s' \ ++ "${OS_NAME}" "${version}" "${OS_VERS}") ++ ;; ++ esac ++ echo -n ${title} ++} ++ + title_correction_code= + + linux_entry () +@@ -91,17 +117,11 @@ linux_entry () + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi + if [ x$type != xsimple ] ; then +- case $type in +- recovery) +- title="$(gettext_printf "%s, with Linux %s (recovery mode)" "${os}" "${version}")" ;; +- *) +- title="$(gettext_printf "%s, with Linux %s" "${os}" "${version}")" ;; +- esac ++ title=$(mktitle "$type" "$version") + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then + replacement_title="$(echo "Advanced options for ${OS}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" +- grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" + fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else diff --git a/SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch b/SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch new file mode 100644 index 0000000..f430e96 --- /dev/null +++ b/SOURCES/0033-Add-friendly-grub2-password-config-tool-985962.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robert Marshall +Date: Thu, 25 Jun 2015 11:13:11 -0400 +Subject: [PATCH] Add friendly grub2 password config tool (#985962) + +Provided a tool for users to reset the grub2 root user password +without having to alter the grub.cfg. The hashed password now +lives in a root-only-readable configuration file. + +Resolves: rhbz#985962 + +Signed-off-by: Robert Marshall +[pjones: fix the efidir in grub-setpassword and rename tool] +Signed-off-by: Peter Jones +[luto: fix grub-setpassword -o's output path] +Signed-off-by: Andy Lutomirski +[rharwood: migrate man page to h2m, context] +Signed-off-by: Robbie Harwood +--- + configure.ac | 1 + + Makefile.util.def | 13 +++++ + docs/man/grub-set-password.h2m | 2 + + util/grub-mkconfig.in | 2 + + util/grub-set-password.in | 128 +++++++++++++++++++++++++++++++++++++++++ + util/grub.d/01_users.in | 11 ++++ + 6 files changed, 157 insertions(+) + create mode 100644 docs/man/grub-set-password.h2m + create mode 100644 util/grub-set-password.in + create mode 100644 util/grub.d/01_users.in + +diff --git a/configure.ac b/configure.ac +index 8331f95b64..7f59ad788f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -72,6 +72,7 @@ grub_TRANSFORM([grub-mkrelpath]) + grub_TRANSFORM([grub-mkrescue]) + grub_TRANSFORM([grub-probe]) + grub_TRANSFORM([grub-reboot]) ++grub_TRANSFORM([grub-set-password]) + grub_TRANSFORM([grub-script-check]) + grub_TRANSFORM([grub-set-default]) + grub_TRANSFORM([grub-sparc64-setup]) +diff --git a/Makefile.util.def b/Makefile.util.def +index 2c9b283a23..4ee22c5daa 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -452,6 +452,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '01_users'; ++ common = util/grub.d/01_users.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '10_windows'; + common = util/grub.d/10_windows.in; +@@ -724,6 +730,13 @@ script = { + installdir = sbin; + }; + ++script = { ++ name = grub-set-password; ++ common = util/grub-set-password.in; ++ mansection = 8; ++ installdir = sbin; ++}; ++ + script = { + name = grub-mkconfig_lib; + common = util/grub-mkconfig_lib.in; +diff --git a/docs/man/grub-set-password.h2m b/docs/man/grub-set-password.h2m +new file mode 100644 +index 0000000000..10ee82f4d5 +--- /dev/null ++++ b/docs/man/grub-set-password.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-set-password \- generate the user.cfg file containing the hashed grub bootloader password +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 8ea2315ebc..ba14cf6261 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -276,6 +276,8 @@ for i in "${grub_mkconfig_dir}"/* ; do + *~) ;; + # emacsen autosave files. FIXME: support other editors + */\#*\#) ;; ++ # rpm config files of yore. ++ *.rpmsave|*.rpmnew|*.rpmorig) ;; + *) + if grub_file_is_not_garbage "$i" && test -x "$i" ; then + echo +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +new file mode 100644 +index 0000000000..5ebf50576d +--- /dev/null ++++ b/util/grub-set-password.in +@@ -0,0 +1,128 @@ ++#!/bin/sh -e ++ ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/') ++if [ -d /sys/firmware/efi/efivars/ ]; then ++ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` ++else ++ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` ++fi ++ ++PACKAGE_VERSION="@PACKAGE_VERSION@" ++PACKAGE_NAME="@PACKAGE_NAME@" ++self=`basename $0` ++bindir="@bindir@" ++grub_mkpasswd="${bindir}/@grub_mkpasswd_pbkdf2@" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ cat < put user.cfg in a user-selected directory ++ ++Report bugs at https://bugzilla.redhat.com. ++EOF ++} ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++# Ensure that it's the root user running this script ++if [ "${EUID}" -ne 0 ]; then ++ echo "The grub bootloader password may only be set by root." ++ usage ++ exit 2 ++fi ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -v | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ -o | --output) ++ OUTPUT_PATH=`argument $option "$@"`; shift ;; ++ --output=*) ++ OUTPUT_PATH=`echo "$option" | sed 's/--output=//'` ;; ++ -o=*) ++ OUTPUT_PATH=`echo "$option" | sed 's/-o=//'` ;; ++ esac ++done ++ ++# set user input or default path for user.cfg file ++if [ -z "${OUTPUT_PATH}" ]; then ++ OUTPUT_PATH="${grubdir}" ++fi ++ ++if [ ! -d "${OUTPUT_PATH}" ]; then ++ echo "${OUTPUT_PATH} does not exist." ++ usage ++ exit 2; ++fi ++ ++ttyopt=$(stty -g) ++fixtty() { ++ stty ${ttyopt} ++} ++ ++trap fixtty EXIT ++stty -echo ++ ++# prompt & confirm new grub2 root user password ++echo -n "Enter password: " ++read PASSWORD ++echo ++echo -n "Confirm password: " ++read PASSWORD_CONFIRM ++echo ++stty ${ttyopt} ++ ++getpass() { ++ local P0 ++ local P1 ++ P0="$1" && shift ++ P1="$1" && shift ++ ++ ( echo ${P0} ; echo ${P1} ) | \ ++ LC_ALL=C ${grub_mkpasswd} | \ ++ grep -v '[eE]nter password:' | \ ++ sed -e "s/PBKDF2 hash of your password is //" ++} ++ ++MYPASS="$(getpass "${PASSWORD}" "${PASSWORD_CONFIRM}")" ++if [ -z "${MYPASS}" ]; then ++ echo "${self}: error: empty password" 1>&2 ++ exit 1 ++fi ++ ++# on the ESP, these will fail to set the permissions, but it's okay because ++# the directory is protected. ++install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : ++chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : ++echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" ++ ++if ! grep -q "^### BEGIN /etc/grub.d/01_users ###$" "${OUTPUT_PATH}/grub.cfg"; then ++ echo "WARNING: The current configuration lacks password support!" ++ echo "Update your configuration with @grub_mkconfig@ to support this feature." ++fi +diff --git a/util/grub.d/01_users.in b/util/grub.d/01_users.in +new file mode 100644 +index 0000000000..db2f44bfb7 +--- /dev/null ++++ b/util/grub.d/01_users.in +@@ -0,0 +1,11 @@ ++#!/bin/sh -e ++cat << EOF ++if [ -f \${prefix}/user.cfg ]; then ++ source \${prefix}/user.cfg ++ if [ -n "\${GRUB2_PASSWORD}" ]; then ++ set superusers="root" ++ export superusers ++ password_pbkdf2 root \${GRUB2_PASSWORD} ++ fi ++fi ++EOF diff --git a/SOURCES/0034-tcp-add-window-scaling-support.patch b/SOURCES/0034-tcp-add-window-scaling-support.patch new file mode 100644 index 0000000..61b5a67 --- /dev/null +++ b/SOURCES/0034-tcp-add-window-scaling-support.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Josef Bacik +Date: Wed, 12 Aug 2015 08:57:55 -0700 +Subject: [PATCH] tcp: add window scaling support + +Sometimes we have to provision boxes across regions, such as California to +Sweden. The http server has a 10 minute timeout, so if we can't get our 250mb +image transferred fast enough our provisioning fails, which is not ideal. So +add tcp window scaling on open connections and set the window size to 1mb. With +this change we're able to get higher sustained transfers between regions and can +transfer our image in well below 10 minutes. Without this patch we'd time out +every time halfway through the transfer. Thanks, + +Signed-off-by: Josef Bacik +--- + grub-core/net/tcp.c | 42 +++++++++++++++++++++++++++++------------- + 1 file changed, 29 insertions(+), 13 deletions(-) + +diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c +index e8ad34b84d..7d4b822626 100644 +--- a/grub-core/net/tcp.c ++++ b/grub-core/net/tcp.c +@@ -106,6 +106,18 @@ struct tcphdr + grub_uint16_t urgent; + } GRUB_PACKED; + ++struct tcp_scale_opt { ++ grub_uint8_t kind; ++ grub_uint8_t length; ++ grub_uint8_t scale; ++} GRUB_PACKED; ++ ++struct tcp_synhdr { ++ struct tcphdr tcphdr; ++ struct tcp_scale_opt scale_opt; ++ grub_uint8_t padding; ++}; ++ + struct tcp_pseudohdr + { + grub_uint32_t src; +@@ -566,7 +578,7 @@ grub_net_tcp_open (char *server, + grub_net_tcp_socket_t socket; + static grub_uint16_t in_port = 21550; + struct grub_net_buff *nb; +- struct tcphdr *tcph; ++ struct tcp_synhdr *tcph; + int i; + grub_uint8_t *nbd; + grub_net_link_level_address_t ll_target_addr; +@@ -635,20 +647,24 @@ grub_net_tcp_open (char *server, + } + + tcph = (void *) nb->data; ++ grub_memset(tcph, 0, sizeof (*tcph)); + socket->my_start_seq = grub_get_time_ms (); + socket->my_cur_seq = socket->my_start_seq + 1; +- socket->my_window = 8192; +- tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq); +- tcph->ack = grub_cpu_to_be32_compile_time (0); +- tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN); +- tcph->window = grub_cpu_to_be16 (socket->my_window); +- tcph->urgent = 0; +- tcph->src = grub_cpu_to_be16 (socket->in_port); +- tcph->dst = grub_cpu_to_be16 (socket->out_port); +- tcph->checksum = 0; +- tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, +- &socket->inf->address, +- &socket->out_nla); ++ socket->my_window = 32768; ++ tcph->tcphdr.seqnr = grub_cpu_to_be32 (socket->my_start_seq); ++ tcph->tcphdr.ack = grub_cpu_to_be32_compile_time (0); ++ tcph->tcphdr.flags = grub_cpu_to_be16_compile_time ((6 << 12) | TCP_SYN); ++ tcph->tcphdr.window = grub_cpu_to_be16 (socket->my_window); ++ tcph->tcphdr.urgent = 0; ++ tcph->tcphdr.src = grub_cpu_to_be16 (socket->in_port); ++ tcph->tcphdr.dst = grub_cpu_to_be16 (socket->out_port); ++ tcph->tcphdr.checksum = 0; ++ tcph->scale_opt.kind = 3; ++ tcph->scale_opt.length = 3; ++ tcph->scale_opt.scale = 5; ++ tcph->tcphdr.checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP, ++ &socket->inf->address, ++ &socket->out_nla); + + tcp_socket_register (socket); + diff --git a/SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch b/SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch new file mode 100644 index 0000000..efeeee0 --- /dev/null +++ b/SOURCES/0035-efinet-and-bootp-add-support-for-dhcpv6.patch @@ -0,0 +1,651 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 11:47:37 +0200 +Subject: [PATCH] efinet and bootp: add support for dhcpv6 + +Signed-off-by: Peter Jones +--- + grub-core/net/bootp.c | 173 +++++++++++++++++++++++++++++++++++++ + grub-core/net/drivers/efi/efinet.c | 53 ++++++++++-- + grub-core/net/net.c | 72 +++++++++++++++ + grub-core/net/tftp.c | 4 + + include/grub/efi/api.h | 129 +++++++++++++++++++++++++-- + include/grub/net.h | 60 +++++++++++++ + 6 files changed, 477 insertions(+), 14 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 6fb5627025..e28fb6a09f 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -902,6 +902,179 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + + static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_ack (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags ++ __attribute__((__unused__)), ++ const grub_net_link_level_address_t *hwaddr, ++ const struct grub_net_dhcpv6_packet *packet, ++ int is_def, char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inter = NULL; ++ struct grub_net_network_level_address addr; ++ int mask = -1; ++ ++ if (!device || !path) ++ return NULL; ++ ++ *device = 0; ++ *path = 0; ++ ++ grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n", ++ hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2], ++ hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]); ++ ++ if (is_def) ++ grub_net_default_server = 0; ++ ++ if (is_def && !grub_net_default_server && packet) ++ { ++ const grub_uint8_t *options = packet->dhcp_options; ++ unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet); ++ unsigned int i; ++ ++ for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); ) ++ { ++ grub_uint16_t num, len; ++ grub_net_dhcpv6_option_t *opt = ++ (grub_net_dhcpv6_option_t *)(options + i); ++ ++ num = grub_be_to_cpu16(opt->option_num); ++ len = grub_be_to_cpu16(opt->option_len); ++ ++ grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len); ++ ++ if (len == 0) ++ break; ++ ++ if (len + i > 1024) ++ break; ++ ++ if (num == GRUB_NET_DHCP6_BOOTFILE_URL) ++ { ++ char *scheme, *userinfo, *host, *file; ++ char *tmp; ++ int hostlen; ++ int port; ++ int rc = extract_url_info ((const char *)opt->option_data, ++ (grub_size_t)len, ++ &scheme, &userinfo, &host, &port, ++ &file); ++ if (rc < 0) ++ continue; ++ ++ /* right now this only handles tftp. */ ++ if (grub_strcmp("tftp", scheme)) ++ { ++ grub_free (scheme); ++ grub_free (userinfo); ++ grub_free (host); ++ grub_free (file); ++ continue; ++ } ++ grub_free (userinfo); ++ ++ hostlen = grub_strlen (host); ++ if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']') ++ { ++ tmp = host+1; ++ host[hostlen-1] = '\0'; ++ } ++ else ++ tmp = host; ++ ++ *device = grub_xasprintf ("%s,%s", scheme, tmp); ++ grub_free (scheme); ++ grub_free (host); ++ ++ if (file && *file) ++ { ++ tmp = grub_strrchr (file, '/'); ++ if (tmp) ++ *(tmp+1) = '\0'; ++ else ++ file[0] = '\0'; ++ } ++ else if (!file) ++ file = grub_strdup (""); ++ ++ if (file[0] == '/') ++ { ++ *path = grub_strdup (file+1); ++ grub_free (file); ++ } ++ else ++ *path = file; ++ } ++ else if (num == GRUB_NET_DHCP6_IA_NA) ++ { ++ const grub_net_dhcpv6_option_t *ia_na_opt; ++ const grub_net_dhcpv6_opt_ia_na_t *ia_na = ++ (const grub_net_dhcpv6_opt_ia_na_t *)opt; ++ unsigned int left = len - OFFSET_OF (options, ia_na); ++ unsigned int j; ++ ++ if ((grub_uint8_t *)ia_na + left > ++ (grub_uint8_t *)options + option_max) ++ left -= ((grub_uint8_t *)ia_na + left) ++ - ((grub_uint8_t *)options + option_max); ++ ++ if (len < OFFSET_OF (option_data, opt) ++ + sizeof (grub_net_dhcpv6_option_t)) ++ { ++ grub_dprintf ("net", ++ "found dhcpv6 ia_na option with no address\n"); ++ continue; ++ } ++ ++ for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); ) ++ { ++ ia_na_opt = (const grub_net_dhcpv6_option_t *) ++ (ia_na->options + j); ++ grub_uint16_t ia_na_opt_num, ia_na_opt_len; ++ ++ ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num); ++ ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len); ++ if (ia_na_opt_len == 0) ++ break; ++ if (j + ia_na_opt_len > left) ++ break; ++ if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS) ++ { ++ const grub_net_dhcpv6_opt_ia_address_t *ia_addr; ++ ++ ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *) ++ ia_na_opt; ++ addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ grub_memcpy(addr.ipv6, ia_addr->ipv6_address, ++ sizeof (ia_addr->ipv6_address)); ++ inter = grub_net_add_addr (name, card, &addr, hwaddr, 0); ++ } ++ ++ j += ia_na_opt_len; ++ left -= ia_na_opt_len; ++ } ++ } ++ ++ i += len + 4; ++ } ++ ++ grub_print_error (); ++ } ++ ++ if (is_def) ++ { ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ ++ if (inter) ++ grub_net_add_ipv6_local (inter, mask); ++ return inter; ++} ++ ++ + void + grub_bootp_init (void) + { +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 5388f952ba..173fb63153 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -18,11 +18,14 @@ + + #include + #include ++#include + #include + #include + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -329,7 +332,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) + { + struct grub_net_card *card; +- grub_efi_device_path_t *dp; ++ grub_efi_device_path_t *dp, *ldp = NULL; + + dp = grub_efi_get_device_path (hnd); + if (! dp) +@@ -340,14 +343,19 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; + struct grub_efi_pxe_mode *pxe_mode; ++ + if (card->driver != &efidriver) + continue; ++ + cdp = grub_efi_get_device_path (card->efi_handle); + if (! cdp) + continue; ++ ++ ldp = grub_efi_find_last_device_path (dp); ++ + if (grub_efi_compare_device_paths (dp, cdp) != 0) + { +- grub_efi_device_path_t *ldp, *dup_dp, *dup_ldp; ++ grub_efi_device_path_t *dup_dp, *dup_ldp; + int match; + + /* EDK2 UEFI PXE driver creates pseudo devices with type IPv4/IPv6 +@@ -356,7 +364,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + devices. We skip them when enumerating cards, so here we need to + find matching MAC device. + */ +- ldp = grub_efi_find_last_device_path (dp); + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) +@@ -373,16 +380,46 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (!match) + continue; + } ++ + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (! pxe) + continue; ++ + pxe_mode = pxe->mode; +- grub_net_configure_by_dhcp_ack (card->name, card, 0, +- (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), +- 1, device, path); ++ if (pxe_mode->using_ipv6) ++ { ++ grub_net_link_level_address_t hwaddr; ++ struct grub_net_network_level_interface *intf; ++ ++ grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); ++ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", ++ pxe_mode->dhcp_ack_received ? "yes" : "no", ++ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); ++ if (!pxe_mode->dhcp_ack_received) ++ continue; ++ ++ hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ grub_memcpy (hwaddr.mac, ++ card->efi_net->mode->current_address, ++ sizeof (hwaddr.mac)); ++ ++ intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr, ++ (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6, ++ 1, device, path); ++ if (intf && device && path) ++ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ } ++ else ++ { ++ grub_dprintf ("efinet", "using ipv4 and dhcp\n"); ++ grub_net_configure_by_dhcp_ack (card->name, card, 0, ++ (struct grub_net_bootp_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ } + return; + } + } +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 0ef148f4ad..22f2689aae 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -960,6 +960,78 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa + grub_net_network_level_interfaces = inter; + } + ++int ++grub_ipv6_get_masksize (grub_uint16_t be_mask[8]) ++{ ++ grub_uint8_t *mask; ++ grub_uint16_t mask16[8]; ++ int x, y; ++ int ret = 128; ++ ++ grub_memcpy (mask16, be_mask, sizeof (mask16)); ++ for (x = 0; x < 8; x++) ++ mask16[x] = grub_be_to_cpu16 (mask16[x]); ++ ++ mask = (grub_uint8_t *)mask16; ++ ++ for (x = 15; x >= 0; x--) ++ { ++ grub_uint8_t octet = mask[x]; ++ if (!octet) ++ { ++ ret -= 8; ++ continue; ++ } ++ for (y = 0; y < 8; y++) ++ { ++ if (octet & (1 << y)) ++ break; ++ else ++ ret--; ++ } ++ break; ++ } ++ ++ return ret; ++} ++ ++grub_err_t ++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inter, ++ int mask) ++{ ++ struct grub_net_route *route; ++ ++ if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6) ++ return 0; ++ ++ if (mask == -1) ++ mask = grub_ipv6_get_masksize ((grub_uint16_t *)inter->address.ipv6); ++ ++ if (mask == -1) ++ return 0; ++ ++ route = grub_zalloc (sizeof (*route)); ++ if (!route) ++ return grub_errno; ++ ++ route->name = grub_xasprintf ("%s:local", inter->name); ++ if (!route->name) ++ { ++ grub_free (route); ++ return grub_errno; ++ } ++ ++ route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ grub_memcpy (route->target.ipv6.base, inter->address.ipv6, ++ sizeof (inter->address.ipv6)); ++ route->target.ipv6.masksize = mask; ++ route->is_gateway = 0; ++ route->interface = inter; ++ ++ grub_net_route_register (route); ++ ++ return 0; ++} + + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 7f44b30f52..4ab2f5c735 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -358,18 +358,22 @@ tftp_open (struct grub_file *file, const char *filename) + file->not_easily_seekable = 1; + file->data = data; + ++ grub_dprintf("tftp", "resolving address for %s\n", file->device->net->server); + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { ++ grub_dprintf("tftp", "Address resolution failed: %d\n", err); + grub_free (data); + return err; + } + ++ grub_dprintf("tftp", "opening connection\n"); + data->sock = grub_net_udp_open (addr, + TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { ++ grub_dprintf("tftp", "connection failed\n"); + grub_free (data); + return grub_errno; + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index f1a52210c0..117469450d 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -592,10 +592,16 @@ typedef void *grub_efi_handle_t; + typedef void *grub_efi_event_t; + typedef grub_efi_uint64_t grub_efi_lba_t; + typedef grub_efi_uintn_t grub_efi_tpl_t; +-typedef grub_uint8_t grub_efi_mac_address_t[32]; +-typedef grub_uint8_t grub_efi_ipv4_address_t[4]; +-typedef grub_uint16_t grub_efi_ipv6_address_t[8]; +-typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4))); ++typedef grub_efi_uint8_t grub_efi_mac_address_t[32]; ++typedef grub_efi_uint8_t grub_efi_ipv4_address_t[4]; ++typedef grub_efi_uint8_t grub_efi_ipv6_address_t[16]; ++typedef union ++{ ++ grub_efi_uint32_t addr[4]; ++ grub_efi_ipv4_address_t v4; ++ grub_efi_ipv6_address_t v6; ++} grub_efi_ip_address_t __attribute__ ((aligned(4))); ++ + typedef grub_efi_uint64_t grub_efi_physical_address_t; + typedef grub_efi_uint64_t grub_efi_virtual_address_t; + +@@ -1474,16 +1480,127 @@ struct grub_efi_simple_text_output_interface + }; + typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output_interface_t; + +-typedef grub_uint8_t grub_efi_pxe_packet_t[1472]; ++typedef struct grub_efi_pxe_dhcpv4_packet ++{ ++ grub_efi_uint8_t bootp_opcode; ++ grub_efi_uint8_t bootp_hwtype; ++ grub_efi_uint8_t bootp_hwaddr_len; ++ grub_efi_uint8_t bootp_gate_hops; ++ grub_efi_uint32_t bootp_ident; ++ grub_efi_uint16_t bootp_seconds; ++ grub_efi_uint16_t bootp_flags; ++ grub_efi_uint8_t bootp_ci_addr[4]; ++ grub_efi_uint8_t bootp_yi_addr[4]; ++ grub_efi_uint8_t bootp_si_addr[4]; ++ grub_efi_uint8_t bootp_gi_addr[4]; ++ grub_efi_uint8_t bootp_hw_addr[16]; ++ grub_efi_uint8_t bootp_srv_name[64]; ++ grub_efi_uint8_t bootp_boot_file[128]; ++ grub_efi_uint32_t dhcp_magik; ++ grub_efi_uint8_t dhcp_options[56]; ++} grub_efi_pxe_dhcpv4_packet_t; ++ ++struct grub_efi_pxe_dhcpv6_packet ++{ ++ grub_efi_uint32_t message_type:8; ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint8_t dhcp_options[1024]; ++} GRUB_PACKED; ++typedef struct grub_efi_pxe_dhcpv6_packet grub_efi_pxe_dhcpv6_packet_t; ++ ++typedef union ++{ ++ grub_efi_uint8_t raw[1472]; ++ grub_efi_pxe_dhcpv4_packet_t dhcpv4; ++ grub_efi_pxe_dhcpv6_packet_t dhcpv6; ++} grub_efi_pxe_packet_t; ++ ++#define GRUB_EFI_PXE_MAX_IPCNT 8 ++#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8 ++ ++typedef struct grub_efi_pxe_ip_filter ++{ ++ grub_efi_uint8_t filters; ++ grub_efi_uint8_t ip_count; ++ grub_efi_uint8_t reserved; ++ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct grub_efi_pxe_arp_entry ++{ ++ grub_efi_ip_address_t ip_addr; ++ grub_efi_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct grub_efi_pxe_route_entry ++{ ++ grub_efi_ip_address_t ip_addr; ++ grub_efi_ip_address_t subnet_mask; ++ grub_efi_ip_address_t gateway_addr; ++} grub_efi_pxe_route_entry_t; ++ ++typedef struct grub_efi_pxe_icmp_error ++{ ++ grub_efi_uint8_t type; ++ grub_efi_uint8_t code; ++ grub_efi_uint16_t checksum; ++ union ++ { ++ grub_efi_uint32_t reserved; ++ grub_efi_uint32_t mtu; ++ grub_efi_uint32_t pointer; ++ struct ++ { ++ grub_efi_uint16_t identifier; ++ grub_efi_uint16_t sequence; ++ } echo; ++ } u; ++ grub_efi_uint8_t data[494]; ++} grub_efi_pxe_icmp_error_t; ++ ++typedef struct grub_efi_pxe_tftp_error ++{ ++ grub_efi_uint8_t error_code; ++ grub_efi_char8_t error_string[127]; ++} grub_efi_pxe_tftp_error_t; + + typedef struct grub_efi_pxe_mode + { +- grub_uint8_t unused[52]; ++ grub_efi_boolean_t started; ++ grub_efi_boolean_t ipv6_available; ++ grub_efi_boolean_t ipv6_supported; ++ grub_efi_boolean_t using_ipv6; ++ grub_efi_boolean_t bis_supported; ++ grub_efi_boolean_t bis_detected; ++ grub_efi_boolean_t auto_arp; ++ grub_efi_boolean_t send_guid; ++ grub_efi_boolean_t dhcp_discover_valid; ++ grub_efi_boolean_t dhcp_ack_received; ++ grub_efi_boolean_t proxy_offer_received; ++ grub_efi_boolean_t pxe_discover_valid; ++ grub_efi_boolean_t pxe_reply_received; ++ grub_efi_boolean_t pxe_bis_reply_received; ++ grub_efi_boolean_t icmp_error_received; ++ grub_efi_boolean_t tftp_error_received; ++ grub_efi_boolean_t make_callbacks; ++ grub_efi_uint8_t ttl; ++ grub_efi_uint8_t tos; ++ grub_efi_ip_address_t station_ip; ++ grub_efi_ip_address_t subnet_mask; + grub_efi_pxe_packet_t dhcp_discover; + grub_efi_pxe_packet_t dhcp_ack; + grub_efi_pxe_packet_t proxy_offer; + grub_efi_pxe_packet_t pxe_discover; + grub_efi_pxe_packet_t pxe_reply; ++ grub_efi_pxe_packet_t pxe_bis_reply; ++ grub_efi_pxe_ip_filter_t ip_filter; ++ grub_efi_uint32_t arp_cache_entries; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES]; ++ grub_efi_uint32_t route_table_entries; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES]; ++ grub_efi_pxe_icmp_error_t icmp_error; ++ grub_efi_pxe_tftp_error_t tftp_error; + } grub_efi_pxe_mode_t; + + typedef struct grub_efi_pxe +diff --git a/include/grub/net.h b/include/grub/net.h +index 7ae4b6bd80..8a05ec4fe7 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -447,6 +447,51 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + ++enum ++ { ++ GRUB_NET_DHCP6_IA_NA = 3, ++ GRUB_NET_DHCP6_IA_ADDRESS = 5, ++ GRUB_NET_DHCP6_BOOTFILE_URL = 59, ++ }; ++ ++struct grub_net_dhcpv6_option ++{ ++ grub_uint16_t option_num; ++ grub_uint16_t option_len; ++ grub_uint8_t option_data[]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t; ++ ++struct grub_net_dhcpv6_opt_ia_na ++{ ++ grub_uint16_t option_num; ++ grub_uint16_t option_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_uint8_t options[]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t; ++ ++struct grub_net_dhcpv6_opt_ia_address ++{ ++ grub_uint16_t option_num; ++ grub_uint16_t option_len; ++ grub_uint64_t ipv6_address[2]; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_uint8_t options[]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t; ++ ++struct grub_net_dhcpv6_packet ++{ ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[1024]; ++} GRUB_PACKED; ++typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t; ++ + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 +@@ -482,6 +527,21 @@ grub_net_configure_by_dhcp_ack (const char *name, + grub_size_t size, + int is_def, char **device, char **path); + ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_ack (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const grub_net_link_level_address_t *hwaddr, ++ const struct grub_net_dhcpv6_packet *packet, ++ int is_def, char **device, char **path); ++ ++int ++grub_ipv6_get_masksize(grub_uint16_t *mask); ++ ++grub_err_t ++grub_net_add_ipv6_local (struct grub_net_network_level_interface *inf, ++ int mask); ++ + grub_err_t + grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf, + int mask); diff --git a/SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch b/SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch new file mode 100644 index 0000000..95490cd --- /dev/null +++ b/SOURCES/0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch @@ -0,0 +1,271 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 23 Jun 2016 11:01:39 -0400 +Subject: [PATCH] Add grub-get-kernel-settings and use it in 10_linux + +This patch adds grub-get-kernel-settings, which reads the system kernel +installation configuration from /etc/sysconfig/kernel, and outputs +${GRUB_...} variables suitable for evaluation by grub-mkconfig. Those +variables are then used by 10_linux to choose whether or not to create +debug stanzas. + +Resolves: rhbz#1226325 +[rharwood: migrate man page to h2m] +--- + configure.ac | 1 + + Makefile.util.def | 7 ++ + docs/man/grub-get-kernel-settings.h2m | 2 + + util/bash-completion.d/grub-completion.bash.in | 22 +++++++ + util/grub-get-kernel-settings.in | 88 ++++++++++++++++++++++++++ + util/grub-mkconfig.in | 3 + + util/grub.d/10_linux.in | 23 +++++-- + 7 files changed, 141 insertions(+), 5 deletions(-) + create mode 100644 docs/man/grub-get-kernel-settings.h2m + create mode 100644 util/grub-get-kernel-settings.in + +diff --git a/configure.ac b/configure.ac +index 7f59ad788f..0d0e6782a1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -65,6 +65,7 @@ grub_TRANSFORM([grub-install]) + grub_TRANSFORM([grub-mkconfig]) + grub_TRANSFORM([grub-mkfont]) + grub_TRANSFORM([grub-mkimage]) ++grub_TRANSFORM([grub-get-kernel-settings]) + grub_TRANSFORM([grub-glue-efi]) + grub_TRANSFORM([grub-mklayout]) + grub_TRANSFORM([grub-mkpasswd-pbkdf2]) +diff --git a/Makefile.util.def b/Makefile.util.def +index 4ee22c5daa..18a9242776 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -716,6 +716,13 @@ script = { + installdir = sbin; + }; + ++script = { ++ name = grub-get-kernel-settings; ++ common = util/grub-get-kernel-settings.in; ++ mansection = 3; ++ installdir = sbin; ++}; ++ + script = { + name = grub-set-default; + common = util/grub-set-default.in; +diff --git a/docs/man/grub-get-kernel-settings.h2m b/docs/man/grub-get-kernel-settings.h2m +new file mode 100644 +index 0000000000..b8051f01f3 +--- /dev/null ++++ b/docs/man/grub-get-kernel-settings.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-get-kernel-settings \- Evaluate the system's kernel installation settings for use while making a grub configuration file +diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in +index 44bf135b9f..5c4acd496d 100644 +--- a/util/bash-completion.d/grub-completion.bash.in ++++ b/util/bash-completion.d/grub-completion.bash.in +@@ -264,6 +264,28 @@ have ${__grub_sparc64_setup_program} && \ + unset __grub_sparc64_setup_program + + ++# ++# grub-get-kernel-settings ++# ++_grub_get_kernel_settings () { ++ local cur ++ ++ COMPREPLY=() ++ cur=`_get_cword` ++ ++ if [[ "$cur" == -* ]]; then ++ __grubcomp "$(__grub_get_options_from_help)" ++ else ++ # Default complete with a filename ++ _filedir ++ fi ++} ++__grub_get_kernel_settings_program="@grub_get_kernel_settings@" ++have ${__grub_get_kernel_settings_program} && \ ++ complete -F _grub_get_kernel_settings -o filenames ${__grub_get_kernel_settings_program} ++unset __grub_get_kernel_settings_program ++ ++ + # + # grub-install + # +diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in +new file mode 100644 +index 0000000000..7e87dfccc0 +--- /dev/null ++++ b/util/grub-get-kernel-settings.in +@@ -0,0 +1,88 @@ ++#!/bin/sh ++set -e ++ ++# Evaluate new-kernel-pkg's configuration file. ++# Copyright (C) 2016 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++PACKAGE_NAME=@PACKAGE_NAME@ ++PACKAGE_VERSION=@PACKAGE_VERSION@ ++datadir="@datadir@" ++if [ "x$pkgdatadir" = x ]; then ++ pkgdatadir="${datadir}/@PACKAGE@" ++fi ++ ++self=`basename $0` ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "${pkgdatadir}/grub-mkconfig_lib" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ gettext_printf "Usage: %s [OPTION]\n" "$self" ++ gettext "Evaluate new-kernel-pkg configuration"; echo ++ echo ++ print_option_help "-h, --help" "$(gettext "print this message and exit")" ++ print_option_help "-v, --version" "$(gettext "print the version information and exit")" ++ echo ++} ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -v | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ -*) ++ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 ++ usage ++ exit 1 ++ ;; ++ # Explicitly ignore non-option arguments, for compatibility. ++ esac ++done ++ ++if test -f /etc/sysconfig/kernel ; then ++ . /etc/sysconfig/kernel ++fi ++ ++if [ "$MAKEDEBUG" = "yes" ]; then ++ echo GRUB_LINUX_MAKE_DEBUG=true ++ echo export GRUB_LINUX_MAKE_DEBUG ++ echo GRUB_CMDLINE_LINUX_DEBUG=\"systemd.log_level=debug systemd.log_target=kmsg\" ++ echo export GRUB_CMDLINE_LINUX_DEBUG ++ echo GRUB_LINUX_DEBUG_TITLE_POSTFIX=\" with debugging\" ++ echo export GRUB_LINUX_DEBUG_TITLE_POSTFIX ++fi ++if [ "$DEFAULTDEBUG" = "yes" ]; then ++ echo GRUB_DEFAULT_TO_DEBUG=true ++else ++ echo GRUB_DEFAULT_TO_DEBUG=false ++fi ++echo export GRUB_DEFAULT_TO_DEBUG ++if [ "$UPDATEDEFAULT" = "yes" ]; then ++ echo GRUB_UPDATE_DEFAULT_KERNEL=true ++ echo export GRUB_UPDATE_DEFAULT_KERNEL ++fi +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index ba14cf6261..005f093809 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -45,6 +45,7 @@ grub_probe="${sbindir}/@grub_probe@" + grub_file="${bindir}/@grub_file@" + grub_editenv="${bindir}/@grub_editenv@" + grub_script_check="${bindir}/@grub_script_check@" ++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" + + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" +@@ -158,6 +159,8 @@ if test -f ${sysconfdir}/default/grub ; then + . ${sysconfdir}/default/grub + fi + ++eval "$("${grub_get_kernel_settings}")" || true ++ + if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then + if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then + GRUB_DISABLE_LINUX_UUID="true" +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 786dbabb4a..292e333324 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -111,7 +111,8 @@ linux_entry () + os="$1" + version="$2" + type="$3" +- args="$4" ++ isdebug="$4" ++ args="$5" + + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" +@@ -123,6 +124,9 @@ linux_entry () + quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" + title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" + fi ++ if [ x$isdebug = xdebug ]; then ++ title="$title${GRUB_LINUX_DEBUG_TITLE_POSTFIX}" ++ fi + echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" + else + echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" +@@ -306,11 +310,15 @@ while [ "x$list" != "x" ] ; do + fi + + if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then +- linux_entry "${OS}" "${version}" simple \ ++ linux_entry "${OS}" "${version}" simple standard \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ linux_entry "${OS}" "${version}" simple debug \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi + + submenu_indentation="$grub_tab" +- ++ + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi +@@ -319,10 +327,15 @@ while [ "x$list" != "x" ] ; do + is_top_level=false + fi + +- linux_entry "${OS}" "${version}" advanced \ ++ linux_entry "${OS}" "${version}" advanced standard \ + "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ linux_entry "${OS}" "${version}" advanced debug \ ++ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi ++ + if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then +- linux_entry "${OS}" "${version}" recovery \ ++ linux_entry "${OS}" "${version}" recovery standard \ + "single ${GRUB_CMDLINE_LINUX}" + fi + diff --git a/SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch b/SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch new file mode 100644 index 0000000..15b2111 --- /dev/null +++ b/SOURCES/0037-bz1374141-fix-incorrect-mask-for-ppc64.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Masahiro Matsuya +Date: Sat, 29 Oct 2016 08:35:26 +0900 +Subject: [PATCH] bz1374141 fix incorrect mask for ppc64 + +The netmask configured in firmware is not respected on ppc64 (big endian). +When 255.255.252.0 is set as netmask in firmware, the following is the value of bootpath string in grub_ieee1275_parse_bootpath(). + + /vdevice/l-lan@30000002:speed=auto,duplex=auto,192.168.88.10,,192.168.89.113,192.168.88.1,5,5,255.255.252.0,512 + +The netmask in this bootpath is no problem, since it's a value specified in firmware. But, +The value of 'subnet_mask.ipv4' was set with 0xfffffc00, and __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4)) returned 16 (not 22). +As a result, 16 was used for netmask wrongly. + +1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) +0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) +1111 1111 0000 0011 0000 0000 0000 0000 # ~grub_le_to_cpu32 (subnet_mask.ipv4) + +And, the count of zero with __builtin_ctz can be 16. +This patch changes it as below. + +1111 1111 1111 1111 1111 1100 0000 0000 # subnet_mask.ipv4 (=0xfffffc00) +0000 0000 1111 1100 1111 1111 1111 1111 # grub_le_to_cpu32 (subnet_mask.ipv4) +1111 1111 1111 1111 1111 1100 0000 0000 # grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) +0000 0000 0000 0000 0000 0011 1111 1111 # ~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)) + +The count of zero with __builtin_clz can be 22. (clz counts the number of one bits preceding the most significant zero bit) + +Signed-off-by: Masahiro Matsuya +Signed-off-by: Robbie Harwood +--- + grub-core/net/drivers/ieee1275/ofnet.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c +index ac4e62a95c..3860b6f78d 100644 +--- a/grub-core/net/drivers/ieee1275/ofnet.c ++++ b/grub-core/net/drivers/ieee1275/ofnet.c +@@ -220,8 +220,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, + flags); + inter->vlantag = vlantag; + grub_net_add_ipv4_local (inter, +- __builtin_ctz (~grub_le_to_cpu32 (subnet_mask.ipv4))); +- ++ __builtin_clz (~grub_swap_bytes32(grub_le_to_cpu32 (subnet_mask.ipv4)))); + } + + if (gateway_addr.ipv4 != 0) diff --git a/SOURCES/0038-Make-grub_fatal-also-backtrace.patch b/SOURCES/0038-Make-grub_fatal-also-backtrace.patch new file mode 100644 index 0000000..f876575 --- /dev/null +++ b/SOURCES/0038-Make-grub_fatal-also-backtrace.patch @@ -0,0 +1,172 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 27 Jan 2016 09:22:42 -0500 +Subject: [PATCH] Make grub_fatal() also backtrace. + +--- + grub-core/Makefile.core.def | 3 ++ + grub-core/kern/misc.c | 8 +++++- + grub-core/lib/arm64/backtrace.c | 62 +++++++++++++++++++++++++++++++++++++++++ + grub-core/lib/backtrace.c | 2 ++ + grub-core/lib/i386/backtrace.c | 14 +++++++++- + 5 files changed, 87 insertions(+), 2 deletions(-) + create mode 100644 grub-core/lib/arm64/backtrace.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index c15e91943b..058c88ac3a 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -188,6 +188,9 @@ kernel = { + + softdiv = lib/division.c; + ++ x86 = lib/i386/backtrace.c; ++ x86 = lib/backtrace.c; ++ + i386 = kern/i386/dl.c; + i386_xen = kern/i386/dl.c; + i386_xen_pvh = kern/i386/dl.c; +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 63b586d09c..a3e215155b 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + union printf_arg + { +@@ -1199,8 +1200,13 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) + static void __attribute__ ((noreturn)) + grub_abort (void) + { ++#ifndef GRUB_UTIL ++#if defined(__i386__) || defined(__x86_64__) ++ grub_backtrace(); ++#endif ++#endif + grub_printf ("\nAborted."); +- ++ + #ifndef GRUB_UTIL + if (grub_term_inputs) + #endif +diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c +new file mode 100644 +index 0000000000..1079b5380e +--- /dev/null ++++ b/grub-core/lib/arm64/backtrace.c +@@ -0,0 +1,62 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++void ++grub_backtrace_pointer (int frame) ++{ ++ while (1) ++ { ++ void *lp = __builtin_return_address (frame); ++ if (!lp) ++ break; ++ ++ lp = __builtin_extract_return_addr (lp); ++ ++ grub_printf ("%p: ", lp); ++ grub_backtrace_print_address (lp); ++ grub_printf (" ("); ++ for (i = 0; i < 2; i++) ++ grub_printf ("%p,", ((void **)ptr) [i + 2]); ++ grub_printf ("%p)\n", ((void **)ptr) [i + 2]); ++ nptr = *(void **)ptr; ++ if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME ++ || nptr == ptr) ++ { ++ grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); ++ break; ++ } ++ ptr = nptr; ++ } ++} ++ ++void ++grub_backtrace (void) ++{ ++ grub_backtrace_pointer (1); ++} ++ +diff --git a/grub-core/lib/backtrace.c b/grub-core/lib/backtrace.c +index 825a8800e2..c0ad6ab8be 100644 +--- a/grub-core/lib/backtrace.c ++++ b/grub-core/lib/backtrace.c +@@ -29,6 +29,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + void + grub_backtrace_print_address (void *addr) + { ++#ifndef GRUB_UTIL + grub_dl_t mod; + + FOR_DL_MODULES (mod) +@@ -44,6 +45,7 @@ grub_backtrace_print_address (void *addr) + } + } + ++#endif + grub_printf ("%p", addr); + } + +diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c +index c3e03c7275..c67273db3a 100644 +--- a/grub-core/lib/i386/backtrace.c ++++ b/grub-core/lib/i386/backtrace.c +@@ -15,11 +15,23 @@ + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ ++#include ++#ifdef GRUB_UTIL ++#define REALLY_GRUB_UTIL GRUB_UTIL ++#undef GRUB_UTIL ++#endif ++ ++#include ++#include ++ ++#ifdef REALLY_GRUB_UTIL ++#define GRUB_UTIL REALLY_GRUB_UTIL ++#undef REALLY_GRUB_UTIL ++#endif + + #include + #include + #include +-#include + #include + #include + #include diff --git a/SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch b/SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch new file mode 100644 index 0000000..afba285 --- /dev/null +++ b/SOURCES/0039-Make-our-info-pages-say-grub2-where-appropriate.patch @@ -0,0 +1,1008 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 12:59:58 +0200 +Subject: [PATCH] Make our info pages say "grub2" where appropriate. + +This needs to be hooked up to --program-transform=, but I haven't had +time. + +Signed-off-by: Peter Jones +--- + docs/grub-dev.texi | 4 +- + docs/grub.texi | 321 ++++++++++++++++++++++++++++------------------------- + 2 files changed, 171 insertions(+), 154 deletions(-) + +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 6c629a23e2..19f708ee66 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub-dev.info ++@setfilename grub2-dev.info + @include version-dev.texi + @settitle GNU GRUB Developers Manual @value{VERSION} + @c Unify all our little indices for now. +@@ -32,7 +32,7 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* grub-dev: (grub-dev). The GRand Unified Bootloader Dev ++* grub2-dev: (grub2-dev). The GRand Unified Bootloader Dev + @end direntry + + @setchapternewpage odd +diff --git a/docs/grub.texi b/docs/grub.texi +index 69f08d289f..0615d0ed97 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -1,7 +1,7 @@ + \input texinfo + @c -*-texinfo-*- + @c %**start of header +-@setfilename grub.info ++@setfilename grub2.info + @include version.texi + @settitle GNU GRUB Manual @value{VERSION} + @c Unify all our little indices for now. +@@ -32,15 +32,15 @@ Invariant Sections. + + @dircategory Kernel + @direntry +-* GRUB: (grub). The GRand Unified Bootloader +-* grub-install: (grub)Invoking grub-install. Install GRUB on your drive +-* grub-mkconfig: (grub)Invoking grub-mkconfig. Generate GRUB configuration +-* grub-mkpasswd-pbkdf2: (grub)Invoking grub-mkpasswd-pbkdf2. +-* grub-mkrelpath: (grub)Invoking grub-mkrelpath. +-* grub-mkrescue: (grub)Invoking grub-mkrescue. Make a GRUB rescue image +-* grub-mount: (grub)Invoking grub-mount. Mount a file system using GRUB +-* grub-probe: (grub)Invoking grub-probe. Probe device information +-* grub-script-check: (grub)Invoking grub-script-check. ++* GRUB2: (grub2). The GRand Unified Bootloader ++* grub2-install: (grub2)Invoking grub2-install. Install GRUB on your drive ++* grub2-mkconfig: (grub2)Invoking grub2-mkconfig. Generate GRUB configuration ++* grub2-mkpasswd-pbkdf2: (grub2)Invoking grub2-mkpasswd-pbkdf2. ++* grub2-mkrelpath: (grub2)Invoking grub2-mkrelpath. ++* grub2-mkrescue: (grub2)Invoking grub2-mkrescue. Make a GRUB rescue image ++* grub2-mount: (grub2)Invoking grub2-mount. Mount a file system using GRUB ++* grub2-probe: (grub2)Invoking grub2-probe. Probe device information ++* grub2-script-check: (grub2)Invoking grub2-script-check. + @end direntry + + @setchapternewpage odd +@@ -103,15 +103,15 @@ This edition documents version @value{VERSION}. + * Platform-specific operations:: Platform-specific operations + * Supported kernels:: The list of supported kernels + * Troubleshooting:: Error messages produced by GRUB +-* Invoking grub-install:: How to use the GRUB installer +-* Invoking grub-mkconfig:: Generate a GRUB configuration file +-* Invoking grub-mkpasswd-pbkdf2:: ++* Invoking grub2-install:: How to use the GRUB installer ++* Invoking grub2-mkconfig:: Generate a GRUB configuration file ++* Invoking grub2-mkpasswd-pbkdf2:: + Generate GRUB password hashes +-* Invoking grub-mkrelpath:: Make system path relative to its root +-* Invoking grub-mkrescue:: Make a GRUB rescue image +-* Invoking grub-mount:: Mount a file system using GRUB +-* Invoking grub-probe:: Probe device information for GRUB +-* Invoking grub-script-check:: Check GRUB script file for syntax errors ++* Invoking grub2-mkrelpath:: Make system path relative to its root ++* Invoking grub2-mkrescue:: Make a GRUB rescue image ++* Invoking grub2-mount:: Mount a file system using GRUB ++* Invoking grub2-probe:: Probe device information for GRUB ++* Invoking grub2-script-check:: Check GRUB script file for syntax errors + * Obtaining and Building GRUB:: How to obtain and build GRUB + * Reporting bugs:: Where you should send a bug report + * Future:: Some future plans on GRUB +@@ -230,7 +230,7 @@ surprising. + + @item + @file{grub.cfg} is typically automatically generated by +-@command{grub-mkconfig} (@pxref{Simple configuration}). This makes it ++@command{grub2-mkconfig} (@pxref{Simple configuration}). This makes it + easier to handle versioned kernel upgrades. + + @item +@@ -244,7 +244,7 @@ scripting language: variables, conditionals, and loops are available. + @item + A small amount of persistent storage is available across reboots, using the + @command{save_env} and @command{load_env} commands in GRUB and the +-@command{grub-editenv} utility. This is not available in all configurations ++@command{grub2-editenv} utility. This is not available in all configurations + (@pxref{Environment block}). + + @item +@@ -549,7 +549,7 @@ On OS which have device nodes similar to Unix-like OS GRUB tools use the + OS name. E.g. for GNU/Linux: + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + On AROS we use another syntax. For volumes: +@@ -572,7 +572,7 @@ For disks we use syntax: + E.g. + + @example +-# @kbd{grub-install //:ata.device/0/0} ++# @kbd{grub2-install //:ata.device/0/0} + @end example + + On Windows we use UNC path. For volumes it's typically +@@ -599,7 +599,7 @@ For disks it's + E.g. + + @example +-# @kbd{grub-install \\?\PhysicalDrive0} ++# @kbd{grub2-install \\?\PhysicalDrive0} + @end example + + Beware that you may need to further escape the backslashes depending on your +@@ -609,7 +609,7 @@ When compiled with cygwin support then cygwin drive names are automatically + when needed. E.g. + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + @node Installation +@@ -622,7 +622,7 @@ from the source tarball, or as a package for your OS. + + After you have done that, you need to install the boot loader on a + drive (floppy or hard disk) by using the utility +-@command{grub-install} (@pxref{Invoking grub-install}) on a UNIX-like OS. ++@command{grub2-install} (@pxref{Invoking grub2-install}) on a UNIX-like OS. + + GRUB comes with boot images, which are normally put in the directory + @file{/usr/lib/grub/-} (for BIOS-based machines +@@ -633,22 +633,22 @@ loader needs to find them (usually @file{/boot}) will be called + the @dfn{boot directory}. + + @menu +-* Installing GRUB using grub-install:: ++* Installing GRUB using grub2-install:: + * Making a GRUB bootable CD-ROM:: + * Device map:: + * BIOS installation:: + @end menu + + +-@node Installing GRUB using grub-install +-@section Installing GRUB using grub-install ++@node Installing GRUB using grub2-install ++@section Installing GRUB using grub2-install + + For information on where GRUB should be installed on PC BIOS platforms, + @pxref{BIOS installation}. + + In order to install GRUB under a UNIX-like OS (such +-as @sc{gnu}), invoke the program @command{grub-install} (@pxref{Invoking +-grub-install}) as the superuser (@dfn{root}). ++as @sc{gnu}), invoke the program @command{grub2-install} (@pxref{Invoking ++grub2-install}) as the superuser (@dfn{root}). + + The usage is basically very simple. You only need to specify one + argument to the program, namely, where to install the boot loader. The +@@ -657,13 +657,13 @@ For example, under Linux the following will install GRUB into the MBR + of the first IDE disk: + + @example +-# @kbd{grub-install /dev/sda} ++# @kbd{grub2-install /dev/sda} + @end example + + Likewise, under GNU/Hurd, this has the same effect: + + @example +-# @kbd{grub-install /dev/hd0} ++# @kbd{grub2-install /dev/hd0} + @end example + + But all the above examples assume that GRUB should put images under +@@ -677,7 +677,7 @@ boot floppy with a filesystem. Here is an example: + # @kbd{mke2fs /dev/fd0} + # @kbd{mount -t ext2 /dev/fd0 /mnt} + # @kbd{mkdir /mnt/boot} +-# @kbd{grub-install --boot-directory=/mnt/boot /dev/fd0} ++# @kbd{grub2-install --boot-directory=/mnt/boot /dev/fd0} + # @kbd{umount /mnt} + @end group + @end example +@@ -689,30 +689,37 @@ floppy instead of exposing the USB drive as a hard disk (they call it + @example + # @kbd{losetup /dev/loop0 /dev/sdb1} + # @kbd{mount /dev/loop0 /mnt/usb} +-# @kbd{grub-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} ++# @kbd{grub2-install --boot-directory=/mnt/usb/bugbios --force --allow-floppy /dev/loop0} + @end example + + This install doesn't conflict with standard install as long as they are in + separate directories. + ++Note that @command{grub2-install} is actually just a shell script and the ++real task is done by other tools such as @command{grub2-mkimage}. Therefore, ++you may run those commands directly to install GRUB, without using ++@command{grub2-install}. Don't do that, however, unless you are very familiar ++with the internals of GRUB. Installing a boot loader on a running OS may be ++extremely dangerous. ++ + On EFI systems for fixed disk install you have to mount EFI System Partition. + If you mount it at @file{/boot/efi} then you don't need any special arguments: + + @example +-# @kbd{grub-install} ++# @kbd{grub2-install} + @end example + + Otherwise you need to specify where your EFI System partition is mounted: + + @example +-# @kbd{grub-install --efi-directory=/mnt/efi} ++# @kbd{grub2-install --efi-directory=/mnt/efi} + @end example + + For removable installs you have to use @option{--removable} and specify both + @option{--boot-directory} and @option{--efi-directory}: + + @example +-# @kbd{grub-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} ++# @kbd{grub2-install --efi-directory=/mnt/usb --boot-directory=/mnt/usb/boot --removable} + @end example + + @node Making a GRUB bootable CD-ROM +@@ -732,10 +739,10 @@ usually also need to include a configuration file @file{grub.cfg} and some + other GRUB modules. + + To make a simple generic GRUB rescue CD, you can use the +-@command{grub-mkrescue} program (@pxref{Invoking grub-mkrescue}): ++@command{grub2-mkrescue} program (@pxref{Invoking grub2-mkrescue}): + + @example +-$ @kbd{grub-mkrescue -o grub.iso} ++$ @kbd{grub2-mkrescue -o grub.iso} + @end example + + You will often need to include other files in your image. To do this, first +@@ -758,7 +765,7 @@ directory @file{iso/}. + Finally, make the image: + + @example +-$ @kbd{grub-mkrescue -o grub.iso iso} ++$ @kbd{grub2-mkrescue -o grub.iso iso} + @end example + + This produces a file named @file{grub.iso}, which then can be burned +@@ -774,7 +781,7 @@ storage devices. + @node Device map + @section The map between BIOS drives and OS devices + +-If the device map file exists, the GRUB utilities (@command{grub-probe}, ++If the device map file exists, the GRUB utilities (@command{grub2-probe}, + etc.) read it to map BIOS drives to OS devices. This file consists of lines + like this: + +@@ -1254,23 +1261,23 @@ need to write the whole thing by hand. + @node Simple configuration + @section Simple configuration handling + +-The program @command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}) ++The program @command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}) + generates @file{grub.cfg} files suitable for most cases. It is suitable for + use when upgrading a distribution, and will discover available kernels and + attempt to generate menu entries for them. + +-@command{grub-mkconfig} does have some limitations. While adding extra ++@command{grub2-mkconfig} does have some limitations. While adding extra + custom menu entries to the end of the list can be done by editing +-@file{/etc/grub.d/40_custom} or creating @file{/boot/grub/custom.cfg}, ++@file{/etc/grub.d/40_custom} or creating @file{/boot/grub2/custom.cfg}, + changing the order of menu entries or changing their titles may require + making complex changes to shell scripts stored in @file{/etc/grub.d/}. This + may be improved in the future. In the meantime, those who feel that it + would be easier to write @file{grub.cfg} directly are encouraged to do so + (@pxref{Booting}, and @ref{Shell-like scripting}), and to disable any system +-provided by their distribution to automatically run @command{grub-mkconfig}. ++provided by their distribution to automatically run @command{grub2-mkconfig}. + + The file @file{/etc/default/grub} controls the operation of +-@command{grub-mkconfig}. It is sourced by a shell script, and so must be ++@command{grub2-mkconfig}. It is sourced by a shell script, and so must be + valid POSIX shell input; normally, it will just be a sequence of + @samp{KEY=value} lines, but if the value contains spaces or other special + characters then it must be quoted. For example: +@@ -1308,7 +1315,7 @@ works it's not recommended since titles often contain unstable device names + and may be translated + + If you set this to @samp{saved}, then the default menu entry will be that +-saved by @samp{GRUB_SAVEDEFAULT} or @command{grub-set-default}. This relies on ++saved by @samp{GRUB_SAVEDEFAULT} or @command{grub2-set-default}. This relies on + the environment block, which may not be available in all situations + (@pxref{Environment block}). + +@@ -1319,7 +1326,7 @@ If this option is set to @samp{true}, then, when an entry is selected, save + it as a new default entry for use by future runs of GRUB. This is only + useful if @samp{GRUB_DEFAULT=saved}; it is a separate option because + @samp{GRUB_DEFAULT=saved} is useful without this option, in conjunction with +-@command{grub-set-default}. Unset by default. ++@command{grub2-set-default}. Unset by default. + This option relies on the environment block, which may not be available in + all situations (@pxref{Environment block}). + +@@ -1449,7 +1456,7 @@ intel-uc.img intel-ucode.img amd-uc.img amd-ucode.img early_ucode.cpio microcode + @end example + + @item GRUB_DISABLE_LINUX_UUID +-Normally, @command{grub-mkconfig} will generate menu entries that use ++Normally, @command{grub2-mkconfig} will generate menu entries that use + universally-unique identifiers (UUIDs) to identify the root filesystem to + the Linux kernel, using a @samp{root=UUID=...} kernel parameter. This is + usually more reliable, but in some cases it may not be appropriate. To +@@ -1471,7 +1478,7 @@ If this option is set to @samp{true}, disable the generation of recovery + mode menu entries. + + @item GRUB_DISABLE_UUID +-Normally, @command{grub-mkconfig} will generate menu entries that use ++Normally, @command{grub2-mkconfig} will generate menu entries that use + universally-unique identifiers (UUIDs) to identify various filesystems to + search for files. This is usually more reliable, but in some cases it may + not be appropriate. To disable this use of UUIDs, set this option to +@@ -1482,12 +1489,12 @@ not be appropriate. To disable this use of UUIDs, set this option to + @item GRUB_VIDEO_BACKEND + If graphical video support is required, either because the @samp{gfxterm} + graphical terminal is in use or because @samp{GRUB_GFXPAYLOAD_LINUX} is set, +-then @command{grub-mkconfig} will normally load all available GRUB video ++then @command{grub2-mkconfig} will normally load all available GRUB video + drivers and use the one most appropriate for your hardware. If you need to + override this for some reason, then you can set this option. + +-After @command{grub-install} has been run, the available video drivers are +-listed in @file{/boot/grub/video.lst}. ++After @command{grub2-install} has been run, the available video drivers are ++listed in @file{/boot/grub2/video.lst}. + + @item GRUB_GFXMODE + Set the resolution used on the @samp{gfxterm} graphical terminal. Note that +@@ -1519,7 +1526,7 @@ boot sequence. If you have problems, set this option to @samp{text} and + GRUB will tell Linux to boot in normal text mode. + + @item GRUB_DISABLE_OS_PROBER +-Normally, @command{grub-mkconfig} will try to use the external ++Normally, @command{grub2-mkconfig} will try to use the external + @command{os-prober} program, if installed, to discover other operating + systems installed on the same system and generate appropriate menu entries + for them. Set this option to @samp{true} to disable this. +@@ -1529,7 +1536,7 @@ List of space-separated FS UUIDs of filesystems to be ignored from os-prober + output. For efi chainloaders it's @@ + + @item GRUB_DISABLE_SUBMENU +-Normally, @command{grub-mkconfig} will generate top level menu entry for ++Normally, @command{grub2-mkconfig} will generate top level menu entry for + the kernel with highest version number and put all other found kernels + or alternative menu entries for recovery mode in submenu. For entries returned + by @command{os-prober} first entry will be put on top level and all others +@@ -1537,11 +1544,11 @@ in submenu. If this option is set to @samp{true}, flat menu with all entries + on top level will be generated instead. Changing this option will require + changing existing values of @samp{GRUB_DEFAULT}, @samp{fallback} (@pxref{fallback}) + and @samp{default} (@pxref{default}) environment variables as well as saved +-default entry using @command{grub-set-default} and value used with +-@command{grub-reboot}. ++default entry using @command{grub2-set-default} and value used with ++@command{grub2-reboot}. + + @item GRUB_ENABLE_CRYPTODISK +-If set to @samp{y}, @command{grub-mkconfig} and @command{grub-install} will ++If set to @samp{y}, @command{grub2-mkconfig} and @command{grub2-install} will + check for encrypted disks and generate additional commands needed to access + them during boot. Note that in this case unattended boot is not possible + because GRUB will wait for passphrase to unlock encrypted container. +@@ -1600,7 +1607,7 @@ confusing @samp{GRUB_TIMEOUT_STYLE=countdown} or + + @end table + +-For more detailed customisation of @command{grub-mkconfig}'s output, you may ++For more detailed customisation of @command{grub2-mkconfig}'s output, you may + edit the scripts in @file{/etc/grub.d} directly. + @file{/etc/grub.d/40_custom} is particularly useful for adding entire custom + menu entries; simply type the menu entries you want to add at the end of +@@ -1862,7 +1869,7 @@ images as well. + Mount this partition on/mnt/boot and disable GRUB in all OSes and manually + install self-compiled latest GRUB with: + +-@code{grub-install --boot-directory=/mnt/boot /dev/sda} ++@code{grub2-install --boot-directory=/mnt/boot /dev/sda} + + In all the OSes install GRUB tools but disable installing GRUB in bootsector, + so you'll have menu.lst and grub.cfg available for use. Also disable os-prober +@@ -1872,20 +1879,20 @@ use by setting: + + in /etc/default/grub + +-Then write a grub.cfg (/mnt/boot/grub/grub.cfg): ++Then write a grub.cfg (/mnt/boot/grub2/grub.cfg): + + @example + + menuentry "OS using grub2" @{ + insmod xfs + search --set=root --label OS1 --hint hd0,msdos8 +- configfile /boot/grub/grub.cfg ++ configfile /boot/grub2/grub.cfg + @} + + menuentry "OS using grub2-legacy" @{ + insmod ext2 + search --set=root --label OS2 --hint hd0,msdos6 +- legacy_configfile /boot/grub/menu.lst ++ legacy_configfile /boot/grub2/menu.lst + @} + + menuentry "Windows XP" @{ +@@ -1948,15 +1955,15 @@ GRUB supports embedding a configuration file directly into the core image, + so that it is loaded before entering normal mode. This is useful, for + example, when it is not straightforward to find the real configuration file, + or when you need to debug problems with loading that file. +-@command{grub-install} uses this feature when it is not using BIOS disk ++@command{grub2-install} uses this feature when it is not using BIOS disk + functions or when installing to a different disk from the one containing + @file{/boot/grub}, in which case it needs to use the @command{search} + command (@pxref{search}) to find @file{/boot/grub}. + + To embed a configuration file, use the @option{-c} option to +-@command{grub-mkimage}. The file is copied into the core image, so it may ++@command{grub2-mkimage}. The file is copied into the core image, so it may + reside anywhere on the file system, and may be removed after running +-@command{grub-mkimage}. ++@command{grub2-mkimage}. + + After the embedded configuration file (if any) is executed, GRUB will load + the @samp{normal} module (@pxref{normal}), which will then read the real +@@ -1991,13 +1998,13 @@ included in the core image: + @example + @group + search.fs_label grub root +-if [ -e /boot/grub/example/test1.cfg ]; then ++if [ -e /boot/grub2/example/test1.cfg ]; then + set prefix=($root)/boot/grub +- configfile /boot/grub/example/test1.cfg ++ configfile /boot/grub2/example/test1.cfg + else +- if [ -e /boot/grub/example/test2.cfg ]; then ++ if [ -e /boot/grub2/example/test2.cfg ]; then + set prefix=($root)/boot/grub +- configfile /boot/grub/example/test2.cfg ++ configfile /boot/grub2/example/test2.cfg + else + echo "Could not find an example configuration file!" + fi +@@ -2521,7 +2528,7 @@ grub-mknetdir --net-directory=/srv/tftp --subdir=/boot/grub -d /usr/lib/grub/i38 + @end group + @end example + +-Then follow instructions printed out by grub-mknetdir on configuring your DHCP ++Then follow instructions printed out by grub2-mknetdir on configuring your DHCP + server. + + The grub.cfg file is placed in the same directory as the path output by +@@ -2715,7 +2722,7 @@ team are: + @end table + + To take full advantage of this function, install GRUB into the MBR +-(@pxref{Installing GRUB using grub-install}). ++(@pxref{Installing GRUB using grub2-install}). + + If you have a laptop which has a similar feature and not in the above list + could you figure your address and contribute? +@@ -2776,7 +2783,7 @@ bytes. + The sole function of @file{boot.img} is to read the first sector of the core + image from a local disk and jump to it. Because of the size restriction, + @file{boot.img} cannot understand any file system structure, so +-@command{grub-install} hardcodes the location of the first sector of the ++@command{grub2-install} hardcodes the location of the first sector of the + core image into @file{boot.img} when installing GRUB. + + @item diskboot.img +@@ -2806,7 +2813,7 @@ images. + + @item core.img + This is the core image of GRUB. It is built dynamically from the kernel +-image and an arbitrary list of modules by the @command{grub-mkimage} ++image and an arbitrary list of modules by the @command{grub2-mkimage} + program. Usually, it contains enough modules to access @file{/boot/grub}, + and loads everything else (including menu handling, the ability to load + target operating systems, and so on) from the file system at run-time. The +@@ -2858,7 +2865,7 @@ GRUB 2 has no single Stage 2 image. Instead, it loads modules from + In GRUB 2, images for booting from CD-ROM drives are now constructed using + @file{cdboot.img} and @file{core.img}, making sure that the core image + contains the @samp{iso9660} module. It is usually best to use the +-@command{grub-mkrescue} program for this. ++@command{grub2-mkrescue} program for this. + + @item nbgrub + There is as yet no equivalent for @file{nbgrub} in GRUB 2; it was used by +@@ -3014,8 +3021,8 @@ There are two ways to specify files, by @dfn{absolute file name} and by + + An absolute file name resembles a Unix absolute file name, using + @samp{/} for the directory separator (not @samp{\} as in DOS). One +-example is @samp{(hd0,1)/boot/grub/grub.cfg}. This means the file +-@file{/boot/grub/grub.cfg} in the first partition of the first hard ++example is @samp{(hd0,1)/boot/grub2/grub.cfg}. This means the file ++@file{/boot/grub2/grub.cfg} in the first partition of the first hard + disk. If you omit the device name in an absolute file name, GRUB uses + GRUB's @dfn{root device} implicitly. So if you set the root device to, + say, @samp{(hd1,1)} by the command @samp{set root=(hd1,1)} (@pxref{set}), +@@ -3023,8 +3030,8 @@ then @code{/boot/kernel} is the same as @code{(hd1,1)/boot/kernel}. + + On ZFS filesystem the first path component must be + @var{volume}@samp{@@}[@var{snapshot}]. +-So @samp{/rootvol@@snap-129/boot/grub/grub.cfg} refers to file +-@samp{/boot/grub/grub.cfg} in snapshot of volume @samp{rootvol} with name ++So @samp{/rootvol@@snap-129/boot/grub2/grub.cfg} refers to file ++@samp{/boot/grub2/grub.cfg} in snapshot of volume @samp{rootvol} with name + @samp{snap-129}. Trailing @samp{@@} after volume name is mandatory even if + snapshot name is omitted. + +@@ -3427,7 +3434,7 @@ The more recent release of Minix would then be identified as + @samp{other>minix>minix-3.4.0}. + + This variable is often set by @samp{GRUB_DEFAULT} (@pxref{Simple +-configuration}), @command{grub-set-default}, or @command{grub-reboot}. ++configuration}), @command{grub2-set-default}, or @command{grub2-reboot}. + + + @node fallback +@@ -3517,7 +3524,7 @@ If this variable is set, it names the language code that the + example, French would be named as @samp{fr}, and Simplified Chinese as + @samp{zh_CN}. + +-@command{grub-mkconfig} (@pxref{Simple configuration}) will try to set a ++@command{grub2-mkconfig} (@pxref{Simple configuration}) will try to set a + reasonable default for this variable based on the system locale. + + +@@ -3525,10 +3532,10 @@ reasonable default for this variable based on the system locale. + @subsection locale_dir + + If this variable is set, it names the directory where translation files may +-be found (@pxref{gettext}), usually @file{/boot/grub/locale}. Otherwise, ++be found (@pxref{gettext}), usually @file{/boot/grub2/locale}. Otherwise, + internationalization is disabled. + +-@command{grub-mkconfig} (@pxref{Simple configuration}) will set a reasonable ++@command{grub2-mkconfig} (@pxref{Simple configuration}) will set a reasonable + default for this variable if internationalization is needed and any + translation files are available. + +@@ -3646,7 +3653,7 @@ input. The default is not to pause output. + + The location of the @samp{/boot/grub} directory as an absolute file name + (@pxref{File name syntax}). This is normally set by GRUB at startup based +-on information provided by @command{grub-install}. GRUB modules are ++on information provided by @command{grub2-install}. GRUB modules are + dynamically loaded from this directory, so it must be set correctly in order + for many parts of GRUB to work. + +@@ -3737,17 +3744,17 @@ GRUB provides an ``environment block'' which can be used to save a small + amount of state. + + The environment block is a preallocated 1024-byte file, which normally lives +-in @file{/boot/grub/grubenv} (although you should not assume this). At boot ++in @file{/boot/grub2/grubenv} (although you should not assume this). At boot + time, the @command{load_env} command (@pxref{load_env}) loads environment + variables from it, and the @command{save_env} (@pxref{save_env}) command + saves environment variables to it. From a running system, the +-@command{grub-editenv} utility can be used to edit the environment block. ++@command{grub2-editenv} utility can be used to edit the environment block. + + For safety reasons, this storage is only available when installed on a plain + disk (no LVM or RAID), using a non-checksumming filesystem (no ZFS), and + using BIOS or EFI functions (no ATA, USB or IEEE1275). + +-@command{grub-mkconfig} uses this facility to implement ++@command{grub2-mkconfig} uses this facility to implement + @samp{GRUB_SAVEDEFAULT} (@pxref{Simple configuration}). + + +@@ -4476,7 +4483,7 @@ Translate @var{string} into the current language. + + The current language code is stored in the @samp{lang} variable in GRUB's + environment (@pxref{lang}). Translation files in MO format are read from +-@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub/locale}. ++@samp{locale_dir} (@pxref{locale_dir}), usually @file{/boot/grub2/locale}. + @end deffn + + +@@ -4871,7 +4878,7 @@ Define a user named @var{user} with password @var{clear-password}. + + @deffn Command password_pbkdf2 user hashed-password + Define a user named @var{user} with password hash @var{hashed-password}. +-Use @command{grub-mkpasswd-pbkdf2} (@pxref{Invoking grub-mkpasswd-pbkdf2}) ++Use @command{grub2-mkpasswd-pbkdf2} (@pxref{Invoking grub2-mkpasswd-pbkdf2}) + to generate password hashes. @xref{Security}. + @end deffn + +@@ -5814,8 +5821,8 @@ The @samp{password} (@pxref{password}) and @samp{password_pbkdf2} + which has an associated password. @samp{password} sets the password in + plain text, requiring @file{grub.cfg} to be secure; @samp{password_pbkdf2} + sets the password hashed using the Password-Based Key Derivation Function +-(RFC 2898), requiring the use of @command{grub-mkpasswd-pbkdf2} +-(@pxref{Invoking grub-mkpasswd-pbkdf2}) to generate password hashes. ++(RFC 2898), requiring the use of @command{grub2-mkpasswd-pbkdf2} ++(@pxref{Invoking grub2-mkpasswd-pbkdf2}) to generate password hashes. + + In order to enable authentication support, the @samp{superusers} environment + variable must be set to a list of usernames, separated by any of spaces, +@@ -5860,7 +5867,7 @@ menuentry "May be run by user1 or a superuser" --users user1 @{ + @end group + @end example + +-The @command{grub-mkconfig} program does not yet have built-in support for ++The @command{grub2-mkconfig} program does not yet have built-in support for + generating configuration files with authentication. You can use + @file{/etc/grub.d/40_custom} to add simple superuser authentication, by + adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} +@@ -5887,7 +5894,17 @@ may halt or otherwise impact the boot process. + + An initial trusted public key can be embedded within the GRUB @file{core.img} + using the @code{--pubkey} option to @command{grub-install} +-(@pxref{Invoking grub-install}). ++(@pxref{Invoking grub2-install}). ++ ++@comment Unfortunately --pubkey is not yet supported by grub2-install, ++@comment but we should not bring up internal detail grub2-mkimage here ++@comment in the user guide (as opposed to developer's manual). ++ ++@comment An initial trusted public key can be embedded within the GRUB ++@comment @file{core.img} using the @code{--pubkey} option to ++@comment @command{grub2-mkimage} (@pxref{Invoking grub2-install}). Presently it ++@comment is necessary to write a custom wrapper around @command{grub2-mkimage} ++@comment using the @code{--grub-mkimage} flag to @command{grub2-install}. + + GRUB uses GPG-style detached signatures (meaning that a file + @file{foo.sig} will be produced when file @file{foo} is signed), and +@@ -5907,8 +5924,8 @@ gpg --detach-sign /path/to/file + For successful validation of all of GRUB's subcomponents and the + loaded OS kernel, they must all be signed. One way to accomplish this + is the following (after having already produced the desired +-@file{grub.cfg} file, e.g., by running @command{grub-mkconfig} +-(@pxref{Invoking grub-mkconfig}): ++@file{grub.cfg} file, e.g., by running @command{grub2-mkconfig} ++(@pxref{Invoking grub2-mkconfig}): + + @example + @group +@@ -5930,7 +5947,7 @@ See also: @ref{check_signatures}, @ref{verify_detached}, @ref{trust}, + Note that internally signature enforcement is controlled by setting + the environment variable @code{check_signatures} equal to + @code{enforce}. Passing one or more @code{--pubkey} options to +-@command{grub-mkimage} implicitly defines @code{check_signatures} ++@command{grub2-mkimage} implicitly defines @code{check_signatures} + equal to @code{enforce} in @file{core.img} prior to processing any + configuration files. + +@@ -6388,10 +6405,10 @@ Required files are: + + GRUB's normal start-up procedure involves setting the @samp{prefix} + environment variable to a value set in the core image by +-@command{grub-install}, setting the @samp{root} variable to match, loading ++@command{grub2-install}, setting the @samp{root} variable to match, loading + the @samp{normal} module from the prefix, and running the @samp{normal} + command (@pxref{normal}). This command is responsible for reading +-@file{/boot/grub/grub.cfg}, running the menu, and doing all the useful ++@file{/boot/grub2/grub.cfg}, running the menu, and doing all the useful + things GRUB is supposed to do. + + If, instead, you only get a rescue shell, this usually means that GRUB +@@ -6417,8 +6434,8 @@ normal + + However, any problem that leaves you in the rescue shell probably means that + GRUB was not correctly installed. It may be more useful to try to reinstall +-it properly using @kbd{grub-install @var{device}} (@pxref{Invoking +-grub-install}). When doing this, there are a few things to remember: ++it properly using @kbd{grub2-install @var{device}} (@pxref{Invoking ++grub2-install}). When doing this, there are a few things to remember: + + @itemize @bullet{} + @item +@@ -6430,7 +6447,7 @@ is usually better to use UUIDs or file system labels and avoid depending on + drive ordering entirely. + + @item +-At least on BIOS systems, if you tell @command{grub-install} to install GRUB ++At least on BIOS systems, if you tell @command{grub2-install} to install GRUB + to a partition but GRUB has already been installed in the master boot + record, then the GRUB installation in the partition will be ignored. + +@@ -6461,21 +6478,21 @@ entry which claims partition start at block 0. This change will not hamper + bootability on other machines. + + +-@node Invoking grub-install +-@chapter Invoking grub-install ++@node Invoking grub2-install ++@chapter Invoking grub2-install + +-The program @command{grub-install} generates a GRUB core image using +-@command{grub-mkimage} and installs it on your system. You must specify the ++The program @command{grub2-install} generates a GRUB core image using ++@command{grub2-mkimage} and installs it on your system. You must specify the + device name on which you want to install GRUB, like this: + + @example +-grub-install @var{install_device} ++grub2-install @var{install_device} + @end example + + The device name @var{install_device} is an OS device name or a GRUB + device name. + +-@command{grub-install} accepts the following options: ++@command{grub2-install} accepts the following options: + + @table @option + @item --help +@@ -6491,13 +6508,13 @@ separate partition or a removable disk. + If this option is not specified then it defaults to @file{/boot}, so + + @example +-@kbd{grub-install /dev/sda} ++@kbd{grub2-install /dev/sda} + @end example + + is equivalent to + + @example +-@kbd{grub-install --boot-directory=/boot/ /dev/sda} ++@kbd{grub2-install --boot-directory=/boot/ /dev/sda} + @end example + + Here is an example in which you have a separate @dfn{boot} partition which is +@@ -6505,16 +6522,16 @@ mounted on + @file{/mnt/boot}: + + @example +-@kbd{grub-install --boot-directory=/mnt/boot /dev/sdb} ++@kbd{grub2-install --boot-directory=/mnt/boot /dev/sdb} + @end example + + @item --recheck +-Recheck the device map, even if @file{/boot/grub/device.map} already ++Recheck the device map, even if @file{/boot/grub2/device.map} already + exists. You should use this option whenever you add/remove a disk + into/from your computer. + + @item --no-rs-codes +-By default on x86 BIOS systems, @command{grub-install} will use some ++By default on x86 BIOS systems, @command{grub2-install} will use some + extra space in the bootloader embedding area for Reed-Solomon + error-correcting codes. This enables GRUB to still boot successfully + if some blocks are corrupted. The exact amount of protection offered +@@ -6527,17 +6544,17 @@ installation}) where GRUB does not reside in any unpartitioned space + outside of the MBR. Disable the Reed-Solomon codes with this option. + @end table + +-@node Invoking grub-mkconfig +-@chapter Invoking grub-mkconfig ++@node Invoking grub2-mkconfig ++@chapter Invoking grub2-mkconfig + +-The program @command{grub-mkconfig} generates a configuration file for GRUB ++The program @command{grub2-mkconfig} generates a configuration file for GRUB + (@pxref{Simple configuration}). + + @example +-grub-mkconfig -o /boot/grub/grub.cfg ++grub-mkconfig -o /boot/grub2/grub.cfg + @end example + +-@command{grub-mkconfig} accepts the following options: ++@command{grub2-mkconfig} accepts the following options: + + @table @option + @item --help +@@ -6553,17 +6570,17 @@ it to standard output. + @end table + + +-@node Invoking grub-mkpasswd-pbkdf2 +-@chapter Invoking grub-mkpasswd-pbkdf2 ++@node Invoking grub2-mkpasswd-pbkdf2 ++@chapter Invoking grub2-mkpasswd-pbkdf2 + +-The program @command{grub-mkpasswd-pbkdf2} generates password hashes for ++The program @command{grub2-mkpasswd-pbkdf2} generates password hashes for + GRUB (@pxref{Security}). + + @example + grub-mkpasswd-pbkdf2 + @end example + +-@command{grub-mkpasswd-pbkdf2} accepts the following options: ++@command{grub2-mkpasswd-pbkdf2} accepts the following options: + + @table @option + @item -c @var{number} +@@ -6581,23 +6598,23 @@ Length of the salt. Defaults to 64. + @end table + + +-@node Invoking grub-mkrelpath +-@chapter Invoking grub-mkrelpath ++@node Invoking grub2-mkrelpath ++@chapter Invoking grub2-mkrelpath + +-The program @command{grub-mkrelpath} makes a file system path relative to ++The program @command{grub2-mkrelpath} makes a file system path relative to + the root of its containing file system. For instance, if @file{/usr} is a + mount point, then: + + @example +-$ @kbd{grub-mkrelpath /usr/share/grub/unicode.pf2} ++$ @kbd{grub2-mkrelpath /usr/share/grub/unicode.pf2} + @samp{/share/grub/unicode.pf2} + @end example + + This is mainly used internally by other GRUB utilities such as +-@command{grub-mkconfig} (@pxref{Invoking grub-mkconfig}), but may ++@command{grub2-mkconfig} (@pxref{Invoking grub2-mkconfig}), but may + occasionally also be useful for debugging. + +-@command{grub-mkrelpath} accepts the following options: ++@command{grub2-mkrelpath} accepts the following options: + + @table @option + @item --help +@@ -6608,17 +6625,17 @@ Print the version number of GRUB and exit. + @end table + + +-@node Invoking grub-mkrescue +-@chapter Invoking grub-mkrescue ++@node Invoking grub2-mkrescue ++@chapter Invoking grub2-mkrescue + +-The program @command{grub-mkrescue} generates a bootable GRUB rescue image ++The program @command{grub2-mkrescue} generates a bootable GRUB rescue image + (@pxref{Making a GRUB bootable CD-ROM}). + + @example + grub-mkrescue -o grub.iso + @end example + +-All arguments not explicitly listed as @command{grub-mkrescue} options are ++All arguments not explicitly listed as @command{grub2-mkrescue} options are + passed on directly to @command{xorriso} in @command{mkisofs} emulation mode. + Options passed to @command{xorriso} will normally be interpreted as + @command{mkisofs} options; if the option @samp{--} is used, then anything +@@ -6633,7 +6650,7 @@ mkdir -p disk/boot/grub + grub-mkrescue -o grub.iso disk + @end example + +-@command{grub-mkrescue} accepts the following options: ++@command{grub2-mkrescue} accepts the following options: + + @table @option + @item --help +@@ -6661,15 +6678,15 @@ Use @var{file} as the @command{xorriso} program, rather than the built-in + default. + + @item --grub-mkimage=@var{file} +-Use @var{file} as the @command{grub-mkimage} program, rather than the ++Use @var{file} as the @command{grub2-mkimage} program, rather than the + built-in default. + @end table + + +-@node Invoking grub-mount +-@chapter Invoking grub-mount ++@node Invoking grub2-mount ++@chapter Invoking grub2-mount + +-The program @command{grub-mount} performs a read-only mount of any file ++The program @command{grub2-mount} performs a read-only mount of any file + system or file system image that GRUB understands, using GRUB's file system + drivers via FUSE. (It is only available if FUSE development files were + present when GRUB was built.) This has a number of uses: +@@ -6701,13 +6718,13 @@ even if nobody has yet written a FUSE module specifically for that file + system type. + @end itemize + +-Using @command{grub-mount} is normally as simple as: ++Using @command{grub2-mount} is normally as simple as: + + @example + grub-mount /dev/sda1 /mnt + @end example + +-@command{grub-mount} must be given one or more images and a mount point as ++@command{grub2-mount} must be given one or more images and a mount point as + non-option arguments (if it is given more than one image, it will treat them + as a RAID set), and also accepts the following options: + +@@ -6729,13 +6746,13 @@ Show debugging output for conditions matching @var{string}. + @item -K prompt|@var{file} + @itemx --zfs-key=prompt|@var{file} + Load a ZFS encryption key. If you use @samp{prompt} as the argument, +-@command{grub-mount} will read a passphrase from the terminal; otherwise, it ++@command{grub2-mount} will read a passphrase from the terminal; otherwise, it + will read key material from the specified file. + + @item -r @var{device} + @itemx --root=@var{device} + Set the GRUB root device to @var{device}. You do not normally need to set +-this; @command{grub-mount} will automatically set the root device to the ++this; @command{grub2-mount} will automatically set the root device to the + root of the supplied file system. + + If @var{device} is just a number, then it will be treated as a partition +@@ -6753,10 +6770,10 @@ Print verbose messages. + @end table + + +-@node Invoking grub-probe +-@chapter Invoking grub-probe ++@node Invoking grub2-probe ++@chapter Invoking grub2-probe + +-The program @command{grub-probe} probes device information for a given path ++The program @command{grub2-probe} probes device information for a given path + or device. + + @example +@@ -6764,7 +6781,7 @@ grub-probe --target=fs /boot/grub + grub-probe --target=drive --device /dev/sda1 + @end example + +-@command{grub-probe} must be given a path or device as a non-option ++@command{grub2-probe} must be given a path or device as a non-option + argument, and also accepts the following options: + + @table @option +@@ -6777,16 +6794,16 @@ Print the version number of GRUB and exit. + @item -d + @itemx --device + If this option is given, then the non-option argument is a system device +-name (such as @samp{/dev/sda1}), and @command{grub-probe} will print ++name (such as @samp{/dev/sda1}), and @command{grub2-probe} will print + information about that device. If it is not given, then the non-option + argument is a filesystem path (such as @samp{/boot/grub}), and +-@command{grub-probe} will print information about the device containing that ++@command{grub2-probe} will print information about the device containing that + part of the filesystem. + + @item -m @var{file} + @itemx --device-map=@var{file} + Use @var{file} as the device map (@pxref{Device map}) rather than the +-default, usually @samp{/boot/grub/device.map}. ++default, usually @samp{/boot/grub2/device.map}. + + @item -t @var{target} + @itemx --target=@var{target} +@@ -6839,19 +6856,19 @@ Print verbose messages. + @end table + + +-@node Invoking grub-script-check +-@chapter Invoking grub-script-check ++@node Invoking grub2-script-check ++@chapter Invoking grub2-script-check + +-The program @command{grub-script-check} takes a GRUB script file ++The program @command{grub2-script-check} takes a GRUB script file + (@pxref{Shell-like scripting}) and checks it for syntax errors, similar to + commands such as @command{sh -n}. It may take a @var{path} as a non-option + argument; if none is supplied, it will read from standard input. + + @example +-grub-script-check /boot/grub/grub.cfg ++grub-script-check /boot/grub2/grub.cfg + @end example + +-@command{grub-script-check} accepts the following options: ++@command{grub2-script-check} accepts the following options: + + @table @option + @item --help diff --git a/SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch b/SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch new file mode 100644 index 0000000..8d3139d --- /dev/null +++ b/SOURCES/0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch @@ -0,0 +1,124 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 24 May 2017 12:42:32 -0400 +Subject: [PATCH] macos: just build chainloader entries, don't try any xnu xnu. + +Since our bugs tell us that the xnu boot entries really just don't work +most of the time, and they create piles of extra boot entries, because +they can't quite figure out 32-vs-64 and other stuff like that. + +It's rediculous, and we should just boot their bootloader through the +chainloader instead. + +So this patch does that. + +Resolves: rhbz#893179 + +Signed-off-by: Peter Jones +--- + util/grub.d/30_os-prober.in | 78 +++++++++++---------------------------------- + 1 file changed, 18 insertions(+), 60 deletions(-) + +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 1b91c102f3..4b27bd2015 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -42,68 +42,25 @@ if [ -z "${OSPROBED}" ] ; then + fi + + osx_entry() { +- if [ x$2 = x32 ]; then +- # TRANSLATORS: it refers to kernel architecture (32-bit) +- bitstr="$(gettext "(32-bit)")" +- else +- # TRANSLATORS: it refers to kernel architecture (64-bit) +- bitstr="$(gettext "(64-bit)")" +- fi + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" +- cat << EOF +-menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { ++ hints="" ++ for hint in `"${grub_probe}" --device ${device} --target=efi_hints 2> /dev/null` ; do ++ hints="${hints} --hint=${hint}" ++ done ++ cat << EOF ++menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' { + EOF + save_default_entry | grub_add_tab + prepare_grub_to_access_device ${DEVICE} | grub_add_tab + cat << EOF ++ set gfxpayload=keep + load_video +- set do_resume=0 +- if [ /var/vm/sleepimage -nt10 / ]; then +- if xnu_resume /var/vm/sleepimage; then +- set do_resume=1 +- fi +- fi +- if [ \$do_resume = 0 ]; then +- xnu_uuid ${OSXUUID} uuid +- if [ -f /Extra/DSDT.aml ]; then +- acpi -e /Extra/DSDT.aml +- fi +- if [ /kernelcache -nt /System/Library/Extensions ]; then +- $1 /kernelcache boot-uuid=\${uuid} rd=*uuid +- elif [ -f /System/Library/Kernels/kernel ]; then +- $1 /System/Library/Kernels/kernel boot-uuid=\${uuid} rd=*uuid +- xnu_kextdir /System/Library/Extensions +- else +- $1 /mach_kernel boot-uuid=\${uuid} rd=*uuid +- if [ /System/Library/Extensions.mkext -nt /System/Library/Extensions ]; then +- xnu_mkext /System/Library/Extensions.mkext +- else +- xnu_kextdir /System/Library/Extensions +- fi +- fi +- if [ -f /Extra/Extensions.mkext ]; then +- xnu_mkext /Extra/Extensions.mkext +- fi +- if [ -d /Extra/Extensions ]; then +- xnu_kextdir /Extra/Extensions +- fi +- if [ -f /Extra/devprop.bin ]; then +- xnu_devprop_load /Extra/devprop.bin +- fi +- if [ -f /Extra/splash.jpg ]; then +- insmod jpeg +- xnu_splash /Extra/splash.jpg +- fi +- if [ -f /Extra/splash.png ]; then +- insmod png +- xnu_splash /Extra/splash.png +- fi +- if [ -f /Extra/splash.tga ]; then +- insmod tga +- xnu_splash /Extra/splash.tga +- fi +- fi ++ insmod part_gpt ++ insmod hfsplus ++ search --no-floppy --fs-uuid --set=root ${hints} $(grub_get_device_id "${DEVICE}") ++ chainloader (\$root)/System/Library/CoreServices/boot.efi ++ boot + } + EOF + } +@@ -292,11 +249,12 @@ EOF + echo "$title_correction_code" + ;; + macosx) +- if [ "${UUID}" ]; then +- OSXUUID="${UUID}" +- osx_entry xnu_kernel 32 +- osx_entry xnu_kernel64 64 +- fi ++ for subdevice in ${DEVICE%[[:digit:]]*}* ; do ++ parttype="`"${grub_probe}" --device ${device} --target=gpt_parttype "${subdevice}" 2> /dev/null`" ++ if [[ "$parttype" = "426f6f74-0000-11aa-aa11-00306543ecac" ]]; then ++ DEVICE="${subdevice}" osx_entry ++ fi ++ done + ;; + hurd) + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" diff --git a/SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch b/SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch new file mode 100644 index 0000000..57d2391 --- /dev/null +++ b/SOURCES/0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch @@ -0,0 +1,703 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeff Mahoney +Date: Tue, 9 Jul 2019 13:39:45 +0200 +Subject: [PATCH] grub2/btrfs: Add ability to boot from subvolumes + +This patch adds the ability to specify a different root on a btrfs +filesystem too boot from other than the default one. + +btrfs-list-snapshots will list the subvolumes available on the +filesystem. + +set btrfs_subvol= and set btrfs_subvolid= will specify +which subvolume to use and any pathnames provided with either of those +variables set will start using that root. If the subvolume or subvolume id +doesn't exist, then an error case will result. + +It is possible to boot into a separate GRUB instance by exporting the +variable and loading the config file from the subvolume. + +Signed-off-by: Jeff Mahoney +--- + grub-core/fs/btrfs.c | 552 +++++++++++++++++++++++++++++++++++++++++++++++++-- + include/grub/btrfs.h | 1 + + 2 files changed, 533 insertions(+), 20 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 63203034df..f1fff7385b 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -38,6 +38,9 @@ + #include + #include + #include ++#include ++#include ++#include + #include + #include + #include +@@ -79,9 +82,11 @@ struct grub_btrfs_superblock + grub_uint64_t generation; + grub_uint64_t root_tree; + grub_uint64_t chunk_tree; +- grub_uint8_t dummy2[0x20]; ++ grub_uint8_t dummy2[0x18]; ++ grub_uint64_t bytes_used; + grub_uint64_t root_dir_objectid; +- grub_uint8_t dummy3[0x41]; ++ grub_uint64_t num_devices; ++ grub_uint8_t dummy3[0x39]; + struct grub_btrfs_device this_device; + char label[0x100]; + grub_uint8_t dummy4[0x100]; +@@ -121,6 +126,7 @@ struct grub_btrfs_data + grub_uint64_t exttree; + grub_size_t extsize; + struct grub_btrfs_extent_data *extent; ++ grub_uint64_t fs_tree; + }; + + struct grub_btrfs_chunk_item +@@ -191,6 +197,14 @@ struct grub_btrfs_leaf_descriptor + } *data; + }; + ++struct grub_btrfs_root_ref ++{ ++ grub_uint64_t dirid; ++ grub_uint64_t sequence; ++ grub_uint16_t name_len; ++ const char name[0]; ++} __attribute__ ((packed)); ++ + struct grub_btrfs_time + { + grub_int64_t sec; +@@ -236,6 +250,14 @@ struct grub_btrfs_extent_data + + #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 + ++#define GRUB_BTRFS_ROOT_TREE_OBJECTID 1ULL ++#define GRUB_BTRFS_FS_TREE_OBJECTID 5ULL ++#define GRUB_BTRFS_ROOT_REF_KEY 156 ++#define GRUB_BTRFS_ROOT_ITEM_KEY 132 ++ ++static grub_uint64_t btrfs_default_subvolid = 0; ++static char *btrfs_default_subvol = NULL; ++ + static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, + 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2 + }; +@@ -1173,6 +1195,62 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return GRUB_ERR_NONE; + } + ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root); ++ ++static grub_err_t ++lookup_root_by_id(struct grub_btrfs_data *data, grub_uint64_t id) ++{ ++ grub_err_t err; ++ grub_uint64_t tree; ++ ++ err = get_fs_root(data, data->sblock.root_tree, id, -1, &tree); ++ if (!err) ++ data->fs_tree = tree; ++ return err; ++} ++ ++static grub_err_t ++find_path (struct grub_btrfs_data *data, ++ const char *path, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++static grub_err_t ++lookup_root_by_name(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return lookup_root_by_name(data, btrfs_default_subvol); ++ ++ if (btrfs_default_subvolid) ++ return lookup_root_by_id(data, btrfs_default_subvolid); ++ ++ data->fs_tree = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++ + static struct grub_btrfs_data * + grub_btrfs_mount (grub_device_t dev) + { +@@ -1208,6 +1286,13 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } ++ + return data; + } + +@@ -1673,6 +1758,91 @@ get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, + return GRUB_ERR_NONE; + } + ++static grub_err_t ++find_pathname(struct grub_btrfs_data *data, grub_uint64_t objectid, ++ grub_uint64_t fs_root, const char *name, char **pathname) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ITEM_TYPE_INODE_REF, ++ .offset = 0, ++ }; ++ struct grub_btrfs_key key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ char *p = grub_strdup (name); ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ grub_size_t alloc = grub_strlen(name) + 1; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ { ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ "Can't find inode ref for {%"PRIuGRUB_UINT64_T ++ ", %u, %"PRIuGRUB_UINT64_T"} %"PRIuGRUB_UINT64_T ++ "/%"PRIuGRUB_SIZE"\n", ++ key_out.object_id, key_out.type, ++ key_out.offset, elemaddr, elemsize); ++ } ++ ++ ++ while (key_out.type == GRUB_BTRFS_ITEM_TYPE_INODE_REF && ++ key_out.object_id != key_out.offset) { ++ struct grub_btrfs_inode_ref *inode_ref; ++ char *new; ++ ++ inode_ref = grub_malloc(elemsize + 1); ++ if (!inode_ref) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for inode_ref (%"PRIuGRUB_SIZE")\n", elemsize); ++ ++ err = grub_btrfs_read_logical(data, elemaddr, inode_ref, elemsize, 0); ++ if (err) ++ return grub_error(err, "read_logical caught %d\n", err); ++ ++ alloc += grub_le_to_cpu16 (inode_ref->n) + 2; ++ new = grub_malloc(alloc); ++ if (!new) ++ return grub_error(GRUB_ERR_OUT_OF_MEMORY, ++ "couldn't allocate memory for name (%"PRIuGRUB_SIZE")\n", alloc); ++ ++ grub_memcpy(new, inode_ref->name, grub_le_to_cpu16 (inode_ref->n)); ++ if (p) ++ { ++ new[grub_le_to_cpu16 (inode_ref->n)] = '/'; ++ grub_strcpy (new + grub_le_to_cpu16 (inode_ref->n) + 1, p); ++ grub_free(p); ++ } ++ else ++ new[grub_le_to_cpu16 (inode_ref->n)] = 0; ++ grub_free(inode_ref); ++ ++ p = new; ++ ++ key.object_id = key_out.offset; ++ ++ err = lower_bound(data, &key, &key_out, fs_root, &elemaddr, ++ &elemsize, &desc, 0); ++ if (err) ++ return grub_error(err, "lower_bound caught %d\n", err); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_REF) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ } ++ ++ *pathname = p; ++ return 0; ++} ++ + static grub_err_t + find_path (struct grub_btrfs_data *data, + const char *path, struct grub_btrfs_key *key, +@@ -1691,14 +1861,26 @@ find_path (struct grub_btrfs_data *data, + char *origpath = NULL; + unsigned symlinks_max = 32; + +- err = get_root (data, key, tree, type); +- if (err) +- return err; +- + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } ++ + while (1) + { + while (path[0] == '/') +@@ -1871,9 +2053,21 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- err = get_root (data, key, tree, type); +- if (err) +- return err; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ err = get_root (data, key, tree, type); ++ if (err) ++ return err; ++ } + } + continue; + } +@@ -2114,18 +2308,10 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) + data->tree, file->offset, buf, len); + } + +-static grub_err_t +-grub_btrfs_uuid (grub_device_t device, char **uuid) ++static char * ++btrfs_unparse_uuid(struct grub_btrfs_data *data) + { +- struct grub_btrfs_data *data; +- +- *uuid = NULL; +- +- data = grub_btrfs_mount (device); +- if (!data) +- return grub_errno; +- +- *uuid = grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", ++ return grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + grub_be_to_cpu16 (data->sblock.uuid[0]), + grub_be_to_cpu16 (data->sblock.uuid[1]), + grub_be_to_cpu16 (data->sblock.uuid[2]), +@@ -2134,6 +2320,20 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) + grub_be_to_cpu16 (data->sblock.uuid[5]), + grub_be_to_cpu16 (data->sblock.uuid[6]), + grub_be_to_cpu16 (data->sblock.uuid[7])); ++} ++ ++static grub_err_t ++grub_btrfs_uuid (grub_device_t device, char **uuid) ++{ ++ struct grub_btrfs_data *data; ++ ++ *uuid = NULL; ++ ++ data = grub_btrfs_mount (device); ++ if (!data) ++ return grub_errno; ++ ++ *uuid = btrfs_unparse_uuid(data); + + grub_btrfs_unmount (data); + +@@ -2190,6 +2390,242 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + } + #endif + ++static grub_err_t ++grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ grub_device_t dev; ++ char *devname; ++ struct grub_btrfs_data *data; ++ char *uuid; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ grub_device_close(dev); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to open fs"); ++ } ++ ++ if (data->sblock.label) ++ grub_printf("Label: '%s' ", data->sblock.label); ++ else ++ grub_printf("Label: none "); ++ ++ uuid = btrfs_unparse_uuid(data); ++ ++ grub_printf(" uuid: %s\n\tTotal devices %" PRIuGRUB_UINT64_T ++ " FS bytes used %" PRIuGRUB_UINT64_T "\n", ++ uuid, grub_cpu_to_le64(data->sblock.num_devices), ++ grub_cpu_to_le64(data->sblock.bytes_used)); ++ ++ grub_btrfs_unmount (data); ++ ++ return 0; ++} ++ ++static grub_err_t ++get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, ++ grub_uint64_t objectid, grub_uint64_t offset, ++ grub_uint64_t *fs_root) ++{ ++ grub_err_t err; ++ struct grub_btrfs_key key_in = { ++ .object_id = objectid, ++ .type = GRUB_BTRFS_ROOT_ITEM_KEY, ++ .offset = offset, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_root_item ri; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM || elemaddr == 0) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, ++ N_("can't find fs root for subvol %"PRIuGRUB_UINT64_T"\n"), ++ key_in.object_id); ++ ++ err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri), 0); ++ if (err) ++ return err; ++ ++ *fs_root = ri.tree; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static const struct grub_arg_option options[] = { ++ {"output", 'o', 0, N_("Output to a variable instead of the console."), ++ N_("VARNAME"), ARG_TYPE_STRING}, ++ {"path-only", 'p', 0, N_("Show only the path of the subvolume."), 0, 0}, ++ {"id-only", 'i', 0, N_("Show only the id of the subvolume."), 0, 0}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++static grub_err_t ++grub_cmd_btrfs_list_subvols (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ struct grub_btrfs_data *data; ++ grub_device_t dev; ++ char *devname; ++ grub_uint64_t tree; ++ struct grub_btrfs_key key_in = { ++ .object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ .type = GRUB_BTRFS_ROOT_REF_KEY, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_disk_addr_t elemaddr; ++ grub_uint64_t fs_root = 0; ++ grub_size_t elemsize; ++ grub_size_t allocated = 0; ++ int r = 0; ++ grub_err_t err; ++ char *buf = NULL; ++ int print = 1; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ char *varname = NULL; ++ char *output = NULL; ++ ++ if (ctxt->state[0].set) { ++ varname = ctxt->state[0].arg; ++ print = 0; ++ } ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "could not open device"); ++ ++ tree = data->sblock.root_tree; ++ err = get_fs_root(data, tree, grub_cpu_to_le64_compile_time (GRUB_BTRFS_FS_TREE_OBJECTID), ++ 0, &fs_root); ++ if (err) ++ goto out; ++ ++ err = lower_bound(data, &key_in, &key_out, tree, ++ &elemaddr, &elemsize, &desc, 0); ++ ++ if (err) ++ { ++ grub_btrfs_unmount(data); ++ return err; ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF || elemaddr == 0) ++ { ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) { ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root refs")); ++ goto out; ++ } ++ ++ do ++ { ++ struct grub_btrfs_root_ref *ref; ++ char *p = NULL; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_REF) ++ { ++ r = 0; ++ break; ++ } ++ ++ if (elemsize > allocated) ++ { ++ grub_free(buf); ++ allocated = 2 * elemsize; ++ buf = grub_malloc(allocated + 1); ++ if (!buf) ++ { ++ r = -grub_errno; ++ break; ++ } ++ } ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ r = -err; ++ break; ++ } ++ buf[elemsize] = 0; ++ ++ find_pathname(data, ref->dirid, fs_root, ref->name, &p); ++ ++ if (print) ++ { ++ if (num_only) ++ grub_printf("ID %"PRIuGRUB_UINT64_T"\n", key_out.offset); ++ else if (path_only) ++ grub_printf("%s\n", p); ++ else ++ grub_printf("ID %"PRIuGRUB_UINT64_T" path %s\n", key_out.offset, p); ++ } else { ++ char *old = output; ++ if (num_only) ++ output = grub_xasprintf("%s%"PRIuGRUB_UINT64_T"\n", ++ old ?: "", key_out.offset); ++ else if (path_only) ++ output = grub_xasprintf("%s%s\n", old ?: "", p); ++ else ++ output = grub_xasprintf("%sID %"PRIuGRUB_UINT64_T" path %s\n", ++ old ?: "", key_out.offset, p); ++ ++ if (old) ++ grub_free(old); ++ } ++ ++ r = next(data, &desc, &elemaddr, &elemsize, &key_out); ++ } while(r > 0); ++ ++ if (output) ++ grub_env_set(varname, output); ++ ++out: ++ free_iterator(&desc); ++ grub_btrfs_unmount(data); ++ ++ grub_device_close (dev); ++ ++ return 0; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2205,12 +2641,88 @@ static struct grub_fs grub_btrfs_fs = { + #endif + }; + ++static grub_command_t cmd_info; ++static grub_extcmd_t cmd_list_subvols; ++ ++static char * ++subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ unsigned long long result = 0; ++ ++ grub_errno = GRUB_ERR_NONE; ++ if (*val) ++ { ++ result = grub_strtoull(val, NULL, 10); ++ if (grub_errno) ++ return NULL; ++ } ++ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = NULL; ++ btrfs_default_subvolid = result; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvolid_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return grub_xasprintf("subvol:%s", btrfs_default_subvol); ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("%"PRIuGRUB_UINT64_T, btrfs_default_subvolid); ++ else ++ return ""; ++} ++ ++static char * ++subvol_set_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (btrfs_default_subvol); ++ btrfs_default_subvol = grub_strdup (val); ++ btrfs_default_subvolid = 0; ++ return grub_strdup(val); ++} ++ ++static const char * ++subvol_get_env (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (btrfs_default_subvol) ++ return btrfs_default_subvol; ++ else if (btrfs_default_subvolid) ++ return grub_xasprintf("subvolid:%" PRIuGRUB_UINT64_T, ++ btrfs_default_subvolid); ++ else ++ return ""; ++} ++ + GRUB_MOD_INIT (btrfs) + { + grub_fs_register (&grub_btrfs_fs); ++ cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, ++ "DEVICE", ++ "Print BtrFS info about DEVICE."); ++ cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", ++ grub_cmd_btrfs_list_subvols, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print list of BtrFS subvolumes on " ++ "DEVICE.", options); ++ grub_register_variable_hook ("btrfs_subvol", subvol_get_env, ++ subvol_set_env); ++ grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, ++ subvolid_set_env); + } + + GRUB_MOD_FINI (btrfs) + { ++ grub_register_variable_hook ("btrfs_subvol", NULL, NULL); ++ grub_register_variable_hook ("btrfs_subvolid", NULL, NULL); ++ grub_unregister_command (cmd_info); ++ grub_unregister_extcmd (cmd_list_subvols); + grub_fs_unregister (&grub_btrfs_fs); + } ++ ++// vim: si et sw=2: +diff --git a/include/grub/btrfs.h b/include/grub/btrfs.h +index 9d93fb6c18..234ad97677 100644 +--- a/include/grub/btrfs.h ++++ b/include/grub/btrfs.h +@@ -29,6 +29,7 @@ enum + GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM = 0x84, + GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF = 0x90, + GRUB_BTRFS_ITEM_TYPE_DEVICE = 0xd8, ++ GRUB_BTRFS_ITEM_TYPE_ROOT_REF = 0x9c, + GRUB_BTRFS_ITEM_TYPE_CHUNK = 0xe4 + }; + diff --git a/SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch b/SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch new file mode 100644 index 0000000..719866e --- /dev/null +++ b/SOURCES/0042-export-btrfs_subvol-and-btrfs_subvolid.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 18 Dec 2013 09:57:04 +0000 +Subject: [PATCH] export btrfs_subvol and btrfs_subvolid + +We should export btrfs_subvol and btrfs_subvolid to have both visible +to subsidiary configuration files loaded using configfile. + +Signed-off-by: Michael Chang +--- + grub-core/fs/btrfs.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index f1fff7385b..ad1b56b716 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2714,6 +2714,8 @@ GRUB_MOD_INIT (btrfs) + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, + subvolid_set_env); ++ grub_env_export ("btrfs_subvol"); ++ grub_env_export ("btrfs_subvolid"); + } + + GRUB_MOD_FINI (btrfs) diff --git a/SOURCES/0043-grub2-btrfs-03-follow_default.patch b/SOURCES/0043-grub2-btrfs-03-follow_default.patch new file mode 100644 index 0000000..621f029 --- /dev/null +++ b/SOURCES/0043-grub2-btrfs-03-follow_default.patch @@ -0,0 +1,198 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 21 Aug 2014 03:39:11 +0000 +Subject: [PATCH] grub2-btrfs-03-follow_default + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 107 ++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 76 insertions(+), 31 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index ad1b56b716..113c1f746c 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1256,6 +1256,7 @@ grub_btrfs_mount (grub_device_t dev) + { + struct grub_btrfs_data *data; + grub_err_t err; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + + if (!dev->disk) + { +@@ -1286,11 +1287,14 @@ grub_btrfs_mount (grub_device_t dev) + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; + +- err = btrfs_handle_subvol (data); +- if (err) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- grub_free (data); +- return NULL; ++ err = btrfs_handle_subvol (data); ++ if (err) ++ { ++ grub_free (data); ++ return NULL; ++ } + } + + return data; +@@ -1855,24 +1859,39 @@ find_path (struct grub_btrfs_data *data, + grub_size_t allocated = 0; + struct grub_btrfs_dir_item *direl = NULL; + struct grub_btrfs_key key_out; ++ int follow_default; + const char *ctoken; + grub_size_t ctokenlen; + char *path_alloc = NULL; + char *origpath = NULL; + unsigned symlinks_max = 32; ++ const char *relpath = grub_env_get ("btrfs_relative_path"); + ++ follow_default = 0; + origpath = grub_strdup (path); + if (!origpath) + return grub_errno; + +- if (data->fs_tree) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; +- *tree = data->fs_tree; +- /* This is a tree root, so everything starts at objectid 256 */ +- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); +- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; +- key->offset = 0; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } + } + else + { +@@ -1883,15 +1902,23 @@ find_path (struct grub_btrfs_data *data, + + while (1) + { +- while (path[0] == '/') +- path++; +- if (!path[0]) +- break; +- slash = grub_strchr (path, '/'); +- if (!slash) +- slash = path + grub_strlen (path); +- ctoken = path; +- ctokenlen = slash - path; ++ if (!follow_default) ++ { ++ while (path[0] == '/') ++ path++; ++ if (!path[0]) ++ break; ++ slash = grub_strchr (path, '/'); ++ if (!slash) ++ slash = path + grub_strlen (path); ++ ctoken = path; ++ ctokenlen = slash - path; ++ } ++ else ++ { ++ ctoken = "default"; ++ ctokenlen = sizeof ("default") - 1; ++ } + + if (*type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) + { +@@ -1902,7 +1929,9 @@ find_path (struct grub_btrfs_data *data, + + if (ctokenlen == 1 && ctoken[0] == '.') + { +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + if (ctokenlen == 2 && ctoken[0] == '.' && ctoken[1] == '.') +@@ -1933,8 +1962,9 @@ find_path (struct grub_btrfs_data *data, + *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; + key->object_id = key_out.offset; + +- path = slash; +- ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + continue; + } + +@@ -2003,7 +2033,9 @@ find_path (struct grub_btrfs_data *data, + return err; + } + +- path = slash; ++ if (!follow_default) ++ path = slash; ++ follow_default = 0; + if (cdirel->type == GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK) + { + struct grub_btrfs_inode inode; +@@ -2053,14 +2085,26 @@ find_path (struct grub_btrfs_data *data, + path = path_alloc = tmp; + if (path[0] == '/') + { +- if (data->fs_tree) ++ if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { +- *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; +- *tree = data->fs_tree; +- /* This is a tree root, so everything starts at objectid 256 */ +- key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); +- key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; +- key->offset = 0; ++ if (data->fs_tree) ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->fs_tree; ++ /* This is a tree root, so everything starts at objectid 256 */ ++ key->object_id = grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK); ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ } ++ else ++ { ++ *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; ++ *tree = data->sblock.root_tree; ++ key->object_id = data->sblock.root_dir_objectid; ++ key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key->offset = 0; ++ follow_default = 1; ++ } + } + else + { +@@ -2716,6 +2760,7 @@ GRUB_MOD_INIT (btrfs) + subvolid_set_env); + grub_env_export ("btrfs_subvol"); + grub_env_export ("btrfs_subvolid"); ++ grub_env_export ("btrfs_relative_path"); + } + + GRUB_MOD_FINI (btrfs) diff --git a/SOURCES/0044-grub2-btrfs-04-grub2-install.patch b/SOURCES/0044-grub2-btrfs-04-grub2-install.patch new file mode 100644 index 0000000..6b2bc78 --- /dev/null +++ b/SOURCES/0044-grub2-btrfs-04-grub2-install.patch @@ -0,0 +1,176 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 21 Aug 2014 03:39:11 +0000 +Subject: [PATCH] grub2-btrfs-04-grub2-install + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/osdep/linux/getroot.c | 7 +++++++ + grub-core/osdep/unix/config.c | 17 +++++++++++++++-- + util/config.c | 10 ++++++++++ + util/grub-install.c | 15 +++++++++++++++ + util/grub-mkrelpath.c | 6 ++++++ + include/grub/emu/config.h | 1 + + 6 files changed, 54 insertions(+), 2 deletions(-) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 001b818fe5..caf9b1ccd3 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -376,6 +376,7 @@ get_btrfs_fs_prefix (const char *mount_path) + return NULL; + } + ++int use_relative_path_on_btrfs = 0; + + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) +@@ -519,6 +520,12 @@ again: + { + ret = grub_find_root_devices_from_btrfs (dir); + fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); ++ if (use_relative_path_on_btrfs) ++ { ++ if (fs_prefix) ++ free (fs_prefix); ++ fs_prefix = xstrdup ("/"); ++ } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) + { +diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c +index 7d6325138c..46a881530c 100644 +--- a/grub-core/osdep/unix/config.c ++++ b/grub-core/osdep/unix/config.c +@@ -82,6 +82,19 @@ grub_util_load_config (struct grub_util_config *cfg) + if (v) + cfg->grub_distributor = xstrdup (v); + ++ v = getenv ("SUSE_BTRFS_SNAPSHOT_BOOTING"); ++ if (v) ++ { ++ if (grub_strncmp(v, "true", sizeof ("true") - 1) == 0) ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ } ++ else ++ { ++ cfg->is_suse_btrfs_snapshot_enabled = 0; ++ } ++ } ++ + cfgfile = grub_util_get_config_filename (); + if (!grub_util_is_regular (cfgfile)) + return; +@@ -105,8 +118,8 @@ grub_util_load_config (struct grub_util_config *cfg) + *ptr++ = *iptr; + } + +- strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" " +- "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\""); ++ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\nSUSE_BTRFS_SNAPSHOT_BOOTING=%s\\n\" " ++ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\" \"$SUSE_BTRFS_SNAPSHOT_BOOTING\""); + + argv[2] = script; + argv[3] = '\0'; +diff --git a/util/config.c b/util/config.c +index ebcdd8f5e2..f044a880a7 100644 +--- a/util/config.c ++++ b/util/config.c +@@ -42,6 +42,16 @@ grub_util_parse_config (FILE *f, struct grub_util_config *cfg, int simple) + cfg->is_cryptodisk_enabled = 1; + continue; + } ++ if (grub_strncmp (ptr, "SUSE_BTRFS_SNAPSHOT_BOOTING=", ++ sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1) == 0) ++ { ++ ptr += sizeof ("SUSE_BTRFS_SNAPSHOT_BOOTING=") - 1; ++ if (*ptr == '"' || *ptr == '\'') ++ ptr++; ++ if (grub_strncmp(ptr, "true", sizeof ("true") - 1) == 0) ++ cfg->is_suse_btrfs_snapshot_enabled = 1; ++ continue; ++ } + if (grub_strncmp (ptr, "GRUB_DISTRIBUTOR=", + sizeof ("GRUB_DISTRIBUTOR=") - 1) == 0) + { +diff --git a/util/grub-install.c b/util/grub-install.c +index 0fbe7f78c6..0f66f36d23 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -827,6 +827,8 @@ fill_core_services (const char *core_services) + free (sysv_plist); + } + ++extern int use_relative_path_on_btrfs; ++ + int + main (int argc, char *argv[]) + { +@@ -860,6 +862,9 @@ main (int argc, char *argv[]) + + grub_util_load_config (&config); + ++ if (config.is_suse_btrfs_snapshot_enabled) ++ use_relative_path_on_btrfs = 1; ++ + if (!bootloader_id && config.grub_distributor) + { + char *ptr; +@@ -1352,6 +1357,16 @@ main (int argc, char *argv[]) + fprintf (load_cfg_f, "set debug='%s'\n", + debug_image); + } ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ fprintf (load_cfg_f, "set btrfs_relative_path='y'\n"); ++ } ++ + char *prefix_drive = NULL; + char *install_drive = NULL; + +diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c +index 47a241a391..5db7a9a7d9 100644 +--- a/util/grub-mkrelpath.c ++++ b/util/grub-mkrelpath.c +@@ -40,9 +40,12 @@ struct arguments + }; + + static struct argp_option options[] = { ++ {"relative", 'r', 0, 0, "use relative path on btrfs", 0}, + { 0, 0, 0, 0, 0, 0 } + }; + ++extern int use_relative_path_on_btrfs; ++ + static error_t + argp_parser (int key, char *arg, struct argp_state *state) + { +@@ -52,6 +55,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + + switch (key) + { ++ case 'r': ++ use_relative_path_on_btrfs = 1; ++ break; + case ARGP_KEY_ARG: + if (state->arg_num == 0) + arguments->pathname = xstrdup (arg); +diff --git a/include/grub/emu/config.h b/include/grub/emu/config.h +index 875d5896ce..c9a7e5f4ad 100644 +--- a/include/grub/emu/config.h ++++ b/include/grub/emu/config.h +@@ -37,6 +37,7 @@ struct grub_util_config + { + int is_cryptodisk_enabled; + char *grub_distributor; ++ int is_suse_btrfs_snapshot_enabled; + }; + + void diff --git a/SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch b/SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch new file mode 100644 index 0000000..ca3f86b --- /dev/null +++ b/SOURCES/0045-grub2-btrfs-05-grub2-mkconfig.patch @@ -0,0 +1,129 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 21 Aug 2014 03:39:11 +0000 +Subject: [PATCH] grub2-btrfs-05-grub2-mkconfig + +Signed-off-by: Michael Chang +--- + util/grub-mkconfig.in | 3 ++- + util/grub-mkconfig_lib.in | 4 ++++ + util/grub.d/00_header.in | 25 ++++++++++++++++++++++++- + util/grub.d/10_linux.in | 4 ++++ + util/grub.d/20_linux_xen.in | 4 ++++ + 5 files changed, 38 insertions(+), 2 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 005f093809..535c0f0249 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -252,7 +252,8 @@ export GRUB_DEFAULT \ + GRUB_BADRAM \ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU \ +- GRUB_DEFAULT_DTB ++ GRUB_DEFAULT_DTB \ ++ SUSE_BTRFS_SNAPSHOT_BOOTING + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 0f6505bf3b..5e96f6cc5d 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -49,7 +49,11 @@ grub_warn () + + make_system_path_relative_to_its_root () + { ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] ; then ++ "${grub_mkrelpath}" -r "$1" ++ else + "${grub_mkrelpath}" "$1" ++ fi + } + + is_path_readable_by_grub () +diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in +index 858b526c92..de727e6ee6 100644 +--- a/util/grub.d/00_header.in ++++ b/util/grub.d/00_header.in +@@ -27,6 +27,14 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + ++if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ] && ++ [ "x${GRUB_FS}" = "xbtrfs" ] ; then ++ cat </dev/null || true` +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index ada20775a1..e9e73b815f 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -73,10 +73,14 @@ fi + + case x"$GRUB_FS" in + xbtrfs) ++ if [ "x${SUSE_BTRFS_SNAPSHOT_BOOTING}" = "xtrue" ]; then ++ GRUB_CMDLINE_LINUX="${GRUB_CMDLINE_LINUX} \${extra_cmdline}" ++ else + rootsubvol="`make_system_path_relative_to_its_root /`" + rootsubvol="${rootsubvol#/}" + if [ "x${rootsubvol}" != x ]; then + GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" ++ fi + fi;; + xzfs) + rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` diff --git a/SOURCES/0046-grub2-btrfs-06-subvol-mount.patch b/SOURCES/0046-grub2-btrfs-06-subvol-mount.patch new file mode 100644 index 0000000..8cdf247 --- /dev/null +++ b/SOURCES/0046-grub2-btrfs-06-subvol-mount.patch @@ -0,0 +1,539 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 9 Jul 2019 13:56:16 +0200 +Subject: [PATCH] grub2-btrfs-06-subvol-mount + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 195 +++++++++++++++++++++++++++++++++++++++- + grub-core/osdep/linux/getroot.c | 148 +++++++++++++++++++++++++++++- + util/grub-install.c | 49 ++++++++++ + include/grub/emu/getroot.h | 5 ++ + 4 files changed, 392 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 113c1f746c..d323746ecf 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -41,6 +41,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -266,6 +267,12 @@ static grub_err_t + grub_btrfs_read_logical (struct grub_btrfs_data *data, + grub_disk_addr_t addr, void *buf, grub_size_t size, + int recursion_depth); ++static grub_err_t ++get_root (struct grub_btrfs_data *data, struct grub_btrfs_key *key, ++ grub_uint64_t *tree, grub_uint8_t *type); ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol); + + static grub_err_t + read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +@@ -1223,9 +1230,26 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path) + grub_err_t err; + grub_uint64_t tree = 0; + grub_uint8_t type; ++ grub_uint64_t saved_tree; + struct grub_btrfs_key key; + ++ if (path[0] == '\0') ++ { ++ data->fs_tree = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ err = get_root (data, &key, &tree, &type); ++ if (err) ++ return err; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ + err = find_path (data, path, &key, &tree, &type); ++ ++ data->fs_tree = saved_tree; ++ + if (err) + return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); + +@@ -2199,11 +2223,20 @@ grub_btrfs_dir (grub_device_t device, const char *path, + int r = 0; + grub_uint64_t tree; + grub_uint8_t type; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, path, &key_in, &tree, &type); ++ tree = find_mtab_subvol_tree (path, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : path, &key_in, &tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2305,11 +2338,21 @@ grub_btrfs_open (struct grub_file *file, const char *name) + struct grub_btrfs_inode inode; + grub_uint8_t type; + struct grub_btrfs_key key_in; ++ grub_uint64_t tree; ++ char *new_path = NULL; + + if (!data) + return grub_errno; + +- err = find_path (data, name, &key_in, &data->tree, &type); ++ tree = find_mtab_subvol_tree (name, &new_path); ++ ++ if (tree) ++ data->fs_tree = tree; ++ ++ err = find_path (data, new_path ? new_path : name, &key_in, &data->tree, &type); ++ if (new_path) ++ grub_free (new_path); ++ + if (err) + { + grub_btrfs_unmount (data); +@@ -2480,6 +2523,150 @@ grub_cmd_btrfs_info (grub_command_t cmd __attribute__ ((unused)), int argc, + return 0; + } + ++struct grub_btrfs_mtab ++{ ++ struct grub_btrfs_mtab *next; ++ struct grub_btrfs_mtab **prev; ++ char *path; ++ char *subvol; ++ grub_uint64_t tree; ++}; ++ ++typedef struct grub_btrfs_mtab* grub_btrfs_mtab_t; ++ ++static struct grub_btrfs_mtab *btrfs_mtab; ++ ++#define FOR_GRUB_MTAB(var) FOR_LIST_ELEMENTS (var, btrfs_mtab) ++#define FOR_GRUB_MTAB_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE((var), (next), btrfs_mtab) ++ ++static void ++add_mountpoint (const char *path, const char *subvol, grub_uint64_t tree) ++{ ++ grub_btrfs_mtab_t m = grub_malloc (sizeof (*m)); ++ ++ m->path = grub_strdup (path); ++ m->subvol = grub_strdup (subvol); ++ m->tree = tree; ++ grub_list_push (GRUB_AS_LIST_P (&btrfs_mtab), GRUB_AS_LIST (m)); ++} ++ ++static grub_err_t ++grub_cmd_btrfs_mount_subvol (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char **argv) ++{ ++ char *devname, *dirname, *subvol; ++ struct grub_btrfs_key key_in; ++ grub_uint8_t type; ++ grub_uint64_t tree; ++ grub_uint64_t saved_tree; ++ grub_err_t err; ++ struct grub_btrfs_data *data = NULL; ++ grub_device_t dev = NULL; ++ ++ if (argc < 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "required and "); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ ++ if (!dev) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ dirname = argv[1]; ++ subvol = argv[2]; ++ ++ data = grub_btrfs_mount (dev); ++ if (!data) ++ { ++ err = grub_errno; ++ goto err_out; ++ } ++ ++ err = find_path (data, dirname, &key_in, &tree, &type); ++ if (err) ++ goto err_out; ++ ++ if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a directory")); ++ goto err_out; ++ } ++ ++ err = get_root (data, &key_in, &tree, &type); ++ ++ if (err) ++ goto err_out; ++ ++ saved_tree = data->fs_tree; ++ data->fs_tree = tree; ++ err = find_path (data, subvol, &key_in, &tree, &type); ++ data->fs_tree = saved_tree; ++ ++ if (err) ++ goto err_out; ++ ++ if (key_in.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", subvol); ++ goto err_out; ++ } ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ add_mountpoint (dirname, subvol, tree); ++ ++ return GRUB_ERR_NONE; ++ ++err_out: ++ ++ if (data) ++ grub_btrfs_unmount (data); ++ ++ if (dev) ++ grub_device_close (dev); ++ ++ return err; ++} ++ ++grub_uint64_t ++find_mtab_subvol_tree (const char *path, char **path_in_subvol) ++{ ++ grub_btrfs_mtab_t m, cm; ++ grub_uint64_t tree; ++ ++ if (!path || !path_in_subvol) ++ return 0; ++ ++ *path_in_subvol = NULL; ++ tree = 0; ++ cm = NULL; ++ ++ FOR_GRUB_MTAB (m) ++ { ++ if (grub_strncmp (path, m->path, grub_strlen (m->path)) == 0) ++ { ++ if (!cm) ++ cm = m; ++ else ++ if (grub_strcmp (m->path, cm->path) > 0) ++ cm = m; ++ } ++ } ++ ++ if (cm) ++ { ++ const char *s = path + grub_strlen (cm->path); ++ *path_in_subvol = (s[0] == '\0') ? grub_strdup ("/") : grub_strdup (s); ++ tree = cm->tree; ++ } ++ ++ return tree; ++} ++ + static grub_err_t + get_fs_root(struct grub_btrfs_data *data, grub_uint64_t tree, + grub_uint64_t objectid, grub_uint64_t offset, +@@ -2686,6 +2873,7 @@ static struct grub_fs grub_btrfs_fs = { + }; + + static grub_command_t cmd_info; ++static grub_command_t cmd_mount_subvol; + static grub_extcmd_t cmd_list_subvols; + + static char * +@@ -2749,6 +2937,9 @@ GRUB_MOD_INIT (btrfs) + cmd_info = grub_register_command("btrfs-info", grub_cmd_btrfs_info, + "DEVICE", + "Print BtrFS info about DEVICE."); ++ cmd_mount_subvol = grub_register_command("btrfs-mount-subvol", grub_cmd_btrfs_mount_subvol, ++ "DEVICE DIRECTORY SUBVOL", ++ "Set btrfs DEVICE the DIRECTORY a mountpoint of SUBVOL."); + cmd_list_subvols = grub_register_extcmd("btrfs-list-subvols", + grub_cmd_btrfs_list_subvols, 0, + "[-p|-n] [-o var] DEVICE", +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index caf9b1ccd3..28790307e0 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -107,6 +107,14 @@ struct btrfs_ioctl_search_key + grub_uint32_t unused[9]; + }; + ++struct btrfs_ioctl_search_header { ++ grub_uint64_t transid; ++ grub_uint64_t objectid; ++ grub_uint64_t offset; ++ grub_uint32_t type; ++ grub_uint32_t len; ++}; ++ + struct btrfs_ioctl_search_args { + struct btrfs_ioctl_search_key key; + grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key)) +@@ -378,6 +386,109 @@ get_btrfs_fs_prefix (const char *mount_path) + + int use_relative_path_on_btrfs = 0; + ++static char * ++get_btrfs_subvol (const char *path) ++{ ++ struct btrfs_ioctl_ino_lookup_args args; ++ grub_uint64_t tree_id; ++ int fd = -1; ++ char *ret = NULL; ++ ++ fd = open (path, O_RDONLY); ++ ++ if (fd < 0) ++ return NULL; ++ ++ memset (&args, 0, sizeof(args)); ++ args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ tree_id = args.treeid; ++ ++ while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ struct btrfs_ioctl_search_args sargs; ++ struct grub_btrfs_root_backref *br; ++ struct btrfs_ioctl_search_header *search_header; ++ char *old; ++ grub_uint16_t len; ++ grub_uint64_t inode_id; ++ ++ memset (&sargs, 0, sizeof(sargs)); ++ ++ sargs.key.tree_id = 1; ++ sargs.key.min_objectid = tree_id; ++ sargs.key.max_objectid = tree_id; ++ ++ sargs.key.min_offset = 0; ++ sargs.key.max_offset = ~0ULL; ++ sargs.key.min_transid = 0; ++ sargs.key.max_transid = ~0ULL; ++ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF; ++ ++ sargs.key.nr_items = 1; ++ ++ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0) ++ goto error; ++ ++ if (sargs.key.nr_items == 0) ++ goto error; ++ ++ search_header = (struct btrfs_ioctl_search_header *)sargs.buf; ++ br = (struct grub_btrfs_root_backref *) (search_header + 1); ++ ++ len = grub_le_to_cpu16 (br->n); ++ inode_id = grub_le_to_cpu64 (br->inode_id); ++ tree_id = search_header->offset; ++ ++ old = ret; ++ ret = malloc (len + 1); ++ memcpy (ret, br->name, len); ++ ret[len] = '\0'; ++ ++ if (inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID) ++ { ++ char *s; ++ ++ memset(&args, 0, sizeof(args)); ++ args.treeid = search_header->offset; ++ args.objectid = inode_id; ++ ++ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0) ++ goto error; ++ ++ s = xasprintf ("%s%s", args.name, ret); ++ free (ret); ++ ret = s; ++ } ++ ++ if (old) ++ { ++ char *s = xasprintf ("%s/%s", ret, old); ++ free (ret); ++ free (old); ++ ret = s; ++ } ++ } ++ ++ close (fd); ++ return ret; ++ ++error: ++ ++ if (fd >= 0) ++ close (fd); ++ if (ret) ++ free (ret); ++ ++ return NULL; ++} ++ ++void (*grub_find_root_btrfs_mount_path_hook)(const char *mount_path); ++ + char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) + { +@@ -519,12 +630,15 @@ again: + else if (grub_strcmp (entries[i].fstype, "btrfs") == 0) + { + ret = grub_find_root_devices_from_btrfs (dir); +- fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); + if (use_relative_path_on_btrfs) + { +- if (fs_prefix) +- free (fs_prefix); + fs_prefix = xstrdup ("/"); ++ if (grub_find_root_btrfs_mount_path_hook) ++ grub_find_root_btrfs_mount_path_hook (entries[i].enc_path); ++ } ++ else ++ { ++ fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path); + } + } + else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0) +@@ -1150,6 +1264,34 @@ grub_util_get_grub_dev_os (const char *os_dev) + return grub_dev; + } + ++ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path) ++{ ++ char *mp = NULL; ++ ++ if (mount_path) ++ *mount_path = NULL; ++ ++ auto void ++ mount_path_hook (const char *m) ++ { ++ mp = strdup (m); ++ } ++ ++ grub_find_root_btrfs_mount_path_hook = mount_path_hook; ++ grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); ++ grub_find_root_btrfs_mount_path_hook = NULL; ++ ++ if (!mp) ++ return NULL; ++ ++ if (mount_path) ++ *mount_path = mp; ++ ++ return get_btrfs_subvol (mp); ++} ++ + char * + grub_make_system_path_relative_to_its_root_os (const char *path) + { +diff --git a/util/grub-install.c b/util/grub-install.c +index 0f66f36d23..84ed6e88ec 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1569,6 +1569,55 @@ main (int argc, char *argv[]) + prefix_drive = xasprintf ("(%s)", grub_drives[0]); + } + ++#ifdef __linux__ ++ ++ if (config.is_suse_btrfs_snapshot_enabled ++ && grub_strncmp(grub_fs->name, "btrfs", sizeof ("btrfs") - 1) == 0) ++ { ++ char *subvol = NULL; ++ char *mount_path = NULL; ++ char **rootdir_devices = NULL; ++ char *rootdir_path = grub_util_path_concat (2, "/", rootdir); ++ ++ if (grub_util_is_directory (rootdir_path)) ++ rootdir_devices = grub_guess_root_devices (rootdir_path); ++ ++ free (rootdir_path); ++ ++ if (rootdir_devices && rootdir_devices[0]) ++ if (grub_strcmp (rootdir_devices[0], grub_devices[0]) == 0) ++ subvol = grub_util_get_btrfs_subvol (platdir, &mount_path); ++ ++ if (subvol && mount_path) ++ { ++ char *def_subvol; ++ ++ def_subvol = grub_util_get_btrfs_subvol ("/", NULL); ++ ++ if (def_subvol) ++ { ++ if (!load_cfg_f) ++ load_cfg_f = grub_util_fopen (load_cfg, "wb"); ++ have_load_cfg = 1; ++ ++ if (grub_strcmp (subvol, def_subvol) != 0) ++ fprintf (load_cfg_f, "btrfs-mount-subvol ($root) %s %s\n", mount_path, subvol); ++ free (def_subvol); ++ } ++ } ++ ++ for (curdev = rootdir_devices; *curdev; curdev++) ++ free (*curdev); ++ if (rootdir_devices) ++ free (rootdir_devices); ++ if (subvol) ++ free (subvol); ++ if (mount_path) ++ free (mount_path); ++ } ++ ++#endif ++ + char mkimage_target[200]; + const char *core_name = NULL; + +diff --git a/include/grub/emu/getroot.h b/include/grub/emu/getroot.h +index 73fa2d34ab..9c642ae3fe 100644 +--- a/include/grub/emu/getroot.h ++++ b/include/grub/emu/getroot.h +@@ -53,6 +53,11 @@ char ** + grub_find_root_devices_from_mountinfo (const char *dir, char **relroot); + #endif + ++#ifdef __linux__ ++char * ++grub_util_get_btrfs_subvol (const char *path, char **mount_path); ++#endif ++ + /* Devmapper functions provided by getroot_devmapper.c. */ + void + grub_util_pull_devmapper (const char *os_dev); diff --git a/SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch b/SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch new file mode 100644 index 0000000..a5db09a --- /dev/null +++ b/SOURCES/0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrei Borzenkov +Date: Tue, 21 Jun 2016 16:44:17 +0000 +Subject: [PATCH] Fallback to old subvol name scheme to support old snapshot + config + +Ref: bsc#953538 +--- + grub-core/fs/btrfs.c | 32 +++++++++++++++++++++++++++++++- + 1 file changed, 31 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index d323746ecf..673ded0352 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1260,11 +1260,41 @@ lookup_root_by_name(struct grub_btrfs_data *data, const char *path) + return GRUB_ERR_NONE; + } + ++static grub_err_t ++lookup_root_by_name_fallback(struct grub_btrfs_data *data, const char *path) ++{ ++ grub_err_t err; ++ grub_uint64_t tree = 0; ++ grub_uint8_t type; ++ struct grub_btrfs_key key; ++ ++ err = find_path (data, path, &key, &tree, &type); ++ if (err) ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, "couldn't locate %s\n", path); ++ ++ if (key.object_id != grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK) || tree == 0) ++ return grub_error(GRUB_ERR_BAD_FILE_TYPE, "%s: not a subvolume\n", path); ++ ++ data->fs_tree = tree; ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + btrfs_handle_subvol(struct grub_btrfs_data *data __attribute__ ((unused))) + { + if (btrfs_default_subvol) +- return lookup_root_by_name(data, btrfs_default_subvol); ++ { ++ grub_err_t err; ++ err = lookup_root_by_name(data, btrfs_default_subvol); ++ ++ /* Fallback to old schemes */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ err = GRUB_ERR_NONE; ++ return lookup_root_by_name_fallback(data, btrfs_default_subvol); ++ } ++ return err; ++ } + + if (btrfs_default_subvolid) + return lookup_root_by_id(data, btrfs_default_subvolid); diff --git a/SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch b/SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch new file mode 100644 index 0000000..99c106d --- /dev/null +++ b/SOURCES/0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch @@ -0,0 +1,274 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 11 May 2017 08:56:57 +0000 +Subject: [PATCH] Grub not working correctly with btrfs snapshots (bsc#1026511) + +Signed-off-by: Michael Chang +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 238 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 673ded0352..2b21cbaa67 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2887,6 +2887,238 @@ out: + return 0; + } + ++static grub_err_t ++grub_btrfs_get_parent_subvol_path (struct grub_btrfs_data *data, ++ grub_uint64_t child_id, ++ const char *child_path, ++ grub_uint64_t *parent_id, ++ char **path_out) ++{ ++ grub_uint64_t fs_root = 0; ++ struct grub_btrfs_key key_in = { ++ .object_id = child_id, ++ .type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF, ++ .offset = 0, ++ }, key_out; ++ struct grub_btrfs_root_ref *ref; ++ char *buf; ++ struct grub_btrfs_leaf_descriptor desc; ++ grub_size_t elemsize; ++ grub_disk_addr_t elemaddr; ++ grub_err_t err; ++ char *parent_path; ++ ++ *parent_id = 0; ++ *path_out = 0; ++ ++ err = lower_bound(data, &key_in, &key_out, data->sblock.root_tree, ++ &elemaddr, &elemsize, &desc, 0); ++ if (err) ++ return err; ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF || elemaddr == 0) ++ next(data, &desc, &elemaddr, &elemsize, &key_out); ++ ++ if (key_out.type != GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF) ++ { ++ free_iterator(&desc); ++ return grub_error(GRUB_ERR_FILE_NOT_FOUND, N_("can't find root backrefs")); ++ } ++ ++ buf = grub_malloc(elemsize + 1); ++ if (!buf) ++ { ++ free_iterator(&desc); ++ return grub_errno; ++ } ++ ++ err = grub_btrfs_read_logical(data, elemaddr, buf, elemsize, 0); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ buf[elemsize] = 0; ++ ref = (struct grub_btrfs_root_ref *)buf; ++ ++ err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset), ++ 0, &fs_root); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } ++ ++ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); ++ ++ if (child_path) ++ { ++ *path_out = grub_xasprintf ("%s/%s", parent_path, child_path); ++ grub_free (parent_path); ++ } ++ else ++ *path_out = parent_path; ++ ++ *parent_id = grub_le_to_cpu64 (key_out.offset); ++ ++ grub_free(buf); ++ free_iterator(&desc); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_btrfs_get_default_subvolume_id (struct grub_btrfs_data *data, grub_uint64_t *id) ++{ ++ grub_err_t err; ++ grub_disk_addr_t elemaddr; ++ grub_size_t elemsize; ++ struct grub_btrfs_key key, key_out; ++ struct grub_btrfs_dir_item *direl = NULL; ++ const char *ctoken = "default"; ++ grub_size_t ctokenlen = sizeof ("default") - 1; ++ ++ *id = 0; ++ key.object_id = data->sblock.root_dir_objectid; ++ key.type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; ++ key.offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); ++ err = lower_bound (data, &key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize, ++ NULL, 0); ++ if (err) ++ return err; ++ ++ if (key_cmp (&key, &key_out) != 0) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ ++ struct grub_btrfs_dir_item *cdirel; ++ direl = grub_malloc (elemsize + 1); ++ err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize, 0); ++ if (err) ++ { ++ grub_free (direl); ++ return err; ++ } ++ for (cdirel = direl; ++ (grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ < (grub_ssize_t) elemsize; ++ cdirel = (void *) ((grub_uint8_t *) (direl + 1) ++ + grub_le_to_cpu16 (cdirel->n) ++ + grub_le_to_cpu16 (cdirel->m))) ++ { ++ if (ctokenlen == grub_le_to_cpu16 (cdirel->n) ++ && grub_memcmp (cdirel->name, ctoken, ctokenlen) == 0) ++ break; ++ } ++ if ((grub_uint8_t *) cdirel - (grub_uint8_t *) direl ++ >= (grub_ssize_t) elemsize) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ if (cdirel->key.type != GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM) ++ { ++ grub_free (direl); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file not found")); ++ return err; ++ } ++ ++ *id = grub_le_to_cpu64 (cdirel->key.object_id); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_btrfs_get_default_subvol (struct grub_extcmd_context *ctxt, ++ int argc, char **argv) ++{ ++ char *devname; ++ grub_device_t dev; ++ struct grub_btrfs_data *data; ++ grub_err_t err; ++ grub_uint64_t id; ++ char *subvol = NULL; ++ grub_uint64_t subvolid = 0; ++ char *varname = NULL; ++ char *output = NULL; ++ int path_only = ctxt->state[1].set; ++ int num_only = ctxt->state[2].set; ++ ++ if (ctxt->state[0].set) ++ varname = ctxt->state[0].arg; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ devname = grub_file_get_device_name(argv[0]); ++ if (!devname) ++ return grub_errno; ++ ++ dev = grub_device_open (devname); ++ grub_free (devname); ++ if (!dev) ++ return grub_errno; ++ ++ data = grub_btrfs_mount(dev); ++ if (!data) ++ { ++ grub_device_close (dev); ++ grub_dprintf ("btrfs", "failed to open fs\n"); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ ++ err = grub_btrfs_get_default_subvolume_id (data, &subvolid); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ id = subvolid; ++ while (id != GRUB_BTRFS_ROOT_VOL_OBJECTID) ++ { ++ grub_uint64_t parent_id; ++ char *path_out; ++ ++ err = grub_btrfs_get_parent_subvol_path (data, grub_cpu_to_le64 (id), subvol, &parent_id, &path_out); ++ if (err) ++ { ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ return err; ++ } ++ ++ if (subvol) ++ grub_free (subvol); ++ subvol = path_out; ++ id = parent_id; ++ } ++ ++ if (num_only && path_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T" /%s", subvolid, subvol); ++ else if (num_only) ++ output = grub_xasprintf ("%"PRIuGRUB_UINT64_T, subvolid); ++ else ++ output = grub_xasprintf ("/%s", subvol); ++ ++ if (varname) ++ grub_env_set(varname, output); ++ else ++ grub_printf ("%s\n", output); ++ ++ grub_free (output); ++ grub_free (subvol); ++ ++ grub_btrfs_unmount (data); ++ grub_device_close (dev); ++ ++ return GRUB_ERR_NONE; ++} ++ + static struct grub_fs grub_btrfs_fs = { + .name = "btrfs", + .fs_dir = grub_btrfs_dir, +@@ -2905,6 +3137,7 @@ static struct grub_fs grub_btrfs_fs = { + static grub_command_t cmd_info; + static grub_command_t cmd_mount_subvol; + static grub_extcmd_t cmd_list_subvols; ++static grub_extcmd_t cmd_get_default_subvol; + + static char * + subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), +@@ -2975,6 +3208,11 @@ GRUB_MOD_INIT (btrfs) + "[-p|-n] [-o var] DEVICE", + "Print list of BtrFS subvolumes on " + "DEVICE.", options); ++ cmd_get_default_subvol = grub_register_extcmd("btrfs-get-default-subvol", ++ grub_cmd_btrfs_get_default_subvol, 0, ++ "[-p|-n] [-o var] DEVICE", ++ "Print default BtrFS subvolume on " ++ "DEVICE.", options); + grub_register_variable_hook ("btrfs_subvol", subvol_get_env, + subvol_set_env); + grub_register_variable_hook ("btrfs_subvolid", subvolid_get_env, diff --git a/SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch b/SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch new file mode 100644 index 0000000..d07dd27 --- /dev/null +++ b/SOURCES/0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 1 Jun 2017 09:59:56 -0400 +Subject: [PATCH] Add grub_efi_allocate_pool() and grub_efi_free_pool() + wrappers. + +Signed-off-by: Peter Jones +--- + include/grub/efi/efi.h | 36 ++++++++++++++++++++++++++++++++---- + 1 file changed, 32 insertions(+), 4 deletions(-) + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 585fa6662b..03f9a9d011 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -24,6 +24,10 @@ + #include + #include + ++/* Variables. */ ++extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); ++extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); ++ + /* Functions. */ + void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_efi_guid_t *protocol, + void *registration); +@@ -60,6 +64,33 @@ EXPORT_FUNC(grub_efi_get_memory_map) (grub_efi_uintn_t *memory_map_size, + grub_efi_uintn_t *descriptor_size, + grub_efi_uint32_t *descriptor_version); + void grub_efi_memory_fini (void); ++ ++static inline grub_efi_status_t ++__attribute__((__unused__)) ++grub_efi_allocate_pool (grub_efi_memory_type_t pool_type, ++ grub_efi_uintn_t buffer_size, ++ void **buffer) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_3 (b->allocate_pool, pool_type, buffer_size, buffer); ++ return status; ++} ++ ++static inline grub_efi_status_t ++__attribute__((__unused__)) ++grub_efi_free_pool (void *buffer) ++{ ++ grub_efi_boot_services_t *b; ++ grub_efi_status_t status; ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_1 (b->free_pool, buffer); ++ return status; ++} ++ + grub_efi_loaded_image_t *EXPORT_FUNC(grub_efi_get_loaded_image) (grub_efi_handle_t image_handle); + void EXPORT_FUNC(grub_efi_print_device_path) (grub_efi_device_path_t *dp); + char *EXPORT_FUNC(grub_efi_get_filename) (grub_efi_device_path_t *dp); +@@ -115,10 +146,7 @@ void grub_efi_init (void); + void grub_efi_fini (void); + void grub_efi_set_prefix (void); + +-/* Variables. */ +-extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); +-extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +- ++/* More variables. */ + extern int EXPORT_VAR(grub_efi_is_finished); + + struct grub_net_card; diff --git a/SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch b/SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch new file mode 100644 index 0000000..2a3d27b --- /dev/null +++ b/SOURCES/0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 1 Jun 2017 10:06:38 -0400 +Subject: [PATCH] Use grub_efi_...() memory helpers where reasonable. + +This uses grub_efi_allocate_pool(), grub_efi_free_pool(), and +grub_efi_free_pages() instead of open-coded efi_call_N() calls, so we +get more reasonable type checking. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/chainloader.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 07c4937898..89ac84cc66 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -65,7 +65,7 @@ grub_chainloader_unload (void) + + b = grub_efi_system_table->boot_services; + efi_call_1 (b->unload_image, image_handle); +- efi_call_2 (b->free_pages, address, pages); ++ grub_efi_free_pages (address, pages); + + grub_free (file_path); + grub_free (cmdline); +@@ -108,7 +108,7 @@ grub_chainloader_boot (void) + } + + if (exit_data) +- efi_call_1 (b->free_pool, exit_data); ++ grub_efi_free_pool (exit_data); + + grub_loader_unset (); + +@@ -527,10 +527,9 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) + static grub_efi_boolean_t + handle_image (void *data, grub_efi_uint32_t datasize) + { +- grub_efi_boot_services_t *b; + grub_efi_loaded_image_t *li, li_bak; + grub_efi_status_t efi_status; +- char *buffer = NULL; ++ void *buffer = NULL; + char *buffer_aligned = NULL; + grub_efi_uint32_t i; + struct grub_pe32_section_table *section; +@@ -541,8 +540,6 @@ handle_image (void *data, grub_efi_uint32_t datasize) + int found_entry_point = 0; + int rc; + +- b = grub_efi_system_table->boot_services; +- + rc = read_header (data, datasize, &context); + if (rc < 0) + { +@@ -582,8 +579,8 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_dprintf ("chain", "image size is %08"PRIxGRUB_UINT64_T", datasize is %08x\n", + context.image_size, datasize); + +- efi_status = efi_call_3 (b->allocate_pool, GRUB_EFI_LOADER_DATA, +- buffer_size, &buffer); ++ efi_status = grub_efi_allocate_pool (GRUB_EFI_LOADER_DATA, buffer_size, ++ &buffer); + + if (efi_status != GRUB_EFI_SUCCESS) + { +@@ -815,14 +812,14 @@ handle_image (void *data, grub_efi_uint32_t datasize) + + grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); + grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); +- efi_status = efi_call_1 (b->free_pool, buffer); ++ efi_status = grub_efi_free_pool (buffer); + + return 1; + + error_exit: + grub_dprintf ("chain", "error_exit: grub_errno: %d\n", grub_errno); + if (buffer) +- efi_call_1 (b->free_pool, buffer); ++ grub_efi_free_pool (buffer); + + return 0; + } +@@ -830,10 +827,7 @@ error_exit: + static grub_err_t + grub_secureboot_chainloader_unload (void) + { +- grub_efi_boot_services_t *b; +- +- b = grub_efi_system_table->boot_services; +- efi_call_2 (b->free_pages, address, pages); ++ grub_efi_free_pages (address, pages); + grub_free (file_path); + grub_free (cmdline); + cmdline = 0; +@@ -1100,7 +1094,7 @@ fail: + grub_free (file_path); + + if (address) +- efi_call_2 (b->free_pages, address, pages); ++ grub_efi_free_pages (address, pages); + + if (cmdline) + grub_free (cmdline); diff --git a/SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch b/SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch new file mode 100644 index 0000000..f649c8c --- /dev/null +++ b/SOURCES/0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 1 Jun 2017 10:07:50 -0400 +Subject: [PATCH] Add PRIxGRUB_EFI_STATUS and use it. + +This avoids syntax checkers getting confused about if it's llx or lx. + +Signed-off-by: Peter Jones +--- + grub-core/loader/efi/chainloader.c | 3 ++- + include/grub/efi/api.h | 9 +++++++++ + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 89ac84cc66..ac8dfd40c6 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -810,7 +810,8 @@ handle_image (void *data, grub_efi_uint32_t datasize) + efi_status = efi_call_2 (entry_point, grub_efi_image_handle, + grub_efi_system_table); + +- grub_dprintf ("chain", "entry_point returned %ld\n", efi_status); ++ grub_dprintf ("chain", "entry_point returned 0x%"PRIxGRUB_EFI_STATUS"\n", ++ efi_status); + grub_memcpy (li, &li_bak, sizeof (grub_efi_loaded_image_t)); + efi_status = grub_efi_free_pool (buffer); + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 117469450d..9962880147 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -546,7 +546,16 @@ typedef grub_uint64_t grub_efi_uint64_t; + typedef grub_uint8_t grub_efi_char8_t; + typedef grub_uint16_t grub_efi_char16_t; + ++ + typedef grub_efi_uintn_t grub_efi_status_t; ++/* Make grub_efi_status_t reasonably printable. */ ++#if GRUB_CPU_SIZEOF_VOID_P == 8 ++#define PRIxGRUB_EFI_STATUS "lx" ++#define PRIdGRUB_EFI_STATUS "ld" ++#else ++#define PRIxGRUB_EFI_STATUS "llx" ++#define PRIdGRUB_EFI_STATUS "lld" ++#endif + + #define GRUB_EFI_ERROR_CODE(value) \ + ((((grub_efi_status_t) 1) << (sizeof (grub_efi_status_t) * 8 - 1)) | (value)) diff --git a/SOURCES/0052-don-t-use-int-for-efi-status.patch b/SOURCES/0052-don-t-use-int-for-efi-status.patch new file mode 100644 index 0000000..4d48e37 --- /dev/null +++ b/SOURCES/0052-don-t-use-int-for-efi-status.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 26 Jun 2017 12:44:59 -0400 +Subject: [PATCH] don't use int for efi status + +--- + grub-core/kern/efi/efi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 05d8237a9b..ae9885edb8 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -167,7 +167,7 @@ grub_reboot (void) + void + grub_exit (int retval) + { +- int rc = GRUB_EFI_LOAD_ERROR; ++ grub_efi_status_t rc = GRUB_EFI_LOAD_ERROR; + + if (retval == 0) + rc = GRUB_EFI_SUCCESS; diff --git a/SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch b/SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch new file mode 100644 index 0000000..fb71ea5 --- /dev/null +++ b/SOURCES/0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 26 Jun 2017 12:46:23 -0400 +Subject: [PATCH] make GRUB_MOD_INIT() declare its function prototypes. + +--- + include/grub/dl.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index b3753c9ca2..91933b85f2 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -54,6 +54,7 @@ grub_mod_fini (void) + + #define GRUB_MOD_INIT(name) \ + static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ ++extern void grub_##name##_init (void); \ + void \ + grub_##name##_init (void) { grub_mod_init (0); } \ + static void \ +@@ -61,6 +62,7 @@ grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + + #define GRUB_MOD_FINI(name) \ + static void grub_mod_fini (void) __attribute__ ((used)); \ ++extern void grub_##name##_fini (void); \ + void \ + grub_##name##_fini (void) { grub_mod_fini (); } \ + static void \ diff --git a/SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch b/SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch new file mode 100644 index 0000000..ae8a8c6 --- /dev/null +++ b/SOURCES/0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 20 Apr 2017 13:29:06 -0400 +Subject: [PATCH] Don't guess /boot/efi/ as HFS+ on ppc machines in + grub-install + +This should never be trying this, and since we've consolidated the +grubenv to always be on /boot/efi/EFI/fedora/, this code causes it to +always make the wrong decision. + +Resolves: rhbz#1484474 + +Signed-off-by: Peter Jones +--- + util/grub-install.c | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 84ed6e88ec..a2bec7446c 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -1190,18 +1190,8 @@ main (int argc, char *argv[]) + char *d; + + is_guess = 1; +- d = grub_util_path_concat (2, bootdir, "macppc"); +- if (!grub_util_is_directory (d)) +- { +- free (d); +- d = grub_util_path_concat (2, bootdir, "efi"); +- } + /* Find the Mac HFS(+) System Partition. */ +- if (!grub_util_is_directory (d)) +- { +- free (d); +- d = grub_util_path_concat (2, bootdir, "EFI"); +- } ++ d = grub_util_path_concat (2, bootdir, "macppc"); + if (!grub_util_is_directory (d)) + { + free (d); diff --git a/SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch b/SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch new file mode 100644 index 0000000..cd58ff4 --- /dev/null +++ b/SOURCES/0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 14:31:19 +0200 +Subject: [PATCH] 20_linux_xen: load xen or multiboot{,2} modules as needed. + +Signed-off-by: Peter Jones +--- + util/grub.d/20_linux_xen.in | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in +index e9e73b815f..c23b064be6 100644 +--- a/util/grub.d/20_linux_xen.in ++++ b/util/grub.d/20_linux_xen.in +@@ -153,6 +153,7 @@ linux_entry_xsm () + else + xen_rm_opts="no-real-mode edd=off" + fi ++ insmod ${xen_module} + ${xen_loader} ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args} \${xen_rm_opts} + echo '$(echo "$lmessage" | grub_quote)' + ${module_loader} ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args} +@@ -166,6 +167,7 @@ EOF + done + sed "s/^/$submenu_indentation/" << EOF + echo '$(echo "$message" | grub_quote)' ++ insmod ${xen_module} + ${module_loader} --nounzip $(echo $initrd_path) + EOF + fi +@@ -253,13 +255,16 @@ while [ "x${xen_list}" != "x" ] ; do + echo " submenu '$(gettext_printf "Xen hypervisor, version %s" "${xen_version}" | grub_quote)' \$menuentry_id_option 'xen-hypervisor-$xen_version-$boot_device_id' {" + fi + if ($grub_file --is-arm64-efi $current_xen); then ++ xen_module="xen_boot" + xen_loader="xen_hypervisor" + module_loader="xen_module" + else + if ($grub_file --is-x86-multiboot2 $current_xen); then ++ xen_module="multiboot2" + xen_loader="multiboot2" + module_loader="module2" + else ++ xen_module="multiboot" + xen_loader="multiboot" + module_loader="module" + fi diff --git a/SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch b/SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch new file mode 100644 index 0000000..beef0f3 --- /dev/null +++ b/SOURCES/0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch @@ -0,0 +1,211 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 7 Nov 2017 17:12:17 -0500 +Subject: [PATCH] Make pmtimer tsc calibration not take 51 seconds to fail. + +On my laptop running at 2.4GHz, if I run a VM where tsc calibration +using pmtimer will fail presuming a broken pmtimer, it takes ~51 seconds +to do so (as measured with the stopwatch on my phone), with a tsc delta +of 0x1cd1c85300, or around 125 billion cycles. + +If instead of trying to wait for 5-200ms to show up on the pmtimer, we try +to wait for 5-200us, it decides it's broken in ~0x2626aa0 TSCs, aka ~2.4 +million cycles, or more or less instantly. + +Additionally, this reading the pmtimer was returning 0xffffffff anyway, +and that's obviously an invalid return. I've added a check for that and +0 so we don't bother waiting for the test if what we're seeing is dead +pins with no response at all. + +If "debug" is includes "pmtimer", you will see one of the following +three outcomes. If pmtimer gives all 0 or all 1 bits, you will see: + +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 1 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 2 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 3 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 4 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 5 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 6 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 7 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 8 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 9 +kern/i386/tsc_pmtimer.c:77: pmtimer: 0xffffff bad_reads: 10 +kern/i386/tsc_pmtimer.c:78: timer is broken; giving up. + +This outcome was tested using qemu+kvm with UEFI (OVMF) firmware and +these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX + +If pmtimer gives any other bit patterns but is not actually marching +forward fast enough to use for clock calibration, you will see: + +kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations) +kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0 + +This outcome was tested using grub compiled with GRUB_PMTIMER_IGNORE_BAD_READS +defined (so as not to trip the bad read test) using qemu+kvm with UEFI +(OVMF) firmware, and these options: -machine pc-q35-2.10 -cpu Broadwell-noTSX + +If pmtimer actually works, you'll see something like: + +kern/i386/tsc_pmtimer.c:121: pmtimer delta is 0x0 (1904 iterations) +kern/i386/tsc_pmtimer.c:124: tsc delta is implausible: 0x2626aa0 + +This outcome was tested using qemu+kvm with UEFI (OVMF) firmware, and +these options: -machine pc-i440fx-2.4 -cpu Broadwell-noTSX + +I've also tested this outcome on a real Intel Xeon E3-1275v3 on an Intel +Server Board S1200V3RPS using the SDV.RP.B8 "Release" build here: +https://firmware.intel.com/sites/default/files/UEFIDevKit_S1200RP_vB8.zip + +Signed-off-by: Peter Jones +--- + grub-core/kern/i386/tsc_pmtimer.c | 109 +++++++++++++++++++++++++++++++------- + 1 file changed, 89 insertions(+), 20 deletions(-) + +diff --git a/grub-core/kern/i386/tsc_pmtimer.c b/grub-core/kern/i386/tsc_pmtimer.c +index c9c3616997..ca15c3aacd 100644 +--- a/grub-core/kern/i386/tsc_pmtimer.c ++++ b/grub-core/kern/i386/tsc_pmtimer.c +@@ -28,40 +28,101 @@ + #include + #include + ++/* ++ * Define GRUB_PMTIMER_IGNORE_BAD_READS if you're trying to test a timer that's ++ * present but doesn't keep time well. ++ */ ++// #define GRUB_PMTIMER_IGNORE_BAD_READS ++ + grub_uint64_t + grub_pmtimer_wait_count_tsc (grub_port_t pmtimer, + grub_uint16_t num_pm_ticks) + { + grub_uint32_t start; +- grub_uint32_t last; +- grub_uint32_t cur, end; ++ grub_uint64_t cur, end; + grub_uint64_t start_tsc; + grub_uint64_t end_tsc; +- int num_iter = 0; ++ unsigned int num_iter = 0; ++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS ++ int bad_reads = 0; ++#endif + +- start = grub_inl (pmtimer) & 0xffffff; +- last = start; ++ /* ++ * Some timers are 24-bit and some are 32-bit, but it doesn't make much ++ * difference to us. Caring which one we have isn't really worth it since ++ * the low-order digits will give us enough data to calibrate TSC. So just ++ * mask the top-order byte off. ++ */ ++ cur = start = grub_inl (pmtimer) & 0xffffffUL; + end = start + num_pm_ticks; + start_tsc = grub_get_tsc (); + while (1) + { +- cur = grub_inl (pmtimer) & 0xffffff; +- if (cur < last) +- cur |= 0x1000000; +- num_iter++; ++ cur &= 0xffffffffff000000ULL; ++ cur |= grub_inl (pmtimer) & 0xffffffUL; ++ ++ end_tsc = grub_get_tsc(); ++ ++#ifndef GRUB_PMTIMER_IGNORE_BAD_READS ++ /* ++ * If we get 10 reads in a row that are obviously dead pins, there's no ++ * reason to do this thousands of times. ++ */ ++ if (cur == 0xffffffUL || cur == 0) ++ { ++ bad_reads++; ++ grub_dprintf ("pmtimer", ++ "pmtimer: 0x%"PRIxGRUB_UINT64_T" bad_reads: %d\n", ++ cur, bad_reads); ++ grub_dprintf ("pmtimer", "timer is broken; giving up.\n"); ++ ++ if (bad_reads == 10) ++ return 0; ++ } ++#endif ++ ++ if (cur < start) ++ cur += 0x1000000; ++ + if (cur >= end) + { +- end_tsc = grub_get_tsc (); ++ grub_dprintf ("pmtimer", "pmtimer delta is 0x%"PRIxGRUB_UINT64_T"\n", ++ cur - start); ++ grub_dprintf ("pmtimer", "tsc delta is 0x%"PRIxGRUB_UINT64_T"\n", ++ end_tsc - start_tsc); + return end_tsc - start_tsc; + } +- /* Check for broken PM timer. +- 50000000 TSCs is between 5 ms (10GHz) and 200 ms (250 MHz) +- if after this time we still don't have 1 ms on pmtimer, then +- pmtimer is broken. ++ ++ /* ++ * Check for broken PM timer. 1ms at 10GHz should be 1E+7 TSCs; at ++ * 250MHz it should be 2.5E6. So if after 4E+7 TSCs on a 10GHz machine, ++ * we should have seen pmtimer show 4ms of change (i.e. cur =~ ++ * start+14320); on a 250MHz machine that should be 16ms (start+57280). ++ * If after this a time we still don't have 1ms on pmtimer, then pmtimer ++ * is broken. ++ * ++ * Likewise, if our code is perfectly efficient and introduces no delays ++ * whatsoever, on a 10GHz system we should see a TSC delta of 3580 in ++ * ~3580 iterations. On a 250MHz machine that should be ~900 iterations. ++ * ++ * With those factors in mind, there are two limits here. There's a hard ++ * limit here at 8x our desired pm timer delta, picked as an arbitrarily ++ * large value that's still not a lot of time to humans, because if we ++ * get that far this is either an implausibly fast machine or the pmtimer ++ * is not running. And there's another limit on 4x our 10GHz tsc delta ++ * without seeing cur converge on our target value. + */ +- if ((num_iter & 0xffffff) == 0 && grub_get_tsc () - start_tsc > 5000000) { +- return 0; +- } ++ if ((++num_iter > (grub_uint32_t)num_pm_ticks << 3UL) || ++ end_tsc - start_tsc > 40000000) ++ { ++ grub_dprintf ("pmtimer", ++ "pmtimer delta is 0x%"PRIxGRUB_UINT64_T" (%u iterations)\n", ++ cur - start, num_iter); ++ grub_dprintf ("pmtimer", ++ "tsc delta is implausible: 0x%"PRIxGRUB_UINT64_T"\n", ++ end_tsc - start_tsc); ++ return 0; ++ } + } + } + +@@ -74,12 +135,20 @@ grub_tsc_calibrate_from_pmtimer (void) + + fadt = grub_acpi_find_fadt (); + if (!fadt) +- return 0; ++ { ++ grub_dprintf ("pmtimer", "No FADT found; not using pmtimer.\n"); ++ return 0; ++ } + pmtimer = fadt->pmtimer; + if (!pmtimer) +- return 0; ++ { ++ grub_dprintf ("pmtimer", "FADT does not specify pmtimer; skipping.\n"); ++ return 0; ++ } + +- /* It's 3.579545 MHz clock. Wait 1 ms. */ ++ /* ++ * It's 3.579545 MHz clock. Wait 1 ms. ++ */ + tsc_diff = grub_pmtimer_wait_count_tsc (pmtimer, 3580); + if (tsc_diff == 0) + return 0; diff --git a/SOURCES/0057-align-struct-efi_variable-better.patch b/SOURCES/0057-align-struct-efi_variable-better.patch new file mode 100644 index 0000000..361cb13 --- /dev/null +++ b/SOURCES/0057-align-struct-efi_variable-better.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 27 Feb 2018 13:55:35 -0500 +Subject: [PATCH] align struct efi_variable better... + +--- + include/grub/efiemu/runtime.h | 2 +- + include/grub/types.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/grub/efiemu/runtime.h b/include/grub/efiemu/runtime.h +index 36d2dedf47..9d93ba88ba 100644 +--- a/include/grub/efiemu/runtime.h ++++ b/include/grub/efiemu/runtime.h +@@ -33,5 +33,5 @@ struct efi_variable + grub_uint32_t namelen; + grub_uint32_t size; + grub_efi_uint32_t attributes; +-} GRUB_PACKED; ++} GRUB_PACKED GRUB_ALIGNED(8); + #endif /* ! GRUB_EFI_EMU_RUNTIME_HEADER */ +diff --git a/include/grub/types.h b/include/grub/types.h +index 0a3ff15913..ba446d9904 100644 +--- a/include/grub/types.h ++++ b/include/grub/types.h +@@ -29,6 +29,7 @@ + #else + #define GRUB_PACKED __attribute__ ((packed)) + #endif ++#define GRUB_ALIGNED(x) __attribute__((aligned (x))) + + #ifdef GRUB_BUILD + # define GRUB_CPU_SIZEOF_VOID_P BUILD_SIZEOF_VOID_P diff --git a/SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch b/SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch new file mode 100644 index 0000000..3e5b230 --- /dev/null +++ b/SOURCES/0058-Add-BLS-support-to-grub-mkconfig.patch @@ -0,0 +1,382 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 9 Dec 2016 15:40:29 -0500 +Subject: [PATCH] Add BLS support to grub-mkconfig + +GRUB now has BootLoaderSpec support, the user can choose to use this by +setting GRUB_ENABLE_BLSCFG to true in /etc/default/grub. On this setup, +the boot menu entries are not added to the grub.cfg, instead BLS config +files are parsed by blscfg command and the entries created dynamically. + +A 10_linux_bls grub.d snippet to generate menu entries from BLS files +is also added that can be used on platforms where the bootloader doesn't +have BLS support and only can parse a normal grub configuration file. + +Portions of the 10_linux_bls were taken from the ostree-grub-generator +script that's included in the OSTree project. + +Fixes to support multi-devices and generate a BLS section even if no +kernels are found in the boot directory were proposed by Yclept Nemo +and Tom Gundersen respectively. + +Signed-off-by: Peter Jones +[javierm: remove outdated URL for BLS document] +Signed-off-by: Javier Martinez Canillas +[iwienand@redhat.com: skip machine ID check when updating entries] +Signed-off-by: Ian Wienand +[rharwood: use sort(1), commit message composits, drop man pages] +Signed-off-by: Robbie Harwood +--- + util/grub-mkconfig.in | 9 +- + util/grub-mkconfig_lib.in | 22 ++++- + util/grub.d/10_linux.in | 218 +++++++++++++++++++++++++++++++++++++++++++++- + 3 files changed, 243 insertions(+), 6 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 535c0f0249..f55339a3f6 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -50,6 +50,8 @@ grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" + export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + ++export GRUB_GRUBENV_UPDATE="yes" ++ + . "${pkgdatadir}/grub-mkconfig_lib" + + # Usage: usage +@@ -59,6 +61,7 @@ usage () { + gettext "Generate a grub config file"; echo + echo + print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" ++ print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")" + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + echo +@@ -94,6 +97,9 @@ do + --output=*) + grub_cfg=`echo "$option" | sed 's/--output=//'` + ;; ++ --no-grubenv-update) ++ GRUB_GRUBENV_UPDATE="no" ++ ;; + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage +@@ -253,7 +259,8 @@ export GRUB_DEFAULT \ + GRUB_OS_PROBER_SKIP_LIST \ + GRUB_DISABLE_SUBMENU \ + GRUB_DEFAULT_DTB \ +- SUSE_BTRFS_SNAPSHOT_BOOTING ++ SUSE_BTRFS_SNAPSHOT_BOOTING \ ++ GRUB_ENABLE_BLSCFG + + if test "x${grub_cfg}" != "x"; then + rm -f "${grub_cfg}.new" +diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in +index 5e96f6cc5d..301d8a8a1e 100644 +--- a/util/grub-mkconfig_lib.in ++++ b/util/grub-mkconfig_lib.in +@@ -30,6 +30,9 @@ fi + if test "x$grub_file" = x; then + grub_file="${bindir}/@grub_file@" + fi ++if test "x$grub_editenv" = x; then ++ grub_editenv="${bindir}/@grub_editenv@" ++fi + if test "x$grub_mkrelpath" = x; then + grub_mkrelpath="${bindir}/@grub_mkrelpath@" + fi +@@ -122,8 +125,19 @@ EOF + fi + } + ++prepare_grub_to_access_device_with_variable () ++{ ++ device_variable="$1" ++ shift ++ prepare_grub_to_access_device "$@" ++ unset "device_variable" ++} ++ + prepare_grub_to_access_device () + { ++ if [ -z "$device_variable" ]; then ++ device_variable="root" ++ fi + old_ifs="$IFS" + IFS=' + ' +@@ -158,18 +172,18 @@ prepare_grub_to_access_device () + # otherwise set root as per value in device.map. + fs_hint="`"${grub_probe}" --device $@ --target=compatibility_hint`" + if [ "x$fs_hint" != x ]; then +- echo "set root='$fs_hint'" ++ echo "set ${device_variable}='$fs_hint'" + fi + if [ "x${GRUB_DISABLE_UUID}" != "xtrue" ] && fs_uuid="`"${grub_probe}" --device $@ --target=fs_uuid 2> /dev/null`" ; then + hints="`"${grub_probe}" --device $@ --target=hints_string 2> /dev/null`" || hints= + if [ "x$hints" != x ]; then + echo "if [ x\$feature_platform_search_hint = xy ]; then" +- echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}" ++ echo " search --no-floppy --fs-uuid --set=${device_variable} ${hints} ${fs_uuid}" + echo "else" +- echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}" ++ echo " search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" + echo "fi" + else +- echo "search --no-floppy --fs-uuid --set=root ${fs_uuid}" ++ echo "search --no-floppy --fs-uuid --set=${device_variable} ${fs_uuid}" + fi + fi + IFS="$old_ifs" +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 7bb3a211a7..2851952659 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -82,6 +82,218 @@ case x"$GRUB_FS" in + ;; + esac + ++populate_header_warn() ++{ ++if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then ++ bls_parser="10_linux script" ++else ++ bls_parser="blscfg command" ++fi ++cat </dev/null)) || : ++ ++ echo "${files[@]}" ++} ++ ++update_bls_cmdline() ++{ ++ local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++ local -a files=($(get_sorted_bls)) ++ ++ for bls in "${files[@]}"; do ++ local options="${cmdline}" ++ if [ -z "${bls##*debug*}" ]; then ++ options="${options} ${GRUB_CMDLINE_LINUX_DEBUG}" ++ fi ++ options="$(echo "${options}" | sed -e 's/\//\\\//g')" ++ sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf" ++ done ++} ++ ++populate_menu() ++{ ++ local -a files=($(get_sorted_bls)) ++ ++ gettext_printf "Generating boot entries from BLS files...\n" >&2 ++ ++ for bls in "${files[@]}"; do ++ read_config "${blsdir}/${bls}.conf" ++ ++ menu="${menu}menuentry '${title}' ${grub_arg} --id=${bls} {\n" ++ menu="${menu}\t linux ${linux} ${options}\n" ++ if [ -n "${initrd}" ] ; then ++ menu="${menu}\t initrd ${boot_prefix}${initrd}\n" ++ fi ++ menu="${menu}}\n\n" ++ done ++ # The printf command seems to be more reliable across shells for special character (\n, \t) evaluation ++ printf "$menu" ++} ++ ++# Make BLS the default if GRUB_ENABLE_BLSCFG was not set and grubby is not installed. ++if [ -z "${GRUB_ENABLE_BLSCFG}" ] && ! command -v new-kernel-pkg >/dev/null; then ++ GRUB_ENABLE_BLSCFG="true" ++fi ++ ++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]; then ++ if [ x$dirname = x/ ]; then ++ if [ -z "${prepare_root_cache}" ]; then ++ prepare_grub_to_access_device ${GRUB_DEVICE} ++ fi ++ else ++ if [ -z "${prepare_boot_cache}" ]; then ++ prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} ++ fi ++ fi ++ ++ if [ -d /sys/firmware/efi ]; then ++ bootefi_device="`${grub_probe} --target=device /boot/efi/`" ++ prepare_grub_to_access_device_with_variable boot ${bootefi_device} ++ else ++ boot_device="`${grub_probe} --target=device /boot/`" ++ prepare_grub_to_access_device_with_variable boot ${boot_device} ++ fi ++ ++ arch="$(uname -m)" ++ if [ "x${arch}" = "xppc64le" ] && [ -d /sys/firmware/opal ]; then ++ ++ BLS_POPULATE_MENU="true" ++ petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot" ++ ++ if test -e ${petitboot_path}; then ++ read -r -d '' petitboot_version < ${petitboot_path} ++ petitboot_version="$(echo ${petitboot_version//v})" ++ ++ if test -n ${petitboot_version}; then ++ major_version="$(echo ${petitboot_version} | cut -d . -f1)" ++ minor_version="$(echo ${petitboot_version} | cut -d . -f2)" ++ ++ re='^[0-9]+$' ++ if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] && ++ ([[ ${major_version} -gt 1 ]] || ++ [[ ${major_version} -eq 1 && ++ ${minor_version} -ge 8 ]]); then ++ BLS_POPULATE_MENU="false" ++ fi ++ fi ++ fi ++ fi ++ ++ populate_header_warn ++ ++ cat << EOF ++# The kernelopts variable should be defined in the grubenv file. But to ensure that menu ++# entries populated from BootLoaderSpec files that use this variable work correctly even ++# without a grubenv file, define a fallback kernelopts variable if this has not been set. ++# ++# The kernelopts variable in the grubenv file can be modified using the grubby tool or by ++# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX ++# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both ++# the kernelopts variable in the grubenv file and the fallback kernelopts variable. ++if [ -z "\${kernelopts}" ]; then ++ set kernelopts="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" ++fi ++EOF ++ ++ update_bls_cmdline ++ ++ if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then ++ populate_menu ++ else ++ cat << EOF ++ ++insmod blscfg ++blscfg ++EOF ++ fi ++ ++ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ blsdir="/boot/loader/entries" ++ [ -d "${blsdir}" ] && GRUB_BLS_FS="$(${grub_probe} --target=fs ${blsdir})" ++ if [ "x${GRUB_BLS_FS}" = "xbtrfs" ] || [ "x${GRUB_BLS_FS}" = "xzfs" ]; then ++ blsdir=$(make_system_path_relative_to_its_root "${blsdir}") ++ if [ "x${blsdir}" != "x/loader/entries" ] && [ "x${blsdir}" != "x/boot/loader/entries" ]; then ++ ${grub_editenv} - set blsdir="${blsdir}" ++ fi ++ fi ++ ++ if [ -n "${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ]; then ++ ${grub_editenv} - set early_initrd="${GRUB_EARLY_INITRD_LINUX_CUSTOM}" ++ fi ++ ++ if [ -n "${GRUB_DEFAULT_DTB}" ]; then ++ ${grub_editenv} - set devicetree="${GRUB_DEFAULT_DTB}" ++ fi ++ ++ if [ -n "${GRUB_SAVEDEFAULT}" ]; then ++ ${grub_editenv} - set save_default="${GRUB_SAVEDEFAULT}" ++ fi ++ fi ++ ++ exit 0 ++fi ++ + mktitle () + { + local title_type +@@ -121,6 +333,7 @@ linux_entry () + if [ -z "$boot_device_id" ]; then + boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" + fi ++ + if [ x$type != xsimple ] ; then + title=$(mktitle "$type" "$version") + if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then +@@ -231,6 +444,7 @@ is_top_level=true + while [ "x$list" != "x" ] ; do + linux=`version_find_latest $list` + gettext_printf "Found linux image: %s\n" "$linux" >&2 ++ + basename=`basename $linux` + dirname=`dirname $linux` + rel_dirname=`make_system_path_relative_to_its_root $dirname` +@@ -269,7 +483,9 @@ while [ "x$list" != "x" ] ; do + for i in ${initrd}; do + initrd_display="${initrd_display} ${dirname}/${i}" + done +- gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 ++ if [ "x${GRUB_ENABLE_BLSCFG}" != "xtrue" ]; then ++ gettext_printf "Found initrd image: %s\n" "$(echo $initrd_display)" >&2 ++ fi + fi + + fdt= diff --git a/SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch b/SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch new file mode 100644 index 0000000..1ac900c --- /dev/null +++ b/SOURCES/0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch @@ -0,0 +1,26 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Feb 2018 11:16:28 +0100 +Subject: [PATCH] Don't attempt to backtrace on grub_abort() for grub-emu + +The emu platform doesn't have a grub_backtrace() implementation, so this +causes a build error. Don't attempt to call this when building grub-emu. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/kern/misc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index a3e215155b..c60601b699 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1201,7 +1201,7 @@ static void __attribute__ ((noreturn)) + grub_abort (void) + { + #ifndef GRUB_UTIL +-#if defined(__i386__) || defined(__x86_64__) ++#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU) + grub_backtrace(); + #endif + #endif diff --git a/SOURCES/0060-Add-grub2-switch-to-blscfg.patch b/SOURCES/0060-Add-grub2-switch-to-blscfg.patch new file mode 100644 index 0000000..e316116 --- /dev/null +++ b/SOURCES/0060-Add-grub2-switch-to-blscfg.patch @@ -0,0 +1,395 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 15 Mar 2018 14:12:40 -0400 +Subject: [PATCH] Add grub2-switch-to-blscfg + +Signed-off-by: Peter Jones +Signed-off-by: Javier Martinez Canillas +[jhlavac: Use ${etcdefaultgrub} instead of /etc/default/grub] +Signed-off-by: Jan Hlavac +[rharwood: skip on ostree installations, migrate man to h2m] +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 7 + + docs/man/grub-switch-to-blscfg.h2m | 2 + + util/grub-set-password.in | 2 +- + util/grub-switch-to-blscfg.in | 317 +++++++++++++++++++++++++++++++++++++ + util/grub.d/10_linux.in | 2 +- + 5 files changed, 328 insertions(+), 2 deletions(-) + create mode 100644 docs/man/grub-switch-to-blscfg.h2m + create mode 100644 util/grub-switch-to-blscfg.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index 18a9242776..88f55e35c4 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1348,6 +1348,13 @@ program = { + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; + ++script = { ++ name = grub-switch-to-blscfg; ++ common = util/grub-switch-to-blscfg.in; ++ mansection = 8; ++ installdir = sbin; ++}; ++ + program = { + name = grub-glue-efi; + mansection = 1; +diff --git a/docs/man/grub-switch-to-blscfg.h2m b/docs/man/grub-switch-to-blscfg.h2m +new file mode 100644 +index 0000000000..fa341426a5 +--- /dev/null ++++ b/docs/man/grub-switch-to-blscfg.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-switch-to-blscfg \- switch to using BLS config files +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +index 5ebf50576d..c0b5ebbfdc 100644 +--- a/util/grub-set-password.in ++++ b/util/grub-set-password.in +@@ -1,6 +1,6 @@ + #!/bin/sh -e + +-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/') ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') + if [ -d /sys/firmware/efi/efivars/ ]; then + grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` + else +diff --git a/util/grub-switch-to-blscfg.in b/util/grub-switch-to-blscfg.in +new file mode 100644 +index 0000000000..a851424beb +--- /dev/null ++++ b/util/grub-switch-to-blscfg.in +@@ -0,0 +1,317 @@ ++#! /bin/sh ++# ++# Set a default boot entry for GRUB. ++# Copyright (C) 2004,2009 Free Software Foundation, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++#set -eu ++ ++# Initialize some variables. ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++sbindir=@sbindir@ ++bindir=@bindir@ ++sysconfdir="@sysconfdir@" ++PACKAGE_NAME=@PACKAGE_NAME@ ++PACKAGE_VERSION=@PACKAGE_VERSION@ ++datarootdir="@datarootdir@" ++datadir="@datadir@" ++if [ ! -v pkgdatadir ]; then ++ pkgdatadir="${datadir}/@PACKAGE@" ++fi ++ ++self=`basename $0` ++ ++grub_get_kernel_settings="${sbindir}/@grub_get_kernel_settings@" ++grub_editenv=${bindir}/@grub_editenv@ ++etcdefaultgrub=/etc/default/grub ++ ++eval "$("${grub_get_kernel_settings}")" || true ++ ++EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') ++if [ -d /sys/firmware/efi/efivars/ ]; then ++ startlink=/etc/grub2-efi.cfg ++ grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` ++else ++ startlink=/etc/grub2.cfg ++ grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` ++fi ++ ++blsdir=`echo "/@bootdirname@/loader/entries" | sed 's,//*,/,g'` ++ ++backupsuffix=.bak ++ ++arch="$(uname -m)" ++ ++export TEXTDOMAIN=@PACKAGE@ ++export TEXTDOMAINDIR="@localedir@" ++ ++. "${pkgdatadir}/grub-mkconfig_lib" ++ ++# Usage: usage ++# Print the usage. ++usage () { ++ gettext_printf "Usage: %s\n" "$self" ++ gettext "Switch to BLS config files.\n"; echo ++ echo ++ print_option_help "-h, --help" "$(gettext "print this message and exit")" ++ print_option_help "-V, --version" "$(gettext "print the version information and exit")" ++ echo ++ print_option_help "--backup-suffix=$(gettext "SUFFIX")" "$backupsuffix" ++ print_option_help "--bls-directory=$(gettext "DIR")" "$blsdir" ++ print_option_help "--config-file=$(gettext "FILE")" "$startlink" ++ print_option_help "--grub-defaults=$(gettext "FILE")" "$etcdefaultgrub" ++ print_option_help "--grub-directory=$(gettext "DIR")" "$grubdir" ++ # echo ++ # gettext "Report bugs to ."; echo ++} ++ ++argument () { ++ opt=$1 ++ shift ++ ++ if test $# -eq 0; then ++ gettext_printf "%s: option requires an argument -- \`%s'\n" "$self" "$opt" 1>&2 ++ exit 1 ++ fi ++ echo $1 ++} ++ ++# Check the arguments. ++while test $# -gt 0 ++do ++ option=$1 ++ shift ++ ++ case "$option" in ++ -h | --help) ++ usage ++ exit 0 ;; ++ -V | --version) ++ echo "$self (${PACKAGE_NAME}) ${PACKAGE_VERSION}" ++ exit 0 ;; ++ ++ --backup-suffix) ++ backupsuffix=`argument $option "$@"` ++ shift ++ ;; ++ --backup-suffix=*) ++ backupsuffix=`echo "$option" | sed 's/--backup-suffix=//'` ++ ;; ++ ++ --bls-directory) ++ blsdir=`argument $option "$@"` ++ shift ++ ;; ++ --bls-directory=*) ++ blsdir=`echo "$option" | sed 's/--bls-directory=//'` ++ ;; ++ ++ --config-file) ++ startlink=`argument $option "$@"` ++ shift ++ ;; ++ --config-file=*) ++ startlink=`echo "$option" | sed 's/--config-file=//'` ++ ;; ++ ++ --grub-defaults) ++ etcdefaultgrub=`argument $option "$@"` ++ shift ++ ;; ++ --grub-defaults=*) ++ etcdefaultgrub=`echo "$option" | sed 's/--grub-defaults=//'` ++ ;; ++ ++ --grub-directory) ++ grubdir=`argument $option "$@"` ++ shift ++ ;; ++ --grub-directory=*) ++ grubdir=`echo "$option" | sed 's/--grub-directory=//'` ++ ;; ++ ++ *) ++ gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 ++ usage ++ exit 1 ++ ;; ++ esac ++done ++ ++find_grub_cfg() { ++ local candidate="" ++ while [ -e "${candidate}" -o $# -gt 0 ] ++ do ++ if [ ! -e "${candidate}" ] ; then ++ candidate="$1" ++ shift ++ fi ++ ++ if [ -L "${candidate}" ]; then ++ candidate="$(realpath "${candidate}")" ++ fi ++ ++ if [ -f "${candidate}" ]; then ++ export GRUB_CONFIG_FILE="${candidate}" ++ return 0 ++ fi ++ done ++ return 1 ++} ++ ++if ! find_grub_cfg ${startlink} ${grubdir}/grub.cfg ; then ++ gettext_printf "Couldn't find config file\n" 1>&2 ++ exit 1 ++fi ++ ++if [ ! -d "${blsdir}" ]; then ++ install -m 700 -d "${blsdir}" ++fi ++ ++if [ -f /etc/machine-id ]; then ++ MACHINE_ID=$(cat /etc/machine-id) ++else ++ MACHINE_ID=$(dmesg | sha256sum) ++fi ++ ++mkbls() { ++ local kernelver=$1 && shift ++ local datetime=$1 && shift ++ local kernelopts=$1 && shift ++ ++ local debugname="" ++ local debugid="" ++ local flavor="" ++ ++ if [ "$kernelver" == *\+* ] ; then ++ local flavor=-"${kernelver##*+}" ++ if [ "${flavor}" == "-debug" ]; then ++ local debugname=" with debugging" ++ local debugid="-debug" ++ fi ++ fi ++ ( ++ source /etc/os-release ++ ++ cat <"${bls_target}" ++ ++ if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then ++ bls_debug="$(echo ${bls_target} | sed -e "s/${kernelver}/${kernelver}~debug/")" ++ cp -aT "${bls_target}" "${bls_debug}" ++ title="$(grep '^title[ \t]' "${bls_debug}" | sed -e 's/^title[ \t]*//')" ++ options="$(echo "${cmdline} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')" ++ sed -i -e "s/^title.*/title ${title}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${bls_debug}" ++ sed -i -e "s/^options.*/options ${options}/" "${bls_debug}" ++ fi ++ done ++ ++ if [ -f "/boot/vmlinuz-0-rescue-${MACHINE_ID}" ]; then ++ mkbls "0-rescue-${MACHINE_ID}" "0" "${bootprefix}" >"${blsdir}/${MACHINE_ID}-0-rescue.conf" ++ fi ++} ++ ++# The grub2 EFI binary is not copied to the ESP as a part of an ostree ++# transaction. Make sure a grub2 version with BLS support is installed ++# but only do this if the blsdir is not set, to make sure that the BLS ++# parsing module will search for the BLS snippets in the default path. ++if test -f /run/ostree-booted && test -d /sys/firmware/efi/efivars && \ ++ ! ${grub_editenv} - list | grep -q blsdir && \ ++ mountpoint -q /boot; then ++ grub_binary="$(find /usr/lib/ostree-boot/efi/EFI/${EFIDIR}/ -name grub*.efi)" ++ install -m 700 ${grub_binary} ${grubdir} || exit 1 ++ # Create a hidden file to indicate that grub2 now has BLS support. ++ touch /boot/grub2/.grub2-blscfg-supported ++fi ++ ++GENERATE=0 ++if grep '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" \ ++ | grep -vq '^GRUB_ENABLE_BLSCFG="*true"*\s*$' ; then ++ if ! sed -i"${backupsuffix}" \ ++ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=true,' \ ++ "${etcdefaultgrub}" ; then ++ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" ++ exit 1 ++ fi ++ GENERATE=1 ++elif ! grep -q '^GRUB_ENABLE_BLSCFG=.*' "${etcdefaultgrub}" ; then ++ if ! echo 'GRUB_ENABLE_BLSCFG=true' >> "${etcdefaultgrub}" ; then ++ gettext_printf "Updating %s failed\n" "${etcdefaultgrub}" ++ exit 1 ++ fi ++ GENERATE=1 ++fi ++ ++if [ "${GENERATE}" -eq 1 ] ; then ++ copy_bls ++ ++ if [ $arch = "x86_64" ] && [ ! -d /sys/firmware/efi ]; then ++ mod_dir="i386-pc" ++ elif [ $arch = "ppc64" -o $arch = "ppc64le" ] && [ ! -d /sys/firmware/opal ]; then ++ mod_dir="powerpc-ieee1275" ++ fi ++ ++ if [ -n "${mod_dir}" ]; then ++ for mod in blscfg increment; do ++ install -m 700 ${prefix}/lib/grub/${mod_dir}/${mod}.mod ${grubdir}/$mod_dir/ || exit 1 ++ done ++ fi ++ ++ cp -af "${GRUB_CONFIG_FILE}" "${GRUB_CONFIG_FILE}${backupsuffix}" ++ if ! grub2-mkconfig -o "${GRUB_CONFIG_FILE}" ; then ++ install -m 700 "${GRUB_CONFIG_FILE}${backupsuffix}" "${GRUB_CONFIG_FILE}" ++ sed -i"${backupsuffix}" \ ++ -e 's,^GRUB_ENABLE_BLSCFG=.*,GRUB_ENABLE_BLSCFG=false,' \ ++ "${etcdefaultgrub}" ++ gettext_printf "Updating %s failed\n" "${GRUB_CONFIG_FILE}" ++ exit 1 ++ fi ++fi ++ ++# Bye. ++exit 0 +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 2851952659..e490e1a43a 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -138,7 +138,7 @@ blsdir="/boot/loader/entries" + + get_sorted_bls() + { +- if ! [ -d "${blsdir}" ]; then ++ if ! [ -d "${blsdir}" ] || [ -f /run/ostree-booted ] || [ -d /ostree/repo ]; then + return + fi + diff --git a/SOURCES/0061-make-better-backtraces.patch b/SOURCES/0061-make-better-backtraces.patch new file mode 100644 index 0000000..7fdcaf7 --- /dev/null +++ b/SOURCES/0061-make-better-backtraces.patch @@ -0,0 +1,910 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 9 Jul 2019 17:05:03 +0200 +Subject: [PATCH] make better backtraces + +Signed-off-by: Peter Jones +--- + Makefile.util.def | 6 ++ + grub-core/Makefile.core.def | 16 ++-- + grub-core/{lib => commands}/backtrace.c | 2 +- + grub-core/gdb/cstub.c | 1 - + grub-core/kern/arm64/backtrace.c | 94 ++++++++++++++++++++++++ + grub-core/kern/backtrace.c | 97 +++++++++++++++++++++++++ + grub-core/kern/dl.c | 45 ++++++++++++ + grub-core/kern/i386/backtrace.c | 125 ++++++++++++++++++++++++++++++++ + grub-core/kern/i386/pc/init.c | 4 +- + grub-core/kern/ieee1275/init.c | 1 - + grub-core/kern/misc.c | 13 ++-- + grub-core/kern/mm.c | 6 +- + grub-core/lib/arm64/backtrace.c | 62 ---------------- + grub-core/lib/i386/backtrace.c | 78 -------------------- + include/grub/backtrace.h | 10 ++- + include/grub/dl.h | 2 + + include/grub/kernel.h | 3 + + grub-core/kern/arm/efi/startup.S | 2 + + grub-core/kern/arm/startup.S | 2 + + grub-core/kern/arm64/efi/startup.S | 2 + + grub-core/kern/i386/qemu/startup.S | 3 +- + grub-core/kern/ia64/efi/startup.S | 3 +- + grub-core/kern/sparc64/ieee1275/crt0.S | 3 +- + grub-core/Makefile.am | 1 + + 24 files changed, 414 insertions(+), 167 deletions(-) + rename grub-core/{lib => commands}/backtrace.c (98%) + create mode 100644 grub-core/kern/arm64/backtrace.c + create mode 100644 grub-core/kern/backtrace.c + create mode 100644 grub-core/kern/i386/backtrace.c + delete mode 100644 grub-core/lib/arm64/backtrace.c + delete mode 100644 grub-core/lib/i386/backtrace.c + +diff --git a/Makefile.util.def b/Makefile.util.def +index 88f55e35c4..bda9fd1211 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -51,6 +51,12 @@ library = { + common = grub-core/partmap/msdos.c; + common = grub-core/fs/proc.c; + common = grub-core/fs/archelp.c; ++ common = grub-core/kern/backtrace.c; ++ ++ x86 = grub-core/kern/i386/backtrace.c; ++ i386_xen = grub-core/kern/i386/backtrace.c; ++ x86_64_xen = grub-core/kern/i386/backtrace.c; ++ arm64 = grub-core/kern/arm64/backtrace.c; + }; + + library = { +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 058c88ac3a..52ec0fafcd 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -142,6 +142,12 @@ kernel = { + common = kern/rescue_reader.c; + common = kern/term.c; + common = kern/verifiers.c; ++ common = kern/backtrace.c; ++ ++ x86 = kern/i386/backtrace.c; ++ i386_xen = kern/i386/backtrace.c; ++ x86_64_xen = kern/i386/backtrace.c; ++ arm64 = kern/arm64/backtrace.c; + + noemu = kern/compiler-rt.c; + noemu = kern/mm.c; +@@ -188,9 +194,6 @@ kernel = { + + softdiv = lib/division.c; + +- x86 = lib/i386/backtrace.c; +- x86 = lib/backtrace.c; +- + i386 = kern/i386/dl.c; + i386_xen = kern/i386/dl.c; + i386_xen_pvh = kern/i386/dl.c; +@@ -2399,15 +2402,12 @@ module = { + + module = { + name = backtrace; +- x86 = lib/i386/backtrace.c; +- i386_xen_pvh = lib/i386/backtrace.c; +- i386_xen = lib/i386/backtrace.c; +- x86_64_xen = lib/i386/backtrace.c; +- common = lib/backtrace.c; ++ common = commands/backtrace.c; + enable = x86; + enable = i386_xen_pvh; + enable = i386_xen; + enable = x86_64_xen; ++ enable = arm64; + }; + + module = { +diff --git a/grub-core/lib/backtrace.c b/grub-core/commands/backtrace.c +similarity index 98% +rename from grub-core/lib/backtrace.c +rename to grub-core/commands/backtrace.c +index c0ad6ab8be..8b5ec3913b 100644 +--- a/grub-core/lib/backtrace.c ++++ b/grub-core/commands/backtrace.c +@@ -54,7 +54,7 @@ grub_cmd_backtrace (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char **args __attribute__ ((unused))) + { +- grub_backtrace (); ++ grub_backtrace (1); + return 0; + } + +diff --git a/grub-core/gdb/cstub.c b/grub-core/gdb/cstub.c +index b64acd70fe..99281472d3 100644 +--- a/grub-core/gdb/cstub.c ++++ b/grub-core/gdb/cstub.c +@@ -215,7 +215,6 @@ grub_gdb_trap (int trap_no) + grub_printf ("Unhandled exception 0x%x at ", trap_no); + grub_backtrace_print_address ((void *) grub_gdb_regs[PC]); + grub_printf ("\n"); +- grub_backtrace_pointer ((void *) grub_gdb_regs[EBP]); + grub_fatal ("Unhandled exception"); + } + +diff --git a/grub-core/kern/arm64/backtrace.c b/grub-core/kern/arm64/backtrace.c +new file mode 100644 +index 0000000000..019c6fdfef +--- /dev/null ++++ b/grub-core/kern/arm64/backtrace.c +@@ -0,0 +1,94 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++struct fplr ++{ ++ void *lr; ++ struct fplr *fp; ++}; ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++{ ++ unsigned int x = 0; ++ struct fplr *fplr = (struct fplr *)frame; ++ ++ while (fplr) ++ { ++ const char *name = NULL; ++ char *addr = NULL; ++ ++ grub_dprintf("backtrace", "fp is %p next_fp is %p\n", ++ fplr, fplr->fp); ++ ++ if (x >= skip) ++ { ++ name = grub_get_symbol_by_addr (fplr->lr, 1); ++ if (name) ++ addr = grub_resolve_symbol (name); ++ grub_backtrace_print_address (fplr->lr); ++ ++ if (addr && addr != fplr->lr) ++ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, ++ (void *)((grub_uint64_t)fplr->lr - (grub_uint64_t)addr)); ++ else ++ grub_printf(" %s() %p \n", name ? name : "unknown", addr); ++ ++ } ++ ++ x += 1; ++ ++ if (fplr->fp < fplr || ++ (grub_uint64_t)fplr->fp - (grub_uint64_t)fplr > MAX_STACK_FRAME || ++ fplr->fp == fplr) ++ { ++ break; ++ } ++ fplr = fplr->fp; ++ } ++} ++ ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.quad .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.quad .data\n" ++ ); ++ ++extern grub_uint64_t _text; ++extern grub_uint64_t _data; ++ ++void ++grub_backtrace_arch (unsigned int skip) ++{ ++ grub_printf ("Backtrace (.text %p .data %p):\n", ++ (void *)_text, (void *)_data); ++ skip += 1; ++ grub_backtrace_pointer(__builtin_frame_address(0), skip); ++} +diff --git a/grub-core/kern/backtrace.c b/grub-core/kern/backtrace.c +new file mode 100644 +index 0000000000..4a82e865cc +--- /dev/null ++++ b/grub-core/kern/backtrace.c +@@ -0,0 +1,97 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static void ++grub_backtrace_print_address_default (void *addr) ++{ ++#ifndef GRUB_UTIL ++ grub_dl_t mod; ++ void *start_addr; ++ ++ FOR_DL_MODULES (mod) ++ { ++ grub_dl_segment_t segment; ++ for (segment = mod->segment; segment; segment = segment->next) ++ if (segment->addr <= addr && (grub_uint8_t *) segment->addr ++ + segment->size > (grub_uint8_t *) addr) ++ { ++ grub_printf ("%s.%x+%" PRIxGRUB_SIZE, mod->name, ++ segment->section, ++ (grub_size_t) ++ ((grub_uint8_t *)addr - (grub_uint8_t *)segment->addr)); ++ return; ++ } ++ } ++ ++ start_addr = grub_resolve_symbol ("_start"); ++ if (start_addr && start_addr < addr) ++ grub_printf ("kernel+%" PRIxGRUB_SIZE, ++ (grub_size_t) ++ ((grub_uint8_t *)addr - (grub_uint8_t *)start_addr)); ++ else ++#endif ++ grub_printf ("%p", addr); ++} ++ ++static void ++grub_backtrace_pointer_default (void *frame __attribute__((__unused__)), ++ unsigned int skip __attribute__((__unused__))) ++{ ++ return; ++} ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++ __attribute__((__weak__, ++ __alias__(("grub_backtrace_pointer_default")))); ++ ++void ++grub_backtrace_print_address (void *addr) ++ __attribute__((__weak__, ++ __alias__(("grub_backtrace_print_address_default")))); ++ ++static void ++grub_backtrace_arch_default(unsigned int skip) ++{ ++ grub_backtrace_pointer(__builtin_frame_address(0), skip + 1); ++} ++ ++void grub_backtrace_arch (unsigned int skip) ++ __attribute__((__weak__, __alias__(("grub_backtrace_arch_default")))); ++ ++void grub_backtrace (unsigned int skip) ++{ ++ grub_backtrace_arch(skip + 1); ++} ++ ++void grub_debug_backtrace (const char * const debug, ++ unsigned int skip) ++{ ++ if (grub_debug_enabled (debug)) ++ grub_backtrace (skip + 1); ++} +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 7afb9e6f72..88d2077709 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -124,6 +124,50 @@ grub_dl_resolve_symbol (const char *name) + return 0; + } + ++void * ++grub_resolve_symbol (const char *name) ++{ ++ grub_symbol_t sym; ++ ++ sym = grub_dl_resolve_symbol (name); ++ if (sym) ++ return sym->addr; ++ return NULL; ++} ++ ++const char * ++grub_get_symbol_by_addr(const void *addr, int isfunc) ++{ ++ unsigned int i; ++ grub_symbol_t before = NULL, after = NULL; ++ for (i = 0; i < GRUB_SYMTAB_SIZE; i++) ++ { ++ grub_symbol_t sym; ++ for (sym = grub_symtab[i]; sym; sym = sym->next) ++ { ++ //grub_printf ("addr 0x%08llx symbol %s\n", (unsigned long long)sym->addr, sym->name); ++ if (sym->addr > addr) ++ { ++ if (!after || sym->addr > after->addr) ++ after = sym; ++ } ++ ++ if (isfunc != sym->isfunc) ++ continue; ++ if (sym->addr > addr) ++ continue; ++ ++ if ((!before && sym->addr <= addr) || (before && before->addr <= sym->addr)) ++ before = sym; ++ } ++ } ++ ++ if (before && addr < after->addr) ++ return before->name; ++ ++ return NULL; ++} ++ + /* Register a symbol with the name NAME and the address ADDR. */ + grub_err_t + grub_dl_register_symbol (const char *name, void *addr, int isfunc, +@@ -336,6 +380,7 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) + const char *str; + Elf_Word size, entsize; + ++ grub_dprintf ("modules", "Resolving symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +diff --git a/grub-core/kern/i386/backtrace.c b/grub-core/kern/i386/backtrace.c +new file mode 100644 +index 0000000000..2413f9a57d +--- /dev/null ++++ b/grub-core/kern/i386/backtrace.c +@@ -0,0 +1,125 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_STACK_FRAME 102400 ++ ++void ++grub_backtrace_pointer (void *frame, unsigned int skip) ++{ ++ void **ebp = (void **)frame; ++ unsigned long x = 0; ++ ++ while (ebp) ++ { ++ void **next_ebp = (void **)ebp[0]; ++ const char *name = NULL; ++ char *addr = NULL; ++ ++ grub_dprintf("backtrace", "ebp is %p next_ebp is %p\n", ebp, next_ebp); ++ ++ if (x >= skip) ++ { ++ name = grub_get_symbol_by_addr (ebp[1], 1); ++ if (name) ++ addr = grub_resolve_symbol (name); ++ grub_backtrace_print_address (ebp[1]); ++ ++ if (addr && addr != ebp[1]) ++ grub_printf (" %s() %p+%p \n", name ? name : "unknown", addr, ++ (char *)((char *)ebp[1] - addr)); ++ else ++ grub_printf(" %s() %p \n", name ? name : "unknown", addr); ++ ++#if 0 ++ grub_printf ("("); ++ for (i = 0, arg = ebp[2]; arg != next_ebp && i < 12; arg++, i++) ++ grub_printf ("%p,", arg); ++ grub_printf (")\n"); ++#endif ++ } ++ ++ x += 1; ++ ++ if (next_ebp < ebp || next_ebp - ebp > MAX_STACK_FRAME || next_ebp == ebp) ++ { ++ //grub_printf ("Invalid stack frame at %p (%p)\n", ebp, next_ebp); ++ break; ++ } ++ ebp = next_ebp; ++ } ++} ++ ++#if defined (__x86_64__) ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.quad .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.quad .data\n" ++ ); ++#elif defined(__i386__) ++asm ("\t.global \"_text\"\n" ++ "_text:\n" ++ "\t.long .text\n" ++ "\t.global \"_data\"\n" ++ "_data:\n" ++ "\t.long .data\n" ++ ); ++#else ++#warning I dunno... ++#endif ++ ++extern unsigned long _text; ++extern unsigned long _data; ++ ++#ifdef GRUB_UTIL ++#define EXT_C(x) x ++#endif ++ ++void ++grub_backtrace_arch (unsigned int skip) ++{ ++ grub_printf ("Backtrace (.text %p .data %p):\n", ++ (void *)_text, (void *)_data); ++ skip += 1; ++#if defined (__x86_64__) ++ asm volatile ("movq %%rbp, %%rdi\n" ++ "movq 0, %%rsi\n" ++ "movl %0, %%esi\n" ++ "call " EXT_C("grub_backtrace_pointer") ++ : ++ : "r" (skip)); ++#elif defined(__i386__) ++ asm volatile ("addl $8, %%esp\n" ++ "pushl %0\n" ++ "pushl %%ebp\n" ++ "call " EXT_C("grub_backtrace_pointer") ++ : ++ : "r" (skip)); ++#else ++ grub_backtrace_pointer(__builtin_frame_address(0), skip); ++#endif ++} +diff --git a/grub-core/kern/i386/pc/init.c b/grub-core/kern/i386/pc/init.c +index 27bc68b8a5..b51d0abfa6 100644 +--- a/grub-core/kern/i386/pc/init.c ++++ b/grub-core/kern/i386/pc/init.c +@@ -153,7 +153,7 @@ compact_mem_regions (void) + } + + grub_addr_t grub_modbase; +-extern grub_uint8_t _start[], _edata[]; ++extern grub_uint8_t _edata[]; + + /* Helper for grub_machine_init. */ + static int +@@ -217,7 +217,7 @@ grub_machine_init (void) + /* This has to happen before any BIOS calls. */ + grub_via_workaround_init (); + +- grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - _start); ++ grub_modbase = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR + (_edata - (grub_uint8_t *)_start); + + /* Initialize the console as early as possible. */ + grub_console_init (); +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 0cd2a62723..937c1bc44c 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -63,7 +63,6 @@ + #define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) + #endif + +-extern char _start[]; + extern char _end[]; + + #ifdef __sparc__ +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index c60601b699..a432a6be54 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1197,15 +1197,15 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) + + + /* Abort GRUB. This function does not return. */ +-static void __attribute__ ((noreturn)) ++static inline void __attribute__ ((noreturn)) + grub_abort (void) + { +-#ifndef GRUB_UTIL +-#if (defined(__i386__) || defined(__x86_64__)) && !defined(GRUB_MACHINE_EMU) +- grub_backtrace(); ++#if !defined(GRUB_MACHINE_EMU) && !defined(GRUB_UTIL) ++ grub_backtrace (1); ++#else ++ grub_printf ("\n"); + #endif +-#endif +- grub_printf ("\nAborted."); ++ grub_printf ("Aborted."); + + #ifndef GRUB_UTIL + if (grub_term_inputs) +@@ -1232,6 +1232,7 @@ grub_fatal (const char *fmt, ...) + { + va_list ap; + ++ grub_printf ("\n"); + va_start (ap, fmt); + grub_vprintf (_(fmt), ap); + va_end (ap); +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index c070afc621..d8c8377578 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -97,13 +97,13 @@ get_header_from_pointer (void *ptr, grub_mm_header_t *p, grub_mm_region_t *r) + break; + + if (! *r) +- grub_fatal ("out of range pointer %p", ptr); ++ grub_fatal ("out of range pointer %p\n", ptr); + + *p = (grub_mm_header_t) ptr - 1; + if ((*p)->magic == GRUB_MM_FREE_MAGIC) +- grub_fatal ("double free at %p", *p); ++ grub_fatal ("double free at %p\n", *p); + if ((*p)->magic != GRUB_MM_ALLOC_MAGIC) +- grub_fatal ("alloc magic is broken at %p: %lx", *p, ++ grub_fatal ("alloc magic is broken at %p: %lx\n", *p, + (unsigned long) (*p)->magic); + } + +diff --git a/grub-core/lib/arm64/backtrace.c b/grub-core/lib/arm64/backtrace.c +deleted file mode 100644 +index 1079b5380e..0000000000 +--- a/grub-core/lib/arm64/backtrace.c ++++ /dev/null +@@ -1,62 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2009 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAX_STACK_FRAME 102400 +- +-void +-grub_backtrace_pointer (int frame) +-{ +- while (1) +- { +- void *lp = __builtin_return_address (frame); +- if (!lp) +- break; +- +- lp = __builtin_extract_return_addr (lp); +- +- grub_printf ("%p: ", lp); +- grub_backtrace_print_address (lp); +- grub_printf (" ("); +- for (i = 0; i < 2; i++) +- grub_printf ("%p,", ((void **)ptr) [i + 2]); +- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); +- nptr = *(void **)ptr; +- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME +- || nptr == ptr) +- { +- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); +- break; +- } +- ptr = nptr; +- } +-} +- +-void +-grub_backtrace (void) +-{ +- grub_backtrace_pointer (1); +-} +- +diff --git a/grub-core/lib/i386/backtrace.c b/grub-core/lib/i386/backtrace.c +deleted file mode 100644 +index c67273db3a..0000000000 +--- a/grub-core/lib/i386/backtrace.c ++++ /dev/null +@@ -1,78 +0,0 @@ +-/* +- * GRUB -- GRand Unified Bootloader +- * Copyright (C) 2009 Free Software Foundation, Inc. +- * +- * GRUB is free software: you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation, either version 3 of the License, or +- * (at your option) any later version. +- * +- * GRUB is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with GRUB. If not, see . +- */ +-#include +-#ifdef GRUB_UTIL +-#define REALLY_GRUB_UTIL GRUB_UTIL +-#undef GRUB_UTIL +-#endif +- +-#include +-#include +- +-#ifdef REALLY_GRUB_UTIL +-#define GRUB_UTIL REALLY_GRUB_UTIL +-#undef REALLY_GRUB_UTIL +-#endif +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAX_STACK_FRAME 102400 +- +-void +-grub_backtrace_pointer (void *ebp) +-{ +- void *ptr, *nptr; +- unsigned i; +- +- ptr = ebp; +- while (1) +- { +- grub_printf ("%p: ", ptr); +- grub_backtrace_print_address (((void **) ptr)[1]); +- grub_printf (" ("); +- for (i = 0; i < 2; i++) +- grub_printf ("%p,", ((void **)ptr) [i + 2]); +- grub_printf ("%p)\n", ((void **)ptr) [i + 2]); +- nptr = *(void **)ptr; +- if (nptr < ptr || (void **) nptr - (void **) ptr > MAX_STACK_FRAME +- || nptr == ptr) +- { +- grub_printf ("Invalid stack frame at %p (%p)\n", ptr, nptr); +- break; +- } +- ptr = nptr; +- } +-} +- +-void +-grub_backtrace (void) +-{ +-#ifdef __x86_64__ +- asm volatile ("movq %%rbp, %%rdi\n" +- "callq *%%rax": :"a"(grub_backtrace_pointer)); +-#else +- asm volatile ("movl %%ebp, %%eax\n" +- "calll *%%ecx": :"c"(grub_backtrace_pointer)); +-#endif +-} +- +diff --git a/include/grub/backtrace.h b/include/grub/backtrace.h +index 395519762f..275cf85e2d 100644 +--- a/include/grub/backtrace.h ++++ b/include/grub/backtrace.h +@@ -19,8 +19,14 @@ + #ifndef GRUB_BACKTRACE_HEADER + #define GRUB_BACKTRACE_HEADER 1 + +-void grub_backtrace (void); +-void grub_backtrace_pointer (void *ptr); ++#include ++#include ++ ++void EXPORT_FUNC(grub_debug_backtrace) (const char * const debug, ++ unsigned int skip); ++void EXPORT_FUNC(grub_backtrace) (unsigned int skip); ++void grub_backtrace_arch (unsigned int skip); ++void grub_backtrace_pointer (void *ptr, unsigned int skip); + void grub_backtrace_print_address (void *addr); + + #endif +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 91933b85f2..2f76e6b043 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -259,6 +259,8 @@ grub_dl_is_persistent (grub_dl_t mod) + + #endif + ++void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); ++const char * EXPORT_FUNC(grub_get_symbol_by_addr) (const void *addr, int isfunc); + grub_err_t grub_dl_register_symbol (const char *name, void *addr, + int isfunc, grub_dl_t mod); + +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index abbca5ea33..300a9766cd 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -111,6 +111,9 @@ grub_addr_t grub_modules_get_end (void); + + #endif + ++void EXPORT_FUNC(start) (void); ++void EXPORT_FUNC(_start) (void); ++ + /* The start point of the C code. */ + void grub_main (void) __attribute__ ((noreturn)); + +diff --git a/grub-core/kern/arm/efi/startup.S b/grub-core/kern/arm/efi/startup.S +index 9f8265315a..f3bc41f9d0 100644 +--- a/grub-core/kern/arm/efi/startup.S ++++ b/grub-core/kern/arm/efi/startup.S +@@ -23,6 +23,8 @@ + .file "startup.S" + .text + .arm ++ .globl start, _start ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in r1/r0. +diff --git a/grub-core/kern/arm/startup.S b/grub-core/kern/arm/startup.S +index 3946fe8e18..5679a1d00a 100644 +--- a/grub-core/kern/arm/startup.S ++++ b/grub-core/kern/arm/startup.S +@@ -48,6 +48,8 @@ + + .text + .arm ++ .globl start, _start ++FUNCTION(start) + FUNCTION(_start) + b codestart + +diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S +index 666a7ee3c9..41676bdb2b 100644 +--- a/grub-core/kern/arm64/efi/startup.S ++++ b/grub-core/kern/arm64/efi/startup.S +@@ -19,7 +19,9 @@ + #include + + .file "startup.S" ++ .globl start, _start + .text ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0. +diff --git a/grub-core/kern/i386/qemu/startup.S b/grub-core/kern/i386/qemu/startup.S +index 0d89858d9b..939f182fc7 100644 +--- a/grub-core/kern/i386/qemu/startup.S ++++ b/grub-core/kern/i386/qemu/startup.S +@@ -24,7 +24,8 @@ + + .text + .code32 +- .globl _start ++ .globl start, _start ++start: + _start: + jmp codestart + +diff --git a/grub-core/kern/ia64/efi/startup.S b/grub-core/kern/ia64/efi/startup.S +index d75c6d7cc7..8f2a593e52 100644 +--- a/grub-core/kern/ia64/efi/startup.S ++++ b/grub-core/kern/ia64/efi/startup.S +@@ -24,8 +24,9 @@ + .psr lsb + .lsb + +- .global _start ++ .global start, _start + .proc _start ++start: + _start: + alloc loc0=ar.pfs,2,4,0,0 + mov loc1=rp +diff --git a/grub-core/kern/sparc64/ieee1275/crt0.S b/grub-core/kern/sparc64/ieee1275/crt0.S +index 03b916f053..701bf63abc 100644 +--- a/grub-core/kern/sparc64/ieee1275/crt0.S ++++ b/grub-core/kern/sparc64/ieee1275/crt0.S +@@ -22,7 +22,8 @@ + + .text + .align 4 +- .globl _start ++ .globl start, _start ++start: + _start: + ba codestart + mov %o4, %o0 +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index ee88e44e97..bfd29a3bf0 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -66,6 +66,7 @@ CLEANFILES += grub_script.yy.c grub_script.yy.h + + include $(srcdir)/Makefile.core.am + ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/backtrace.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/cache.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/command.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/device.h diff --git a/SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch b/SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch new file mode 100644 index 0000000..a916299 --- /dev/null +++ b/SOURCES/0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch @@ -0,0 +1,23 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 9 Nov 2017 15:58:52 -0500 +Subject: [PATCH] normal: don't draw our startup message if debug is set + +--- + grub-core/normal/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 55558cc0b9..af9792c963 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -430,6 +430,9 @@ grub_normal_reader_init (int nested) + const char *msg_esc = _("ESC at any time exits."); + char *msg_formatted; + ++ if (grub_env_get ("debug") != NULL) ++ return 0; ++ + msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For " + "the first word, TAB lists possible command completions. Anywhere " + "else TAB lists possible device or file completions. %s"), diff --git a/SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch b/SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch new file mode 100644 index 0000000..c7ae8d0 --- /dev/null +++ b/SOURCES/0063-Work-around-some-minor-include-path-weirdnesses.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 16 Mar 2018 13:28:57 -0400 +Subject: [PATCH] Work around some minor include path weirdnesses + +Signed-off-by: Peter Jones +--- + include/grub/arm/efi/console.h | 24 ++++++++++++++++++++++++ + include/grub/arm64/efi/console.h | 24 ++++++++++++++++++++++++ + include/grub/i386/efi/console.h | 24 ++++++++++++++++++++++++ + include/grub/x86_64/efi/console.h | 24 ++++++++++++++++++++++++ + 4 files changed, 96 insertions(+) + create mode 100644 include/grub/arm/efi/console.h + create mode 100644 include/grub/arm64/efi/console.h + create mode 100644 include/grub/i386/efi/console.h + create mode 100644 include/grub/x86_64/efi/console.h + +diff --git a/include/grub/arm/efi/console.h b/include/grub/arm/efi/console.h +new file mode 100644 +index 0000000000..1592f6f76b +--- /dev/null ++++ b/include/grub/arm/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_ARM_EFI_CONSOLE_H ++#define GRUB_ARM_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_ARM_EFI_CONSOLE_H */ +diff --git a/include/grub/arm64/efi/console.h b/include/grub/arm64/efi/console.h +new file mode 100644 +index 0000000000..9568933938 +--- /dev/null ++++ b/include/grub/arm64/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_ARM64_EFI_CONSOLE_H ++#define GRUB_ARM64_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_ARM64_EFI_CONSOLE_H */ +diff --git a/include/grub/i386/efi/console.h b/include/grub/i386/efi/console.h +new file mode 100644 +index 0000000000..9231375cb0 +--- /dev/null ++++ b/include/grub/i386/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_I386_EFI_CONSOLE_H ++#define GRUB_I386_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_I386_EFI_CONSOLE_H */ +diff --git a/include/grub/x86_64/efi/console.h b/include/grub/x86_64/efi/console.h +new file mode 100644 +index 0000000000..dba9d8678d +--- /dev/null ++++ b/include/grub/x86_64/efi/console.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_X86_64_EFI_CONSOLE_H ++#define GRUB_X86_64_EFI_CONSOLE_H ++ ++#include ++ ++#endif /* ! GRUB_X86_64_EFI_CONSOLE_H */ diff --git a/SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch b/SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch new file mode 100644 index 0000000..99d8055 --- /dev/null +++ b/SOURCES/0064-Make-it-possible-to-enabled-build-id-sha1.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 25 Jun 2015 15:41:06 -0400 +Subject: [PATCH] Make it possible to enabled --build-id=sha1 + +Signed-off-by: Peter Jones +--- + configure.ac | 8 ++++++++ + acinclude.m4 | 19 +++++++++++++++++++ + 2 files changed, 27 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 0d0e6782a1..302300711f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1442,7 +1442,15 @@ grub_PROG_TARGET_CC + if test "x$TARGET_APPLE_LINKER" != x1 ; then + grub_PROG_OBJCOPY_ABSOLUTE + fi ++ ++AC_ARG_ENABLE([build-id], ++ [AS_HELP_STRING([--enable-build-id], ++ [ask the linker to supply build-id notes (default=no)])]) ++if test x$enable_build_id = xyes; then ++grub_PROG_LD_BUILD_ID_SHA1 ++else + grub_PROG_LD_BUILD_ID_NONE ++fi + if test "x$target_cpu" = xi386; then + if test "$platform" != emu && test "x$TARGET_APPLE_LINKER" != x1 ; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then +diff --git a/acinclude.m4 b/acinclude.m4 +index 6e14bb553c..21238fcfd0 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -136,6 +136,25 @@ if test "x$grub_cv_prog_ld_build_id_none" = xyes; then + fi + ]) + ++dnl Supply --build-id=sha1 to ld if building modules. ++dnl This suppresses warnings from ld on some systems ++AC_DEFUN([grub_PROG_LD_BUILD_ID_SHA1], ++[AC_MSG_CHECKING([whether linker accepts --build-id=sha1]) ++AC_CACHE_VAL(grub_cv_prog_ld_build_id_sha1, ++[save_LDFLAGS="$LDFLAGS" ++LDFLAGS="$LDFLAGS -Wl,--build-id=sha1" ++AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_prog_ld_build_id_sha1=yes], ++ [grub_cv_prog_ld_build_id_sha1=no]) ++LDFLAGS="$save_LDFLAGS" ++]) ++AC_MSG_RESULT([$grub_cv_prog_ld_build_id_sha1]) ++ ++if test "x$grub_cv_prog_ld_build_id_sha1" = xyes; then ++ TARGET_LDFLAGS="$TARGET_LDFLAGS -Wl,--build-id=sha1" ++fi ++]) ++ + dnl Check nm + AC_DEFUN([grub_PROG_NM_WORKS], + [AC_MSG_CHECKING([whether nm works]) diff --git a/SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch b/SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch new file mode 100644 index 0000000..7658e9b --- /dev/null +++ b/SOURCES/0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 28 Jun 2015 13:09:58 -0400 +Subject: [PATCH] Add grub_qdprintf() - grub_dprintf() without the file+line + number. + +This just makes copy+paste of our debug loading info easier. + +Signed-off-by: Peter Jones +--- + grub-core/kern/misc.c | 18 ++++++++++++++++++ + include/grub/misc.h | 2 ++ + 2 files changed, 20 insertions(+) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index a432a6be54..9a2fae6398 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -191,6 +191,24 @@ grub_real_dprintf (const char *file, const int line, const char *condition, + } + } + ++void ++grub_qdprintf (const char *condition, const char *fmt, ...) ++{ ++ va_list args; ++ const char *debug = grub_env_get ("debug"); ++ ++ if (! debug) ++ return; ++ ++ if (grub_strword (debug, "all") || grub_strword (debug, condition)) ++ { ++ va_start (args, fmt); ++ grub_vprintf (fmt, args); ++ va_end (args); ++ grub_refresh (); ++ } ++} ++ + #define PREALLOC_SIZE 255 + + int +diff --git a/include/grub/misc.h b/include/grub/misc.h +index fd18e6320b..3adc4036e3 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -345,6 +345,8 @@ void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const int line, + const char *condition, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 4, 5))); ++void EXPORT_FUNC(grub_qdprintf) (const char *condition, ++ const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 2, 3))); + int EXPORT_FUNC(grub_vprintf) (const char *fmt, va_list args); + int EXPORT_FUNC(grub_snprintf) (char *str, grub_size_t n, const char *fmt, ...) + __attribute__ ((format (GNU_PRINTF, 3, 4))); diff --git a/SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch b/SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch new file mode 100644 index 0000000..ccf34a5 --- /dev/null +++ b/SOURCES/0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch @@ -0,0 +1,178 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 25 Jun 2015 15:11:36 -0400 +Subject: [PATCH] Make a "gdb" dprintf that tells us load addresses. + +This makes a grub_dprintf() call during platform init and during module +loading that tells us the virtual addresses of the .text and .data +sections of grub-core/kernel.exec and any modules it loads. + +Specifically, it displays them in the gdb "add-symbol-file" syntax, with +the presumption that there's a variable $grubdir that reflects the path +to any such binaries. + +Signed-off-by: Peter Jones +--- + grub-core/kern/dl.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ + grub-core/kern/efi/efi.c | 4 ++-- + grub-core/kern/efi/init.c | 26 +++++++++++++++++++++++- + include/grub/efi/efi.h | 2 +- + 4 files changed, 78 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 88d2077709..9557254035 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -501,6 +501,23 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) + return s; + return NULL; + } ++static long ++grub_dl_find_section_index (Elf_Ehdr *e, const char *name) ++{ ++ Elf_Shdr *s; ++ const char *str; ++ unsigned i; ++ ++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + s->sh_offset; ++ ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (grub_strcmp (str + s->sh_name, name) == 0) ++ return (long)i; ++ return -1; ++} + + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. +@@ -653,6 +670,37 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + + return GRUB_ERR_NONE; + } ++static void ++grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) ++{ ++ void *text, *data = NULL; ++ long idx; ++ ++ idx = grub_dl_find_section_index (e, ".text"); ++ if (idx < 0) ++ return; ++ ++ text = grub_dl_get_section_addr (mod, idx); ++ if (!text) ++ return; ++ ++ idx = grub_dl_find_section_index (e, ".data"); ++ if (idx >= 0) ++ data = grub_dl_get_section_addr (mod, idx); ++ ++ if (data) ++ grub_qdprintf ("gdb", "add-symbol-file \\\n" ++ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " ++ "\\\n %p -s .data %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, ++ mod->name, text, data); ++ else ++ grub_qdprintf ("gdb", "add-symbol-file \\\n" ++ "/usr/lib/debug/usr/lib/grub/%s-%s/%s.debug " ++ "\\\n%p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, ++ mod->name, text); ++} + + /* Load a module from core memory. */ + grub_dl_t +@@ -712,6 +760,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + grub_dprintf ("modules", "module name: %s\n", mod->name); + grub_dprintf ("modules", "init function: %p\n", mod->init); + ++ grub_dl_print_gdb_info (mod, e); ++ + if (grub_dl_add (mod)) + { + grub_dl_unload (mod); +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index ae9885edb8..d6a2fb5778 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -296,7 +296,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + /* Search the mods section from the PE32/PE32+ image. This code uses + a PE32 header, but should work with PE32+ as well. */ + grub_addr_t +-grub_efi_modules_addr (void) ++grub_efi_section_addr (const char *section_name) + { + grub_efi_loaded_image_t *image; + struct grub_pe32_header *header; +@@ -321,7 +321,7 @@ grub_efi_modules_addr (void) + i < coff_header->num_sections; + i++, section++) + { +- if (grub_strcmp (section->name, "mods") == 0) ++ if (grub_strcmp (section->name, section_name) == 0) + break; + } + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 6d39bd3ad2..2d12e6188f 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -115,10 +115,33 @@ grub_efi_env_init (void) + grub_free (envblk_s.buf); + } + ++static void ++grub_efi_print_gdb_info (void) ++{ ++ grub_addr_t text; ++ grub_addr_t data; ++ ++ text = grub_efi_section_addr (".text"); ++ if (!text) ++ return; ++ ++ data = grub_efi_section_addr (".data"); ++ if (data) ++ grub_qdprintf ("gdb", ++ "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/" ++ "kernel.exec %p -s .data %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text, (void *)data); ++ else ++ grub_qdprintf ("gdb", ++ "add-symbol-file /usr/lib/debug/usr/lib/grub/%s-%s/" ++ "kernel.exec %p\n", ++ GRUB_TARGET_CPU, GRUB_PLATFORM, (void *)text); ++} ++ + void + grub_efi_init (void) + { +- grub_modbase = grub_efi_modules_addr (); ++ grub_modbase = grub_efi_section_addr ("mods"); + /* First of all, initialize the console so that GRUB can display + messages. */ + grub_console_init (); +@@ -142,6 +165,7 @@ grub_efi_init (void) + 0, 0, 0, NULL); + + grub_efi_env_init (); ++ grub_efi_print_gdb_info (); + grub_efidisk_init (); + } + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 03f9a9d011..2e0691454b 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -138,7 +138,7 @@ grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); + grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); + #endif + +-grub_addr_t grub_efi_modules_addr (void); ++grub_addr_t grub_efi_section_addr (const char *section); + + void grub_efi_mm_init (void); + void grub_efi_mm_fini (void); diff --git a/SOURCES/0067-Fixup-for-newer-compiler.patch b/SOURCES/0067-Fixup-for-newer-compiler.patch new file mode 100644 index 0000000..ed23271 --- /dev/null +++ b/SOURCES/0067-Fixup-for-newer-compiler.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 May 2018 13:40:19 -0400 +Subject: [PATCH] Fixup for newer compiler + +--- + grub-core/fs/btrfs.c | 2 +- + include/grub/gpt_partition.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 2b21cbaa67..4cc86e9b79 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -218,7 +218,7 @@ struct grub_btrfs_inode + grub_uint64_t size; + grub_uint8_t dummy2[0x70]; + struct grub_btrfs_time mtime; +-} GRUB_PACKED; ++} GRUB_PACKED __attribute__ ((aligned(8))); + + struct grub_btrfs_extent_data + { +diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h +index 7a93f43291..8212697bf6 100644 +--- a/include/grub/gpt_partition.h ++++ b/include/grub/gpt_partition.h +@@ -76,7 +76,7 @@ struct grub_gpt_partentry + grub_uint64_t end; + grub_uint64_t attrib; + char name[72]; +-} GRUB_PACKED; ++} GRUB_PACKED __attribute__ ((aligned(8))); + + grub_err_t + grub_gpt_partition_map_iterate (grub_disk_t disk, diff --git a/SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch b/SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch new file mode 100644 index 0000000..9b78c00 --- /dev/null +++ b/SOURCES/0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 12 May 2018 11:29:07 +0200 +Subject: [PATCH] Don't attempt to export the start and _start symbols for + grub-emu + +Commit 318ee04aadc ("make better backtraces") reworked the backtrace logic +but the changes lead to the following build error on the grub-emu platform: + +grub_emu_lite-symlist.o:(.data+0xf08): undefined reference to `start' +collect2: error: ld returned 1 exit status +make[3]: *** [Makefile:25959: grub-emu-lite] Error 1 +make[3]: *** Waiting for unfinished jobs.... +cat kernel_syms.input | grep -v '^#' | sed -n \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/defined kernel '""'\1/;p;}' \ + | sort -u >kernel_syms.lst + +The problem is that start and _start symbols are exported unconditionally, +but these aren't defined for grub-emu since is an emultaed platform so it +doesn't have a startup logic. Don't attempt to export those for grub-emu. + +Signed-off-by: Javier Martinez Canillas +--- + include/grub/kernel.h | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index 300a9766cd..55849777ea 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -111,8 +111,10 @@ grub_addr_t grub_modules_get_end (void); + + #endif + ++#if !defined(GRUB_MACHINE_EMU) + void EXPORT_FUNC(start) (void); + void EXPORT_FUNC(_start) (void); ++#endif + + /* The start point of the C code. */ + void grub_main (void) __attribute__ ((noreturn)); diff --git a/SOURCES/0069-Fixup-for-newer-compiler.patch b/SOURCES/0069-Fixup-for-newer-compiler.patch new file mode 100644 index 0000000..167dca1 --- /dev/null +++ b/SOURCES/0069-Fixup-for-newer-compiler.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 10 May 2018 13:40:19 -0400 +Subject: [PATCH] Fixup for newer compiler + +--- + conf/Makefile.common | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 191b1a70c6..5f0ef96985 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -38,7 +38,7 @@ CFLAGS_KERNEL = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_KERNEL = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) + CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 + CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) +-STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx ++STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes + + CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding + LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d diff --git a/SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch b/SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch new file mode 100644 index 0000000..fb44628 --- /dev/null +++ b/SOURCES/0070-Add-support-for-non-Ethernet-network-cards.patch @@ -0,0 +1,766 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrzej Kacprowski +Date: Wed, 10 Jul 2019 15:22:29 +0200 +Subject: [PATCH] Add support for non-Ethernet network cards + +This patch replaces fixed 6-byte link layer address with +up to 32-byte variable sized address. +This allows supporting Infiniband and Omni-Path fabric +which use 20-byte address, but other network card types +can also take advantage of this change. +The network card driver is responsible for replacing L2 +header provided by grub2 if needed. +This approach is compatible with UEFI network stack which +also allows up to 32-byte variable size link address. + +The BOOTP/DHCP packet format is limited to 16 byte client +hardware address, if link address is more that 16-bytes +then chaddr field in BOOTP it will be set to 0 as per rfc4390. + +Resolves: rhbz#1370642 + +Signed-off-by: Andrzej Kacprowski +[msalter: Fix max string calculation in grub_net_hwaddr_to_str] +Signed-off-by: Mark Salter +--- + grub-core/net/arp.c | 155 ++++++++++++++++++++++----------- + grub-core/net/bootp.c | 15 ++-- + grub-core/net/drivers/efi/efinet.c | 8 +- + grub-core/net/drivers/emu/emunet.c | 1 + + grub-core/net/drivers/i386/pc/pxe.c | 13 +-- + grub-core/net/drivers/ieee1275/ofnet.c | 2 + + grub-core/net/drivers/uboot/ubootnet.c | 1 + + grub-core/net/ethernet.c | 88 +++++++++---------- + grub-core/net/icmp6.c | 15 ++-- + grub-core/net/ip.c | 4 +- + grub-core/net/net.c | 50 ++++++----- + include/grub/net.h | 19 ++-- + 12 files changed, 219 insertions(+), 152 deletions(-) + +diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c +index 54306e3b16..67b409a8ac 100644 +--- a/grub-core/net/arp.c ++++ b/grub-core/net/arp.c +@@ -31,22 +31,12 @@ enum + ARP_REPLY = 2 + }; + +-enum +- { +- /* IANA ARP constant to define hardware type as ethernet. */ +- GRUB_NET_ARPHRD_ETHERNET = 1 +- }; +- +-struct arppkt { ++struct arphdr { + grub_uint16_t hrd; + grub_uint16_t pro; + grub_uint8_t hln; + grub_uint8_t pln; + grub_uint16_t op; +- grub_uint8_t sender_mac[6]; +- grub_uint32_t sender_ip; +- grub_uint8_t recv_mac[6]; +- grub_uint32_t recv_ip; + } GRUB_PACKED; + + static int have_pending; +@@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + const grub_net_network_level_address_t *proto_addr) + { + struct grub_net_buff nb; +- struct arppkt *arp_packet; ++ struct arphdr *arp_header; + grub_net_link_level_address_t target_mac_addr; + grub_err_t err; + int i; + grub_uint8_t *nbd; + grub_uint8_t arp_data[128]; ++ grub_uint8_t hln; ++ grub_uint8_t pln; ++ grub_uint8_t arp_packet_len; ++ grub_uint8_t *tmp_ptr; + + if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + return grub_error (GRUB_ERR_BUG, "unsupported address family"); +@@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, + grub_netbuff_clear (&nb); + grub_netbuff_reserve (&nb, 128); + +- err = grub_netbuff_push (&nb, sizeof (*arp_packet)); ++ hln = inf->card->default_address.len; ++ pln = sizeof (proto_addr->ipv4); ++ arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln); ++ ++ err = grub_netbuff_push (&nb, arp_packet_len); + if (err) + return err; + +- arp_packet = (struct arppkt *) nb.data; +- arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); +- arp_packet->hln = 6; +- arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); +- arp_packet->pln = 4; +- arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); +- /* Sender hardware address. */ +- grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6); +- arp_packet->sender_ip = inf->address.ipv4; +- grub_memset (arp_packet->recv_mac, 0, 6); +- arp_packet->recv_ip = proto_addr->ipv4; +- /* Target protocol address */ +- grub_memset (&target_mac_addr.mac, 0xff, 6); ++ arp_header = (struct arphdr *) nb.data; ++ arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type); ++ arp_header->hln = hln; ++ arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); ++ arp_header->pln = pln; ++ arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); ++ tmp_ptr = nb.data + sizeof (*arp_header); ++ ++ /* The source hardware address. */ ++ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ ++ grub_memcpy (tmp_ptr, &inf->address.ipv4, pln); ++ tmp_ptr += pln; ++ ++ /* The target hardware address. */ ++ grub_memset (tmp_ptr, 0, hln); ++ tmp_ptr += hln; ++ ++ /* The target protocol address */ ++ grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln); ++ tmp_ptr += pln; ++ ++ grub_memset (&target_mac_addr.mac, 0xff, hln); + + nbd = nb.data; + send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP); +@@ -114,28 +124,53 @@ grub_err_t + grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + grub_uint16_t *vlantag) + { +- struct arppkt *arp_packet = (struct arppkt *) nb->data; ++ struct arphdr *arp_header = (struct arphdr *) nb->data; + grub_net_network_level_address_t sender_addr, target_addr; + grub_net_link_level_address_t sender_mac_addr; + struct grub_net_network_level_interface *inf; ++ grub_uint16_t hw_type; ++ grub_uint8_t hln; ++ grub_uint8_t pln; ++ grub_uint8_t arp_packet_len; ++ grub_uint8_t *tmp_ptr; + +- if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) +- || arp_packet->pln != 4 || arp_packet->hln != 6 +- || nb->tail - nb->data < (int) sizeof (*arp_packet)) ++ hw_type = card->default_address.type; ++ hln = card->default_address.len; ++ pln = sizeof(sender_addr.ipv4); ++ arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln); ++ ++ if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) ++ || arp_header->hrd != grub_cpu_to_be16 (hw_type) ++ || arp_header->hln != hln || arp_header->pln != pln ++ || nb->tail - nb->data < (int) arp_packet_len) { + return GRUB_ERR_NONE; ++ } + ++ tmp_ptr = nb->data + sizeof (*arp_header); ++ ++ /* The source hardware address. */ ++ sender_mac_addr.type = hw_type; ++ sender_mac_addr.len = hln; ++ grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ + sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; ++ grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln); ++ tmp_ptr += pln; ++ ++ grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); ++ ++ /* The target hardware address. */ ++ tmp_ptr += hln; ++ ++ /* The target protocol address. */ + target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; +- sender_addr.ipv4 = arp_packet->sender_ip; +- target_addr.ipv4 = arp_packet->recv_ip; +- if (arp_packet->sender_ip == pending_req) ++ grub_memcpy(&target_addr.ipv4, tmp_ptr, pln); ++ ++ if (sender_addr.ipv4 == pending_req) + have_pending = 1; + +- sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac, +- sizeof (sender_mac_addr.mac)); +- grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); +- + FOR_NET_NETWORK_LEVEL_INTERFACES (inf) + { + /* Verify vlantag id */ +@@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + + /* Am I the protocol address target? */ + if (grub_net_addr_cmp (&inf->address, &target_addr) == 0 +- && arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) ++ && arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) + { + grub_net_link_level_address_t target; + struct grub_net_buff nb_reply; +- struct arppkt *arp_reply; ++ struct arphdr *arp_reply; + grub_uint8_t arp_data[128]; + grub_err_t err; + +@@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, + grub_netbuff_clear (&nb_reply); + grub_netbuff_reserve (&nb_reply, 128); + +- err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet)); ++ err = grub_netbuff_push (&nb_reply, arp_packet_len); + if (err) + return err; + +- arp_reply = (struct arppkt *) nb_reply.data; ++ arp_reply = (struct arphdr *) nb_reply.data; + +- arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); ++ arp_reply->hrd = grub_cpu_to_be16 (hw_type); + arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); +- arp_reply->pln = 4; +- arp_reply->hln = 6; ++ arp_reply->pln = pln; ++ arp_reply->hln = hln; + arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY); +- arp_reply->sender_ip = arp_packet->recv_ip; +- arp_reply->recv_ip = arp_packet->sender_ip; +- arp_reply->hln = 6; +- +- target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (target.mac, arp_packet->sender_mac, 6); +- grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6); +- grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6); ++ ++ tmp_ptr = nb_reply.data + sizeof (*arp_reply); ++ ++ /* The source hardware address. */ ++ grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The source protocol address. */ ++ grub_memcpy (tmp_ptr, &target_addr.ipv4, pln); ++ tmp_ptr += pln; ++ ++ /* The target hardware address. */ ++ grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln); ++ tmp_ptr += hln; ++ ++ /* The target protocol address */ ++ grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln); ++ tmp_ptr += pln; ++ ++ target.type = hw_type; ++ target.len = hln; ++ grub_memcpy (target.mac, sender_mac_addr.mac, hln); + + /* Change operation to REPLY and send packet */ + send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP); +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index e28fb6a09f..08b6b2b5d6 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -233,7 +233,6 @@ grub_net_configure_by_dhcp_ack (const char *name, + int is_def, char **device, char **path) + { + grub_net_network_level_address_t addr; +- grub_net_link_level_address_t hwaddr; + struct grub_net_network_level_interface *inter; + int mask = -1; + char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; +@@ -250,12 +249,8 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (path) + *path = 0; + +- grub_memcpy (hwaddr.mac, bp->mac_addr, +- bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len +- : sizeof (hwaddr.mac)); +- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- +- inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags); ++ grub_dprintf("dhcp", "configuring dhcp for %s\n", name); ++ inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags); + if (!inter) + return 0; + +@@ -567,7 +562,9 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + grub_memset (pack, 0, sizeof (*pack)); + pack->opcode = 1; + pack->hw_type = 1; +- pack->hw_len = 6; ++ pack->hw_len = iface->hwaddress.len > 16 ? 0 ++ : iface->hwaddress.len; ++ + err = grub_get_datetime (&date); + if (err || !grub_datetime2unixtime (&date, &t)) + { +@@ -580,7 +577,7 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) + else + pack->ident = iface->xid; + +- grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); ++ grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, pack->hw_len); + + grub_netbuff_push (nb, sizeof (*udph)); + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 173fb63153..a673bea807 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -279,6 +279,9 @@ grub_efinet_findcards (void) + /* This should not happen... Why? */ + continue; + ++ if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE) ++ continue; ++ + if (net->mode->state == GRUB_EFI_NETWORK_STOPPED + && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS) + continue; +@@ -315,10 +318,11 @@ grub_efinet_findcards (void) + card->name = grub_xasprintf ("efinet%d", i++); + card->driver = &efidriver; + card->flags = 0; +- card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ card->default_address.type = net->mode->if_type; ++ card->default_address.len = net->mode->hwaddr_size; + grub_memcpy (card->default_address.mac, + net->mode->current_address, +- sizeof (card->default_address.mac)); ++ net->mode->hwaddr_size); + card->efi_net = net; + card->efi_handle = *handle; + +diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c +index b194920861..5b6c5e16a6 100644 +--- a/grub-core/net/drivers/emu/emunet.c ++++ b/grub-core/net/drivers/emu/emunet.c +@@ -46,6 +46,7 @@ static struct grub_net_card emucard = + .mtu = 1500, + .default_address = { + .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET, ++ . len = 6, + {.mac = {0, 1, 2, 3, 4, 5}} + }, + .flags = 0 +diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c +index 3f4152d036..9f8fb4b6d2 100644 +--- a/grub-core/net/drivers/i386/pc/pxe.c ++++ b/grub-core/net/drivers/i386/pc/pxe.c +@@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe) + grub_memset (ui, 0, sizeof (*ui)); + grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry); + ++ grub_pxe_card.default_address.len = 6; + grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr, +- sizeof (grub_pxe_card.default_address.mac)); +- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) ++ grub_pxe_card.default_address.len); ++ for (i = 0; i < grub_pxe_card.default_address.len; i++) + if (grub_pxe_card.default_address.mac[i] != 0) + break; +- if (i != sizeof (grub_pxe_card.default_address.mac)) ++ if (i != grub_pxe_card.default_address.len) + { +- for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) ++ for (i = 0; i < grub_pxe_card.default_address.len; i++) + if (grub_pxe_card.default_address.mac[i] != 0xff) + break; + } +- if (i == sizeof (grub_pxe_card.default_address.mac)) ++ if (i == grub_pxe_card.default_address.len) + grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr, +- sizeof (grub_pxe_card.default_address.mac)); ++ grub_pxe_card.default_address.len); + grub_pxe_card.mtu = ui->mtu; + + grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c +index 3860b6f78d..bcb3f9ea02 100644 +--- a/grub-core/net/drivers/ieee1275/ofnet.c ++++ b/grub-core/net/drivers/ieee1275/ofnet.c +@@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, + grub_uint16_t vlantag = 0; + + hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ hw_addr.len = 6; + + args = bootpath + grub_strlen (devpath) + 1; + do +@@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) + grub_memcpy (&lla.mac, pprop, 6); + + lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ lla.len = 6; + card->default_address = lla; + + card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; +diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c +index 056052e40d..22ebcbf211 100644 +--- a/grub-core/net/drivers/uboot/ubootnet.c ++++ b/grub-core/net/drivers/uboot/ubootnet.c +@@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet) + + grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6); + card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ card->default_address.len = 6; + + card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; + card->txbuf = grub_zalloc (card->txbufsize); +diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c +index 4d7ceed6f9..9aae83a5eb 100644 +--- a/grub-core/net/ethernet.c ++++ b/grub-core/net/ethernet.c +@@ -29,13 +29,6 @@ + + #define LLCADDRMASK 0x7f + +-struct etherhdr +-{ +- grub_uint8_t dst[6]; +- grub_uint8_t src[6]; +- grub_uint16_t type; +-} GRUB_PACKED; +- + struct llchdr + { + grub_uint8_t dsap; +@@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + grub_net_link_level_address_t target_addr, + grub_net_ethertype_t ethertype) + { +- struct etherhdr *eth; ++ grub_uint8_t *eth; + grub_err_t err; +- grub_uint8_t etherhdr_size; +- grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER; ++ grub_uint32_t vlantag = 0; ++ grub_uint8_t hw_addr_len = inf->card->default_address.len; ++ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; + +- etherhdr_size = sizeof (*eth); +- COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE); ++ /* Source and destination link addresses + ethertype + vlan tag */ ++ COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) < ++ GRUB_NET_MAX_LINK_HEADER_SIZE); + + /* Increase ethernet header in case of vlantag */ + if (inf->vlantag != 0) +@@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + err = grub_netbuff_push (nb, etherhdr_size); + if (err) + return err; +- eth = (struct etherhdr *) nb->data; +- grub_memcpy (eth->dst, target_addr.mac, 6); +- grub_memcpy (eth->src, inf->hwaddress.mac, 6); ++ eth = nb->data; ++ grub_memcpy (eth, target_addr.mac, hw_addr_len); ++ eth += hw_addr_len; ++ grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len); ++ eth += hw_addr_len; ++ ++ /* Check if a vlan-tag is present. */ ++ if (vlantag != 0) ++ { ++ *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag); ++ eth += sizeof (vlantag); ++ } ++ ++ /* Write ethertype */ ++ *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype); + +- eth->type = grub_cpu_to_be16 (ethertype); + if (!inf->card->opened) + { + err = GRUB_ERR_NONE; +@@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, + inf->card->opened = 1; + } + +- /* Check and add a vlan-tag if needed. */ +- if (inf->vlantag != 0) +- { +- /* Move eth type to the right */ +- grub_memcpy ((char *) nb->data + etherhdr_size - 2, +- (char *) nb->data + etherhdr_size - 6, 2); +- +- /* Add the tag in the middle */ +- grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2); +- grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2); +- } +- + return inf->card->driver->send (inf->card, nb); + } + +@@ -104,31 +98,40 @@ grub_err_t + grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + struct grub_net_card *card) + { +- struct etherhdr *eth; ++ grub_uint8_t *eth; + struct llchdr *llch; + struct snaphdr *snaph; + grub_net_ethertype_t type; + grub_net_link_level_address_t hwaddress; + grub_net_link_level_address_t src_hwaddress; + grub_err_t err; +- grub_uint8_t etherhdr_size = sizeof (*eth); ++ grub_uint8_t hw_addr_len = card->default_address.len; ++ grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; + grub_uint16_t vlantag = 0; + ++ eth = nb->data; + +- /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */ +- /* longer than the original one. The vlantag id is extracted and the header */ +- /* is reseted to the original size. */ +- if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER) ++ hwaddress.type = card->default_address.type; ++ hwaddress.len = hw_addr_len; ++ grub_memcpy (hwaddress.mac, eth, hw_addr_len); ++ eth += hw_addr_len; ++ ++ src_hwaddress.type = card->default_address.type; ++ src_hwaddress.len = hw_addr_len; ++ grub_memcpy (src_hwaddress.mac, eth, hw_addr_len); ++ eth += hw_addr_len; ++ ++ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); ++ if (type == VLANTAG_IDENTIFIER) + { +- vlantag = grub_get_unaligned16 (nb->data + etherhdr_size); ++ /* Skip vlan tag */ ++ eth += 2; ++ vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); + etherhdr_size += 4; +- /* Move eth type to the original position */ +- grub_memcpy((char *) nb->data + etherhdr_size - 6, +- (char *) nb->data + etherhdr_size - 2, 2); ++ eth += 2; ++ type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); + } + +- eth = (struct etherhdr *) nb->data; +- type = grub_be_to_cpu16 (eth->type); + err = grub_netbuff_pull (nb, etherhdr_size); + if (err) + return err; +@@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb, + } + } + +- hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac)); +- src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac)); +- + switch (type) + { + /* ARP packet. */ +diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c +index 2cbd95dce2..56a3ec5c8e 100644 +--- a/grub-core/net/icmp6.c ++++ b/grub-core/net/icmp6.c +@@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } +@@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + } +@@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, + && ohdr->len == 1) + { + grub_net_link_level_address_t ll_address; +- ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); ++ ll_address.type = card->default_address.type; ++ ll_address.len = card->default_address.len; ++ grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); + grub_net_link_layer_add_address (card, source, &ll_address, 0); + } + if (ohdr->type == OPTION_PREFIX && ohdr->len == 4) +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index ea5edf8f1f..a5896f6dc2 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -276,8 +276,8 @@ handle_dgram (struct grub_net_buff *nb, + if (inf->card == card + && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV + && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET +- && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, +- sizeof (inf->hwaddress.mac)) == 0) ++ && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, ++ bootp->hw_len) == 0 || bootp->hw_len == 0)) + { + grub_net_process_dhcp (nb, inf); + grub_netbuff_free (nb); +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 22f2689aae..a46f82362e 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -133,8 +133,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + << 48) + && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) + { +- hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memset (hw_addr->mac, -1, 6); ++ hw_addr->type = inf->card->default_address.type; ++ hw_addr->len = inf->card->default_address.len; ++ grub_memset (hw_addr->mac, -1, hw_addr->len); + return GRUB_ERR_NONE; + } + +@@ -142,6 +143,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, + && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) + { + hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; ++ hw_addr->len = inf->card->default_address.len; + hw_addr->mac[0] = 0x33; + hw_addr->mac[1] = 0x33; + hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); +@@ -762,23 +764,23 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) + void + grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) + { +- str[0] = 0; +- switch (addr->type) ++ char *ptr; ++ unsigned i; ++ int maxstr; ++ ++ if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) + { +- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: +- { +- char *ptr; +- unsigned i; +- for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++) +- { +- grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), +- "%02x:", addr->mac[i] & 0xff); +- ptr += (sizeof ("XX:") - 1); +- } +- return; +- } ++ str[0] = 0; ++ grub_printf (_("Unsupported hw address type %d len %d\n"), ++ addr->type, addr->len); ++ return; ++ } ++ maxstr = addr->len * grub_strlen ("XX:"); ++ for (ptr = str, i = 0; i < addr->len; i++) ++ { ++ ptr += grub_snprintf (ptr, maxstr - (ptr - str), ++ "%02x:", addr->mac[i] & 0xff); + } +- grub_printf (_("Unsupported hw address type %d\n"), addr->type); + } + + int +@@ -789,13 +791,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + return -1; + if (a->type > b->type) + return +1; +- switch (a->type) ++ if (a->len < b->len) ++ return -1; ++ if (a->len > b->len) ++ return +1; ++ if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) + { +- case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: +- return grub_memcmp (a->mac, b->mac, sizeof (a->mac)); ++ grub_printf (_("Unsupported hw address type %d len %d\n"), ++ a->type, a->len); ++ return + 1; + } +- grub_printf (_("Unsupported hw address type %d\n"), a->type); +- return 1; ++ return grub_memcmp (a->mac, b->mac, a->len); + } + + int +diff --git a/include/grub/net.h b/include/grub/net.h +index 8a05ec4fe7..af0404db7e 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -29,7 +29,8 @@ + + enum + { +- GRUB_NET_MAX_LINK_HEADER_SIZE = 64, ++ GRUB_NET_MAX_LINK_HEADER_SIZE = 96, ++ GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32, + GRUB_NET_UDP_HEADER_SIZE = 8, + GRUB_NET_TCP_HEADER_SIZE = 20, + GRUB_NET_OUR_IPV4_HEADER_SIZE = 20, +@@ -42,15 +43,17 @@ enum + + typedef enum grub_link_level_protocol_id + { +- GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET ++ /* IANA ARP constant to define hardware type. */ ++ GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1, + } grub_link_level_protocol_id_t; + + typedef struct grub_net_link_level_address + { + grub_link_level_protocol_id_t type; ++ grub_uint8_t len; + union + { +- grub_uint8_t mac[6]; ++ grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE]; + }; + } grub_net_link_level_address_t; + +@@ -566,11 +569,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a, + #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX") + + /* +- Currently suppoerted adresses: +- ethernet: XX:XX:XX:XX:XX:XX ++ Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE + */ +- +-#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX")) ++#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX:"\ ++ "XX:XX:XX:XX:XX:XX:XX:XX")) + + void + grub_net_addr_to_str (const grub_net_network_level_address_t *target, diff --git a/SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch b/SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch new file mode 100644 index 0000000..307e33c --- /dev/null +++ b/SOURCES/0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch @@ -0,0 +1,270 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aaron Miller +Date: Fri, 29 Jul 2016 17:41:38 +0800 +Subject: [PATCH] net: read bracketed ipv6 addrs and port numbers + +Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses +to be recognized with brackets around them, which is required to specify a port +number + +Signed-off-by: Aaron Miller +[pjones: various bug fixes] +Signed-off-by: Peter Jones +--- + grub-core/net/http.c | 25 ++++++++++++--- + grub-core/net/net.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++--- + grub-core/net/tftp.c | 8 +++-- + include/grub/net.h | 1 + + 4 files changed, 109 insertions(+), 12 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index b616cf40b1..12a2632ea5 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -289,7 +289,9 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + nb2 = grub_netbuff_alloc (data->chunk_rem); + if (!nb2) + return grub_errno; +- grub_netbuff_put (nb2, data->chunk_rem); ++ err = grub_netbuff_put (nb2, data->chunk_rem); ++ if (err) ++ return grub_errno; + grub_memcpy (nb2->data, nb->data, data->chunk_rem); + if (file->device->net->packs.count >= 20) + { +@@ -312,12 +314,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + int i; + struct grub_net_buff *nb; + grub_err_t err; ++ char* server = file->device->net->server; ++ int port = file->device->net->port; + + nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE + + sizeof ("GET ") - 1 + + grub_strlen (data->filename) + + sizeof (" HTTP/1.1\r\nHost: ") - 1 +- + grub_strlen (file->device->net->server) ++ + grub_strlen (server) + sizeof (":XXXXXXXXXX") + + sizeof ("\r\nUser-Agent: " PACKAGE_STRING + "\r\n") - 1 + + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX" +@@ -356,7 +360,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + sizeof (" HTTP/1.1\r\nHost: ") - 1); + + ptr = nb->tail; +- err = grub_netbuff_put (nb, grub_strlen (file->device->net->server)); ++ err = grub_netbuff_put (nb, grub_strlen (server)); + if (err) + { + grub_netbuff_free (nb); +@@ -365,6 +369,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + grub_memcpy (ptr, file->device->net->server, + grub_strlen (file->device->net->server)); + ++ if (port) ++ { ++ ptr = nb->tail; ++ grub_snprintf ((char *) ptr, ++ sizeof (":XXXXXXXXXX"), ++ ":%d", ++ port); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, + sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") +@@ -390,8 +403,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + grub_netbuff_put (nb, 2); + grub_memcpy (ptr, "\r\n", 2); + +- data->sock = grub_net_tcp_open (file->device->net->server, +- HTTP_PORT, http_receive, ++ grub_dprintf ("http", "opening path %s on host %s TCP port %d\n", ++ data->filename, server, port ? port : HTTP_PORT); ++ data->sock = grub_net_tcp_open (server, ++ port ? port : HTTP_PORT, http_receive, + http_err, NULL, + file); + if (!data->sock) +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index a46f82362e..0ce5e675ed 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -444,6 +444,13 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + grub_uint16_t newip[8]; + const char *ptr = val; + int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') ++ { ++ bracketed = 1; ++ ptr++; ++ } + + if (ptr[0] == ':' && ptr[1] != ':') + return 0; +@@ -482,6 +489,8 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); + } + grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') ++ ptr++; + if (rest) + *rest = ptr; + return 1; +@@ -1343,8 +1352,10 @@ grub_net_open_real (const char *name) + { + grub_net_app_level_t proto; + const char *protname, *server; ++ char *host; + grub_size_t protnamelen; + int try; ++ int port = 0; + + if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) + { +@@ -1382,6 +1393,72 @@ grub_net_open_real (const char *name) + return NULL; + } + ++ char* port_start; ++ /* ipv6 or port specified? */ ++ if ((port_start = grub_strchr (server, ':'))) ++ { ++ char* ipv6_begin; ++ if((ipv6_begin = grub_strchr (server, '['))) ++ { ++ char* ipv6_end = grub_strchr (server, ']'); ++ if(!ipv6_end) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("mismatched [ in address")); ++ return NULL; ++ } ++ /* port number after bracketed ipv6 addr */ ++ if(ipv6_end[1] == ':') ++ { ++ port = grub_strtoul (ipv6_end + 2, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ } ++ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1); ++ } ++ else ++ { ++ if (grub_strchr (port_start + 1, ':')) ++ { ++ int iplen = grub_strlen (server); ++ /* bracket bare ipv6 addrs */ ++ host = grub_malloc (iplen + 3); ++ if(!host) ++ { ++ return NULL; ++ } ++ host[0] = '['; ++ grub_memcpy (host + 1, server, iplen); ++ host[iplen + 1] = ']'; ++ host[iplen + 2] = '\0'; ++ } ++ else ++ { ++ /* hostname:port or ipv4:port */ ++ port = grub_strtol (port_start + 1, NULL, 10); ++ if(port > 65535) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("bad port number")); ++ return NULL; ++ } ++ host = grub_strndup (server, port_start - server); ++ } ++ } ++ } ++ else ++ { ++ host = grub_strdup (server); ++ } ++ if (!host) ++ { ++ return NULL; ++ } ++ + for (try = 0; try < 2; try++) + { + FOR_NET_APP_LEVEL (proto) +@@ -1391,14 +1468,13 @@ grub_net_open_real (const char *name) + { + grub_net_t ret = grub_zalloc (sizeof (*ret)); + if (!ret) +- return NULL; +- ret->protocol = proto; +- ret->server = grub_strdup (server); +- if (!ret->server) + { +- grub_free (ret); ++ grub_free (host); + return NULL; + } ++ ret->protocol = proto; ++ ret->port = port; ++ ret->server = host; + ret->fs = &grub_net_fs; + return ret; + } +@@ -1473,6 +1549,7 @@ grub_net_open_real (const char *name) + grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), + name); + ++ grub_free (host); + return NULL; + } + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 4ab2f5c735..d54b13f09f 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -295,6 +295,7 @@ tftp_open (struct grub_file *file, const char *filename) + grub_err_t err; + grub_uint8_t *nbd; + grub_net_network_level_address_t addr; ++ int port = file->device->net->port; + + data = grub_zalloc (sizeof (*data)); + if (!data) +@@ -362,14 +363,17 @@ tftp_open (struct grub_file *file, const char *filename) + err = grub_net_resolve_address (file->device->net->server, &addr); + if (err) + { +- grub_dprintf("tftp", "Address resolution failed: %d\n", err); ++ grub_dprintf ("tftp", "Address resolution failed: %d\n", err); ++ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n", ++ (unsigned long long)data->file_size, ++ (unsigned long long)data->block_size); + grub_free (data); + return err; + } + + grub_dprintf("tftp", "opening connection\n"); + data->sock = grub_net_udp_open (addr, +- TFTP_SERVER_PORT, tftp_receive, ++ port ? port : TFTP_SERVER_PORT, tftp_receive, + file); + if (!data->sock) + { +diff --git a/include/grub/net.h b/include/grub/net.h +index af0404db7e..d55d505a03 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -273,6 +273,7 @@ typedef struct grub_net + { + char *server; + char *name; ++ int port; + grub_net_app_level_t protocol; + grub_net_packets_t packs; + grub_off_t offset; diff --git a/SOURCES/0072-bootp-New-net_bootp6-command.patch b/SOURCES/0072-bootp-New-net_bootp6-command.patch new file mode 100644 index 0000000..bef3acd --- /dev/null +++ b/SOURCES/0072-bootp-New-net_bootp6-command.patch @@ -0,0 +1,1368 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 10 Jul 2019 15:42:36 +0200 +Subject: [PATCH] bootp: New net_bootp6 command + +Implement new net_bootp6 command for IPv6 network auto configuration via the +DHCPv6 protocol (RFC3315). + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +[pjones: Put back our code to add a local route] +Signed-off-by: Peter Jones +--- + grub-core/net/bootp.c | 1059 ++++++++++++++++++++++++++++++------ + grub-core/net/drivers/efi/efinet.c | 20 +- + grub-core/net/ip.c | 39 ++ + include/grub/efi/api.h | 2 +- + include/grub/net.h | 91 ++-- + 5 files changed, 1002 insertions(+), 209 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 08b6b2b5d6..fe93b80f1c 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -24,6 +24,98 @@ + #include + #include + #include ++#include ++#include ++ ++static int ++dissect_url (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} + + struct grub_dhcp_discover_options + { +@@ -604,6 +696,584 @@ out: + return err; + } + ++/* The default netbuff size for sending DHCPv6 packets which should be ++ large enough to hold the information */ ++#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512 ++ ++struct grub_dhcp6_options ++{ ++ grub_uint8_t *client_duid; ++ grub_uint16_t client_duid_len; ++ grub_uint8_t *server_duid; ++ grub_uint16_t server_duid_len; ++ grub_uint32_t iaid; ++ grub_uint32_t t1; ++ grub_uint32_t t2; ++ grub_net_network_level_address_t *ia_addr; ++ grub_uint32_t preferred_lifetime; ++ grub_uint32_t valid_lifetime; ++ grub_net_network_level_address_t *dns_server_addrs; ++ grub_uint16_t num_dns_server; ++ char *boot_file_proto; ++ char *boot_file_server_ip; ++ char *boot_file_path; ++}; ++ ++typedef struct grub_dhcp6_options *grub_dhcp6_options_t; ++ ++struct grub_dhcp6_session ++{ ++ struct grub_dhcp6_session *next; ++ struct grub_dhcp6_session **prev; ++ grub_uint32_t iaid; ++ grub_uint32_t transaction_id:24; ++ grub_uint64_t start_time; ++ struct grub_net_dhcp6_option_duid_ll duid; ++ struct grub_net_network_level_interface *iface; ++ ++ /* The associated dhcpv6 options */ ++ grub_dhcp6_options_t adv; ++ grub_dhcp6_options_t reply; ++}; ++ ++typedef struct grub_dhcp6_session *grub_dhcp6_session_t; ++ ++typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data); ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, ++ dhcp6_option_hook_fn hook, void *hook_data); ++ ++static void ++parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data; ++ ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ if (code == GRUB_NET_DHCP6_OPTION_IAADDR) ++ { ++ const struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ ++ if (len < sizeof (*iaaddr)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len); ++ return; ++ } ++ if (!dhcp6->ia_addr) ++ { ++ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr)); ++ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr); ++ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8); ++ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime); ++ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime); ++ } ++ } ++} ++ ++static void ++parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data) ++{ ++ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data; ++ grub_uint16_t code = grub_be_to_cpu16 (opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (opt->len); ++ ++ switch (code) ++ { ++ case GRUB_NET_DHCP6_OPTION_CLIENTID: ++ ++ if (dhcp6->client_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len); ++ break; ++ } ++ dhcp6->client_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->client_duid, opt->data, len); ++ dhcp6->client_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_SERVERID: ++ ++ if (dhcp6->server_duid || !len) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len); ++ break; ++ } ++ dhcp6->server_duid = grub_malloc (len); ++ grub_memcpy (dhcp6->server_duid, opt->data, len); ++ dhcp6->server_duid_len = len; ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_IA_NA: ++ { ++ const struct grub_net_dhcp6_option_iana *ia_na; ++ grub_uint16_t data_len; ++ ++ if (dhcp6->iaid || len < sizeof (*ia_na)) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len); ++ break; ++ } ++ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data; ++ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid); ++ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1); ++ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2); ++ ++ data_len = len - sizeof (*ia_na); ++ if (data_len) ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6); ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS: ++ { ++ const grub_uint8_t *po; ++ grub_uint16_t ln; ++ grub_net_network_level_address_t *la; ++ ++ if (!len || len & 0xf) ++ { ++ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n"); ++ break; ++ } ++ dhcp6->num_dns_server = ln = len >> 4; ++ dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la)); ++ ++ for (po = opt->data; ln > 0; po += 0x10, la++, ln--) ++ { ++ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ la->ipv6[0] = grub_get_unaligned64 (po); ++ la->ipv6[1] = grub_get_unaligned64 (po + 8); ++ la->option = DNS_OPTION_PREFER_IPV6; ++ } ++ } ++ break; ++ ++ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL: ++ dissect_url ((const char *)opt->data, ++ &dhcp6->boot_file_proto, ++ &dhcp6->boot_file_server_ip, ++ &dhcp6->boot_file_path); ++ break; ++ ++ default: ++ break; ++ } ++} ++ ++static void ++foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data) ++{ ++ while (size) ++ { ++ grub_uint16_t code, len; ++ ++ if (size < sizeof (*opt)) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size); ++ break; ++ } ++ size -= sizeof (*opt); ++ len = grub_be_to_cpu16 (opt->len); ++ code = grub_be_to_cpu16 (opt->code); ++ if (size < len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code); ++ break; ++ } ++ if (!len) ++ { ++ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code); ++ break; ++ } ++ else ++ { ++ if (hook) ++ hook (opt, hook_data); ++ size -= len; ++ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt)); ++ } ++ } ++} ++ ++static grub_dhcp6_options_t ++grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size) ++{ ++ grub_dhcp6_options_t options; ++ ++ if (size < sizeof (*v6h)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return NULL; ++ } ++ ++ options = grub_zalloc (sizeof(*options)); ++ if (!options) ++ return NULL; ++ ++ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options, ++ size - sizeof (*v6h), parse_dhcp6_option, options); ++ ++ return options; ++} ++ ++static void ++grub_dhcp6_options_free (grub_dhcp6_options_t options) ++{ ++ if (options->client_duid) ++ grub_free (options->client_duid); ++ if (options->server_duid) ++ grub_free (options->server_duid); ++ if (options->ia_addr) ++ grub_free (options->ia_addr); ++ if (options->dns_server_addrs) ++ grub_free (options->dns_server_addrs); ++ if (options->boot_file_proto) ++ grub_free (options->boot_file_proto); ++ if (options->boot_file_server_ip) ++ grub_free (options->boot_file_server_ip); ++ if (options->boot_file_path) ++ grub_free (options->boot_file_path); ++ ++ grub_free (options); ++} ++ ++static grub_dhcp6_session_t grub_dhcp6_sessions; ++#define FOR_DHCP6_SESSIONS_SAFE(var, next) FOR_LIST_ELEMENTS_SAFE (var, next, grub_dhcp6_sessions) ++#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions) ++ ++static void ++grub_net_configure_by_dhcp6_info (const char *name, ++ struct grub_net_card *card, ++ grub_dhcp6_options_t dhcp6, ++ int is_def, ++ int flags, ++ struct grub_net_network_level_interface **ret_inf) ++{ ++ grub_net_network_level_netaddress_t netaddr; ++ struct grub_net_network_level_interface *inf; ++ ++ if (dhcp6->ia_addr) ++ { ++ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags); ++ ++ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0]; ++ netaddr.ipv6.base[1] = 0; ++ netaddr.ipv6.masksize = 64; ++ grub_net_add_route (name, netaddr, inf); ++ ++ if (ret_inf) ++ *ret_inf = inf; ++ } ++ ++ if (dhcp6->dns_server_addrs) ++ { ++ grub_uint16_t i; ++ ++ for (i = 0; i < dhcp6->num_dns_server; ++i) ++ grub_net_add_dns_server (dhcp6->dns_server_addrs + i); ++ } ++ ++ if (dhcp6->boot_file_path) ++ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path, ++ grub_strlen (dhcp6->boot_file_path)); ++ ++ if (is_def && dhcp6->boot_file_server_ip) ++ { ++ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++} ++ ++static void ++grub_dhcp6_session_add (struct grub_net_network_level_interface *iface, ++ grub_uint32_t iaid) ++{ ++ grub_dhcp6_session_t se; ++ struct grub_datetime date; ++ grub_err_t err; ++ grub_int32_t t = 0; ++ ++ se = grub_malloc (sizeof (*se)); ++ ++ err = grub_get_datetime (&date); ++ if (err || !grub_datetime2unixtime (&date, &t)) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ t = 0; ++ } ++ ++ se->iface = iface; ++ se->iaid = iaid; ++ se->transaction_id = t; ++ se->start_time = grub_get_time_ms (); ++ se->duid.type = grub_cpu_to_be16_compile_time (3) ; ++ se->duid.hw_type = grub_cpu_to_be16_compile_time (1); ++ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr)); ++ se->adv = NULL; ++ se->reply = NULL; ++ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se)); ++} ++ ++static void ++grub_dhcp6_session_remove (grub_dhcp6_session_t se) ++{ ++ grub_list_remove (GRUB_AS_LIST (se)); ++ if (se->adv) ++ grub_dhcp6_options_free (se->adv); ++ if (se->reply) ++ grub_dhcp6_options_free (se->reply); ++ grub_free (se); ++} ++ ++static void ++grub_dhcp6_session_remove_all (void) ++{ ++ grub_dhcp6_session_t se, next; ++ ++ FOR_DHCP6_SESSIONS_SAFE (se, next) ++ { ++ grub_dhcp6_session_remove (se); ++ } ++ grub_dhcp6_sessions = NULL; ++} ++ ++static grub_err_t ++grub_dhcp6_session_configure_network (grub_dhcp6_session_t se) ++{ ++ char *name; ++ ++ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name); ++ if (!name) ++ return grub_errno; ++ ++ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0); ++ grub_free (name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_dhcp6_session_send_request (grub_dhcp6_session_t se) ++{ ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ struct udphdr *udph; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ grub_uint64_t elapsed; ++ struct grub_net_network_level_interface *inf = se->iface; ++ grub_dhcp6_options_t dhcp6 = se->adv; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast); ++ if (err) ++ return err; ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ return grub_errno; ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len); ++ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len); ++ ++ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID); ++ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len); ++ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len); ++ ++ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ if (dhcp6->ia_addr) ++ { ++ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ } ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ if (dhcp6->ia_addr) ++ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt)); ++ ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid); ++ ++ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1); ++ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2); ++ ++ if (dhcp6->ia_addr) ++ { ++ opt = (struct grub_net_dhcp6_option *)ia_na->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr)); ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data; ++ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]); ++ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]); ++ ++ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime); ++ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime); ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO); ++ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL)); ++ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ opt = (struct grub_net_dhcp6_option*) nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ ++ /* the time is expressed in hundredths of a second */ ++ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0); ++ ++ if (elapsed > 0xffff) ++ elapsed = 0xffff; ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed)); ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *) nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_REQUEST; ++ v6h->transaction_id = se->transaction_id; ++ ++ err = grub_netbuff_push (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &inf->address, ++ &multicast); ++ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb, ++ GRUB_NET_IP_UDP); ++ ++ grub_netbuff_free (nb); ++ ++ return err; ++} ++ ++struct grub_net_network_level_interface * ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6h, ++ grub_size_t size, ++ int is_def, ++ char **device, char **path) ++{ ++ struct grub_net_network_level_interface *inf; ++ grub_dhcp6_options_t dhcp6; ++ int mask = -1; ++ ++ dhcp6 = grub_dhcp6_options_get (v6h, size); ++ if (!dhcp6) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf); ++ ++ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip) ++ { ++ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip); ++ grub_print_error (); ++ } ++ if (path && dhcp6->boot_file_path) ++ { ++ *path = grub_strdup (dhcp6->boot_file_path); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ ++ grub_dhcp6_options_free (dhcp6); ++ ++ if (inf) ++ grub_net_add_ipv6_local (inf, mask); ++ ++ return inf; ++} ++ + /* + * This is called directly from net/ip.c:handle_dgram(), because those + * BOOTP/DHCP packets are a bit special due to their improper +@@ -672,6 +1342,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb, + } + } + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card __attribute__ ((unused))) ++{ ++ const struct grub_net_dhcp6_packet *v6h; ++ grub_dhcp6_session_t se; ++ grub_size_t size; ++ grub_dhcp6_options_t options; ++ ++ v6h = (const struct grub_net_dhcp6_packet *) nb->data; ++ size = nb->tail - nb->data; ++ ++ options = grub_dhcp6_options_get (v6h, size); ++ if (!options) ++ return grub_errno; ++ ++ if (!options->client_duid || !options->server_duid || !options->ia_addr) ++ { ++ grub_dhcp6_options_free (options); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet"); ++ } ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ if (se->transaction_id == v6h->transaction_id && ++ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 && ++ se->iaid == options->iaid) ++ break; ++ } ++ ++ if (!se) ++ { ++ grub_dprintf ("bootp", "DHCPv6 session not found\n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE) ++ { ++ if (se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->adv = options; ++ return grub_dhcp6_session_send_request (se); ++ } ++ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY) ++ { ++ if (!se->adv) ++ { ++ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n"); ++ grub_dhcp6_options_free (options); ++ return GRUB_ERR_NONE; ++ } ++ ++ se->reply = options; ++ grub_dhcp6_session_configure_network (se); ++ grub_dhcp6_session_remove (se); ++ return GRUB_ERR_NONE; ++ } ++ else ++ { ++ grub_dhcp6_options_free (options); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +@@ -897,180 +1638,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), + return err; + } + +-static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; +- +-struct grub_net_network_level_interface * +-grub_net_configure_by_dhcpv6_ack (const char *name, +- struct grub_net_card *card, +- grub_net_interface_flags_t flags +- __attribute__((__unused__)), +- const grub_net_link_level_address_t *hwaddr, +- const struct grub_net_dhcpv6_packet *packet, +- int is_def, char **device, char **path) ++static grub_err_t ++grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) + { +- struct grub_net_network_level_interface *inter = NULL; +- struct grub_net_network_level_address addr; +- int mask = -1; ++ struct grub_net_card *card; ++ grub_uint32_t iaid = 0; ++ int interval; ++ grub_err_t err; ++ grub_dhcp6_session_t se; + +- if (!device || !path) +- return NULL; ++ err = GRUB_ERR_NONE; + +- *device = 0; +- *path = 0; ++ FOR_NET_CARDS (card) ++ { ++ struct grub_net_network_level_interface *iface; + +- grub_dprintf ("net", "mac address is %02x:%02x:%02x:%02x:%02x:%02x\n", +- hwaddr->mac[0], hwaddr->mac[1], hwaddr->mac[2], +- hwaddr->mac[3], hwaddr->mac[4], hwaddr->mac[5]); ++ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) ++ continue; + +- if (is_def) +- grub_net_default_server = 0; ++ iface = grub_net_ipv6_get_link_local (card, &card->default_address); ++ if (!iface) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } + +- if (is_def && !grub_net_default_server && packet) ++ grub_dhcp6_session_add (iface, iaid++); ++ } ++ ++ for (interval = 200; interval < 10000; interval *= 2) + { +- const grub_uint8_t *options = packet->dhcp_options; +- unsigned int option_max = 1024 - OFFSET_OF (dhcp_options, packet); +- unsigned int i; +- +- for (i = 0; i < option_max - sizeof (grub_net_dhcpv6_option_t); ) +- { +- grub_uint16_t num, len; +- grub_net_dhcpv6_option_t *opt = +- (grub_net_dhcpv6_option_t *)(options + i); +- +- num = grub_be_to_cpu16(opt->option_num); +- len = grub_be_to_cpu16(opt->option_len); +- +- grub_dprintf ("net", "got dhcpv6 option %d len %d\n", num, len); +- +- if (len == 0) +- break; +- +- if (len + i > 1024) +- break; +- +- if (num == GRUB_NET_DHCP6_BOOTFILE_URL) +- { +- char *scheme, *userinfo, *host, *file; +- char *tmp; +- int hostlen; +- int port; +- int rc = extract_url_info ((const char *)opt->option_data, +- (grub_size_t)len, +- &scheme, &userinfo, &host, &port, +- &file); +- if (rc < 0) +- continue; +- +- /* right now this only handles tftp. */ +- if (grub_strcmp("tftp", scheme)) +- { +- grub_free (scheme); +- grub_free (userinfo); +- grub_free (host); +- grub_free (file); +- continue; +- } +- grub_free (userinfo); +- +- hostlen = grub_strlen (host); +- if (hostlen > 2 && host[0] == '[' && host[hostlen-1] == ']') +- { +- tmp = host+1; +- host[hostlen-1] = '\0'; +- } +- else +- tmp = host; +- +- *device = grub_xasprintf ("%s,%s", scheme, tmp); +- grub_free (scheme); +- grub_free (host); +- +- if (file && *file) +- { +- tmp = grub_strrchr (file, '/'); +- if (tmp) +- *(tmp+1) = '\0'; +- else +- file[0] = '\0'; +- } +- else if (!file) +- file = grub_strdup (""); +- +- if (file[0] == '/') +- { +- *path = grub_strdup (file+1); +- grub_free (file); +- } +- else +- *path = file; +- } +- else if (num == GRUB_NET_DHCP6_IA_NA) +- { +- const grub_net_dhcpv6_option_t *ia_na_opt; +- const grub_net_dhcpv6_opt_ia_na_t *ia_na = +- (const grub_net_dhcpv6_opt_ia_na_t *)opt; +- unsigned int left = len - OFFSET_OF (options, ia_na); +- unsigned int j; +- +- if ((grub_uint8_t *)ia_na + left > +- (grub_uint8_t *)options + option_max) +- left -= ((grub_uint8_t *)ia_na + left) +- - ((grub_uint8_t *)options + option_max); +- +- if (len < OFFSET_OF (option_data, opt) +- + sizeof (grub_net_dhcpv6_option_t)) +- { +- grub_dprintf ("net", +- "found dhcpv6 ia_na option with no address\n"); +- continue; +- } +- +- for (j = 0; left > sizeof (grub_net_dhcpv6_option_t); ) +- { +- ia_na_opt = (const grub_net_dhcpv6_option_t *) +- (ia_na->options + j); +- grub_uint16_t ia_na_opt_num, ia_na_opt_len; +- +- ia_na_opt_num = grub_be_to_cpu16 (ia_na_opt->option_num); +- ia_na_opt_len = grub_be_to_cpu16 (ia_na_opt->option_len); +- if (ia_na_opt_len == 0) +- break; +- if (j + ia_na_opt_len > left) +- break; +- if (ia_na_opt_num == GRUB_NET_DHCP6_IA_ADDRESS) +- { +- const grub_net_dhcpv6_opt_ia_address_t *ia_addr; +- +- ia_addr = (const grub_net_dhcpv6_opt_ia_address_t *) +- ia_na_opt; +- addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; +- grub_memcpy(addr.ipv6, ia_addr->ipv6_address, +- sizeof (ia_addr->ipv6_address)); +- inter = grub_net_add_addr (name, card, &addr, hwaddr, 0); +- } +- +- j += ia_na_opt_len; +- left -= ia_na_opt_len; +- } +- } +- +- i += len + 4; +- } +- +- grub_print_error (); ++ int done = 1; ++ ++ FOR_DHCP6_SESSIONS (se) ++ { ++ struct grub_net_buff *nb; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_packet *v6h; ++ struct grub_net_dhcp6_option_duid_ll *duid; ++ struct grub_net_dhcp6_option_iana *ia_na; ++ grub_net_network_level_address_t multicast; ++ grub_net_link_level_address_t ll_multicast; ++ struct udphdr *udph; ++ ++ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; ++ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48); ++ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL); ++ ++ err = grub_net_link_layer_resolve (se->iface, ++ &multicast, &ll_multicast); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ ++ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ ++ if (!nb) ++ { ++ grub_dhcp6_session_remove_all (); ++ return grub_errno; ++ } ++ ++ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t)); ++ grub_set_unaligned16 (opt->data, 0); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID); ++ opt->len = grub_cpu_to_be16 (sizeof (*duid)); ++ ++ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data; ++ grub_memcpy (duid, &se->duid, sizeof (*duid)); ++ ++ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->data; ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16 (sizeof (*ia_na)); ++ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data; ++ ia_na->iaid = grub_cpu_to_be32 (se->iaid); ++ ia_na->t1 = 0; ++ ia_na->t2 = 0; ++ ++ err = grub_netbuff_push (nb, sizeof (*v6h)); ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ v6h = (struct grub_net_dhcp6_packet *)nb->data; ++ v6h->message_type = GRUB_NET_DHCP6_SOLICIT; ++ v6h->transaction_id = se->transaction_id; ++ ++ grub_netbuff_push (nb, sizeof (*udph)); ++ ++ udph = (struct udphdr *) nb->data; ++ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT); ++ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT); ++ udph->chksum = 0; ++ udph->len = grub_cpu_to_be16 (nb->tail - nb->data); ++ ++ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, ++ &se->iface->address, &multicast); ++ ++ err = grub_net_send_ip_packet (se->iface, &multicast, ++ &ll_multicast, nb, GRUB_NET_IP_UDP); ++ done = 0; ++ grub_netbuff_free (nb); ++ ++ if (err) ++ { ++ grub_dhcp6_session_remove_all (); ++ return err; ++ } ++ } ++ if (!done) ++ grub_net_poll_cards (interval, 0); + } + +- if (is_def) ++ FOR_DHCP6_SESSIONS (se) + { +- grub_env_set ("net_default_interface", name); +- grub_env_export ("net_default_interface"); ++ grub_error_push (); ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("couldn't autoconfigure %s"), ++ se->iface->card->name); + } + +- if (inter) +- grub_net_add_ipv6_local (inter, mask); +- return inter; ++ grub_dhcp6_session_remove_all (); ++ ++ return err; + } + ++static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; + + void + grub_bootp_init (void) +@@ -1084,11 +1819,15 @@ grub_bootp_init (void) + cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt, + N_("VAR INTERFACE NUMBER DESCRIPTION"), + N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value.")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6, ++ N_("[CARD]"), ++ N_("perform a DHCPv6 autoconfiguration")); + } + + void + grub_bootp_fini (void) + { ++ grub_unregister_command (cmd_bootp6); + grub_unregister_command (cmd_getdhcp); + grub_unregister_command (cmd_bootp); + grub_unregister_command (cmd_dhcp); +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index a673bea807..8e25680db0 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -393,9 +393,6 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + pxe_mode = pxe->mode; + if (pxe_mode->using_ipv6) + { +- grub_net_link_level_address_t hwaddr; +- struct grub_net_network_level_interface *intf; +- + grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); + grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", + pxe_mode->dhcp_ack_received ? "yes" : "no", +@@ -403,15 +400,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (!pxe_mode->dhcp_ack_received) + continue; + +- hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; +- grub_memcpy (hwaddr.mac, +- card->efi_net->mode->current_address, +- sizeof (hwaddr.mac)); +- +- intf = grub_net_configure_by_dhcpv6_ack (card->name, card, 0, &hwaddr, +- (const struct grub_net_dhcpv6_packet *)&pxe_mode->dhcp_ack.dhcpv6, +- 1, device, path); +- if (intf && device && path) ++ grub_net_configure_by_dhcpv6_reply (card->name, card, 0, ++ (struct grub_net_dhcp6_packet *) ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), ++ 1, device, path); ++ if (grub_errno) ++ grub_print_error (); ++ if (device && path) + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + } + else +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index a5896f6dc2..ce6bdc75c6 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -239,6 +239,45 @@ handle_dgram (struct grub_net_buff *nb, + { + struct udphdr *udph; + udph = (struct udphdr *) nb->data; ++ ++ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT)) ++ { ++ if (udph->chksum) ++ { ++ grub_uint16_t chk, expected; ++ chk = udph->chksum; ++ udph->chksum = 0; ++ expected = grub_net_ip_transport_checksum (nb, ++ GRUB_NET_IP_UDP, ++ source, ++ dest); ++ if (expected != chk) ++ { ++ grub_dprintf ("net", "Invalid UDP checksum. " ++ "Expected %x, got %x\n", ++ grub_be_to_cpu16 (expected), ++ grub_be_to_cpu16 (chk)); ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ udph->chksum = chk; ++ } ++ ++ err = grub_netbuff_pull (nb, sizeof (*udph)); ++ if (err) ++ { ++ grub_netbuff_free (nb); ++ return err; ++ } ++ ++ err = grub_net_process_dhcp6 (nb, card); ++ if (err) ++ grub_print_error (); ++ ++ grub_netbuff_free (nb); ++ return GRUB_ERR_NONE; ++ } ++ + if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68) + { + const struct grub_net_bootp_packet *bootp; +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 9962880147..7614b58dca 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -1532,7 +1532,7 @@ typedef struct grub_efi_pxe_ip_filter + { + grub_efi_uint8_t filters; + grub_efi_uint8_t ip_count; +- grub_efi_uint8_t reserved; ++ grub_efi_uint16_t reserved; + grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; + } grub_efi_pxe_ip_filter_t; + +diff --git a/include/grub/net.h b/include/grub/net.h +index d55d505a03..543251f727 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -451,50 +451,65 @@ struct grub_net_bootp_packet + grub_uint8_t vendor[0]; + } GRUB_PACKED; + +-enum +- { +- GRUB_NET_DHCP6_IA_NA = 3, +- GRUB_NET_DHCP6_IA_ADDRESS = 5, +- GRUB_NET_DHCP6_BOOTFILE_URL = 59, +- }; +- +-struct grub_net_dhcpv6_option ++struct grub_net_dhcp6_packet + { +- grub_uint16_t option_num; +- grub_uint16_t option_len; +- grub_uint8_t option_data[]; ++ grub_uint32_t message_type:8; ++ grub_uint32_t transaction_id:24; ++ grub_uint8_t dhcp_options[0]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_option grub_net_dhcpv6_option_t; + +-struct grub_net_dhcpv6_opt_ia_na +-{ +- grub_uint16_t option_num; +- grub_uint16_t option_len; ++struct grub_net_dhcp6_option { ++ grub_uint16_t code; ++ grub_uint16_t len; ++ grub_uint8_t data[0]; ++} GRUB_PACKED; ++ ++struct grub_net_dhcp6_option_iana { + grub_uint32_t iaid; + grub_uint32_t t1; + grub_uint32_t t2; +- grub_uint8_t options[]; ++ grub_uint8_t data[0]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_opt_ia_na grub_net_dhcpv6_opt_ia_na_t; + +-struct grub_net_dhcpv6_opt_ia_address +-{ +- grub_uint16_t option_num; +- grub_uint16_t option_len; +- grub_uint64_t ipv6_address[2]; ++struct grub_net_dhcp6_option_iaaddr { ++ grub_uint8_t addr[16]; + grub_uint32_t preferred_lifetime; + grub_uint32_t valid_lifetime; +- grub_uint8_t options[]; ++ grub_uint8_t data[0]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_opt_ia_address grub_net_dhcpv6_opt_ia_address_t; + +-struct grub_net_dhcpv6_packet ++struct grub_net_dhcp6_option_duid_ll + { +- grub_uint32_t message_type:8; +- grub_uint32_t transaction_id:24; +- grub_uint8_t dhcp_options[1024]; ++ grub_uint16_t type; ++ grub_uint16_t hw_type; ++ grub_uint8_t hwaddr[6]; + } GRUB_PACKED; +-typedef struct grub_net_dhcpv6_packet grub_net_dhcpv6_packet_t; ++ ++enum ++ { ++ GRUB_NET_DHCP6_SOLICIT = 1, ++ GRUB_NET_DHCP6_ADVERTISE = 2, ++ GRUB_NET_DHCP6_REQUEST = 3, ++ GRUB_NET_DHCP6_REPLY = 7 ++ }; ++ ++enum ++ { ++ DHCP6_CLIENT_PORT = 546, ++ DHCP6_SERVER_PORT = 547 ++ }; ++ ++enum ++ { ++ GRUB_NET_DHCP6_OPTION_CLIENTID = 1, ++ GRUB_NET_DHCP6_OPTION_SERVERID = 2, ++ GRUB_NET_DHCP6_OPTION_IA_NA = 3, ++ GRUB_NET_DHCP6_OPTION_IAADDR = 5, ++ GRUB_NET_DHCP6_OPTION_ORO = 6, ++ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8, ++ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23, ++ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59 ++ }; + + #define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63 + #define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82 +@@ -532,12 +547,12 @@ grub_net_configure_by_dhcp_ack (const char *name, + int is_def, char **device, char **path); + + struct grub_net_network_level_interface * +-grub_net_configure_by_dhcpv6_ack (const char *name, +- struct grub_net_card *card, +- grub_net_interface_flags_t flags, +- const grub_net_link_level_address_t *hwaddr, +- const struct grub_net_dhcpv6_packet *packet, +- int is_def, char **device, char **path); ++grub_net_configure_by_dhcpv6_reply (const char *name, ++ struct grub_net_card *card, ++ grub_net_interface_flags_t flags, ++ const struct grub_net_dhcp6_packet *v6, ++ grub_size_t size, ++ int is_def, char **device, char **path); + + int + grub_ipv6_get_masksize(grub_uint16_t *mask); +@@ -554,6 +569,10 @@ void + grub_net_process_dhcp (struct grub_net_buff *nb, + struct grub_net_network_level_interface *iface); + ++grub_err_t ++grub_net_process_dhcp6 (struct grub_net_buff *nb, ++ struct grub_net_card *card); ++ + int + grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, + const grub_net_link_level_address_t *b); diff --git a/SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch b/SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch new file mode 100644 index 0000000..988c178 --- /dev/null +++ b/SOURCES/0073-efinet-UEFI-IPv6-PXE-support.patch @@ -0,0 +1,126 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 15 Apr 2015 14:48:30 +0800 +Subject: [PATCH] efinet: UEFI IPv6 PXE support + +When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is +cached in firmware buffer which can be obtained by PXE Base Code protocol. The +network interface can be setup through the parameters in that obtained packet. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 2 ++ + include/grub/efi/api.h | 71 +++++++++++++++++++++++--------------- + 2 files changed, 46 insertions(+), 27 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 8e25680db0..014e5bf980 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -409,6 +409,8 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_print_error (); + if (device && path) + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); ++ if (grub_errno) ++ grub_print_error (); + } + else + { +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 7614b58dca..91ab528e4d 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -1524,31 +1524,6 @@ typedef union + grub_efi_pxe_dhcpv6_packet_t dhcpv6; + } grub_efi_pxe_packet_t; + +-#define GRUB_EFI_PXE_MAX_IPCNT 8 +-#define GRUB_EFI_PXE_MAX_ARP_ENTRIES 8 +-#define GRUB_EFI_PXE_MAX_ROUTE_ENTRIES 8 +- +-typedef struct grub_efi_pxe_ip_filter +-{ +- grub_efi_uint8_t filters; +- grub_efi_uint8_t ip_count; +- grub_efi_uint16_t reserved; +- grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_MAX_IPCNT]; +-} grub_efi_pxe_ip_filter_t; +- +-typedef struct grub_efi_pxe_arp_entry +-{ +- grub_efi_ip_address_t ip_addr; +- grub_efi_mac_address_t mac_addr; +-} grub_efi_pxe_arp_entry_t; +- +-typedef struct grub_efi_pxe_route_entry +-{ +- grub_efi_ip_address_t ip_addr; +- grub_efi_ip_address_t subnet_mask; +- grub_efi_ip_address_t gateway_addr; +-} grub_efi_pxe_route_entry_t; +- + typedef struct grub_efi_pxe_icmp_error + { + grub_efi_uint8_t type; +@@ -1574,6 +1549,48 @@ typedef struct grub_efi_pxe_tftp_error + grub_efi_char8_t error_string[127]; + } grub_efi_pxe_tftp_error_t; + ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 ++typedef struct grub_efi_pxe_ip_filter ++{ ++ grub_efi_uint8_t filters; ++ grub_efi_uint8_t ip_count; ++ grub_efi_uint16_t reserved; ++ grub_efi_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT]; ++} grub_efi_pxe_ip_filter_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_mac_address_t mac_addr; ++} grub_efi_pxe_arp_entry_t; ++ ++typedef struct { ++ grub_efi_pxe_ip_address_t ip_addr; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ grub_efi_pxe_ip_address_t gw_addr; ++} grub_efi_pxe_route_entry_t; ++ ++ ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8 ++#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8 ++ + typedef struct grub_efi_pxe_mode + { + grub_efi_boolean_t started; +@@ -1605,9 +1622,9 @@ typedef struct grub_efi_pxe_mode + grub_efi_pxe_packet_t pxe_bis_reply; + grub_efi_pxe_ip_filter_t ip_filter; + grub_efi_uint32_t arp_cache_entries; +- grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_MAX_ARP_ENTRIES]; ++ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES]; + grub_efi_uint32_t route_table_entries; +- grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_MAX_ROUTE_ENTRIES]; ++ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES]; + grub_efi_pxe_icmp_error_t icmp_error; + grub_efi_pxe_tftp_error_t tftp_error; + } grub_efi_pxe_mode_t; diff --git a/SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch b/SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch new file mode 100644 index 0000000..b42e09b --- /dev/null +++ b/SOURCES/0074-grub.texi-Add-net_bootp6-doument.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Tue, 5 May 2015 14:19:24 +0800 +Subject: [PATCH] grub.texi: Add net_bootp6 doument + +Update grub documentation for net_bootp6 command. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + docs/grub.texi | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 0615d0ed97..04ed6ac1f0 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5487,6 +5487,7 @@ This command is only available on AArch64 systems. + * net_add_dns:: Add a DNS server + * net_add_route:: Add routing entry + * net_bootp:: Perform a bootp/DHCP autoconfiguration ++* net_bootp6:: Perform a DHCPv6 autoconfiguration + * net_del_addr:: Remove IP address from interface + * net_del_dns:: Remove a DNS server + * net_del_route:: Remove a route entry +@@ -5611,6 +5612,22 @@ Sets environment variable @samp{net_}@var{}@samp{_boot_file} + + @end deffn + ++@node net_bootp6 ++@subsection net_bootp6 ++ ++@deffn Command net_bootp6 [@var{card}] ++Perform configuration of @var{card} using DHCPv6 protocol. If no card name is ++specified, try to configure all existing cards. If configuration was ++successful, interface with name @var{card}@samp{:dhcp6} and configured address ++is added to @var{card}. ++ ++@table @samp ++@item 1 (Domain Name Server) ++Adds all servers from option value to the list of servers used during name ++resolution. ++@end table ++ ++@end deffn + + @node net_get_dhcp_option + @subsection net_get_dhcp_option diff --git a/SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch b/SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch new file mode 100644 index 0000000..abff9eb --- /dev/null +++ b/SOURCES/0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 10 Jul 2019 23:58:28 +0200 +Subject: [PATCH] bootp: Add processing DHCPACK packet from HTTP Boot + +The vendor class identifier with the string "HTTPClient" is used to denote the +packet as responding to HTTP boot request. In DHCP4 config, the filename for +HTTP boot is the URL of the boot file while for PXE boot it is the path to the +boot file. As a consequence, the next-server becomes obseleted because the HTTP +URL already contains the server address for the boot file. For DHCP6 config, +there's no difference definition in existing config as dhcp6.bootfile-url can +be used to specify URL for both HTTP and PXE boot file. + +This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK +packet by treating it as HTTP format, not as the PXE format. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/bootp.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ + include/grub/net.h | 1 + + 2 files changed, 56 insertions(+) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index fe93b80f1c..8fb8918ae7 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -500,6 +501,60 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (opt && opt_len) + grub_env_set_net_property (name, "rootpath", (const char *) opt, opt_len); + ++ opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER, &opt_len); ++ if (opt && opt_len) ++ { ++ grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); ++ if (opt && grub_strcmp (opt, "HTTPClient") == 0) ++ { ++ char *proto, *ip, *pa; ++ ++ if (!dissect_url (bp->boot_file, &proto, &ip, &pa)) ++ return inter; ++ ++ grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa)); ++ if (is_def) ++ { ++ grub_net_default_server = grub_strdup (ip); ++ grub_env_set ("net_default_interface", name); ++ grub_env_export ("net_default_interface"); ++ } ++ if (device && !*device) ++ { ++ *device = grub_xasprintf ("%s,%s", proto, ip); ++ grub_print_error (); ++ } ++ if (path) ++ { ++ *path = grub_strdup (pa); ++ grub_print_error (); ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ } ++ grub_net_add_ipv4_local (inter, mask); ++ inter->dhcp_ack = grub_malloc (size); ++ if (inter->dhcp_ack) ++ { ++ grub_memcpy (inter->dhcp_ack, bp, size); ++ inter->dhcp_acklen = size; ++ } ++ else ++ grub_errno = GRUB_ERR_NONE; ++ ++ grub_free (proto); ++ grub_free (ip); ++ grub_free (pa); ++ return inter; ++ } ++ } ++ + opt = find_dhcp_option (bp, size, GRUB_NET_BOOTP_EXTENSIONS_PATH, &opt_len); + if (opt && opt_len) + grub_env_set_net_property (name, "extensionspath", (const char *) opt, opt_len); +diff --git a/include/grub/net.h b/include/grub/net.h +index 543251f727..42af7de250 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -531,6 +531,7 @@ enum + GRUB_NET_DHCP_MESSAGE_TYPE = 53, + GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, + GRUB_NET_DHCP_PARAMETER_REQUEST_LIST = 55, ++ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 60, + GRUB_NET_BOOTP_CLIENT_ID = 61, + GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, + GRUB_NET_DHCP_BOOTFILE_NAME = 67, diff --git a/SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch b/SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch new file mode 100644 index 0000000..f4faf27 --- /dev/null +++ b/SOURCES/0076-efinet-Setting-network-from-UEFI-device-path.patch @@ -0,0 +1,405 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Sun, 10 Jul 2016 23:46:31 +0800 +Subject: [PATCH] efinet: Setting network from UEFI device path + +The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no +longer provided for HTTP Boot. Instead, we have to get the HTTP boot +information from the device path nodes defined in following UEFI Specification +sections. + + 9.3.5.12 IPv4 Device Path + 9.3.5.13 IPv6 Device Path + 9.3.5.23 Uniform Resource Identifiers (URI) Device Path + +This patch basically does: + +include/grub/efi/api.h: +Add new structure of Uniform Resource Identifiers (URI) Device Path + +grub-core/net/drivers/efi/efinet.c: +Check if PXE Base Code is available, if not it will try to obtain the netboot +information from the device path where the image booted from. The DHCPACK +packet is recoverd from the information in device patch and feed into the same +DHCP packet processing functions to ensure the network interface is setting up +the same way it used to be. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 284 +++++++++++++++++++++++++++++++++++-- + include/grub/efi/api.h | 11 ++ + 2 files changed, 280 insertions(+), 15 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 014e5bf980..8171ecaa5e 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -331,6 +332,227 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static struct grub_net_buff * ++grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) ++{ ++ grub_efi_uint16_t uri_len; ++ grub_efi_device_path_t *ldp, *ddp; ++ grub_efi_uri_device_path_t *uri_dp; ++ struct grub_net_buff *nb; ++ grub_err_t err; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ if (!ddp) ++ return NULL; ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0; ++ ++ if (!uri_len) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ uri_dp = (grub_efi_uri_device_path_t *) ldp; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ nb = grub_netbuff_alloc (512); ++ if (!nb) ++ { ++ grub_free (ddp); ++ return NULL; ++ } ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; ++ struct grub_net_bootp_packet *bp; ++ grub_uint8_t *ptr; ++ ++ bp = (struct grub_net_bootp_packet *) nb->tail; ++ err = grub_netbuff_put (nb, sizeof (*bp) + 4); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ if (sizeof(bp->boot_file) < uri_len) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len); ++ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip)); ++ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip)); ++ ++ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0; ++ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1; ++ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2; ++ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_NETMASK; ++ *ptr++ = sizeof (ipv4->subnet_mask); ++ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_ROUTER; ++ *ptr++ = sizeof (ipv4->gateway_ip_address); ++ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address)); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER; ++ *ptr++ = sizeof ("HTTPClient") - 1; ++ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, 1); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr = GRUB_NET_BOOTP_END; ++ *use_ipv6 = 0; ++ ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp; ++ bp->hw_type = mac->if_type; ++ bp->hw_len = sizeof (bp->mac_addr); ++ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len); ++ } ++ } ++ else ++ { ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp; ++ ++ struct grub_net_dhcp6_packet *d6p; ++ struct grub_net_dhcp6_option *opt; ++ struct grub_net_dhcp6_option_iana *iana; ++ struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ ++ d6p = (struct grub_net_dhcp6_packet *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*d6p)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ d6p->message_type = GRUB_NET_DHCP6_REPLY; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr)); ++ ++ err = grub_netbuff_put (nb, sizeof(*iana)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR); ++ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr)); ++ ++ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*iaaddr)); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address)); ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL); ++ opt->len = grub_cpu_to_be16 (uri_len); ++ grub_memcpy (opt->data, uri_dp->uri, uri_len); ++ ++ *use_ipv6 = 1; ++ } ++ ++ grub_free (ddp); ++ return nb; ++} ++ + static void + grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + char **path) +@@ -346,7 +568,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + { + grub_efi_device_path_t *cdp; + struct grub_efi_pxe *pxe; +- struct grub_efi_pxe_mode *pxe_mode; ++ struct grub_efi_pxe_mode *pxe_mode = NULL; ++ grub_uint8_t *packet_buf; ++ grub_size_t packet_bufsz ; ++ int ipv6; ++ struct grub_net_buff *nb = NULL; + + if (card->driver != &efidriver) + continue; +@@ -370,11 +596,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + */ + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE +- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); + if (!dup_dp) + continue; ++ ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -387,23 +623,37 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + + pxe = grub_efi_open_protocol (hnd, &pxe_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); +- if (! pxe) +- continue; ++ if (!pxe) ++ { ++ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6); ++ if (!nb) ++ { ++ grub_print_error (); ++ continue; ++ } ++ packet_buf = nb->head; ++ packet_bufsz = nb->tail - nb->head; ++ } ++ else ++ { ++ pxe_mode = pxe->mode; ++ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack; ++ packet_bufsz = sizeof (pxe_mode->dhcp_ack); ++ ipv6 = pxe_mode->using_ipv6; ++ } + +- pxe_mode = pxe->mode; +- if (pxe_mode->using_ipv6) ++ if (ipv6) + { + grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); +- grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", +- pxe_mode->dhcp_ack_received ? "yes" : "no", +- pxe_mode->dhcp_ack_received ? "" : " cannot continue"); +- if (!pxe_mode->dhcp_ack_received) +- continue; ++ if (pxe_mode) ++ grub_dprintf ("efinet", "dhcp_ack_received: %s%s\n", ++ pxe_mode->dhcp_ack_received ? "yes" : "no", ++ pxe_mode->dhcp_ack_received ? "" : " cannot continue"); + + grub_net_configure_by_dhcpv6_reply (card->name, card, 0, + (struct grub_net_dhcp6_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + if (grub_errno) + grub_print_error (); +@@ -417,11 +667,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + grub_dprintf ("efinet", "using ipv4 and dhcp\n"); + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) +- &pxe_mode->dhcp_ack, +- sizeof (pxe_mode->dhcp_ack), ++ packet_buf, ++ packet_bufsz, + 1, device, path); + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + } ++ ++ if (nb) ++ grub_netbuff_free (nb); ++ + return; + } + } +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 91ab528e4d..4a51667adb 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -864,6 +864,8 @@ struct grub_efi_ipv4_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_ipv4_address_t gateway_ip_address; ++ grub_efi_ipv4_address_t subnet_mask; + } GRUB_PACKED; + typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t; + +@@ -918,6 +920,15 @@ struct grub_efi_sata_device_path + } GRUB_PACKED; + typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t; + ++#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24 ++ ++struct grub_efi_uri_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t uri[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ diff --git a/SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch b/SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch new file mode 100644 index 0000000..2d92ff0 --- /dev/null +++ b/SOURCES/0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch @@ -0,0 +1,336 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Thu, 14 Jul 2016 17:48:45 +0800 +Subject: [PATCH] efinet: Setting DNS server from UEFI protocol + +In the URI device path node, any name rahter than address can be used for +looking up the resources so that DNS service become needed to get answer of the +name's address. Unfortunately the DNS is not defined in any of the device path +nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL +to obtain it. + +These two protcols are defined the sections of UEFI specification. + + 27.5 EFI IPv4 Configuration II Protocol + 27.7 EFI IPv6 Configuration Protocol + +include/grub/efi/api.h: +Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and +EFI_IP6_CONFIG_PROTOCOL. + +grub-core/net/drivers/efi/efinet.c: +Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list +of DNS server address for IPv4 and IPv6 respectively. The address of DNS +servers is structured into DHCPACK packet and feed into the same DHCP packet +processing functions to ensure the network interface is setting up the same way +it used to be. + +Signed-off-by: Michael Chang +Signed-off-by: Ken Lin +--- + grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 75 +++++++++++++++++ + 2 files changed, 238 insertions(+) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 8171ecaa5e..715a6168d7 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -33,6 +33,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + /* GUID. */ + static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; + static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; + + static grub_err_t + send_card_buffer (struct grub_net_card *dev, +@@ -332,6 +334,125 @@ grub_efinet_findcards (void) + grub_free (handles); + } + ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static grub_efi_ipv4_address_t * ++grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_protocol_t *conf; ++ grub_efi_ipv4_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t); ++ return addrs; ++} ++ ++static grub_efi_ipv6_address_t * ++grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns) ++{ ++ grub_efi_handle_t hnd; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_protocol_t *conf; ++ grub_efi_ipv6_address_t *addrs; ++ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t); ++ ++ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL); ++ ++ if (!hnd) ++ return 0; ++ ++ conf = grub_efi_open_protocol (hnd, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!conf) ++ return 0; ++ ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (addrs); ++ addrs = grub_malloc (data_size); ++ if (!addrs) ++ return 0; ++ ++ status = efi_call_4 (conf->get_data, conf, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ &data_size, addrs); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (addrs); ++ return 0; ++ } ++ ++ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t); ++ return addrs; ++} ++ + static struct grub_net_buff * + grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6) + { +@@ -390,6 +511,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp; + struct grub_net_bootp_packet *bp; + grub_uint8_t *ptr; ++ grub_efi_ipv4_address_t *dns; ++ grub_efi_uintn_t num_dns; + + bp = (struct grub_net_bootp_packet *) nb->tail; + err = grub_netbuff_put (nb, sizeof (*bp) + 4); +@@ -451,6 +574,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + *ptr++ = sizeof ("HTTPClient") - 1; + grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1); + ++ dns = grub_dns_server_ip4_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ ptr = nb->tail; ++ err = grub_netbuff_put (nb, size_dns + 2); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ *ptr++ = GRUB_NET_BOOTP_DNS; ++ *ptr++ = size_dns; ++ grub_memcpy (ptr, dns, size_dns); ++ grub_free (dns); ++ } ++ + ptr = nb->tail; + err = grub_netbuff_put (nb, 1); + if (err) +@@ -483,6 +625,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + struct grub_net_dhcp6_option *opt; + struct grub_net_dhcp6_option_iana *iana; + struct grub_net_dhcp6_option_iaaddr *iaaddr; ++ grub_efi_ipv6_address_t *dns; ++ grub_efi_uintn_t num_dns; + + d6p = (struct grub_net_dhcp6_packet *)nb->tail; + err = grub_netbuff_put (nb, sizeof(*d6p)); +@@ -546,6 +690,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + opt->len = grub_cpu_to_be16 (uri_len); + grub_memcpy (opt->data, uri_dp->uri, uri_len); + ++ dns = grub_dns_server_ip6_address (dp, &num_dns); ++ if (dns) ++ { ++ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns; ++ ++ opt = (struct grub_net_dhcp6_option *)nb->tail; ++ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns); ++ if (err) ++ { ++ grub_free (ddp); ++ grub_netbuff_free (nb); ++ return NULL; ++ } ++ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS); ++ opt->len = grub_cpu_to_be16 (size_dns); ++ grub_memcpy (opt->data, dns, size_dns); ++ grub_free (dns); ++ } ++ + *use_ipv6 = 1; + } + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 4a51667adb..0b490195ad 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -352,6 +352,15 @@ + #define GRUB_EFI_RNG_PROTOCOL_GUID \ + { 0x3152bca5, 0xeade, 0x433d, \ + { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ ++ ++#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \ ++ { 0x5b446ed1, 0xe30b, 0x4faa, \ ++ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ ++ } ++ ++#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \ ++ { 0x937fe521, 0x95ae, 0x4d1a, \ ++ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + + struct grub_efi_sal_system_table +@@ -1883,6 +1892,72 @@ struct grub_efi_rng_protocol + }; + typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + ++enum grub_efi_ip4_config2_data_type { ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t; ++ ++struct grub_efi_ip4_config2_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this, ++ grub_efi_ip4_config2_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; ++ ++enum grub_efi_ip6_config_data_type { ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM ++}; ++typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t; ++ ++struct grub_efi_ip6_config_protocol ++{ ++ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t data_size, ++ void *data); ++ ++ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_uintn_t *data_size, ++ void *data); ++ ++ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++ ++ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this, ++ grub_efi_ip6_config_data_type_t data_type, ++ grub_efi_event_t event); ++}; ++typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) diff --git a/SOURCES/0078-Support-UEFI-networking-protocols.patch b/SOURCES/0078-Support-UEFI-networking-protocols.patch new file mode 100644 index 0000000..145becf --- /dev/null +++ b/SOURCES/0078-Support-UEFI-networking-protocols.patch @@ -0,0 +1,5053 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 22 Feb 2017 14:27:50 +0800 +Subject: [PATCH] Support UEFI networking protocols + +References: fate#320130, bsc#1015589, bsc#1076132 +Patch-Mainline: no + +V1: + * Add preliminary support of UEFI networking protocols + * Support UEFI HTTPS Boot + +V2: + * Workaround http data access in firmware + * Fix DNS device path parsing for efinet device + * Relaxed UEFI Protocol requirement + * Support Intel OPA (Omni-Path Architecture) PXE Boot + +V3: + * Fix bufio in calculating address of next_buf + * Check HTTP respond code + * Use HEAD request method to test before GET + * Finish HTTP transaction in one go + * Fix bsc#1076132 + +Signed-off-by: Michael Chang +[pjones: make efi_netfs not duplicate symbols from efinet] +Signed-off-by: Peter Jones +--- + grub-core/Makefile.core.def | 12 + + grub-core/io/bufio.c | 2 +- + grub-core/kern/efi/efi.c | 96 ++- + grub-core/net/drivers/efi/efinet.c | 27 + + grub-core/net/efi/dhcp.c | 397 ++++++++++ + grub-core/net/efi/efi_netfs.c | 57 ++ + grub-core/net/efi/http.c | 419 +++++++++++ + grub-core/net/efi/ip4_config.c | 398 ++++++++++ + grub-core/net/efi/ip6_config.c | 422 +++++++++++ + grub-core/net/efi/net.c | 1428 ++++++++++++++++++++++++++++++++++++ + grub-core/net/efi/pxe.c | 424 +++++++++++ + grub-core/net/net.c | 74 ++ + util/grub-mknetdir.c | 23 +- + include/grub/efi/api.h | 180 ++++- + include/grub/efi/dhcp.h | 343 +++++++++ + include/grub/efi/http.h | 215 ++++++ + include/grub/net/efi.h | 144 ++++ + 17 files changed, 4620 insertions(+), 41 deletions(-) + create mode 100644 grub-core/net/efi/dhcp.c + create mode 100644 grub-core/net/efi/efi_netfs.c + create mode 100644 grub-core/net/efi/http.c + create mode 100644 grub-core/net/efi/ip4_config.c + create mode 100644 grub-core/net/efi/ip6_config.c + create mode 100644 grub-core/net/efi/net.c + create mode 100644 grub-core/net/efi/pxe.c + create mode 100644 include/grub/efi/dhcp.h + create mode 100644 include/grub/efi/http.h + create mode 100644 include/grub/net/efi.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 52ec0fafcd..12797336c9 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2300,6 +2300,12 @@ module = { + common = hook/datehook.c; + }; + ++module = { ++ name = efi_netfs; ++ common = net/efi/efi_netfs.c; ++ enable = efi; ++}; ++ + module = { + name = net; + common = net/net.c; +@@ -2313,6 +2319,12 @@ module = { + common = net/ethernet.c; + common = net/arp.c; + common = net/netbuff.c; ++ efi = net/efi/net.c; ++ efi = net/efi/http.c; ++ efi = net/efi/pxe.c; ++ efi = net/efi/ip4_config.c; ++ efi = net/efi/ip6_config.c; ++ efi = net/efi/dhcp.c; + }; + + module = { +diff --git a/grub-core/io/bufio.c b/grub-core/io/bufio.c +index a458c3aca7..1637731535 100644 +--- a/grub-core/io/bufio.c ++++ b/grub-core/io/bufio.c +@@ -139,7 +139,7 @@ grub_bufio_read (grub_file_t file, char *buf, grub_size_t len) + return res; + + /* Need to read some more. */ +- next_buf = (file->offset + res + len - 1) & ~((grub_off_t) bufio->block_size - 1); ++ next_buf = (grub_divmod64 (file->offset + res + len - 1, bufio->block_size, NULL)) * bufio->block_size; + /* Now read between file->offset + res and bufio->buffer_at. */ + if (file->offset + res < next_buf) + { +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index d6a2fb5778..2a446f5031 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -755,7 +755,7 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + { + grub_efi_ipv4_device_path_t *ipv4 + = (grub_efi_ipv4_device_path_t *) dp; +- grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x)", ++ grub_printf ("/IPv4(%u.%u.%u.%u,%u.%u.%u.%u,%u,%u,%x,%x", + (unsigned) ipv4->local_ip_address[0], + (unsigned) ipv4->local_ip_address[1], + (unsigned) ipv4->local_ip_address[2], +@@ -768,33 +768,60 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + (unsigned) ipv4->remote_port, + (unsigned) ipv4->protocol, + (unsigned) ipv4->static_ip_address); ++ if (len == sizeof (*ipv4)) ++ { ++ grub_printf (",%u.%u.%u.%u,%u.%u.%u.%u", ++ (unsigned) ipv4->gateway_ip_address[0], ++ (unsigned) ipv4->gateway_ip_address[1], ++ (unsigned) ipv4->gateway_ip_address[2], ++ (unsigned) ipv4->gateway_ip_address[3], ++ (unsigned) ipv4->subnet_mask[0], ++ (unsigned) ipv4->subnet_mask[1], ++ (unsigned) ipv4->subnet_mask[2], ++ (unsigned) ipv4->subnet_mask[3]); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE: + { + grub_efi_ipv6_device_path_t *ipv6 + = (grub_efi_ipv6_device_path_t *) dp; +- grub_printf ("/IPv6(%x:%x:%x:%x:%x:%x:%x:%x,%x:%x:%x:%x:%x:%x:%x:%x,%u,%u,%x,%x)", +- (unsigned) ipv6->local_ip_address[0], +- (unsigned) ipv6->local_ip_address[1], +- (unsigned) ipv6->local_ip_address[2], +- (unsigned) ipv6->local_ip_address[3], +- (unsigned) ipv6->local_ip_address[4], +- (unsigned) ipv6->local_ip_address[5], +- (unsigned) ipv6->local_ip_address[6], +- (unsigned) ipv6->local_ip_address[7], +- (unsigned) ipv6->remote_ip_address[0], +- (unsigned) ipv6->remote_ip_address[1], +- (unsigned) ipv6->remote_ip_address[2], +- (unsigned) ipv6->remote_ip_address[3], +- (unsigned) ipv6->remote_ip_address[4], +- (unsigned) ipv6->remote_ip_address[5], +- (unsigned) ipv6->remote_ip_address[6], +- (unsigned) ipv6->remote_ip_address[7], ++ grub_printf ("/IPv6(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x,%u,%u,%x,%x", ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->local_ip_address[7]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->remote_ip_address[7]), + (unsigned) ipv6->local_port, + (unsigned) ipv6->remote_port, + (unsigned) ipv6->protocol, + (unsigned) ipv6->static_ip_address); ++ if (len == sizeof (*ipv6)) ++ { ++ grub_printf (",%u,%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", ++ (unsigned) ipv6->prefix_length, ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[0]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[1]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[2]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[3]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[4]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[5]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[6]), ++ (unsigned) grub_be_to_cpu16 (ipv6->gateway_ip_address[7])); ++ } ++ grub_printf (")"); + } + break; + case GRUB_EFI_INFINIBAND_DEVICE_PATH_SUBTYPE: +@@ -834,6 +861,39 @@ grub_efi_print_device_path (grub_efi_device_path_t *dp) + dump_vendor_path ("Messaging", + (grub_efi_vendor_device_path_t *) dp); + break; ++ case GRUB_EFI_URI_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_uri_device_path_t *uri ++ = (grub_efi_uri_device_path_t *) dp; ++ grub_printf ("/URI(%s)", uri->uri); ++ } ++ break; ++ case GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE: ++ { ++ grub_efi_dns_device_path_t *dns ++ = (grub_efi_dns_device_path_t *) dp; ++ if (dns->is_ipv6) ++ { ++ grub_printf ("/DNS(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)", ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[0])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[1])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[2])), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]) >> 16), ++ (grub_uint16_t)(grub_be_to_cpu32(dns->dns_server_ip[0].addr[3]))); ++ } ++ else ++ { ++ grub_printf ("/DNS(%d.%d.%d.%d)", ++ dns->dns_server_ip[0].v4.addr[0], ++ dns->dns_server_ip[0].v4.addr[1], ++ dns->dns_server_ip[0].v4.addr[2], ++ dns->dns_server_ip[0].v4.addr[3]); ++ } ++ } ++ break; + default: + grub_printf ("/UnknownMessaging(%x)", (unsigned) subtype); + break; +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index 715a6168d7..e11d759f19 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -491,6 +492,17 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u + + ldp = grub_efi_find_last_device_path (ddp); + ++ /* Skip the DNS Device */ ++ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ ++ ldp = grub_efi_find_last_device_path (ddp); ++ } ++ + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)) +@@ -760,6 +772,7 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE + || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE ++ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE + && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + continue; + dup_dp = grub_efi_duplicate_device_path (dp); +@@ -774,6 +787,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + dup_ldp->length = sizeof (*dup_ldp); + } + ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE) ++ { ++ dup_ldp = grub_efi_find_last_device_path (dup_dp); ++ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ dup_ldp->length = sizeof (*dup_ldp); ++ } ++ + dup_ldp = grub_efi_find_last_device_path (dup_dp); + dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; + dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; +@@ -845,6 +867,9 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + + GRUB_MOD_INIT(efinet) + { ++ if (grub_efi_net_config) ++ return; ++ + grub_efinet_findcards (); + grub_efi_net_config = grub_efi_net_config_real; + } +@@ -856,5 +881,7 @@ GRUB_MOD_FINI(efinet) + FOR_NET_CARDS_SAFE (card, next) + if (card->driver == &efidriver) + grub_net_card_unregister (card); ++ ++ grub_efi_net_config = NULL; + } + +diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c +new file mode 100644 +index 0000000000..dbef63d8c0 +--- /dev/null ++++ b/grub-core/net/efi/dhcp.c +@@ -0,0 +1,397 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef GRUB_EFI_NET_DEBUG ++static void ++dhcp4_mode_print (grub_efi_dhcp4_mode_data_t *mode) ++{ ++ switch (mode->state) ++ { ++ case GRUB_EFI_DHCP4_STOPPED: ++ grub_printf ("STATE: STOPPED\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT: ++ grub_printf ("STATE: INIT\n"); ++ break; ++ case GRUB_EFI_DHCP4_SELECTING: ++ grub_printf ("STATE: SELECTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REQUESTING: ++ grub_printf ("STATE: REQUESTING\n"); ++ break; ++ case GRUB_EFI_DHCP4_BOUND: ++ grub_printf ("STATE: BOUND\n"); ++ break; ++ case GRUB_EFI_DHCP4_RENEWING: ++ grub_printf ("STATE: RENEWING\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBINDING: ++ grub_printf ("STATE: REBINDING\n"); ++ break; ++ case GRUB_EFI_DHCP4_INIT_REBOOT: ++ grub_printf ("STATE: INIT_REBOOT\n"); ++ break; ++ case GRUB_EFI_DHCP4_REBOOTING: ++ grub_printf ("STATE: REBOOTING\n"); ++ break; ++ default: ++ grub_printf ("STATE: UNKNOWN\n"); ++ break; ++ } ++ ++ grub_printf ("CLIENT_ADDRESS: %u.%u.%u.%u\n", ++ mode->client_address[0], ++ mode->client_address[1], ++ mode->client_address[2], ++ mode->client_address[3]); ++ grub_printf ("SERVER_ADDRESS: %u.%u.%u.%u\n", ++ mode->server_address[0], ++ mode->server_address[1], ++ mode->server_address[2], ++ mode->server_address[3]); ++ grub_printf ("SUBNET_MASK: %u.%u.%u.%u\n", ++ mode->subnet_mask[0], ++ mode->subnet_mask[1], ++ mode->subnet_mask[2], ++ mode->subnet_mask[3]); ++ grub_printf ("ROUTER_ADDRESS: %u.%u.%u.%u\n", ++ mode->router_address[0], ++ mode->router_address[1], ++ mode->router_address[2], ++ mode->router_address[3]); ++} ++#endif ++ ++static grub_efi_ipv4_address_t * ++grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packet_t *reply_packet) ++{ ++ grub_efi_dhcp4_packet_option_t **option_list; ++ grub_efi_status_t status; ++ grub_efi_uint32_t option_count = 0; ++ grub_efi_uint32_t i; ++ ++ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, NULL); ++ ++ if (status != GRUB_EFI_BUFFER_TOO_SMALL) ++ return NULL; ++ ++ option_list = grub_malloc (option_count * sizeof(*option_list)); ++ if (!option_list) ++ return NULL; ++ ++ status = efi_call_4 (dhcp4->parse, dhcp4, reply_packet, &option_count, option_list); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ ++ for (i = 0; i < option_count; ++i) ++ { ++ if (option_list[i]->op_code == 6) ++ { ++ grub_efi_ipv4_address_t *dns_address; ++ ++ if (((option_list[i]->length & 0x3) != 0) || (option_list[i]->length == 0)) ++ continue; ++ ++ /* We only contact primary dns */ ++ dns_address = grub_malloc (sizeof (*dns_address)); ++ if (!dns_address) ++ { ++ grub_free (option_list); ++ return NULL; ++ } ++ grub_memcpy (dns_address, option_list[i]->data, sizeof (dns_address)); ++ grub_free (option_list); ++ return dns_address; ++ } ++ } ++ ++ grub_free (option_list); ++ return NULL; ++} ++ ++#if 0 ++/* Somehow this doesn't work ... */ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_pxe_t *pxe = dev->ip4_pxe; ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ grub_efi_status_t status; ++ ++ if (!mode->started) ++ { ++ status = efi_call_2 (pxe->start, pxe, 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++ status = efi_call_2 (pxe->dhcp, pxe, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ dev->prefer_ip6 = 0; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++#endif ++ ++static grub_err_t ++grub_cmd_efi_bootp (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ grub_efi_status_t status; ++ grub_efi_dhcp4_mode_data_t mode; ++ grub_efi_dhcp4_config_data_t config; ++ grub_efi_dhcp4_packet_option_t *options; ++ grub_efi_ipv4_address_t *dns_address; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_net_ip_address_t ip_addr; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (netdev->card_name, args[0]) != 0) ++ continue; ++ ++ grub_memset (&config, 0, sizeof(config)); ++ ++ config.option_count = 1; ++ options = grub_malloc (sizeof(*options) + 2); ++ /* Parameter request list */ ++ options->op_code = 55; ++ options->length = 3; ++ /* subnet mask */ ++ options->data[0] = 1; ++ /* router */ ++ options->data[1] = 3; ++ /* DNS */ ++ options->data[2] = 6; ++ config.option_list = &options; ++ ++ /* FIXME: What if the dhcp has bounded */ ++ status = efi_call_2 (netdev->dhcp4->configure, netdev->dhcp4, &config); ++ grub_free (options); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 configure failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_2 (netdev->dhcp4->start, netdev->dhcp4, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_2 (netdev->dhcp4->get_mode_data, netdev->dhcp4, &mode); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++#ifdef GRUB_EFI_NET_DEBUG ++ dhcp4_mode_print (&mode); ++#endif ++ ++ for (inf = netdev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 0) ++ break; ++ ++ grub_memcpy (net_ip.ip4.address, mode.client_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, mode.subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", netdev->card_name); ++ ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ grub_memcpy (ip_addr.ip4, mode.router_address, sizeof (ip_addr.ip4)); ++ efi_net_interface_set_gateway (inf, &ip_addr); ++ ++ dns_address = grub_efi_dhcp4_parse_dns (netdev->dhcp4, mode.reply_packet); ++ if (dns_address) ++ efi_net_interface_set_dns (inf, (grub_efi_net_ip_address_t *)&dns_address); ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++static grub_err_t ++grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, ++ char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_uint32_t ia_id; ++ ++ for (dev = net_devices, ia_id = 0; dev; dev = dev->next, ia_id++) ++ { ++ grub_efi_dhcp6_config_data_t config; ++ grub_efi_dhcp6_packet_option_t *option_list[1]; ++ grub_efi_dhcp6_packet_option_t *opt; ++ grub_efi_status_t status; ++ grub_efi_dhcp6_mode_data_t mode; ++ grub_efi_dhcp6_retransmission_t retrans; ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_net_interface_t *inf = NULL; ++ ++ if (argc > 0 && grub_strcmp (dev->card_name, args[0]) != 0) ++ continue; ++ ++ opt = grub_malloc (sizeof(*opt) + 2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_ORO 6 ++ ++ opt->op_code = grub_cpu_to_be16_compile_time (GRUB_EFI_DHCP6_OPT_ORO); ++ opt->op_len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_efi_uint16_t)); ++ ++#define GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL 59 ++#define GRUB_EFI_DHCP6_OPT_DNS_SERVERS 23 ++ ++ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_BOOT_FILE_URL)); ++ grub_set_unaligned16 (opt->data + 1 * sizeof (grub_efi_uint16_t), ++ grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)); ++ ++ option_list[0] = opt; ++ retrans.irt = 4; ++ retrans.mrc = 4; ++ retrans.mrt = 32; ++ retrans.mrd = 60; ++ ++ config.dhcp6_callback = NULL; ++ config.callback_context = NULL; ++ config.option_count = 1; ++ config.option_list = option_list; ++ config.ia_descriptor.ia_id = ia_id; ++ config.ia_descriptor.type = GRUB_EFI_DHCP6_IA_TYPE_NA; ++ config.ia_info_event = NULL; ++ config.reconfigure_accept = 0; ++ config.rapid_commit = 0; ++ config.solicit_retransmission = &retrans; ++ ++ status = efi_call_2 (dev->dhcp6->configure, dev->dhcp6, &config); ++ grub_free (opt); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 configure failed, %d\n", (int)status); ++ continue; ++ } ++ status = efi_call_1 (dev->dhcp6->start, dev->dhcp6); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp6 start failed, %d\n", (int)status); ++ continue; ++ } ++ ++ status = efi_call_3 (dev->dhcp6->get_mode_data, dev->dhcp6, &mode, NULL); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("dhcp4 get mode failed, %d\n", (int)status); ++ continue; ++ } ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6 == 1) ++ break; ++ ++ grub_memcpy (net_ip.ip6.address, mode.ia->ia_address[0].ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = 64; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ ++ if (!inf) ++ { ++ char *name = grub_xasprintf ("%s:dhcp", dev->card_name); ++ ++ inf = grub_efi_net_create_interface (dev, ++ name, ++ &net_ip, ++ 1); ++ grub_free (name); ++ } ++ else ++ { ++ efi_net_interface_set_address (inf, &net_ip, 1); ++ } ++ ++ { ++ grub_efi_uint32_t count = 0; ++ grub_efi_dhcp6_packet_option_t **options = NULL; ++ grub_efi_uint32_t i; ++ ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, NULL); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) ++ { ++ options = grub_malloc (count * sizeof(*options)); ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (options) ++ grub_free (options); ++ continue; ++ } ++ ++ for (i = 0; i < count; ++i) ++ { ++ if (options[i]->op_code == grub_cpu_to_be16_compile_time(GRUB_EFI_DHCP6_OPT_DNS_SERVERS)) ++ { ++ grub_efi_net_ip_address_t dns; ++ grub_memcpy (dns.ip6, options[i]->data, sizeof(net_ip.ip6)); ++ efi_net_interface_set_dns (inf, &dns); ++ break; ++ } ++ } ++ ++ if (options) ++ grub_free (options); ++ } ++ ++ efi_call_1 (b->free_pool, mode.client_id); ++ efi_call_1 (b->free_pool, mode.ia); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_command_func_t grub_efi_net_bootp = grub_cmd_efi_bootp; ++grub_command_func_t grub_efi_net_bootp6 = grub_cmd_efi_bootp6; +diff --git a/grub-core/net/efi/efi_netfs.c b/grub-core/net/efi/efi_netfs.c +new file mode 100644 +index 0000000000..ef371d885e +--- /dev/null ++++ b/grub-core/net/efi/efi_netfs.c +@@ -0,0 +1,57 @@ ++#include ++#include ++#define EFI_NET_CMD_PREFIX "net_efi" ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsaddrs; ++static grub_command_t cmd_efi_addaddr; ++static grub_command_t cmd_efi_bootp; ++static grub_command_t cmd_efi_bootp6; ++ ++static int initialized; ++ ++GRUB_MOD_INIT(efi_netfs) ++{ ++ if (grub_net_open) ++ return; ++ ++ if (grub_efi_net_fs_init ()) ++ { ++ cmd_efi_lsroutes = grub_register_command ("net_efi_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_efi_lscards = grub_register_command ("net_efi_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_efi_lsaddrs = grub_register_command ("net_efi_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_efi_addaddr = grub_register_command ("net_efi_add_addr", grub_efi_net_add_addr, ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_efi_bootp = grub_register_command ("net_efi_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_efi_bootp6 = grub_register_command ("net_efi_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ initialized = 1; ++ } ++} ++ ++GRUB_MOD_FINI(efi_netfs) ++{ ++ if (initialized) ++ { ++ grub_unregister_command (cmd_efi_lsroutes); ++ grub_unregister_command (cmd_efi_lscards); ++ grub_unregister_command (cmd_efi_lsaddrs); ++ grub_unregister_command (cmd_efi_addaddr); ++ grub_unregister_command (cmd_efi_bootp); ++ grub_unregister_command (cmd_efi_bootp6); ++ grub_efi_net_fs_fini (); ++ initialized = 0; ++ return; ++ } ++} +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +new file mode 100644 +index 0000000000..3f61fd2fa5 +--- /dev/null ++++ b/grub-core/net/efi/http.c +@@ -0,0 +1,419 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static void ++http_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_http_config_data_t http_config; ++ grub_efi_httpv4_access_point_t httpv4_node; ++ grub_efi_httpv6_access_point_t httpv6_node; ++ grub_efi_status_t status; ++ ++ grub_efi_http_t *http = dev->http; ++ ++ grub_memset (&http_config, 0, sizeof(http_config)); ++ http_config.http_version = GRUB_EFI_HTTPVERSION11; ++ http_config.timeout_millisec = 5000; ++ ++ if (prefer_ip6) ++ { ++ grub_efi_uintn_t sz; ++ grub_efi_ip6_config_manual_address_t manual_address; ++ ++ http_config.local_address_is_ipv6 = 1; ++ sz = sizeof (manual_address); ++ status = efi_call_4 (dev->ip6_config->get_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, &manual_address); ++ ++ if (status == GRUB_EFI_NOT_FOUND) ++ { ++ grub_printf ("The MANUAL ADDRESS is not found\n"); ++ } ++ ++ /* FIXME: The manual interface would return BUFFER TOO SMALL !!! */ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_printf ("??? %d\n",(int) status); ++ return; ++ } ++ ++ grub_memcpy (httpv6_node.local_address, manual_address.address, sizeof (httpv6_node.local_address)); ++ httpv6_node.local_port = 0; ++ http_config.access_point.ipv6_node = &httpv6_node; ++ } ++ else ++ { ++ http_config.local_address_is_ipv6 = 0; ++ grub_memset (&httpv4_node, 0, sizeof(httpv4_node)); ++ httpv4_node.use_default_address = 1; ++ ++ /* Use random port here */ ++ /* See TcpBind() in edk2/NetworkPkg/TcpDxe/TcpDispatcher.c */ ++ httpv4_node.local_port = 0; ++ http_config.access_point.ipv4_node = &httpv4_node; ++ } ++ ++ status = efi_call_2 (http->configure, http, &http_config); ++ ++ if (status == GRUB_EFI_ALREADY_STARTED) ++ { ++ /* XXX: This hangs HTTPS boot */ ++#if 0 ++ if (efi_call_2 (http->configure, http, NULL) != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); ++ grub_print_error (); ++ return; ++ } ++ status = efi_call_2 (http->configure, http, &http_config); ++#endif ++ return; ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't configure http protocol, reason: %d"), (int)status); ++ grub_print_error (); ++ return ; ++ } ++} ++ ++static grub_efi_boolean_t request_callback_done; ++static grub_efi_boolean_t response_callback_done; ++ ++static void ++grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ request_callback_done = 1; ++} ++ ++static void ++grub_efi_http_response_callback (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ response_callback_done = 1; ++} ++ ++static grub_err_t ++efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, int headeronly, grub_off_t *file_size) ++{ ++ grub_efi_http_request_data_t request_data; ++ grub_efi_http_message_t request_message; ++ grub_efi_http_token_t request_token; ++ grub_efi_http_response_data_t response_data; ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ grub_efi_http_header_t request_headers[3]; ++ ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ char *url = NULL; ++ ++ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; ++ request_headers[0].field_value = (grub_efi_char8_t *)server; ++ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; ++ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; ++ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; ++ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ ++ { ++ grub_efi_ipv6_address_t address; ++ const char *rest; ++ grub_efi_char16_t *ucs2_url; ++ grub_size_t url_len, ucs2_url_len; ++ const char *protocol = (use_https == 1) ? "https" : "http"; ++ ++ if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) ++ url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); ++ else ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ ++ if (!url) ++ { ++ return grub_errno; ++ } ++ ++ url_len = grub_strlen (url); ++ ucs2_url_len = url_len * GRUB_MAX_UTF16_PER_UTF8; ++ ucs2_url = grub_malloc ((ucs2_url_len + 1) * sizeof (ucs2_url[0])); ++ ++ if (!ucs2_url) ++ { ++ grub_free (url); ++ return grub_errno; ++ } ++ ++ ucs2_url_len = grub_utf8_to_utf16 (ucs2_url, ucs2_url_len, (grub_uint8_t *)url, url_len, NULL); /* convert string format from ascii to usc2 */ ++ ucs2_url[ucs2_url_len] = 0; ++ grub_free (url); ++ request_data.url = ucs2_url; ++ } ++ ++ request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; ++ ++ request_message.data.request = &request_data; ++ request_message.header_count = 3; ++ request_message.headers = request_headers; ++ request_message.body_length = 0; ++ request_message.body = NULL; ++ ++ /* request token */ ++ request_token.event = NULL; ++ request_token.status = GRUB_EFI_NOT_READY; ++ request_token.message = &request_message; ++ ++ request_callback_done = 0; ++ status = efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_request_callback, ++ NULL, ++ &request_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); ++ } ++ ++ status = efi_call_2 (http->request, http, &request_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to send a request! status=0x%x\n", status); ++ } ++ /* TODO: Add Timeout */ ++ while (!request_callback_done) ++ efi_call_1(http->poll, http); ++ ++ response_data.status_code = GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS; ++ response_message.data.response = &response_data; ++ /* herader_count will be updated by the HTTP driver on response */ ++ response_message.header_count = 0; ++ /* headers will be populated by the driver on response */ ++ response_message.headers = NULL; ++ /* use zero BodyLength to only receive the response headers */ ++ response_message.body_length = 0; ++ response_message.body = NULL; ++ response_token.event = NULL; ++ ++ status = efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, ++ NULL, ++ &response_token.event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to create an event! status=0x%x\n", status); ++ } ++ ++ response_token.status = GRUB_EFI_SUCCESS; ++ response_token.message = &response_message; ++ ++ /* wait for HTTP response */ ++ response_callback_done = 0; ++ status = efi_call_2 (http->response, http, &response_token); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ return grub_error (GRUB_ERR_IO, "Fail to receive a response! status=%d\n", (int)status); ++ } ++ ++ /* TODO: Add Timeout */ ++ while (!response_callback_done) ++ efi_call_1 (http->poll, http); ++ ++ if (response_message.data.response->status_code != GRUB_EFI_HTTP_STATUS_200_OK) ++ { ++ grub_efi_http_status_code_t status_code = response_message.data.response->status_code; ++ ++ if (response_message.headers) ++ efi_call_1 (b->free_pool, response_message.headers); ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ if (status_code == GRUB_EFI_HTTP_STATUS_404_NOT_FOUND) ++ { ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, _("file `%s' not found"), name); ++ } ++ else ++ { ++ return grub_error (GRUB_ERR_NET_UNKNOWN_ERROR, ++ _("unsupported uefi http status code 0x%x"), status_code); ++ } ++ } ++ ++ if (file_size) ++ { ++ int i; ++ /* parse the length of the file from the ContentLength header */ ++ for (*file_size = 0, i = 0; i < (int)response_message.header_count; ++i) ++ { ++ if (!grub_strcmp((const char*)response_message.headers[i].field_name, "Content-Length")) ++ { ++ *file_size = grub_strtoul((const char*)response_message.headers[i].field_value, 0, 10); ++ break; ++ } ++ } ++ } ++ ++ if (response_message.headers) ++ efi_call_1 (b->free_pool, response_message.headers); ++ efi_call_1 (b->close_event, response_token.event); ++ efi_call_1 (b->close_event, request_token.event); ++ grub_free (request_data.url); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++efihttp_read (struct grub_efi_net_device *dev, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_efi_http_message_t response_message; ++ grub_efi_http_token_t response_token; ++ ++ grub_efi_status_t status; ++ grub_size_t sum = 0; ++ grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; ++ grub_efi_http_t *http = dev->http; ++ ++ if (!len) ++ { ++ grub_error (GRUB_ERR_BUG, "Invalid arguments to EFI HTTP Read"); ++ return -1; ++ } ++ ++ efi_call_5 (b->create_event, ++ GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, ++ grub_efi_http_response_callback, ++ NULL, ++ &response_token.event); ++ ++ while (len) ++ { ++ response_message.data.response = NULL; ++ response_message.header_count = 0; ++ response_message.headers = NULL; ++ response_message.body_length = len; ++ response_message.body = buf; ++ ++ response_token.message = &response_message; ++ response_token.status = GRUB_EFI_NOT_READY; ++ ++ response_callback_done = 0; ++ ++ status = efi_call_2 (http->response, http, &response_token); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ efi_call_1 (b->close_event, response_token.event); ++ grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); ++ return -1; ++ } ++ ++ while (!response_callback_done) ++ efi_call_1(http->poll, http); ++ ++ sum += response_message.body_length; ++ buf += response_message.body_length; ++ len -= response_message.body_length; ++ } ++ ++ efi_call_1 (b->close_event, response_token.event); ++ ++ return sum; ++} ++ ++static grub_err_t ++grub_efihttp_open (struct grub_efi_net_device *dev, ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file, ++ const char *filename __attribute__ ((unused)), ++ int type) ++{ ++ grub_err_t err; ++ grub_off_t size; ++ char *buf; ++ ++ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ buf = grub_malloc (size); ++ efihttp_read (dev, buf, size); ++ ++ file->size = size; ++ file->data = buf; ++ file->not_easily_seekable = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efihttp_close (struct grub_efi_net_device *dev __attribute__ ((unused)), ++ int prefer_ip6 __attribute__ ((unused)), ++ grub_file_t file) ++{ ++ if (file->data) ++ grub_free (file->data); ++ ++ file->data = 0; ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_read (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ grub_size_t r = len; ++ ++ if (!file->data || !buf || !len) ++ return 0; ++ ++ if ((file->device->net->offset + len) > file->size) ++ r = file->size - file->device->net->offset; ++ ++ if (r) ++ { ++ grub_memcpy (buf, (char *)file->data + file->device->net->offset, r); ++ file->device->net->offset += r; ++ } ++ ++ return r; ++} ++ ++struct grub_efi_net_io io_http = ++ { ++ .configure = http_configure, ++ .open = grub_efihttp_open, ++ .read = grub_efihttp_read, ++ .close = grub_efihttp_close ++ }; +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +new file mode 100644 +index 0000000000..b711a5d945 +--- /dev/null ++++ b/grub-core/net/efi/ip4_config.c +@@ -0,0 +1,398 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) ++{ ++ char *hw_addr, *p; ++ int sz, s; ++ int i; ++ ++ sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; ++ ++ hw_addr = grub_malloc (sz); ++ if (!hw_addr) ++ return NULL; ++ ++ p = hw_addr; ++ s = sz; ++ for (i = 0; i < (int)hw_address_size; i++) ++ { ++ grub_snprintf (p, sz, "%02x:", hw_address[i]); ++ p += sizeof ("XX:") - 1; ++ s -= sizeof ("XX:") - 1; ++ } ++ ++ hw_addr[sz - 2] = '\0'; ++ return hw_addr; ++} ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address) ++{ ++ char *addr; ++ ++ addr = grub_malloc (sizeof ("XXX.XXX.XXX.XXX")); ++ if (!addr) ++ return NULL; ++ ++ /* FIXME: Use grub_xasprintf ? */ ++ grub_snprintf (addr, ++ sizeof ("XXX.XXX.XXX.XXX"), ++ "%u.%u.%u.%u", ++ (*address)[0], ++ (*address)[1], ++ (*address)[2], ++ (*address)[3]); ++ ++ return addr; ++} ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) ++{ ++ grub_uint32_t newip = 0; ++ int i; ++ const char *ptr = val; ++ ++ for (i = 0; i < 4; i++) ++ { ++ unsigned long t; ++ t = grub_strtoul (ptr, (char **) &ptr, 0); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (*ptr != '.' && i == 0) ++ { ++ /* XXX: t is in host byte order */ ++ newip = t; ++ break; ++ } ++ if (t & ~0xff) ++ return 0; ++ newip <<= 8; ++ newip |= t; ++ if (i != 3 && *ptr != '.') ++ return 0; ++ ptr++; ++ } ++ ++ newip = grub_cpu_to_be32 (newip); ++ ++ grub_memcpy (address, &newip, sizeof(*address)); ++ ++ if (rest) ++ *rest = (ptr - 1); ++ return 1; ++} ++ ++static grub_efi_ip4_config2_interface_info_t * ++efi_ip4_config_interface_info (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ if (!interface_info) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip4_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip4_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip4_address_to_string (&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++ ++static int ++address_mask_size (grub_efi_ipv4_address_t *address) ++{ ++ grub_uint8_t i; ++ grub_uint32_t u32_addr = grub_be_to_cpu32 (grub_get_unaligned32 (address)); ++ ++ if (u32_addr == 0) ++ return 0; ++ ++ for (i = 0; i < 32 ; ++i) ++ { ++ if (u32_addr == ((0xffffffff >> i) << i)) ++ return (32 - i); ++ } ++ ++ return -1; ++} ++ ++static char ** ++grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ char **ret; ++ int i, id; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); ++ ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ char *subnet, *gateway, *mask; ++ grub_uint32_t u32_subnet, u32_gateway; ++ int mask_size; ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ u32_gateway = grub_get_unaligned32 (&route_table->gateway_address); ++ gateway = grub_efi_ip4_address_to_string (&route_table->gateway_address); ++ u32_subnet = grub_get_unaligned32 (&route_table->subnet_address); ++ subnet = grub_efi_ip4_address_to_string (&route_table->subnet_address); ++ mask_size = address_mask_size (&route_table->subnet_mask); ++ mask = grub_efi_ip4_address_to_string (&route_table->subnet_mask); ++ if (u32_subnet && !u32_gateway && interface_name) ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, subnet, mask_size, interface_name); ++ else if (u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ else if (!u32_subnet && u32_gateway) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, subnet, mask_size, gateway); ++ grub_free (subnet); ++ grub_free (gateway); ++ grub_free (mask); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip4_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip4_config2_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv4_address_t *address = &ip_address->ip4; ++ ++ interface_info = efi_ip4_config_interface_info (dev->ip4_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_table_size; i++) ++ { ++ grub_efi_ip4_route_table_t *route_table = interface_info->route_table + i; ++ grub_uint32_t u32_address, u32_mask, u32_subnet; ++ ++ u32_address = grub_get_unaligned32 (address); ++ u32_subnet = grub_get_unaligned32 (route_table->subnet_address); ++ u32_mask = grub_get_unaligned32 (route_table->subnet_mask); ++ ++ /* SKIP Default GATEWAY */ ++ if (!u32_subnet && !u32_mask) ++ continue; ++ ++ if ((u32_address & u32_mask) == u32_subnet) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (!inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip4_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *address = &net_ip->ip4; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address = ++ efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address) ++ { ++ grub_memcpy (address->subnet_mask, manual_address->subnet_mask, sizeof(address->subnet_mask)); ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->subnet_mask[0] = 0xff; ++ address->subnet_mask[1] = 0xff; ++ address->subnet_mask[2] = 0xff; ++ address->subnet_mask[3] = 0; ++ } ++ } ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip4_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++/* FIXME: Multiple DNS */ ++static int ++grub_efi_ip4_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip4), &address->ip4); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip4_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip4_interface_hw_address, ++ .get_address = grub_efi_ip4_interface_address, ++ .get_route_table = grub_efi_ip4_interface_route_table, ++ .best_interface = grub_efi_ip4_interface_match, ++ .set_address = grub_efi_ip4_interface_set_manual_address, ++ .set_gateway = grub_efi_ip4_interface_set_gateway, ++ .set_dns = grub_efi_ip4_interface_set_dns ++ }; +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +new file mode 100644 +index 0000000000..017c4d05bc +--- /dev/null ++++ b/grub-core/net/efi/ip6_config.c +@@ -0,0 +1,422 @@ ++#include ++#include ++#include ++#include ++#include ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) ++{ ++ char *str = grub_malloc (sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")); ++ char *p; ++ int i; ++ int squash; ++ ++ if (!str) ++ return NULL; ++ ++ p = str; ++ squash = 0; ++ for (i = 0; i < 8; ++i) ++ { ++ grub_uint16_t addr; ++ ++ if (i == 7) ++ squash = 2; ++ ++ addr = grub_get_unaligned16 (address->addr + i * 2); ++ ++ if (grub_be_to_cpu16 (addr)) ++ { ++ char buf[sizeof ("XXXX")]; ++ if (i > 0) ++ *p++ = ':'; ++ grub_snprintf (buf, sizeof (buf), "%x", grub_be_to_cpu16 (addr)); ++ grub_strcpy (p, buf); ++ p += grub_strlen (buf); ++ ++ if (squash == 1) ++ squash = 2; ++ } ++ else ++ { ++ if (squash == 0) ++ { ++ *p++ = ':'; ++ squash = 1; ++ } ++ else if (squash == 2) ++ { ++ *p++ = ':'; ++ *p++ = '0'; ++ } ++ } ++ } ++ *p = '\0'; ++ return str; ++} ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, (char **) &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (address, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_efi_ip6_config_interface_info_t * ++efi_ip6_config_interface_info (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ ++ sz = sizeof (*interface_info) + sizeof (*interface_info->route_table); ++ interface_info = grub_malloc (sz); ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ grub_free (interface_info); ++ interface_info = grub_malloc (sz); ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, ++ &sz, interface_info); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ return interface_info; ++} ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *name; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ name = grub_malloc (GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE ++ * GRUB_MAX_UTF8_PER_UTF16 + 1); ++ *grub_utf16_to_utf8 ((grub_uint8_t *)name, interface_info->name, ++ GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE) = 0; ++ grub_free (interface_info); ++ return name; ++} ++ ++static char * ++grub_efi_ip6_interface_hw_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char *hw_addr; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ ++ if (!interface_info) ++ return NULL; ++ ++ hw_addr = grub_efi_hw_address_to_string (interface_info->hw_address_size, interface_info->hw_address); ++ grub_free (interface_info); ++ ++ return hw_addr; ++} ++ ++static char * ++grub_efi_ip6_interface_address (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ char *addr; ++ ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (!manual_address) ++ return NULL; ++ ++ addr = grub_efi_ip6_address_to_string ((grub_efi_pxe_ipv6_address_t *)&manual_address->address); ++ grub_free (manual_address); ++ return addr; ++} ++ ++static char ** ++grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ char **ret; ++ int i, id; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); ++ ++ if (!ret) ++ { ++ grub_free (interface_info); ++ return NULL; ++ } ++ ++ id = 0; ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ char *gateway, *destination; ++ grub_uint64_t u64_gateway[2]; ++ grub_uint64_t u64_destination[2]; ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ grub_efi_net_interface_t *inf; ++ char *interface_name = NULL; ++ ++ gateway = grub_efi_ip6_address_to_string (&route_table->gateway); ++ destination = grub_efi_ip6_address_to_string (&route_table->destination); ++ ++ u64_gateway[0] = grub_get_unaligned64 (route_table->gateway.addr); ++ u64_gateway[1] = grub_get_unaligned64 (route_table->gateway.addr + 8); ++ u64_destination[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_destination[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ interface_name = inf->name; ++ ++ if ((!u64_gateway[0] && !u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ { ++ if (interface_name) ++ { ++ if ((grub_be_to_cpu64 (u64_destination[0]) == 0xfe80000000000000ULL) ++ && (!u64_destination[1]) ++ && (route_table->prefix_length == 64)) ++ ret[id++] = grub_xasprintf ("%s:link %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ else ++ ret[id++] = grub_xasprintf ("%s:local %s/%d %s", dev->card_name, destination, route_table->prefix_length, interface_name); ++ } ++ } ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (u64_destination[0] || u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:gw %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ else if ((u64_gateway[0] || u64_gateway[1]) ++ && (!u64_destination[0] && !u64_destination[1])) ++ ret[id++] = grub_xasprintf ("%s:default %s/%d gw %s", dev->card_name, destination, route_table->prefix_length, gateway); ++ ++ grub_free (gateway); ++ grub_free (destination); ++ } ++ ++ ret[id] = NULL; ++ grub_free (interface_info); ++ return ret; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_ip6_interface_match (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *ip_address) ++{ ++ grub_efi_ip6_config_interface_info_t *interface_info; ++ grub_efi_net_interface_t *inf; ++ int i; ++ grub_efi_ipv6_address_t *address = &ip_address->ip6; ++ ++ interface_info = efi_ip6_config_interface_info (dev->ip6_config); ++ if (!interface_info) ++ return NULL; ++ ++ for (i = 0; i < (int)interface_info->route_count ; i++) ++ { ++ grub_uint64_t u64_addr[2]; ++ grub_uint64_t u64_subnet[2]; ++ grub_uint64_t u64_mask[2]; ++ ++ grub_efi_ip6_route_table_t *route_table = interface_info->route_table + i; ++ ++ /* SKIP Default GATEWAY */ ++ if (route_table->prefix_length == 0) ++ continue; ++ ++ u64_addr[0] = grub_get_unaligned64 (address); ++ u64_addr[1] = grub_get_unaligned64 (address + 4); ++ u64_subnet[0] = grub_get_unaligned64 (route_table->destination.addr); ++ u64_subnet[1] = grub_get_unaligned64 (route_table->destination.addr + 8); ++ u64_mask[0] = (route_table->prefix_length <= 64) ? ++ 0xffffffffffffffffULL << (64 - route_table->prefix_length) : ++ 0xffffffffffffffffULL; ++ u64_mask[1] = (route_table->prefix_length <= 64) ? ++ 0 : ++ 0xffffffffffffffffULL << (128 - route_table->prefix_length); ++ ++ if (((u64_addr[0] & u64_mask[0]) == u64_subnet[0]) ++ && ((u64_addr[1] & u64_mask[1]) == u64_subnet[1])) ++ { ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (inf->prefer_ip6) ++ { ++ grub_free (interface_info); ++ return inf; ++ } ++ } ++ } ++ ++ grub_free (interface_info); ++ return NULL; ++} ++ ++static int ++grub_efi_ip6_interface_set_manual_address (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int with_subnet) ++{ ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *address = &net_ip->ip6; ++ ++ if (!with_subnet) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address = ++ efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address) ++ { ++ address->prefix_length = manual_address->prefix_length; ++ grub_free (manual_address); ++ } ++ else ++ { ++ /* XXX: */ ++ address->prefix_length = 64; ++ } ++ } ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ sizeof(*address), address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_gateway (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++static int ++grub_efi_ip6_interface_set_dns (struct grub_efi_net_device *dev, ++ grub_efi_net_ip_address_t *address) ++{ ++ ++ grub_efi_status_t status; ++ ++ status = efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER, ++ sizeof (address->ip6), &address->ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ return 1; ++} ++ ++grub_efi_net_ip_config_t *efi_net_ip6_config = &(grub_efi_net_ip_config_t) ++ { ++ .get_hw_address = grub_efi_ip6_interface_hw_address, ++ .get_address = grub_efi_ip6_interface_address, ++ .get_route_table = grub_efi_ip6_interface_route_table, ++ .best_interface = grub_efi_ip6_interface_match, ++ .set_address = grub_efi_ip6_interface_set_manual_address, ++ .set_gateway = grub_efi_ip6_interface_set_gateway, ++ .set_dns = grub_efi_ip6_interface_set_dns ++ }; +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +new file mode 100644 +index 0000000000..86bce6535d +--- /dev/null ++++ b/grub-core/net/efi/net.c +@@ -0,0 +1,1428 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define GRUB_EFI_IP6_PREFIX_LENGTH 64 ++ ++static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; ++static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; ++static grub_efi_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; ++static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; ++static grub_efi_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; ++static grub_efi_guid_t dhcp6_guid = GRUB_EFI_DHCP6_PROTOCOL_GUID; ++ ++struct grub_efi_net_device *net_devices; ++ ++static char *default_server; ++static grub_efi_net_interface_t *net_interface; ++static grub_efi_net_interface_t *net_default_interface; ++ ++#define efi_net_interface_configure(inf) inf->io->configure (inf->dev, inf->prefer_ip6) ++#define efi_net_interface_open(inf, file, name) inf->io->open (inf->dev, inf->prefer_ip6, file, name, inf->io_type) ++#define efi_net_interface_read(inf, file, buf, sz) inf->io->read (inf->dev, inf->prefer_ip6, file, buf, sz) ++#define efi_net_interface_close(inf, file) inf->io->close (inf->dev, inf->prefer_ip6, file) ++#define efi_net_interface(m,...) efi_net_interface_ ## m (net_interface, ## __VA_ARGS__) ++ ++static grub_efi_handle_t ++grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path, ++ grub_efi_device_path_t **r_device_path) ++{ ++ grub_efi_handle_t handle; ++ grub_efi_status_t status; ++ ++ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path, ++ protocol, &device_path, &handle); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return 0; ++ ++ if (r_device_path) ++ *r_device_path = device_path; ++ ++ return handle; ++} ++ ++static int ++url_parse_fields (const char *url, char **proto, char **host, char **path) ++{ ++ const char *p, *ps; ++ grub_size_t l; ++ ++ *proto = *host = *path = NULL; ++ ps = p = url; ++ ++ while ((p = grub_strchr (p, ':'))) ++ { ++ if (grub_strlen (p) < sizeof ("://") - 1) ++ break; ++ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0) ++ { ++ l = p - ps; ++ *proto = grub_malloc (l + 1); ++ if (!*proto) ++ { ++ grub_print_error (); ++ return 0; ++ } ++ ++ grub_memcpy (*proto, ps, l); ++ (*proto)[l] = '\0'; ++ p += sizeof ("://") - 1; ++ break; ++ } ++ ++p; ++ } ++ ++ if (!*proto) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url); ++ return 0; ++ } ++ ++ ps = p; ++ p = grub_strchr (p, '/'); ++ ++ if (!p) ++ { ++ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ ++ l = p - ps; ++ ++ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']') ++ { ++ *host = grub_malloc (l - 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps + 1, l - 2); ++ (*host)[l - 2] = 0; ++ } ++ else ++ { ++ *host = grub_malloc (l + 1); ++ if (!*host) ++ { ++ grub_print_error (); ++ grub_free (*proto); ++ *proto = NULL; ++ return 0; ++ } ++ grub_memcpy (*host, ps, l); ++ (*host)[l] = 0; ++ } ++ ++ *path = grub_strdup (p); ++ if (!*path) ++ { ++ grub_print_error (); ++ grub_free (*host); ++ grub_free (*proto); ++ *host = NULL; ++ *proto = NULL; ++ return 0; ++ } ++ return 1; ++} ++ ++static void ++url_get_boot_location (const char *url, char **device, char **path, int is_default) ++{ ++ char *protocol, *server, *file; ++ char *slash; ++ ++ if (!url_parse_fields (url, &protocol, &server, &file)) ++ return; ++ ++ if ((slash = grub_strrchr (file, '/'))) ++ *slash = 0; ++ else ++ *file = 0; ++ ++ *device = grub_xasprintf ("%s,%s", protocol, server); ++ *path = grub_strdup(file); ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++ ++ grub_free (protocol); ++ grub_free (file); ++} ++ ++static void ++pxe_get_boot_location (const struct grub_net_bootp_packet *bp, ++ char **device, ++ char **path, ++ int is_default) ++{ ++ char *server = grub_xasprintf ("%d.%d.%d.%d", ++ ((grub_uint8_t *) &bp->server_ip)[0], ++ ((grub_uint8_t *) &bp->server_ip)[1], ++ ((grub_uint8_t *) &bp->server_ip)[2], ++ ((grub_uint8_t *) &bp->server_ip)[3]); ++ ++ *device = grub_xasprintf ("tftp,%s", server); ++ ++ *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file)); ++ ++ if (*path) ++ { ++ char *slash; ++ slash = grub_strrchr (*path, '/'); ++ if (slash) ++ *slash = 0; ++ else ++ **path = 0; ++ } ++ ++ if (is_default) ++ default_server = server; ++ else ++ grub_free (server); ++} ++ ++static void ++pxe_get_boot_location_v6 (const struct grub_net_dhcp6_packet *dp, ++ grub_size_t dhcp_size, ++ char **device, ++ char **path) ++{ ++ ++ struct grub_net_dhcp6_option *dhcp_opt; ++ grub_size_t dhcp_remain_size; ++ *device = *path = 0; ++ ++ if (dhcp_size < sizeof (*dp)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small")); ++ return; ++ } ++ ++ dhcp_remain_size = dhcp_size - sizeof (*dp); ++ dhcp_opt = (struct grub_net_dhcp6_option *)dp->dhcp_options; ++ ++ while (dhcp_remain_size) ++ { ++ grub_uint16_t code = grub_be_to_cpu16 (dhcp_opt->code); ++ grub_uint16_t len = grub_be_to_cpu16 (dhcp_opt->len); ++ grub_uint16_t option_size = sizeof (*dhcp_opt) + len; ++ ++ if (dhcp_remain_size < option_size || code == 0) ++ break; ++ ++ if (code == GRUB_NET_DHCP6_OPTION_BOOTFILE_URL) ++ { ++ char *url = grub_malloc (len + 1); ++ ++ grub_memcpy (url, dhcp_opt->data, len); ++ url[len] = 0; ++ ++ url_get_boot_location ((const char *)url, device, path, 1); ++ grub_free (url); ++ break; ++ } ++ ++ dhcp_remain_size -= option_size; ++ dhcp_opt = (struct grub_net_dhcp6_option *)((grub_uint8_t *)dhcp_opt + option_size); ++ } ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_device_path (grub_efi_device_path_t *dp, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_net_interface_t *inf = NULL; ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if (type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ { ++ if (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_uri_device_path_t *uri_dp; ++ uri_dp = (grub_efi_uri_device_path_t *) dp; ++ /* Beware that uri_dp->uri may not be null terminated */ ++ url_get_boot_location ((const char *)uri_dp->uri, device, path, 1); ++ } ++ else if (subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip4.address, ipv4->local_ip_address, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, ipv4->subnet_mask, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ else if (subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) dp; ++ ++ if (inf) ++ continue; ++ grub_memcpy (net_ip.ip6.address, ipv6->local_ip_address, sizeof (net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ inf = grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1); ++ } ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return inf; ++} ++ ++static grub_efi_net_interface_t * ++grub_efi_net_config_from_handle (grub_efi_handle_t *hnd, ++ struct grub_efi_net_device *netdev, ++ char **device, ++ char **path) ++{ ++ grub_efi_pxe_t *pxe = NULL; ++ ++ if (hnd == netdev->ip4_pxe_handle) ++ pxe = netdev->ip4_pxe; ++ else if (hnd == netdev->ip6_pxe_handle) ++ pxe = netdev->ip6_pxe; ++ ++ if (!pxe) ++ return (grub_efi_net_config_from_device_path ( ++ grub_efi_get_device_path (hnd), ++ netdev, ++ device, ++ path)); ++ ++ if (pxe->mode->using_ipv6) ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location_v6 ( ++ (const struct grub_net_dhcp6_packet *) &pxe->mode->dhcp_ack, ++ sizeof (pxe->mode->dhcp_ack), ++ device, ++ path); ++ ++ grub_memcpy (net_ip.ip6.address, pxe->mode->station_ip.v6, sizeof(net_ip.ip6.address)); ++ net_ip.ip6.prefix_length = GRUB_EFI_IP6_PREFIX_LENGTH; ++ net_ip.ip6.is_anycast = 0; ++ net_ip.is_ip6 = 1; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++ else ++ { ++ grub_efi_net_ip_manual_address_t net_ip; ++ ++ pxe_get_boot_location ( ++ (const struct grub_net_bootp_packet *) &pxe->mode->dhcp_ack, ++ device, ++ path, ++ 1); ++ ++ grub_memcpy (net_ip.ip4.address, pxe->mode->station_ip.v4, sizeof (net_ip.ip4.address)); ++ grub_memcpy (net_ip.ip4.subnet_mask, pxe->mode->subnet_mask.v4, sizeof (net_ip.ip4.subnet_mask)); ++ net_ip.is_ip6 = 0; ++ return (grub_efi_net_create_interface (netdev, ++ netdev->card_name, ++ &net_ip, ++ 1)); ++ } ++} ++ ++static const char * ++grub_efi_net_var_get_address (struct grub_env_var *var, ++ const char *val __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var_name; ++ ++ var_name = grub_xasprintf ("net_%s_ip", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_address (inf); ++ grub_free (var_name); ++ var_name = grub_xasprintf ("net_%s_mac", inf->name); ++ if (grub_strcmp (var_name, var->name) == 0) ++ return efi_net_interface_get_hw_address (inf); ++ grub_free (var_name); ++ } ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_interface (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ if (grub_strcmp (inf->name, val) == 0) ++ { ++ net_default_interface = inf; ++ return grub_strdup (val); ++ } ++ ++ return NULL; ++} ++ ++static char * ++grub_efi_net_var_set_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val) ++{ ++ grub_free (default_server); ++ default_server = grub_strdup (val); ++ return grub_strdup (val); ++} ++ ++static const char * ++grub_efi_net_var_get_server (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return default_server ? : ""; ++} ++ ++static const char * ++grub_efi_net_var_get_ip (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_ip", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static const char * ++grub_efi_net_var_get_mac (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ const char *intf = grub_env_get ("net_default_interface"); ++ const char *ret = NULL; ++ if (intf) ++ { ++ char *buf = grub_xasprintf ("net_%s_mac", intf); ++ if (buf) ++ ret = grub_env_get (buf); ++ grub_free (buf); ++ } ++ return ret; ++} ++ ++static void ++grub_efi_net_export_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, grub_efi_net_var_get_address, 0); ++ grub_env_export (var); ++ grub_free (var); ++ } ++ } ++} ++ ++static void ++grub_efi_net_unset_interface_vars (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *var; ++ ++ var = grub_xasprintf ("net_%s_ip", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ var = grub_xasprintf ("net_%s_mac", inf->name); ++ grub_register_variable_hook (var, 0, 0); ++ grub_env_unset (var); ++ grub_free (var); ++ } ++ } ++} ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet) ++{ ++ grub_efi_net_interface_t *inf; ++ ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ if (inf->prefer_ip6 == net_ip->is_ip6) ++ break; ++ } ++ ++ if (!inf) ++ { ++ inf = grub_malloc (sizeof(*inf)); ++ inf->name = grub_strdup (interface_name); ++ inf->prefer_ip6 = net_ip->is_ip6; ++ inf->dev = dev; ++ inf->next = dev->net_interfaces; ++ inf->ip_config = (net_ip->is_ip6) ? efi_net_ip6_config : efi_net_ip4_config ; ++ dev->net_interfaces = inf; ++ } ++ else ++ { ++ grub_free (inf->name); ++ inf->name = grub_strdup (interface_name); ++ } ++ ++ if (!efi_net_interface_set_address (inf, net_ip, has_subnet)) ++ { ++ grub_error (GRUB_ERR_BUG, N_("Set Address Failed")); ++ return NULL; ++ } ++ ++ return inf; ++} ++ ++static void ++grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, ++ char **path) ++{ ++ grub_efi_handle_t config_hnd; ++ ++ struct grub_efi_net_device *netdev; ++ grub_efi_net_interface_t *inf; ++ ++ config_hnd = grub_efi_locate_device_path (&ip4_config_guid, grub_efi_get_device_path (hnd), NULL); ++ ++ if (!config_hnd) ++ return; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ if (netdev->handle == config_hnd) ++ break; ++ ++ if (!netdev) ++ return; ++ ++ if (!(inf = grub_efi_net_config_from_handle (hnd, netdev, device, path))) ++ return; ++ ++ grub_env_set ("net_default_interface", inf->name); ++ grub_efi_net_export_interface_vars (); ++} ++ ++static grub_err_t ++grub_efi_netfs_dir (grub_device_t device, const char *path __attribute__ ((unused)), ++ grub_fs_dir_hook_t hook __attribute__ ((unused)), ++ void *hook_data __attribute__ ((unused))) ++{ ++ if (!device->net) ++ return grub_error (GRUB_ERR_BUG, "invalid net device"); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_efi_netfs_open (struct grub_file *file_out __attribute__ ((unused)), ++ const char *name __attribute__ ((unused))) ++{ ++ struct grub_file *file, *bufio; ++ ++ file = grub_malloc (sizeof (*file)); ++ if (!file) ++ return grub_errno; ++ ++ grub_memcpy (file, file_out, sizeof (struct grub_file)); ++ file->device->net->name = grub_strdup (name); ++ ++ if (!file->device->net->name) ++ { ++ grub_free (file); ++ return grub_errno; ++ } ++ ++ efi_net_interface(open, file, name); ++ grub_print_error (); ++ ++ bufio = grub_bufio_open (file, 32768); ++ if (!bufio) ++ { ++ grub_free (file->device->net->name); ++ grub_free (file); ++ return grub_errno; ++ } ++ grub_memcpy (file_out, bufio, sizeof (struct grub_file)); ++ grub_free (bufio); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++grub_efihttp_chunk_read (grub_file_t file, char *buf, ++ grub_size_t len, grub_size_t chunk_size) ++{ ++ char *chunk = grub_malloc (chunk_size); ++ grub_size_t sum = 0; ++ ++ while (len) ++ { ++ grub_ssize_t rd; ++ grub_size_t sz = (len > chunk_size) ? chunk_size : len; ++ ++ rd = efi_net_interface (read, file, chunk, sz); ++ ++ if (rd <= 0) ++ return rd; ++ ++ if (buf) ++ { ++ grub_memcpy (buf, chunk, rd); ++ buf += rd; ++ } ++ sum += rd; ++ len -= rd; ++ } ++ ++ grub_free (chunk); ++ return sum; ++} ++ ++static grub_ssize_t ++grub_efi_netfs_read (grub_file_t file __attribute__ ((unused)), ++ char *buf __attribute__ ((unused)), grub_size_t len __attribute__ ((unused))) ++{ ++ if (file->offset > file->device->net->offset) ++ { ++ grub_efihttp_chunk_read (file, NULL, file->offset - file->device->net->offset, 10240); ++ } ++ else if (file->offset < file->device->net->offset) ++ { ++ efi_net_interface (close, file); ++ efi_net_interface (open, file, file->device->net->name); ++ if (file->offset) ++ grub_efihttp_chunk_read (file, NULL, file->offset, 10240); ++ } ++ ++ return efi_net_interface (read, file, buf, len); ++} ++ ++static grub_err_t ++grub_efi_netfs_close (grub_file_t file) ++{ ++ efi_net_interface (close, file); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_efi_handle_t ++grub_efi_service_binding (grub_efi_handle_t dev, grub_efi_guid_t *service_binding_guid) ++{ ++ grub_efi_service_binding_t *service; ++ grub_efi_status_t status; ++ grub_efi_handle_t child_dev = NULL; ++ ++ service = grub_efi_open_protocol (dev, service_binding_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!service) ++ { ++ grub_error (GRUB_ERR_IO, N_("couldn't open efi service binding protocol")); ++ return NULL; ++ } ++ ++ status = efi_call_2 (service->create_child, service, &child_dev); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_error (GRUB_ERR_IO, N_("Failed to create child device of http service %x"), status); ++ return NULL; ++ } ++ ++ return child_dev; ++} ++ ++static grub_err_t ++grub_efi_net_parse_address (const char *address, ++ grub_efi_ip4_config2_manual_address_t *ip4, ++ grub_efi_ip6_config_manual_address_t *ip6, ++ int *is_ip6, ++ int *has_cidr) ++{ ++ const char *rest; ++ ++ if (grub_efi_string_to_ip4_address (address, &ip4->address, &rest)) ++ { ++ *is_ip6 = 0; ++ if (*rest == '/') ++ { ++ grub_uint32_t subnet_mask_size; ++ ++ subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); ++ ++ if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) ++ { ++ grub_uint32_t subnet_mask; ++ ++ subnet_mask = grub_cpu_to_be32 ((0xffffffffU << (32 - subnet_mask_size))); ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0) ++ { ++ grub_uint32_t subnet_mask = 0xffffffffU; ++ grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (grub_efi_string_to_ip6_address (address, &ip6->address, &rest)) ++ { ++ *is_ip6 = 1; ++ if (*rest == '/') ++ { ++ grub_efi_uint8_t prefix_length; ++ ++ prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); ++ if (!grub_errno && prefix_length <= 128 && *rest == 0) ++ { ++ ip6->prefix_length = prefix_length; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 1; ++ return GRUB_ERR_NONE; ++ } ++ } ++ else if (*rest == 0) ++ { ++ ip6->prefix_length = 128; ++ ip6->is_anycast = 0; ++ if (has_cidr) ++ *has_cidr = 0; ++ return GRUB_ERR_NONE; ++ } ++ } ++ ++ return grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("unrecognised network address `%s'"), ++ address); ++} ++ ++static grub_efi_net_interface_t * ++match_route (const char *server) ++{ ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_interface_t *inf; ++ int is_ip6 = 0; ++ ++ err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); ++ ++ if (err) ++ { ++ grub_print_error (); ++ return NULL; ++ } ++ ++ if (is_ip6) ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip6, ip6.address, sizeof(ip6.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip6_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ else ++ { ++ struct grub_efi_net_device *dev; ++ grub_efi_net_ip_address_t addr; ++ ++ grub_memcpy (addr.ip4, ip4.address, sizeof(ip4.address)); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ if ((inf = efi_net_ip4_config->best_interface (dev, &addr))) ++ return inf; ++ } ++ ++ return 0; ++} ++ ++static void ++grub_efi_net_add_pxebc_to_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &pxe_io_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (handle = handles; num_handles--; handle++) ++ { ++ grub_efi_device_path_t *dp, *ddp, *ldp; ++ grub_efi_pxe_t *pxe; ++ struct grub_efi_net_device *d; ++ int is_ip6 = 0; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ddp = grub_efi_duplicate_device_path (dp); ++ ldp = grub_efi_find_last_device_path (ddp); ++ ++ if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE) ++ { ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ else if (ldp->type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE ++ && ldp->subtype == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE) ++ { ++ is_ip6 = 1; ++ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE; ++ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE; ++ ldp->length = sizeof (*ldp); ++ } ++ ++ for (d = net_devices; d; d = d->next) ++ if (grub_efi_compare_device_paths (ddp, grub_efi_get_device_path (d->handle)) == 0) ++ break; ++ ++ if (!d) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ pxe = grub_efi_open_protocol (*handle, &pxe_io_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ if (!pxe) ++ { ++ grub_free (ddp); ++ continue; ++ } ++ ++ if (is_ip6) ++ { ++ d->ip6_pxe_handle = *handle; ++ d->ip6_pxe = pxe; ++ } ++ else ++ { ++ d->ip4_pxe_handle = *handle; ++ d->ip4_pxe = pxe; ++ } ++ ++ grub_free (ddp); ++ } ++ ++ grub_free (handles); ++} ++ ++static void ++set_ip_policy_to_static (void) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ grub_efi_ip4_config2_policy_t ip4_policy = GRUB_EFI_IP4_CONFIG2_POLICY_STATIC; ++ ++ if (efi_call_4 (dev->ip4_config->set_data, dev->ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY, ++ sizeof (ip4_policy), &ip4_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP4_CONFIG2_POLICY_STATIC on dev `%s'", dev->card_name); ++ ++ if (dev->ip6_config) ++ { ++ grub_efi_ip6_config_policy_t ip6_policy = GRUB_EFI_IP6_CONFIG_POLICY_MANUAL; ++ ++ if (efi_call_4 (dev->ip6_config->set_data, dev->ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY, ++ sizeof (ip6_policy), &ip6_policy) != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efinetfs", "could not set GRUB_EFI_IP6_CONFIG_POLICY_MANUAL on dev `%s'", dev->card_name); ++ } ++ } ++} ++ ++/* FIXME: Do not fail if the card did not support any of the protocol (Eg http) */ ++static void ++grub_efi_net_find_cards (void) ++{ ++ grub_efi_uintn_t num_handles; ++ grub_efi_handle_t *handles; ++ grub_efi_handle_t *handle; ++ int id; ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &ip4_config_guid, ++ 0, &num_handles); ++ if (!handles) ++ return; ++ ++ for (id = 0, handle = handles; num_handles--; handle++, id++) ++ { ++ grub_efi_device_path_t *dp; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ ++ struct grub_efi_net_device *d; ++ ++ dp = grub_efi_get_device_path (*handle); ++ if (!dp) ++ continue; ++ ++ ip4_config = grub_efi_open_protocol (*handle, &ip4_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!ip4_config) ++ continue; ++ ++ ip6_config = grub_efi_open_protocol (*handle, &ip6_config_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ ++ http_handle = grub_efi_service_binding (*handle, &http_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ http = (http_handle) ++ ? grub_efi_open_protocol (http_handle, &http_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ dhcp4_handle = grub_efi_service_binding (*handle, &dhcp4_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp4 = (dhcp4_handle) ++ ? grub_efi_open_protocol (dhcp4_handle, &dhcp4_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ ++ dhcp6_handle = grub_efi_service_binding (*handle, &dhcp6_service_binding_guid); ++ grub_errno = GRUB_ERR_NONE; ++ dhcp6 = (dhcp6_handle) ++ ? grub_efi_open_protocol (dhcp6_handle, &dhcp6_guid, GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL) ++ : NULL; ++ ++ d = grub_malloc (sizeof (*d)); ++ if (!d) ++ { ++ grub_free (handles); ++ while (net_devices) ++ { ++ d = net_devices->next; ++ grub_free (net_devices); ++ net_devices = d; ++ } ++ return; ++ } ++ d->handle = *handle; ++ d->ip4_config = ip4_config; ++ d->ip6_config = ip6_config; ++ d->http_handle = http_handle; ++ d->http = http; ++ d->dhcp4_handle = dhcp4_handle; ++ d->dhcp4 = dhcp4; ++ d->dhcp6_handle = dhcp6_handle; ++ d->dhcp6 = dhcp6; ++ d->next = net_devices; ++ d->card_name = grub_xasprintf ("efinet%d", id); ++ d->net_interfaces = NULL; ++ net_devices = d; ++ } ++ ++ grub_efi_net_add_pxebc_to_cards (); ++ grub_free (handles); ++ set_ip_policy_to_static (); ++} ++ ++static void ++listroutes_ip4 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip4_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static void ++listroutes_ip6 (struct grub_efi_net_device *netdev) ++{ ++ char **routes; ++ ++ routes = NULL; ++ ++ if ((routes = efi_net_ip6_config->get_route_table (netdev))) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_printf ("%s\n", *r); ++ } ++ ++ if (routes) ++ { ++ char **r; ++ ++ for (r = routes; *r; ++r) ++ grub_free (*r); ++ grub_free (routes); ++ } ++} ++ ++static grub_err_t ++grub_cmd_efi_listroutes (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *netdev; ++ ++ for (netdev = net_devices; netdev; netdev = netdev->next) ++ { ++ listroutes_ip4 (netdev); ++ listroutes_ip6 (netdev); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++static grub_err_t ++grub_cmd_efi_listcards (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ char *hw_addr; ++ ++ hw_addr = efi_net_ip4_config->get_hw_address (dev); ++ ++ if (hw_addr) ++ { ++ grub_printf ("%s %s\n", dev->card_name, hw_addr); ++ grub_free (hw_addr); ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_efi_listaddrs (struct grub_command *cmd __attribute__ ((unused)), ++ int argc __attribute__ ((unused)), ++ char **args __attribute__ ((unused))) ++{ ++ struct grub_efi_net_device *dev; ++ grub_efi_net_interface_t *inf; ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ for (inf = dev->net_interfaces; inf; inf = inf->next) ++ { ++ char *hw_addr = NULL; ++ char *addr = NULL; ++ ++ if ((hw_addr = efi_net_interface_get_hw_address (inf)) ++ && (addr = efi_net_interface_get_address (inf))) ++ grub_printf ("%s %s %s\n", inf->name, hw_addr, addr); ++ ++ if (hw_addr) ++ grub_free (hw_addr); ++ if (addr) ++ grub_free (addr); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* FIXME: support MAC specifying. */ ++static grub_err_t ++grub_cmd_efi_addaddr (struct grub_command *cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ struct grub_efi_net_device *dev; ++ grub_err_t err; ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ grub_efi_net_ip_manual_address_t net_ip; ++ int is_ip6 = 0; ++ int cidr = 0; ++ ++ if (argc != 3) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); ++ ++ for (dev = net_devices; dev; dev = dev->next) ++ { ++ if (grub_strcmp (dev->card_name, args[1]) == 0) ++ break; ++ } ++ ++ if (!dev) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("card not found")); ++ ++ err = grub_efi_net_parse_address (args[2], &ip4, &ip6, &is_ip6, &cidr); ++ ++ if (err) ++ return err; ++ ++ net_ip.is_ip6 = is_ip6; ++ if (is_ip6) ++ grub_memcpy (&net_ip.ip6, &ip6, sizeof(net_ip.ip6)); ++ else ++ grub_memcpy (&net_ip.ip4, &ip4, sizeof(net_ip.ip4)); ++ ++ if (!grub_efi_net_create_interface (dev, ++ args[0], ++ &net_ip, ++ cidr)) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_fs grub_efi_netfs; ++ ++static grub_net_t ++grub_net_open_real (const char *name __attribute__ ((unused))) ++{ ++ grub_size_t protnamelen; ++ const char *protname, *server; ++ grub_net_t ret; ++ ++ net_interface = NULL; ++ ++ if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = name + sizeof ("pxe:") - 1; ++ } ++ else if (grub_strcmp (name, "pxe") == 0) ++ { ++ protname = "tftp"; ++ protnamelen = sizeof ("tftp") - 1; ++ server = default_server; ++ } ++ else ++ { ++ const char *comma; ++ ++ comma = grub_strchr (name, ','); ++ if (comma) ++ { ++ protnamelen = comma - name; ++ server = comma + 1; ++ protname = name; ++ } ++ else ++ { ++ protnamelen = grub_strlen (name); ++ server = default_server; ++ protname = name; ++ } ++ } ++ ++ if (!server) ++ { ++ grub_error (GRUB_ERR_NET_BAD_ADDRESS, ++ N_("no server is specified")); ++ return NULL; ++ } ++ ++ /*FIXME: Use DNS translate name to address */ ++ net_interface = match_route (server); ++ ++ /*XXX: should we check device with default gateway ? */ ++ if (!net_interface && !(net_interface = net_default_interface)) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), ++ name); ++ return NULL; ++ } ++ ++ if ((protnamelen == (sizeof ("https") - 1) ++ && grub_memcmp ("https", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 1; ++ } ++ else if ((protnamelen == (sizeof ("http") - 1) ++ && grub_memcmp ("http", protname, protnamelen) == 0)) ++ { ++ net_interface->io = &io_http; ++ net_interface->io_type = 0; ++ } ++ else if (protnamelen == (sizeof ("tftp") - 1) ++ && grub_memcmp ("tftp", protname, protnamelen) == 0) ++ { ++ net_interface->io = &io_pxe; ++ net_interface->io_type = 0; ++ } ++ else ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' not found"), ++ name); ++ return NULL; ++ } ++ ++ /*XXX: Should we try to avoid doing excess "reconfigure" here ??? */ ++ efi_net_interface (configure); ++ ++ ret = grub_zalloc (sizeof (*ret)); ++ if (!ret) ++ return NULL; ++ ++ ret->server = grub_strdup (server); ++ if (!ret->server) ++ { ++ grub_free (ret); ++ return NULL; ++ } ++ ++ ret->fs = &grub_efi_netfs; ++ return ret; ++} ++#if 0 ++static grub_command_t cmd_efi_lsaddr; ++static grub_command_t cmd_efi_lscards; ++static grub_command_t cmd_efi_lsroutes; ++static grub_command_t cmd_efi_addaddr; ++#endif ++ ++static struct grub_fs grub_efi_netfs = ++ { ++ .name = "efi netfs", ++ .fs_dir = grub_efi_netfs_dir, ++ .fs_open = grub_efi_netfs_open, ++ .fs_read = grub_efi_netfs_read, ++ .fs_close = grub_efi_netfs_close, ++ .fs_label = NULL, ++ .fs_uuid = NULL, ++ .fs_mtime = NULL, ++ }; ++ ++int ++grub_efi_net_boot_from_https (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; ++ return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++int ++grub_efi_net_boot_from_opa (void) ++{ ++ grub_efi_loaded_image_t *image = NULL; ++ grub_efi_device_path_t *dp; ++ ++ image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (!image) ++ return 0; ++ ++ dp = grub_efi_get_device_path (image->device_handle); ++ ++ while (1) ++ { ++ grub_efi_uint8_t type = GRUB_EFI_DEVICE_PATH_TYPE (dp); ++ grub_efi_uint8_t subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp); ++ grub_efi_uint16_t len = GRUB_EFI_DEVICE_PATH_LENGTH (dp); ++ ++ if ((type == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE) ++ && (subtype == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)) ++ { ++ grub_efi_mac_address_device_path_t *mac_dp = (grub_efi_mac_address_device_path_t *)dp; ++ return (mac_dp->if_type == 0xC7) ? 1 : 0; ++ } ++ ++ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) ++ break; ++ dp = (grub_efi_device_path_t *) ((char *) dp + len); ++ } ++ ++ return 0; ++} ++ ++static char * ++grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ return NULL; ++} ++ ++grub_command_func_t grub_efi_net_list_routes = grub_cmd_efi_listroutes; ++grub_command_func_t grub_efi_net_list_cards = grub_cmd_efi_listcards; ++grub_command_func_t grub_efi_net_list_addrs = grub_cmd_efi_listaddrs; ++grub_command_func_t grub_efi_net_add_addr = grub_cmd_efi_addaddr; ++ ++int ++grub_efi_net_fs_init () ++{ ++ grub_efi_net_find_cards (); ++ grub_efi_net_config = grub_efi_net_config_real; ++ grub_net_open = grub_net_open_real; ++ grub_register_variable_hook ("net_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("net_default_server"); ++ grub_register_variable_hook ("pxe_default_server", grub_efi_net_var_get_server, ++ grub_efi_net_var_set_server); ++ grub_env_export ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, ++ grub_efi_net_var_set_interface); ++ grub_env_export ("net_default_interface"); ++ grub_register_variable_hook ("net_default_ip", grub_efi_net_var_get_ip, ++ 0); ++ grub_env_export ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", grub_efi_net_var_get_mac, ++ 0); ++ grub_env_export ("net_default_mac"); ++ ++ grub_env_set ("grub_netfs_type", "efi"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ ++ return 1; ++} ++ ++void ++grub_efi_net_fs_fini (void) ++{ ++ grub_env_unset ("grub_netfs_type"); ++ grub_efi_net_unset_interface_vars (); ++ grub_register_variable_hook ("net_default_server", 0, 0); ++ grub_env_unset ("net_default_server"); ++ grub_register_variable_hook ("net_default_interface", 0, 0); ++ grub_env_unset ("net_default_interface"); ++ grub_register_variable_hook ("pxe_default_server", 0, 0); ++ grub_env_unset ("pxe_default_server"); ++ grub_register_variable_hook ("net_default_ip", 0, 0); ++ grub_env_unset ("net_default_ip"); ++ grub_register_variable_hook ("net_default_mac", 0, 0); ++ grub_env_unset ("net_default_mac"); ++ grub_efi_net_config = NULL; ++ grub_net_open = NULL; ++ grub_fs_unregister (&grub_efi_netfs); ++} +diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c +new file mode 100644 +index 0000000000..531949cba5 +--- /dev/null ++++ b/grub-core/net/efi/pxe.c +@@ -0,0 +1,424 @@ ++ ++#include ++#include ++#include ++#include ++#include ++ ++static grub_efi_ip6_config_manual_address_t * ++efi_ip6_config_manual_address (grub_efi_ip6_config_protocol_t *ip6_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip6_config->get_data, ip6_config, ++ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static grub_efi_ip4_config2_manual_address_t * ++efi_ip4_config_manual_address (grub_efi_ip4_config2_protocol_t *ip4_config) ++{ ++ grub_efi_uintn_t sz; ++ grub_efi_status_t status; ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ ++ sz = sizeof (*manual_address); ++ manual_address = grub_malloc (sz); ++ if (!manual_address) ++ return NULL; ++ ++ status = efi_call_4 (ip4_config->get_data, ip4_config, ++ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS, ++ &sz, manual_address); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_free (manual_address); ++ return NULL; ++ } ++ ++ return manual_address; ++} ++ ++static void ++pxe_configure (struct grub_efi_net_device *dev, int prefer_ip6) ++{ ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ grub_efi_pxe_mode_t *mode = pxe->mode; ++ ++ if (!mode->started) ++ { ++ grub_efi_status_t status; ++ status = efi_call_2 (pxe->start, pxe, prefer_ip6); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't start PXE\n"); ++ } ++ ++#if 0 ++ grub_printf ("PXE STARTED: %u\n", mode->started); ++ grub_printf ("PXE USING IPV6: %u\n", mode->using_ipv6); ++#endif ++ ++ if (mode->using_ipv6) ++ { ++ grub_efi_ip6_config_manual_address_t *manual_address; ++ manual_address = efi_ip6_config_manual_address (dev->ip6_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v6, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ ++ grub_memcpy (station_ip.v6.addr, manual_address->address, sizeof (station_ip.v6.addr)); ++ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, NULL); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ else ++ { ++ grub_efi_ip4_config2_manual_address_t *manual_address; ++ manual_address = efi_ip4_config_manual_address (dev->ip4_config); ++ ++ if (manual_address && ++ grub_memcmp (manual_address->address, mode->station_ip.v4, sizeof (manual_address->address)) != 0) ++ { ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t station_ip; ++ grub_efi_pxe_ip_address_t subnet_mask; ++ ++ grub_memcpy (station_ip.v4.addr, manual_address->address, sizeof (station_ip.v4.addr)); ++ grub_memcpy (subnet_mask.v4.addr, manual_address->subnet_mask, sizeof (subnet_mask.v4.addr)); ++ ++ status = efi_call_3 (pxe->set_station_ip, pxe, &station_ip, &subnet_mask); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_printf ("Couldn't set station ip\n"); ++ ++ grub_free (manual_address); ++ } ++ } ++ ++#if 0 ++ if (mode->using_ipv6) ++ { ++ grub_printf ("PXE STATION IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ mode->station_ip.v6.addr[0], ++ mode->station_ip.v6.addr[1], ++ mode->station_ip.v6.addr[2], ++ mode->station_ip.v6.addr[3], ++ mode->station_ip.v6.addr[4], ++ mode->station_ip.v6.addr[5], ++ mode->station_ip.v6.addr[6], ++ mode->station_ip.v6.addr[7], ++ mode->station_ip.v6.addr[8], ++ mode->station_ip.v6.addr[9], ++ mode->station_ip.v6.addr[10], ++ mode->station_ip.v6.addr[11], ++ mode->station_ip.v6.addr[12], ++ mode->station_ip.v6.addr[13], ++ mode->station_ip.v6.addr[14], ++ mode->station_ip.v6.addr[15]); ++ } ++ else ++ { ++ grub_printf ("PXE STATION IP: %d.%d.%d.%d\n", ++ mode->station_ip.v4.addr[0], ++ mode->station_ip.v4.addr[1], ++ mode->station_ip.v4.addr[2], ++ mode->station_ip.v4.addr[3]); ++ grub_printf ("PXE SUBNET MASK: %d.%d.%d.%d\n", ++ mode->subnet_mask.v4.addr[0], ++ mode->subnet_mask.v4.addr[1], ++ mode->subnet_mask.v4.addr[2], ++ mode->subnet_mask.v4.addr[3]); ++ } ++#endif ++ ++ /* TODO: Set The Station IP to the IP2 Config */ ++} ++ ++static int ++parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) ++{ ++ grub_uint16_t newip[8]; ++ const char *ptr = val; ++ int word, quaddot = -1; ++ int bracketed = 0; ++ ++ if (ptr[0] == '[') { ++ bracketed = 1; ++ ptr++; ++ } ++ ++ if (ptr[0] == ':' && ptr[1] != ':') ++ return 0; ++ if (ptr[0] == ':') ++ ptr++; ++ ++ for (word = 0; word < 8; word++) ++ { ++ unsigned long t; ++ if (*ptr == ':') ++ { ++ quaddot = word; ++ word--; ++ ptr++; ++ continue; ++ } ++ t = grub_strtoul (ptr, (char **) &ptr, 16); ++ if (grub_errno) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ break; ++ } ++ if (t & ~0xffff) ++ return 0; ++ newip[word] = grub_cpu_to_be16 (t); ++ if (*ptr != ':') ++ break; ++ ptr++; ++ } ++ if (quaddot == -1 && word < 7) ++ return 0; ++ if (quaddot != -1) ++ { ++ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot], ++ (word - quaddot + 1) * sizeof (newip[0])); ++ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0])); ++ } ++ grub_memcpy (ip, newip, 16); ++ if (bracketed && *ptr == ']') { ++ ptr++; ++ } ++ if (rest) ++ *rest = ptr; ++ return 1; ++} ++ ++static grub_err_t ++pxe_open (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type __attribute__((unused))) ++{ ++ int i; ++ char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_ip_address_t server_ip; ++ grub_efi_uint64_t file_size = 0; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++#if 0 ++ grub_printf ("PXE SERVER IP: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", ++ server_ip.v6.addr[0], ++ server_ip.v6.addr[1], ++ server_ip.v6.addr[2], ++ server_ip.v6.addr[3], ++ server_ip.v6.addr[4], ++ server_ip.v6.addr[5], ++ server_ip.v6.addr[6], ++ server_ip.v6.addr[7], ++ server_ip.v6.addr[8], ++ server_ip.v6.addr[9], ++ server_ip.v6.addr[10], ++ server_ip.v6.addr[11], ++ server_ip.v6.addr[12], ++ server_ip.v6.addr[13], ++ server_ip.v6.addr[14], ++ server_ip.v6.addr[15]); ++#endif ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ NULL, ++ 0, ++ &file_size, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)filename, ++ NULL, ++ 0); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ return grub_error (GRUB_ERR_IO, "Couldn't get file size"); ++ ++ file->size = (grub_off_t)file_size; ++ file->not_easily_seekable = 0; ++ file->data = 0; ++ file->device->net->offset = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++pxe_close (struct grub_efi_net_device *dev __attribute__((unused)), ++ int prefer_ip6 __attribute__((unused)), ++ grub_file_t file __attribute__((unused))) ++{ ++ file->offset = 0; ++ file->size = 0; ++ file->device->net->offset = 0; ++ ++ if (file->data) ++ { ++ grub_free (file->data); ++ file->data = NULL; ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_ssize_t ++pxe_read (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len) ++{ ++ int i; ++ char *p; ++ grub_efi_status_t status; ++ grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; ++ grub_efi_uint64_t bufsz = len; ++ grub_efi_pxe_ip_address_t server_ip; ++ char *buf2 = NULL; ++ ++ if (file->data) ++ { ++ /* TODO: RANGE Check for offset and file size */ ++ grub_memcpy (buf, (char*)file->data + file->device->net->offset, len); ++ file->device->net->offset += len; ++ return len; ++ } ++ ++ if (file->device->net->offset) ++ { ++ grub_error (GRUB_ERR_BUG, "No Offet Read Possible"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (pxe->mode->using_ipv6) ++ { ++ const char *rest; ++ grub_uint64_t ip6[2]; ++ if (parse_ip6 (file->device->net->server, ip6, &rest) && *rest == 0) ++ grub_memcpy (server_ip.v6.addr, ip6, sizeof (server_ip.v6.addr)); ++ /* TODO: ERROR Handling Here */ ++ } ++ else ++ { ++ for (i = 0, p = file->device->net->server; i < 4; ++i, ++p) ++ server_ip.v4.addr[i] = grub_strtoul (p, &p, 10); ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ ++ if (bufsz != file->size) ++ { ++ grub_error (GRUB_ERR_BUG, "Short read should not happen here"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (status == GRUB_EFI_BUFFER_TOO_SMALL) ++ { ++ ++ buf2 = grub_malloc (bufsz); ++ ++ if (!buf2) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "ERROR OUT OF MEMORY"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ status = efi_call_10 (pxe->mtftp, ++ pxe, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ buf2, ++ 0, ++ &bufsz, ++ NULL, ++ &server_ip, ++ (grub_efi_char8_t *)file->device->net->name, ++ NULL, ++ 0); ++ } ++ ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ if (buf2) ++ grub_free (buf2); ++ ++ grub_error (GRUB_ERR_IO, "Failed to Read File"); ++ grub_print_error (); ++ return 0; ++ } ++ ++ if (buf2) ++ grub_memcpy (buf, buf2, len); ++ ++ file->device->net->offset = len; ++ ++ if (buf2) ++ file->data = buf2; ++ ++ return len; ++} ++ ++struct grub_efi_net_io io_pxe = ++ { ++ .configure = pxe_configure, ++ .open = pxe_open, ++ .read = pxe_read, ++ .close = pxe_close ++ }; ++ +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 0ce5e675ed..55aed92722 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -32,6 +32,9 @@ + #include + #include + #include ++#ifdef GRUB_MACHINE_EFI ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -2033,8 +2036,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; + static grub_command_t cmd_lsroutes, cmd_lscards; + static grub_command_t cmd_lsaddr, cmd_slaac; + ++#ifdef GRUB_MACHINE_EFI ++ ++static enum { ++ INIT_MODE_NONE, ++ INIT_MODE_GRUB, ++ INIT_MODE_EFI ++} init_mode; ++ ++static grub_command_t cmd_bootp, cmd_bootp6; ++ ++#endif ++ + GRUB_MOD_INIT(net) + { ++#ifdef GRUB_MACHINE_EFI ++ if (grub_net_open) ++ return; ++ ++ if ((grub_efi_net_boot_from_https () || grub_efi_net_boot_from_opa ()) ++ && grub_efi_net_fs_init ()) ++ { ++ cmd_lsroutes = grub_register_command ("net_ls_routes", grub_efi_net_list_routes, ++ "", N_("list network routes")); ++ cmd_lscards = grub_register_command ("net_ls_cards", grub_efi_net_list_cards, ++ "", N_("list network cards")); ++ cmd_lsaddr = grub_register_command ("net_ls_addr", grub_efi_net_list_addrs, ++ "", N_("list network addresses")); ++ cmd_addaddr = grub_register_command ("net_add_addr", grub_efi_net_add_addr, ++ /* TRANSLATORS: HWADDRESS stands for ++ "hardware address". */ ++ N_("SHORTNAME CARD ADDRESS [HWADDRESS]"), ++ N_("Add a network address.")); ++ cmd_bootp = grub_register_command ("net_bootp", grub_efi_net_bootp, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ cmd_bootp6 = grub_register_command ("net_bootp6", grub_efi_net_bootp6, ++ N_("[CARD]"), ++ N_("perform a bootp autoconfiguration")); ++ init_mode = INIT_MODE_EFI; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", defserver_get_env, + defserver_set_env); + grub_env_export ("net_default_server"); +@@ -2082,10 +2126,37 @@ GRUB_MOD_INIT(net) + grub_net_restore_hw, + GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++ ++#ifdef GRUB_MACHINE_EFI ++ grub_env_set ("grub_netfs_type", "grub"); ++ grub_register_variable_hook ("grub_netfs_type", 0, grub_env_write_readonly); ++ grub_env_export ("grub_netfs_type"); ++ init_mode = INIT_MODE_GRUB; ++#endif ++ + } + + GRUB_MOD_FINI(net) + { ++ ++#ifdef GRUB_MACHINE_EFI ++ if (init_mode == INIT_MODE_NONE) ++ return; ++ ++ if (init_mode == INIT_MODE_EFI) ++ { ++ grub_unregister_command (cmd_lsroutes); ++ grub_unregister_command (cmd_lscards); ++ grub_unregister_command (cmd_lsaddr); ++ grub_unregister_command (cmd_addaddr); ++ grub_unregister_command (cmd_bootp); ++ grub_unregister_command (cmd_bootp6); ++ grub_efi_net_fs_fini (); ++ init_mode = INIT_MODE_NONE; ++ return; ++ } ++#endif ++ + grub_register_variable_hook ("net_default_server", 0, 0); + grub_register_variable_hook ("pxe_default_server", 0, 0); + +@@ -2104,4 +2175,7 @@ GRUB_MOD_FINI(net) + grub_net_fini_hw (0); + grub_loader_unregister_preboot_hook (fini_hnd); + grub_net_poll_cards_idle = grub_net_poll_cards_idle_real; ++#ifdef GRUB_MACHINE_EFI ++ init_mode = INIT_MODE_NONE; ++#endif + } +diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c +index a2461cda1c..77958dd9dd 100644 +--- a/util/grub-mknetdir.c ++++ b/util/grub-mknetdir.c +@@ -32,13 +32,15 @@ + + static char *rootdir = NULL, *subdir = NULL; + static char *debug_image = NULL; ++static char efi_netfs = 0; + + enum + { + OPTION_NET_DIRECTORY = 0x301, + OPTION_SUBDIR, + OPTION_DEBUG, +- OPTION_DEBUG_IMAGE ++ OPTION_DEBUG_IMAGE, ++ OPTION_DEBUG_EFI_NETFS + }; + + static struct argp_option options[] = { +@@ -49,6 +51,7 @@ static struct argp_option options[] = { + 0, N_("relative subdirectory on network server"), 2}, + {"debug", OPTION_DEBUG, 0, OPTION_HIDDEN, 0, 2}, + {"debug-image", OPTION_DEBUG_IMAGE, N_("STRING"), OPTION_HIDDEN, 0, 2}, ++ {"debug-efi-netfs", OPTION_DEBUG_EFI_NETFS, 0, OPTION_HIDDEN, 0, 2}, + {0, 0, 0, 0, 0, 0} + }; + +@@ -67,6 +70,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + free (subdir); + subdir = xstrdup (arg); + return 0; ++ case OPTION_DEBUG_EFI_NETFS: ++ efi_netfs = 1; ++ return 0; + /* This is an undocumented feature... */ + case OPTION_DEBUG: + verbosity++; +@@ -82,7 +88,6 @@ argp_parser (int key, char *arg, struct argp_state *state) + } + } + +- + struct argp argp = { + options, argp_parser, NULL, + "\v"N_("Prepares GRUB network boot images at net_directory/subdir " +@@ -92,7 +97,7 @@ struct argp argp = { + + static char *base; + +-static const struct ++static struct + { + const char *mkimage_target; + const char *netmodule; +@@ -156,6 +161,7 @@ process_input_dir (const char *input_dir, enum grub_install_plat platform) + grub_install_push_module (targets[platform].netmodule); + + output = grub_util_path_concat_ext (2, grubdir, "core", targets[platform].ext); ++ + grub_install_make_image_wrap (input_dir, prefix, output, + 0, load_cfg, + targets[platform].mkimage_target, 0); +@@ -195,7 +201,16 @@ main (int argc, char *argv[]) + + grub_install_mkdir_p (base); + +- grub_install_push_module ("tftp"); ++ if (!efi_netfs) ++ { ++ grub_install_push_module ("tftp"); ++ grub_install_push_module ("http"); ++ } ++ else ++ { ++ targets[GRUB_INSTALL_PLATFORM_I386_EFI].netmodule = "efi_netfs"; ++ targets[GRUB_INSTALL_PLATFORM_X86_64_EFI].netmodule = "efi_netfs"; ++ } + + if (!grub_install_source_directory) + { +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 0b490195ad..f431f49973 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -622,6 +622,23 @@ typedef union + + typedef grub_efi_uint64_t grub_efi_physical_address_t; + typedef grub_efi_uint64_t grub_efi_virtual_address_t; ++typedef struct { ++ grub_uint8_t addr[4]; ++} grub_efi_pxe_ipv4_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[16]; ++} grub_efi_pxe_ipv6_address_t; ++ ++typedef struct { ++ grub_uint8_t addr[32]; ++} grub_efi_pxe_mac_address_t; ++ ++typedef union { ++ grub_uint32_t addr[4]; ++ grub_efi_pxe_ipv4_address_t v4; ++ grub_efi_pxe_ipv6_address_t v6; ++} grub_efi_pxe_ip_address_t; + + struct grub_efi_guid + { +@@ -889,6 +906,8 @@ struct grub_efi_ipv6_device_path + grub_efi_uint16_t remote_port; + grub_efi_uint16_t protocol; + grub_efi_uint8_t static_ip_address; ++ grub_efi_uint8_t prefix_length; ++ grub_efi_ipv6_address_t gateway_ip_address; + } GRUB_PACKED; + typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t; + +@@ -938,6 +957,15 @@ struct grub_efi_uri_device_path + } GRUB_PACKED; + typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t; + ++#define GRUB_EFI_DNS_DEVICE_PATH_SUBTYPE 31 ++struct grub_efi_dns_device_path ++{ ++ grub_efi_device_path_t header; ++ grub_efi_uint8_t is_ipv6; ++ grub_efi_pxe_ip_address_t dns_server_ip[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_dns_device_path grub_efi_dns_device_path_t; ++ + #define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10 + + /* Media Device Path. */ +@@ -1020,6 +1048,23 @@ struct grub_efi_bios_device_path + } GRUB_PACKED; + typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t; + ++/* Service Binding definitions */ ++struct grub_efi_service_binding; ++ ++typedef grub_efi_status_t ++(*grub_efi_service_binding_create_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef grub_efi_status_t ++(*grub_efi_service_binding_destroy_child) (struct grub_efi_service_binding *this, ++ grub_efi_handle_t *child_handle); ++ ++typedef struct grub_efi_service_binding ++{ ++ grub_efi_service_binding_create_child create_child; ++ grub_efi_service_binding_destroy_child destroy_child; ++} grub_efi_service_binding_t; ++ + struct grub_efi_open_protocol_information_entry + { + grub_efi_handle_t agent_handle; +@@ -1569,23 +1614,27 @@ typedef struct grub_efi_pxe_tftp_error + grub_efi_char8_t error_string[127]; + } grub_efi_pxe_tftp_error_t; + +-typedef struct { +- grub_uint8_t addr[4]; +-} grub_efi_pxe_ipv4_address_t; ++typedef grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_t; + +-typedef struct { +- grub_uint8_t addr[16]; +-} grub_efi_pxe_ipv6_address_t; ++typedef enum { ++ GRUB_EFI_PXE_BASE_CODE_TFTP_FIRST, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_WRITE_FILE, ++ GRUB_EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_FILE, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY, ++ GRUB_EFI_PXE_BASE_CODE_MTFTP_LAST ++} grub_efi_pxe_base_code_tftp_opcode_t; + + typedef struct { +- grub_uint8_t addr[32]; +-} grub_efi_pxe_mac_address_t; +- +-typedef union { +- grub_uint32_t addr[4]; +- grub_efi_pxe_ipv4_address_t v4; +- grub_efi_pxe_ipv6_address_t v6; +-} grub_efi_pxe_ip_address_t; ++ grub_efi_ip_address_t mcast_ip; ++ grub_efi_pxe_base_code_udp_port_t c_port; ++ grub_efi_pxe_base_code_udp_port_t s_port; ++ grub_efi_uint16_t listen_timeout; ++ grub_efi_uint16_t transmit_timeout; ++} grub_efi_pxe_base_code_mtftp_info_t; + + #define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8 + typedef struct grub_efi_pxe_ip_filter +@@ -1652,17 +1701,31 @@ typedef struct grub_efi_pxe_mode + typedef struct grub_efi_pxe + { + grub_uint64_t rev; +- void (*start) (void); ++ grub_efi_status_t (*start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); + void (*stop) (void); +- void (*dhcp) (void); ++ grub_efi_status_t (*dhcp) (struct grub_efi_pxe *this, ++ grub_efi_boolean_t sort_offers); + void (*discover) (void); +- void (*mftp) (void); ++ grub_efi_status_t (*mtftp) (struct grub_efi_pxe *this, ++ grub_efi_pxe_base_code_tftp_opcode_t operation, ++ void *buffer_ptr, ++ grub_efi_boolean_t overwrite, ++ grub_efi_uint64_t *buffer_size, ++ grub_efi_uintn_t *block_size, ++ grub_efi_pxe_ip_address_t *server_ip, ++ //grub_efi_ip_address_t *server_ip, ++ grub_efi_char8_t *filename, ++ grub_efi_pxe_base_code_mtftp_info_t *info, ++ grub_efi_boolean_t dont_use_buffer); + void (*udpwrite) (void); + void (*udpread) (void); + void (*setipfilter) (void); + void (*arp) (void); + void (*setparams) (void); +- void (*setstationip) (void); ++ grub_efi_status_t (*set_station_ip) (struct grub_efi_pxe *this, ++ grub_efi_pxe_ip_address_t *new_station_ip, ++ grub_efi_pxe_ip_address_t *new_subnet_mask); ++ //void (*setstationip) (void); + void (*setpackets) (void); + struct grub_efi_pxe_mode *mode; + } grub_efi_pxe_t; +@@ -1924,6 +1987,44 @@ struct grub_efi_ip4_config2_protocol + }; + typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t; + ++struct grub_efi_ip4_route_table { ++ grub_efi_ipv4_address_t subnet_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_ipv4_address_t gateway_address; ++}; ++ ++typedef struct grub_efi_ip4_route_table grub_efi_ip4_route_table_t; ++ ++#define GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 ++ ++struct grub_efi_ip4_config2_interface_info { ++ grub_efi_char16_t name[GRUB_EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_ipv4_address_t station_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t route_table_size; ++ grub_efi_ip4_route_table_t *route_table; ++}; ++ ++typedef struct grub_efi_ip4_config2_interface_info grub_efi_ip4_config2_interface_info_t; ++ ++enum grub_efi_ip4_config2_policy { ++ GRUB_EFI_IP4_CONFIG2_POLICY_STATIC, ++ GRUB_EFI_IP4_CONFIG2_POLICY_DHCP, ++ GRUB_EFI_IP4_CONFIG2_POLICY_MAX ++}; ++ ++typedef enum grub_efi_ip4_config2_policy grub_efi_ip4_config2_policy_t; ++ ++struct grub_efi_ip4_config2_manual_address { ++ grub_efi_ipv4_address_t address; ++ grub_efi_ipv4_address_t subnet_mask; ++}; ++ ++typedef struct grub_efi_ip4_config2_manual_address grub_efi_ip4_config2_manual_address_t; ++ + enum grub_efi_ip6_config_data_type { + GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO, + GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID, +@@ -1958,6 +2059,49 @@ struct grub_efi_ip6_config_protocol + }; + typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t; + ++enum grub_efi_ip6_config_policy { ++ GRUB_EFI_IP6_CONFIG_POLICY_MANUAL, ++ GRUB_EFI_IP6_CONFIG_POLICY_AUTOMATIC ++}; ++typedef enum grub_efi_ip6_config_policy grub_efi_ip6_config_policy_t; ++ ++struct grub_efi_ip6_address_info { ++ grub_efi_ipv6_address_t address; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_address_info grub_efi_ip6_address_info_t; ++ ++struct grub_efi_ip6_route_table { ++ grub_efi_pxe_ipv6_address_t gateway; ++ grub_efi_pxe_ipv6_address_t destination; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_route_table grub_efi_ip6_route_table_t; ++ ++struct grub_efi_ip6_config_interface_info { ++ grub_efi_char16_t name[32]; ++ grub_efi_uint8_t if_type; ++ grub_efi_uint32_t hw_address_size; ++ grub_efi_mac_address_t hw_address; ++ grub_efi_uint32_t address_info_count; ++ grub_efi_ip6_address_info_t *address_info; ++ grub_efi_uint32_t route_count; ++ grub_efi_ip6_route_table_t *route_table; ++}; ++typedef struct grub_efi_ip6_config_interface_info grub_efi_ip6_config_interface_info_t; ++ ++struct grub_efi_ip6_config_dup_addr_detect_transmits { ++ grub_efi_uint32_t dup_addr_detect_transmits; ++}; ++typedef struct grub_efi_ip6_config_dup_addr_detect_transmits grub_efi_ip6_config_dup_addr_detect_transmits_t; ++ ++struct grub_efi_ip6_config_manual_address { ++ grub_efi_ipv6_address_t address; ++ grub_efi_boolean_t is_anycast; ++ grub_efi_uint8_t prefix_length; ++}; ++typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) +diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h +new file mode 100644 +index 0000000000..fdb88eb810 +--- /dev/null ++++ b/include/grub/efi/dhcp.h +@@ -0,0 +1,343 @@ ++#ifndef GRUB_EFI_DHCP_HEADER ++#define GRUB_EFI_DHCP_HEADER 1 ++ ++#define GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9d9a39d8, 0xbd42, 0x4a73, \ ++ { 0xa4, 0xd5, 0x8e, 0xe9, 0x4b, 0xe1, 0x13, 0x80 } \ ++ } ++ ++#define GRUB_EFI_DHCP4_PROTOCOL_GUID \ ++ { 0x8a219718, 0x4ef5, 0x4761, \ ++ { 0x91, 0xc8, 0xc0, 0xf0, 0x4b, 0xda, 0x9e, 0x56 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0x9fb9a8a1, 0x2f4a, 0x43a6, \ ++ { 0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4 ,0x7a, 0xd5 } \ ++ } ++ ++#define GRUB_EFI_DHCP6_PROTOCOL_GUID \ ++ { 0x87c8bad7, 0x595, 0x4053, \ ++ { 0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ ++ } ++ ++typedef struct grub_efi_dhcp4_protocol grub_efi_dhcp4_protocol_t; ++ ++enum grub_efi_dhcp4_state { ++ GRUB_EFI_DHCP4_STOPPED, ++ GRUB_EFI_DHCP4_INIT, ++ GRUB_EFI_DHCP4_SELECTING, ++ GRUB_EFI_DHCP4_REQUESTING, ++ GRUB_EFI_DHCP4_BOUND, ++ GRUB_EFI_DHCP4_RENEWING, ++ GRUB_EFI_DHCP4_REBINDING, ++ GRUB_EFI_DHCP4_INIT_REBOOT, ++ GRUB_EFI_DHCP4_REBOOTING ++}; ++ ++typedef enum grub_efi_dhcp4_state grub_efi_dhcp4_state_t; ++ ++struct grub_efi_dhcp4_header { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t hw_type; ++ grub_efi_uint8_t hw_addr_len; ++ grub_efi_uint8_t hops; ++ grub_efi_uint32_t xid; ++ grub_efi_uint16_t seconds; ++ grub_efi_uint16_t reserved; ++ grub_efi_ipv4_address_t client_addr; ++ grub_efi_ipv4_address_t your_addr; ++ grub_efi_ipv4_address_t server_addr; ++ grub_efi_ipv4_address_t gateway_addr; ++ grub_efi_uint8_t client_hw_addr[16]; ++ grub_efi_char8_t server_name[64]; ++ grub_efi_char8_t boot_file_name[128]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_header grub_efi_dhcp4_header_t; ++ ++struct grub_efi_dhcp4_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp4_header_t header; ++ grub_efi_uint32_t magik; ++ grub_efi_uint8_t option[1]; ++ } dhcp4; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet grub_efi_dhcp4_packet_t; ++ ++struct grub_efi_dhcp4_listen_point { ++ grub_efi_ipv4_address_t listen_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint16_t listen_port; ++}; ++ ++typedef struct grub_efi_dhcp4_listen_point grub_efi_dhcp4_listen_point_t; ++ ++struct grub_efi_dhcp4_transmit_receive_token { ++ grub_efi_status_t status; ++ grub_efi_event_t completion_event; ++ grub_efi_ipv4_address_t remote_address; ++ grub_efi_uint16_t remote_port; ++ grub_efi_ipv4_address_t gateway_address; ++ grub_efi_uint32_t listen_point_count; ++ grub_efi_dhcp4_listen_point_t *listen_points; ++ grub_efi_uint32_t timeout_value; ++ grub_efi_dhcp4_packet_t *packet; ++ grub_efi_uint32_t response_count; ++ grub_efi_dhcp4_packet_t *response_list; ++}; ++ ++typedef struct grub_efi_dhcp4_transmit_receive_token grub_efi_dhcp4_transmit_receive_token_t; ++ ++enum grub_efi_dhcp4_event { ++ GRUB_EFI_DHCP4_SEND_DISCOVER = 0X01, ++ GRUB_EFI_DHCP4_RCVD_OFFER, ++ GRUB_EFI_DHCP4_SELECT_OFFER, ++ GRUB_EFI_DHCP4_SEND_REQUEST, ++ GRUB_EFI_DHCP4_RCVD_ACK, ++ GRUB_EFI_DHCP4_RCVD_NAK, ++ GRUB_EFI_DHCP4_SEND_DECLINE, ++ GRUB_EFI_DHCP4_BOUND_COMPLETED, ++ GRUB_EFI_DHCP4_ENTER_RENEWING, ++ GRUB_EFI_DHCP4_ENTER_REBINDING, ++ GRUB_EFI_DHCP4_ADDRESS_LOST, ++ GRUB_EFI_DHCP4_FAIL ++}; ++ ++typedef enum grub_efi_dhcp4_event grub_efi_dhcp4_event_t; ++ ++struct grub_efi_dhcp4_packet_option { ++ grub_efi_uint8_t op_code; ++ grub_efi_uint8_t length; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp4_packet_option grub_efi_dhcp4_packet_option_t; ++ ++struct grub_efi_dhcp4_config_data { ++ grub_efi_uint32_t discover_try_count; ++ grub_efi_uint32_t *discover_timeout; ++ grub_efi_uint32_t request_try_count; ++ grub_efi_uint32_t *request_timeout; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_status_t (*dhcp4_callback) ( ++ grub_efi_dhcp4_protocol_t *this, ++ void *context, ++ grub_efi_dhcp4_state_t current_state, ++ grub_efi_dhcp4_event_t dhcp4_event, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_dhcp4_packet_t **new_packet ++ ); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp4_packet_option_t **option_list; ++}; ++ ++typedef struct grub_efi_dhcp4_config_data grub_efi_dhcp4_config_data_t; ++ ++struct grub_efi_dhcp4_mode_data { ++ grub_efi_dhcp4_state_t state; ++ grub_efi_dhcp4_config_data_t config_data; ++ grub_efi_ipv4_address_t client_address; ++ grub_efi_mac_address_t client_mac_address; ++ grub_efi_ipv4_address_t server_address; ++ grub_efi_ipv4_address_t router_address; ++ grub_efi_ipv4_address_t subnet_mask; ++ grub_efi_uint32_t lease_time; ++ grub_efi_dhcp4_packet_t *reply_packet; ++}; ++ ++typedef struct grub_efi_dhcp4_mode_data grub_efi_dhcp4_mode_data_t; ++ ++struct grub_efi_dhcp4_protocol { ++ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); ++ grub_efi_status_t (*configure) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); ++ grub_efi_status_t (*start) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_boolean_t rebind_request, ++ grub_efi_event_t completion_event); ++ grub_efi_status_t (*release) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (*stop) (grub_efi_dhcp4_protocol_t *this); ++ grub_efi_status_t (*build) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *seed_packet, ++ grub_efi_uint32_t delete_count, ++ grub_efi_uint8_t *delete_list, ++ grub_efi_uint32_t append_count, ++ grub_efi_dhcp4_packet_option_t *append_list[], ++ grub_efi_dhcp4_packet_t **new_packet); ++ grub_efi_status_t (*transmit_receive) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_transmit_receive_token_t *token); ++ grub_efi_status_t (*parse) (grub_efi_dhcp4_protocol_t *this, ++ grub_efi_dhcp4_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp4_packet_option_t *packet_option_list[]); ++}; ++ ++typedef struct grub_efi_dhcp6_protocol grub_efi_dhcp6_protocol_t; ++ ++struct grub_efi_dhcp6_retransmission { ++ grub_efi_uint32_t irt; ++ grub_efi_uint32_t mrc; ++ grub_efi_uint32_t mrt; ++ grub_efi_uint32_t mrd; ++}; ++ ++typedef struct grub_efi_dhcp6_retransmission grub_efi_dhcp6_retransmission_t; ++ ++enum grub_efi_dhcp6_event { ++ GRUB_EFI_DHCP6_SEND_SOLICIT, ++ GRUB_EFI_DHCP6_RCVD_ADVERTISE, ++ GRUB_EFI_DHCP6_SELECT_ADVERTISE, ++ GRUB_EFI_DHCP6_SEND_REQUEST, ++ GRUB_EFI_DHCP6_RCVD_REPLY, ++ GRUB_EFI_DHCP6_RCVD_RECONFIGURE, ++ GRUB_EFI_DHCP6_SEND_DECLINE, ++ GRUB_EFI_DHCP6_SEND_CONFIRM, ++ GRUB_EFI_DHCP6_SEND_RELEASE, ++ GRUB_EFI_DHCP6_SEND_RENEW, ++ GRUB_EFI_DHCP6_SEND_REBIND ++}; ++ ++typedef enum grub_efi_dhcp6_event grub_efi_dhcp6_event_t; ++ ++struct grub_efi_dhcp6_packet_option { ++ grub_efi_uint16_t op_code; ++ grub_efi_uint16_t op_len; ++ grub_efi_uint8_t data[1]; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet_option grub_efi_dhcp6_packet_option_t; ++ ++struct grub_efi_dhcp6_header { ++ grub_efi_uint32_t transaction_id:24; ++ grub_efi_uint32_t message_type:8; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_header grub_efi_dhcp6_header_t; ++ ++struct grub_efi_dhcp6_packet { ++ grub_efi_uint32_t size; ++ grub_efi_uint32_t length; ++ struct { ++ grub_efi_dhcp6_header_t header; ++ grub_efi_uint8_t option[1]; ++ } dhcp6; ++} GRUB_PACKED; ++ ++typedef struct grub_efi_dhcp6_packet grub_efi_dhcp6_packet_t; ++ ++struct grub_efi_dhcp6_ia_address { ++ grub_efi_ipv6_address_t ip_address; ++ grub_efi_uint32_t preferred_lifetime; ++ grub_efi_uint32_t valid_lifetime; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_address grub_efi_dhcp6_ia_address_t; ++ ++enum grub_efi_dhcp6_state { ++ GRUB_EFI_DHCP6_INIT, ++ GRUB_EFI_DHCP6_SELECTING, ++ GRUB_EFI_DHCP6_REQUESTING, ++ GRUB_EFI_DHCP6_DECLINING, ++ GRUB_EFI_DHCP6_CONFIRMING, ++ GRUB_EFI_DHCP6_RELEASING, ++ GRUB_EFI_DHCP6_BOUND, ++ GRUB_EFI_DHCP6_RENEWING, ++ GRUB_EFI_DHCP6_REBINDING ++}; ++ ++typedef enum grub_efi_dhcp6_state grub_efi_dhcp6_state_t; ++ ++#define GRUB_EFI_DHCP6_IA_TYPE_NA 3 ++#define GRUB_EFI_DHCP6_IA_TYPE_TA 4 ++ ++struct grub_efi_dhcp6_ia_descriptor { ++ grub_efi_uint16_t type; ++ grub_efi_uint32_t ia_id; ++}; ++ ++typedef struct grub_efi_dhcp6_ia_descriptor grub_efi_dhcp6_ia_descriptor_t; ++ ++struct grub_efi_dhcp6_ia { ++ grub_efi_dhcp6_ia_descriptor_t descriptor; ++ grub_efi_dhcp6_state_t state; ++ grub_efi_dhcp6_packet_t *reply_packet; ++ grub_efi_uint32_t ia_address_count; ++ grub_efi_dhcp6_ia_address_t ia_address[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_ia grub_efi_dhcp6_ia_t; ++ ++struct grub_efi_dhcp6_duid { ++ grub_efi_uint16_t length; ++ grub_efi_uint8_t duid[1]; ++}; ++ ++typedef struct grub_efi_dhcp6_duid grub_efi_dhcp6_duid_t; ++ ++struct grub_efi_dhcp6_mode_data { ++ grub_efi_dhcp6_duid_t *client_id; ++ grub_efi_dhcp6_ia_t *ia; ++}; ++ ++typedef struct grub_efi_dhcp6_mode_data grub_efi_dhcp6_mode_data_t; ++ ++struct grub_efi_dhcp6_config_data { ++ grub_efi_status_t (*dhcp6_callback) (grub_efi_dhcp6_protocol_t this, ++ void *context, ++ grub_efi_dhcp6_state_t current_state, ++ grub_efi_dhcp6_event_t dhcp6_event, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_dhcp6_packet_t **new_packet); ++ void *callback_context; ++ grub_efi_uint32_t option_count; ++ grub_efi_dhcp6_packet_option_t **option_list; ++ grub_efi_dhcp6_ia_descriptor_t ia_descriptor; ++ grub_efi_event_t ia_info_event; ++ grub_efi_boolean_t reconfigure_accept; ++ grub_efi_boolean_t rapid_commit; ++ grub_efi_dhcp6_retransmission_t *solicit_retransmission; ++}; ++ ++typedef struct grub_efi_dhcp6_config_data grub_efi_dhcp6_config_data_t; ++ ++struct grub_efi_dhcp6_protocol { ++ grub_efi_status_t (*get_mode_data) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_mode_data_t *dhcp6_mode_data, ++ grub_efi_dhcp6_config_data_t *dhcp6_config_data); ++ grub_efi_status_t (*configure) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); ++ grub_efi_status_t (*start) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (*info_request) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t send_client_id, ++ grub_efi_dhcp6_packet_option_t *option_request, ++ grub_efi_uint32_t option_count, ++ grub_efi_dhcp6_packet_option_t *option_list[], ++ grub_efi_dhcp6_retransmission_t *retransmission, ++ grub_efi_event_t timeout_event, ++ grub_efi_status_t (*reply_callback) (grub_efi_dhcp6_protocol_t *this, ++ void *context, ++ grub_efi_dhcp6_packet_t *packet), ++ void *callback_context); ++ grub_efi_status_t (*renew_rebind) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_boolean_t rebind_request); ++ grub_efi_status_t (*decline) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (*release) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_uint32_t address_count, ++ grub_efi_ipv6_address_t *addresses); ++ grub_efi_status_t (*stop) (grub_efi_dhcp6_protocol_t *this); ++ grub_efi_status_t (*parse) (grub_efi_dhcp6_protocol_t *this, ++ grub_efi_dhcp6_packet_t *packet, ++ grub_efi_uint32_t *option_count, ++ grub_efi_dhcp6_packet_option_t *packet_option_list[]); ++}; ++ ++#endif /* ! GRUB_EFI_DHCP_HEADER */ +diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h +new file mode 100644 +index 0000000000..c5e9a89f50 +--- /dev/null ++++ b/include/grub/efi/http.h +@@ -0,0 +1,215 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_HTTP_HEADER ++#define GRUB_EFI_HTTP_HEADER 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ ++ { 0xbdc8e6af, 0xd9bc, 0x4379, \ ++ { 0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ ++ } ++ ++#define GRUB_EFI_HTTP_PROTOCOL_GUID \ ++ { 0x7A59B29B, 0x910B, 0x4171, \ ++ { 0x82, 0x42, 0xA8, 0x5A, 0x0D, 0xF2, 0x5B, 0x5B } \ ++ } ++ ++#define EFIHTTP_WAIT_TIME 10000 // 10000ms = 10s ++#define EFIHTTP_RX_BUF_LEN 10240 ++ ++//****************************************** ++// Protocol Interface Structure ++//****************************************** ++struct grub_efi_http; ++ ++//****************************************** ++// EFI_HTTP_VERSION ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPVERSION10, ++ GRUB_EFI_HTTPVERSION11, ++ GRUB_EFI_HTTPVERSIONUNSUPPORTED ++} grub_efi_http_version_t; ++ ++//****************************************** ++// EFI_HTTPv4_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_boolean_t use_default_address; ++ grub_efi_ipv4_address_t local_address; ++ grub_efi_ipv4_address_t local_subnet; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv4_access_point_t; ++ ++//****************************************** ++// EFI_HTTPv6_ACCESS_POINT ++//****************************************** ++typedef struct { ++ grub_efi_ipv6_address_t local_address; ++ grub_efi_uint16_t local_port; ++} grub_efi_httpv6_access_point_t; ++ ++//****************************************** ++// EFI_HTTP_CONFIG_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_version_t http_version; ++ grub_efi_uint32_t timeout_millisec; ++ grub_efi_boolean_t local_address_is_ipv6; ++ union { ++ grub_efi_httpv4_access_point_t *ipv4_node; ++ grub_efi_httpv6_access_point_t *ipv6_node; ++ } access_point; ++} grub_efi_http_config_data_t; ++ ++//****************************************** ++// EFI_HTTP_METHOD ++//****************************************** ++typedef enum { ++ GRUB_EFI_HTTPMETHODGET, ++ GRUB_EFI_HTTPMETHODPOST, ++ GRUB_EFI_HTTPMETHODPATCH, ++ GRUB_EFI_HTTPMETHODOPTIONS, ++ GRUB_EFI_HTTPMETHODCONNECT, ++ GRUB_EFI_HTTPMETHODHEAD, ++ GRUB_EFI_HTTPMETHODPUT, ++ GRUB_EFI_HTTPMETHODDELETE, ++ GRUB_EFI_HTTPMETHODTRACE, ++} grub_efi_http_method_t; ++ ++//****************************************** ++// EFI_HTTP_REQUEST_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_method_t method; ++ grub_efi_char16_t *url; ++} grub_efi_http_request_data_t; ++ ++typedef enum { ++ GRUB_EFI_HTTP_STATUS_UNSUPPORTED_STATUS = 0, ++ GRUB_EFI_HTTP_STATUS_100_CONTINUE, ++ GRUB_EFI_HTTP_STATUS_101_SWITCHING_PROTOCOLS, ++ GRUB_EFI_HTTP_STATUS_200_OK, ++ GRUB_EFI_HTTP_STATUS_201_CREATED, ++ GRUB_EFI_HTTP_STATUS_202_ACCEPTED, ++ GRUB_EFI_HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, ++ GRUB_EFI_HTTP_STATUS_204_NO_CONTENT, ++ GRUB_EFI_HTTP_STATUS_205_RESET_CONTENT, ++ GRUB_EFI_HTTP_STATUS_206_PARTIAL_CONTENT, ++ GRUB_EFI_HTTP_STATUS_300_MULTIPLE_CHIOCES, ++ GRUB_EFI_HTTP_STATUS_301_MOVED_PERMANENTLY, ++ GRUB_EFI_HTTP_STATUS_302_FOUND, ++ GRUB_EFI_HTTP_STATUS_303_SEE_OTHER, ++ GRUB_EFI_HTTP_STATUS_304_NOT_MODIFIED, ++ GRUB_EFI_HTTP_STATUS_305_USE_PROXY, ++ GRUB_EFI_HTTP_STATUS_307_TEMPORARY_REDIRECT, ++ GRUB_EFI_HTTP_STATUS_400_BAD_REQUEST, ++ GRUB_EFI_HTTP_STATUS_401_UNAUTHORIZED, ++ GRUB_EFI_HTTP_STATUS_402_PAYMENT_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_403_FORBIDDEN, ++ GRUB_EFI_HTTP_STATUS_404_NOT_FOUND, ++ GRUB_EFI_HTTP_STATUS_405_METHOD_NOT_ALLOWED, ++ GRUB_EFI_HTTP_STATUS_406_NOT_ACCEPTABLE, ++ GRUB_EFI_HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_408_REQUEST_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_409_CONFLICT, ++ GRUB_EFI_HTTP_STATUS_410_GONE, ++ GRUB_EFI_HTTP_STATUS_411_LENGTH_REQUIRED, ++ GRUB_EFI_HTTP_STATUS_412_PRECONDITION_FAILED, ++ GRUB_EFI_HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, ++ GRUB_EFI_HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, ++ GRUB_EFI_HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, ++ GRUB_EFI_HTTP_STATUS_417_EXPECTATION_FAILED, ++ GRUB_EFI_HTTP_STATUS_500_INTERNAL_SERVER_ERROR, ++ GRUB_EFI_HTTP_STATUS_501_NOT_IMPLEMENTED, ++ GRUB_EFI_HTTP_STATUS_502_BAD_GATEWAY, ++ GRUB_EFI_HTTP_STATUS_503_SERVICE_UNAVAILABLE, ++ GRUB_EFI_HTTP_STATUS_504_GATEWAY_TIME_OUT, ++ GRUB_EFI_HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED ++} grub_efi_http_status_code_t; ++ ++//****************************************** ++// EFI_HTTP_RESPONSE_DATA ++//****************************************** ++typedef struct { ++ grub_efi_http_status_code_t status_code; ++} grub_efi_http_response_data_t; ++ ++//****************************************** ++// EFI_HTTP_HEADER ++//****************************************** ++typedef struct { ++ grub_efi_char8_t *field_name; ++ grub_efi_char8_t *field_value; ++} grub_efi_http_header_t; ++ ++//****************************************** ++// EFI_HTTP_MESSAGE ++//****************************************** ++typedef struct { ++ union { ++ grub_efi_http_request_data_t *request; ++ grub_efi_http_response_data_t *response; ++ } data; ++ grub_efi_uint32_t header_count; ++ grub_efi_http_header_t *headers; ++ grub_efi_uint32_t body_length; ++ void *body; ++} grub_efi_http_message_t; ++ ++//****************************************** ++// EFI_HTTP_TOKEN ++//****************************************** ++typedef struct { ++ grub_efi_event_t event; ++ grub_efi_status_t status; ++ grub_efi_http_message_t *message; ++} grub_efi_http_token_t; ++ ++struct grub_efi_http { ++ grub_efi_status_t ++ (*get_mode_data) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (*configure) (struct grub_efi_http *this, ++ grub_efi_http_config_data_t *http_config_data); ++ ++ grub_efi_status_t ++ (*request) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*cancel) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*response) (struct grub_efi_http *this, ++ grub_efi_http_token_t *token); ++ ++ grub_efi_status_t ++ (*poll) (struct grub_efi_http *this); ++}; ++typedef struct grub_efi_http grub_efi_http_t; ++ ++#endif /* !GRUB_EFI_HTTP_HEADER */ +diff --git a/include/grub/net/efi.h b/include/grub/net/efi.h +new file mode 100644 +index 0000000000..de90d223e8 +--- /dev/null ++++ b/include/grub/net/efi.h +@@ -0,0 +1,144 @@ ++#ifndef GRUB_NET_EFI_HEADER ++#define GRUB_NET_EFI_HEADER 1 ++ ++#include ++#include ++#include ++#include ++ ++typedef struct grub_efi_net_interface grub_efi_net_interface_t; ++typedef struct grub_efi_net_ip_config grub_efi_net_ip_config_t; ++typedef union grub_efi_net_ip_address grub_efi_net_ip_address_t; ++typedef struct grub_efi_net_ip_manual_address grub_efi_net_ip_manual_address_t; ++ ++struct grub_efi_net_interface ++{ ++ char *name; ++ int prefer_ip6; ++ struct grub_efi_net_device *dev; ++ struct grub_efi_net_io *io; ++ grub_efi_net_ip_config_t *ip_config; ++ int io_type; ++ struct grub_efi_net_interface *next; ++}; ++ ++#define efi_net_interface_get_hw_address(inf) inf->ip_config->get_hw_address (inf->dev) ++#define efi_net_interface_get_address(inf) inf->ip_config->get_address (inf->dev) ++#define efi_net_interface_get_route_table(inf) inf->ip_config->get_route_table (inf->dev) ++#define efi_net_interface_set_address(inf, addr, with_subnet) inf->ip_config->set_address (inf->dev, addr, with_subnet) ++#define efi_net_interface_set_gateway(inf, addr) inf->ip_config->set_gateway (inf->dev, addr) ++#define efi_net_interface_set_dns(inf, addr) inf->ip_config->set_dns (inf->dev, addr) ++ ++struct grub_efi_net_ip_config ++{ ++ char * (*get_hw_address) (struct grub_efi_net_device *dev); ++ char * (*get_address) (struct grub_efi_net_device *dev); ++ char ** (*get_route_table) (struct grub_efi_net_device *dev); ++ grub_efi_net_interface_t * (*best_interface) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_address) (struct grub_efi_net_device *dev, grub_efi_net_ip_manual_address_t *net_ip, int with_subnet); ++ int (*set_gateway) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *address); ++ int (*set_dns) (struct grub_efi_net_device *dev, grub_efi_net_ip_address_t *dns); ++}; ++ ++union grub_efi_net_ip_address ++{ ++ grub_efi_ipv4_address_t ip4; ++ grub_efi_ipv6_address_t ip6; ++}; ++ ++struct grub_efi_net_ip_manual_address ++{ ++ int is_ip6; ++ union ++ { ++ grub_efi_ip4_config2_manual_address_t ip4; ++ grub_efi_ip6_config_manual_address_t ip6; ++ }; ++}; ++ ++struct grub_efi_net_device ++{ ++ grub_efi_handle_t handle; ++ grub_efi_ip4_config2_protocol_t *ip4_config; ++ grub_efi_ip6_config_protocol_t *ip6_config; ++ grub_efi_handle_t http_handle; ++ grub_efi_http_t *http; ++ grub_efi_handle_t ip4_pxe_handle; ++ grub_efi_pxe_t *ip4_pxe; ++ grub_efi_handle_t ip6_pxe_handle; ++ grub_efi_pxe_t *ip6_pxe; ++ grub_efi_handle_t dhcp4_handle; ++ grub_efi_dhcp4_protocol_t *dhcp4; ++ grub_efi_handle_t dhcp6_handle; ++ grub_efi_dhcp6_protocol_t *dhcp6; ++ char *card_name; ++ grub_efi_net_interface_t *net_interfaces; ++ struct grub_efi_net_device *next; ++}; ++ ++struct grub_efi_net_io ++{ ++ void (*configure) (struct grub_efi_net_device *dev, int prefer_ip6); ++ grub_err_t (*open) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ const char *filename, ++ int type); ++ grub_ssize_t (*read) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file, ++ char *buf, ++ grub_size_t len); ++ grub_err_t (*close) (struct grub_efi_net_device *dev, ++ int prefer_ip6, ++ grub_file_t file); ++}; ++ ++extern struct grub_efi_net_device *net_devices; ++ ++extern struct grub_efi_net_io io_http; ++extern struct grub_efi_net_io io_pxe; ++ ++extern grub_efi_net_ip_config_t *efi_net_ip4_config; ++extern grub_efi_net_ip_config_t *efi_net_ip6_config; ++ ++char * ++grub_efi_ip4_address_to_string (grub_efi_ipv4_address_t *address); ++ ++char * ++grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address); ++ ++char * ++grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address); ++ ++int ++grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest); ++ ++int ++grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *address, const char **rest); ++ ++char * ++grub_efi_ip6_interface_name (struct grub_efi_net_device *dev); ++ ++char * ++grub_efi_ip4_interface_name (struct grub_efi_net_device *dev); ++ ++grub_efi_net_interface_t * ++grub_efi_net_create_interface (struct grub_efi_net_device *dev, ++ const char *interface_name, ++ grub_efi_net_ip_manual_address_t *net_ip, ++ int has_subnet); ++ ++int grub_efi_net_fs_init (void); ++void grub_efi_net_fs_fini (void); ++int grub_efi_net_boot_from_https (void); ++int grub_efi_net_boot_from_opa (void); ++ ++extern grub_command_func_t grub_efi_net_list_routes; ++extern grub_command_func_t grub_efi_net_list_cards; ++extern grub_command_func_t grub_efi_net_list_addrs; ++extern grub_command_func_t grub_efi_net_add_addr; ++extern grub_command_func_t grub_efi_net_bootp; ++extern grub_command_func_t grub_efi_net_bootp6; ++ ++#endif /* ! GRUB_NET_EFI_HEADER */ diff --git a/SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch b/SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch new file mode 100644 index 0000000..b487271 --- /dev/null +++ b/SOURCES/0079-AUDIT-0-http-boot-tracker-bug.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sebastian Krahmer +Date: Tue, 28 Nov 2017 17:24:38 +0800 +Subject: [PATCH] AUDIT-0: http boot tracker bug + +Fixing a memory leak in case of error, and a integer overflow, leading to a +heap overflow due to overly large chunk sizes. + +We need to check against some maximum value, otherwise values like 0xffffffff +will eventually lead in the allocation functions to small sized buffers, since +the len is rounded up to the next reasonable alignment. The following memcpy +will then smash the heap, leading to RCE. + +This is no big issue for pure http boot, since its going to execute an +untrusted kernel anyway, but it will break trusted boot scenarios, where only +signed code is allowed to be executed. + +Signed-off-by: Michael Chang +--- + grub-core/net/efi/net.c | 4 +++- + grub-core/net/http.c | 5 ++++- + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 86bce6535d..4bb308026c 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -645,8 +645,10 @@ grub_efihttp_chunk_read (grub_file_t file, char *buf, + + rd = efi_net_interface (read, file, chunk, sz); + +- if (rd <= 0) ++ if (rd <= 0) { ++ grub_free (chunk); + return rd; ++ } + + if (buf) + { +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 12a2632ea5..b52b558d63 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -31,7 +31,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + enum + { +- HTTP_PORT = 80 ++ HTTP_PORT = 80, ++ HTTP_MAX_CHUNK_SIZE = 0x80000000 + }; + + +@@ -78,6 +79,8 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + if (data->in_chunk_len == 2) + { + data->chunk_rem = grub_strtoul (ptr, 0, 16); ++ if (data->chunk_rem > HTTP_MAX_CHUNK_SIZE) ++ return GRUB_ERR_NET_PACKET_TOO_BIG; + grub_errno = GRUB_ERR_NONE; + if (data->chunk_rem == 0) + { diff --git a/SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch b/SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch new file mode 100644 index 0000000..6e2e4e2 --- /dev/null +++ b/SOURCES/0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 4 Jun 2018 19:49:47 +0200 +Subject: [PATCH] grub-editenv: Add "incr" command to increment integer value + env. variables + +To be able to automatically detect if the last boot was successful, +We want to keep count of succesful / failed boots in some integer +environment variable. + +This commit adds a grub-editenvt "incr" command to increment such +integer value env. variables by 1 for use from various boot scripts. + +Signed-off-by: Hans de Goede +--- + util/grub-editenv.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 50 insertions(+) + +diff --git a/util/grub-editenv.c b/util/grub-editenv.c +index db6f187cc6..948eec8a11 100644 +--- a/util/grub-editenv.c ++++ b/util/grub-editenv.c +@@ -53,6 +53,9 @@ static struct argp_option options[] = { + /* TRANSLATORS: "unset" is a keyword. It's a summary of "unset" subcommand. */ + {N_("unset [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, + N_("Delete variables."), 0}, ++ /* TRANSLATORS: "incr" is a keyword. It's a summary of "incr" subcommand. */ ++ {N_("incr [NAME ...]"), 0, 0, OPTION_DOC|OPTION_NO_USAGE, ++ N_("Increase value of integer variables."), 0}, + + {0, 0, 0, OPTION_DOC, N_("Options:"), -1}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, +@@ -253,6 +256,51 @@ unset_variables (const char *name, int argc, char *argv[]) + grub_envblk_close (envblk); + } + ++struct get_int_value_params { ++ char *varname; ++ int value; ++}; ++ ++static int ++get_int_value (const char *varname, const char *value, void *hook_data) ++{ ++ struct get_int_value_params *params = hook_data; ++ ++ if (strcmp (varname, params->varname) == 0) { ++ params->value = strtol (value, NULL, 10); ++ return 1; ++ } ++ return 0; ++} ++ ++static void ++incr_variables (const char *name, int argc, char *argv[]) ++{ ++ grub_envblk_t envblk; ++ char buf[16]; ++ ++ envblk = open_envblk_file (name); ++ while (argc) ++ { ++ struct get_int_value_params params = { ++ .varname = argv[0], ++ .value = 0, /* Consider unset variables 0 */ ++ }; ++ ++ grub_envblk_iterate (envblk, ¶ms, get_int_value); ++ snprintf(buf, sizeof(buf), "%d", params.value + 1); ++ ++ if (! grub_envblk_set (envblk, argv[0], buf)) ++ grub_util_error ("%s", _("environment block too small")); ++ ++ argc--; ++ argv++; ++ } ++ ++ write_envblk (name, envblk); ++ grub_envblk_close (envblk); ++} ++ + int + main (int argc, char *argv[]) + { +@@ -292,6 +340,8 @@ main (int argc, char *argv[]) + set_variables (filename, argc - curindex, argv + curindex); + else if (strcmp (command, "unset") == 0) + unset_variables (filename, argc - curindex, argv + curindex); ++ else if (strcmp (command, "incr") == 0) ++ incr_variables (filename, argc - curindex, argv + curindex); + else + { + char *program = xstrdup(program_name); diff --git a/SOURCES/0081-Add-auto-hide-menu-support.patch b/SOURCES/0081-Add-auto-hide-menu-support.patch new file mode 100644 index 0000000..a4fbe4a --- /dev/null +++ b/SOURCES/0081-Add-auto-hide-menu-support.patch @@ -0,0 +1,183 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 6 Jun 2018 08:44:11 +0200 +Subject: [PATCH] Add auto-hide menu support + +On single-os systems we do not want to show the menu, unless something +went wrong with the previous boot, in which case the user may need the +menu to debug/fix the problem. + +This commit adds a new grub.d/00_menu_auto_hide file which emits a +config snippet implementing this. I've chosen to do this in a separate +grub.d file because chances of this going upstream are small and this way +it will be easier to rebase. + +Since auto-hiding the menu requires detecting the previous boot was ok, +we get fastboot support (where we don't check for a key at all) for free +so this commit also adds support for this. + +The new config-file code uses the following variables: + +menu_auto_hide Set this to "1" to activate the new auto-hide feature + Set this to "2" to auto-hide the menu even when multiple + operating systems are installed. Note the menu will still + auto show after booting an other os as that won't set + boot_success. +menu_show_once Set this to "1" to force showing the menu once. +boot_success The OS sets this to "1" to indicate a successful boot. +boot_indeterminate The OS increments this integer when rebooting after e.g. + installing updates or a selinux relabel. +fastboot If set to "1" and the conditions for auto-hiding the menu + are met, the menu is not shown and all checks for keypresses + are skipped, booting the default immediately. + +30_os-prober.in changes somewhat inspired by: +https://git.launchpad.net/~ubuntu-core-dev/grub/+git/ubuntu/tree/debian/patches/quick_boot.patch + +Signed-off-by: Hans de Goede +--- + Makefile.util.def | 6 +++++ + util/grub.d/01_menu_auto_hide.in | 48 ++++++++++++++++++++++++++++++++++++++++ + util/grub.d/30_os-prober.in | 18 +++++++++++++++ + 3 files changed, 72 insertions(+) + create mode 100644 util/grub.d/01_menu_auto_hide.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index bda9fd1211..cb8e3c3270 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -458,6 +458,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '01_menu_auto_hide'; ++ common = util/grub.d/01_menu_auto_hide.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '01_users'; + common = util/grub.d/01_users.in; +diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/01_menu_auto_hide.in +new file mode 100644 +index 0000000000..ad175870a5 +--- /dev/null ++++ b/util/grub.d/01_menu_auto_hide.in +@@ -0,0 +1,48 @@ ++#! /bin/sh ++ ++# Disable / skip generating menu-auto-hide config parts on serial terminals ++for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do ++ case "$x" in ++ serial*) ++ exit 0 ++ ;; ++ esac ++done ++ ++cat << EOF ++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then ++ set last_boot_ok=1 ++else ++ set last_boot_ok=0 ++fi ++ ++# Reset boot_indeterminate after a successful boot ++if [ "\${boot_success}" = "1" ] ; then ++ set boot_indeterminate=0 ++# Avoid boot_indeterminate causing the menu to be hidden more then once ++elif [ "\${boot_indeterminate}" = "1" ]; then ++ set boot_indeterminate=2 ++fi ++set boot_success=0 ++save_env boot_success boot_indeterminate ++ ++if [ x\$feature_timeout_style = xy ] ; then ++ if [ "\${menu_show_once}" ]; then ++ unset menu_show_once ++ save_env menu_show_once ++ set timeout_style=menu ++ set timeout=60 ++ elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then ++ set orig_timeout_style=\${timeout_style} ++ set orig_timeout=\${timeout} ++ if [ "\${fastboot}" = "1" ]; then ++ # timeout_style=menu + timeout=0 avoids the countdown code keypress check ++ set timeout_style=menu ++ set timeout=0 ++ else ++ set timeout_style=hidden ++ set timeout=1 ++ fi ++ fi ++fi ++EOF +diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in +index 4b27bd2015..3c9431cfcf 100644 +--- a/util/grub.d/30_os-prober.in ++++ b/util/grub.d/30_os-prober.in +@@ -42,6 +42,7 @@ if [ -z "${OSPROBED}" ] ; then + fi + + osx_entry() { ++ found_other_os=1 + # TRANSLATORS: it refers on the OS residing on device %s + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + hints="" +@@ -102,6 +103,7 @@ for OS in ${OSPROBED} ; do + + case ${BOOT} in + chain) ++ found_other_os=1 + + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF +@@ -132,6 +134,7 @@ EOF + EOF + ;; + efi) ++ found_other_os=1 + + EFIPATH=${DEVICE#*@} + DEVICE=${DEVICE%@*} +@@ -176,6 +179,7 @@ EOF + LINITRD="${LINITRD#/boot}" + fi + ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + recovery_params="$(echo "${LPARAMS}" | grep single)" || true + counter=1 +@@ -257,6 +261,7 @@ EOF + done + ;; + hurd) ++ found_other_os=1 + onstr="$(gettext_printf "(on %s)" "${DEVICE}")" + cat << EOF + menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' { +@@ -283,6 +288,7 @@ EOF + EOF + ;; + minix) ++ found_other_os=1 + cat << EOF + menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { + EOF +@@ -299,3 +305,15 @@ EOF + ;; + esac + done ++ ++# We override the results of the menu_auto_hide code here, this is a bit ugly, ++# but grub-mkconfig writes out the file linearly, so this is the only way ++if [ "${found_other_os}" = "1" ]; then ++ cat << EOF ++# Other OS found, undo autohiding of menu unless menu_auto_hide=2 ++if [ "\${orig_timeout_style}" -a "\${menu_auto_hide}" != "2" ]; then ++ set timeout_style=\${orig_timeout_style} ++ set timeout=\${orig_timeout} ++fi ++EOF ++fi diff --git a/SOURCES/0082-Add-grub-set-bootflag-utility.patch b/SOURCES/0082-Add-grub-set-bootflag-utility.patch new file mode 100644 index 0000000..495bb13 --- /dev/null +++ b/SOURCES/0082-Add-grub-set-bootflag-utility.patch @@ -0,0 +1,290 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 12 Jun 2018 13:25:16 +0200 +Subject: [PATCH] Add grub-set-bootflag utility + +This commit adds a new grub-set-bootflag utility, which can be used +to set known bootflags in the grubenv: boot_success or menu_show_once. + +grub-set-bootflag is different from grub-editenv in 2 ways: + +1) It is intended to be executed by regular users so must be installed +as suid root. As such it is written to not use any existing grubenv +related code for easy auditing. + +It can't be executed through pkexec because we want to call it under gdm +and pkexec does not work under gdm due the gdm user having /sbin/nologin +as shell. + +2) Since it can be executed by regular users it only allows setting +(assigning a value of 1 to) bootflags which it knows about. Currently +those are just boot_success and menu_show_once. + +This commit also adds a couple of example systemd and files which show +how this can be used to set boot_success from a user-session: + +docs/grub-boot-success.service +docs/grub-boot-success.timer + +The 2 grub-boot-success.systemd files should be placed in /lib/systemd/user +and a symlink to grub-boot-success.timer should be added to +/lib/systemd/user/timers.target.wants. + +Signed-off-by: Hans de Goede +[makhomed: grub-boot-success.timer: Only run if not in a container] +Signed-off-by: Gena Makhomed +[rharwood: migrate to h2m] +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 7 ++ + util/grub-set-bootflag.c | 172 +++++++++++++++++++++++++++++++++++++++++ + conf/Makefile.extra-dist | 3 + + docs/grub-boot-success.service | 6 ++ + docs/grub-boot-success.timer | 7 ++ + docs/man/grub-set-bootflag.h2m | 2 + + 6 files changed, 197 insertions(+) + create mode 100644 util/grub-set-bootflag.c + create mode 100644 docs/grub-boot-success.service + create mode 100644 docs/grub-boot-success.timer + create mode 100644 docs/man/grub-set-bootflag.h2m + +diff --git a/Makefile.util.def b/Makefile.util.def +index cb8e3c3270..d066652e9b 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1429,3 +1429,10 @@ program = { + ldadd = grub-core/lib/gnulib/libgnu.a; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; ++ ++program = { ++ name = grub-set-bootflag; ++ installdir = sbin; ++ mansection = 1; ++ common = util/grub-set-bootflag.c; ++}; +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +new file mode 100644 +index 0000000000..d506f7e75b +--- /dev/null ++++ b/util/grub-set-bootflag.c +@@ -0,0 +1,172 @@ ++/* grub-set-bootflag.c - tool to set boot-flags in the grubenv. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2018 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++/* ++ * NOTE this gets run by users as root (through pkexec), so this does not ++ * use any grub library / util functions to allow for easy auditing. ++ * The grub headers are only included to get certain defines. ++ */ ++ ++#include /* For *_DIR_NAME defines */ ++#include ++#include /* For GRUB_ENVBLK_DEFCFG define */ ++#include ++#include ++#include ++#include ++ ++#include "progname.h" ++ ++#define GRUBENV "/" GRUB_BOOT_DIR_NAME "/" GRUB_DIR_NAME "/" GRUB_ENVBLK_DEFCFG ++#define GRUBENV_SIZE 1024 ++ ++const char *bootflags[] = { ++ "boot_success", ++ "menu_show_once", ++ NULL ++}; ++ ++static void usage(FILE *out) ++{ ++ int i; ++ ++ fprintf (out, "Usage: 'grub-set-bootflag ', where is one of:\n"); ++ for (i = 0; bootflags[i]; i++) ++ fprintf (out, " %s\n", bootflags[i]); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ /* NOTE buf must be at least the longest bootflag length + 4 bytes */ ++ char env[GRUBENV_SIZE + 1], buf[64], *s; ++ const char *bootflag; ++ int i, len, ret; ++ FILE *f; ++ ++ if (argc != 2) ++ { ++ usage (stderr); ++ return 1; ++ } ++ else if (!strcmp (argv[1], "--help")) ++ { ++ usage (stdout); ++ return 0; ++ } ++ else if (!strcmp (argv[1], "--version")) ++ { ++ printf ("grub-set-bootflag (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); ++ return 0; ++ } ++ ++ for (i = 0; bootflags[i]; i++) ++ if (!strcmp (argv[1], bootflags[i])) ++ break; ++ if (!bootflags[i]) ++ { ++ fprintf (stderr, "Invalid bootflag: '%s'\n", argv[1]); ++ usage (stderr); ++ return 1; ++ } ++ ++ bootflag = bootflags[i]; ++ len = strlen (bootflag); ++ ++ f = fopen (GRUBENV, "r"); ++ if (!f) ++ { ++ perror ("Error opening " GRUBENV " for reading"); ++ return 1; ++ } ++ ++ ret = fread (env, 1, GRUBENV_SIZE, f); ++ fclose (f); ++ if (ret != GRUBENV_SIZE) ++ { ++ errno = EINVAL; ++ perror ("Error reading from " GRUBENV); ++ return 1; ++ } ++ ++ /* 0 terminate env */ ++ env[GRUBENV_SIZE] = 0; ++ ++ if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE))) ++ { ++ fprintf (stderr, "Error invalid environment block\n"); ++ return 1; ++ } ++ ++ /* Find a pre-existing definition of the bootflag */ ++ s = strstr (env, bootflag); ++ while (s && s[len] != '=') ++ s = strstr (s + len, bootflag); ++ ++ if (s && ((s[len + 1] != '0' && s[len + 1] != '1') || s[len + 2] != '\n')) ++ { ++ fprintf (stderr, "Pre-existing bootflag '%s' has unexpected value\n", bootflag); ++ return 1; ++ } ++ ++ /* No pre-existing bootflag? -> find free space */ ++ if (!s) ++ { ++ for (i = 0; i < (len + 3); i++) ++ buf[i] = '#'; ++ buf[i] = 0; ++ s = strstr (env, buf); ++ } ++ ++ if (!s) ++ { ++ fprintf (stderr, "No space in grubenv to store bootflag '%s'\n", bootflag); ++ return 1; ++ } ++ ++ /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */ ++ snprintf(buf, sizeof(buf), "%s=1\n", bootflag); ++ memcpy(s, buf, len + 3); ++ ++ /* "r+", don't truncate so that the diskspace stays reserved */ ++ f = fopen (GRUBENV, "r+"); ++ if (!f) ++ { ++ perror ("Error opening " GRUBENV " for writing"); ++ return 1; ++ } ++ ++ ret = fwrite (env, 1, GRUBENV_SIZE, f); ++ if (ret != GRUBENV_SIZE) ++ { ++ perror ("Error writing to " GRUBENV); ++ return 1; ++ } ++ ++ ret = fflush (f); ++ if (ret) ++ { ++ perror ("Error flushing " GRUBENV); ++ return 1; ++ } ++ ++ fsync (fileno (f)); ++ fclose (f); ++ ++ return 0; ++} +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 8f1485d52a..ad235de7fc 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -15,6 +15,9 @@ EXTRA_DIST += docs/man + EXTRA_DIST += docs/autoiso.cfg + EXTRA_DIST += docs/grub.cfg + EXTRA_DIST += docs/osdetect.cfg ++EXTRA_DIST += docs/org.gnu.grub.policy ++EXTRA_DIST += docs/grub-boot-success.service ++EXTRA_DIST += docs/grub-boot-success.timer + + EXTRA_DIST += conf/i386-cygwin-img-ld.sc + +diff --git a/docs/grub-boot-success.service b/docs/grub-boot-success.service +new file mode 100644 +index 0000000000..80e79584c9 +--- /dev/null ++++ b/docs/grub-boot-success.service +@@ -0,0 +1,6 @@ ++[Unit] ++Description=Mark boot as successful ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/sbin/grub2-set-bootflag boot_success +diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer +new file mode 100644 +index 0000000000..406f172005 +--- /dev/null ++++ b/docs/grub-boot-success.timer +@@ -0,0 +1,7 @@ ++[Unit] ++Description=Mark boot as successful after the user session has run 2 minutes ++ConditionUser=!@system ++ConditionVirtualization=!container ++ ++[Timer] ++OnActiveSec=2min +diff --git a/docs/man/grub-set-bootflag.h2m b/docs/man/grub-set-bootflag.h2m +new file mode 100644 +index 0000000000..94ec0b92ed +--- /dev/null ++++ b/docs/man/grub-set-bootflag.h2m +@@ -0,0 +1,2 @@ ++[NAME] ++grub-set-bootflag \- set a bootflag in the GRUB environment block diff --git a/SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch b/SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch new file mode 100644 index 0000000..96eff36 --- /dev/null +++ b/SOURCES/0083-docs-Add-grub-boot-indeterminate.service-example.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 19 Jun 2018 15:20:54 +0200 +Subject: [PATCH] docs: Add grub-boot-indeterminate.service example + +This is an example service file, for use from +/lib/systemd/system/system-update.target.wants +to increment the boot_indeterminate variable when +doing offline updates. + +Signed-off-by: Hans de Goede +--- + docs/grub-boot-indeterminate.service | 11 +++++++++++ + 1 file changed, 11 insertions(+) + create mode 100644 docs/grub-boot-indeterminate.service + +diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service +new file mode 100644 +index 0000000000..6c8dcb186b +--- /dev/null ++++ b/docs/grub-boot-indeterminate.service +@@ -0,0 +1,11 @@ ++[Unit] ++Description=Mark boot as indeterminate ++DefaultDependencies=false ++Requires=sysinit.target ++After=sysinit.target ++Wants=system-update-pre.target ++Before=system-update-pre.target ++ ++[Service] ++Type=oneshot ++ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate diff --git a/SOURCES/0084-gentpl-add-disable-support.patch b/SOURCES/0084-gentpl-add-disable-support.patch new file mode 100644 index 0000000..3b305e6 --- /dev/null +++ b/SOURCES/0084-gentpl-add-disable-support.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 11 Jul 2018 13:43:15 -0400 +Subject: [PATCH] gentpl: add 'disable = ' support + +Signed-off-by: Peter Jones +--- + gentpl.py | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/gentpl.py b/gentpl.py +index c86550d4f9..f3c5f84f85 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -592,11 +592,21 @@ def platform_conditional(platform, closure): + # }; + # + def foreach_enabled_platform(defn, closure): ++ enabled = False ++ disabled = False + if 'enable' in defn: ++ enabled = True + for platform in GRUB_PLATFORMS: + if platform_tagged(defn, platform, "enable"): + platform_conditional(platform, closure) +- else: ++ ++ if 'disable' in defn: ++ disabled = True ++ for platform in GRUB_PLATFORMS: ++ if not platform_tagged(defn, platform, "disable"): ++ platform_conditional(platform, closure) ++ ++ if not enabled and not disabled: + for platform in GRUB_PLATFORMS: + platform_conditional(platform, closure) + +@@ -655,6 +665,8 @@ def first_time(defn, snippet): + def is_platform_independent(defn): + if 'enable' in defn: + return False ++ if 'disable' in defn: ++ return False + for suffix in [ "", "_nodist" ]: + template = platform_values(defn, GRUB_PLATFORMS[0], suffix) + for platform in GRUB_PLATFORMS[1:]: diff --git a/SOURCES/0085-gentpl-add-pc-firmware-type.patch b/SOURCES/0085-gentpl-add-pc-firmware-type.patch new file mode 100644 index 0000000..0bfd2ea --- /dev/null +++ b/SOURCES/0085-gentpl-add-pc-firmware-type.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 11:04:24 +0200 +Subject: [PATCH] gentpl: add 'pc' firmware type + +Signed-off-by: Peter Jones +--- + gentpl.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/gentpl.py b/gentpl.py +index f3c5f84f85..f09b336869 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -51,6 +51,7 @@ GROUPS["riscv32"] = [ "riscv32_efi" ] + GROUPS["riscv64"] = [ "riscv64_efi" ] + + # Groups based on firmware ++GROUPS["pc"] = [ "i386_pc" ] + GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", + "riscv32_efi", "riscv64_efi" ] + GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] diff --git a/SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch b/SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch new file mode 100644 index 0000000..a3a9400 --- /dev/null +++ b/SOURCES/0086-efinet-also-use-the-firmware-acceleration-for-http.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 30 Jul 2018 14:06:42 -0400 +Subject: [PATCH] efinet: also use the firmware acceleration for http + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/net.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 4bb308026c..6603cd83ed 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -1324,7 +1324,9 @@ grub_efi_net_boot_from_https (void) + && (subtype == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)) + { + grub_efi_uri_device_path_t *uri_dp = (grub_efi_uri_device_path_t *) dp; +- return (grub_strncmp ((const char*)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0) ? 1 : 0; ++ grub_dprintf ("efinet", "url:%s\n", (const char *)uri_dp->uri); ++ return (grub_strncmp ((const char *)uri_dp->uri, "https://", sizeof ("https://") - 1) == 0 || ++ grub_strncmp ((const char *)uri_dp->uri, "http://", sizeof ("http://") - 1) == 0); + } + + if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp)) diff --git a/SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch b/SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch new file mode 100644 index 0000000..90d9777 --- /dev/null +++ b/SOURCES/0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 30 Jul 2018 16:39:57 -0400 +Subject: [PATCH] efi/http: Make root_url reflect the protocol+hostname of our + boot url. + +This lets you write config files that don't know urls. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/http.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index 3f61fd2fa5..243acbaa35 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + static void + http_configure (struct grub_efi_net_device *dev, int prefer_ip6) +@@ -351,6 +352,24 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + grub_err_t err; + grub_off_t size; + char *buf; ++ char *root_url; ++ grub_efi_ipv6_address_t address; ++ const char *rest; ++ ++ if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0) ++ root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server); ++ else ++ root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server); ++ if (root_url) ++ { ++ grub_env_unset ("root_url"); ++ grub_env_set ("root_url", root_url); ++ grub_free (root_url); ++ } ++ else ++ { ++ return grub_errno; ++ } + + err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); + if (err != GRUB_ERR_NONE) diff --git a/SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch b/SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch new file mode 100644 index 0000000..6d2974f --- /dev/null +++ b/SOURCES/0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 26 Jun 2018 17:16:06 -0400 +Subject: [PATCH] Make it so we can tell configure which cflags utils are built + with + +This lets us have kernel.img be built with TARGET_CFLAGS but grub-mkimage and +friends built with HOST_CFLAGS. That in turn lets us build with an ARM compiler +that only has hard-float ABI versions of crt*.o and libgcc*, but still use soft +float for grub.efi. + +Signed-off-by: Peter Jones +--- + configure.ac | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- + conf/Makefile.common | 23 ++++++++++++----------- + gentpl.py | 8 ++++---- + 3 files changed, 64 insertions(+), 16 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 302300711f..008f6c273b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -849,11 +849,23 @@ if ( test "x$target_cpu" = xi386 || test "x$target_cpu" = xx86_64 ) && test "x$p + TARGET_CFLAGS="$TARGET_CFLAGS -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow" + fi + ++# Should grub utils get the host CFLAGS, or the target CFLAGS? ++AC_ARG_WITH([utils], ++ AS_HELP_STRING([--with-utils=host|target|build], ++ [choose which flags to build utilities with. (default=target)]), ++ [have_with_utils=y], ++ [have_with_utils=n]) ++if test x"$have_with_utils" = xy ; then ++ with_utils="$withval" ++else ++ with_utils=target ++fi ++ + # GRUB doesn't use float or doubles at all. Yet some toolchains may decide + # that floats are a good fit to run instead of what's written in the code. + # Given that floating point unit is disabled (if present to begin with) + # when GRUB is running which may result in various hard crashes. +-if test x"$platform" != xemu ; then ++if test x"$platform" != xemu -a x"$with_utils" == xtarget ; then + AC_CACHE_CHECK([for options to get soft-float], grub_cv_target_cc_soft_float, [ + grub_cv_target_cc_soft_float=no + if test "x$target_cpu" = xarm64; then +@@ -1954,6 +1966,41 @@ HOST_CPPFLAGS="$HOST_CPPFLAGS -I\$(top_builddir)/include" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_srcdir)/include" + TARGET_CPPFLAGS="$TARGET_CPPFLAGS -I\$(top_builddir)/include" + ++case "$with_utils" in ++ host) ++ UTILS_CFLAGS=$HOST_CFLAGS ++ UTILS_CPPFLAGS=$HOST_CPPFLAGS ++ UTILS_CCASFLAGS=$HOST_CCASFLAGS ++ UTILS_LDFLAGS=$HOST_LDFLAGS ++ ;; ++ target) ++ UTILS_CFLAGS=$TARGET_CFLAGS ++ UTILS_CPPFLAGS=$TARGET_CPPFLAGS ++ UTILS_CCASFLAGS=$TARGET_CCASFLAGS ++ UTILS_LDFLAGS=$TARGET_LDFLAGS ++ ;; ++ build) ++ UTILS_CFLAGS=$BUILD_CFLAGS ++ UTILS_CPPFLAGS=$BUILD_CPPFLAGS ++ UTILS_CCASFLAGS=$BUILD_CCASFLAGS ++ UTILS_LDFLAGS=$BUILD_LDFLAGS ++ ;; ++ *) ++ AC_MSG_ERROR([--with-utils must be either host, target, or build]) ++ ;; ++esac ++AC_MSG_NOTICE([Using $with_utils flags for utilities.]) ++ ++unset CFLAGS ++unset CPPFLAGS ++unset CCASFLAGS ++unset LDFLAGS ++ ++AC_SUBST(UTILS_CFLAGS) ++AC_SUBST(UTILS_CPPFLAGS) ++AC_SUBST(UTILS_CCASFLAGS) ++AC_SUBST(UTILS_LDFLAGS) ++ + GRUB_TARGET_CPU="${target_cpu}" + GRUB_PLATFORM="${platform}" + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 5f0ef96985..2ff9b39357 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -40,24 +40,25 @@ CPPFLAGS_KERNEL = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) -DGRUB_KERNEL=1 + CCASFLAGS_KERNEL = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + STRIPFLAGS_KERNEL = -R .eh_frame -R .rel.dyn -R .reginfo -R .note -R .comment -R .drectve -R .note.gnu.gold-version -R .MIPS.abiflags -R .ARM.exidx -R .note.gnu.property -R .gnu.build.attributes + +-CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding +-LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d +-CPPFLAGS_MODULE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) +-CCASFLAGS_MODULE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) ++CFLAGS_MODULE = $(TARGET_CFLAGS) $(CFLAGS_PLATFORM) -ffreestanding ++LDFLAGS_MODULE = $(TARGET_LDFLAGS) $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r,-d ++CPPFLAGS_MODULE = $(TARGET_CPPFLAGS) $(CPPFLAGS_DEFAULT) $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) ++CCASFLAGS_MODULE = $(TARGET_CCASFLAGS) $(CCASFLAGS_DEFAULT) $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + + CFLAGS_IMAGE = $(CFLAGS_PLATFORM) -fno-builtin + LDFLAGS_IMAGE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-S + CPPFLAGS_IMAGE = $(CPPFLAGS_CPU) $(CPPFLAGS_PLATFORM) + CCASFLAGS_IMAGE = $(CCASFLAGS_CPU) $(CCASFLAGS_PLATFORM) + +-CFLAGS_PROGRAM = +-LDFLAGS_PROGRAM = +-CPPFLAGS_PROGRAM = +-CCASFLAGS_PROGRAM = ++CFLAGS_PROGRAM = $(UTILS_CFLAGS) ++LDFLAGS_PROGRAM = $(UTILS_LDFLAGS) ++CPPFLAGS_PROGRAM = $(UTILS_CPPFLAGS) ++CCASFLAGS_PROGRAM = $(UTILS_CCASFLAGS) + +-CFLAGS_LIBRARY = +-CPPFLAGS_LIBRARY = +-CCASFLAGS_LIBRARY = ++CFLAGS_LIBRARY = $(UTILS_CFLAGS) ++LDFLAGS_LIBRARY = $(UTILS_LDFLAGS) ++CPPFLAGS_LIBRARY = $(UTILS_CPPFLAGS) ++CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS) + + # Other variables + +diff --git a/gentpl.py b/gentpl.py +index f09b336869..0e62e14666 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -697,10 +697,10 @@ def module(defn, platform): + var_set(cname(defn) + "_SOURCES", platform_sources(defn, platform) + " ## platform sources") + var_set("nodist_" + cname(defn) + "_SOURCES", platform_nodist_sources(defn, platform) + " ## platform nodist sources") + var_set(cname(defn) + "_LDADD", platform_ldadd(defn, platform)) +- var_set(cname(defn) + "_CFLAGS", "$(AM_CFLAGS) $(CFLAGS_MODULE) " + platform_cflags(defn, platform)) +- var_set(cname(defn) + "_LDFLAGS", "$(AM_LDFLAGS) $(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) +- var_set(cname(defn) + "_CPPFLAGS", "$(AM_CPPFLAGS) $(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) +- var_set(cname(defn) + "_CCASFLAGS", "$(AM_CCASFLAGS) $(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) ++ var_set(cname(defn) + "_CFLAGS", "$(CFLAGS_MODULE) " + platform_cflags(defn, platform)) ++ var_set(cname(defn) + "_LDFLAGS", "$(LDFLAGS_MODULE) " + platform_ldflags(defn, platform)) ++ var_set(cname(defn) + "_CPPFLAGS", "$(CPPFLAGS_MODULE) " + platform_cppflags(defn, platform)) ++ var_set(cname(defn) + "_CCASFLAGS", "$(CCASFLAGS_MODULE) " + platform_ccasflags(defn, platform)) + var_set(cname(defn) + "_DEPENDENCIES", "$(TARGET_OBJ2ELF) " + platform_dependencies(defn, platform)) + + gvar_add("dist_noinst_DATA", extra_dist(defn)) diff --git a/SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch b/SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch new file mode 100644 index 0000000..78c15d6 --- /dev/null +++ b/SOURCES/0089-module-verifier-make-it-possible-to-run-checkers-on-.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 1 Aug 2018 10:24:52 -0400 +Subject: [PATCH] module-verifier: make it possible to run checkers on + grub-module-verifierxx.c + +This makes it so you can treat grub-module-verifierxx.c as a file you can +build directly, so syntax checkers like vim's "syntastic" plugin, which uses +"gcc -x c -fsyntax-only" to build it, will work. + +One still has to do whatever setup is required to make it pick the right +include dirs, which -W options we use, etc., but this makes it so you can do +the checking on the file you're editing, rather than on a different file. + +v2: fix the typo in the #else clause in util/grub-module-verifierXX.c + +Signed-off-by: Peter Jones +--- + util/grub-module-verifier32.c | 2 ++ + util/grub-module-verifier64.c | 2 ++ + util/grub-module-verifierXX.c | 9 +++++++++ + 3 files changed, 13 insertions(+) + +diff --git a/util/grub-module-verifier32.c b/util/grub-module-verifier32.c +index 257229f8f0..ba7d41aafe 100644 +--- a/util/grub-module-verifier32.c ++++ b/util/grub-module-verifier32.c +@@ -1,2 +1,4 @@ + #define MODULEVERIFIER_ELF32 1 ++#ifndef GRUB_MODULE_VERIFIERXX + #include "grub-module-verifierXX.c" ++#endif +diff --git a/util/grub-module-verifier64.c b/util/grub-module-verifier64.c +index 4db6b4bedd..fc23ef800b 100644 +--- a/util/grub-module-verifier64.c ++++ b/util/grub-module-verifier64.c +@@ -1,2 +1,4 @@ + #define MODULEVERIFIER_ELF64 1 ++#ifndef GRUB_MODULE_VERIFIERXX + #include "grub-module-verifierXX.c" ++#endif +diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c +index ceb24309ae..a98e2f9b1a 100644 +--- a/util/grub-module-verifierXX.c ++++ b/util/grub-module-verifierXX.c +@@ -1,3 +1,12 @@ ++#define GRUB_MODULE_VERIFIERXX ++#if !defined(MODULEVERIFIER_ELF32) && !defined(MODULEVERIFIER_ELF64) ++#if __SIZEOF_POINTER__ == 8 ++#include "grub-module-verifier64.c" ++#else ++#include "grub-module-verifier32.c" ++#endif ++#endif ++ + #include + + #include diff --git a/SOURCES/0090-Rework-how-the-fdt-command-builds.patch b/SOURCES/0090-Rework-how-the-fdt-command-builds.patch new file mode 100644 index 0000000..8f41272 --- /dev/null +++ b/SOURCES/0090-Rework-how-the-fdt-command-builds.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 13:01:41 +0200 +Subject: [PATCH] Rework how the fdt command builds. + +Trying to avoid all variants of: +cat syminfo.lst | sort | gawk -f ../../grub-core/genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1) +grub_fdt_install in linux is not defined +grub_fdt_load in linux is not defined +grub_fdt_unload in linux is not defined +grub_fdt_install in xen_boot is not defined +grub_fdt_load in xen_boot is not defined +grub_fdt_unload in xen_boot is not defined + +Signed-off-by: Peter Jones +[javierm: Fix build with platform emu, aarch64, and risc-v] +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 5 ++--- + grub-core/lib/fdt.c | 2 -- + grub-core/loader/efi/fdt.c | 2 ++ + include/grub/fdt.h | 6 ++++++ + grub-core/Makefile.am | 1 + + 5 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 12797336c9..4e7d90da76 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -177,7 +177,6 @@ kernel = { + arm_coreboot = kern/arm/coreboot/init.c; + arm_coreboot = kern/arm/coreboot/timer.c; + arm_coreboot = kern/arm/coreboot/coreboot.S; +- arm_coreboot = lib/fdt.c; + arm_coreboot = bus/fdt.c; + arm_coreboot = term/ps2.c; + arm_coreboot = term/arm/pl050.c; +@@ -351,6 +350,8 @@ kernel = { + riscv64 = kern/riscv/cache_flush.S; + riscv64 = kern/riscv/dl.c; + ++ fdt = lib/fdt.c; ++ + emu = disk/host.c; + emu = kern/emu/cache_s.S; + emu = kern/emu/hostdisk.c; +@@ -1825,7 +1826,6 @@ module = { + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; +- fdt = lib/fdt.c; + + common = loader/linux.c; + common = lib/cmdline.c; +@@ -1837,7 +1837,6 @@ module = { + module = { + name = fdt; + efi = loader/efi/fdt.c; +- common = lib/fdt.c; + enable = fdt; + }; + +diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c +index 0d371c5633..37e04bd69e 100644 +--- a/grub-core/lib/fdt.c ++++ b/grub-core/lib/fdt.c +@@ -21,8 +21,6 @@ + #include + #include + +-GRUB_MOD_LICENSE ("GPLv3+"); +- + #define FDT_SUPPORTED_VERSION 17 + + #define FDT_BEGIN_NODE 0x00000001 +diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c +index c86f283d75..c572415d38 100644 +--- a/grub-core/loader/efi/fdt.c ++++ b/grub-core/loader/efi/fdt.c +@@ -27,6 +27,8 @@ + #include + #include + ++GRUB_MOD_LICENSE ("GPLv3+"); ++ + static void *loaded_fdt; + static void *fdt; + +diff --git a/include/grub/fdt.h b/include/grub/fdt.h +index e609c7e411..3514aa4a5b 100644 +--- a/include/grub/fdt.h ++++ b/include/grub/fdt.h +@@ -19,6 +19,9 @@ + #ifndef GRUB_FDT_HEADER + #define GRUB_FDT_HEADER 1 + ++#if !defined(GRUB_MACHINE_EMU) && \ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) ++ + #include + #include + +@@ -144,4 +147,7 @@ int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const ch + grub_fdt_set_prop ((fdt), (nodeoffset), "reg", reg_64, 16); \ + }) + ++#endif /* !defined(GRUB_MACHINE_EMU) && \ ++ (defined(__arm__) || defined(__aarch64__) || defined(__riscv)) */ ++ + #endif /* ! GRUB_FDT_HEADER */ +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index bfd29a3bf0..c2e8a82bce 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -76,6 +76,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/sb.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/env_private.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/err.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fdt.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/file.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/fs.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/i18n.h diff --git a/SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch b/SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch new file mode 100644 index 0000000..ea09b65 --- /dev/null +++ b/SOURCES/0091-Disable-non-wordsize-allocations-on-arm.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 2 Aug 2018 10:56:38 -0400 +Subject: [PATCH] Disable non-wordsize allocations on arm + +Signed-off-by: Peter Jones +--- + configure.ac | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 008f6c273b..54462e0892 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1260,6 +1260,26 @@ if test "x$target_cpu" = xarm; then + done + ]) + ++ AC_CACHE_CHECK([for options to disable movt and movw relocations], ++ grub_cv_target_cc_mword_relocations, ++ [grub_cv_target_cc_mword_relocations=no ++ for cand in "-mword-relocations" ; do ++ if test x"$grub_cv_target_cc_mword_relocations" != xno ; then ++ break ++ fi ++ CFLAGS="$TARGET_CFLAGS $cand -Werror" ++ CPPFLAGS="$TARGET_CPPFLAGS" ++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], ++ [grub_cv_target_cc_mword_relocations="$cand"], ++ []) ++ done ++ ]) ++ if test x"$grub_cv_target_cc_mword_relocations" = xno ; then ++ AC_MSG_ERROR(["your compiler doesn't support disabling movw/movt relocations"]) ++ else ++ TARGET_CFLAGS="$TARGET_CFLAGS $grub_cv_target_cc_mword_relocations" ++ fi ++ + if test x"$grub_cv_target_cc_mno_movt" != xno ; then + # A trick so that clang doesn't see it on link stage + TARGET_CPPFLAGS="$TARGET_CPPFLAGS $grub_cv_target_cc_mno_movt" diff --git a/SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch b/SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch new file mode 100644 index 0000000..30d8075 --- /dev/null +++ b/SOURCES/0092-Prepend-prefix-when-HTTP-path-is-relative.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stephen Benjamin +Date: Thu, 16 Aug 2018 16:58:51 -0400 +Subject: [PATCH] Prepend prefix when HTTP path is relative + +This sets a couple of variables. With the url http://www.example.com/foo/bar : +http_path: /foo/bar +http_url: http://www.example.com/foo/bar + +Signed-off-by: Peter Jones +Signed-off-by: Stephen Benjamin +Signed-off-by: Robbie Harwood +--- + grub-core/kern/main.c | 10 +++++- + grub-core/net/efi/http.c | 82 ++++++++++++++++++++++++++++++++++++------------ + 2 files changed, 71 insertions(+), 21 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index d1de9fa687..1c540fc8c2 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -131,11 +131,19 @@ grub_set_prefix_and_root (void) + if (fwdevice && fwpath) + { + char *fw_path; ++ char separator[3] = ")"; + +- fw_path = grub_xasprintf ("(%s)/%s", fwdevice, fwpath); ++ grub_dprintf ("fw_path", "\n"); ++ grub_dprintf ("fw_path", "fwdevice:\"%s\" fwpath:\"%s\"\n", fwdevice, fwpath); ++ ++ if (!grub_strncmp(fwdevice, "http", 4) && fwpath[0] != '/') ++ grub_strcpy(separator, ")/"); ++ ++ fw_path = grub_xasprintf ("(%s%s%s", fwdevice, separator, fwpath); + if (fw_path) + { + grub_env_set ("fw_path", fw_path); ++ grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); + grub_free (fw_path); + } + } +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index 243acbaa35..de351b2cd0 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -9,10 +9,52 @@ + static void + http_configure (struct grub_efi_net_device *dev, int prefer_ip6) + { ++ grub_efi_ipv6_address_t address; + grub_efi_http_config_data_t http_config; + grub_efi_httpv4_access_point_t httpv4_node; + grub_efi_httpv6_access_point_t httpv6_node; + grub_efi_status_t status; ++ int https; ++ char *http_url; ++ const char *rest, *http_server, *http_path = NULL; ++ ++ http_server = grub_env_get ("root"); ++ https = (grub_strncmp (http_server, "https", 5) == 0) ? 1 : 0; ++ ++ /* extract http server + port */ ++ if (http_server) ++ { ++ http_server = grub_strchr (http_server, ','); ++ if (http_server) ++ http_server++; ++ } ++ ++ /* fw_path is like (http,192.168.1.1:8000)/httpboot, extract path part */ ++ http_path = grub_env_get ("fw_path"); ++ if (http_path) ++ { ++ http_path = grub_strchr (http_path, ')'); ++ if (http_path) ++ { ++ http_path++; ++ grub_env_unset ("http_path"); ++ grub_env_set ("http_path", http_path); ++ } ++ } ++ ++ if (http_server && http_path) ++ { ++ if (grub_efi_string_to_ip6_address (http_server, &address, &rest) && *rest == 0) ++ http_url = grub_xasprintf ("%s://[%s]%s", https ? "https" : "http", http_server, http_path); ++ else ++ http_url = grub_xasprintf ("%s://%s%s", https ? "https" : "http", http_server, http_path); ++ if (http_url) ++ { ++ grub_env_unset ("http_url"); ++ grub_env_set ("http_url", http_url); ++ grub_free (http_url); ++ } ++ } + + grub_efi_http_t *http = dev->http; + +@@ -352,32 +394,32 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + grub_err_t err; + grub_off_t size; + char *buf; +- char *root_url; +- grub_efi_ipv6_address_t address; +- const char *rest; ++ char *file_name = NULL; ++ const char *http_path; + +- if (grub_efi_string_to_ip6_address (file->device->net->server, &address, &rest) && *rest == 0) +- root_url = grub_xasprintf ("%s://[%s]", type ? "https" : "http", file->device->net->server); +- else +- root_url = grub_xasprintf ("%s://%s", type ? "https" : "http", file->device->net->server); +- if (root_url) +- { +- grub_env_unset ("root_url"); +- grub_env_set ("root_url", root_url); +- grub_free (root_url); +- } +- else +- { ++ /* If path is relative, prepend http_path */ ++ http_path = grub_env_get ("http_path"); ++ if (http_path && file->device->net->name[0] != '/') { ++ file_name = grub_xasprintf ("%s/%s", http_path, file->device->net->name); ++ if (!file_name) + return grub_errno; +- } ++ } + +- err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 1, 0); ++ err = efihttp_request (dev->http, file->device->net->server, ++ file_name ? file_name : file->device->net->name, type, 1, 0); + if (err != GRUB_ERR_NONE) +- return err; ++ { ++ grub_free (file_name); ++ return err; ++ } + +- err = efihttp_request (dev->http, file->device->net->server, file->device->net->name, type, 0, &size); ++ err = efihttp_request (dev->http, file->device->net->server, ++ file_name ? file_name : file->device->net->name, type, 0, &size); ++ grub_free (file_name); + if (err != GRUB_ERR_NONE) +- return err; ++ { ++ return err; ++ } + + buf = grub_malloc (size); + efihttp_read (dev, buf, size); diff --git a/SOURCES/0093-Make-grub_error-more-verbose.patch b/SOURCES/0093-Make-grub_error-more-verbose.patch new file mode 100644 index 0000000..306a3d3 --- /dev/null +++ b/SOURCES/0093-Make-grub_error-more-verbose.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 27 Aug 2018 13:14:06 -0400 +Subject: [PATCH] Make grub_error() more verbose + +Signed-off-by: Peter Jones +--- + grub-core/kern/err.c | 13 +++++++++++-- + include/grub/err.h | 8 ++++++-- + 2 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/err.c b/grub-core/kern/err.c +index 53c734de70..aebfe0cf83 100644 +--- a/grub-core/kern/err.c ++++ b/grub-core/kern/err.c +@@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE]; + static int grub_error_stack_pos; + static int grub_error_stack_assert; + ++#ifdef grub_error ++#undef grub_error ++#endif ++ + grub_err_t +-grub_error (grub_err_t n, const char *fmt, ...) ++grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...) + { + va_list ap; ++ int m; + + grub_errno = n; + ++ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line); ++ if (m < 0) ++ m = 0; ++ + va_start (ap, fmt); +- grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap); ++ grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap); + va_end (ap); + + return n; +diff --git a/include/grub/err.h b/include/grub/err.h +index b08d5d0de4..c0f90ef07c 100644 +--- a/include/grub/err.h ++++ b/include/grub/err.h +@@ -85,8 +85,12 @@ struct grub_error_saved + extern grub_err_t EXPORT_VAR(grub_errno); + extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG]; + +-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...) +- __attribute__ ((format (GNU_PRINTF, 2, 3))); ++grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...) ++ __attribute__ ((format (GNU_PRINTF, 4, 5))); ++ ++#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__) ++ ++ + void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn)); + void EXPORT_FUNC(grub_error_push) (void); + int EXPORT_FUNC(grub_error_pop) (void); diff --git a/SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch b/SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch new file mode 100644 index 0000000..22475d6 --- /dev/null +++ b/SOURCES/0094-Make-reset-an-alias-for-the-reboot-command.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 31 Aug 2018 16:42:03 -0400 +Subject: [PATCH] Make "reset" an alias for the "reboot" command. + +I'm really tired of half the tools I get to use having one and the other half +having the other. + +Signed-off-by: Peter Jones +--- + grub-core/commands/reboot.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/reboot.c b/grub-core/commands/reboot.c +index 46d364c99a..f5cc228363 100644 +--- a/grub-core/commands/reboot.c ++++ b/grub-core/commands/reboot.c +@@ -32,15 +32,18 @@ grub_cmd_reboot (grub_command_t cmd __attribute__ ((unused)), + grub_reboot (); + } + +-static grub_command_t cmd; ++static grub_command_t reboot_cmd, reset_cmd; + + GRUB_MOD_INIT(reboot) + { +- cmd = grub_register_command ("reboot", grub_cmd_reboot, +- 0, N_("Reboot the computer.")); ++ reboot_cmd = grub_register_command ("reboot", grub_cmd_reboot, ++ 0, N_("Reboot the computer.")); ++ reset_cmd = grub_register_command ("reset", grub_cmd_reboot, ++ 0, N_("Reboot the computer.")); + } + + GRUB_MOD_FINI(reboot) + { +- grub_unregister_command (cmd); ++ grub_unregister_command (reboot_cmd); ++ grub_unregister_command (reset_cmd); + } diff --git a/SOURCES/0095-Add-a-version-command.patch b/SOURCES/0095-Add-a-version-command.patch new file mode 100644 index 0000000..18c355c --- /dev/null +++ b/SOURCES/0095-Add-a-version-command.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Sep 2018 14:20:37 -0400 +Subject: [PATCH] Add a "version" command + +This adds a command that shows you info about grub's version, the grub +target platform, the compiler version, and if you built with +--with-rpm-version=, the rpm package version. + +Signed-off-by: Peter Jones +[rharwood: don't say GNU, commit message cleanup] +Signed-off-by: Robbie Harwood +--- + configure.ac | 13 ++++++++++ + grub-core/Makefile.core.def | 5 ++++ + grub-core/commands/version.c | 56 ++++++++++++++++++++++++++++++++++++++++++++ + config.h.in | 1 + + 4 files changed, 75 insertions(+) + create mode 100644 grub-core/commands/version.c + +diff --git a/configure.ac b/configure.ac +index 54462e0892..7b4e1854d3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -284,6 +284,19 @@ AC_SUBST(target_cpu) + AC_SUBST(platform) + + # Define default variables ++have_with_rpm_version=n ++AC_ARG_WITH([rpm_version], ++ AS_HELP_STRING([--with-rpm-version=VERSION], ++ [set the rpm package version [[guessed]]]), ++ [have_with_rpm_version=y], ++ [have_with_rpm_version=n]) ++if test x$have_with_rpm_version = xy; then ++ rpm_version="$with_rpm_version" ++else ++ rpm_version="" ++fi ++GRUB_RPM_VERSION="$rpm_version" ++AC_SUBST(GRUB_RPM_VERSION) + + have_with_bootdir=n + AC_ARG_WITH([bootdir], +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 4e7d90da76..4f203533f5 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -579,6 +579,11 @@ image = { + enable = mips_loongson; + }; + ++module = { ++ name = version; ++ common = commands/version.c; ++}; ++ + module = { + name = disk; + common = lib/disk.c; +diff --git a/grub-core/commands/version.c b/grub-core/commands/version.c +new file mode 100644 +index 0000000000..de0acb07ba +--- /dev/null ++++ b/grub-core/commands/version.c +@@ -0,0 +1,56 @@ ++/* version.c - Command to print the grub version and build info. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_err_t ++grub_cmd_version (grub_command_t cmd UNUSED, int argc, char **args UNUSED) ++{ ++ if (argc != 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("no arguments expected")); ++ ++ grub_printf (_("GRUB version %s\n"), PACKAGE_VERSION); ++ grub_printf (_("Platform %s-%s\n"), GRUB_TARGET_CPU, GRUB_PLATFORM); ++ if (grub_strlen(GRUB_RPM_VERSION) != 0) ++ grub_printf (_("RPM package version %s\n"), GRUB_RPM_VERSION); ++ grub_printf (_("Compiler version %s\n"), __VERSION__); ++ ++ return 0; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(version) ++{ ++ cmd = grub_register_command ("version", grub_cmd_version, NULL, ++ N_("Print version and build information.")); ++} ++ ++GRUB_MOD_FINI(version) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/config.h.in b/config.h.in +index 9e8f9911b1..c7e316f0f1 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -59,6 +59,7 @@ + + #define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" + #define GRUB_PLATFORM "@GRUB_PLATFORM@" ++#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" + + #define RE_ENABLE_I18N 1 + diff --git a/SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch b/SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch new file mode 100644 index 0000000..72c8d30 --- /dev/null +++ b/SOURCES/0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Sep 2018 15:58:29 -0400 +Subject: [PATCH] Add more dprintf, and nerf dprintf in script.c + +Signed-off-by: Peter Jones +--- + grub-core/disk/diskfilter.c | 3 +++ + grub-core/disk/efi/efidisk.c | 1 + + grub-core/kern/device.c | 1 + + grub-core/script/script.c | 5 +++++ + 4 files changed, 10 insertions(+) + +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index 0320115662..7cdffe3ebd 100644 +--- a/grub-core/disk/diskfilter.c ++++ b/grub-core/disk/diskfilter.c +@@ -188,6 +188,8 @@ scan_disk (const char *name, int accept_diskfilter) + grub_disk_t disk; + static int scan_depth = 0; + ++ grub_dprintf ("diskfilter", "scanning %s\n", name); ++ + if (!accept_diskfilter && is_valid_diskfilter_name (name)) + return 0; + +@@ -1212,6 +1214,7 @@ insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id, + the same. */ + if (pv->disk && grub_disk_native_sectors (disk) >= pv->part_size) + return GRUB_ERR_NONE; ++ grub_dprintf ("diskfilter", "checking %s\n", disk->name); + pv->disk = grub_disk_open (disk->name); + if (!pv->disk) + return grub_errno; +diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c +index f077b5f553..fe8ba6e6c9 100644 +--- a/grub-core/disk/efi/efidisk.c ++++ b/grub-core/disk/efi/efidisk.c +@@ -855,6 +855,7 @@ grub_efidisk_get_device_name (grub_efi_handle_t *handle) + return 0; + } + ++ grub_dprintf ("efidisk", "getting disk for %s\n", device_name); + parent = grub_disk_open (device_name); + grub_free (dup_dp); + +diff --git a/grub-core/kern/device.c b/grub-core/kern/device.c +index 73b8ecc0c0..f58b58c89d 100644 +--- a/grub-core/kern/device.c ++++ b/grub-core/kern/device.c +@@ -34,6 +34,7 @@ grub_device_open (const char *name) + { + grub_device_t dev = 0; + ++ grub_dprintf ("device", "opening device %s\n", name); + if (! name) + { + name = grub_env_get ("root"); +diff --git a/grub-core/script/script.c b/grub-core/script/script.c +index ec4d4337c6..844e8343ca 100644 +--- a/grub-core/script/script.c ++++ b/grub-core/script/script.c +@@ -22,6 +22,11 @@ + #include + #include + ++#ifdef grub_dprintf ++#undef grub_dprintf ++#endif ++#define grub_dprintf(no, fmt, ...) ++ + /* It is not possible to deallocate the memory when a syntax error was + found. Because of that it is required to keep track of all memory + allocations. The memory is freed in case of an error, or assigned diff --git a/SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch b/SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch new file mode 100644 index 0000000..57d937c --- /dev/null +++ b/SOURCES/0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch @@ -0,0 +1,279 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 14:38:57 +0200 +Subject: [PATCH] arm/arm64 loader: Better memory allocation and error + messages. + +On mustang, our memory map looks like: + +Type Physical start - end #Pages Size Attributes +reserved 0000004000000000-00000040001fffff 00000200 2MiB UC WC WT WB +conv-mem 0000004000200000-0000004393ffffff 00393e00 14654MiB UC WC WT WB +ldr-code 0000004394000000-00000043f7ffffff 00064000 1600MiB UC WC WT WB +BS-data 00000043f8000000-00000043f801ffff 00000020 128KiB UC WC WT WB +conv-mem 00000043f8020000-00000043fa15bfff 0000213c 34032KiB UC WC WT WB +ldr-code 00000043fa15c000-00000043fa2a1fff 00000146 1304KiB UC WC WT WB +ldr-data 00000043fa2a2000-00000043fa3e8fff 00000147 1308KiB UC WC WT WB +conv-mem 00000043fa3e9000-00000043fa3e9fff 00000001 4KiB UC WC WT WB +ldr-data 00000043fa3ea000-00000043fa3eafff 00000001 4KiB UC WC WT WB +ldr-code 00000043fa3eb000-00000043fa4affff 000000c5 788KiB UC WC WT WB +BS-code 00000043fa4b0000-00000043fa59ffff 000000f0 960KiB UC WC WT WB +RT-code 00000043fa5a0000-00000043fa5affff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa5b0000-00000043fa5bffff 00000010 64KiB RT UC WC WT WB +RT-code 00000043fa5c0000-00000043fa5cffff 00000010 64KiB RT UC WC WT WB +ldr-data 00000043fa5d0000-00000043fa5d0fff 00000001 4KiB UC WC WT WB +BS-code 00000043fa5d1000-00000043fa5ddfff 0000000d 52KiB UC WC WT WB +reserved 00000043fa5de000-00000043fa60ffff 00000032 200KiB UC WC WT WB +ACPI-rec 00000043fa610000-00000043fa6affff 000000a0 640KiB UC WC WT WB +ACPI-nvs 00000043fa6b0000-00000043fa6bffff 00000010 64KiB UC WC WT WB +ACPI-rec 00000043fa6c0000-00000043fa70ffff 00000050 320KiB UC WC WT WB +RT-code 00000043fa710000-00000043fa72ffff 00000020 128KiB RT UC WC WT WB +RT-data 00000043fa730000-00000043fa78ffff 00000060 384KiB RT UC WC WT WB +RT-code 00000043fa790000-00000043fa79ffff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa7a0000-00000043fa99ffff 00000200 2MiB RT UC WC WT WB +RT-code 00000043fa9a0000-00000043fa9affff 00000010 64KiB RT UC WC WT WB +RT-data 00000043fa9b0000-00000043fa9cffff 00000020 128KiB RT UC WC WT WB +BS-code 00000043fa9d0000-00000043fa9d9fff 0000000a 40KiB UC WC WT WB +reserved 00000043fa9da000-00000043fa9dbfff 00000002 8KiB UC WC WT WB +conv-mem 00000043fa9dc000-00000043fc29dfff 000018c2 25352KiB UC WC WT WB +BS-data 00000043fc29e000-00000043fc78afff 000004ed 5044KiB UC WC WT WB +conv-mem 00000043fc78b000-00000043fca01fff 00000277 2524KiB UC WC WT WB +BS-data 00000043fca02000-00000043fcea3fff 000004a2 4744KiB UC WC WT WB +conv-mem 00000043fcea4000-00000043fcea4fff 00000001 4KiB UC WC WT WB +BS-data 00000043fcea5000-00000043fd192fff 000002ee 3000KiB UC WC WT WB +conv-mem 00000043fd193000-00000043fd2b0fff 0000011e 1144KiB UC WC WT WB +BS-data 00000043fd2b1000-00000043ff80ffff 0000255f 38268KiB UC WC WT WB +BS-code 00000043ff810000-00000043ff99ffff 00000190 1600KiB UC WC WT WB +RT-code 00000043ff9a0000-00000043ff9affff 00000010 64KiB RT UC WC WT WB +conv-mem 00000043ff9b0000-00000043ff9bffff 00000010 64KiB UC WC WT WB +RT-data 00000043ff9c0000-00000043ff9effff 00000030 192KiB RT UC WC WT WB +conv-mem 00000043ff9f0000-00000043ffa05fff 00000016 88KiB UC WC WT WB +BS-data 00000043ffa06000-00000043ffffffff 000005fa 6120KiB UC WC WT WB +MMIO 0000000010510000-0000000010510fff 00000001 4KiB RT +MMIO 0000000010548000-0000000010549fff 00000002 8KiB RT +MMIO 0000000017000000-0000000017001fff 00000002 8KiB RT +MMIO 000000001c025000-000000001c025fff 00000001 4KiB RT + +This patch adds a requirement when we're trying to find the base of ram, that +the memory we choose is actually /allocatable/ conventional memory, not merely +write-combining. On this machine that means we wind up with an allocation +around 0x4392XXXXXX, which is a reasonable address. + +This also changes grub_efi_allocate_pages_real() so that if 0 is allocated, it +tries to allocate again starting with the same max address it did the first +time, rather than interposing GRUB_EFI_MAX_USABLE_ADDRESS there, so that any +per-platform constraints on its given address are maintained. + +Signed-off-by: Peter Jones +--- + grub-core/kern/efi/mm.c | 33 +++++++++++++++----- + grub-core/loader/arm64/linux.c | 68 +++++++++++++++++++++++++++++++----------- + 2 files changed, 76 insertions(+), 25 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index f6aef0ef64..85ad4b4494 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -154,6 +154,7 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + { + grub_efi_status_t status; + grub_efi_boot_services_t *b; ++ grub_efi_physical_address_t ret = address; + + /* Limit the memory access to less than 4GB for 32-bit platforms. */ + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) +@@ -170,19 +171,22 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + + b = grub_efi_system_table->boot_services; +- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); ++ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + if (status != GRUB_EFI_SUCCESS) + { ++ grub_dprintf ("efi", ++ "allocate_pages(%d, %d, 0x%0lx, 0x%016lx) = 0x%016lx\n", ++ alloctype, memtype, pages, address, status); + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + return NULL; + } + +- if (address == 0) ++ if (ret == 0) + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ +- address = GRUB_EFI_MAX_USABLE_ADDRESS; +- status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &address); ++ ret = address; ++ status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) + { +@@ -191,9 +195,9 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + } + } + +- grub_efi_store_alloc (address, pages); ++ grub_efi_store_alloc (ret, pages); + +- return (void *) ((grub_addr_t) address); ++ return (void *) ((grub_addr_t) ret); + } + + void * +@@ -713,8 +717,21 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS; + (grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- if (desc->attribute & GRUB_EFI_MEMORY_WB) +- *base_addr = grub_min (*base_addr, desc->physical_start); ++ { ++ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY && ++ (desc->attribute & GRUB_EFI_MEMORY_WB)) ++ { ++ *base_addr = grub_min (*base_addr, desc->physical_start); ++ grub_dprintf ("efi", "setting base_addr=0x%016lx\n", *base_addr); ++ } ++ else ++ { ++ grub_dprintf ("efi", "ignoring address 0x%016lx\n", desc->physical_start); ++ } ++ } ++ ++ if (*base_addr == GRUB_EFI_MAX_USABLE_ADDRESS) ++ grub_dprintf ("efi", "base_addr 0x%016lx is probably wrong.\n", *base_addr); + + grub_free(memory_map); + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 04994d5c67..70a0075ec5 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -71,20 +71,25 @@ finalize_params_linux (void) + { + grub_efi_loaded_image_t *loaded_image = NULL; + int node, retval, len; +- ++ grub_err_t err = GRUB_ERR_NONE; + void *fdt; + + fdt = grub_fdt_load (GRUB_EFI_LINUX_FDT_EXTRA_SPACE); +- + if (!fdt) +- goto failure; ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to load FDT"); ++ goto failure; ++ } + + node = grub_fdt_find_subnode (fdt, 0, "chosen"); + if (node < 0) + node = grub_fdt_add_subnode (fdt, 0, "chosen"); + + if (node < 1) +- goto failure; ++ { ++ err = grub_error(grub_errno, "failed to load chosen fdt node."); ++ goto failure; ++ } + + /* Set initrd info */ + if (initrd_start && initrd_end > initrd_start) +@@ -95,15 +100,26 @@ finalize_params_linux (void) + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-start", + initrd_start); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-start property"); ++ goto failure; ++ } ++ + retval = grub_fdt_set_prop64 (fdt, node, "linux,initrd-end", + initrd_end); + if (retval) +- goto failure; ++ { ++ err = grub_error(retval, "Failed to set linux,initrd-end property"); ++ goto failure; ++ } + } + +- if (grub_fdt_install() != GRUB_ERR_NONE) +- goto failure; ++ retval = grub_fdt_install(); ++ if (retval != GRUB_ERR_NONE) ++ { ++ err = grub_error(retval, "Failed to install fdt"); ++ goto failure; ++ } + + grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n", + fdt); +@@ -111,14 +127,20 @@ finalize_params_linux (void) + /* Convert command line to UCS-2 */ + loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (!loaded_image) +- goto failure; ++ { ++ err = grub_error(grub_errno, "Failed to install fdt"); ++ goto failure; ++ } + + loaded_image->load_options_size = len = + (grub_strlen (linux_args) + 1) * sizeof (grub_efi_char16_t); + loaded_image->load_options = + grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (loaded_image->load_options_size)); + if (!loaded_image->load_options) +- return grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ { ++ err = grub_error(GRUB_ERR_BAD_OS, "failed to create kernel parameters"); ++ goto failure; ++ } + + loaded_image->load_options_size = + 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, +@@ -128,7 +150,7 @@ finalize_params_linux (void) + + failure: + grub_fdt_unload(); +- return grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"); ++ return err; + } + + static void +@@ -212,16 +234,28 @@ grub_linux_unload (void) + static void * + allocate_initrd_mem (int initrd_pages) + { +- grub_addr_t max_addr; ++ grub_addr_t max_addr = 0; ++ grub_err_t err; ++ void *ret; + +- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) +- return NULL; ++ err = grub_efi_get_ram_base (&max_addr); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_error (err, "grub_efi_get_ram_base() failed"); ++ return NULL; ++ } ++ ++ grub_dprintf ("linux", "max_addr: 0x%016lx, INITRD_MAX_ADDRESS_OFFSET: 0x%016llx\n", ++ max_addr, INITRD_MAX_ADDRESS_OFFSET); + + max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; ++ grub_dprintf ("linux", "calling grub_efi_allocate_pages_real (0x%016lx, 0x%08x, EFI_ALLOCATE_MAX_ADDRESS, EFI_LOADER_DATA)", max_addr, initrd_pages); + +- return grub_efi_allocate_pages_real (max_addr, initrd_pages, +- GRUB_EFI_ALLOCATE_MAX_ADDRESS, +- GRUB_EFI_LOADER_DATA); ++ ret = grub_efi_allocate_pages_real (max_addr, initrd_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_DATA); ++ grub_dprintf ("linux", "got 0x%016llx\n", (unsigned long long)ret); ++ return ret; + } + + static grub_err_t diff --git a/SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch b/SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch new file mode 100644 index 0000000..4f42ea5 --- /dev/null +++ b/SOURCES/0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch @@ -0,0 +1,211 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 17:17:02 +0200 +Subject: [PATCH] Try to pick better locations for kernel and initrd + +- Don't limit allocations on 64-bit platforms to < 0x[37f]fffffff if + we're using the "large" code model ; use __UINTPTR_MAX__. +- Get the comparison right to check the address we've allocated. +- Fix the allocation for the command line as well. + +*But*, when we did this some systems started failing badly; coudln't +parse partition tables, etc. What's going on here is the disk controller +is silently failing DMAs to addresses above 4GB, so we're trying to parse +uninitialized (or HW zeroed) ram when looking for the partition table, +etc. + +So to limit this, we make grub_malloc() pick addresses below 4GB on +x86_64, but the direct EFI page allocation functions can get addresses +above that. + +Additionally, we now try to locate kernel+initrd+cmdline+etc below +0x7fffffff, and if they're too big to fit any memory window there, then +we try a higher address. + +Signed-off-by: Peter Jones +[david.abdurachmanov: fix macro for riscv64] +Signed-off-by: David Abdurachmanov +Signed-off-by: Robbie Harwood +--- + grub-core/kern/efi/mm.c | 8 ++++---- + grub-core/loader/i386/efi/linux.c | 24 +++++++++++++++++------- + include/grub/arm/efi/memory.h | 1 + + include/grub/arm64/efi/memory.h | 1 + + include/grub/i386/efi/memory.h | 1 + + include/grub/ia64/efi/memory.h | 1 + + include/grub/riscv64/efi/memory.h | 1 + + include/grub/x86_64/efi/memory.h | 4 +++- + 8 files changed, 29 insertions(+), 12 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 85ad4b4494..e84961d078 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -122,7 +122,7 @@ grub_efi_allocate_pages_max (grub_efi_physical_address_t max, + grub_efi_boot_services_t *b; + grub_efi_physical_address_t address = max; + +- if (max > 0xffffffff) ++ if (max > GRUB_EFI_MAX_USABLE_ADDRESS) + return 0; + + b = grub_efi_system_table->boot_services; +@@ -480,7 +480,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY + #if 1 +- && desc->physical_start <= GRUB_EFI_MAX_USABLE_ADDRESS ++ && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 + && desc->num_pages != 0) +@@ -498,9 +498,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + #if 1 + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages +- > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS)) ++ > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) + filtered_desc->num_pages +- = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_USABLE_ADDRESS) ++ = (BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS) + - BYTES_TO_PAGES (filtered_desc->physical_start)); + #endif + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3017d0f3e5..33e981e76e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -106,7 +107,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(size)); ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); ++ if (!initrd_mem) ++ initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); + if (!initrd_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +@@ -202,8 +205,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (0x3fffffff, ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); + if (! params) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +@@ -273,8 +279,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + #endif + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ if (!linux_cmdline) ++ linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(lh->cmdline_size + 1)); + if (!linux_cmdline) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +@@ -301,11 +310,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(lh->init_size)); ++ if (!kernel_mem) ++ kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, + BYTES_TO_PAGES(lh->init_size)); +- + if (!kernel_mem) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +diff --git a/include/grub/arm/efi/memory.h b/include/grub/arm/efi/memory.h +index 2c64918e3f..a4c2ec8350 100644 +--- a/include/grub/arm/efi/memory.h ++++ b/include/grub/arm/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h +index c6cb324171..acb61dca44 100644 +--- a/include/grub/arm64/efi/memory.h ++++ b/include/grub/arm64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/i386/efi/memory.h b/include/grub/i386/efi/memory.h +index 2c64918e3f..a4c2ec8350 100644 +--- a/include/grub/i386/efi/memory.h ++++ b/include/grub/i386/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/ia64/efi/memory.h b/include/grub/ia64/efi/memory.h +index 2c64918e3f..a4c2ec8350 100644 +--- a/include/grub/ia64/efi/memory.h ++++ b/include/grub/ia64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/riscv64/efi/memory.h b/include/grub/riscv64/efi/memory.h +index c6cb324171..acb61dca44 100644 +--- a/include/grub/riscv64/efi/memory.h ++++ b/include/grub/riscv64/efi/memory.h +@@ -2,5 +2,6 @@ + #include + + #define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffffffffULL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/x86_64/efi/memory.h b/include/grub/x86_64/efi/memory.h +index 46e9145a30..e81cfb3221 100644 +--- a/include/grub/x86_64/efi/memory.h ++++ b/include/grub/x86_64/efi/memory.h +@@ -2,9 +2,11 @@ + #include + + #if defined (__code_model_large__) +-#define GRUB_EFI_MAX_USABLE_ADDRESS 0xffffffff ++#define GRUB_EFI_MAX_USABLE_ADDRESS __UINTPTR_MAX__ ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS 0x7fffffff + #else + #define GRUB_EFI_MAX_USABLE_ADDRESS 0x7fffffff ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS + #endif + + #endif /* ! GRUB_MEMORY_CPU_HEADER */ diff --git a/SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch b/SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch new file mode 100644 index 0000000..77db523 --- /dev/null +++ b/SOURCES/0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch @@ -0,0 +1,199 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 18:03:25 +0200 +Subject: [PATCH] Attempt to fix up all the places -Wsign-compare=error finds. + +Signed-off-by: Peter Jones +--- + grub-core/kern/emu/misc.c | 2 +- + grub-core/lib/reed_solomon.c | 4 ++-- + grub-core/osdep/linux/blocklist.c | 2 +- + grub-core/osdep/linux/getroot.c | 2 +- + grub-core/osdep/linux/hostdisk.c | 2 +- + util/grub-fstest.c | 2 +- + util/grub-menulst2cfg.c | 2 +- + util/grub-mkfont.c | 13 +++++++------ + util/grub-probe.c | 2 +- + util/setup.c | 2 +- + 10 files changed, 17 insertions(+), 16 deletions(-) + +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index 0ff13bcaf8..d278c2921f 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -185,7 +185,7 @@ grub_util_get_image_size (const char *path) + sz = ftello (f); + if (sz < 0) + grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); +- if (sz != (size_t) sz) ++ if (sz > (off_t)(GRUB_SIZE_MAX >> 1)) + grub_util_error (_("file `%s' is too big"), path); + ret = (size_t) sz; + +diff --git a/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c +index 467305b46a..79037c093f 100644 +--- a/grub-core/lib/reed_solomon.c ++++ b/grub-core/lib/reed_solomon.c +@@ -157,7 +157,7 @@ static void + rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs) + { + gf_single_t *rs_polynomial; +- int i, j; ++ unsigned int i, j; + gf_single_t *m; + m = xcalloc (s + rs, sizeof (gf_single_t)); + grub_memcpy (m, data, s * sizeof (gf_single_t)); +@@ -324,7 +324,7 @@ static void + encode_block (gf_single_t *ptr, grub_size_t s, + gf_single_t *rptr, grub_size_t rs) + { +- int i, j; ++ unsigned int i, j; + for (i = 0; i < SECTOR_SIZE; i++) + { + grub_size_t ds = (s + SECTOR_SIZE - 1 - i) / SECTOR_SIZE; +diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c +index c77d6085cc..42a315031f 100644 +--- a/grub-core/osdep/linux/blocklist.c ++++ b/grub-core/osdep/linux/blocklist.c +@@ -109,7 +109,7 @@ grub_install_get_blocklist (grub_device_t root_dev, + else + { + struct fiemap *fie2; +- int i; ++ unsigned int i; + fie2 = xmalloc (sizeof (*fie2) + + fie1.fm_mapped_extents + * sizeof (fie1.fm_extents[1])); +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 28790307e0..9f730b3518 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -236,7 +236,7 @@ grub_find_root_devices_from_btrfs (const char *dir) + { + int fd; + struct btrfs_ioctl_fs_info_args fsi; +- int i, j = 0; ++ unsigned int i, j = 0; + char **ret; + + fd = open (dir, 0); +diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c +index da62f924e3..7bc99ac1c1 100644 +--- a/grub-core/osdep/linux/hostdisk.c ++++ b/grub-core/osdep/linux/hostdisk.c +@@ -83,7 +83,7 @@ grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_sec + if (sector_size & (sector_size - 1) || !sector_size) + return -1; + for (log_sector_size = 0; +- (1 << log_sector_size) < sector_size; ++ (1U << log_sector_size) < sector_size; + log_sector_size++); + + if (log_secsize) +diff --git a/util/grub-fstest.c b/util/grub-fstest.c +index 8386564200..bfcef852d8 100644 +--- a/util/grub-fstest.c ++++ b/util/grub-fstest.c +@@ -323,7 +323,7 @@ cmd_cmp (char *src, char *dest) + read_file (src, cmp_hook, ff); + + { +- grub_uint64_t pre; ++ long long pre; + pre = ftell (ff); + fseek (ff, 0, SEEK_END); + if (pre != ftell (ff)) +diff --git a/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c +index a39f869394..358d604210 100644 +--- a/util/grub-menulst2cfg.c ++++ b/util/grub-menulst2cfg.c +@@ -34,7 +34,7 @@ main (int argc, char **argv) + char *buf = NULL; + size_t bufsize = 0; + char *suffix = xstrdup (""); +- int suffixlen = 0; ++ size_t suffixlen = 0; + const char *out_fname = 0; + + grub_util_host_init (&argc, &argv); +diff --git a/util/grub-mkfont.c b/util/grub-mkfont.c +index 0fe45a6103..3e09240b99 100644 +--- a/util/grub-mkfont.c ++++ b/util/grub-mkfont.c +@@ -138,7 +138,8 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + int width, height; + int cuttop, cutbottom, cutleft, cutright; + grub_uint8_t *data; +- int mask, i, j, bitmap_size; ++ int mask, i, bitmap_size; ++ unsigned int j; + FT_GlyphSlot glyph; + int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME; + FT_Error err; +@@ -183,7 +184,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + cuttop = cutbottom = cutleft = cutright = 0; + else + { +- for (cuttop = 0; cuttop < glyph->bitmap.rows; cuttop++) ++ for (cuttop = 0; cuttop < (long)glyph->bitmap.rows; cuttop++) + { + for (j = 0; j < glyph->bitmap.width; j++) + if (glyph->bitmap.buffer[j / 8 + cuttop * glyph->bitmap.pitch] +@@ -203,10 +204,10 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + break; + } + cutbottom = glyph->bitmap.rows - 1 - cutbottom; +- if (cutbottom + cuttop >= glyph->bitmap.rows) ++ if (cutbottom + cuttop >= (long)glyph->bitmap.rows) + cutbottom = 0; + +- for (cutleft = 0; cutleft < glyph->bitmap.width; cutleft++) ++ for (cutleft = 0; cutleft < (long)glyph->bitmap.width; cutleft++) + { + for (j = 0; j < glyph->bitmap.rows; j++) + if (glyph->bitmap.buffer[cutleft / 8 + j * glyph->bitmap.pitch] +@@ -225,7 +226,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + break; + } + cutright = glyph->bitmap.width - 1 - cutright; +- if (cutright + cutleft >= glyph->bitmap.width) ++ if (cutright + cutleft >= (long)glyph->bitmap.width) + cutright = 0; + } + +@@ -262,7 +263,7 @@ add_glyph (struct grub_font_info *font_info, FT_UInt glyph_idx, FT_Face face, + + mask = 0; + data = &glyph_info->bitmap[0] - 1; +- for (j = cuttop; j < height + cuttop; j++) ++ for (j = cuttop; j < (long)height + cuttop; j++) + for (i = cutleft; i < width + cutleft; i++) + add_pixel (&data, &mask, + glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] & +diff --git a/util/grub-probe.c b/util/grub-probe.c +index c08e46bbb4..c6fac732b4 100644 +--- a/util/grub-probe.c ++++ b/util/grub-probe.c +@@ -798,7 +798,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + + case 't': + { +- int i; ++ unsigned int i; + + for (i = PRINT_FS; i < ARRAY_SIZE (targets); i++) + if (strcmp (arg, targets[i]) == 0) +diff --git a/util/setup.c b/util/setup.c +index da5f2c07f5..8b22bb8cca 100644 +--- a/util/setup.c ++++ b/util/setup.c +@@ -406,7 +406,7 @@ SETUP (const char *dir, + int is_ldm; + grub_err_t err; + grub_disk_addr_t *sectors; +- int i; ++ unsigned int i; + grub_fs_t fs; + unsigned int nsec, maxsec; + diff --git a/SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch b/SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch new file mode 100644 index 0000000..03b4bbf --- /dev/null +++ b/SOURCES/0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 11 Jul 2019 18:20:37 +0200 +Subject: [PATCH] Don't use -Wno-sign-compare -Wno-conversion -Wno-error, do + use -Wextra. + +Signed-off-by: Peter Jones +--- + configure.ac | 14 +++++++++++--- + conf/Makefile.common | 2 +- + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 7b4e1854d3..490353713a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1452,11 +1452,11 @@ fi + # Set them to their new values for the tests below. + CC="$TARGET_CC" + if test x"$platform" = xemu ; then +-CFLAGS="$TARGET_CFLAGS -Wno-error" ++CFLAGS="$TARGET_CFLAGS" + elif test "x$TARGET_APPLE_LINKER" = x1 ; then +-CFLAGS="$TARGET_CFLAGS -nostdlib -static -Wno-error" ++CFLAGS="$TARGET_CFLAGS -nostdlib -static" + else +-CFLAGS="$TARGET_CFLAGS -nostdlib -Wno-error" ++CFLAGS="$TARGET_CFLAGS -nostdlib" + fi + CPPFLAGS="$TARGET_CPPFLAGS" + +@@ -1990,6 +1990,14 @@ if test x"$enable_werror" != xno ; then + HOST_CFLAGS="$HOST_CFLAGS -Werror" + fi + ++AC_ARG_ENABLE([wextra], ++ [AS_HELP_STRING([--disable-wextra], ++ [do not use -Wextra when building GRUB])]) ++if test x"$enable_wextra" != xno ; then ++ TARGET_CFLAGS="$TARGET_CFLAGS -Wextra" ++ HOST_CFLAGS="$HOST_CFLAGS -Wextra" ++fi ++ + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 2ff9b39357..35e14ff017 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield + +-CFLAGS_GNULIB = -Wno-undef -Wno-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion ++CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib + + CFLAGS_POSIX = -fno-builtin diff --git a/SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch b/SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch new file mode 100644 index 0000000..5a9c6f2 --- /dev/null +++ b/SOURCES/0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Jul 2019 09:53:32 +0200 +Subject: [PATCH] x86-efi: Use bounce buffers for reading to addresses > 4GB + +Lots of machines apparently can't DMA correctly above 4GB during UEFI, +so use bounce buffers for the initramfs read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 52 +++++++++++++++++++++++++++++++++------ + 1 file changed, 45 insertions(+), 7 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 33e981e76e..2f0336809e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -35,11 +35,16 @@ static grub_dl_t my_mod; + static int loaded; + static void *kernel_mem; + static grub_uint64_t kernel_size; +-static grub_uint8_t *initrd_mem; ++static void *initrd_mem; + static grub_uint32_t handover_offset; + struct linux_kernel_params *params; + static char *linux_cmdline; + ++#define MIN(a, b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++ + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + + static grub_err_t +@@ -73,6 +78,44 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + ++#define BOUNCE_BUFFER_MAX 0x10000000ull ++ ++static grub_ssize_t ++read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) ++{ ++ grub_ssize_t bufpos = 0; ++ static grub_size_t bbufsz = 0; ++ static char *bbuf = NULL; ++ ++ if (bbufsz == 0) ++ bbufsz = MIN(BOUNCE_BUFFER_MAX, len); ++ ++ while (!bbuf && bbufsz) ++ { ++ bbuf = grub_malloc(bbufsz); ++ if (!bbuf) ++ bbufsz >>= 1; ++ } ++ if (!bbuf) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer")); ++ ++ while (bufpos < (long long)len) ++ { ++ grub_ssize_t sz; ++ ++ sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos)); ++ if (sz < 0) ++ return sz; ++ if (sz == 0) ++ break; ++ ++ grub_memcpy(bufp + bufpos, bbuf, sz); ++ bufpos += sz; ++ } ++ ++ return bufpos; ++} ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -126,7 +169,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + for (i = 0; i < nfiles; i++) + { + grub_ssize_t cursize = grub_file_size (files[i]); +- if (grub_file_read (files[i], ptr, cursize) != cursize) ++ if (read (files[i], ptr, cursize) != cursize) + { + if (!grub_errno) + grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"), +@@ -152,11 +195,6 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) diff --git a/SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch b/SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch new file mode 100644 index 0000000..9b10d68 --- /dev/null +++ b/SOURCES/0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch @@ -0,0 +1,133 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 13 Sep 2018 14:42:34 -0400 +Subject: [PATCH] x86-efi: Re-arrange grub_cmd_linux() a little bit. + +This just helps the next patch be easier to read. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 75 +++++++++++++++++++++------------------ + 1 file changed, 41 insertions(+), 34 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 2f0336809e..5f48fa5561 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -243,32 +243,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } ++ lh = (struct linux_i386_kernel_header *)kernel; ++ grub_dprintf ("linux", "original lh is at %p\n", kernel); + +- grub_dprintf ("linux", "params = %p\n", params); +- +- grub_memset (params, 0, sizeof(*params)); +- +- setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); +- grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", +- MIN((grub_size_t)0x202+setup_header_end_offset, +- sizeof (*params)) - 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- (grub_uint8_t *)params + 0x1f1); +- grub_memcpy ((grub_uint8_t *)params + 0x1f1, +- (grub_uint8_t *)kernel + 0x1f1, +- MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); +- lh = (struct linux_i386_kernel_header *)params; +- grub_dprintf ("linux", "lh is at %p\n", lh); + grub_dprintf ("linux", "checking lh->boot_flag\n"); + if (lh->boot_flag != grub_cpu_to_le16 (0xaa55)) + { +@@ -316,6 +293,34 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (!params) ++ params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, ++ BYTES_TO_PAGES(sizeof(*params))); ++ if (! params) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); ++ goto fail; ++ } ++ ++ grub_dprintf ("linux", "params = %p\n", params); ++ ++ grub_memset (params, 0, sizeof(*params)); ++ ++ setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); ++ grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ MIN((grub_size_t)0x202+setup_header_end_offset, ++ sizeof (*params)) - 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ (grub_uint8_t *)params + 0x1f1); ++ grub_memcpy ((grub_uint8_t *)params + 0x1f1, ++ (grub_uint8_t *)kernel + 0x1f1, ++ MIN((grub_size_t)0x202+setup_header_end_offset,sizeof (*params)) - 0x1f1); ++ ++ lh = (struct linux_i386_kernel_header *)params; ++ grub_dprintf ("linux", "new lh is at %p\n", lh); ++ + grub_dprintf ("linux", "setting up cmdline\n"); + linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, + BYTES_TO_PAGES(lh->cmdline_size + 1)); +@@ -341,8 +346,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); + lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; + +- grub_dprintf ("linux", "computing handover offset\n"); + handover_offset = lh->handover_offset; ++ grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +@@ -359,26 +364,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); + goto fail; + } +- +- grub_dprintf ("linux", "kernel_mem = %lx\n", (unsigned long) kernel_mem); ++ grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- loaded=1; ++ ++ loaded = 1; ++ + grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); + lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +- grub_dprintf ("linux", "setting lh->type_of_loader\n"); + lh->type_of_loader = 0x6; ++ grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n", ++ lh->type_of_loader); + +- grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n"); + params->ext_loader_type = 0; + params->ext_loader_ver = 2; +- grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n", +- kernel_mem, handover_offset); ++ grub_dprintf ("linux", ++ "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", ++ params->ext_loader_type, params->ext_loader_ver); + +- fail: ++fail: + if (file) + grub_file_close (file); + diff --git a/SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch b/SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch new file mode 100644 index 0000000..700c98b --- /dev/null +++ b/SOURCES/0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:03:55 -0400 +Subject: [PATCH] x86-efi: Make our own allocator for kernel stuff + +This helps enable allocations above 4GB. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 167 +++++++++++++++++++++----------------- + 1 file changed, 94 insertions(+), 73 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 5f48fa5561..3e4f7ef39f 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -47,6 +47,65 @@ static char *linux_cmdline; + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + ++struct allocation_choice { ++ grub_efi_physical_address_t addr; ++ grub_efi_allocate_type_t alloc_type; ++}; ++ ++static struct allocation_choice max_addresses[] = ++ { ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { 0, 0 } ++ }; ++ ++static inline void ++kernel_free(void *addr, grub_efi_uintn_t size) ++{ ++ if (addr && size) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)addr, ++ BYTES_TO_PAGES(size)); ++} ++ ++static void * ++kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++{ ++ void *addr = 0; ++ unsigned int i; ++ grub_efi_physical_address_t prev_max = 0; ++ ++ for (i = 0; max_addresses[i].addr != 0 && addr == 0; i++) ++ { ++ grub_uint64_t max = max_addresses[i].addr; ++ grub_efi_uintn_t pages; ++ ++ if (max == prev_max) ++ continue; ++ ++ pages = BYTES_TO_PAGES(size); ++ grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", ++ pages, (void *)max); ++ ++ prev_max = max; ++ addr = grub_efi_allocate_pages_real (max, pages, ++ max_addresses[i].alloc_type, ++ GRUB_EFI_LOADER_DATA); ++ if (addr) ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ } ++ ++ while (grub_error_pop ()) ++ { ++ ; ++ } ++ ++ if (addr == NULL) ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, "%s", errmsg); ++ ++ return addr; ++} ++ + static grub_err_t + grub_linuxefi_boot (void) + { +@@ -62,19 +121,12 @@ grub_linuxefi_unload (void) + { + grub_dl_unref (my_mod); + loaded = 0; +- if (initrd_mem) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, +- BYTES_TO_PAGES(params->ramdisk_size)); +- if (linux_cmdline) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) +- linux_cmdline, +- BYTES_TO_PAGES(params->cmdline_size + 1)); +- if (kernel_mem) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, +- BYTES_TO_PAGES(kernel_size)); +- if (params) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, +- BYTES_TO_PAGES(16384)); ++ ++ kernel_free(initrd_mem, params->ramdisk_size); ++ kernel_free(linux_cmdline, params->cmdline_size + 1); ++ kernel_free(kernel_mem, kernel_size); ++ kernel_free(params, sizeof(*params)); ++ + return GRUB_ERR_NONE; + } + +@@ -150,19 +202,13 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + size += ALIGN_UP (grub_file_size (files[i]), 4); + } + +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- initrd_mem = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, BYTES_TO_PAGES(size)); +- if (!initrd_mem) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate initrd")); +- goto fail; +- } +- +- grub_dprintf ("linux", "initrd_mem = %lx\n", (unsigned long) initrd_mem); ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) ++ goto fail; ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = size; +- params->ramdisk_image = (grub_uint32_t)(grub_addr_t) initrd_mem; ++ params->ramdisk_image = initrd_mem; + + ptr = initrd_mem; + +@@ -221,7 +267,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + filelen = grub_file_size (file); + + kernel = grub_malloc(filelen); +- + if (!kernel) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); +@@ -274,7 +319,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +-#if defined(__x86_64__) || defined(__aarch64__) ++#if defined(__x86_64__) + grub_dprintf ("linux", "checking lh->xloadflags\n"); + if (!(lh->xloadflags & LINUX_XLF_KERNEL_64)) + { +@@ -293,17 +338,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); ++ params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) +- params = grub_efi_allocate_pages_max (GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(sizeof(*params))); +- if (! params) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); +- goto fail; +- } +- ++ goto fail; + grub_dprintf ("linux", "params = %p\n", params); + + grub_memset (params, 0, sizeof(*params)); +@@ -322,19 +359,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); + if (!linux_cmdline) +- linux_cmdline = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); +- if (!linux_cmdline) +- { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); +- goto fail; +- } +- +- grub_dprintf ("linux", "linux_cmdline = %lx\n", +- (unsigned long)linux_cmdline); ++ goto fail; ++ grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); + + grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, +@@ -343,27 +371,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + GRUB_VERIFY_KERNEL_CMDLINE); + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); +- grub_dprintf ("linux", "setting lh->cmd_line_ptr\n"); +- lh->cmd_line_ptr = (grub_uint32_t)(grub_addr_t)linux_cmdline; ++ grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", ++ linux_cmdline); ++ lh->cmd_line_ptr = linux_cmdline; + + handover_offset = lh->handover_offset; +- grub_dprintf("linux", "handover_offset: %08x\n", handover_offset); ++ grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + +- kernel_mem = grub_efi_allocate_pages_max(lh->pref_address, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_ALLOCATION_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) +- kernel_mem = grub_efi_allocate_pages_max(GRUB_EFI_MAX_USABLE_ADDRESS, +- BYTES_TO_PAGES(lh->init_size)); +- if (!kernel_mem) ++ grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); ++ if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); +- goto fail; ++ max_addresses[0].addr = lh->pref_address; ++ max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ if (!kernel_mem) ++ goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + + grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +@@ -398,18 +423,14 @@ fail: + loaded = 0; + } + +- if (linux_cmdline && lh && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) +- linux_cmdline, +- BYTES_TO_PAGES(lh->cmdline_size + 1)); ++ if (!loaded) ++ { ++ if (lh) ++ kernel_free (linux_cmdline, lh->cmdline_size + 1); + +- if (kernel_mem && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, +- BYTES_TO_PAGES(kernel_size)); +- +- if (params && !loaded) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)params, +- BYTES_TO_PAGES(16384)); ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); ++ } + + return grub_errno; + } diff --git a/SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch b/SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch new file mode 100644 index 0000000..6ac11a1 --- /dev/null +++ b/SOURCES/0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch @@ -0,0 +1,171 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 12 Sep 2018 16:12:27 -0400 +Subject: [PATCH] x86-efi: Allow initrd+params+cmdline allocations above 4GB. + +This enables everything except the kernel itself to be above 4GB. +Putting the kernel up there still doesn't work, because of the way +params->code32_start is used. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 67 +++++++++++++++++++++++++++++++++++---- + include/grub/i386/linux.h | 6 +++- + 2 files changed, 65 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3e4f7ef39f..6bc18d5aef 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -52,13 +52,22 @@ struct allocation_choice { + grub_efi_allocate_type_t alloc_type; + }; + +-static struct allocation_choice max_addresses[] = ++static struct allocation_choice max_addresses[4] = + { ++ /* the kernel overrides this one with pref_address and ++ * GRUB_EFI_ALLOCATE_ADDRESS */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this one is always below 4GB, which we still *prefer* even if the flag ++ * is set. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ + { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { 0, 0 } + }; ++static struct allocation_choice saved_addresses[4]; ++ ++#define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) ++#define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) + + static inline void + kernel_free(void *addr, grub_efi_uintn_t size) +@@ -80,6 +89,11 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; + ++ /* ++ * When we're *not* loading the kernel, or >4GB allocations aren't ++ * supported, these entries are basically all the same, so don't re-try ++ * the same parameters. ++ */ + if (max == prev_max) + continue; + +@@ -168,6 +182,9 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + return bufpos; + } + ++#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull)) ++#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) ++ + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -207,8 +224,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + +- params->ramdisk_size = size; +- params->ramdisk_image = initrd_mem; ++ params->ramdisk_size = LOW_U32(size); ++ params->ramdisk_image = LOW_U32(initrd_mem); ++#if defined(__x86_64__) ++ params->ext_ramdisk_size = HIGH_U32(size); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++#endif + + ptr = initrd_mem; + +@@ -338,6 +359,18 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++#if defined(__x86_64__) ++ if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); ++ max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ } ++ else ++ { ++ grub_dprintf ("linux", "Loading kernel above 4GB is not supported\n"); ++ } ++#endif ++ + params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -372,21 +405,40 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- linux_cmdline); +- lh->cmd_line_ptr = linux_cmdline; ++ LOW_U32(linux_cmdline)); ++ lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++#if defined(__x86_64__) ++ if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ { ++ grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", ++ HIGH_U32(linux_cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ } ++#endif + + handover_offset = lh->handover_offset; + grub_dprintf("linux", "handover_offset: 0x%08x\n", handover_offset); + + start = (lh->setup_sects + 1) * 512; + ++ /* ++ * AFAICS >4GB for kernel *cannot* work because of params->code32_start being ++ * 32-bit and getting called unconditionally in head_64.S from either entry ++ * point. ++ * ++ * so nerf that out here... ++ */ ++ save_addresses(); + grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); + if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { + max_addresses[0].addr = lh->pref_address; + max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } ++ max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); +@@ -395,8 +447,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + loaded = 1; + +- grub_dprintf ("linux", "setting lh->code32_start to %p\n", kernel_mem); +- lh->code32_start = (grub_uint32_t)(grub_addr_t) kernel_mem; ++ grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", ++ LOW_U32(kernel_mem)); ++ lh->code32_start = LOW_U32(kernel_mem); + + grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start); + +diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h +index 25ef52c04e..fac22476cc 100644 +--- a/include/grub/i386/linux.h ++++ b/include/grub/i386/linux.h +@@ -236,7 +236,11 @@ struct linux_kernel_params + grub_uint32_t ofw_cif_handler; /* b8 */ + grub_uint32_t ofw_idt; /* bc */ + +- grub_uint8_t padding7[0x1b8 - 0xc0]; ++ grub_uint32_t ext_ramdisk_image; /* 0xc0 */ ++ grub_uint32_t ext_ramdisk_size; /* 0xc4 */ ++ grub_uint32_t ext_cmd_line_ptr; /* 0xc8 */ ++ ++ grub_uint8_t padding7[0x1b8 - 0xcc]; + + union + { diff --git a/SOURCES/0105-Fix-getroot.c-s-trampolines.patch b/SOURCES/0105-Fix-getroot.c-s-trampolines.patch new file mode 100644 index 0000000..e744b77 --- /dev/null +++ b/SOURCES/0105-Fix-getroot.c-s-trampolines.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 28 Sep 2018 15:42:19 -0400 +Subject: [PATCH] Fix getroot.c's trampolines. + +This makes the stack executable on most of the grub utilities, which is +bad, and rpmdiff complains about it. + +Signed-off-by: Peter Jones +--- + grub-core/osdep/linux/getroot.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c +index 9f730b3518..f0c503f43d 100644 +--- a/grub-core/osdep/linux/getroot.c ++++ b/grub-core/osdep/linux/getroot.c +@@ -1264,22 +1264,20 @@ grub_util_get_grub_dev_os (const char *os_dev) + return grub_dev; + } + ++static void *mp = NULL; ++static void ++btrfs_mount_path_hook(const char *m) ++{ ++ mp = strdup (m); ++} + + char * + grub_util_get_btrfs_subvol (const char *path, char **mount_path) + { +- char *mp = NULL; +- + if (mount_path) + *mount_path = NULL; + +- auto void +- mount_path_hook (const char *m) +- { +- mp = strdup (m); +- } +- +- grub_find_root_btrfs_mount_path_hook = mount_path_hook; ++ grub_find_root_btrfs_mount_path_hook = btrfs_mount_path_hook; + grub_free (grub_find_root_devices_from_mountinfo (path, NULL)); + grub_find_root_btrfs_mount_path_hook = NULL; + diff --git a/SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch b/SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch new file mode 100644 index 0000000..658c7a4 --- /dev/null +++ b/SOURCES/0106-Do-not-allow-stack-trampolines-anywhere.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 12 Jul 2019 10:06:50 +0200 +Subject: [PATCH] Do not allow stack trampolines, anywhere. + +Signed-off-by: Peter Jones +--- + configure.ac | 3 +++ + conf/Makefile.common | 2 +- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 490353713a..a02d40a05b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1998,6 +1998,9 @@ if test x"$enable_wextra" != xno ; then + HOST_CFLAGS="$HOST_CFLAGS -Wextra" + fi + ++TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines" ++HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines" ++ + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 35e14ff017..0647c53b91 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -66,7 +66,7 @@ grubconfdir = $(sysconfdir)/grub.d + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield + +-CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code ++CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib + + CFLAGS_POSIX = -fno-builtin diff --git a/SOURCES/0107-Reimplement-boot_counter.patch b/SOURCES/0107-Reimplement-boot_counter.patch new file mode 100644 index 0000000..d018de4 --- /dev/null +++ b/SOURCES/0107-Reimplement-boot_counter.patch @@ -0,0 +1,196 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 4 Oct 2018 14:22:09 -0400 +Subject: [PATCH] Reimplement boot_counter + +This adds "increment" and "decrement" commands, and uses them to maintain our +variables in 01_fallback_counter. It also simplifies the counter logic, so +that there are no nested tests that conflict with each other. + +Apparently, this *really* wasn't tested well enough. + +Resolves: rhbz#1614637 +Signed-off-by: Peter Jones +[lorbus: add comments and revert logic changes in 01_fallback_counting] +Signed-off-by: Christian Glombek +--- + Makefile.util.def | 6 +++ + grub-core/Makefile.core.def | 5 ++ + grub-core/commands/increment.c | 105 ++++++++++++++++++++++++++++++++++++ + util/grub.d/01_fallback_counting.in | 22 ++++++++ + 4 files changed, 138 insertions(+) + create mode 100644 grub-core/commands/increment.c + create mode 100644 util/grub.d/01_fallback_counting.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index d066652e9b..e10fe766d1 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -458,6 +458,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '01_fallback_counting'; ++ common = util/grub.d/01_fallback_counting.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '01_menu_auto_hide'; + common = util/grub.d/01_menu_auto_hide.in; +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 4f203533f5..ea4d59f51b 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -398,6 +398,11 @@ kernel = { + extra_dist = kern/mips/cache_flush.S; + }; + ++module = { ++ name = increment; ++ common = commands/increment.c; ++}; ++ + program = { + name = grub-emu; + mansection = 1; +diff --git a/grub-core/commands/increment.c b/grub-core/commands/increment.c +new file mode 100644 +index 0000000000..79cf137656 +--- /dev/null ++++ b/grub-core/commands/increment.c +@@ -0,0 +1,105 @@ ++/* increment.c - Commands to increment and decrement variables. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef enum { ++ INCREMENT, ++ DECREMENT, ++} operation; ++ ++static grub_err_t ++incr_decr(operation op, int argc, char **args) ++{ ++ const char *old; ++ char *new; ++ long value; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("no variable specified")); ++ if (argc > 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_ ("too many arguments")); ++ ++ old = grub_env_get (*args); ++ if (!old) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("No such variable \"%s\""), ++ *args); ++ ++ value = grub_strtol (old, NULL, 0); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ switch (op) ++ { ++ case INCREMENT: ++ value += 1; ++ break; ++ case DECREMENT: ++ value -= 1; ++ break; ++ } ++ ++ new = grub_xasprintf ("%ld", value); ++ if (!new) ++ return grub_errno; ++ ++ grub_env_set (*args, new); ++ grub_free (new); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_incr(struct grub_command *cmd UNUSED, ++ int argc, char **args) ++{ ++ return incr_decr(INCREMENT, argc, args); ++} ++ ++static grub_err_t ++grub_cmd_decr(struct grub_command *cmd UNUSED, ++ int argc, char **args) ++{ ++ return incr_decr(DECREMENT, argc, args); ++} ++ ++static grub_command_t cmd_incr, cmd_decr; ++ ++GRUB_MOD_INIT(increment) ++{ ++ cmd_incr = grub_register_command ("increment", grub_cmd_incr, N_("VARIABLE"), ++ N_("increment VARIABLE")); ++ cmd_decr = grub_register_command ("decrement", grub_cmd_decr, N_("VARIABLE"), ++ N_("decrement VARIABLE")); ++} ++ ++GRUB_MOD_FINI(increment) ++{ ++ grub_unregister_command (cmd_incr); ++ grub_unregister_command (cmd_decr); ++} +diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/01_fallback_counting.in +new file mode 100644 +index 0000000000..be0e770ea8 +--- /dev/null ++++ b/util/grub.d/01_fallback_counting.in +@@ -0,0 +1,22 @@ ++#! /bin/sh -e ++ ++# Boot Counting ++# The boot_counter env var can be used to count down boot attempts after an ++# OSTree upgrade and choose the rollback deployment when 0 is reached. Both ++# boot_counter and boot_success need to be (re-)set from userspace. ++cat << EOF ++insmod increment ++# Check if boot_counter exists and boot_success=0 to activate this behaviour. ++if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then ++ # if countdown has ended, choose to boot rollback deployment (default=1 on ++ # OSTree-based systems) ++ if [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then ++ set default=1 ++ set boot_counter=-1 ++ # otherwise decrement boot_counter ++ else ++ decrement boot_counter ++ fi ++ save_env boot_counter ++fi ++EOF diff --git a/SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch b/SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch new file mode 100644 index 0000000..af74901 --- /dev/null +++ b/SOURCES/0108-Fix-menu-entry-selection-based-on-ID-and-title.patch @@ -0,0 +1,233 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 19 Oct 2018 10:57:52 -0400 +Subject: [PATCH] Fix menu entry selection based on ID and title + +Currently if grub_strtoul(saved_entry_value, NULL, 0) does not return an +error, we assume the value it has produced is a correct index into our +menu entry list, and do not try to interpret the value as the "id" or +"title" . In cases where "id" or "title" start with a numeral, this +makes them impossible to use as selection criteria. + +This patch splits the search into three phases - matching id, matching +title, and only once those have been exhausted, trying to interpret the +ID as a numeral. In that case, we also require that the entire string +is numeric, not merely a string with leading numeric characters. + +Resolves: rhbz#1640979 + +Signed-off-by: Peter Jones +[javierm: fix menu entry selection based on title] +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/menu.c | 141 ++++++++++++++++++++++++------------------------ + 1 file changed, 71 insertions(+), 70 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index d7a222e681..4a02aadb01 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -164,12 +164,12 @@ grub_menu_set_timeout (int timeout) + } + + static int +-menuentry_eq (const char *id, const char *spec) ++menuentry_eq (const char *id, const char *spec, int limit) + { + const char *ptr1, *ptr2; + ptr1 = id; + ptr2 = spec; +- while (1) ++ while (limit == -1 || ptr1 - id <= limit) + { + if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) + return ptr2 - spec; +@@ -178,7 +178,11 @@ menuentry_eq (const char *id, const char *spec) + if (*ptr2 == '>') + ptr2++; + if (*ptr1 != *ptr2) +- return 0; ++ { ++ if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2)) ++ return ptr1 -id -1; ++ return 0; ++ } + if (*ptr1 == 0) + return ptr1 - id; + ptr1++; +@@ -187,6 +191,58 @@ menuentry_eq (const char *id, const char *spec) + return 0; + } + ++static int ++get_entry_number_helper(grub_menu_t menu, ++ const char * const val, const char ** const tail) ++{ ++ /* See if the variable matches the title of a menu entry. */ ++ int entry = -1; ++ grub_menu_entry_t e; ++ int i; ++ ++ for (i = 0, e = menu->entry_list; e; i++) ++ { ++ int l = 0; ++ while (val[l] && !grub_isspace(val[l])) ++ l++; ++ ++ if (menuentry_eq (e->id, val, l)) ++ { ++ if (tail) ++ *tail = val + l; ++ return i; ++ } ++ e = e->next; ++ } ++ ++ for (i = 0, e = menu->entry_list; e; i++) ++ { ++ ++ if (menuentry_eq (e->title, val, -1)) ++ { ++ if (tail) ++ *tail = NULL; ++ return i; ++ } ++ e = e->next; ++ } ++ ++ if (tail) ++ *tail = NULL; ++ ++ entry = (int) grub_strtoul (val, tail, 0); ++ if (grub_errno == GRUB_ERR_BAD_NUMBER || ++ (*tail && **tail && !grub_isspace(**tail))) ++ { ++ entry = -1; ++ if (tail) ++ *tail = NULL; ++ grub_errno = GRUB_ERR_NONE; ++ } ++ ++ return entry; ++} ++ + /* Get the first entry number from the value of the environment variable NAME, + which is a space-separated list of non-negative integers. The entry number + which is returned is stripped from the value of NAME. If no entry number +@@ -196,7 +252,6 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + { + const char *val, *tail; + int entry; +- int sz = 0; + + val = grub_env_get (name); + if (! val) +@@ -204,50 +259,24 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + + grub_error_push (); + +- entry = (int) grub_strtoul (val, &tail, 0); ++ entry = get_entry_number_helper(menu, val, &tail); ++ if (!(*tail == 0 || grub_isspace(*tail))) ++ entry = -1; + +- if (grub_errno == GRUB_ERR_BAD_NUMBER) ++ if (entry >= 0) + { +- /* See if the variable matches the title of a menu entry. */ +- grub_menu_entry_t e = menu->entry_list; +- int i; +- +- for (i = 0; e; i++) +- { +- sz = menuentry_eq (e->title, val); +- if (sz < 1) +- sz = menuentry_eq (e->id, val); +- +- if (sz >= 1) +- { +- entry = i; +- break; +- } +- e = e->next; +- } +- +- if (sz > 0) +- grub_errno = GRUB_ERR_NONE; +- +- if (! e) +- entry = -1; +- } +- +- if (grub_errno == GRUB_ERR_NONE) +- { +- if (sz > 0) +- tail += sz; +- + /* Skip whitespace to find the next entry. */ + while (*tail && grub_isspace (*tail)) + tail++; +- grub_env_set (name, tail); ++ if (*tail) ++ grub_env_set (name, tail); ++ else ++ grub_env_unset (name); + } + else + { + grub_env_unset (name); + grub_errno = GRUB_ERR_NONE; +- entry = -1; + } + + grub_error_pop (); +@@ -524,6 +553,7 @@ static int + get_entry_number (grub_menu_t menu, const char *name) + { + const char *val; ++ const char *tail; + int entry; + + val = grub_env_get (name); +@@ -531,38 +561,9 @@ get_entry_number (grub_menu_t menu, const char *name) + return -1; + + grub_error_push (); +- +- entry = (int) grub_strtoul (val, 0, 0); +- +- if (grub_errno == GRUB_ERR_BAD_NUMBER) +- { +- /* See if the variable matches the title of a menu entry. */ +- grub_menu_entry_t e = menu->entry_list; +- int i; +- +- grub_errno = GRUB_ERR_NONE; +- +- for (i = 0; e; i++) +- { +- if (menuentry_eq (e->title, val) +- || menuentry_eq (e->id, val)) +- { +- entry = i; +- break; +- } +- e = e->next; +- } +- +- if (! e) +- entry = -1; +- } +- +- if (grub_errno != GRUB_ERR_NONE) +- { +- grub_errno = GRUB_ERR_NONE; +- entry = -1; +- } +- ++ entry = get_entry_number_helper(menu, val, &tail); ++ if (tail && *tail != '\0') ++ entry = -1; + grub_error_pop (); + + return entry; diff --git a/SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch b/SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch new file mode 100644 index 0000000..68779eb --- /dev/null +++ b/SOURCES/0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 26 Nov 2018 10:06:42 +0100 +Subject: [PATCH] Make the menu entry users option argument to be optional + +The --users option is used to restrict the access to specific menu entries +only to a set of users. But the option requires an argument to either be a +constant or a variable that has been set. So for example the following: + + menuentry "May be run by superusers or users in $users" --users $users { + linux /vmlinuz + } + +Would fail if $users is not defined and grub would discard the menu entry. +Instead, allow the --users option to have an optional argument and ignore +the option if the argument was not set. + +Related: rhbz#1652434 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/menuentry.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c +index b194123eb6..b175a1b43b 100644 +--- a/grub-core/commands/menuentry.c ++++ b/grub-core/commands/menuentry.c +@@ -29,7 +29,7 @@ static const struct grub_arg_option options[] = + { + {"class", 1, GRUB_ARG_OPTION_REPEATABLE, + N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING}, +- {"users", 2, 0, ++ {"users", 2, GRUB_ARG_OPTION_OPTIONAL, + N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"), + ARG_TYPE_STRING}, + {"hotkey", 3, 0, +@@ -281,7 +281,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args) + if (! ctxt->state[3].set && ! ctxt->script) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition"); + +- if (ctxt->state[1].set) ++ if (ctxt->state[1].set && ctxt->state[1].arg) + users = ctxt->state[1].arg; + else if (ctxt->state[5].set) + users = NULL; diff --git a/SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch b/SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch new file mode 100644 index 0000000..33d2724 --- /dev/null +++ b/SOURCES/0110-Add-efi-export-env-and-efi-load-env-commands.patch @@ -0,0 +1,346 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 16 Jan 2019 13:21:46 -0500 +Subject: [PATCH] Add efi-export-env and efi-load-env commands + +This adds "efi-export-env VARIABLE" and "efi-load-env", which manipulate the +environment block stored in the EFI variable +GRUB_ENV-91376aff-cba6-42be-949d-06fde81128e8. + +Signed-off-by: Peter Jones +--- + grub-core/Makefile.core.def | 6 ++ + grub-core/commands/efi/env.c | 168 +++++++++++++++++++++++++++++++++++++++++++ + grub-core/kern/efi/efi.c | 3 + + grub-core/kern/efi/init.c | 5 -- + grub-core/lib/envblk.c | 43 +++++++++++ + util/grub-set-bootflag.c | 1 + + include/grub/efi/efi.h | 5 ++ + include/grub/lib/envblk.h | 3 + + 8 files changed, 229 insertions(+), 5 deletions(-) + create mode 100644 grub-core/commands/efi/env.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index ea4d59f51b..dc9fea6f44 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -820,6 +820,12 @@ module = { + enable = efi; + }; + ++module = { ++ name = efienv; ++ common = commands/efi/env.c; ++ enable = efi; ++}; ++ + module = { + name = efifwsetup; + efi = commands/efi/efifwsetup.c; +diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c +new file mode 100644 +index 0000000000..cbd13e03e8 +--- /dev/null ++++ b/grub-core/commands/efi/env.c +@@ -0,0 +1,168 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2012 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static const grub_efi_guid_t grub_env_guid = GRUB_EFI_GRUB_VARIABLE_GUID; ++ ++static grub_err_t ++grub_efi_export_env(grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ const char *value; ++ char *old_value; ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ grub_err_t err; ++ int changed = 1; ++ grub_efi_status_t status; ++ ++ grub_dprintf ("efienv", "argc:%d\n", argc); ++ for (int i = 0; i < argc; i++) ++ grub_dprintf ("efienv", "argv[%d]: %s\n", i, argv[i]); ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("variable name expected")); ++ ++ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ { ++ char *buf = grub_malloc (1025); ++ if (!buf) ++ return grub_errno; ++ ++ grub_memcpy (buf, GRUB_ENVBLK_SIGNATURE, sizeof (GRUB_ENVBLK_SIGNATURE) - 1); ++ grub_memset (buf + sizeof (GRUB_ENVBLK_SIGNATURE) - 1, '#', ++ DEFAULT_ENVBLK_SIZE - sizeof (GRUB_ENVBLK_SIGNATURE) + 1); ++ buf[1024] = '\0'; ++ ++ envblk_s.buf = buf; ++ envblk_s.size = 1024; ++ } ++ else ++ { ++ char *buf = grub_realloc (envblk_s.buf, envblk_s.size + 1); ++ if (!buf) ++ return grub_errno; ++ ++ envblk_s.buf = buf; ++ envblk_s.buf[envblk_s.size] = '\0'; ++ } ++ ++ err = grub_envblk_get(envblk, argv[0], &old_value); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("efienv", "grub_envblk_get returned %d\n", err); ++ return err; ++ } ++ ++ value = grub_env_get(argv[0]); ++ if ((!value && !old_value) || ++ (value && old_value && !grub_strcmp(old_value, value))) ++ changed = 0; ++ ++ if (old_value) ++ grub_free(old_value); ++ ++ if (changed == 0) ++ { ++ grub_dprintf ("efienv", "No changes necessary\n"); ++ return 0; ++ } ++ ++ if (value) ++ { ++ grub_dprintf ("efienv", "setting \"%s\" to \"%s\"\n", argv[0], value); ++ grub_envblk_set(envblk, argv[0], value); ++ } ++ else ++ { ++ grub_dprintf ("efienv", "deleting \"%s\" from envblk\n", argv[0]); ++ grub_envblk_delete(envblk, argv[0]); ++ } ++ ++ grub_dprintf ("efienv", "envblk is %lu bytes:\n\"%s\"\n", envblk_s.size, envblk_s.buf); ++ ++ grub_dprintf ("efienv", "removing GRUB_ENV\n"); ++ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, NULL, 0); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efienv", "removal returned %ld\n", status); ++ ++ grub_dprintf ("efienv", "setting GRUB_ENV\n"); ++ status = grub_efi_set_variable ("GRUB_ENV", &grub_env_guid, ++ envblk_s.buf, envblk_s.size); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_dprintf ("efienv", "setting GRUB_ENV returned %ld\n", status); ++ ++ return 0; ++} ++ ++static int ++set_var (const char *name, const char *value, ++ void *whitelist __attribute__((__unused__))) ++{ ++ grub_env_set (name, value); ++ return 0; ++} ++ ++static grub_err_t ++grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[] __attribute__((__unused__))) ++{ ++ struct grub_envblk envblk_s = { NULL, 0 }; ++ grub_envblk_t envblk = &envblk_s; ++ ++ grub_efi_get_variable ("GRUB_ENV", &grub_env_guid, &envblk_s.size, ++ (void **) &envblk_s.buf); ++ if (!envblk_s.buf || envblk_s.size < 1) ++ return 0; ++ ++ if (argc > 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected argument")); ++ ++ grub_envblk_iterate (envblk, NULL, set_var); ++ grub_free (envblk_s.buf); ++} ++ ++static grub_command_t export_cmd, loadenv_cmd; ++ ++GRUB_MOD_INIT(lsefi) ++{ ++ export_cmd = grub_register_command ("efi-export-env", grub_efi_export_env, ++ N_("VARIABLE_NAME"), N_("Export environment variable to UEFI.")); ++ loadenv_cmd = grub_register_command ("efi-load-env", grub_efi_load_env, ++ NULL, N_("Load the grub environment from UEFI.")); ++} ++ ++GRUB_MOD_FINI(lsefi) ++{ ++ grub_unregister_command (export_cmd); ++ grub_unregister_command (loadenv_cmd); ++} +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 2a446f5031..14bc10eb56 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -225,6 +225,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + if (status == GRUB_EFI_SUCCESS) + return GRUB_ERR_NONE; + ++ if (status == GRUB_EFI_NOT_FOUND && datasize == 0) ++ return GRUB_ERR_NONE; ++ + return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); + } + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 2d12e6188f..0574d8d621 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -85,11 +85,6 @@ stack_protector_init (void) + + grub_addr_t grub_modbase; + +-#define GRUB_EFI_GRUB_VARIABLE_GUID \ +- { 0x91376aff, 0xcba6, 0x42be, \ +- { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ +- } +- + /* Helper for grub_efi_env_init */ + static int + set_var (const char *name, const char *value, +diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c +index 2e4e78b132..874506da16 100644 +--- a/grub-core/lib/envblk.c ++++ b/grub-core/lib/envblk.c +@@ -223,6 +223,49 @@ grub_envblk_delete (grub_envblk_t envblk, const char *name) + } + } + ++struct get_var_state { ++ const char * const name; ++ char * value; ++ int found; ++}; ++ ++static int ++get_var (const char * const name, const char * const value, void *statep) ++{ ++ struct get_var_state *state = (struct get_var_state *)statep; ++ ++ if (!grub_strcmp(state->name, name)) ++ { ++ state->found = 1; ++ state->value = grub_strdup(value); ++ if (!state->value) ++ grub_errno = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ ++ return 1; ++ } ++ ++ return 0; ++} ++ ++grub_err_t ++grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value) ++{ ++ struct get_var_state state = { ++ .name = name, ++ .value = NULL, ++ .found = 0, ++ }; ++ ++ grub_envblk_iterate(envblk, (void *)&state, get_var); ++ ++ *value = state.value; ++ ++ if (state.found && !state.value) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ + void + grub_envblk_iterate (grub_envblk_t envblk, + void *hook_data, +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index d506f7e75b..a6ccc11383 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -25,6 +25,7 @@ + + #include /* For *_DIR_NAME defines */ + #include ++#include + #include /* For GRUB_ENVBLK_DEFCFG define */ + #include + #include +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 2e0691454b..8dfc89a33b 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -24,6 +24,11 @@ + #include + #include + ++#define GRUB_EFI_GRUB_VARIABLE_GUID \ ++ { 0x91376aff, 0xcba6, 0x42be, \ ++ { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ ++ } ++ + /* Variables. */ + extern grub_efi_system_table_t *EXPORT_VAR(grub_efi_system_table); + extern grub_efi_handle_t EXPORT_VAR(grub_efi_image_handle); +diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h +index c3e6559217..ab969af246 100644 +--- a/include/grub/lib/envblk.h ++++ b/include/grub/lib/envblk.h +@@ -22,6 +22,8 @@ + #define GRUB_ENVBLK_SIGNATURE "# GRUB Environment Block\n" + #define GRUB_ENVBLK_DEFCFG "grubenv" + ++#define DEFAULT_ENVBLK_SIZE 1024 ++ + #ifndef ASM_FILE + + struct grub_envblk +@@ -33,6 +35,7 @@ typedef struct grub_envblk *grub_envblk_t; + + grub_envblk_t grub_envblk_open (char *buf, grub_size_t size); + int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value); ++grub_err_t grub_envblk_get (grub_envblk_t envblk, const char * const name, char ** const value); + void grub_envblk_delete (grub_envblk_t envblk, const char *name); + void grub_envblk_iterate (grub_envblk_t envblk, + void *hook_data, diff --git a/SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch b/SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch new file mode 100644 index 0000000..15305f8 --- /dev/null +++ b/SOURCES/0111-Make-it-possible-to-subtract-conditions-from-debug.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 17 Jan 2019 13:10:39 -0500 +Subject: [PATCH] Make it possible to subtract conditions from debug= + +This makes it so you can do set debug to "all,-scripting,-lexer" and get the +obvious outcome. Any negation present will take preference over that +conditional, so "all,-scripting,scripting" is the same thing as +"all,-scripting". + +Signed-off-by: Peter Jones +--- + grub-core/kern/misc.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 9a2fae6398..578bf51a5f 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -164,12 +164,24 @@ int + grub_debug_enabled (const char * condition) + { + const char *debug; ++ char *negcond; ++ int negated = 0; + + debug = grub_env_get ("debug"); + if (!debug) + return 0; + +- if (grub_strword (debug, "all") || grub_strword (debug, condition)) ++ negcond = grub_zalloc (grub_strlen (condition) + 2); ++ if (negcond) ++ { ++ grub_strcpy (negcond, "-"); ++ grub_strcpy (negcond+1, condition); ++ negated = grub_strword (debug, negcond); ++ grub_free (negcond); ++ } ++ ++ if (!negated && ++ (grub_strword (debug, "all") || grub_strword (debug, condition))) + return 1; + + return 0; diff --git a/SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch b/SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch new file mode 100644 index 0000000..214fa4f --- /dev/null +++ b/SOURCES/0112-Export-all-variables-from-the-initial-context-when-c.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 22 Jan 2019 15:40:25 +0100 +Subject: [PATCH] Export all variables from the initial context when creating a + submenu + +When a submenu is created, only the exported variables are copied to the +new menu context. But we want the variables to be global, so export lets +export all variables to the new created submenu. + +Also, don't unset the default variable when a new submenu is created. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/context.c | 2 +- + grub-core/normal/menu.c | 2 -- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c +index ee53d4a68e..87edd254c4 100644 +--- a/grub-core/normal/context.c ++++ b/grub-core/normal/context.c +@@ -99,7 +99,7 @@ grub_env_new_context (int export_all) + grub_err_t + grub_env_context_open (void) + { +- return grub_env_new_context (0); ++ return grub_env_new_context (1); + } + + int grub_extractor_level = 0; +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index 4a02aadb01..fe2e77a43e 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -375,8 +375,6 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + + if (ptr && ptr[0] && ptr[1]) + grub_env_set ("default", ptr + 1); +- else +- grub_env_unset ("default"); + + grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args); + diff --git a/SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch b/SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch new file mode 100644 index 0000000..43e8d16 --- /dev/null +++ b/SOURCES/0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christian Glombek +Date: Tue, 2 Apr 2019 16:22:21 +0200 +Subject: [PATCH] grub.d: Split out boot success reset from menu auto hide + script + +Also rename fallback and menu auto hide script to be executed +before and after boot success reset script. +In menu auto hide script, rename last_boot_ok var to menu_hide_ok + +Signed-off-by: Christian Glombek +Signed-off-by: Robbie Harwood +--- + Makefile.util.def | 14 ++++++++---- + ...allback_counting.in => 08_fallback_counting.in} | 14 ++++++------ + util/grub.d/10_reset_boot_success.in | 25 ++++++++++++++++++++++ + .../{01_menu_auto_hide.in => 12_menu_auto_hide.in} | 23 +++++--------------- + 4 files changed, 48 insertions(+), 28 deletions(-) + rename util/grub.d/{01_fallback_counting.in => 08_fallback_counting.in} (65%) + create mode 100644 util/grub.d/10_reset_boot_success.in + rename util/grub.d/{01_menu_auto_hide.in => 12_menu_auto_hide.in} (58%) + +diff --git a/Makefile.util.def b/Makefile.util.def +index e10fe766d1..b4ce5383b7 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -459,14 +459,14 @@ script = { + }; + + script = { +- name = '01_fallback_counting'; +- common = util/grub.d/01_fallback_counting.in; ++ name = '08_fallback_counting'; ++ common = util/grub.d/08_fallback_counting.in; + installdir = grubconf; + }; + + script = { +- name = '01_menu_auto_hide'; +- common = util/grub.d/01_menu_auto_hide.in; ++ name = '12_menu_auto_hide'; ++ common = util/grub.d/12_menu_auto_hide.in; + installdir = grubconf; + }; + +@@ -518,6 +518,12 @@ script = { + condition = COND_HOST_LINUX; + }; + ++script = { ++ name = '10_reset_boot_success'; ++ common = util/grub.d/10_reset_boot_success.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '10_xnu'; + common = util/grub.d/10_xnu.in; +diff --git a/util/grub.d/01_fallback_counting.in b/util/grub.d/08_fallback_counting.in +similarity index 65% +rename from util/grub.d/01_fallback_counting.in +rename to util/grub.d/08_fallback_counting.in +index be0e770ea8..2e2c3ff7d3 100644 +--- a/util/grub.d/01_fallback_counting.in ++++ b/util/grub.d/08_fallback_counting.in +@@ -1,15 +1,17 @@ + #! /bin/sh -e +- +-# Boot Counting ++# Fallback Countdown ++# ++# This snippet depends on 10_reset_boot_success and needs to be kept in sync. ++# + # The boot_counter env var can be used to count down boot attempts after an +-# OSTree upgrade and choose the rollback deployment when 0 is reached. Both +-# boot_counter and boot_success need to be (re-)set from userspace. ++# OSTree upgrade and choose the rollback deployment when 0 is reached. ++# Both boot_counter=X and boot_success=1 need to be set from userspace. + cat << EOF + insmod increment + # Check if boot_counter exists and boot_success=0 to activate this behaviour. + if [ -n "\${boot_counter}" -a "\${boot_success}" = "0" ]; then +- # if countdown has ended, choose to boot rollback deployment (default=1 on +- # OSTree-based systems) ++ # if countdown has ended, choose to boot rollback deployment, ++ # i.e. default=1 on OSTree-based systems. + if [ "\${boot_counter}" = "0" -o "\${boot_counter}" = "-1" ]; then + set default=1 + set boot_counter=-1 +diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in +new file mode 100644 +index 0000000000..6c88d933dd +--- /dev/null ++++ b/util/grub.d/10_reset_boot_success.in +@@ -0,0 +1,25 @@ ++#! /bin/sh -e ++# Reset Boot Success ++# ++# The 08_fallback_counting and 12_menu_auto_hide snippets rely on this one ++# and need to be kept in sync. ++# ++# The boot_success var needs to be set to 1 from userspace to mark a boot successful. ++cat << EOF ++insmod increment ++# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry ++if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then ++ set menu_hide_ok=1 ++else ++ set menu_hide_ok=0 ++fi ++# Reset boot_indeterminate after a successful boot, increment otherwise ++if [ "\${boot_success}" = "1" ] ; then ++ set boot_indeterminate=0 ++else ++ increment boot_indeterminate ++fi ++# Reset boot_success for current boot ++set boot_success=0 ++save_env boot_success boot_indeterminate ++EOF +diff --git a/util/grub.d/01_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in +similarity index 58% +rename from util/grub.d/01_menu_auto_hide.in +rename to util/grub.d/12_menu_auto_hide.in +index ad175870a5..6a7c0fa0d4 100644 +--- a/util/grub.d/01_menu_auto_hide.in ++++ b/util/grub.d/12_menu_auto_hide.in +@@ -1,5 +1,8 @@ + #! /bin/sh +- ++# Menu Auto Hide ++# ++# This snippet depends on 10_reset_boot_success and needs to be kept in sync. ++# + # Disable / skip generating menu-auto-hide config parts on serial terminals + for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + case "$x" in +@@ -10,29 +13,13 @@ for x in ${GRUB_TERMINAL_INPUT} ${GRUB_TERMINAL_OUTPUT}; do + done + + cat << EOF +-if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then +- set last_boot_ok=1 +-else +- set last_boot_ok=0 +-fi +- +-# Reset boot_indeterminate after a successful boot +-if [ "\${boot_success}" = "1" ] ; then +- set boot_indeterminate=0 +-# Avoid boot_indeterminate causing the menu to be hidden more then once +-elif [ "\${boot_indeterminate}" = "1" ]; then +- set boot_indeterminate=2 +-fi +-set boot_success=0 +-save_env boot_success boot_indeterminate +- + if [ x\$feature_timeout_style = xy ] ; then + if [ "\${menu_show_once}" ]; then + unset menu_show_once + save_env menu_show_once + set timeout_style=menu + set timeout=60 +- elif [ "\${menu_auto_hide}" -a "\${last_boot_ok}" = "1" ]; then ++ elif [ "\${menu_auto_hide}" -a "\${menu_hide_ok}" = "1" ]; then + set orig_timeout_style=\${timeout_style} + set orig_timeout=\${timeout} + if [ "\${fastboot}" = "1" ]; then diff --git a/SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch b/SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch new file mode 100644 index 0000000..df36517 --- /dev/null +++ b/SOURCES/0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 9 Apr 2019 13:12:40 +0200 +Subject: [PATCH] Don't assume that boot commands will only return on fail + +While it's true that for most loaders the boot command never returns, it +may be the case that it does. For example the GRUB emulator boot command +calls to systemctl kexec which in turn does an asynchonous call to kexec. + +So in this case GRUB will wrongly assume that the boot command fails and +print a "Failed to boot both default and fallback entries" even when the +kexec call later succeeds. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/menu.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index fe2e77a43e..ec0c92bade 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -285,7 +285,7 @@ get_and_remove_first_entry_number (grub_menu_t menu, const char *name) + } + + /* Run a menu entry. */ +-static void ++static grub_err_t + grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + { + grub_err_t err = GRUB_ERR_NONE; +@@ -302,7 +302,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + { + grub_print_error (); + grub_errno = GRUB_ERR_NONE; +- return; ++ return grub_errno; + } + + errs_before = grub_err_printed_errors; +@@ -315,7 +315,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + grub_env_context_open (); + menu = grub_zalloc (sizeof (*menu)); + if (! menu) +- return; ++ return grub_errno; + grub_env_set_menu (menu); + if (auto_boot) + grub_env_set ("timeout", "0"); +@@ -385,7 +385,7 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + + if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) + /* Implicit execution of boot, only if something is loaded. */ +- grub_command_execute ("boot", 0, 0); ++ err = grub_command_execute ("boot", 0, 0); + + if (errs_before != grub_err_printed_errors) + grub_wait_after_message (); +@@ -408,6 +408,8 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) + else + grub_env_unset ("default"); + grub_env_unset ("timeout"); ++ ++ return err; + } + + /* Execute ENTRY from the menu MENU, falling back to entries specified +@@ -422,10 +424,13 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + void *callback_data) + { + int fallback_entry; ++ grub_err_t err; + + callback->notify_booting (entry, callback_data); + +- grub_menu_execute_entry (entry, 1); ++ err = grub_menu_execute_entry (entry, 1); ++ if (err == GRUB_ERR_NONE) ++ return; + + /* Deal with fallback entries. */ + while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback")) +@@ -436,11 +441,9 @@ grub_menu_execute_with_fallback (grub_menu_t menu, + + entry = grub_menu_get_entry (menu, fallback_entry); + callback->notify_fallback (entry, callback_data); +- grub_menu_execute_entry (entry, 1); +- /* If the function call to execute the entry returns at all, then this is +- taken to indicate a boot failure. For menu entries that do something +- other than actually boot an operating system, this could assume +- incorrectly that something failed. */ ++ err = grub_menu_execute_entry (entry, 1); ++ if (err == GRUB_ERR_NONE) ++ return; + } + + if (!autobooted) diff --git a/SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch b/SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch new file mode 100644 index 0000000..9ffb3ae --- /dev/null +++ b/SOURCES/0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 13 Nov 2019 12:15:43 +0100 +Subject: [PATCH] grub-set-bootflag: Update comment about running as root + through pkexec + +We have stopped using pkexec for grub-set-bootflag, instead it is now +installed suid root, update the comment accordingly. + +Signed-off-by: Hans de Goede +--- + util/grub-set-bootflag.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index a6ccc11383..3eb04beb5e 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -18,7 +18,7 @@ + */ + + /* +- * NOTE this gets run by users as root (through pkexec), so this does not ++ * NOTE this gets run by users as root (its suid root), so this does not + * use any grub library / util functions to allow for easy auditing. + * The grub headers are only included to get certain defines. + */ diff --git a/SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch b/SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch new file mode 100644 index 0000000..11722d1 --- /dev/null +++ b/SOURCES/0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 13 Nov 2019 13:02:01 +0100 +Subject: [PATCH] grub-set-bootflag: Write new env to tmpfile and then rename + +Make the grubenv writing code in grub-set-bootflag more robust by +writing the modified grubenv to a tmpfile first and then renaming the +tmpfile over the old grubenv (following symlinks). + +Signed-off-by: Hans de Goede +--- + util/grub-set-bootflag.c | 87 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 78 insertions(+), 9 deletions(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 3eb04beb5e..3b4c25ca2a 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -28,7 +28,9 @@ + #include + #include /* For GRUB_ENVBLK_DEFCFG define */ + #include ++#include + #include ++#include + #include + #include + +@@ -56,8 +58,10 @@ int main(int argc, char *argv[]) + { + /* NOTE buf must be at least the longest bootflag length + 4 bytes */ + char env[GRUBENV_SIZE + 1], buf[64], *s; ++ /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ ++ char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; + const char *bootflag; +- int i, len, ret; ++ int i, fd, len, ret; + FILE *f; + + if (argc != 2) +@@ -89,7 +93,32 @@ int main(int argc, char *argv[]) + bootflag = bootflags[i]; + len = strlen (bootflag); + +- f = fopen (GRUBENV, "r"); ++ /* ++ * Really become root. setuid avoids an user killing us, possibly leaking ++ * the tmpfile. setgid avoids the new grubenv's gid being that of the user. ++ */ ++ ret = setuid(0); ++ if (ret) ++ { ++ perror ("Error setuid(0) failed"); ++ return 1; ++ } ++ ++ ret = setgid(0); ++ if (ret) ++ { ++ perror ("Error setgid(0) failed"); ++ return 1; ++ } ++ ++ /* Canonicalize GRUBENV filename, resolving symlinks, etc. */ ++ if (!realpath(GRUBENV, env_filename)) ++ { ++ perror ("Error canonicalizing " GRUBENV " filename"); ++ return 1; ++ } ++ ++ f = fopen (env_filename, "r"); + if (!f) + { + perror ("Error opening " GRUBENV " for reading"); +@@ -144,30 +173,70 @@ int main(int argc, char *argv[]) + snprintf(buf, sizeof(buf), "%s=1\n", bootflag); + memcpy(s, buf, len + 3); + +- /* "r+", don't truncate so that the diskspace stays reserved */ +- f = fopen (GRUBENV, "r+"); ++ ++ /* ++ * Create a tempfile for writing the new env. Use the canonicalized filename ++ * for the template so that the tmpfile is in the same dir / on same fs. ++ */ ++ snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename); ++ fd = mkstemp(tmp_filename); ++ if (fd == -1) ++ { ++ perror ("Creating tmpfile failed"); ++ return 1; ++ } ++ ++ f = fdopen (fd, "w"); + if (!f) + { +- perror ("Error opening " GRUBENV " for writing"); ++ perror ("Error fdopen of tmpfile failed"); ++ unlink(tmp_filename); + return 1; + } + + ret = fwrite (env, 1, GRUBENV_SIZE, f); + if (ret != GRUBENV_SIZE) + { +- perror ("Error writing to " GRUBENV); ++ perror ("Error writing tmpfile"); ++ unlink(tmp_filename); + return 1; + } + + ret = fflush (f); + if (ret) + { +- perror ("Error flushing " GRUBENV); ++ perror ("Error flushing tmpfile"); ++ unlink(tmp_filename); + return 1; + } + +- fsync (fileno (f)); +- fclose (f); ++ ret = fsync (fileno (f)); ++ if (ret) ++ { ++ perror ("Error syncing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ ret = fclose (f); ++ if (ret) ++ { ++ perror ("Error closing tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ ++ /* ++ * And finally rename the tmpfile with the new env over the old env, the ++ * linux kernel guarantees that this is atomic (from a syscall pov). ++ */ ++ ret = rename(tmp_filename, env_filename); ++ if (ret) ++ { ++ perror ("Error renaming tmpfile to " GRUBENV " failed"); ++ unlink(tmp_filename); ++ return 1; ++ } + + return 0; + } diff --git a/SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch b/SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch new file mode 100644 index 0000000..948ff73 --- /dev/null +++ b/SOURCES/0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 26 Nov 2019 09:51:41 +0100 +Subject: [PATCH] grub.d: Fix boot_indeterminate getting set on boot_success=0 + boot +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The "grub.d: Split out boot success reset from menu auto hide script" +not only moved the code to clear boot_success and boot_indeterminate +but for some reason also mixed in some broken changes to the +boot_indeterminate handling. + +The boot_indeterminate var is meant to suppress the boot menu after +a reboot from either a selinux-relabel or offline-updates. These +2 special boot scenarios do not set boot_success since there is no +successfull interaction with the user. Instead they increment +boot_indeterminate, and if it is 1 and only when it is 1, so the +first reboot after a "special" boot we suppress the menu. + +To ensure that we do show the menu if we somehow get stuck in a +"special" boot loop where we do special-boots without them +incrementing boot_indeterminate, the code before the +"grub.d: Split out boot success reset from menu auto hide script" +commit would increment boot_indeterminate once when it is 1, so that +even if the "special" boot reboot-loop immediately we would show the +menu on the next boot. + +That commit broke this however, because it not only moves the code, +it also changes it from only "incrementing" boot_indeterminate once to +always incrementing it, except when boot_success == 1 (and we reset it). + +This broken behavior causes the following problem: + +1. Boot a broken kernel, system hangs, power-cycle +2. boot_success now != 1, so we increment boot_indeterminate from 0 + (unset!) to 1. User either simply tries again, or makes some changes + but the end-result still is a system hang, power-cycle +3. Now boot_indeterminate==1 so we do not show the menu even though the + previous boot failed -> BAD + +This commit fixes this by restoring the behavior of setting +boot_indeterminate to 2 when it was 1 before. + +Fixes: "grub.d: Split out boot success reset from menu auto hide script" +Signed-off-by: Hans de Goede +[jpokorny: 01_menu_auto_hide.in: fix a then/than typo] +Signed-off-by: Jan Pokorný +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_reset_boot_success.in | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/util/grub.d/10_reset_boot_success.in b/util/grub.d/10_reset_boot_success.in +index 6c88d933dd..e73f4137b3 100644 +--- a/util/grub.d/10_reset_boot_success.in ++++ b/util/grub.d/10_reset_boot_success.in +@@ -6,18 +6,18 @@ + # + # The boot_success var needs to be set to 1 from userspace to mark a boot successful. + cat << EOF +-insmod increment + # Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry + if [ "\${boot_success}" = "1" -o "\${boot_indeterminate}" = "1" ]; then + set menu_hide_ok=1 + else + set menu_hide_ok=0 + fi +-# Reset boot_indeterminate after a successful boot, increment otherwise ++# Reset boot_indeterminate after a successful boot + if [ "\${boot_success}" = "1" ] ; then + set boot_indeterminate=0 +-else +- increment boot_indeterminate ++# Avoid boot_indeterminate causing the menu to be hidden more than once ++elif [ "\${boot_indeterminate}" = "1" ]; then ++ set boot_indeterminate=2 + fi + # Reset boot_success for current boot + set boot_success=0 diff --git a/SOURCES/0118-Add-start-symbol-for-RISC-V.patch b/SOURCES/0118-Add-start-symbol-for-RISC-V.patch new file mode 100644 index 0000000..2746fa2 --- /dev/null +++ b/SOURCES/0118-Add-start-symbol-for-RISC-V.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Abdurachmanov +Date: Sat, 9 Nov 2019 19:51:57 +0000 +Subject: [PATCH] Add start symbol for RISC-V + +All other architectures have start symbol. + +Hopefully this resolves: + + BUILDSTDERR: ././grub-mkimage: error: undefined symbol start. + +Signed-off-by: David Abdurachmanov +--- + grub-core/kern/riscv/efi/startup.S | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/kern/riscv/efi/startup.S b/grub-core/kern/riscv/efi/startup.S +index f2a7b2b1ed..781773136e 100644 +--- a/grub-core/kern/riscv/efi/startup.S ++++ b/grub-core/kern/riscv/efi/startup.S +@@ -29,6 +29,7 @@ + + .file "startup.S" + .text ++FUNCTION(start) + FUNCTION(_start) + /* + * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. diff --git a/SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch b/SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch new file mode 100644 index 0000000..8bfc964 --- /dev/null +++ b/SOURCES/0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 15 Jan 2020 12:47:46 +0100 +Subject: [PATCH] bootstrap.conf: Force autogen.sh to use python3 + +The python-unversioned-command package is not installed in the buildroot, +but the bootstrap script expects the python command to be present if one +is not defined. So building the package leads to the following error: + +./autogen.sh: line 20: python: command not found + +This is harmless since gnulib is included as a source anyways, because the +builders can't download. But still the issue should be fixed by forcing to +use python3 that's the default in Fedora now. + +Signed-off-by: Javier Martinez Canillas +--- + bootstrap.conf | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bootstrap.conf b/bootstrap.conf +index 6b043fc354..52d4af44be 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -92,7 +92,7 @@ bootstrap_post_import_hook () { + patch -d po -p3 \ + < "po/gettext-patches/$patchname.patch" + done +- FROM_BOOTSTRAP=1 ./autogen.sh ++ PYTHON=python3 FROM_BOOTSTRAP=1 ./autogen.sh + set +e # bootstrap expects this + } + diff --git a/SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch b/SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch new file mode 100644 index 0000000..f745782 --- /dev/null +++ b/SOURCES/0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 5 Mar 2020 16:21:47 +0100 +Subject: [PATCH] efi/http: Export {fw,http}_path variables to make them global + +The fw_path environment variable is used by http_configure() function to +determine the HTTP path that should be used as prefix when using relative +HTTP paths. And this is stored in the http_path environment variable. + +Later, that variable is looked up by grub_efihttp_open() to generate the +complete path to be used in the HTTP request. + +But these variables are not exported, which means that are not global and +so are only found in the initial context. + +This can cause commands like configfile that create a new context to fail +because the fw_path and http_path variables will not be found. + +Resolves: rhbz#1616395 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/kern/main.c | 1 + + grub-core/net/efi/http.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 1c540fc8c2..b573be6650 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -143,6 +143,7 @@ grub_set_prefix_and_root (void) + if (fw_path) + { + grub_env_set ("fw_path", fw_path); ++ grub_env_export ("fw_path"); + grub_dprintf ("fw_path", "fw_path:\"%s\"\n", fw_path); + grub_free (fw_path); + } +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index de351b2cd0..755b7a6d05 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -39,6 +39,7 @@ http_configure (struct grub_efi_net_device *dev, int prefer_ip6) + http_path++; + grub_env_unset ("http_path"); + grub_env_set ("http_path", http_path); ++ grub_env_export ("http_path"); + } + } + diff --git a/SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch b/SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch new file mode 100644 index 0000000..03d85c2 --- /dev/null +++ b/SOURCES/0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch @@ -0,0 +1,114 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 5 Mar 2020 16:21:58 +0100 +Subject: [PATCH] efi/http: Enclose literal IPv6 addresses in square brackets + +According to RFC 2732 (https://www.ietf.org/rfc/rfc2732.txt), literal IPv6 +addresses must be enclosed in square brackets. But GRUB currently does not +do this and is causing HTTP servers to send Bad Request (400) responses. + +For example, the following is the HTTP stream when fetching a config file: + +HEAD /EFI/BOOT/grub.cfg HTTP/1.1 +Host: 2000:dead:beef:a::1 +Accept: */* +User-Agent: UefiHttpBoot/1.0 + +HTTP/1.1 400 Bad Request +Date: Thu, 05 Mar 2020 14:46:02 GMT +Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d +Connection: close +Content-Type: text/html; charset=iso-8859-1 + +and after enclosing the IPv6 address the HTTP request is successful: + +HEAD /EFI/BOOT/grub.cfg HTTP/1.1 +Host: [2000:dead:beef:a::1] +Accept: */* +User-Agent: UefiHttpBoot/1.0 + +HTTP/1.1 200 OK +Date: Thu, 05 Mar 2020 14:48:04 GMT +Server: Apache/2.4.41 (Fedora) OpenSSL/1.1.1d +Last-Modified: Thu, 27 Feb 2020 17:45:58 GMT +ETag: "206-59f924b24b1da" +Accept-Ranges: bytes +Content-Length: 518 + +Resolves: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/http.c | 37 ++++++++++++++++++++++++++++--------- + 1 file changed, 28 insertions(+), 9 deletions(-) + +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index 755b7a6d05..fc8cb25ae0 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -158,13 +158,7 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + grub_efi_status_t status; + grub_efi_boot_services_t *b = grub_efi_system_table->boot_services; + char *url = NULL; +- +- request_headers[0].field_name = (grub_efi_char8_t *)"Host"; +- request_headers[0].field_value = (grub_efi_char8_t *)server; +- request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; +- request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; +- request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; +- request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ char *hostname = NULL; + + { + grub_efi_ipv6_address_t address; +@@ -174,9 +168,24 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + const char *protocol = (use_https == 1) ? "https" : "http"; + + if (grub_efi_string_to_ip6_address (server, &address, &rest) && *rest == 0) +- url = grub_xasprintf ("%s://[%s]%s", protocol, server, name); ++ { ++ hostname = grub_xasprintf ("[%s]", server); ++ if (!hostname) ++ return GRUB_ERR_OUT_OF_MEMORY; ++ ++ server = hostname; ++ ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ if (!url) ++ { ++ grub_free (hostname); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ } + else +- url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ { ++ url = grub_xasprintf ("%s://%s%s", protocol, server, name); ++ } + + if (!url) + { +@@ -199,6 +208,13 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + request_data.url = ucs2_url; + } + ++ request_headers[0].field_name = (grub_efi_char8_t *)"Host"; ++ request_headers[0].field_value = (grub_efi_char8_t *)server; ++ request_headers[1].field_name = (grub_efi_char8_t *)"Accept"; ++ request_headers[1].field_value = (grub_efi_char8_t *)"*/*"; ++ request_headers[2].field_name = (grub_efi_char8_t *)"User-Agent"; ++ request_headers[2].field_value = (grub_efi_char8_t *)"UefiHttpBoot/1.0"; ++ + request_data.method = (headeronly > 0) ? GRUB_EFI_HTTPMETHODHEAD : GRUB_EFI_HTTPMETHODGET; + + request_message.data.request = &request_data; +@@ -228,6 +244,9 @@ efihttp_request (grub_efi_http_t *http, char *server, char *name, int use_https, + + status = efi_call_2 (http->request, http, &request_token); + ++ if (hostname) ++ grub_free (hostname); ++ + if (status != GRUB_EFI_SUCCESS) + { + efi_call_1 (b->close_event, request_token.event); diff --git a/SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch b/SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch new file mode 100644 index 0000000..8fe26cd --- /dev/null +++ b/SOURCES/0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 9 Mar 2020 15:29:45 +0100 +Subject: [PATCH] efi/net: Allow to specify a port number in addresses + +The grub_efi_net_parse_address() function is not covering the case where a +port number is specified in an IPv4 or IPv6 address, so will fail to parse +the network address. + +For most cases the issue is harmless, because the function is only used to +match an address with a network interface and if fails the default is used. + +But still is a bug that has to be fixed and it causes error messages to be +printed like the following: + +error: net/efi/net.c:782:unrecognised network address '192.168.122.1:8080' + +error: net/efi/net.c:781:unrecognised network address '[2000:dead:beef:a::1]:8080' + +Resolves: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 6603cd83ed..84573937b1 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -742,7 +742,7 @@ grub_efi_net_parse_address (const char *address, + return GRUB_ERR_NONE; + } + } +- else if (*rest == 0) ++ else if (*rest == 0 || *rest == ':') + { + grub_uint32_t subnet_mask = 0xffffffffU; + grub_memcpy (ip4->subnet_mask, &subnet_mask, sizeof (ip4->subnet_mask)); +@@ -768,7 +768,7 @@ grub_efi_net_parse_address (const char *address, + return GRUB_ERR_NONE; + } + } +- else if (*rest == 0) ++ else if (*rest == 0 || *rest == ':') + { + ip6->prefix_length = 128; + ip6->is_anycast = 0; diff --git a/SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch b/SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch new file mode 100644 index 0000000..2dc7001 --- /dev/null +++ b/SOURCES/0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 9 Mar 2020 15:30:05 +0100 +Subject: [PATCH] efi/ip4_config: Improve check to detect literal IPv6 + addresses + +The grub_efi_string_to_ip4_address() function wrongly assumes that an IPv6 +address is an IPv4 address, because it doesn't take into account the case +of a caller passing an IPv6 address as a string. + +This leads to the grub_efi_net_parse_address() function to fail and print +the following error message: + +error: net/efi/net.c:785:unrecognised network address '2000:dead:beef:a::1' + +Resolves: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/ip4_config.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +index b711a5d945..313c818b18 100644 +--- a/grub-core/net/efi/ip4_config.c ++++ b/grub-core/net/efi/ip4_config.c +@@ -56,9 +56,20 @@ int + grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) + { + grub_uint32_t newip = 0; +- int i; ++ int i, ncolon = 0; + const char *ptr = val; + ++ /* Check that is not an IPv6 address */ ++ for (i = 0; i < grub_strlen(ptr); i++) ++ { ++ if (ptr[i] == '[' && i == 0) ++ return 0; ++ ++ if (ptr[i] == ':') ++ if (i == 0 || ++ncolon == 2) ++ return 0; ++ } ++ + for (i = 0; i < 4; i++) + { + unsigned long t; diff --git a/SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch b/SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch new file mode 100644 index 0000000..da94e08 --- /dev/null +++ b/SOURCES/0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 10 Mar 2020 11:23:49 +0100 +Subject: [PATCH] efi/net: Print a debug message if parsing the address fails + +Currently if parsing the address fails an error message is printed. But in +most cases this isn't a fatal error since the grub_efi_net_parse_address() +function is only used to match an address with a network interface to use. + +And if this fails, the default interface is used which is good enough for +most cases. So instead of printing an error that would pollute the console +just print a debug message if the address is not parsed correctly. + +A user can enable debug messages for the efinet driver to have information +about the failure and the fact that the default interface is being used. + +Related: rhbz#1732765 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/efi/net.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index 84573937b1..a3f0535d43 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -778,9 +778,9 @@ grub_efi_net_parse_address (const char *address, + } + } + +- return grub_error (GRUB_ERR_NET_BAD_ADDRESS, +- N_("unrecognised network address `%s'"), +- address); ++ grub_dprintf ("efinet", "unrecognised network address '%s'\n", address); ++ ++ return GRUB_ERR_NET_BAD_ADDRESS; + } + + static grub_efi_net_interface_t * +@@ -795,10 +795,7 @@ match_route (const char *server) + err = grub_efi_net_parse_address (server, &ip4, &ip6, &is_ip6, 0); + + if (err) +- { +- grub_print_error (); + return NULL; +- } + + if (is_ip6) + { +@@ -1233,8 +1230,15 @@ grub_net_open_real (const char *name __attribute__ ((unused))) + /*FIXME: Use DNS translate name to address */ + net_interface = match_route (server); + ++ if (!net_interface && net_default_interface) ++ { ++ net_interface = net_default_interface; ++ grub_dprintf ("efinet", "interface lookup failed, using default '%s'\n", ++ net_interface->name); ++ } ++ + /*XXX: should we check device with default gateway ? */ +- if (!net_interface && !(net_interface = net_default_interface)) ++ if (!net_interface) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("disk `%s' no route found"), + name); diff --git a/SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch b/SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch new file mode 100644 index 0000000..8793b0d --- /dev/null +++ b/SOURCES/0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Wed, 22 Apr 2020 12:41:52 +0200 +Subject: [PATCH] kern/term: Also accept F8 as a user interrupt key + +Make F8, which used to be the hotkey to show the Windows boot menu during +boot for a long long time, also interrupt sleeps / stop the menu countdown. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/kern/term.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c +index 14d5964983..4d61f4e979 100644 +--- a/grub-core/kern/term.c ++++ b/grub-core/kern/term.c +@@ -144,9 +144,10 @@ grub_key_is_interrupt (int key) + /* + * ESC sometimes is the BIOS setup hotkey and may be hard to discover, also + * check F4, which was chosen because is not used as a hotkey to enter the +- * BIOS setup by any vendor. ++ * BIOS setup by any vendor. Also, F8 which was the key to get the Windows ++ * bootmenu for a long time. + */ +- if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4) ++ if (key == GRUB_TERM_ESC || key == GRUB_TERM_KEY_F4 || key == GRUB_TERM_KEY_F8) + return 1; + + /* diff --git a/SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch b/SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch new file mode 100644 index 0000000..6aa5013 --- /dev/null +++ b/SOURCES/0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 23 Apr 2020 15:06:46 +0200 +Subject: [PATCH] efi: Set image base address before jumping to the PE/COFF + entry point + +Upstream GRUB uses the EFI LoadImage() and StartImage() to boot the Linux +kernel. But our custom EFI loader that supports Secure Boot instead uses +the EFI handover protocol (for x86) or jumping directly to the PE/COFF +entry point (for aarch64). + +This is done to allow the bootloader to verify the images using the shim +lock protocol to avoid booting untrusted binaries. + +Since the bootloader loads the kernel from the boot media instead of using +LoadImage(), it is responsible to set the Loaded Image base address before +booting the kernel. + +Otherwise the kernel EFI stub will complain that it was not set correctly +and print the following warning message: + +EFI stub: ERROR: FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value + +Resolves: rhbz#1814690 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/efi/linux.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 0622dfa48d..e8b9ecb17f 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -72,6 +72,7 @@ grub_err_t + grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + void *kernel_params) + { ++ grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; + +@@ -79,6 +80,19 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + offset = 512; + #endif + ++ /* ++ * Since the EFI loader is not calling the LoadImage() and StartImage() ++ * services for loading the kernel and booting respectively, it has to ++ * set the Loaded Image base address. ++ */ ++ loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); ++ if (loaded_image) ++ loaded_image->image_base = kernel_addr; ++ else ++ grub_dprintf ("linux", "Loaded Image base address could not be set\n"); ++ ++ grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", ++ kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + diff --git a/SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch b/SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch new file mode 100644 index 0000000..d1c7b17 --- /dev/null +++ b/SOURCES/0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 16 May 2020 11:33:18 +0200 +Subject: [PATCH] tpm: Don't propagate TPM measurement errors to the verifiers + layer + +Currently if the EFI firmware fails to do a TPM measurement for a file, +the error will be propagated to the verifiers framework and so opening +the file will not succeed. + +This mean that buggy firmwares will prevent the system to boot since the +loader won't be able to open any file. But failing to do TPM measurements +shouldn't be a fatal error and the system should still be able to boot. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/tpm.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c +index 2052c36eab..e287d042e6 100644 +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm.c +@@ -42,7 +42,8 @@ grub_tpm_verify_init (grub_file_t io, + static grub_err_t + grub_tpm_verify_write (void *context, void *buf, grub_size_t size) + { +- return grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context); ++ grub_tpm_measure (buf, size, GRUB_BINARY_PCR, context); ++ return GRUB_ERR_NONE; + } + + static grub_err_t +@@ -50,7 +51,6 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) + { + const char *prefix = NULL; + char *description; +- grub_err_t status; + + switch (type) + { +@@ -66,15 +66,15 @@ grub_tpm_verify_string (char *str, enum grub_verify_string_type type) + } + description = grub_malloc (grub_strlen (str) + grub_strlen (prefix) + 1); + if (!description) +- return grub_errno; ++ return GRUB_ERR_NONE; + grub_memcpy (description, prefix, grub_strlen (prefix)); + grub_memcpy (description + grub_strlen (prefix), str, + grub_strlen (str) + 1); +- status = +- grub_tpm_measure ((unsigned char *) str, grub_strlen (str), +- GRUB_STRING_PCR, description); ++ ++ grub_tpm_measure ((unsigned char *) str, grub_strlen (str), GRUB_STRING_PCR, ++ description); + grub_free (description); +- return status; ++ return GRUB_ERR_NONE; + } + + struct grub_file_verifier grub_tpm_verifier = { diff --git a/SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch b/SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch new file mode 100644 index 0000000..7c41e87 --- /dev/null +++ b/SOURCES/0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 26 May 2020 16:59:28 +0200 +Subject: [PATCH] x86-efi: Reduce maximum bounce buffer size to 16 MiB + +The EFI linux loader allocates a bounce buffer to copy the initrd since in +some machines doing DMA on addresses above 4GB is not possible during EFI. + +But the verifiers framework also allocates a buffer to copy the initrd in +its grub_file_open() handler. It does this since the data to verify has to +be passed as a single chunk to modules that use the verifiers framework. + +If the initrd image size is big there may not be enough memory in the heap +to allocate two buffers of that size. This causes an allocation failure in +the verifiers framework and leads to the initrd not being read. + +To prevent these allocation failures, let's reduce the maximum size of the +bounce buffer used in the EFI loader. Since the data read can be copied to +the actual initrd address in multilple chunks. + +Resolves: rhbz#1838633 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/loader/i386/efi/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 6bc18d5aef..15d40d6e35 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -144,7 +144,7 @@ grub_linuxefi_unload (void) + return GRUB_ERR_NONE; + } + +-#define BOUNCE_BUFFER_MAX 0x10000000ull ++#define BOUNCE_BUFFER_MAX 0x1000000ull + + static grub_ssize_t + read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) diff --git a/SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch b/SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch new file mode 100644 index 0000000..7fef93e --- /dev/null +++ b/SOURCES/0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 2 Jun 2020 13:25:01 +0200 +Subject: [PATCH] http: Prepend prefix when the HTTP path is relative as done + in efi/http + +There are two different HTTP drivers that can be used when requesting an +HTTP resource: the efi/http that uses the EFI_HTTP_PROTOCOL and the http +that uses GRUB's HTTP and TCP/IP implementation. + +The efi/http driver appends a prefix that is defined in the variable +http_path, but the http driver doesn't. + +So using this driver and attempting to fetch a resource using a relative +path fails. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/net/http.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index b52b558d63..7f878b5615 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -501,13 +501,20 @@ http_open (struct grub_file *file, const char *filename) + { + grub_err_t err; + struct http_data *data; ++ const char *http_path; + + data = grub_zalloc (sizeof (*data)); + if (!data) + return grub_errno; + file->size = GRUB_FILE_SIZE_UNKNOWN; + +- data->filename = grub_strdup (filename); ++ /* If path is relative, prepend http_path */ ++ http_path = grub_env_get ("http_path"); ++ if (http_path && filename[0] != '/') ++ data->filename = grub_xasprintf ("%s/%s", http_path, filename); ++ else ++ data->filename = grub_strdup (filename); ++ + if (!data->filename) + { + grub_free (data); diff --git a/SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch b/SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch new file mode 100644 index 0000000..f3b10c1 --- /dev/null +++ b/SOURCES/0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 16 Jan 2019 13:21:46 -0500 +Subject: [PATCH] Fix a missing return in efi-export-env and efi-load-env + commands + +Somewhere along the way this got mis-merged to include a return without +a value. Fix it up. + +Signed-off-by: Peter Jones +--- + grub-core/commands/efi/env.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c +index cbd13e03e8..977edb6b06 100644 +--- a/grub-core/commands/efi/env.c ++++ b/grub-core/commands/efi/env.c +@@ -149,6 +149,8 @@ grub_efi_load_env(grub_command_t cmd __attribute__ ((unused)), + + grub_envblk_iterate (envblk, NULL, set_var); + grub_free (envblk_s.buf); ++ ++ return GRUB_ERR_NONE; + } + + static grub_command_t export_cmd, loadenv_cmd; diff --git a/SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch b/SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch new file mode 100644 index 0000000..90e7a34 --- /dev/null +++ b/SOURCES/0131-efi-dhcp-fix-some-allocation-error-checking.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 19 Jul 2020 17:11:06 -0400 +Subject: [PATCH] efi+dhcp: fix some allocation error checking. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/dhcp.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c +index dbef63d8c0..e5c79b748b 100644 +--- a/grub-core/net/efi/dhcp.c ++++ b/grub-core/net/efi/dhcp.c +@@ -80,7 +80,7 @@ grub_efi_dhcp4_parse_dns (grub_efi_dhcp4_protocol_t *dhcp4, grub_efi_dhcp4_packe + if (status != GRUB_EFI_BUFFER_TOO_SMALL) + return NULL; + +- option_list = grub_malloc (option_count * sizeof(*option_list)); ++ option_list = grub_calloc (option_count, sizeof(*option_list)); + if (!option_list) + return NULL; + +@@ -360,8 +360,11 @@ grub_cmd_efi_bootp6 (struct grub_command *cmd __attribute__ ((unused)), + + if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) + { +- options = grub_malloc (count * sizeof(*options)); +- status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ options = grub_calloc (count, sizeof(*options)); ++ if (options) ++ status = efi_call_4 (dev->dhcp6->parse, dev->dhcp6, mode.ia->reply_packet, &count, options); ++ else ++ status = GRUB_EFI_OUT_OF_RESOURCES; + } + + if (status != GRUB_EFI_SUCCESS) diff --git a/SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch b/SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch new file mode 100644 index 0000000..149ada8 --- /dev/null +++ b/SOURCES/0132-efi-http-fix-some-allocation-error-checking.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 19 Jul 2020 17:14:15 -0400 +Subject: [PATCH] efi+http: fix some allocation error checking. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/http.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/grub-core/net/efi/http.c b/grub-core/net/efi/http.c +index fc8cb25ae0..26647a50fa 100644 +--- a/grub-core/net/efi/http.c ++++ b/grub-core/net/efi/http.c +@@ -412,8 +412,8 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + int type) + { + grub_err_t err; +- grub_off_t size; +- char *buf; ++ grub_off_t size = 0; ++ char *buf = NULL; + char *file_name = NULL; + const char *http_path; + +@@ -441,8 +441,11 @@ grub_efihttp_open (struct grub_efi_net_device *dev, + return err; + } + +- buf = grub_malloc (size); +- efihttp_read (dev, buf, size); ++ if (size) ++ { ++ buf = grub_malloc (size); ++ efihttp_read (dev, buf, size); ++ } + + file->size = size; + file->data = buf; diff --git a/SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch b/SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch new file mode 100644 index 0000000..6413eb6 --- /dev/null +++ b/SOURCES/0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Sun, 19 Jul 2020 17:27:00 -0400 +Subject: [PATCH] efi/ip[46]_config.c: fix some potential allocation overflows + +In theory all of this data comes from the firmware stack and it should +be safe, but it's better to be paranoid. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/ip4_config.c | 25 ++++++++++++++++++------- + grub-core/net/efi/ip6_config.c | 13 ++++++++++--- + 2 files changed, 28 insertions(+), 10 deletions(-) + +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +index 313c818b18..9725e928f7 100644 +--- a/grub-core/net/efi/ip4_config.c ++++ b/grub-core/net/efi/ip4_config.c +@@ -4,15 +4,20 @@ + #include + #include + #include ++#include + + char * + grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_address_t hw_address) + { + char *hw_addr, *p; +- int sz, s; +- int i; ++ grub_size_t sz, s, i; + +- sz = (int)hw_address_size * (sizeof ("XX:") - 1) + 1; ++ if (grub_mul (hw_address_size, sizeof ("XX:") - 1, &sz) || ++ grub_add (sz, 1, &sz)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } + + hw_addr = grub_malloc (sz); + if (!hw_addr) +@@ -20,7 +25,7 @@ grub_efi_hw_address_to_string (grub_efi_uint32_t hw_address_size, grub_efi_mac_a + + p = hw_addr; + s = sz; +- for (i = 0; i < (int)hw_address_size; i++) ++ for (i = 0; i < hw_address_size; i++) + { + grub_snprintf (p, sz, "%02x:", hw_address[i]); + p += sizeof ("XX:") - 1; +@@ -238,14 +243,20 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) + { + grub_efi_ip4_config2_interface_info_t *interface_info; + char **ret; +- int i, id; ++ int id; ++ grub_size_t i, nmemb; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); + if (!interface_info) + return NULL; + +- ret = grub_malloc (sizeof (*ret) * (interface_info->route_table_size + 1)); ++ if (grub_add (interface_info->route_table_size, 1, &nmemb)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } + ++ ret = grub_calloc (nmemb, sizeof (*ret)); + if (!ret) + { + grub_free (interface_info); +@@ -253,7 +264,7 @@ grub_efi_ip4_interface_route_table (struct grub_efi_net_device *dev) + } + + id = 0; +- for (i = 0; i < (int)interface_info->route_table_size; i++) ++ for (i = 0; i < interface_info->route_table_size; i++) + { + char *subnet, *gateway, *mask; + grub_uint32_t u32_subnet, u32_gateway; +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +index 017c4d05bc..a46f6f9b68 100644 +--- a/grub-core/net/efi/ip6_config.c ++++ b/grub-core/net/efi/ip6_config.c +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + char * + grub_efi_ip6_address_to_string (grub_efi_pxe_ipv6_address_t *address) +@@ -228,14 +229,20 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) + { + grub_efi_ip6_config_interface_info_t *interface_info; + char **ret; +- int i, id; ++ int id; ++ grub_size_t i, nmemb; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); + if (!interface_info) + return NULL; + +- ret = grub_malloc (sizeof (*ret) * (interface_info->route_count + 1)); ++ if (grub_add (interface_info->route_count, 1, &nmemb)) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ return NULL; ++ } + ++ ret = grub_calloc (nmemb, sizeof (*ret)); + if (!ret) + { + grub_free (interface_info); +@@ -243,7 +250,7 @@ grub_efi_ip6_interface_route_table (struct grub_efi_net_device *dev) + } + + id = 0; +- for (i = 0; i < (int)interface_info->route_count ; i++) ++ for (i = 0; i < interface_info->route_count ; i++) + { + char *gateway, *destination; + grub_uint64_t u64_gateway[2]; diff --git a/SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch b/SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch new file mode 100644 index 0000000..8e63d1d --- /dev/null +++ b/SOURCES/0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Watson +Date: Fri, 24 Jul 2020 17:18:09 +0100 +Subject: [PATCH] efilinux: Fix integer overflows in grub_cmd_initrd + +These could be triggered by an extremely large number of arguments to +the initrd command on 32-bit architectures, or a crafted filesystem with +very large files on any architecture. + +Signed-off-by: Colin Watson +--- + grub-core/loader/i386/efi/linux.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 15d40d6e35..f992ceeef2 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -28,6 +28,8 @@ + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -206,7 +208,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- files = grub_zalloc (argc * sizeof (files[0])); ++ files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; + +@@ -216,7 +218,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + if (! files[i]) + goto fail; + nfiles++; +- size += ALIGN_UP (grub_file_size (files[i]), 4); ++ if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size)) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); ++ goto fail; ++ } + } + + initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); diff --git a/SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch b/SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch new file mode 100644 index 0000000..828fe16 --- /dev/null +++ b/SOURCES/0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch @@ -0,0 +1,130 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Wed, 22 Jul 2020 11:31:43 +0100 +Subject: [PATCH] linuxefi: fail kernel validation without shim protocol. + +If certificates that signed grub are installed into db, grub can be +booted directly. It will then boot any kernel without signature +validation. The booted kernel will think it was booted in secureboot +mode and will implement lockdown, yet it could have been tampered. + +This version of the patch skips calling verification, when booted +without secureboot. And is indented with gnu ident. + +CVE-2020-15705 + +Reported-by: Mathieu Trudel-Lapierre +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/arm64/linux.c | 13 +++++++++---- + grub-core/loader/efi/chainloader.c | 1 + + grub-core/loader/efi/linux.c | 1 + + grub-core/loader/i386/efi/linux.c | 17 +++++++++++------ + 4 files changed, 22 insertions(+), 10 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 70a0075ec5..47f8cf0d84 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -363,11 +364,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + +- rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); +- if (rc < 0) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); +- goto fail; ++ rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); ++ if (rc <= 0) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("%s has invalid signature"), argv[0]); ++ goto fail; ++ } + } + + pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index ac8dfd40c6..d41e8ea14a 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -1084,6 +1084,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + return 0; + } ++ // -1 fall-through to fail + + fail: + if (dev) +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index e8b9ecb17f..9260731c10 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -33,6 +33,7 @@ struct grub_efi_shim_lock + }; + typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; + ++// Returns 1 on success, -1 on error, 0 when not available + int + grub_linuxefi_secure_validate (void *data, grub_uint32_t size) + { +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index f992ceeef2..3cf0f9b330 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -101,7 +102,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + + pages = BYTES_TO_PAGES(size); + grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", +- pages, (void *)max); ++ (unsigned long)pages, (void *)(unsigned long)max); + + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, +@@ -307,12 +308,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- rc = grub_linuxefi_secure_validate (kernel, filelen); +- if (rc < 0) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), +- argv[0]); +- goto fail; ++ rc = grub_linuxefi_secure_validate (kernel, filelen); ++ if (rc <= 0) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("%s has invalid signature"), argv[0]); ++ goto fail; ++ } + } + + lh = (struct linux_i386_kernel_header *)kernel; +@@ -386,6 +390,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201); + grub_dprintf ("linux", "copying %lu bytes from %p to %p\n", ++ (unsigned long) + MIN((grub_size_t)0x202+setup_header_end_offset, + sizeof (*params)) - 0x1f1, + (grub_uint8_t *)kernel + 0x1f1, diff --git a/SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch b/SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch new file mode 100644 index 0000000..f20f5c7 --- /dev/null +++ b/SOURCES/0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/bootp.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/bootp.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c +index 8fb8918ae7..7baf3540c8 100644 +--- a/grub-core/net/bootp.c ++++ b/grub-core/net/bootp.c +@@ -329,7 +329,7 @@ grub_net_configure_by_dhcp_ack (const char *name, + struct grub_net_network_level_interface *inter; + int mask = -1; + char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; +- const grub_uint8_t *opt; ++ const char *opt; + grub_uint8_t opt_len, overload = 0; + const char *boot_file = 0, *server_name = 0; + grub_size_t boot_file_len, server_name_len; +@@ -505,7 +505,7 @@ grub_net_configure_by_dhcp_ack (const char *name, + if (opt && opt_len) + { + grub_env_set_net_property (name, "vendor_class_identifier", (const char *) opt, opt_len); +- if (opt && grub_strcmp (opt, "HTTPClient") == 0) ++ if (opt && grub_strcmp ((char *)opt, "HTTPClient") == 0) + { + char *proto, *ip, *pa; + diff --git a/SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch b/SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch new file mode 100644 index 0000000..ea92110 --- /dev/null +++ b/SOURCES/0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip4_config.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/ip4_config.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/ip4_config.c b/grub-core/net/efi/ip4_config.c +index 9725e928f7..cb880fc3e8 100644 +--- a/grub-core/net/efi/ip4_config.c ++++ b/grub-core/net/efi/ip4_config.c +@@ -61,7 +61,8 @@ int + grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *address, const char **rest) + { + grub_uint32_t newip = 0; +- int i, ncolon = 0; ++ grub_size_t i; ++ int ncolon = 0; + const char *ptr = val; + + /* Check that is not an IPv6 address */ +@@ -78,7 +79,7 @@ grub_efi_string_to_ip4_address (const char *val, grub_efi_ipv4_address_t *addres + for (i = 0; i < 4; i++) + { + unsigned long t; +- t = grub_strtoul (ptr, (char **) &ptr, 0); ++ t = grub_strtoul (ptr, &ptr, 0); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; diff --git a/SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch b/SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch new file mode 100644 index 0000000..915e6d7 --- /dev/null +++ b/SOURCES/0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/ip6_config.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/ip6_config.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/efi/ip6_config.c b/grub-core/net/efi/ip6_config.c +index a46f6f9b68..1c5415d718 100644 +--- a/grub-core/net/efi/ip6_config.c ++++ b/grub-core/net/efi/ip6_config.c +@@ -85,7 +85,7 @@ grub_efi_string_to_ip6_address (const char *val, grub_efi_ipv6_address_t *addres + ptr++; + continue; + } +- t = grub_strtoul (ptr, (char **) &ptr, 16); ++ t = grub_strtoul (ptr, &ptr, 16); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; diff --git a/SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch b/SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch new file mode 100644 index 0000000..fbba65a --- /dev/null +++ b/SOURCES/0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/net.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/efi/net.c b/grub-core/net/efi/net.c +index a3f0535d43..78e5442fc5 100644 +--- a/grub-core/net/efi/net.c ++++ b/grub-core/net/efi/net.c +@@ -729,7 +729,7 @@ grub_efi_net_parse_address (const char *address, + { + grub_uint32_t subnet_mask_size; + +- subnet_mask_size = grub_strtoul (rest + 1, (char **) &rest, 0); ++ subnet_mask_size = grub_strtoul (rest + 1, &rest, 0); + + if (!grub_errno && subnet_mask_size <= 32 && *rest == 0) + { +@@ -758,7 +758,7 @@ grub_efi_net_parse_address (const char *address, + { + grub_efi_uint8_t prefix_length; + +- prefix_length = grub_strtoul (rest + 1, (char **) &rest, 0); ++ prefix_length = grub_strtoul (rest + 1, &rest, 0); + if (!grub_errno && prefix_length <= 128 && *rest == 0) + { + ip6->prefix_length = prefix_length; diff --git a/SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch b/SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch new file mode 100644 index 0000000..9b9acfe --- /dev/null +++ b/SOURCES/0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 20 Jul 2020 12:24:02 -0400 +Subject: [PATCH] Fix const char ** pointers in grub-core/net/efi/pxe.c + +This will need to get folded back in the right place on the next rebase, +but it's before "Make grub_strtol() "end" pointers have safer const +qualifiers" currently, so for now I'm leaving it here instead of merging +it back with the original patch. + +Signed-off-by: Peter Jones +--- + grub-core/net/efi/pxe.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/efi/pxe.c b/grub-core/net/efi/pxe.c +index 531949cba5..73e2bb01c1 100644 +--- a/grub-core/net/efi/pxe.c ++++ b/grub-core/net/efi/pxe.c +@@ -187,7 +187,7 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest) + ptr++; + continue; + } +- t = grub_strtoul (ptr, (char **) &ptr, 16); ++ t = grub_strtoul (ptr, &ptr, 16); + if (grub_errno) + { + grub_errno = GRUB_ERR_NONE; +@@ -225,7 +225,7 @@ pxe_open (struct grub_efi_net_device *dev, + int type __attribute__((unused))) + { + int i; +- char *p; ++ const char *p; + grub_efi_status_t status; + grub_efi_pxe_ip_address_t server_ip; + grub_efi_uint64_t file_size = 0; +@@ -313,7 +313,7 @@ pxe_read (struct grub_efi_net_device *dev, + grub_size_t len) + { + int i; +- char *p; ++ const char *p; + grub_efi_status_t status; + grub_efi_pxe_t *pxe = (prefer_ip6) ? dev->ip6_pxe : dev->ip4_pxe; + grub_efi_uint64_t bufsz = len; diff --git a/SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch b/SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch new file mode 100644 index 0000000..8cf45c3 --- /dev/null +++ b/SOURCES/0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch @@ -0,0 +1,190 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 22 Jul 2020 14:03:42 +0200 +Subject: [PATCH] Add systemd integration scripts to make "systemctl reboot + --boot-loader-menu=xxx" work with grub + +This commit adds a number of scripts / config files to make +"systemctl reboot --boot-loader-menu=xxx" work with grub: + +1. /lib/systemd/system/systemd-logind.service.d/10-grub.conf +This sets SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU in the env. for logind, +indicating that the boot-loader which is used supports this feature, see: +https://github.com/systemd/systemd/blob/master/docs/ENVIRONMENT.md + +2. /lib/systemd/system/grub-systemd-integration.service + /lib/systemd/system/reboot.target.wants/grub-systemd-integration.service -> + ../grub-systemd-integration.service + /usr/libexec/grub/grub-systemd-integration.sh + +The symlink in the .wants dir causes the added service file to be started +by systemd just before rebooting the system. +If /run/systemd/reboot-to-boot-loader-menu exist then the service will run +the grub-systemd-integration.sh script. +This script sets the new menu_show_once_timeout grubenv variable to the +requested timeout in seconds. + +3. /etc/grub.d/14_menu_show_once + +This new grub-mkconfig snippet adds the necessary code to the generated +grub.conf to honor the new menu_show_once_timeout variable, and to +automatically clear it after consuming it. + +Note the service and libexec script use grub-systemd-integration as name +because in the future they may be used to add further integration with +systemctl reboot --foo options, e.g. support for --boot-loader-entry=NAME. + +A few notes about upstreaming this patch from the rhboot grub2 fork: +1. I have deliberately put the grub.conf bits for this in a new / separate + grub-mkconfig snippet generator for easy upstreaming +2. Even though the commit message mentions the .wants symlink for the .service + I have been unable to come up with a clean way to do this at "make install" + time, this should be fixed before upstreaming. + +Downstream notes: +1. Since make install does not add the .wants symlink, this needs to be done + in grub2.spec %install +2. This is keeping support for the "old" Fedora specific menu_show_once env + variable, which has a hardcoded timeout of 60 sec in 12_menu_auto_hide in + place for now. This can be dropped (eventually) in a follow-up patch once + GNOME has been converted to use the systemd dbus API equivalent of + "systemctl reboot --boot-loader-menu=xxx". + +Signed-off-by: Hans de Goede +--- + Makefile.util.def | 27 ++++++++++++++++++++++++ + conf/Makefile.common | 6 ++++++ + util/grub.d/14_menu_show_once.in | 13 ++++++++++++ + util/systemd/10-grub-logind-service.conf.in | 2 ++ + util/systemd/grub-systemd-integration.service.in | 8 +++++++ + util/systemd/systemd-integration.sh.in | 6 ++++++ + 6 files changed, 62 insertions(+) + create mode 100755 util/grub.d/14_menu_show_once.in + create mode 100644 util/systemd/10-grub-logind-service.conf.in + create mode 100644 util/systemd/grub-systemd-integration.service.in + create mode 100644 util/systemd/systemd-integration.sh.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index b4ce5383b7..6366442129 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -470,6 +470,12 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = '14_menu_show_once'; ++ common = util/grub.d/14_menu_show_once.in; ++ installdir = grubconf; ++}; ++ + script = { + name = '01_users'; + common = util/grub.d/01_users.in; +@@ -569,6 +575,27 @@ script = { + installdir = grubconf; + }; + ++script = { ++ name = 'grub-systemd-integration.service'; ++ common = util/systemd/grub-systemd-integration.service.in; ++ installdir = systemdunit; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { ++ name = 'systemd-integration.sh'; ++ common = util/systemd/systemd-integration.sh.in; ++ installdir = grublibexec; ++ condition = COND_HOST_LINUX; ++}; ++ ++script = { ++ name = '10-grub-logind-service.conf'; ++ common = util/systemd/10-grub-logind-service.conf.in; ++ installdir = systemd_logind_service_d; ++ condition = COND_HOST_LINUX; ++}; ++ + program = { + mansection = 1; + name = grub-mkrescue; +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 0647c53b91..9fe5863b2d 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -63,8 +63,11 @@ CCASFLAGS_LIBRARY = $(UTILS_CCASFLAGS) + # Other variables + + grubconfdir = $(sysconfdir)/grub.d ++grublibexecdir = $(libexecdir)/$(grubdirname) + platformdir = $(pkglibdir)/$(target_cpu)-$(platform) + starfielddir = $(pkgdatadir)/themes/starfield ++systemdunitdir = ${prefix}/lib/systemd/system ++systemd_logind_service_ddir = $(systemdunitdir)/systemd-logind.service.d + + CFLAGS_GNULIB = -Wno-undef -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Werror=trampolines -fno-trampolines + CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib +@@ -121,6 +124,9 @@ noinst_LIBRARIES = + dist_noinst_DATA = + platform_SCRIPTS = + platform_PROGRAMS = ++grublibexec_SCRIPTS = ++systemdunit_SCRIPTS = ++systemd_logind_service_d_SCRIPTS = + + TESTS = + EXTRA_DIST = +diff --git a/util/grub.d/14_menu_show_once.in b/util/grub.d/14_menu_show_once.in +new file mode 100755 +index 0000000000..1cd7f36142 +--- /dev/null ++++ b/util/grub.d/14_menu_show_once.in +@@ -0,0 +1,13 @@ ++#! /bin/sh ++# Force the menu to be shown once, with a timeout of ${menu_show_once_timeout} ++# if requested by ${menu_show_once_timeout} being set in the env. ++cat << EOF ++if [ x\$feature_timeout_style = xy ]; then ++ if [ "\${menu_show_once_timeout}" ]; then ++ set timeout_style=menu ++ set timeout="\${menu_show_once_timeout}" ++ unset menu_show_once_timeout ++ save_env menu_show_once_timeout ++ fi ++fi ++EOF +diff --git a/util/systemd/10-grub-logind-service.conf.in b/util/systemd/10-grub-logind-service.conf.in +new file mode 100644 +index 0000000000..f2d4ac0073 +--- /dev/null ++++ b/util/systemd/10-grub-logind-service.conf.in +@@ -0,0 +1,2 @@ ++[Service] ++Environment=SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU=true +diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in +new file mode 100644 +index 0000000000..c81fb594ce +--- /dev/null ++++ b/util/systemd/grub-systemd-integration.service.in +@@ -0,0 +1,8 @@ ++[Unit] ++Description=Grub2 systemctl reboot --boot-loader-menu=... support ++Before=umount.target systemd-reboot.service ++DefaultDependencies=no ++ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu ++ ++[Service] ++ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh +diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in +new file mode 100644 +index 0000000000..dc1218597b +--- /dev/null ++++ b/util/systemd/systemd-integration.sh.in +@@ -0,0 +1,6 @@ ++#!/bin/sh ++ ++TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) ++TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) ++ ++@grub_editenv@ - set menu_show_once_timeout=$TIMEOUT diff --git a/SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch b/SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch new file mode 100644 index 0000000..a16ed68 --- /dev/null +++ b/SOURCES/0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 23 Jul 2020 09:27:36 +0200 +Subject: [PATCH] systemd-integration.sh: Also set old menu_show_once grubenv + var + +Downstream RH / Fedora patch for compatibility with old, not (yet) +regenerated grub.cfg files which miss the menu_show_once_timeout check. +This older grubenv variable leads to a fixed timeout of 60 seconds. + +Note that the new menu_show_once_timeout will overrule these 60 seconds +if both are set and the grub.cfg does have the menu_show_once_timeout +check. + +Signed-off-by: Hans de Goede +--- + util/systemd/systemd-integration.sh.in | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/util/systemd/systemd-integration.sh.in b/util/systemd/systemd-integration.sh.in +index dc1218597b..a4c071c5b0 100644 +--- a/util/systemd/systemd-integration.sh.in ++++ b/util/systemd/systemd-integration.sh.in +@@ -4,3 +4,8 @@ TIMEOUT_USEC=$(cat /run/systemd/reboot-to-boot-loader-menu) + TIMEOUT=$(((TIMEOUT_USEC + 500000) / 1000000)) + + @grub_editenv@ - set menu_show_once_timeout=$TIMEOUT ++ ++# Downstream RH / Fedora patch for compatibility with old, not (yet) ++# regenerated grub.cfg files which miss the menu_show_once_timeout check ++# this older grubenv variable leads to a fixed timeout of 60 seconds ++@grub_editenv@ - set menu_show_once=1 diff --git a/SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch b/SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch new file mode 100644 index 0000000..f891a69 --- /dev/null +++ b/SOURCES/0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Thu, 3 Dec 2020 09:13:24 +0100 +Subject: [PATCH] at_keyboard: use set 1 when keyboard is in Translate mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When keyboard controller acts in Translate mode (0x40 mask), then use +set 1 since translation is done. +Otherwise use the mode queried from the controller (usually set 2). + +Added "atkeyb" debugging messages in at_keyboard module as well. + +Resolves: rhbz#1897587 + +Tested on: +- Asus N53SN (set 1 used) +- Dell Precision (set 1 used) +- HP Elitebook (set 2 used) +- HP G5430 (set 1 used, keyboard in XT mode!) +- Lenovo P71 & Lenovo T460s (set 2 used) +- QEMU/KVM (set 1 used) + +Signed-off-by: Renaud Métrich +--- + grub-core/term/at_keyboard.c | 29 ++++++++++++++++++++++++----- + include/grub/at_keyboard.h | 4 ++++ + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index 597111077b..2601438260 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -135,20 +135,28 @@ query_mode (void) + int e; + + e = write_mode (0); +- if (!e) ++ if (!e) { ++ grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n"); + return 0; ++ } + + do { + keyboard_controller_wait_until_ready (); + ret = grub_inb (KEYBOARD_REG_DATA); + } while (ret == GRUB_AT_ACK); + /* QEMU translates the set even in no-translate mode. */ +- if (ret == 0x43 || ret == 1) ++ if (ret == 0x43 || ret == 1) { ++ grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret); + return 1; +- if (ret == 0x41 || ret == 2) ++ } ++ if (ret == 0x41 || ret == 2) { ++ grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret); + return 2; +- if (ret == 0x3f || ret == 3) ++ } ++ if (ret == 0x3f || ret == 3) { ++ grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret); + return 3; ++ } + return 0; + } + +@@ -165,7 +173,13 @@ set_scancodes (void) + } + + #if !USE_SCANCODE_SET +- ps2_state.current_set = 1; ++ if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) { ++ grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set); ++ ps2_state.current_set = 1; ++ } else { ++ grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set); ++ ps2_state.current_set = grub_keyboard_orig_set; ++ } + return; + #else + +@@ -266,6 +280,7 @@ grub_keyboard_controller_init (void) + grub_keyboard_orig_set = 2; + #else + grub_keyboard_controller_orig = grub_keyboard_controller_read (); ++ grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig); + grub_keyboard_orig_set = query_mode (); + #endif + set_scancodes (); +@@ -275,11 +290,15 @@ grub_keyboard_controller_init (void) + static grub_err_t + grub_keyboard_controller_fini (struct grub_term_input *term __attribute__ ((unused))) + { ++/* In !USE_SCANCODE_SET mode, we didn't change anything, so nothing to restore */ ++#if USE_SCANCODE_SET + if (ps2_state.current_set == 0) + return GRUB_ERR_NONE; ++ grub_dprintf ("atkeyb", "restoring set %d, controller 0x%x\n", grub_keyboard_orig_set, grub_keyboard_controller_orig); + if (grub_keyboard_orig_set) + write_mode (grub_keyboard_orig_set); + grub_keyboard_controller_write (grub_keyboard_controller_orig); ++#endif + return GRUB_ERR_NONE; + } + +diff --git a/include/grub/at_keyboard.h b/include/grub/at_keyboard.h +index bcb4d9ba78..9414dc1b99 100644 +--- a/include/grub/at_keyboard.h ++++ b/include/grub/at_keyboard.h +@@ -19,6 +19,10 @@ + #ifndef GRUB_AT_KEYBOARD_HEADER + #define GRUB_AT_KEYBOARD_HEADER 1 + ++/* ++ * Refer to https://wiki.osdev.org/%228042%22_PS/2_Controller for details. ++ */ ++ + /* Used for sending commands to the controller. */ + #define KEYBOARD_COMMAND_ISREADY(x) !((x) & 0x02) + #define KEYBOARD_COMMAND_READ 0x20 diff --git a/SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch b/SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch new file mode 100644 index 0000000..f6a7530 --- /dev/null +++ b/SOURCES/0144-grub-install-disable-support-for-EFI-platforms.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jan Hlavac +Date: Fri, 20 Nov 2020 23:51:47 +0100 +Subject: [PATCH] grub-install: disable support for EFI platforms + +For each platform, GRUB is shipped as a kernel image and a set of +modules. These files are then used by the grub-install utility to +install GRUB on a specific device. However, in order to support UEFI +Secure Boot, the resulting EFI binary must be signed by a recognized +private key. For this reason, for EFI platforms, most distributions also +ship prebuilt EFI binaries signed by a distribution-specific private +key. In this case, however, the grub-install utility should not be used +because it would overwrite the signed EFI binary. + +The current fix is suboptimal because it preserves all EFI-related code. +A better solution could be to modularize the code and provide a +build-time option. + +Resolves: rhbz#1737444 + +Signed-off-by: Jan Hlavac +[rharwood: drop man page] +--- + util/grub-install.c | 37 ++++++++++++++++--------------------- + docs/grub.texi | 7 +++++++ + 2 files changed, 23 insertions(+), 21 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index a2bec7446c..5babc7af55 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -899,6 +899,22 @@ main (int argc, char *argv[]) + + platform = grub_install_get_target (grub_install_source_directory); + ++ switch (platform) ++ { ++ case GRUB_INSTALL_PLATFORM_ARM_EFI: ++ case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ case GRUB_INSTALL_PLATFORM_I386_EFI: ++ case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ is_efi = 1; ++ grub_util_error (_("this utility cannot be used for EFI platforms" ++ " because it does not support UEFI Secure Boot")); ++ break; ++ default: ++ is_efi = 0; ++ break; ++ } ++ + { + char *platname = grub_install_get_platform_name (platform); + fprintf (stderr, _("Installing for %s platform.\n"), platname); +@@ -1011,28 +1027,7 @@ main (int argc, char *argv[]) + grub_hostfs_init (); + grub_host_init (); + +- switch (platform) +- { +- case GRUB_INSTALL_PLATFORM_I386_EFI: +- case GRUB_INSTALL_PLATFORM_X86_64_EFI: +- case GRUB_INSTALL_PLATFORM_ARM_EFI: +- case GRUB_INSTALL_PLATFORM_ARM64_EFI: +- case GRUB_INSTALL_PLATFORM_RISCV32_EFI: +- case GRUB_INSTALL_PLATFORM_RISCV64_EFI: +- case GRUB_INSTALL_PLATFORM_IA64_EFI: +- is_efi = 1; +- break; +- default: +- is_efi = 0; +- break; +- +- /* pacify warning. */ +- case GRUB_INSTALL_PLATFORM_MAX: +- break; +- } +- + /* Find the EFI System Partition. */ +- + if (is_efi) + { + grub_fs_t fs; +diff --git a/docs/grub.texi b/docs/grub.texi +index 04ed6ac1f0..4870faaa00 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6509,6 +6509,13 @@ grub2-install @var{install_device} + The device name @var{install_device} is an OS device name or a GRUB + device name. + ++In order to support UEFI Secure Boot, the resulting GRUB EFI binary must ++be signed by a recognized private key. For this reason, for EFI ++platforms, most distributions also ship prebuilt GRUB EFI binaries ++signed by a distribution-specific private key. In this case, however, ++@command{grub2-install} should not be used because it would overwrite ++the signed EFI binary. ++ + @command{grub2-install} accepts the following options: + + @table @option diff --git a/SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch b/SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch new file mode 100644 index 0000000..ec5b30b --- /dev/null +++ b/SOURCES/0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 14:57:41 +0100 +Subject: [PATCH] New --with-debug-timestamps configure flag to prepend debug + traces with absolute and relative timestamp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + configure.ac | 18 ++++++++++++++++++ + grub-core/kern/misc.c | 20 ++++++++++++++++++++ + config.h.in | 1 + + 3 files changed, 39 insertions(+) + +diff --git a/configure.ac b/configure.ac +index a02d40a05b..ab0d326f00 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1585,6 +1585,17 @@ else + fi + AC_SUBST([BOOT_TIME_STATS]) + ++AC_ARG_WITH([debug-timestamps], ++ AS_HELP_STRING([--with-debug-timestamps], ++ [prepend debug traces with absolute and relative timestamps])) ++ ++if test x$with_debug_timestamps = xyes; then ++ DEBUG_WITH_TIMESTAMPS=1 ++else ++ DEBUG_WITH_TIMESTAMPS=0 ++fi ++AC_SUBST([DEBUG_WITH_TIMESTAMPS]) ++ + AC_ARG_ENABLE([grub-emu-sdl], + [AS_HELP_STRING([--enable-grub-emu-sdl], + [build and install the `grub-emu' debugging utility with SDL support (default=guessed)])]) +@@ -2136,6 +2147,7 @@ AM_CONDITIONAL([COND_APPLE_LINKER], [test x$TARGET_APPLE_LINKER = x1]) + AM_CONDITIONAL([COND_ENABLE_EFIEMU], [test x$enable_efiemu = xyes]) + AM_CONDITIONAL([COND_ENABLE_CACHE_STATS], [test x$DISK_CACHE_STATS = x1]) + AM_CONDITIONAL([COND_ENABLE_BOOT_TIME_STATS], [test x$BOOT_TIME_STATS = x1]) ++AM_CONDITIONAL([COND_DEBUG_WITH_TIMESTAMPS], [test x$DEBUG_WITH_TIMESTAMPS = x1]) + + AM_CONDITIONAL([COND_HAVE_CXX], [test x$HAVE_CXX = xyes]) + +@@ -2231,6 +2243,12 @@ else + echo With boot time statistics: No + fi + ++if [ x"$with_debug_timestamps" = xyes ]; then ++echo Debug traces with timestamps: Yes ++else ++echo Debug traces with timestamps: No ++fi ++ + if [ x"$efiemu_excuse" = x ]; then + echo efiemu runtime: Yes + else +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 578bf51a5f..9f54b6b7d2 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -25,6 +25,9 @@ + #include + #include + #include ++#if DEBUG_WITH_TIMESTAMPS ++#include ++#endif + + union printf_arg + { +@@ -192,9 +195,26 @@ grub_real_dprintf (const char *file, const int line, const char *condition, + const char *fmt, ...) + { + va_list args; ++#if DEBUG_WITH_TIMESTAMPS ++ static long unsigned int last_time = 0; ++ static int last_had_cr = 1; ++#endif + + if (grub_debug_enabled (condition)) + { ++#if DEBUG_WITH_TIMESTAMPS ++ /* Don't print timestamp if last printed message isn't terminated yet */ ++ if (last_had_cr) { ++ long unsigned int tmabs = (long unsigned int) grub_get_time_ms(); ++ long unsigned int tmrel = tmabs - last_time; ++ last_time = tmabs; ++ grub_printf ("%3lu.%03lus +%2lu.%03lus ", tmabs / 1000, tmabs % 1000, tmrel / 1000, tmrel % 1000); ++ } ++ if (fmt[grub_strlen(fmt)-1] == '\n') ++ last_had_cr = 1; ++ else ++ last_had_cr = 0; ++#endif + grub_printf ("%s:%d: ", file, line); + va_start (args, fmt); + grub_vprintf (fmt, args); +diff --git a/config.h.in b/config.h.in +index c7e316f0f1..c80e3e0aba 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -12,6 +12,7 @@ + /* Define to 1 to enable disk cache statistics. */ + #define DISK_CACHE_STATS @DISK_CACHE_STATS@ + #define BOOT_TIME_STATS @BOOT_TIME_STATS@ ++#define DEBUG_WITH_TIMESTAMPS @DEBUG_WITH_TIMESTAMPS@ + + /* We don't need those. */ + #define MINILZO_CFG_SKIP_LZO_PTR 1 diff --git a/SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch b/SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch new file mode 100644 index 0000000..d26027c --- /dev/null +++ b/SOURCES/0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 15:22:16 +0100 +Subject: [PATCH] Added debug statements to grub_disk_open() and + grub_disk_close() on success +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/kern/disk.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c +index e1b0e073e0..05a28ab142 100644 +--- a/grub-core/kern/disk.c ++++ b/grub-core/kern/disk.c +@@ -285,6 +285,8 @@ grub_disk_open (const char *name) + return 0; + } + ++ grub_dprintf ("disk", "Opening `%s' succeeded.\n", name); ++ + return disk; + } + +@@ -292,7 +294,7 @@ void + grub_disk_close (grub_disk_t disk) + { + grub_partition_t part; +- grub_dprintf ("disk", "Closing `%s'.\n", disk->name); ++ grub_dprintf ("disk", "Closing `%s'...\n", disk->name); + + if (disk->dev && disk->dev->disk_close) + (disk->dev->disk_close) (disk); +@@ -306,8 +308,10 @@ grub_disk_close (grub_disk_t disk) + grub_free (disk->partition); + disk->partition = part; + } ++ grub_dprintf ("disk", "Closing `%s' succeeded.\n", disk->name); + grub_free ((void *) disk->name); + grub_free (disk); ++ + } + + /* Small read (less than cache size and not pass across cache unit boundaries). diff --git a/SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch b/SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch new file mode 100644 index 0000000..9ce5d9d --- /dev/null +++ b/SOURCES/0147-Introduce-function-grub_debug_is_enabled-void-return.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Mon, 25 Nov 2019 09:29:53 +0100 +Subject: [PATCH] Introduce function grub_debug_is_enabled(void) returning 1 if + 'debug' is in the environment and not empty +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/kern/misc.c | 13 +++++++++++++ + include/grub/misc.h | 1 + + 2 files changed, 14 insertions(+) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 9f54b6b7d2..a186ad3dd4 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -163,6 +163,19 @@ int grub_err_printf (const char *fmt, ...) + __attribute__ ((alias("grub_printf"))); + #endif + ++/* Return 1 if 'debug' is set and not empty */ ++int ++grub_debug_is_enabled (void) ++{ ++ const char *debug; ++ ++ debug = grub_env_get ("debug"); ++ if (!debug || debug[0] == '\0') ++ return 0; ++ ++ return 1; ++} ++ + int + grub_debug_enabled (const char * condition) + { +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 3adc4036e3..6c4aa85ac5 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -340,6 +340,7 @@ grub_puts (const char *s) + } + + int EXPORT_FUNC(grub_puts_) (const char *s); ++int EXPORT_FUNC(grub_debug_is_enabled) (void); + int EXPORT_FUNC(grub_debug_enabled) (const char *condition); + void EXPORT_FUNC(grub_real_dprintf) (const char *file, + const int line, diff --git a/SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch b/SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch new file mode 100644 index 0000000..c35d8a3 --- /dev/null +++ b/SOURCES/0148-Don-t-clear-screen-when-debugging-is-enabled.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 16:23:54 +0100 +Subject: [PATCH] Don't clear screen when debugging is enabled +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +[rharwood@redhat.com: rebase fuzz] +Signed-off-by: Robbie Harwood +--- + grub-core/normal/main.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index af9792c963..7de9e4c36d 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -215,8 +215,9 @@ grub_normal_init_page (struct grub_term_output *term, + char *msg_formatted; + grub_uint32_t *unicode_msg; + grub_uint32_t *last_position; +- +- grub_term_cls (term); ++ ++ if (! grub_debug_is_enabled ()) ++ grub_term_cls (term); + + msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION); + if (!msg_formatted) diff --git a/SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch b/SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch new file mode 100644 index 0000000..e444325 --- /dev/null +++ b/SOURCES/0149-kern-file-Fix-error-handling-in-grub_file_open.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Steve McIntyre +Date: Tue, 6 Dec 2022 01:45:11 +0000 +Subject: [PATCH] kern/file: Fix error handling in grub_file_open() + +grub_file_open() calls grub_file_get_device_name(), but doesn't check +the return. Instead, it checks if grub_errno is set. + +However, nothing initialises grub_errno here when grub_file_open() +starts. This means that trying to open one file that doesn't exist and +then trying to open another file that does will (incorrectly) also +fail to open that second file. + +Let's fix that. + +Signed-off-by: Steve McIntyre +--- + grub-core/kern/file.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 58454458c4..5b58f45cfd 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -66,6 +66,9 @@ grub_file_open (const char *name, enum grub_file_type type) + const char *file_name; + grub_file_filter_id_t filter; + ++ /* Reset grub_errno before we start */ ++ grub_errno = GRUB_ERR_NONE; ++ + device_name = grub_file_get_device_name (name); + if (grub_errno) + goto fail; diff --git a/SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch b/SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch new file mode 100644 index 0000000..6327899 --- /dev/null +++ b/SOURCES/0150-grub_file_-instrumentation-new-file-debug-tag.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Fri, 29 Nov 2019 11:02:00 +0100 +Subject: [PATCH] grub_file_* instrumentation (new 'file' debug tag) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Renaud Métrich +--- + grub-core/kern/file.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 5b58f45cfd..ec10e54fc0 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -66,6 +66,8 @@ grub_file_open (const char *name, enum grub_file_type type) + const char *file_name; + grub_file_filter_id_t filter; + ++ grub_dprintf ("file", "Opening `%s' ...\n", name); ++ + /* Reset grub_errno before we start */ + grub_errno = GRUB_ERR_NONE; + +@@ -131,6 +133,8 @@ grub_file_open (const char *name, enum grub_file_type type) + if (!file) + grub_file_close (last_file); + ++ grub_dprintf ("file", "Opening `%s' succeeded.\n", name); ++ + return file; + + fail: +@@ -141,6 +145,8 @@ grub_file_open (const char *name, enum grub_file_type type) + + grub_free (file); + ++ grub_dprintf ("file", "Opening `%s' failed.\n", name); ++ + return 0; + } + +@@ -172,6 +178,7 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + + if (len == 0) + return 0; ++ + read_hook = file->read_hook; + read_hook_data = file->read_hook_data; + if (!file->read_hook) +@@ -192,11 +199,18 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + grub_err_t + grub_file_close (grub_file_t file) + { ++ grub_dprintf ("file", "Closing `%s' ...\n", file->name); + if (file->fs->fs_close) + (file->fs->fs_close) (file); + + if (file->device) + grub_device_close (file->device); ++ ++ if (grub_errno == GRUB_ERR_NONE) ++ grub_dprintf ("file", "Closing `%s' succeeded.\n", file->name); ++ else ++ grub_dprintf ("file", "Closing `%s' failed with %d.\n", file->name, grub_errno); ++ + grub_free (file->name); + grub_free (file); + return grub_errno; diff --git a/SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch b/SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch new file mode 100644 index 0000000..f6c5244 --- /dev/null +++ b/SOURCES/0151-ieee1275-Avoiding-many-unecessary-open-close.patch @@ -0,0 +1,136 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 14 Dec 2020 17:42:45 +0100 +Subject: [PATCH] ieee1275: Avoiding many unecessary open/close + +Signed-off-by: Diego Domingos +--- + grub-core/disk/ieee1275/ofdisk.c | 64 ++++++++++++++++++++++------------------ + 1 file changed, 35 insertions(+), 29 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 03674cb477..ea7f78ac7d 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -44,7 +44,7 @@ struct ofdisk_hash_ent + }; + + static grub_err_t +-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, ++grub_ofdisk_get_block_size (grub_uint32_t *block_size, + struct ofdisk_hash_ent *op); + + #define OFDISK_HASH_SZ 8 +@@ -461,6 +461,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + grub_ssize_t actual; + grub_uint32_t block_size = 0; + grub_err_t err; ++ struct ofdisk_hash_ent *op; + + if (grub_strncmp (name, "ieee1275/", sizeof ("ieee1275/") - 1) != 0) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, +@@ -471,6 +472,35 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + + grub_dprintf ("disk", "Opening `%s'.\n", devpath); + ++ op = ofdisk_hash_find (devpath); ++ if (!op) ++ op = ofdisk_hash_add (devpath, NULL); ++ if (!op) ++ { ++ grub_free (devpath); ++ return grub_errno; ++ } ++ ++ /* Check if the call to open is the same to the last disk already opened */ ++ if (last_devpath && !grub_strcmp(op->open_path,last_devpath)) ++ { ++ goto finish; ++ } ++ ++ /* If not, we need to close the previous disk and open the new one */ ++ else { ++ if (last_ihandle){ ++ grub_ieee1275_close (last_ihandle); ++ } ++ last_ihandle = 0; ++ last_devpath = NULL; ++ ++ grub_ieee1275_open (op->open_path, &last_ihandle); ++ if (! last_ihandle) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); ++ last_devpath = op->open_path; ++ } ++ + if (grub_ieee1275_finddevice (devpath, &dev)) + { + grub_free (devpath); +@@ -491,25 +521,18 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a block device"); + } + ++ ++ finish: + /* XXX: There is no property to read the number of blocks. There + should be a property `#blocks', but it is not there. Perhaps it + is possible to use seek for this. */ + disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; + + { +- struct ofdisk_hash_ent *op; +- op = ofdisk_hash_find (devpath); +- if (!op) +- op = ofdisk_hash_add (devpath, NULL); +- if (!op) +- { +- grub_free (devpath); +- return grub_errno; +- } + disk->id = (unsigned long) op; + disk->data = op->open_path; + +- err = grub_ofdisk_get_block_size (devpath, &block_size, op); ++ err = grub_ofdisk_get_block_size (&block_size, op); + if (err) + { + grub_free (devpath); +@@ -532,13 +555,6 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + static void + grub_ofdisk_close (grub_disk_t disk) + { +- if (disk->data == last_devpath) +- { +- if (last_ihandle) +- grub_ieee1275_close (last_ihandle); +- last_ihandle = 0; +- last_devpath = NULL; +- } + disk->data = 0; + } + +@@ -685,7 +701,7 @@ grub_ofdisk_init (void) + } + + static grub_err_t +-grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, ++grub_ofdisk_get_block_size (grub_uint32_t *block_size, + struct ofdisk_hash_ent *op) + { + struct size_args_ieee1275 +@@ -698,16 +714,6 @@ grub_ofdisk_get_block_size (const char *device, grub_uint32_t *block_size, + grub_ieee1275_cell_t size2; + } args_ieee1275; + +- if (last_ihandle) +- grub_ieee1275_close (last_ihandle); +- +- last_ihandle = 0; +- last_devpath = NULL; +- +- grub_ieee1275_open (device, &last_ihandle); +- if (! last_ihandle) +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); +- + *block_size = 0; + + if (op->block_size_fails >= 2) diff --git a/SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch b/SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch new file mode 100644 index 0000000..04c5c32 --- /dev/null +++ b/SOURCES/0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 14 Dec 2020 17:45:28 +0100 +Subject: [PATCH] ieee1275/powerpc: implements fibre channel discovery for + ofpathname + +grub-ofpathname doesn't work with fibre channel because there is no +function currently implemented for it. +This patch enables it by prividing a function that looks for the port +name, building the entire path for OF devices. + +Signed-off-by: Diego Domingos +--- + grub-core/osdep/linux/ofpath.c | 49 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index a6153d3595..0f5d54e9f2 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -350,6 +350,38 @@ of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *devi + return ret; + } + ++ ++static void ++of_fc_port_name(const char *path, const char *subpath, char *port_name) ++{ ++ char *bname, *basepath, *p; ++ int fd; ++ ++ bname = xmalloc(sizeof(char)*150); ++ basepath = xmalloc(strlen(path)); ++ ++ /* Generate the path to get port name information from the drive */ ++ strncpy(basepath,path,subpath-path); ++ basepath[subpath-path-1] = '\0'; ++ p = get_basename(basepath); ++ snprintf(bname,sizeof(char)*150,"%s/fc_transport/%s/port_name",basepath,p); ++ ++ /* Read the information from the port name */ ++ fd = open (bname, O_RDONLY); ++ if (fd < 0) ++ grub_util_error (_("cannot open `%s': %s"), bname, strerror (errno)); ++ ++ if (read(fd,port_name,sizeof(char)*19) < 0) ++ grub_util_error (_("cannot read `%s': %s"), bname, strerror (errno)); ++ ++ sscanf(port_name,"0x%s",port_name); ++ ++ close(fd); ++ ++ free(bname); ++ free(basepath); ++} ++ + #ifdef __sparc__ + static char * + of_path_of_nvme(const char *sys_devname __attribute__((unused)), +@@ -577,6 +609,16 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev + digit_string = trailing_digits (device); + if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0) + { ++ if(strstr(of_path,"vfc-client")) ++ { ++ char * port_name = xmalloc(sizeof(char)*17); ++ of_fc_port_name(sysfs_path, p, port_name); ++ ++ snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name); ++ free(port_name); ++ } ++ else ++ { + unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun; + if (*digit_string == '\0') + { +@@ -590,6 +632,13 @@ of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *dev + snprintf(disk, sizeof (disk), + "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1)); + } ++ } ++ } else if (strstr(of_path,"fibre-channel")||(strstr(of_path,"vfc-client"))){ ++ char * port_name = xmalloc(sizeof(char)*17); ++ of_fc_port_name(sysfs_path, p, port_name); ++ ++ snprintf(disk,sizeof(disk),"/%s@%s", disk_name, port_name); ++ free(port_name); + } + else + { diff --git a/SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch b/SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch new file mode 100644 index 0000000..85dbde7 --- /dev/null +++ b/SOURCES/0153-ieee1275-powerpc-enables-device-mapper-discovery.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 14 Dec 2020 17:47:16 +0100 +Subject: [PATCH] ieee1275/powerpc: enables device mapper discovery + +this patch enables the device mapper discovery on ofpath.c. Currently, +when we are dealing with a device like /dev/dm-* the ofpath returns null +since there is no function implemented to handle this case. + +This patch implements a function that will look into /sys/block/dm-* +devices and search recursively inside slaves directory to find the root +disk. + +Signed-off-by: Diego Domingos +--- + grub-core/osdep/linux/ofpath.c | 64 +++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 63 insertions(+), 1 deletion(-) + +diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c +index 0f5d54e9f2..cc849d9c94 100644 +--- a/grub-core/osdep/linux/ofpath.c ++++ b/grub-core/osdep/linux/ofpath.c +@@ -37,6 +37,7 @@ + #include + #include + #include ++#include + + #ifdef __sparc__ + typedef enum +@@ -755,13 +756,74 @@ strip_trailing_digits (const char *p) + return new; + } + ++static char * ++get_slave_from_dm(const char * device){ ++ char *curr_device, *tmp; ++ char *directory; ++ char *ret = NULL; ++ ++ directory = grub_strdup (device); ++ tmp = get_basename(directory); ++ curr_device = grub_strdup (tmp); ++ *tmp = '\0'; ++ ++ /* Recursively check for slaves devices so we can find the root device */ ++ while ((curr_device[0] == 'd') && (curr_device[1] == 'm') && (curr_device[2] == '-')){ ++ DIR *dp; ++ struct dirent *ep; ++ char* device_path; ++ ++ device_path = grub_xasprintf ("/sys/block/%s/slaves", curr_device); ++ dp = opendir(device_path); ++ free(device_path); ++ ++ if (dp != NULL) ++ { ++ ep = readdir (dp); ++ while (ep != NULL){ ++ ++ /* avoid some system directories */ ++ if (!strcmp(ep->d_name,".")) ++ goto next_dir; ++ if (!strcmp(ep->d_name,"..")) ++ goto next_dir; ++ ++ free (curr_device); ++ free (ret); ++ curr_device = grub_strdup (ep->d_name); ++ ret = grub_xasprintf ("%s%s", directory, curr_device); ++ break; ++ ++ next_dir: ++ ep = readdir (dp); ++ continue; ++ } ++ closedir (dp); ++ } ++ else ++ grub_util_warn (_("cannot open directory `%s'"), device_path); ++ } ++ ++ free (directory); ++ free (curr_device); ++ ++ return ret; ++} ++ + char * + grub_util_devname_to_ofpath (const char *sys_devname) + { +- char *name_buf, *device, *devnode, *devicenode, *ofpath; ++ char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname; + + name_buf = xrealpath (sys_devname); + ++ realname = get_slave_from_dm (name_buf); ++ if (realname) ++ { ++ free (name_buf); ++ name_buf = realname; ++ } ++ + device = get_basename (name_buf); + devnode = strip_trailing_digits (name_buf); + devicenode = strip_trailing_digits (device); diff --git a/SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch b/SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch new file mode 100644 index 0000000..f938fd1 --- /dev/null +++ b/SOURCES/0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch @@ -0,0 +1,245 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Fri, 18 Dec 2020 15:39:26 +0100 +Subject: [PATCH] Add 'at_keyboard_fallback_set' var to force the set manually +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This seems required with HP DL380p Gen 8 systems. +Indeed, with this system, we can see the following sequence: + +1. controller is queried to get current configuration (returns 0x30 which is quite standard) +2. controller is queried to get the current keyboard set in used, using code 0xf0 (first part) +3. controller answers with 0xfa which means "ACK" (== ok) +4. then we send "0" to tell "we want to know which set your are supporting" +5. controller answers with 0xfa ("ACK") +6. controller should then give us 1, 2, 3 or 0x43, 0x41, 0x3f, but here it gives us 0xfe which means "NACK" + +Since there seems no way to determine the current set, and in fact the +controller expects set2 to be used, we need to rely on an environment +variable. +Everything has been tested on this system: using 0xFE (resend command), +making sure we wait for ACK in the 2 steps "write_mode", etc. + +Below is litterature I used to come up with "there is no other +solution": +- https://wiki.osdev.org/%228042%22_PS/2_Controller +- http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm +- http://www.s100computers.com/My%20System%20Pages/MSDOS%20Board/PC%20Keyboard.pdf + +Signed-off-by: Renaud Métrich +Signed-off-by: Robbie Harwood +--- + grub-core/term/at_keyboard.c | 121 ++++++++++++++++++++++++++++++++++--------- + 1 file changed, 96 insertions(+), 25 deletions(-) + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index 2601438260..dac0f946fe 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -31,6 +31,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_uint8_t grub_keyboard_controller_orig; + static grub_uint8_t grub_keyboard_orig_set; + struct grub_ps2_state ps2_state; ++static int fallback_set; + + static int ping_sent; + +@@ -76,6 +77,8 @@ at_command (grub_uint8_t data) + break; + return 0; + } ++ if (i == GRUB_AT_TRIES) ++ grub_dprintf ("atkeyb", "at_command() timed out! (stopped after %d tries)\n", i); + return (i != GRUB_AT_TRIES); + } + +@@ -105,6 +108,21 @@ grub_keyboard_controller_read (void) + + #endif + ++static int ++resend_last_result (void) ++{ ++ grub_uint8_t ret; ++ keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "resend_last_result: sending 0xfe\n"); ++ grub_outb (0xfe, KEYBOARD_REG_DATA); ++ ret = wait_ack (); ++ grub_dprintf ("atkeyb", "resend_last_result: wait_ack() returned 0x%x\n", ret); ++ keyboard_controller_wait_until_ready (); ++ ret = grub_inb (KEYBOARD_REG_DATA); ++ grub_dprintf ("atkeyb", "resend_last_result: read 0x%x from controller\n", ret); ++ return ret; ++} ++ + static int + write_mode (int mode) + { +@@ -113,11 +131,14 @@ write_mode (int mode) + { + grub_uint8_t ack; + keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "write_mode: sending 0xf0\n"); + grub_outb (0xf0, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); ++ grub_dprintf ("atkeyb", "write_mode: sending mode %d\n", mode); + grub_outb (mode, KEYBOARD_REG_DATA); + keyboard_controller_wait_until_ready (); + ack = wait_ack (); ++ grub_dprintf ("atkeyb", "write_mode: wait_ack() returned 0x%x\n", ack); + if (ack == GRUB_AT_NACK) + continue; + if (ack == GRUB_AT_ACK) +@@ -125,6 +146,9 @@ write_mode (int mode) + return 0; + } + ++ if (i == GRUB_AT_TRIES) ++ grub_dprintf ("atkeyb", "write_mode() timed out! (stopped after %d tries)\n", i); ++ + return (i != GRUB_AT_TRIES); + } + +@@ -132,31 +156,66 @@ static int + query_mode (void) + { + grub_uint8_t ret; ++ grub_uint64_t endtime; ++ unsigned i; + int e; ++ char *envvar; + +- e = write_mode (0); +- if (!e) { +- grub_dprintf("atkeyb", "query_mode: write_mode(0) failed\n"); +- return 0; +- } ++ for (i = 0; i < GRUB_AT_TRIES; i++) { ++ grub_dprintf ("atkeyb", "query_mode: sending command to controller\n"); ++ e = write_mode (0); ++ if (!e) { ++ grub_dprintf ("atkeyb", "query_mode: write_mode(0) failed\n"); ++ return 0; ++ } + +- do { +- keyboard_controller_wait_until_ready (); +- ret = grub_inb (KEYBOARD_REG_DATA); +- } while (ret == GRUB_AT_ACK); +- /* QEMU translates the set even in no-translate mode. */ +- if (ret == 0x43 || ret == 1) { +- grub_dprintf("atkeyb", "query_mode: returning 1 (ret=0x%x)\n", ret); +- return 1; +- } +- if (ret == 0x41 || ret == 2) { +- grub_dprintf("atkeyb", "query_mode: returning 2 (ret=0x%x)\n", ret); +- return 2; ++ endtime = grub_get_time_ms () + 20; ++ do { ++ keyboard_controller_wait_until_ready (); ++ ret = grub_inb (KEYBOARD_REG_DATA); ++ grub_dprintf ("atkeyb", "query_mode/loop: read 0x%x from controller\n", ret); ++ } while ((ret == GRUB_AT_ACK || ret == GRUB_AT_NACK) && grub_get_time_ms () < endtime); ++ if (ret == 0xfe) { ++ grub_dprintf ("atkeyb", "query_mode: asking controller to resend last result\n"); ++ ret = resend_last_result(); ++ grub_dprintf ("atkeyb", "query_mode: read 0x%x from controller\n", ret); ++ } ++ /* QEMU translates the set even in no-translate mode. */ ++ if (ret == 0x43 || ret == 1) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 1\n", ret); ++ return 1; ++ } ++ if (ret == 0x41 || ret == 2) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 2\n", ret); ++ return 2; ++ } ++ if (ret == 0x3f || ret == 3) { ++ grub_dprintf ("atkeyb", "query_mode: controller returned 0x%x, returning 3\n", ret); ++ return 3; ++ } ++ grub_dprintf ("atkeyb", "query_mode: controller returned unexpected value 0x%x, retrying\n", ret); + } +- if (ret == 0x3f || ret == 3) { +- grub_dprintf("atkeyb", "query_mode: returning 3 (ret=0x%x)\n", ret); +- return 3; ++ ++ /* ++ * Falling here means we tried querying and the controller returned something ++ * we don't understand, try to use 'at_keyboard_fallback_set' if it exists, ++ * otherwise return 0. ++ */ ++ envvar = grub_env_get ("at_keyboard_fallback_set"); ++ if (envvar) { ++ fallback_set = grub_strtoul (envvar, 0, 10); ++ if ((grub_errno) || (fallback_set < 1) || (fallback_set > 3)) { ++ grub_dprintf ("atkeyb", "WARNING: ignoring unexpected value '%s' for '%s' variable\n", ++ envvar, "at_keyboard_fallback_set"); ++ fallback_set = 0; ++ } else { ++ grub_dprintf ("atkeyb", "query_mode: '%s' specified in environment, returning %d\n", ++ "at_keyboard_fallback_set", fallback_set); ++ } ++ return fallback_set; + } ++ grub_dprintf ("atkeyb", "WARNING: no '%s' specified in environment, returning 0\n", ++ "at_keyboard_fallback_set"); + return 0; + } + +@@ -165,14 +224,25 @@ set_scancodes (void) + { + /* You must have visited computer museum. Keyboard without scancode set + knowledge. Assume XT. */ +- if (!grub_keyboard_orig_set) +- { +- grub_dprintf ("atkeyb", "No sets support assumed\n"); +- ps2_state.current_set = 1; ++ if (!grub_keyboard_orig_set) { ++ if (fallback_set) { ++ grub_dprintf ("atkeyb", "No sets support assumed but set forced to %d\n", fallback_set); ++ ps2_state.current_set = fallback_set; + return; + } ++ grub_dprintf ("atkeyb", "No sets support assumed, forcing to set 1\n"); ++ ps2_state.current_set = 1; ++ return; ++ } + + #if !USE_SCANCODE_SET ++ if (fallback_set) { ++ grub_dprintf ("atkeyb", "queried set is %d but set forced to %d\n", ++ grub_keyboard_orig_set, fallback_set); ++ ps2_state.current_set = fallback_set; ++ return; ++ } ++ + if ((grub_keyboard_controller_orig & KEYBOARD_AT_TRANSLATE) == KEYBOARD_AT_TRANSLATE) { + grub_dprintf ("atkeyb", "queried set is %d but keyboard in Translate mode, so actually in set 1\n", grub_keyboard_orig_set); + ps2_state.current_set = 1; +@@ -261,6 +331,7 @@ grub_at_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused))) + static void + grub_keyboard_controller_init (void) + { ++ grub_dprintf ("atkeyb", "initializing the controller\n"); + ps2_state.at_keyboard_status = 0; + /* Drain input buffer. */ + while (1) +@@ -282,6 +353,7 @@ grub_keyboard_controller_init (void) + grub_keyboard_controller_orig = grub_keyboard_controller_read (); + grub_dprintf ("atkeyb", "grub_keyboard_controller_orig = 0x%x\n", grub_keyboard_controller_orig); + grub_keyboard_orig_set = query_mode (); ++ grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set); + #endif + set_scancodes (); + keyboard_controller_led (ps2_state.led_status); +@@ -329,7 +401,6 @@ grub_at_restore_hw (void) + return GRUB_ERR_NONE; + } + +- + static struct grub_term_input grub_at_keyboard_term = + { + .name = "at_keyboard", diff --git a/SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch b/SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch new file mode 100644 index 0000000..81660d4 --- /dev/null +++ b/SOURCES/0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch @@ -0,0 +1,309 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Rashmica Gupta +Date: Thu, 11 Jun 2020 11:26:23 +1000 +Subject: [PATCH] Add suport for signing grub with an appended signature + +Add infrastructure to allow firmware to verify the integrity of grub +by use of a Linux-kernel-module-style appended signature. We initially +target powerpc-ieee1275, but the code should be extensible to other +platforms. + +Usually these signatures are appended to a file without modifying the +ELF file itself. (This is what the 'sign-file' tool does, for example.) +The verifier loads the signed file from the file system and looks at the +end of the file for the appended signature. However, on powerpc-ieee1275 +platforms, the bootloader is often stored directly in the PReP partition +as raw bytes without a file-system. This makes determining the location +of an appended signature more difficult. + +To address this, we add a new ELF note. + +The name field of shall be the string "Appended-Signature", zero-padded +to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values +for the string "ASig"). It must be the final section in the ELF binary. + +The description shall contain the appended signature structure as defined +by the Linux kernel. The description will also be padded to be a multiple +of 4 bytes. The padding shall be added before the appended signature +structure (not at the end) so that the final bytes of a signed ELF file +are the appended signature magic. + +A subsequent patch documents how to create a grub core.img validly signed +under this scheme. + +Signed-off-by: Daniel Axtens +Signed-off-by: Rashmica Gupta +--- + util/grub-install-common.c | 18 ++++++++++++++---- + util/grub-mkimage.c | 15 +++++++++++++-- + util/grub-mkimagexx.c | 39 ++++++++++++++++++++++++++++++++++++++- + util/mkimage.c | 13 +++++++------ + include/grub/util/install.h | 8 ++++++-- + include/grub/util/mkimage.h | 4 ++-- + 6 files changed, 80 insertions(+), 17 deletions(-) + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index 4e212e690c..a74fee16e2 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -461,10 +461,12 @@ static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; + static grub_compression_t compression; ++static size_t appsig_size; + + int + grub_install_parse (int key, char *arg) + { ++ const char *end; + switch (key) + { + case 'C': +@@ -562,6 +564,12 @@ grub_install_parse (int key, char *arg) + grub_util_error (_("Unrecognized compression `%s'"), arg); + case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE: + return 1; ++ case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE: ++ grub_errno = 0; ++ appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ return 1; + default: + return 0; + } +@@ -661,11 +669,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + " --output '%s' " + " --dtb '%s' " + "--sbat '%s' " +- "--format '%s' --compression '%s' %s %s %s\n", ++ "--format '%s' --compression '%s' " ++ "--appended-signature-size %zu %s %s %s\n", + dir, prefix, + outname, dtb ? : "", sbat ? : "", mkimage_target, +- compnames[compression], note ? "--note" : "", +- disable_shim_lock ? "--disable-shim-lock" : "", s); ++ compnames[compression], appsig_size, ++ disable_shim_lock ? "--disable-shim-lock" : "", ++ note ? "--note" : "", s); + free (s); + + tgt = grub_install_get_image_target (mkimage_target); +@@ -675,7 +685,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, + pubkeys, npubkeys, config_path, tgt, +- note, compression, dtb, sbat, ++ note, appsig_size, compression, dtb, sbat, + disable_shim_lock); + while (dc--) + grub_install_pop_module (); +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index c0d5599370..8a53310548 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -84,6 +84,7 @@ static struct argp_option options[] = { + {"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0}, + {"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, ++ {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -128,6 +129,7 @@ struct arguments + char *sbat; + int note; + int disable_shim_lock; ++ size_t appsig_size; + const struct grub_install_image_target_desc *image_target; + grub_compression_t comp; + }; +@@ -138,6 +140,7 @@ argp_parser (int key, char *arg, struct argp_state *state) + /* Get the input argument from argp_parse, which we + know is a pointer to our arguments structure. */ + struct arguments *arguments = state->input; ++ const char* end; + + switch (key) + { +@@ -170,6 +173,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->note = 1; + break; + ++ case 'S': ++ grub_errno = 0; ++ arguments->appsig_size = grub_strtol(arg, &end, 10); ++ if (grub_errno) ++ return 0; ++ break; ++ + case 'm': + if (arguments->memdisk) + free (arguments->memdisk); +@@ -324,8 +334,9 @@ main (int argc, char *argv[]) + arguments.memdisk, arguments.pubkeys, + arguments.npubkeys, arguments.config, + arguments.image_target, arguments.note, +- arguments.comp, arguments.dtb, +- arguments.sbat, arguments.disable_shim_lock); ++ arguments.appsig_size, arguments.comp, ++ arguments.dtb, arguments.sbat, ++ arguments.disable_shim_lock); + + if (grub_util_file_sync (fp) < 0) + grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout", +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index d78fa3e533..393119486d 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -84,6 +84,15 @@ struct grub_ieee1275_note + struct grub_ieee1275_note_desc descriptor; + }; + ++#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature" ++#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */ ++ ++struct grub_appended_signature_note ++{ ++ Elf32_Nhdr header; ++ char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)]; ++}; ++ + #define GRUB_XEN_NOTE_NAME "Xen" + + struct fixup_block_list +@@ -207,7 +216,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr) + + void + SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf_Addr target_addr, + struct grub_mkimage_layout *layout) + { +@@ -221,6 +230,12 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + int shnum = 4; + int string_size = sizeof (".text") + sizeof ("mods") + 1; + ++ if (appsig_size) ++ { ++ phnum++; ++ footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ } ++ + if (image_target->id != IMAGE_LOONGSON_ELF) + phnum += 2; + +@@ -484,6 +499,28 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc + phdr->p_offset = grub_host_to_target32 (header_size + program_size); + } + ++ if (appsig_size) { ++ int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4); ++ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) ++ (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ ++ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME)); ++ /* needs to sit at the end, so we round this up and sign some zero padding */ ++ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4)); ++ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE); ++ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME); ++ ++ phdr++; ++ phdr->p_type = grub_host_to_target32 (PT_NOTE); ++ phdr->p_flags = grub_host_to_target32 (PF_R); ++ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof); ++ phdr->p_vaddr = 0; ++ phdr->p_paddr = 0; ++ phdr->p_filesz = grub_host_to_target32 (note_size); ++ phdr->p_memsz = 0; ++ phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0)); ++ } ++ + { + char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr) + + shnum * sizeof (*shdr)); +diff --git a/util/mkimage.c b/util/mkimage.c +index a26cf76f72..bab1227601 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -869,8 +869,9 @@ grub_install_generate_image (const char *dir, const char *prefix, + char *memdisk_path, char **pubkey_paths, + size_t npubkeys, char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, grub_compression_t comp, const char *dtb_path, +- const char *sbat_path, int disable_shim_lock) ++ int note, size_t appsig_size, grub_compression_t comp, ++ const char *dtb_path, const char *sbat_path, ++ int disable_shim_lock) + { + char *kernel_img, *core_img; + size_t total_module_size, core_size; +@@ -1773,11 +1774,11 @@ grub_install_generate_image (const char *dir, const char *prefix, + else + target_addr = image_target->link_addr; + if (image_target->voidp_sizeof == 4) +- grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + else +- grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size, +- target_addr, &layout); ++ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img, ++ &core_size, target_addr, &layout); + } + break; + } +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index 7df3191f47..cf4531e02b 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,9 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ ++ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ ++ 1}, \ + { "verbose", 'v', 0, 0, \ + N_("print verbose messages."), 1 } + +@@ -128,7 +131,8 @@ enum grub_install_options { + GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS, + GRUB_INSTALL_OPTIONS_DTB, + GRUB_INSTALL_OPTIONS_SBAT, +- GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK ++ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, ++ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE + }; + + extern char *grub_install_source_directory; +@@ -188,7 +192,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + size_t npubkeys, + char *config_path, + const struct grub_install_image_target_desc *image_target, +- int note, ++ int note, size_t appsig_size, + grub_compression_t comp, const char *dtb_file, + const char *sbat_path, const int disable_shim_lock); + +diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h +index 3819a67441..6f1da89b9b 100644 +--- a/include/grub/util/mkimage.h ++++ b/include/grub/util/mkimage.h +@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path, + const struct grub_install_image_target_desc *image_target); + void + grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf32_Addr target_addr, + struct grub_mkimage_layout *layout); + void + grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target, +- int note, char **core_img, size_t *core_size, ++ int note, size_t appsig_size, char **core_img, size_t *core_size, + Elf64_Addr target_addr, + struct grub_mkimage_layout *layout); + diff --git a/SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch b/SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch new file mode 100644 index 0000000..f2b5c17 --- /dev/null +++ b/SOURCES/0156-docs-grub-Document-signing-grub-under-UEFI.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:00:57 +1000 +Subject: [PATCH] docs/grub: Document signing grub under UEFI + +Before adding information about how grub is signed with an appended +signature scheme, it's worth adding some information about how it +can currently be signed for UEFI. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 4870faaa00..365d1d6931 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -5817,6 +5817,7 @@ environment variables and commands are listed in the same order. + * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation + * Measured Boot:: Measuring boot components + * Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5895,7 +5896,7 @@ commands. + + GRUB's @file{core.img} can optionally provide enforcement that all files + subsequently read from disk are covered by a valid digital signature. +-This document does @strong{not} cover how to ensure that your ++This section does @strong{not} cover how to ensure that your + platform's firmware (e.g., Coreboot) validates @file{core.img}. + + If environment variable @code{check_signatures} +@@ -6067,6 +6068,25 @@ be restricted and some operations/commands cannot be executed. + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. + ++@node Signing GRUB itself ++@section Signing GRUB itself ++ ++To ensure a complete secure-boot chain, there must be a way for the code that ++loads GRUB to verify the integrity of the core image. ++ ++This is ultimately platform-specific and individual platforms can define their ++own mechanisms. However, there are general-purpose mechanisms that can be used ++with GRUB. ++ ++@section Signing GRUB for UEFI secure boot ++ ++On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed ++with a tool such as @command{pesign} or @command{sbsign}. Refer to the ++suggestions in @pxref{UEFI secure boot and shim} to ensure that the final ++image works under UEFI secure boot and can maintain the secure-boot chain. It ++will also be necessary to enrol the public key used into a relevant firmware ++key database. ++ + @node Platform limitations + @chapter Platform limitations + diff --git a/SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch b/SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch new file mode 100644 index 0000000..ee3d659 --- /dev/null +++ b/SOURCES/0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch @@ -0,0 +1,67 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 15 Aug 2020 02:19:36 +1000 +Subject: [PATCH] docs/grub: Document signing grub with an appended signature + +Signing grub for firmware that verifies an appended signature is a +bit fiddly. I don't want people to have to figure it out from scratch +so document it here. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/docs/grub.texi b/docs/grub.texi +index 365d1d6931..afbde7c1f7 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6087,6 +6087,48 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It + will also be necessary to enrol the public key used into a relevant firmware + key database. + ++@section Signing GRUB with an appended signature ++ ++The @file{core.elf} itself can be signed with a Linux kernel module-style ++appended signature. ++ ++To support IEEE1275 platforms where the boot image is often loaded directly ++from a disk partition rather than from a file system, the @file{core.elf} ++can specify the size and location of the appended signature with an ELF ++note added by @command{grub-install}. ++ ++An image can be signed this way using the @command{sign-file} command from ++the Linux kernel: ++ ++@example ++@group ++# grub.key is your private key and certificate.der is your public key ++ ++# Determine the size of the appended signature. It depends on the signing ++# certificate and the hash algorithm ++touch empty ++sign-file SHA256 grub.key certificate.der empty empty.sig ++SIG_SIZE=`stat -c '%s' empty.sig` ++rm empty empty.sig ++ ++# Build a grub image with $SIG_SIZE reserved for the signature ++grub-install --appended-signature-size $SIG_SIZE --modules="..." ... ++ ++# Replace the reserved size with a signature: ++# cut off the last $SIG_SIZE bytes with truncate's minus modifier ++truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned ++# sign the trimmed file with an appended signature, restoring the correct size ++sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed ++ ++# Don't forget to install the signed image as required ++# (e.g. on powerpc-ieee1275, to the PReP partition) ++@end group ++@end example ++ ++As with UEFI secure boot, it is necessary to build in the required modules, ++or sign them separately. ++ ++ + @node Platform limitations + @chapter Platform limitations + diff --git a/SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch b/SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch new file mode 100644 index 0000000..b23ce49 --- /dev/null +++ b/SOURCES/0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 00:13:21 +1000 +Subject: [PATCH] dl: provide a fake grub_dl_set_persistent for the emu target + +Trying to start grub-emu with a module that calls grub_dl_set_persistent +will crash because grub-emu fakes modules and passes NULL to the module +init function. + +Provide an empty function for the emu case. + +Fixes: ee7808e2197c (dl: Add support for persistent modules) +Signed-off-by: Daniel Axtens +--- + include/grub/dl.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 2f76e6b043..20d870f2a4 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -245,11 +245,22 @@ grub_dl_get (const char *name) + return 0; + } + ++#ifdef GRUB_MACHINE_EMU ++/* ++ * Under grub-emu, modules are faked and NULL is passed to GRUB_MOD_INIT. ++ * So we fake this out to avoid a NULL deref. ++ */ ++static inline void ++grub_dl_set_persistent (grub_dl_t mod __attribute__((unused))) ++{ ++} ++#else + static inline void + grub_dl_set_persistent (grub_dl_t mod) + { + mod->persistent = 1; + } ++#endif + + static inline int + grub_dl_is_persistent (grub_dl_t mod) diff --git a/SOURCES/0159-pgp-factor-out-rsa_pad.patch b/SOURCES/0159-pgp-factor-out-rsa_pad.patch new file mode 100644 index 0000000..43fd882 --- /dev/null +++ b/SOURCES/0159-pgp-factor-out-rsa_pad.patch @@ -0,0 +1,191 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 1 Oct 2020 20:23:48 +1000 +Subject: [PATCH] pgp: factor out rsa_pad + +rsa_pad does the PKCS#1 v1.5 padding for the RSA signature scheme. +We want to use it in other RSA signature verification applications. + +I considered and rejected putting it in lib/crypto.c. That file doesn't +currently require any MPI functions, but rsa_pad does. That's not so +much of a problem for the grub kernel and modules, but crypto.c also +gets built into all the grub utilities. So - despite the utils not +using any asymmetric ciphers - we would need to built the entire MPI +infrastructure in to them. + +A better and simpler solution is just to spin rsa_pad out into its own +PKCS#1 v1.5 module. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 8 ++++++ + grub-core/commands/pgp.c | 28 ++------------------- + grub-core/lib/pkcs1_v15.c | 59 +++++++++++++++++++++++++++++++++++++++++++++ + include/grub/pkcs1_v15.h | 27 +++++++++++++++++++++ + 4 files changed, 96 insertions(+), 26 deletions(-) + create mode 100644 grub-core/lib/pkcs1_v15.c + create mode 100644 include/grub/pkcs1_v15.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index dc9fea6f44..64cc758835 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2511,6 +2511,14 @@ module = { + cppflags = '$(CPPFLAGS_GCRY)'; + }; + ++module = { ++ name = pkcs1_v15; ++ common = lib/pkcs1_v15.c; ++ ++ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare'; ++ cppflags = '$(CPPFLAGS_GCRY)'; ++}; ++ + module = { + name = all_video; + common = lib/fake_module.c; +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 5daa1e9d00..2408db4994 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -411,32 +412,7 @@ static int + rsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + const gcry_md_spec_t *hash, struct grub_public_subkey *sk) + { +- grub_size_t tlen, emlen, fflen; +- grub_uint8_t *em, *emptr; +- unsigned nbits = gcry_mpi_get_nbits (sk->mpis[0]); +- int ret; +- tlen = hash->mdlen + hash->asnlen; +- emlen = (nbits + 7) / 8; +- if (emlen < tlen + 11) +- return 1; +- +- em = grub_malloc (emlen); +- if (!em) +- return 1; +- +- em[0] = 0x00; +- em[1] = 0x01; +- fflen = emlen - tlen - 3; +- for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) +- *emptr = 0xff; +- *emptr++ = 0x00; +- grub_memcpy (emptr, hash->asnoid, hash->asnlen); +- emptr += hash->asnlen; +- grub_memcpy (emptr, hval, hash->mdlen); +- +- ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); +- grub_free (em); +- return ret; ++ return grub_crypto_rsa_pad(hmpi, hval, hash, sk->mpis[0]); + } + + struct grub_pubkey_context +diff --git a/grub-core/lib/pkcs1_v15.c b/grub-core/lib/pkcs1_v15.c +new file mode 100644 +index 0000000000..dbacd563d0 +--- /dev/null ++++ b/grub-core/lib/pkcs1_v15.c +@@ -0,0 +1,59 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++/* ++ * Given a hash value 'hval', of hash specification 'hash', perform ++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' ++ * (see RFC 8017 s 9.2) and place the result in 'hmpi'. ++ */ ++gcry_err_code_t ++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, ++ const gcry_md_spec_t * hash, gcry_mpi_t mod) ++{ ++ grub_size_t tlen, emlen, fflen; ++ grub_uint8_t *em, *emptr; ++ unsigned nbits = gcry_mpi_get_nbits (mod); ++ int ret; ++ tlen = hash->mdlen + hash->asnlen; ++ emlen = (nbits + 7) / 8; ++ if (emlen < tlen + 11) ++ return GPG_ERR_TOO_SHORT; ++ ++ em = grub_malloc (emlen); ++ if (!em) ++ return 1; ++ ++ em[0] = 0x00; ++ em[1] = 0x01; ++ fflen = emlen - tlen - 3; ++ for (emptr = em + 2; emptr < em + 2 + fflen; emptr++) ++ *emptr = 0xff; ++ *emptr++ = 0x00; ++ grub_memcpy (emptr, hash->asnoid, hash->asnlen); ++ emptr += hash->asnlen; ++ grub_memcpy (emptr, hval, hash->mdlen); ++ ++ ret = gcry_mpi_scan (hmpi, GCRYMPI_FMT_USG, em, emlen, 0); ++ grub_free (em); ++ return ret; ++} +diff --git a/include/grub/pkcs1_v15.h b/include/grub/pkcs1_v15.h +new file mode 100644 +index 0000000000..5c338c84a1 +--- /dev/null ++++ b/include/grub/pkcs1_v15.h +@@ -0,0 +1,27 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++/* ++ * Given a hash value 'hval', of hash specification 'hash', perform ++ * the EMSA-PKCS1-v1_5 padding suitable for a key with modulus 'mod' ++ * (See RFC 8017 s 9.2) ++ */ ++gcry_err_code_t ++grub_crypto_rsa_pad (gcry_mpi_t * hmpi, grub_uint8_t * hval, ++ const gcry_md_spec_t * hash, gcry_mpi_t mod); ++ diff --git a/SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch b/SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch new file mode 100644 index 0000000..541474e --- /dev/null +++ b/SOURCES/0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 2 Oct 2020 10:49:26 +1000 +Subject: [PATCH] crypto: move storage for grub_crypto_pk_* to crypto.c + +The way gcry_rsa and friends (the asymmetric ciphers) are loaded for the +pgp module is a bit quirky. + +include/grub/crypto.h contains: + extern struct gcry_pk_spec *grub_crypto_pk_rsa; + +commands/pgp.c contains the actual storage: + struct gcry_pk_spec *grub_crypto_pk_rsa; + +And the module itself saves to the storage in pgp.c: + GRUB_MOD_INIT(gcry_rsa) + { + grub_crypto_pk_rsa = &_gcry_pubkey_spec_rsa; + } + +This is annoying: gcry_rsa now has a dependency on pgp! + +We want to be able to bring in gcry_rsa without bringing in PGP, +so move the storage to crypto.c. + +Previously, gcry_rsa depended on pgp and mpi. Now it depends on +crypto and mpi. As pgp depends on crypto, this doesn't add any new +module dependencies using the PGP verfier. + +[FWIW, the story is different for the symmetric ciphers. cryptodisk +and friends (zfs encryption etc) use grub_crypto_lookup_cipher_by_name() +to get a cipher handle. That depends on grub_ciphers being populated +by people calling grub_cipher_register. import_gcry.py ensures that the +symmetric ciphers call it.] + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/pgp.c | 4 ---- + grub-core/lib/crypto.c | 4 ++++ + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 2408db4994..355a43844a 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -147,10 +147,6 @@ const char *hashes[] = { + [0x0b] = "sha224" + }; + +-struct gcry_pk_spec *grub_crypto_pk_dsa; +-struct gcry_pk_spec *grub_crypto_pk_ecdsa; +-struct gcry_pk_spec *grub_crypto_pk_rsa; +- + static int + dsa_pad (gcry_mpi_t *hmpi, grub_uint8_t *hval, + const gcry_md_spec_t *hash, struct grub_public_subkey *sk); +diff --git a/grub-core/lib/crypto.c b/grub-core/lib/crypto.c +index ca334d5a40..c578128a59 100644 +--- a/grub-core/lib/crypto.c ++++ b/grub-core/lib/crypto.c +@@ -121,6 +121,10 @@ grub_md_unregister (gcry_md_spec_t *cipher) + } + } + ++struct gcry_pk_spec *grub_crypto_pk_dsa; ++struct gcry_pk_spec *grub_crypto_pk_ecdsa; ++struct gcry_pk_spec *grub_crypto_pk_rsa; ++ + void + grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, + grub_size_t inlen) diff --git a/SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch b/SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch new file mode 100644 index 0000000..3176f1b --- /dev/null +++ b/SOURCES/0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Sat, 2 May 2020 00:27:57 +1000 +Subject: [PATCH] posix_wrap: tweaks in preparation for libtasn1 + + - Define SIZEOF_UNSIGNED_LONG_INT, it's the same as + SIZEOF_UNSIGNED_LONG. + + - Define WORD_BIT, the size in bits of an int. This is a defined + in the Single Unix Specification and in gnulib's limits.h. gnulib + assumes it's 32 bits on all our platforms, including 64 bit + platforms, so we also use that value. + + - Provide strto[u]l[l] preprocessor macros that resolve to + grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we + also define HAVE_STRTOUL here. + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/posix_wrap/limits.h | 1 + + grub-core/lib/posix_wrap/stdlib.h | 8 ++++++++ + grub-core/lib/posix_wrap/sys/types.h | 1 + + 3 files changed, 10 insertions(+) + +diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h +index 7217138ffd..591dbf3289 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -37,5 +37,6 @@ + #define LONG_MAX GRUB_LONG_MAX + + #define CHAR_BIT 8 ++#define WORD_BIT 32 + + #endif +diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h +index 7a8d385e97..4634db09f2 100644 +--- a/grub-core/lib/posix_wrap/stdlib.h ++++ b/grub-core/lib/posix_wrap/stdlib.h +@@ -58,4 +58,12 @@ abs (int c) + return (c >= 0) ? c : -c; + } + ++#define strtol grub_strtol ++ ++/* for libgcrypt */ ++#define HAVE_STRTOUL ++#define strtoul grub_strtoul ++ ++#define strtoull grub_strtoull ++ + #endif +diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h +index 854eb0122e..f63412c8da 100644 +--- a/grub-core/lib/posix_wrap/sys/types.h ++++ b/grub-core/lib/posix_wrap/sys/types.h +@@ -51,6 +51,7 @@ typedef grub_uint8_t byte; + typedef grub_addr_t uintptr_t; + + #define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG ++#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG + #define SIZEOF_UNSIGNED_INT 4 + #define SIZEOF_UNSIGNED_LONG_LONG 8 + #define SIZEOF_UNSIGNED_SHORT 2 diff --git a/SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch b/SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch new file mode 100644 index 0000000..9587661 --- /dev/null +++ b/SOURCES/0162-libtasn1-import-libtasn1-4.16.0.patch @@ -0,0 +1,8934 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 10 Jun 2020 16:31:22 +1000 +Subject: [PATCH] libtasn1: import libtasn1-4.16.0 + +Import a very trimmed-down set of libtasn1 files: + +pushd /tmp +wget https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.16.0.tar.gz +popd +pushd grub-core/lib +mkdir libtasn1 +cp /tmp/libtasn1-4.16.0/{README.md,LICENSE} libtasn1/ +mkdir libtasn1/lib +cp /tmp/libtasn1-4.16.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h} libtasn1/lib +cp /tmp/libtasn1-4.16.0/lib/includes/libtasn1.h ../../include/grub/ +git add libtasn1/ ../../include/grub/libtasn1.h +popd + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/libtasn1/lib/coding.c | 1415 ++++++++++++++++++ + grub-core/lib/libtasn1/lib/decoding.c | 2478 +++++++++++++++++++++++++++++++ + grub-core/lib/libtasn1/lib/element.c | 1111 ++++++++++++++ + grub-core/lib/libtasn1/lib/errors.c | 100 ++ + grub-core/lib/libtasn1/lib/gstr.c | 74 + + grub-core/lib/libtasn1/lib/parser_aux.c | 1173 +++++++++++++++ + grub-core/lib/libtasn1/lib/structure.c | 1220 +++++++++++++++ + grub-core/lib/libtasn1/lib/element.h | 40 + + grub-core/lib/libtasn1/lib/gstr.h | 47 + + grub-core/lib/libtasn1/lib/int.h | 221 +++ + grub-core/lib/libtasn1/lib/parser_aux.h | 172 +++ + grub-core/lib/libtasn1/lib/structure.h | 45 + + include/grub/libtasn1.h | 588 ++++++++ + grub-core/lib/libtasn1/LICENSE | 16 + + grub-core/lib/libtasn1/README.md | 91 ++ + 15 files changed, 8791 insertions(+) + create mode 100644 grub-core/lib/libtasn1/lib/coding.c + create mode 100644 grub-core/lib/libtasn1/lib/decoding.c + create mode 100644 grub-core/lib/libtasn1/lib/element.c + create mode 100644 grub-core/lib/libtasn1/lib/errors.c + create mode 100644 grub-core/lib/libtasn1/lib/gstr.c + create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c + create mode 100644 grub-core/lib/libtasn1/lib/structure.c + create mode 100644 grub-core/lib/libtasn1/lib/element.h + create mode 100644 grub-core/lib/libtasn1/lib/gstr.h + create mode 100644 grub-core/lib/libtasn1/lib/int.h + create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h + create mode 100644 grub-core/lib/libtasn1/lib/structure.h + create mode 100644 include/grub/libtasn1.h + create mode 100644 grub-core/lib/libtasn1/LICENSE + create mode 100644 grub-core/lib/libtasn1/README.md + +diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c +new file mode 100644 +index 0000000000..245ea64cf0 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/coding.c +@@ -0,0 +1,1415 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: coding.c */ ++/* Description: Functions to create a DER coding of */ ++/* an ASN1 type. */ ++/*****************************************************/ ++ ++#include ++#include "parser_aux.h" ++#include ++#include "element.h" ++#include "minmax.h" ++#include ++ ++#define MAX_TAG_LEN 16 ++ ++/******************************************************/ ++/* Function : _asn1_error_description_value_not_found */ ++/* Description: creates the ErrorDescription string */ ++/* for the ASN1_VALUE_NOT_FOUND error. */ ++/* Parameters: */ ++/* node: node of the tree where the value is NULL. */ ++/* ErrorDescription: string returned. */ ++/* Return: */ ++/******************************************************/ ++static void ++_asn1_error_description_value_not_found (asn1_node node, ++ char *ErrorDescription) ++{ ++ ++ if (ErrorDescription == NULL) ++ return; ++ ++ Estrcpy (ErrorDescription, ":: value of element '"); ++ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), ++ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); ++ Estrcat (ErrorDescription, "' not found"); ++ ++} ++ ++/** ++ * asn1_length_der: ++ * @len: value to convert. ++ * @der: buffer to hold the returned encoding (may be %NULL). ++ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]). ++ * ++ * Creates the DER encoding of the provided length value. ++ * The @der buffer must have enough room for the output. The maximum ++ * length this function will encode is %ASN1_MAX_LENGTH_SIZE. ++ * ++ * To know the size of the DER encoding use a %NULL value for @der. ++ **/ ++void ++asn1_length_der (unsigned long int len, unsigned char *der, int *der_len) ++{ ++ int k; ++ unsigned char temp[ASN1_MAX_LENGTH_SIZE]; ++#if SIZEOF_UNSIGNED_LONG_INT > 8 ++ len &= 0xFFFFFFFFFFFFFFFF; ++#endif ++ ++ if (len < 128) ++ { ++ /* short form */ ++ if (der != NULL) ++ der[0] = (unsigned char) len; ++ *der_len = 1; ++ } ++ else ++ { ++ /* Long form */ ++ k = 0; ++ while (len) ++ { ++ temp[k++] = len & 0xFF; ++ len = len >> 8; ++ } ++ *der_len = k + 1; ++ if (der != NULL) ++ { ++ der[0] = ((unsigned char) k & 0x7F) + 128; ++ while (k--) ++ der[*der_len - 1 - k] = temp[k]; ++ } ++ } ++} ++ ++/******************************************************/ ++/* Function : _asn1_tag_der */ ++/* Description: creates the DER coding for the CLASS */ ++/* and TAG parameters. */ ++/* It is limited by the ASN1_MAX_TAG_SIZE variable */ ++/* Parameters: */ ++/* class: value to convert. */ ++/* tag_value: value to convert. */ ++/* ans: string returned. */ ++/* ans_len: number of meaningful bytes of ANS */ ++/* (ans[0]..ans[ans_len-1]). */ ++/* Return: */ ++/******************************************************/ ++static void ++_asn1_tag_der (unsigned char class, unsigned int tag_value, ++ unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len) ++{ ++ int k; ++ unsigned char temp[ASN1_MAX_TAG_SIZE]; ++ ++ if (tag_value < 31) ++ { ++ /* short form */ ++ ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F)); ++ *ans_len = 1; ++ } ++ else ++ { ++ /* Long form */ ++ ans[0] = (class & 0xE0) + 31; ++ k = 0; ++ while (tag_value != 0) ++ { ++ temp[k++] = tag_value & 0x7F; ++ tag_value >>= 7; ++ ++ if (k > ASN1_MAX_TAG_SIZE - 1) ++ break; /* will not encode larger tags */ ++ } ++ *ans_len = k + 1; ++ while (k--) ++ ans[*ans_len - 1 - k] = temp[k] + 128; ++ ans[*ans_len - 1] -= 128; ++ } ++} ++ ++/** ++ * asn1_octet_der: ++ * @str: the input data. ++ * @str_len: STR length (str[0]..str[*str_len-1]). ++ * @der: encoded string returned. ++ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]). ++ * ++ * Creates a length-value DER encoding for the input data. ++ * The DER encoding of the input data will be placed in the @der variable. ++ * ++ * Note that the OCTET STRING tag is not included in the output. ++ * ++ * This function does not return any value because it is expected ++ * that @der_len will contain enough bytes to store the string ++ * plus the DER encoding. The DER encoding size can be obtained using ++ * asn1_length_der(). ++ **/ ++void ++asn1_octet_der (const unsigned char *str, int str_len, ++ unsigned char *der, int *der_len) ++{ ++ int len_len; ++ ++ if (der == NULL || str_len < 0) ++ return; ++ ++ asn1_length_der (str_len, der, &len_len); ++ memcpy (der + len_len, str, str_len); ++ *der_len = str_len + len_len; ++} ++ ++ ++/** ++ * asn1_encode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @str: the string data. ++ * @str_len: the string length ++ * @tl: the encoded tag and length ++ * @tl_len: the bytes of the @tl field ++ * ++ * Creates the DER encoding for various simple ASN.1 types like strings etc. ++ * It stores the tag and length in @tl, which should have space for at least ++ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl. ++ * ++ * The complete DER encoding should consist of the value in @tl appended ++ * with the provided @str. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_encode_simple_der (unsigned int etype, const unsigned char *str, ++ unsigned int str_len, unsigned char *tl, ++ unsigned int *tl_len) ++{ ++ int tag_len, len_len; ++ unsigned tlen; ++ unsigned char der_tag[ASN1_MAX_TAG_SIZE]; ++ unsigned char der_length[ASN1_MAX_LENGTH_SIZE]; ++ unsigned char *p; ++ ++ if (str == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ if (ETYPE_OK (etype) == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* doesn't handle constructed classes */ ++ if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len); ++ ++ asn1_length_der (str_len, der_length, &len_len); ++ ++ if (tag_len <= 0 || len_len <= 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ tlen = tag_len + len_len; ++ ++ if (*tl_len < tlen) ++ return ASN1_MEM_ERROR; ++ ++ p = tl; ++ memcpy (p, der_tag, tag_len); ++ p += tag_len; ++ memcpy (p, der_length, len_len); ++ ++ *tl_len = tlen; ++ ++ return ASN1_SUCCESS; ++} ++ ++/******************************************************/ ++/* Function : _asn1_time_der */ ++/* Description: creates the DER coding for a TIME */ ++/* type (length included). */ ++/* Parameters: */ ++/* str: TIME null-terminated string. */ ++/* der: string returned. */ ++/* der_len: number of meaningful bytes of DER */ ++/* (der[0]..der[ans_len-1]). Initially it */ ++/* if must store the lenght of DER. */ ++/* Return: */ ++/* ASN1_MEM_ERROR when DER isn't big enough */ ++/* ASN1_SUCCESS otherwise */ ++/******************************************************/ ++static int ++_asn1_time_der (unsigned char *str, int str_len, unsigned char *der, ++ int *der_len) ++{ ++ int len_len; ++ int max_len; ++ ++ if (der == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ max_len = *der_len; ++ ++ asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len); ++ ++ if ((len_len + str_len) <= max_len) ++ memcpy (der + len_len, str, str_len); ++ *der_len = len_len + str_len; ++ ++ if ((*der_len) > max_len) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/* ++void ++_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str) ++{ ++ int len_len,str_len; ++ char temp[20]; ++ ++ if(str==NULL) return; ++ str_len=asn1_get_length_der(der,*der_len,&len_len); ++ if (str_len<0) return; ++ memcpy(temp,der+len_len,str_len); ++ *der_len=str_len+len_len; ++ switch(str_len) ++ { ++ case 11: ++ temp[10]=0; ++ strcat(temp,"00+0000"); ++ break; ++ case 13: ++ temp[12]=0; ++ strcat(temp,"+0000"); ++ break; ++ case 15: ++ temp[15]=0; ++ memmove(temp+12,temp+10,6); ++ temp[10]=temp[11]='0'; ++ break; ++ case 17: ++ temp[17]=0; ++ break; ++ default: ++ return; ++ } ++ strcpy(str,temp); ++} ++*/ ++ ++static ++void encode_val(uint64_t val, unsigned char *der, int max_len, int *der_len) ++{ ++ int first, k; ++ unsigned char bit7; ++ ++ first = 0; ++ for (k = sizeof(val); k >= 0; k--) ++ { ++ bit7 = (val >> (k * 7)) & 0x7F; ++ if (bit7 || first || !k) ++ { ++ if (k) ++ bit7 |= 0x80; ++ if (max_len > (*der_len)) ++ der[*der_len] = bit7; ++ (*der_len)++; ++ first = 1; ++ } ++ } ++} ++ ++/******************************************************/ ++/* Function : _asn1_object_id_der */ ++/* Description: creates the DER coding for an */ ++/* OBJECT IDENTIFIER type (length included). */ ++/* Parameters: */ ++/* str: OBJECT IDENTIFIER null-terminated string. */ ++/* der: string returned. */ ++/* der_len: number of meaningful bytes of DER */ ++/* (der[0]..der[ans_len-1]). Initially it */ ++/* must store the length of DER. */ ++/* Return: */ ++/* ASN1_MEM_ERROR when DER isn't big enough */ ++/* ASN1_SUCCESS if succesful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_object_id_der (const char *str, unsigned char *der, int *der_len) ++{ ++ int len_len, counter, max_len; ++ char *temp, *n_end, *n_start; ++ uint64_t val, val1 = 0; ++ int str_len = _asn1_strlen (str); ++ ++ max_len = *der_len; ++ *der_len = 0; ++ ++ if (der == NULL && max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ temp = malloc (str_len + 2); ++ if (temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ memcpy (temp, str, str_len); ++ temp[str_len] = '.'; ++ temp[str_len + 1] = 0; ++ ++ counter = 0; ++ n_start = temp; ++ while ((n_end = strchr (n_start, '.'))) ++ { ++ *n_end = 0; ++ val = _asn1_strtou64 (n_start, NULL, 10); ++ counter++; ++ ++ if (counter == 1) ++ { ++ val1 = val; ++ } ++ else if (counter == 2) ++ { ++ uint64_t val0; ++ ++ if (val1 > 2) ++ { ++ free(temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ else if ((val1 == 0 || val1 == 1) && val > 39) ++ { ++ free(temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ val0 = 40 * val1 + val; ++ encode_val(val0, der, max_len, der_len); ++ } ++ else ++ { ++ encode_val(val, der, max_len, der_len); ++ } ++ n_start = n_end + 1; ++ } ++ ++ asn1_length_der (*der_len, NULL, &len_len); ++ if (max_len >= (*der_len + len_len)) ++ { ++ memmove (der + len_len, der, *der_len); ++ asn1_length_der (*der_len, der, &len_len); ++ } ++ *der_len += len_len; ++ ++ free (temp); ++ ++ if (max_len < (*der_len)) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_object_id_der: ++ * @str: An object identifier in numeric, dot format. ++ * @der: buffer to hold the returned encoding (may be %NULL). ++ * @der_len: initially the size of @der; will hold the final size. ++ * @flags: must be zero ++ * ++ * Creates the DER encoding of the provided object identifier. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID ++ * if @str is not a valid OID, %ASN1_MEM_ERROR if the @der ++ * vector isn't big enough and in this case @der_len will contain the ++ * length needed. ++ **/ ++int asn1_object_id_der(const char *str, unsigned char *der, int *der_len, unsigned flags) ++{ ++ unsigned char tag_der[MAX_TAG_LEN]; ++ int tag_len = 0, r; ++ int max_len = *der_len; ++ ++ *der_len = 0; ++ ++ _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID), ETYPE_TAG (ASN1_ETYPE_OBJECT_ID), ++ tag_der, &tag_len); ++ ++ if (max_len > tag_len) ++ { ++ memcpy(der, tag_der, tag_len); ++ } ++ max_len -= tag_len; ++ der += tag_len; ++ ++ r = _asn1_object_id_der (str, der, &max_len); ++ if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS) ++ { ++ *der_len = max_len + tag_len; ++ } ++ ++ return r; ++} ++ ++static const unsigned char bit_mask[] = ++ { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 }; ++ ++/** ++ * asn1_bit_der: ++ * @str: BIT string. ++ * @bit_len: number of meaningful bits in STR. ++ * @der: string returned. ++ * @der_len: number of meaningful bytes of DER ++ * (der[0]..der[ans_len-1]). ++ * ++ * Creates a length-value DER encoding for the input data ++ * as it would have been for a BIT STRING. ++ * The DER encoded data will be copied in @der. ++ * ++ * Note that the BIT STRING tag is not included in the output. ++ * ++ * This function does not return any value because it is expected ++ * that @der_len will contain enough bytes to store the string ++ * plus the DER encoding. The DER encoding size can be obtained using ++ * asn1_length_der(). ++ **/ ++void ++asn1_bit_der (const unsigned char *str, int bit_len, ++ unsigned char *der, int *der_len) ++{ ++ int len_len, len_byte, len_pad; ++ ++ if (der == NULL) ++ return; ++ ++ len_byte = bit_len >> 3; ++ len_pad = 8 - (bit_len & 7); ++ if (len_pad == 8) ++ len_pad = 0; ++ else ++ len_byte++; ++ asn1_length_der (len_byte + 1, der, &len_len); ++ der[len_len] = len_pad; ++ ++ if (str) ++ memcpy (der + len_len + 1, str, len_byte); ++ der[len_len + len_byte] &= bit_mask[len_pad]; ++ *der_len = len_byte + len_len + 1; ++} ++ ++ ++/******************************************************/ ++/* Function : _asn1_complete_explicit_tag */ ++/* Description: add the length coding to the EXPLICIT */ ++/* tags. */ ++/* Parameters: */ ++/* node: pointer to the tree element. */ ++/* der: string with the DER coding of the whole tree*/ ++/* counter: number of meaningful bytes of DER */ ++/* (der[0]..der[*counter-1]). */ ++/* max_len: size of der vector */ ++/* Return: */ ++/* ASN1_MEM_ERROR if der vector isn't big enough, */ ++/* otherwise ASN1_SUCCESS. */ ++/******************************************************/ ++static int ++_asn1_complete_explicit_tag (asn1_node node, unsigned char *der, ++ int *counter, int *max_len) ++{ ++ asn1_node p; ++ int is_tag_implicit, len2, len3; ++ unsigned char temp[SIZEOF_UNSIGNED_INT]; ++ ++ if (der == NULL && *max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ if (p == NULL) ++ return ASN1_DER_ERROR; ++ /* When there are nested tags we must complete them reverse to ++ the order they were created. This is because completing a tag ++ modifies all data within it, including the incomplete tags ++ which store buffer positions -- simon@josefsson.org 2002-09-06 ++ */ ++ while (p->right) ++ p = p->right; ++ while (p && p != node->down->left) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_EXPLICIT) ++ { ++ len2 = strtol (p->name, NULL, 10); ++ _asn1_set_name (p, NULL); ++ ++ asn1_length_der (*counter - len2, temp, &len3); ++ if (len3 <= (*max_len)) ++ { ++ memmove (der + len2 + len3, der + len2, ++ *counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ *max_len -= len3; ++ *counter += len3; ++ is_tag_implicit = 0; ++ } ++ else ++ { /* CONST_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->left; ++ } ++ } ++ ++ if (*max_len < 0) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++const tag_and_class_st _asn1_tags[] = { ++ [ASN1_ETYPE_GENERALSTRING] = ++ {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"}, ++ [ASN1_ETYPE_NUMERIC_STRING] = ++ {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"}, ++ [ASN1_ETYPE_IA5_STRING] = ++ {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"}, ++ [ASN1_ETYPE_TELETEX_STRING] = ++ {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"}, ++ [ASN1_ETYPE_PRINTABLE_STRING] = ++ {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"}, ++ [ASN1_ETYPE_UNIVERSAL_STRING] = ++ {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"}, ++ [ASN1_ETYPE_BMP_STRING] = ++ {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"}, ++ [ASN1_ETYPE_UTF8_STRING] = ++ {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"}, ++ [ASN1_ETYPE_VISIBLE_STRING] = ++ {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"}, ++ [ASN1_ETYPE_OCTET_STRING] = ++ {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"}, ++ [ASN1_ETYPE_BIT_STRING] = ++ {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"}, ++ [ASN1_ETYPE_OBJECT_ID] = ++ {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"}, ++ [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"}, ++ [ASN1_ETYPE_BOOLEAN] = ++ {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"}, ++ [ASN1_ETYPE_INTEGER] = ++ {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"}, ++ [ASN1_ETYPE_ENUMERATED] = ++ {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"}, ++ [ASN1_ETYPE_SEQUENCE] = ++ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SEQUENCE"}, ++ [ASN1_ETYPE_SEQUENCE_OF] = ++ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SEQ_OF"}, ++ [ASN1_ETYPE_SET] = ++ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"}, ++ [ASN1_ETYPE_SET_OF] = ++ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, ++ "type:SET_OF"}, ++ [ASN1_ETYPE_GENERALIZED_TIME] = ++ {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"}, ++ [ASN1_ETYPE_UTC_TIME] = ++ {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"}, ++}; ++ ++unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); ++ ++/******************************************************/ ++/* Function : _asn1_insert_tag_der */ ++/* Description: creates the DER coding of tags of one */ ++/* NODE. */ ++/* Parameters: */ ++/* node: pointer to the tree element. */ ++/* der: string returned */ ++/* counter: number of meaningful bytes of DER */ ++/* (counter[0]..der[*counter-1]). */ ++/* max_len: size of der vector */ ++/* Return: */ ++/* ASN1_GENERIC_ERROR if the type is unknown, */ ++/* ASN1_MEM_ERROR if der vector isn't big enough, */ ++/* otherwise ASN1_SUCCESS. */ ++/******************************************************/ ++static int ++_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter, ++ int *max_len) ++{ ++ asn1_node p; ++ int tag_len, is_tag_implicit; ++ unsigned char class, class_implicit = 0, temp[MAX(SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)]; ++ unsigned long tag_implicit = 0; ++ unsigned char tag_der[MAX_TAG_LEN]; ++ ++ is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_APPLICATION) ++ class = ASN1_CLASS_APPLICATION; ++ else if (p->type & CONST_UNIVERSAL) ++ class = ASN1_CLASS_UNIVERSAL; ++ else if (p->type & CONST_PRIVATE) ++ class = ASN1_CLASS_PRIVATE; ++ else ++ class = ASN1_CLASS_CONTEXT_SPECIFIC; ++ ++ if (p->type & CONST_EXPLICIT) ++ { ++ if (is_tag_implicit) ++ _asn1_tag_der (class_implicit, tag_implicit, tag_der, ++ &tag_len); ++ else ++ _asn1_tag_der (class | ASN1_CLASS_STRUCTURED, ++ _asn1_strtoul (p->value, NULL, 10), ++ tag_der, &tag_len); ++ ++ *max_len -= tag_len; ++ if (der && *max_len >= 0) ++ memcpy (der + *counter, tag_der, tag_len); ++ *counter += tag_len; ++ ++ _asn1_ltostr (*counter, (char *) temp); ++ _asn1_set_name (p, (const char *) temp); ++ ++ is_tag_implicit = 0; ++ } ++ else ++ { /* CONST_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || ++ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) ++ || (type_field (node->type) == ASN1_ETYPE_SET) ++ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) ++ class |= ASN1_CLASS_STRUCTURED; ++ class_implicit = class; ++ tag_implicit = _asn1_strtoul (p->value, NULL, 10); ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->right; ++ } ++ } ++ ++ if (is_tag_implicit) ++ { ++ _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len); ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ switch (type) ++ { ++ CASE_HANDLED_ETYPES: ++ _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag, ++ tag_der, &tag_len); ++ break; ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_ANY: ++ tag_len = 0; ++ break; ++ default: ++ return ASN1_GENERIC_ERROR; ++ } ++ } ++ ++ *max_len -= tag_len; ++ if (der && *max_len >= 0) ++ memcpy (der + *counter, tag_der, tag_len); ++ *counter += tag_len; ++ ++ if (*max_len < 0) ++ return ASN1_MEM_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/******************************************************/ ++/* Function : _asn1_ordering_set */ ++/* Description: puts the elements of a SET type in */ ++/* the correct order according to DER rules. */ ++/* Parameters: */ ++/* der: string with the DER coding. */ ++/* node: pointer to the SET element. */ ++/* Return: */ ++/* ASN1_SUCCESS if successful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node) ++{ ++ struct vet ++ { ++ int end; ++ unsigned long value; ++ struct vet *next, *prev; ++ }; ++ ++ int counter, len, len2; ++ struct vet *first, *last, *p_vet, *p2_vet; ++ asn1_node p; ++ unsigned char class, *temp; ++ unsigned long tag, t; ++ int err; ++ ++ counter = 0; ++ ++ if (type_field (node->type) != ASN1_ETYPE_SET) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = node->down; ++ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || ++ (type_field (p->type) == ASN1_ETYPE_SIZE))) ++ p = p->right; ++ ++ if ((p == NULL) || (p->right == NULL)) ++ return ASN1_SUCCESS; ++ ++ first = last = NULL; ++ while (p) ++ { ++ p_vet = malloc (sizeof (struct vet)); ++ if (p_vet == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ ++ p_vet->next = NULL; ++ p_vet->prev = last; ++ if (first == NULL) ++ first = p_vet; ++ else ++ last->next = p_vet; ++ last = p_vet; ++ ++ /* tag value calculation */ ++ err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2, ++ &tag); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ ++ t = ((unsigned int)class) << 24; ++ p_vet->value = t | tag; ++ counter += len2; ++ ++ /* extraction and length */ ++ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ counter += len + len2; ++ ++ p_vet->end = counter; ++ p = p->right; ++ } ++ ++ p_vet = first; ++ ++ while (p_vet) ++ { ++ p2_vet = p_vet->next; ++ counter = 0; ++ while (p2_vet) ++ { ++ if (p_vet->value > p2_vet->value) ++ { ++ /* change position */ ++ temp = malloc (p_vet->end - counter); ++ if (temp == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ ++ memcpy (temp, der + counter, p_vet->end - counter); ++ memcpy (der + counter, der + p_vet->end, ++ p2_vet->end - p_vet->end); ++ memcpy (der + counter + p2_vet->end - p_vet->end, temp, ++ p_vet->end - counter); ++ free (temp); ++ ++ tag = p_vet->value; ++ p_vet->value = p2_vet->value; ++ p2_vet->value = tag; ++ ++ p_vet->end = counter + (p2_vet->end - p_vet->end); ++ } ++ counter = p_vet->end; ++ ++ p2_vet = p2_vet->next; ++ p_vet = p_vet->next; ++ } ++ ++ if (p_vet != first) ++ p_vet->prev->next = NULL; ++ else ++ first = NULL; ++ free (p_vet); ++ p_vet = first; ++ } ++ return ASN1_SUCCESS; ++ ++error: ++ while (first != NULL) ++ { ++ p_vet = first; ++ first = first->next; ++ free(p_vet); ++ } ++ return err; ++} ++ ++struct vet ++{ ++ unsigned char *ptr; ++ int size; ++}; ++ ++static int setof_compar(const void *_e1, const void *_e2) ++{ ++ unsigned length; ++ const struct vet *e1 = _e1, *e2 = _e2; ++ int rval; ++ ++ /* The encodings of the component values of a set-of value shall ++ * appear in ascending order, the encodings being compared ++ * as octet strings with the shorter components being ++ * padded at their trailing end with 0-octets. ++ * The padding octets are for comparison purposes and ++ * do not appear in the encodings. ++ */ ++ length = MIN(e1->size, e2->size); ++ ++ rval = memcmp(e1->ptr, e2->ptr, length); ++ if (rval == 0 && e1->size != e2->size) ++ { ++ if (e1->size > e2->size) ++ rval = 1; ++ else if (e2->size > e1->size) ++ rval = -1; ++ } ++ ++ return rval; ++} ++ ++/******************************************************/ ++/* Function : _asn1_ordering_set_of */ ++/* Description: puts the elements of a SET OF type in */ ++/* the correct order according to DER rules. */ ++/* Parameters: */ ++/* der: string with the DER coding. */ ++/* node: pointer to the SET OF element. */ ++/* Return: */ ++/* ASN1_SUCCESS if successful */ ++/* or an error value. */ ++/******************************************************/ ++static int ++_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node) ++{ ++ int counter, len, len2; ++ struct vet *list = NULL, *tlist; ++ unsigned list_size = 0; ++ struct vet *p_vet; ++ asn1_node p; ++ unsigned char class; ++ unsigned i; ++ unsigned char *out = NULL; ++ int err; ++ ++ if (der == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ counter = 0; ++ ++ if (type_field (node->type) != ASN1_ETYPE_SET_OF) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = node->down; ++ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) || ++ (type_field (p->type) == ASN1_ETYPE_SIZE))) ++ p = p->right; ++ if (p == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ p = p->right; ++ ++ if ((p == NULL) || (p->right == NULL)) ++ return ASN1_SUCCESS; ++ ++ while (p) ++ { ++ list_size++; ++ tlist = realloc (list, list_size*sizeof(struct vet)); ++ if (tlist == NULL) ++ { ++ err = ASN1_MEM_ALLOC_ERROR; ++ goto error; ++ } ++ list = tlist; ++ p_vet = &list[list_size-1]; ++ ++ p_vet->ptr = der+counter; ++ p_vet->size = 0; ++ ++ /* extraction of tag and length */ ++ if (der_len - counter > 0) ++ { ++ err = asn1_get_tag_der (der + counter, der_len - counter, &class, ++ &len, NULL); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ counter += len; ++ p_vet->size += len; ++ ++ len2 = asn1_get_length_der (der + counter, der_len - counter, &len); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ counter += len + len2; ++ p_vet->size += len + len2; ++ ++ } ++ else ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ p = p->right; ++ } ++ ++ if (counter > der_len) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ ++ qsort(list, list_size, sizeof(struct vet), setof_compar); ++ ++ out = malloc(der_len); ++ if (out == NULL) ++ { ++ err = ASN1_MEM_ERROR; ++ goto error; ++ } ++ ++ /* the sum of p_vet->size == der_len */ ++ counter = 0; ++ for (i = 0; i < list_size; i++) ++ { ++ p_vet = &list[i]; ++ memcpy(out+counter, p_vet->ptr, p_vet->size); ++ counter += p_vet->size; ++ } ++ memcpy(der, out, der_len); ++ free(out); ++ ++ err = ASN1_SUCCESS; ++ ++error: ++ free(list); ++ return err; ++} ++ ++/** ++ * asn1_der_coding: ++ * @element: pointer to an ASN1 element ++ * @name: the name of the structure you want to encode (it must be ++ * inside *POINTER). ++ * @ider: vector that will contain the DER encoding. DER must be a ++ * pointer to memory cells already allocated. ++ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy ++ * holds the sizeof of der vector. ++ * @ErrorDescription: return the error description or an empty ++ * string if success. ++ * ++ * Creates the DER encoding for the NAME structure (inside *POINTER ++ * structure). ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there ++ * is an element without a value, %ASN1_MEM_ERROR if the @ider ++ * vector isn't big enough and in this case @len will contain the ++ * length needed. ++ **/ ++int ++asn1_der_coding (asn1_node_const element, const char *name, void *ider, int *len, ++ char *ErrorDescription) ++{ ++ asn1_node node, p, p2; ++ unsigned char temp[MAX(LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)]; ++ int counter, counter_old, len2, len3, move, max_len, max_len_old; ++ int err; ++ unsigned char *der = ider; ++ ++ if (ErrorDescription) ++ ErrorDescription[0] = 0; ++ ++ node = asn1_find_node (element, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ /* Node is now a locally allocated variable. ++ * That is because in some point we modify the ++ * structure, and I don't know why! --nmav ++ */ ++ node = _asn1_copy_structure3 (node); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ max_len = *len; ++ ++ if (der == NULL && max_len > 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ counter = 0; ++ move = DOWN; ++ p = node; ++ ++ while (1) ++ { ++ ++ counter_old = counter; ++ max_len_old = max_len; ++ if (move != UP) ++ { ++ p->start = counter; ++ err = _asn1_insert_tag_der (p, der, &counter, &max_len); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ } ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_NULL: ++ max_len--; ++ if (der != NULL && max_len >= 0) ++ der[counter] = 0; ++ counter++; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ max_len -= 2; ++ if (der != NULL && max_len >= 0) ++ { ++ der[counter++] = 1; ++ if (p->value[0] == 'F') ++ der[counter++] = 0; ++ else ++ der[counter++] = 0xFF; ++ } ++ else ++ counter += 2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2 + len3; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value, len3 + len2); ++ counter += len3 + len2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if ((p->type & CONST_DEFAULT) && (p->value == NULL)) ++ { ++ counter = counter_old; ++ max_len = max_len_old; ++ } ++ else ++ { ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ++ ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = max_len; ++ err = _asn1_object_id_der ((char*)p->value, der + counter, &len2); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ ++ max_len -= len2; ++ counter += len2; ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = max_len; ++ err = _asn1_time_der (p->value, p->value_len, der + counter, &len2); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ ++ max_len -= len2; ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2 + len3; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SET: ++ if (move != UP) ++ { ++ p->tmp_ival = counter; ++ if (p->down == NULL) ++ { ++ move = UP; ++ continue; ++ } ++ else ++ { ++ p2 = p->down; ++ while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG)) ++ p2 = p2->right; ++ if (p2) ++ { ++ p = p2; ++ move = RIGHT; ++ continue; ++ } ++ move = UP; ++ continue; ++ } ++ } ++ else ++ { /* move==UP */ ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0)) ++ { ++ err = _asn1_ordering_set (der + len2, counter - len2, p); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ } ++ asn1_length_der (counter - len2, temp, &len3); ++ max_len -= len3; ++ if (der != NULL && max_len >= 0) ++ { ++ memmove (der + len2 + len3, der + len2, counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ counter += len3; ++ move = RIGHT; ++ } ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (move != UP) ++ { ++ p->tmp_ival = counter; ++ p = p->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ if (p->right) ++ { ++ p = p->right; ++ move = RIGHT; ++ continue; ++ } ++ else ++ p = _asn1_find_up (p); ++ move = UP; ++ } ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if ((type_field (p->type) == ASN1_ETYPE_SET_OF) ++ && (counter - len2 > 0) && (max_len >= 0)) ++ { ++ err = _asn1_ordering_set_of (der + len2, counter - len2, p); ++ if (err != ASN1_SUCCESS) ++ goto error; ++ } ++ asn1_length_der (counter - len2, temp, &len3); ++ max_len -= len3; ++ if (der != NULL && max_len >= 0) ++ { ++ memmove (der + len2 + len3, der + len2, counter - len2); ++ memcpy (der + len2, temp, len3); ++ } ++ counter += len3; ++ move = RIGHT; ++ } ++ break; ++ case ASN1_ETYPE_ANY: ++ if (p->value == NULL) ++ { ++ _asn1_error_description_value_not_found (p, ErrorDescription); ++ err = ASN1_VALUE_NOT_FOUND; ++ goto error; ++ } ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ if (len2 < 0) ++ { ++ err = ASN1_DER_ERROR; ++ goto error; ++ } ++ max_len -= len2; ++ if (der != NULL && max_len >= 0) ++ memcpy (der + counter, p->value + len3, len2); ++ counter += len2; ++ move = RIGHT; ++ break; ++ default: ++ move = (move == UP) ? RIGHT : DOWN; ++ break; ++ } ++ ++ if ((move != DOWN) && (counter != counter_old)) ++ { ++ p->end = counter - 1; ++ err = _asn1_complete_explicit_tag (p, der, &counter, &max_len); ++ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR) ++ goto error; ++ } ++ ++ if (p == node && move != DOWN) ++ break; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ *len = counter; ++ ++ if (max_len < 0) ++ { ++ err = ASN1_MEM_ERROR; ++ goto error; ++ } ++ ++ err = ASN1_SUCCESS; ++ ++error: ++ asn1_delete_structure (&node); ++ return err; ++} +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +new file mode 100644 +index 0000000000..ff04eb778c +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -0,0 +1,2478 @@ ++/* ++ * Copyright (C) 2002-2016 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: decoding.c */ ++/* Description: Functions to manage DER decoding */ ++/*****************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef DEBUG ++# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) ++#else ++# define warn() ++#endif ++ ++#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0)) ++ ++#define HAVE_TWO(x) (x>=2?1:0) ++ ++/* Decoding flags (dflags) used in several decoding functions. ++ * DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag ++ * DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful ++ * when no tags are present). ++ * DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings. ++ * DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings. ++ * DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings. ++ * This is the maximum levels of recursion possible to prevent stack ++ * exhaustion. ++ */ ++ ++#define DECODE_FLAG_HAVE_TAG 1 ++#define DECODE_FLAG_CONSTRUCTED (1<<1) ++#define DECODE_FLAG_LEVEL1 (1<<2) ++#define DECODE_FLAG_LEVEL2 (1<<3) ++#define DECODE_FLAG_LEVEL3 (1<<4) ++ ++#define DECR_LEN(l, s) do { \ ++ l -= s; \ ++ if (l < 0) { \ ++ warn(); \ ++ result = ASN1_DER_ERROR; \ ++ goto cleanup; \ ++ } \ ++ } while (0) ++ ++static int ++_asn1_get_indefinite_length_string (const unsigned char *der, int der_len, int *len); ++ ++static int ++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len, ++ unsigned dflags); ++ ++static int ++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len, unsigned dflags); ++ ++static void ++_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription) ++{ ++ ++ Estrcpy (ErrorDescription, ":: tag error near element '"); ++ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription), ++ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40); ++ Estrcat (ErrorDescription, "'"); ++ ++} ++ ++/** ++ * asn1_get_length_der: ++ * @der: DER data to decode. ++ * @der_len: Length of DER data to decode. ++ * @len: Output variable containing the length of the DER length field. ++ * ++ * Extract a length field from DER data. ++ * ++ * Returns: Return the decoded length value, or -1 on indefinite ++ * length, or -2 when the value was too big to fit in a int, or -4 ++ * when the decoded length value plus @len would exceed @der_len. ++ **/ ++long ++asn1_get_length_der (const unsigned char *der, int der_len, int *len) ++{ ++ unsigned int ans; ++ int k, punt, sum; ++ ++ *len = 0; ++ if (der_len <= 0) ++ return 0; ++ ++ if (!(der[0] & 128)) ++ { ++ /* short form */ ++ *len = 1; ++ ans = der[0]; ++ } ++ else ++ { ++ /* Long form */ ++ k = der[0] & 0x7F; ++ punt = 1; ++ if (k) ++ { /* definite length method */ ++ ans = 0; ++ while (punt <= k && punt < der_len) ++ { ++ if (INT_MULTIPLY_OVERFLOW (ans, 256)) ++ return -2; ++ ans *= 256; ++ ++ if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt]))) ++ return -2; ++ ans += der[punt]; ++ punt++; ++ } ++ } ++ else ++ { /* indefinite length method */ ++ *len = punt; ++ return -1; ++ } ++ ++ *len = punt; ++ } ++ ++ sum = ans; ++ if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len))) ++ return -2; ++ sum += *len; ++ ++ if (sum > der_len) ++ return -4; ++ ++ return ans; ++} ++ ++/** ++ * asn1_get_tag_der: ++ * @der: DER data to decode. ++ * @der_len: Length of DER data to decode. ++ * @cls: Output variable containing decoded class. ++ * @len: Output variable containing the length of the DER TAG data. ++ * @tag: Output variable containing the decoded tag (may be %NULL). ++ * ++ * Decode the class and TAG from DER code. ++ * ++ * Returns: Returns %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_tag_der (const unsigned char *der, int der_len, ++ unsigned char *cls, int *len, unsigned long *tag) ++{ ++ unsigned int ris; ++ int punt; ++ ++ if (der == NULL || der_len < 2 || len == NULL) ++ return ASN1_DER_ERROR; ++ ++ *cls = der[0] & 0xE0; ++ if ((der[0] & 0x1F) != 0x1F) ++ { ++ /* short form */ ++ *len = 1; ++ ris = der[0] & 0x1F; ++ } ++ else ++ { ++ /* Long form */ ++ punt = 1; ++ ris = 0; ++ while (punt < der_len && der[punt] & 128) ++ { ++ ++ if (INT_MULTIPLY_OVERFLOW (ris, 128)) ++ return ASN1_DER_ERROR; ++ ris *= 128; ++ ++ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) ++ return ASN1_DER_ERROR; ++ ris += (der[punt] & 0x7F); ++ punt++; ++ } ++ ++ if (punt >= der_len) ++ return ASN1_DER_ERROR; ++ ++ if (INT_MULTIPLY_OVERFLOW (ris, 128)) ++ return ASN1_DER_ERROR; ++ ris *= 128; ++ ++ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F)))) ++ return ASN1_DER_ERROR; ++ ris += (der[punt] & 0x7F); ++ punt++; ++ ++ *len = punt; ++ } ++ ++ if (tag) ++ *tag = ris; ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_length_ber: ++ * @ber: BER data to decode. ++ * @ber_len: Length of BER data to decode. ++ * @len: Output variable containing the length of the BER length field. ++ * ++ * Extract a length field from BER data. The difference to ++ * asn1_get_length_der() is that this function will return a length ++ * even if the value has indefinite encoding. ++ * ++ * Returns: Return the decoded length value, or negative value when ++ * the value was too big. ++ * ++ * Since: 2.0 ++ **/ ++long ++asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len) ++{ ++ int ret; ++ long err; ++ ++ ret = asn1_get_length_der (ber, ber_len, len); ++ ++ if (ret == -1 && ber_len > 1) ++ { /* indefinite length method */ ++ err = _asn1_get_indefinite_length_string (ber + 1, ber_len-1, &ret); ++ if (err != ASN1_SUCCESS) ++ return -3; ++ } ++ ++ return ret; ++} ++ ++/** ++ * asn1_get_octet_der: ++ * @der: DER data to decode containing the OCTET SEQUENCE. ++ * @der_len: The length of the @der data to decode. ++ * @ret_len: Output variable containing the encoded length of the DER data. ++ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE. ++ * ++ * Extract an OCTET SEQUENCE from DER data. Note that this function ++ * expects the DER data past the tag field, i.e., the length and ++ * content octets. ++ * ++ * Returns: Returns %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_octet_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, int str_size, ++ int *str_len) ++{ ++ int len_len = 0; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ *str_len = asn1_get_length_der (der, der_len, &len_len); ++ ++ if (*str_len < 0) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = *str_len + len_len; ++ if (str_size >= *str_len) ++ { ++ if (*str_len > 0 && str != NULL) ++ memcpy (str, der + len_len, *str_len); ++ } ++ else ++ { ++ return ASN1_MEM_ERROR; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/*- ++ * _asn1_get_time_der: ++ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME ++ * @der: DER data to decode containing the time ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put the textual time in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER ++ * ++ * Performs basic checks in the DER encoded time object and returns its textual form. ++ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime ++ * and YYMMDD000000Z for UTCTime. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ -*/ ++static int ++_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len, ++ char *str, int str_size, unsigned flags) ++{ ++ int len_len, str_len; ++ unsigned i; ++ unsigned sign_count = 0; ++ unsigned dot_count = 0; ++ const unsigned char *p; ++ ++ if (der_len <= 0 || str == NULL) ++ return ASN1_DER_ERROR; ++ ++ str_len = asn1_get_length_der (der, der_len, &len_len); ++ if (str_len <= 0 || str_size < str_len) ++ return ASN1_DER_ERROR; ++ ++ /* perform some sanity checks on the data */ ++ if (str_len < 8) ++ { ++ warn(); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ ++ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME)) ++ { ++ p = &der[len_len]; ++ for (i=0;i<(unsigned)(str_len-1);i++) ++ { ++ if (c_isdigit(p[i]) == 0) ++ { ++ if (type == ASN1_ETYPE_GENERALIZED_TIME) ++ { ++ /* tolerate lax encodings */ ++ if (p[i] == '.' && dot_count == 0) ++ { ++ dot_count++; ++ continue; ++ } ++ ++ /* This is not really valid DER, but there are ++ * structures using that */ ++ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && ++ (p[i] == '+' || p[i] == '-') && sign_count == 0) ++ { ++ sign_count++; ++ continue; ++ } ++ } ++ ++ warn(); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ } ++ ++ if (sign_count == 0 && p[str_len-1] != 'Z') ++ { ++ warn(); ++ return ASN1_TIME_ENCODING_ERROR; ++ } ++ } ++ memcpy (str, der + len_len, str_len); ++ str[str_len] = 0; ++ *ret_len = str_len + len_len; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_object_id_der: ++ * @der: DER data to decode containing the OBJECT IDENTIFIER ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put the textual object id in. ++ * @str_size: Length of pre-allocated output buffer. ++ * ++ * Converts a DER encoded object identifier to its textual form. This ++ * function expects the DER object identifier without the tag. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len, ++ char *str, int str_size) ++{ ++ int len_len, len, k; ++ int leading, parsed; ++ char temp[LTOSTR_MAX_SIZE]; ++ uint64_t val, val1, val0; ++ ++ *ret_len = 0; ++ if (str && str_size > 0) ++ str[0] = 0; /* no oid */ ++ ++ if (str == NULL || der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ len = asn1_get_length_der (der, der_len, &len_len); ++ ++ if (len <= 0 || len + len_len > der_len) ++ return ASN1_DER_ERROR; ++ ++ /* leading octet can never be 0x80 */ ++ if (der[len_len] == 0x80) ++ return ASN1_DER_ERROR; ++ ++ val0 = 0; ++ ++ for (k = 0; k < len; k++) ++ { ++ if (INT_LEFT_SHIFT_OVERFLOW (val0, 7)) ++ return ASN1_DER_ERROR; ++ ++ val0 <<= 7; ++ val0 |= der[len_len + k] & 0x7F; ++ if (!(der[len_len + k] & 0x80)) ++ break; ++ } ++ parsed = ++k; ++ ++ /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */ ++ /* X = val, Y = val1 */ ++ ++ /* check if X == 0 */ ++ val = 0; ++ val1 = val0; ++ if (val1 > 39) ++ { ++ val = 1; ++ val1 = val0 - 40; ++ if (val1 > 39) ++ { ++ val = 2; ++ val1 = val0 - 80; ++ } ++ } ++ ++ _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp)); ++ _asn1_str_cat (str, str_size, "."); ++ _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp)); ++ ++ val = 0; ++ leading = 1; ++ for (k = parsed; k < len; k++) ++ { ++ /* X.690 mandates that the leading byte must never be 0x80 ++ */ ++ if (leading != 0 && der[len_len + k] == 0x80) ++ return ASN1_DER_ERROR; ++ leading = 0; ++ ++ /* check for wrap around */ ++ if (INT_LEFT_SHIFT_OVERFLOW (val, 7)) ++ return ASN1_DER_ERROR; ++ ++ val = val << 7; ++ val |= der[len_len + k] & 0x7F; ++ ++ if (!(der[len_len + k] & 0x80)) ++ { ++ _asn1_str_cat (str, str_size, "."); ++ _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp)); ++ val = 0; ++ leading = 1; ++ } ++ } ++ ++ if (INT_ADD_OVERFLOW (len, len_len)) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = len + len_len; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_get_bit_der: ++ * @der: DER data to decode containing the BIT SEQUENCE. ++ * @der_len: Length of DER data to decode. ++ * @ret_len: Output variable containing the length of the DER data. ++ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in. ++ * @str_size: Length of pre-allocated output buffer. ++ * @bit_len: Output variable containing the size of the BIT SEQUENCE. ++ * ++ * Extract a BIT SEQUENCE from DER data. ++ * ++ * Returns: %ASN1_SUCCESS on success, or an error. ++ **/ ++int ++asn1_get_bit_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, int str_size, ++ int *bit_len) ++{ ++ int len_len = 0, len_byte; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ len_byte = asn1_get_length_der (der, der_len, &len_len) - 1; ++ if (len_byte < 0) ++ return ASN1_DER_ERROR; ++ ++ *ret_len = len_byte + len_len + 1; ++ *bit_len = len_byte * 8 - der[len_len]; ++ ++ if (*bit_len < 0) ++ return ASN1_DER_ERROR; ++ ++ if (str_size >= len_byte) ++ { ++ if (len_byte > 0 && str) ++ memcpy (str, der + len_len + 1, len_byte); ++ } ++ else ++ { ++ return ASN1_MEM_ERROR; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++/* tag_len: the total tag length (explicit+inner) ++ * inner_tag_len: the inner_tag length ++ */ ++static int ++_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len, ++ int *tag_len, int *inner_tag_len, unsigned flags) ++{ ++ asn1_node p; ++ int counter, len2, len3, is_tag_implicit; ++ int result; ++ unsigned long tag, tag_implicit = 0; ++ unsigned char class, class2, class_implicit = 0; ++ ++ if (der_len <= 0) ++ return ASN1_GENERIC_ERROR; ++ ++ counter = is_tag_implicit = 0; ++ ++ if (node->type & CONST_TAG) ++ { ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if (p->type & CONST_APPLICATION) ++ class2 = ASN1_CLASS_APPLICATION; ++ else if (p->type & CONST_UNIVERSAL) ++ class2 = ASN1_CLASS_UNIVERSAL; ++ else if (p->type & CONST_PRIVATE) ++ class2 = ASN1_CLASS_PRIVATE; ++ else ++ class2 = ASN1_CLASS_CONTEXT_SPECIFIC; ++ ++ if (p->type & CONST_EXPLICIT) ++ { ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ counter += len2; ++ ++ if (flags & ASN1_DECODE_FLAG_STRICT_DER) ++ len3 = ++ asn1_get_length_der (der + counter, der_len, ++ &len2); ++ else ++ len3 = ++ asn1_get_length_ber (der + counter, der_len, ++ &len2); ++ if (len3 < 0) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ counter += len2; ++ ++ if (!is_tag_implicit) ++ { ++ if ((class != (class2 | ASN1_CLASS_STRUCTURED)) || ++ (tag != strtoul ((char *) p->value, NULL, 10))) ++ return ASN1_TAG_ERROR; ++ } ++ else ++ { /* ASN1_TAG_IMPLICIT */ ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ return ASN1_TAG_ERROR; ++ } ++ is_tag_implicit = 0; ++ } ++ else ++ { /* ASN1_TAG_IMPLICIT */ ++ if (!is_tag_implicit) ++ { ++ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) || ++ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF) ++ || (type_field (node->type) == ASN1_ETYPE_SET) ++ || (type_field (node->type) == ASN1_ETYPE_SET_OF)) ++ class2 |= ASN1_CLASS_STRUCTURED; ++ class_implicit = class2; ++ tag_implicit = strtoul ((char *) p->value, NULL, 10); ++ is_tag_implicit = 1; ++ } ++ } ++ } ++ p = p->right; ++ } ++ } ++ ++ if (is_tag_implicit) ++ { ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ { ++ if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING) ++ { ++ class_implicit |= ASN1_CLASS_STRUCTURED; ++ if ((class != class_implicit) || (tag != tag_implicit)) ++ return ASN1_TAG_ERROR; ++ } ++ else ++ return ASN1_TAG_ERROR; ++ } ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ if (type == ASN1_ETYPE_TAG) ++ { ++ *tag_len = 0; ++ if (inner_tag_len) ++ *inner_tag_len = 0; ++ return ASN1_SUCCESS; ++ } ++ ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ ++ switch (type) ++ { ++ case ASN1_ETYPE_NULL: ++ case ASN1_ETYPE_BOOLEAN: ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ case ASN1_ETYPE_OBJECT_ID: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET: ++ case ASN1_ETYPE_SET_OF: ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if ((class != _asn1_tags[type].class) ++ || (tag != _asn1_tags[type].tag)) ++ return ASN1_DER_ERROR; ++ break; ++ ++ case ASN1_ETYPE_OCTET_STRING: ++ /* OCTET STRING is handled differently to allow ++ * BER encodings (structured class). */ ++ if (((class != ASN1_CLASS_UNIVERSAL) ++ && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED))) ++ || (tag != ASN1_TAG_OCTET_STRING)) ++ return ASN1_DER_ERROR; ++ break; ++ case ASN1_ETYPE_ANY: ++ counter -= len2; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ counter -= len2; ++ break; ++ default: ++ return ASN1_DER_ERROR; ++ break; ++ } ++ } ++ ++ counter += len2; ++ *tag_len = counter; ++ if (inner_tag_len) ++ *inner_tag_len = len2; ++ return ASN1_SUCCESS; ++ ++cleanup: ++ return result; ++} ++ ++static int ++extract_tag_der_recursive(asn1_node node, const unsigned char *der, int der_len, ++ int *ret_len, int *inner_len, unsigned flags) ++{ ++asn1_node p; ++int ris = ASN1_DER_ERROR; ++ ++ if (type_field (node->type) == ASN1_ETYPE_CHOICE) ++ { ++ p = node->down; ++ while (p) ++ { ++ ris = _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len, flags); ++ if (ris == ASN1_SUCCESS) ++ break; ++ p = p->right; ++ } ++ ++ *ret_len = 0; ++ return ris; ++ } ++ else ++ return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len, flags); ++} ++ ++static int ++_asn1_delete_not_used (asn1_node node) ++{ ++ asn1_node p, p2; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if (p->type & CONST_NOT_USED) ++ { ++ p2 = NULL; ++ if (p != node) ++ { ++ p2 = _asn1_find_left (p); ++ if (!p2) ++ p2 = _asn1_find_up (p); ++ } ++ asn1_delete_structure (&p); ++ p = p2; ++ } ++ ++ if (!p) ++ break; /* reach node */ ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { ++ if (p == node) ++ p = NULL; ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ } ++ return ASN1_SUCCESS; ++} ++ ++static int ++_asn1_get_indefinite_length_string (const unsigned char *der, ++ int der_len, int *len) ++{ ++ int len2, len3, counter, indefinite; ++ int result; ++ unsigned long tag; ++ unsigned char class; ++ ++ counter = indefinite = 0; ++ ++ while (1) ++ { ++ if (HAVE_TWO(der_len) && (der[counter] == 0) && (der[counter + 1] == 0)) ++ { ++ counter += 2; ++ DECR_LEN(der_len, 2); ++ ++ indefinite--; ++ if (indefinite <= 0) ++ break; ++ else ++ continue; ++ } ++ ++ if (asn1_get_tag_der ++ (der + counter, der_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ return ASN1_DER_ERROR; ++ ++ DECR_LEN(der_len, len2); ++ counter += len2; ++ ++ len2 = asn1_get_length_der (der + counter, der_len, &len3); ++ if (len2 < -1) ++ return ASN1_DER_ERROR; ++ ++ if (len2 == -1) ++ { ++ indefinite++; ++ counter += 1; ++ DECR_LEN(der_len, 1); ++ } ++ else ++ { ++ counter += len2 + len3; ++ DECR_LEN(der_len, len2+len3); ++ } ++ } ++ ++ *len = counter; ++ return ASN1_SUCCESS; ++ ++cleanup: ++ return result; ++} ++ ++static void delete_unneeded_choice_fields(asn1_node p) ++{ ++ asn1_node p2; ++ ++ while (p->right) ++ { ++ p2 = p->right; ++ asn1_delete_structure (&p2); ++ } ++} ++ ++ ++/** ++ * asn1_der_decoding2 ++ * @element: pointer to an ASN1 structure. ++ * @ider: vector that contains the DER encoding. ++ * @max_ider_len: pointer to an integer giving the information about the ++ * maximal number of bytes occupied by *@ider. The real size of the DER ++ * encoding is returned through this pointer. ++ * @flags: flags controlling the behaviour of the function. ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the structure *@element with values of a DER encoding string. The ++ * structure must just be created with function asn1_create_element(). ++ * ++ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore ++ * padding after the decoded DER data. Upon a successful return the value of ++ * *@max_ider_len will be set to the number of bytes decoded. ++ * ++ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will ++ * not decode any BER-encoded elements. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or ++ * %ASN1_DER_ERROR if the der encoding doesn't match the structure ++ * name (*@ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding2 (asn1_node *element, const void *ider, int *max_ider_len, ++ unsigned int flags, char *errorDescription) ++{ ++ asn1_node node, p, p2, p3; ++ char temp[128]; ++ int counter, len2, len3, len4, move, ris, tlen; ++ struct node_tail_cache_st tcache = {NULL, NULL}; ++ unsigned char class; ++ unsigned long tag; ++ int tag_len; ++ int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len; ++ int inner_tag_len; ++ unsigned char *ptmp; ++ const unsigned char *ptag; ++ const unsigned char *der = ider; ++ ++ node = *element; ++ ++ if (errorDescription != NULL) ++ errorDescription[0] = 0; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (node->type & CONST_OPTION) ++ { ++ result = ASN1_GENERIC_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ counter = 0; ++ move = DOWN; ++ p = node; ++ while (1) ++ { ++ tag_len = 0; ++ inner_tag_len = 0; ++ ris = ASN1_SUCCESS; ++ if (move != UP) ++ { ++ if (p->type & CONST_SET) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ if (len2 == -1) ++ { ++ if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) ++ { ++ p = p2; ++ move = UP; ++ counter += 2; ++ DECR_LEN(ider_len, 2); ++ continue; ++ } ++ } ++ else if (counter == len2) ++ { ++ p = p2; ++ move = UP; ++ continue; ++ } ++ else if (counter > len2) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ p2 = p2->down; ++ while (p2) ++ { ++ if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED)) ++ { ++ ris = ++ extract_tag_der_recursive (p2, der + counter, ++ ider_len, &len2, NULL, flags); ++ if (ris == ASN1_SUCCESS) ++ { ++ p2->type &= ~CONST_NOT_USED; ++ p = p2; ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ if (p2 == NULL) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ ++ /* the position in the DER structure this starts */ ++ p->start = counter; ++ p->end = total_len - 1; ++ ++ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ if (counter == len2) ++ { ++ if (p->right) ++ { ++ p2 = p->right; ++ move = RIGHT; ++ } ++ else ++ move = UP; ++ ++ if (p->type & CONST_OPTION) ++ asn1_delete_structure (&p); ++ ++ p = p2; ++ continue; ++ } ++ } ++ ++ if (type_field (p->type) == ASN1_ETYPE_CHOICE) ++ { ++ while (p->down) ++ { ++ ris = ++ extract_tag_der_recursive (p->down, der + counter, ++ ider_len, &len2, NULL, flags); ++ ++ if (ris == ASN1_SUCCESS) ++ { ++ delete_unneeded_choice_fields(p->down); ++ break; ++ } ++ else if (ris == ASN1_ERROR_TYPE_ANY) ++ { ++ result = ASN1_ERROR_TYPE_ANY; ++ warn(); ++ goto cleanup; ++ } ++ else ++ { ++ p2 = p->down; ++ asn1_delete_structure (&p2); ++ } ++ } ++ ++ if (p->down == NULL) ++ { ++ if (!(p->type & CONST_OPTION)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ else if (type_field (p->type) != ASN1_ETYPE_CHOICE) ++ p = p->down; ++ ++ p->start = counter; ++ } ++ ++ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT)) ++ { ++ p2 = _asn1_find_up (p); ++ len2 = p2->tmp_ival; ++ ++ if ((len2 != -1) && (counter > len2)) ++ ris = ASN1_TAG_ERROR; ++ } ++ ++ if (ris == ASN1_SUCCESS) ++ ris = ++ extract_tag_der_recursive (p, der + counter, ider_len, ++ &tag_len, &inner_tag_len, flags); ++ ++ if (ris != ASN1_SUCCESS) ++ { ++ if (p->type & CONST_OPTION) ++ { ++ p->type |= CONST_NOT_USED; ++ move = RIGHT; ++ } ++ else if (p->type & CONST_DEFAULT) ++ { ++ _asn1_set_value (p, NULL, 0); ++ move = RIGHT; ++ } ++ else ++ { ++ if (errorDescription != NULL) ++ _asn1_error_description_tag_error (p, errorDescription); ++ ++ result = ASN1_TAG_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ else ++ { ++ DECR_LEN(ider_len, tag_len); ++ counter += tag_len; ++ } ++ } ++ ++ if (ris == ASN1_SUCCESS) ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_NULL: ++ DECR_LEN(ider_len, 1); ++ if (der[counter]) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ counter++; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ DECR_LEN(ider_len, 2); ++ ++ if (der[counter++] != 1) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ if (der[counter++] == 0) ++ _asn1_set_value (p, "F", 1); ++ else ++ _asn1_set_value (p, "T", 1); ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ len2 = ++ asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len3+len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ result = ++ asn1_get_object_id_der (der + counter, ider_len, &len2, ++ temp, sizeof (temp)); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ ++ tlen = strlen (temp); ++ if (tlen > 0) ++ _asn1_set_value (p, temp, tlen + 1); ++ ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ result = ++ _asn1_get_time_der (type_field (p->type), der + counter, ider_len, &len2, temp, ++ sizeof (temp) - 1, flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ ++ tlen = strlen (temp); ++ if (tlen > 0) ++ _asn1_set_value (p, temp, tlen); ++ ++ counter += len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ if (counter < inner_tag_len) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ ptag = der + counter - inner_tag_len; ++ if ((flags & ASN1_DECODE_FLAG_STRICT_DER) || !(ptag[0] & ASN1_CLASS_STRUCTURED)) ++ { ++ if (ptag[0] & ASN1_CLASS_STRUCTURED) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ len2 = ++ asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len3+len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ } ++ else ++ { ++ unsigned dflags = 0, vlen, ber_len; ++ ++ if (ptag[0] & ASN1_CLASS_STRUCTURED) ++ dflags |= DECODE_FLAG_CONSTRUCTED; ++ ++ result = _asn1_decode_simple_ber(type_field (p->type), der+counter, ider_len, &ptmp, &vlen, &ber_len, dflags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, ber_len); ++ ++ _asn1_set_value_lv (p, ptmp, vlen); ++ ++ counter += ber_len; ++ free(ptmp); ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ case ASN1_ETYPE_BIT_STRING: ++ len2 = ++ asn1_get_length_der (der + counter, ider_len, &len3); ++ if (len2 < 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len3+len2); ++ ++ _asn1_set_value (p, der + counter, len3 + len2); ++ counter += len3 + len2; ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_SET: ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ p->tmp_ival = 0; ++ if (len2 == -1) ++ { /* indefinite length method */ ++ DECR_LEN(ider_len, 2); ++ if ((der[counter]) || der[counter + 1]) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ counter += 2; ++ } ++ else ++ { /* definite length method */ ++ if (len2 != counter) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ move = RIGHT; ++ } ++ else ++ { /* move==DOWN || move==RIGHT */ ++ len3 = ++ asn1_get_length_der (der + counter, ider_len, &len2); ++ if (IS_ERR(len3, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ counter += len2; ++ ++ if (len3 > 0) ++ { ++ p->tmp_ival = counter + len3; ++ move = DOWN; ++ } ++ else if (len3 == 0) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ { ++ p3 = p2->right; ++ asn1_delete_structure (&p2); ++ p2 = p3; ++ } ++ else ++ p2 = p2->right; ++ } ++ move = RIGHT; ++ } ++ else ++ { /* indefinite length method */ ++ p->tmp_ival = -1; ++ move = DOWN; ++ } ++ } ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (move == UP) ++ { ++ len2 = p->tmp_ival; ++ if (len2 == -1) ++ { /* indefinite length method */ ++ if (!HAVE_TWO(ider_len) || ((der[counter]) || der[counter + 1])) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn(); ++ goto cleanup; ++ } ++ p = tcache.tail; ++ move = RIGHT; ++ continue; ++ } ++ ++ p->tmp_ival = 0; ++ tcache.tail = NULL; /* finished decoding this structure */ ++ tcache.head = NULL; ++ DECR_LEN(ider_len, 2); ++ counter += 2; ++ } ++ else ++ { /* definite length method */ ++ if (len2 > counter) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn(); ++ goto cleanup; ++ } ++ p = tcache.tail; ++ move = RIGHT; ++ continue; ++ } ++ ++ p->tmp_ival = 0; ++ tcache.tail = NULL; /* finished decoding this structure */ ++ tcache.head = NULL; ++ ++ if (len2 != counter) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ } ++ else ++ { /* move==DOWN || move==RIGHT */ ++ len3 = ++ asn1_get_length_der (der + counter, ider_len, &len2); ++ if (IS_ERR(len3, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ counter += len2; ++ if (len3) ++ { ++ if (len3 > 0) ++ { /* definite length method */ ++ p->tmp_ival = counter + len3; ++ } ++ else ++ { /* indefinite length method */ ++ p->tmp_ival = -1; ++ } ++ ++ p2 = p->down; ++ if (p2 == NULL) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ while ((type_field (p2->type) == ASN1_ETYPE_TAG) ++ || (type_field (p2->type) == ASN1_ETYPE_SIZE)) ++ p2 = p2->right; ++ if (p2->right == NULL) ++ { ++ result = _asn1_append_sequence_set (p, &tcache); ++ if (result != 0) ++ { ++ warn(); ++ goto cleanup; ++ } ++ } ++ p = p2; ++ } ++ } ++ move = RIGHT; ++ break; ++ case ASN1_ETYPE_ANY: ++ /* Check indefinite lenth method in an EXPLICIT TAG */ ++ ++ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) && (p->type & CONST_TAG) && ++ tag_len == 2 && (der[counter - 1] == 0x80)) ++ indefinite = 1; ++ else ++ indefinite = 0; ++ ++ if (asn1_get_tag_der ++ (der + counter, ider_len, &class, &len2, ++ &tag) != ASN1_SUCCESS) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ ++ len4 = ++ asn1_get_length_der (der + counter + len2, ++ ider_len, &len3); ++ if (IS_ERR(len4, flags)) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ if (len4 != -1) /* definite */ ++ { ++ len2 += len4; ++ ++ DECR_LEN(ider_len, len4+len3); ++ _asn1_set_value_lv (p, der + counter, len2 + len3); ++ counter += len2 + len3; ++ } ++ else /* == -1 */ ++ { /* indefinite length */ ++ ider_len += len2; /* undo DECR_LEN */ ++ ++ if (counter == 0) ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ ++ result = ++ _asn1_get_indefinite_length_string (der + counter, ider_len, &len2); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ DECR_LEN(ider_len, len2); ++ _asn1_set_value_lv (p, der + counter, len2); ++ counter += len2; ++ ++ } ++ ++ /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with ++ an indefinite length method. */ ++ if (indefinite) ++ { ++ DECR_LEN(ider_len, 2); ++ if (!der[counter] && !der[counter + 1]) ++ { ++ counter += 2; ++ } ++ else ++ { ++ result = ASN1_DER_ERROR; ++ warn(); ++ goto cleanup; ++ } ++ } ++ ++ move = RIGHT; ++ break; ++ default: ++ move = (move == UP) ? RIGHT : DOWN; ++ break; ++ } ++ } ++ ++ if (p) ++ { ++ p->end = counter - 1; ++ } ++ ++ if (p == node && move != DOWN) ++ break; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ if ((move == RIGHT) && !(p->type & CONST_SET)) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ _asn1_delete_not_used (*element); ++ ++ if ((ider_len < 0) || ++ (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0))) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ *max_ider_len = total_len - ider_len; ++ ++ return ASN1_SUCCESS; ++ ++cleanup: ++ asn1_delete_structure (element); ++ return result; ++} ++ ++ ++/** ++ * asn1_der_decoding: ++ * @element: pointer to an ASN1 structure. ++ * @ider: vector that contains the DER encoding. ++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]. ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the structure *@element with values of a DER encoding ++ * string. The structure must just be created with function ++ * asn1_create_element(). ++ * ++ * Note that the *@element variable is provided as a pointer for ++ * historical reasons. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or ++ * %ASN1_DER_ERROR if the der encoding doesn't match the structure ++ * name (*@ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, ++ char *errorDescription) ++{ ++ return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); ++} ++ ++/** ++ * asn1_der_decoding_element: ++ * @structure: pointer to an ASN1 structure ++ * @elementName: name of the element to fill ++ * @ider: vector that contains the DER encoding of the whole structure. ++ * @len: number of bytes of *der: der[0]..der[len-1] ++ * @errorDescription: null-terminated string contains details when an ++ * error occurred. ++ * ++ * Fill the element named @ELEMENTNAME with values of a DER encoding ++ * string. The structure must just be created with function ++ * asn1_create_element(). The DER vector must contain the encoding ++ * string of the whole @STRUCTURE. If an error occurs during the ++ * decoding procedure, the *@STRUCTURE is deleted and set equal to ++ * %NULL. ++ * ++ * This function is deprecated and may just be an alias to asn1_der_decoding ++ * in future versions. Use asn1_der_decoding() instead. ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if ELEMENT is %NULL or @elementName == NULL, and ++ * %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't ++ * match the structure @structure (*ELEMENT deleted). ++ **/ ++int ++asn1_der_decoding_element (asn1_node * structure, const char *elementName, ++ const void *ider, int len, char *errorDescription) ++{ ++ return asn1_der_decoding(structure, ider, len, errorDescription); ++} ++ ++/** ++ * asn1_der_decoding_startEnd: ++ * @element: pointer to an ASN1 element ++ * @ider: vector that contains the DER encoding. ++ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1] ++ * @name_element: an element of NAME structure. ++ * @start: the position of the first byte of NAME_ELEMENT decoding ++ * (@ider[*start]) ++ * @end: the position of the last byte of NAME_ELEMENT decoding ++ * (@ider[*end]) ++ * ++ * Find the start and end point of an element in a DER encoding ++ * string. I mean that if you have a der encoding and you have already ++ * used the function asn1_der_decoding() to fill a structure, it may ++ * happen that you want to find the piece of string concerning an ++ * element of the structure. ++ * ++ * One example is the sequence "tbsCertificate" inside an X509 ++ * certificate. ++ * ++ * Note that since libtasn1 3.7 the @ider and @ider_len parameters ++ * can be omitted, if the element is already decoded using asn1_der_decoding(). ++ * ++ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND ++ * if ELEMENT is %asn1_node EMPTY or @name_element is not a valid ++ * element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding ++ * doesn't match the structure ELEMENT. ++ **/ ++int ++asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len, ++ const char *name_element, int *start, int *end) ++{ ++ asn1_node node, node_to_find; ++ int result = ASN1_DER_ERROR; ++ ++ node = element; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ node_to_find = asn1_find_node (node, name_element); ++ ++ if (node_to_find == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ *start = node_to_find->start; ++ *end = node_to_find->end; ++ ++ if (*start == 0 && *end == 0) ++ { ++ if (ider == NULL || ider_len == 0) ++ return ASN1_GENERIC_ERROR; ++ ++ /* it seems asn1_der_decoding() wasn't called before. Do it now */ ++ result = asn1_der_decoding (&node, ider, ider_len, NULL); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ return result; ++ } ++ ++ node_to_find = asn1_find_node (node, name_element); ++ if (node_to_find == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ *start = node_to_find->start; ++ *end = node_to_find->end; ++ } ++ ++ if (*end < *start) ++ return ASN1_GENERIC_ERROR; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_expand_any_defined_by: ++ * @definitions: ASN1 definitions ++ * @element: pointer to an ASN1 structure ++ * ++ * Expands every "ANY DEFINED BY" element of a structure created from ++ * a DER decoding process (asn1_der_decoding function). The element ++ * ANY must be defined by an OBJECT IDENTIFIER. The type used to ++ * expand the element ANY is the first one following the definition of ++ * the actual value of the OBJECT IDENTIFIER. ++ * ++ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if ++ * some "ANY DEFINED BY" element couldn't be expanded due to a ++ * problem in OBJECT_ID -> TYPE association, or other error codes ++ * depending on DER decoding. ++ **/ ++int ++asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 2], ++ value[ASN1_MAX_NAME_SIZE]; ++ int retCode = ASN1_SUCCESS, result; ++ int len, len2, len3; ++ asn1_node_const p2; ++ asn1_node p, p3, aux = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ const char *definitionsName; ++ ++ if ((definitions == NULL) || (*element == NULL)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ definitionsName = definitions->name; ++ ++ p = *element; ++ while (p) ++ { ++ ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_ANY: ++ if ((p->type & CONST_DEFINED_BY) && (p->value)) ++ { ++ /* search the "DEF_BY" element */ ++ p2 = p->down; ++ while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT)) ++ p2 = p2->right; ++ ++ if (!p2) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = _asn1_find_up (p); ++ ++ if (!p3) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = p3->down; ++ while (p3) ++ { ++ if (!(strcmp (p3->name, p2->name))) ++ break; ++ p3 = p3->right; ++ } ++ ++ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || ++ (p3->value == NULL)) ++ { ++ ++ p3 = _asn1_find_up (p); ++ p3 = _asn1_find_up (p3); ++ ++ if (!p3) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ p3 = p3->down; ++ ++ while (p3) ++ { ++ if (!(strcmp (p3->name, p2->name))) ++ break; ++ p3 = p3->right; ++ } ++ ++ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ++ || (p3->value == NULL)) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ } ++ ++ /* search the OBJECT_ID into definitions */ ++ p2 = definitions->down; ++ while (p2) ++ { ++ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p2->type & CONST_ASSIGN)) ++ { ++ snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name); ++ ++ len = ASN1_MAX_NAME_SIZE; ++ result = ++ asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) ++ && (!_asn1_strcmp (p3->value, value))) ++ { ++ p2 = p2->right; /* pointer to the structure to ++ use for expansion */ ++ while ((p2) && (p2->type & CONST_ASSIGN)) ++ p2 = p2->right; ++ ++ if (p2) ++ { ++ snprintf(name, sizeof(name), "%s.%s", definitionsName, p2->name); ++ ++ result = ++ asn1_create_element (definitions, name, &aux); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_cpy_name (aux, p); ++ len2 = ++ asn1_get_length_der (p->value, ++ p->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ ++ result = ++ asn1_der_decoding (&aux, p->value + len3, ++ len2, ++ errorDescription); ++ if (result == ASN1_SUCCESS) ++ { ++ ++ _asn1_set_right (aux, p->right); ++ _asn1_set_right (p, aux); ++ ++ result = asn1_delete_structure (&p); ++ if (result == ASN1_SUCCESS) ++ { ++ p = aux; ++ aux = NULL; ++ break; ++ } ++ else ++ { /* error with asn1_delete_structure */ ++ asn1_delete_structure (&aux); ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_der_decoding */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_create_element */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with the pointer to the structure to exapand */ ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ } ++ } ++ p2 = p2->right; ++ } /* end while */ ++ ++ if (!p2) ++ { ++ retCode = ASN1_ERROR_TYPE_ANY; ++ break; ++ } ++ ++ } ++ break; ++ default: ++ break; ++ } ++ ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p == *element) ++ { ++ p = NULL; ++ break; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == *element) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return retCode; ++} ++ ++/** ++ * asn1_expand_octet_string: ++ * @definitions: ASN1 definitions ++ * @element: pointer to an ASN1 structure ++ * @octetName: name of the OCTECT STRING field to expand. ++ * @objectName: name of the OBJECT IDENTIFIER field to use to define ++ * the type for expansion. ++ * ++ * Expands an "OCTET STRING" element of a structure created from a DER ++ * decoding process (the asn1_der_decoding() function). The type used ++ * for expansion is the first one following the definition of the ++ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME. ++ * ++ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND ++ * if @objectName or @octetName are not correct, ++ * %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to ++ * use for expansion, or other errors depending on DER decoding. ++ **/ ++int ++asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, ++ const char *octetName, const char *objectName) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE]; ++ int retCode = ASN1_SUCCESS, result; ++ int len, len2, len3; ++ asn1_node_const p2; ++ asn1_node aux = NULL; ++ asn1_node octetNode = NULL, objectNode = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ if ((definitions == NULL) || (*element == NULL)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ octetNode = asn1_find_node (*element, octetName); ++ if (octetNode == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING) ++ return ASN1_ELEMENT_NOT_FOUND; ++ if (octetNode->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ objectNode = asn1_find_node (*element, objectName); ++ if (objectNode == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if (objectNode->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ ++ /* search the OBJECT_ID into definitions */ ++ p2 = definitions->down; ++ while (p2) ++ { ++ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p2->type & CONST_ASSIGN)) ++ { ++ strcpy (name, definitions->name); ++ strcat (name, "."); ++ strcat (name, p2->name); ++ ++ len = sizeof (value); ++ result = asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) ++ && (!_asn1_strcmp (objectNode->value, value))) ++ { ++ ++ p2 = p2->right; /* pointer to the structure to ++ use for expansion */ ++ while ((p2) && (p2->type & CONST_ASSIGN)) ++ p2 = p2->right; ++ ++ if (p2) ++ { ++ strcpy (name, definitions->name); ++ strcat (name, "."); ++ strcat (name, p2->name); ++ ++ result = asn1_create_element (definitions, name, &aux); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_cpy_name (aux, octetNode); ++ len2 = ++ asn1_get_length_der (octetNode->value, ++ octetNode->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ ++ result = ++ asn1_der_decoding (&aux, octetNode->value + len3, ++ len2, errorDescription); ++ if (result == ASN1_SUCCESS) ++ { ++ ++ _asn1_set_right (aux, octetNode->right); ++ _asn1_set_right (octetNode, aux); ++ ++ result = asn1_delete_structure (&octetNode); ++ if (result == ASN1_SUCCESS) ++ { ++ aux = NULL; ++ break; ++ } ++ else ++ { /* error with asn1_delete_structure */ ++ asn1_delete_structure (&aux); ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_der_decoding */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with asn1_create_element */ ++ retCode = result; ++ break; ++ } ++ } ++ else ++ { /* error with the pointer to the structure to exapand */ ++ retCode = ASN1_VALUE_NOT_VALID; ++ break; ++ } ++ } ++ } ++ ++ p2 = p2->right; ++ ++ } ++ ++ if (!p2) ++ retCode = ASN1_VALUE_NOT_VALID; ++ ++ return retCode; ++} ++ ++/*- ++ * _asn1_decode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @dflags: DECODE_FLAG_* ++ * ++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). ++ * The output is a pointer inside the @der. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ -*/ ++static int ++_asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len, unsigned dflags) ++{ ++ int tag_len, len_len; ++ const unsigned char *p; ++ int der_len = _der_len; ++ unsigned char class; ++ unsigned long tag; ++ long ret; ++ ++ if (der == NULL || der_len == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING(etype) == 0) ++ return ASN1_VALUE_NOT_VALID; ++ ++ /* doesn't handle constructed classes */ ++ class = ETYPE_CLASS(etype); ++ if (class != ASN1_CLASS_UNIVERSAL) ++ return ASN1_VALUE_NOT_VALID; ++ ++ p = der; ++ ++ if (dflags & DECODE_FLAG_HAVE_TAG) ++ { ++ ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); ++ if (ret != ASN1_SUCCESS) ++ return ret; ++ ++ if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype)) ++ { ++ warn(); ++ return ASN1_DER_ERROR; ++ } ++ ++ p += tag_len; ++ der_len -= tag_len; ++ if (der_len <= 0) ++ return ASN1_DER_ERROR; ++ } ++ ++ ret = asn1_get_length_der (p, der_len, &len_len); ++ if (ret < 0) ++ return ASN1_DER_ERROR; ++ ++ p += len_len; ++ der_len -= len_len; ++ if (der_len <= 0) ++ return ASN1_DER_ERROR; ++ ++ *str_len = ret; ++ *str = p; ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_decode_simple_der: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * ++ * Decodes a simple DER encoded type (e.g. a string, which is not constructed). ++ * The output is a pointer inside the @der. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, const unsigned char **str, ++ unsigned int *str_len) ++{ ++ return _asn1_decode_simple_der(etype, der, _der_len, str, str_len, DECODE_FLAG_HAVE_TAG); ++} ++ ++static int append(uint8_t **dst, unsigned *dst_size, const unsigned char *src, unsigned src_size) ++{ ++ if (src_size == 0) ++ return ASN1_SUCCESS; ++ ++ *dst = _asn1_realloc(*dst, *dst_size+src_size); ++ if (*dst == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ memcpy(*dst + *dst_size, src, src_size); ++ *dst_size += src_size; ++ return ASN1_SUCCESS; ++} ++ ++/*- ++ * _asn1_decode_simple_ber: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @ber_len: the total length occupied by BER (may be %NULL) ++ * @have_tag: whether a DER tag is included ++ * ++ * Decodes a BER encoded type. The output is an allocated value ++ * of the data. This decodes BER STRINGS only. Other types are ++ * decoded as DER. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ -*/ ++static int ++_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len, ++ unsigned dflags) ++{ ++ int tag_len, len_len; ++ const unsigned char *p; ++ int der_len = _der_len; ++ uint8_t *total = NULL; ++ unsigned total_size = 0; ++ unsigned char class; ++ unsigned long tag; ++ unsigned char *out = NULL; ++ const unsigned char *cout = NULL; ++ unsigned out_len; ++ long result; ++ ++ if (ber_len) *ber_len = 0; ++ ++ if (der == NULL || der_len == 0) ++ { ++ warn(); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ if (ETYPE_OK (etype) == 0) ++ { ++ warn(); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ /* doesn't handle constructed + definite classes */ ++ class = ETYPE_CLASS (etype); ++ if (class != ASN1_CLASS_UNIVERSAL) ++ { ++ warn(); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ p = der; ++ ++ if (dflags & DECODE_FLAG_HAVE_TAG) ++ { ++ result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ return result; ++ } ++ ++ if (tag != ETYPE_TAG (etype)) ++ { ++ warn(); ++ return ASN1_DER_ERROR; ++ } ++ ++ p += tag_len; ++ ++ DECR_LEN(der_len, tag_len); ++ ++ if (ber_len) *ber_len += tag_len; ++ } ++ ++ /* indefinite constructed */ ++ if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED) && ETYPE_IS_STRING(etype)) && ++ !(dflags & DECODE_FLAG_LEVEL3)) ++ { ++ if (der_len == 0) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ if (der_len > 0 && p[0] == 0x80) /* indefinite */ ++ { ++ len_len = 1; ++ DECR_LEN(der_len, len_len); ++ p += len_len; ++ ++ if (ber_len) *ber_len += len_len; ++ ++ /* decode the available octet strings */ ++ do ++ { ++ unsigned tmp_len; ++ unsigned flags = DECODE_FLAG_HAVE_TAG; ++ ++ if (dflags & DECODE_FLAG_LEVEL1) ++ flags |= DECODE_FLAG_LEVEL2; ++ else if (dflags & DECODE_FLAG_LEVEL2) ++ flags |= DECODE_FLAG_LEVEL3; ++ else ++ flags |= DECODE_FLAG_LEVEL1; ++ ++ result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, ++ flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ p += tmp_len; ++ DECR_LEN(der_len, tmp_len); ++ ++ if (ber_len) *ber_len += tmp_len; ++ ++ DECR_LEN(der_len, 2); /* we need the EOC */ ++ ++ result = append(&total, &total_size, out, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ free(out); ++ out = NULL; ++ ++ if (p[0] == 0 && p[1] == 0) /* EOC */ ++ { ++ if (ber_len) *ber_len += 2; ++ break; ++ } ++ ++ /* no EOC */ ++ der_len += 2; ++ ++ if (der_len == 2) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ } ++ while(1); ++ } ++ else /* constructed */ ++ { ++ long const_len; ++ ++ result = asn1_get_length_ber(p, der_len, &len_len); ++ if (result < 0) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ DECR_LEN(der_len, len_len); ++ p += len_len; ++ ++ const_len = result; ++ ++ if (ber_len) *ber_len += len_len; ++ ++ /* decode the available octet strings */ ++ while(const_len > 0) ++ { ++ unsigned tmp_len; ++ unsigned flags = DECODE_FLAG_HAVE_TAG; ++ ++ if (dflags & DECODE_FLAG_LEVEL1) ++ flags |= DECODE_FLAG_LEVEL2; ++ else if (dflags & DECODE_FLAG_LEVEL2) ++ flags |= DECODE_FLAG_LEVEL3; ++ else ++ flags |= DECODE_FLAG_LEVEL1; ++ ++ result = _asn1_decode_simple_ber(etype, p, der_len, &out, &out_len, &tmp_len, ++ flags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ p += tmp_len; ++ DECR_LEN(der_len, tmp_len); ++ DECR_LEN(const_len, tmp_len); ++ ++ if (ber_len) *ber_len += tmp_len; ++ ++ result = append(&total, &total_size, out, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ free(out); ++ out = NULL; ++ } ++ } ++ } ++ else if (class == ETYPE_CLASS(etype)) ++ { ++ if (ber_len) ++ { ++ result = asn1_get_length_der (p, der_len, &len_len); ++ if (result < 0) ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ *ber_len += result + len_len; ++ } ++ ++ /* non-string values are decoded as DER */ ++ result = _asn1_decode_simple_der(etype, der, _der_len, &cout, &out_len, dflags); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ ++ result = append(&total, &total_size, cout, out_len); ++ if (result != ASN1_SUCCESS) ++ { ++ warn(); ++ goto cleanup; ++ } ++ } ++ else ++ { ++ warn(); ++ result = ASN1_DER_ERROR; ++ goto cleanup; ++ } ++ ++ *str = total; ++ *str_len = total_size; ++ ++ return ASN1_SUCCESS; ++cleanup: ++ free(out); ++ free(total); ++ return result; ++} ++ ++/** ++ * asn1_decode_simple_ber: ++ * @etype: The type of the string to be encoded (ASN1_ETYPE_) ++ * @der: the encoded string ++ * @_der_len: the bytes of the encoded string ++ * @str: a pointer to the data ++ * @str_len: the length of the data ++ * @ber_len: the total length occupied by BER (may be %NULL) ++ * ++ * Decodes a BER encoded type. The output is an allocated value ++ * of the data. This decodes BER STRINGS only. Other types are ++ * decoded as DER. ++ * ++ * Returns: %ASN1_SUCCESS if successful or an error value. ++ **/ ++int ++asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, unsigned char **str, ++ unsigned int *str_len, unsigned int *ber_len) ++{ ++ return _asn1_decode_simple_ber(etype, der, _der_len, str, str_len, ber_len, DECODE_FLAG_HAVE_TAG); ++} +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +new file mode 100644 +index 0000000000..997eb2725d +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -0,0 +1,1111 @@ ++/* ++ * Copyright (C) 2000-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++/*****************************************************/ ++/* File: element.c */ ++/* Description: Functions with the read and write */ ++/* functions. */ ++/*****************************************************/ ++ ++ ++#include ++#include "parser_aux.h" ++#include ++#include "structure.h" ++#include "c-ctype.h" ++#include "element.h" ++ ++void ++_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) ++{ ++ asn1_node_const p; ++ char tmp_name[64]; ++ ++ p = node; ++ ++ name[0] = 0; ++ ++ while (p != NULL) ++ { ++ if (p->name[0] != 0) ++ { ++ _asn1_str_cpy (tmp_name, sizeof (tmp_name), name), ++ _asn1_str_cpy (name, name_size, p->name); ++ _asn1_str_cat (name, name_size, "."); ++ _asn1_str_cat (name, name_size, tmp_name); ++ } ++ p = _asn1_find_up (p); ++ } ++ ++ if (name[0] == 0) ++ _asn1_str_cpy (name, name_size, "ROOT"); ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_convert_integer */ ++/* Description: converts an integer from a null terminated string */ ++/* to der decoding. The convertion from a null */ ++/* terminated string to an integer is made with */ ++/* the 'strtol' function. */ ++/* Parameters: */ ++/* value: null terminated string to convert. */ ++/* value_out: convertion result (memory must be already */ ++/* allocated). */ ++/* value_out_size: number of bytes of value_out. */ ++/* len: number of significant byte of value_out. */ ++/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_convert_integer (const unsigned char *value, unsigned char *value_out, ++ int value_out_size, int *len) ++{ ++ char negative; ++ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; ++ long valtmp; ++ int k, k2; ++ ++ valtmp = _asn1_strtol (value, NULL, 10); ++ ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) ++ { ++ val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF; ++ } ++ ++ if (val[0] & 0x80) ++ negative = 1; ++ else ++ negative = 0; ++ ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++) ++ { ++ if (negative && (val[k] != 0xFF)) ++ break; ++ else if (!negative && val[k]) ++ break; ++ } ++ ++ if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80))) ++ k--; ++ ++ *len = SIZEOF_UNSIGNED_LONG_INT - k; ++ ++ if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size) ++ /* VALUE_OUT is too short to contain the value conversion */ ++ return ASN1_MEM_ERROR; ++ ++ if (value_out != NULL) ++ { ++ for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++) ++ value_out[k2 - k] = val[k2]; ++ } ++ ++#if 0 ++ printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len); ++ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) ++ printf (", vOut[%d]=%d", k, value_out[k]); ++ printf ("\n"); ++#endif ++ ++ return ASN1_SUCCESS; ++} ++ ++/* Appends a new element into the sequence (or set) defined by this ++ * node. The new element will have a name of '?number', where number ++ * is a monotonically increased serial number. ++ * ++ * The last element in the list may be provided in @pcache, to avoid ++ * traversing the list, an expensive operation in long lists. ++ * ++ * On success it returns in @pcache the added element (which is the ++ * tail in the list of added elements). ++ */ ++int ++_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) ++{ ++ asn1_node p, p2; ++ char temp[LTOSTR_MAX_SIZE]; ++ long n; ++ ++ if (!node || !(node->down)) ++ return ASN1_GENERIC_ERROR; ++ ++ p = node->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ ++ p2 = _asn1_copy_structure3 (p); ++ if (p2 == NULL) ++ return ASN1_GENERIC_ERROR; ++ ++ if (pcache == NULL || pcache->tail == NULL || pcache->head != node) ++ { ++ while (p->right) ++ { ++ p = p->right; ++ } ++ } ++ else ++ { ++ p = pcache->tail; ++ } ++ ++ _asn1_set_right (p, p2); ++ if (pcache) ++ { ++ pcache->head = node; ++ pcache->tail = p2; ++ } ++ ++ if (p->name[0] == 0) ++ _asn1_str_cpy (temp, sizeof (temp), "?1"); ++ else ++ { ++ n = strtol (p->name + 1, NULL, 0); ++ n++; ++ temp[0] = '?'; ++ _asn1_ltostr (n, temp + 1); ++ } ++ _asn1_set_name (p2, temp); ++ /* p2->type |= CONST_OPTION; */ ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_write_value: ++ * @node_root: pointer to a structure ++ * @name: the name of the element inside the structure that you want to set. ++ * @ivalue: vector used to specify the value to set. If len is >0, ++ * VALUE must be a two's complement form integer. if len=0 *VALUE ++ * must be a null terminated string with an integer value. ++ * @len: number of bytes of *value to use to set the value: ++ * value[0]..value[len-1] or 0 if value is a null terminated string ++ * ++ * Set the value of one element inside a structure. ++ * ++ * If an element is OPTIONAL and you want to delete it, you must use ++ * the value=NULL and len=0. Using "pkix.asn": ++ * ++ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID", ++ * NULL, 0); ++ * ++ * Description for each type: ++ * ++ * INTEGER: VALUE must contain a two's complement form integer. ++ * ++ * value[0]=0xFF , len=1 -> integer=-1. ++ * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1. ++ * value[0]=0x01 , len=1 -> integer= 1. ++ * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1. ++ * value="123" , len=0 -> integer= 123. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE must be the null terminated string "TRUE" or ++ * "FALSE" and LEN != 0. ++ * ++ * value="TRUE" , len=1 -> boolean=TRUE. ++ * value="FALSE" , len=1 -> boolean=FALSE. ++ * ++ * OBJECT IDENTIFIER: VALUE must be a null terminated string with ++ * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0. ++ * ++ * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha. ++ * ++ * UTCTime: VALUE must be a null terminated string in one of these ++ * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ", ++ * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'", ++ * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0. ++ * ++ * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 ++ * at 12h 00m Greenwich Mean Time ++ * ++ * GeneralizedTime: VALUE must be in one of this format: ++ * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ", ++ * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'", ++ * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s ++ * indicates the seconds with any precision like "10.1" or "01.02". ++ * LEN != 0 ++ * ++ * value="2001010112001.12-0700" , len=1 -> time=Jannuary ++ * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time ++ * ++ * OCTET STRING: VALUE contains the octet string and LEN is the ++ * number of octets. ++ * ++ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , ++ * len=3 -> three bytes octet string ++ * ++ * GeneralString: VALUE contains the generalstring and LEN is the ++ * number of octets. ++ * ++ * value="$\backslash$x01$\backslash$x02$\backslash$x03" , ++ * len=3 -> three bytes generalstring ++ * ++ * BIT STRING: VALUE contains the bit string organized by bytes and ++ * LEN is the number of bits. ++ * ++ * value="$\backslash$xCF" , len=6 -> bit string="110011" (six ++ * bits) ++ * ++ * CHOICE: if NAME indicates a choice type, VALUE must specify one of ++ * the alternatives with a null terminated string. LEN != 0. Using ++ * "pkix.asn"\: ++ * ++ * result=asn1_write_value(cert, ++ * "certificate1.tbsCertificate.subject", "rdnSequence", ++ * 1); ++ * ++ * ANY: VALUE indicates the der encoding of a structure. LEN != 0. ++ * ++ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and ++ * LEN != 0. With this instruction another element is appended in ++ * the sequence. The name of this element will be "?1" if it's the ++ * first one, "?2" for the second and so on. ++ * ++ * Using "pkix.asn"\: ++ * ++ * result=asn1_write_value(cert, ++ * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1); ++ * ++ * SET OF: the same as SEQUENCE OF. Using "pkix.asn": ++ * ++ * result=asn1_write_value(cert, ++ * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1); ++ * ++ * Returns: %ASN1_SUCCESS if the value was set, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and ++ * %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format. ++ **/ ++int ++asn1_write_value (asn1_node node_root, const char *name, ++ const void *ivalue, int len) ++{ ++ asn1_node node, p, p2; ++ unsigned char *temp, *value_temp = NULL, *default_temp = NULL; ++ int len2, k, k2, negative; ++ size_t i; ++ const unsigned char *value = ivalue; ++ unsigned int type; ++ ++ node = asn1_find_node (node_root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0)) ++ { ++ asn1_delete_structure (&node); ++ return ASN1_SUCCESS; ++ } ++ ++ type = type_field (node->type); ++ ++ if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0)) ++ { ++ p = node->down; ++ while ((type_field (p->type) == ASN1_ETYPE_TAG) ++ || (type_field (p->type) == ASN1_ETYPE_SIZE)) ++ p = p->right; ++ ++ while (p->right) ++ asn1_delete_structure (&p->right); ++ ++ return ASN1_SUCCESS; ++ } ++ ++ /* Don't allow element deletion for other types */ ++ if (value == NULL) ++ { ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ switch (type) ++ { ++ case ASN1_ETYPE_BOOLEAN: ++ if (!_asn1_strcmp (value, "TRUE")) ++ { ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_TRUE) ++ _asn1_set_value (node, NULL, 0); ++ else ++ _asn1_set_value (node, "T", 1); ++ } ++ else ++ _asn1_set_value (node, "T", 1); ++ } ++ else if (!_asn1_strcmp (value, "FALSE")) ++ { ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_FALSE) ++ _asn1_set_value (node, NULL, 0); ++ else ++ _asn1_set_value (node, "F", 1); ++ } ++ else ++ _asn1_set_value (node, "F", 1); ++ } ++ else ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if (len == 0) ++ { ++ if ((c_isdigit (value[0])) || (value[0] == '-')) ++ { ++ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ _asn1_convert_integer (value, value_temp, ++ SIZEOF_UNSIGNED_LONG_INT, &len); ++ } ++ else ++ { /* is an identifier like v1 */ ++ if (!(node->type & CONST_LIST)) ++ return ASN1_VALUE_NOT_VALID; ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p->name, value)) ++ { ++ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ _asn1_convert_integer (p->value, ++ value_temp, ++ SIZEOF_UNSIGNED_LONG_INT, ++ &len); ++ break; ++ } ++ } ++ p = p->right; ++ } ++ if (p == NULL) ++ return ASN1_VALUE_NOT_VALID; ++ } ++ } ++ else ++ { /* len != 0 */ ++ value_temp = malloc (len); ++ if (value_temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ memcpy (value_temp, value, len); ++ } ++ ++ if (value_temp[0] & 0x80) ++ negative = 1; ++ else ++ negative = 0; ++ ++ if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED)) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ ++ for (k = 0; k < len - 1; k++) ++ if (negative && (value_temp[k] != 0xFF)) ++ break; ++ else if (!negative && value_temp[k]) ++ break; ++ ++ if ((negative && !(value_temp[k] & 0x80)) || ++ (!negative && (value_temp[k] & 0x80))) ++ k--; ++ ++ _asn1_set_value_lv (node, value_temp + k, len - k); ++ ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if ((c_isdigit (p->value[0])) || (p->value[0] == '-')) ++ { ++ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (default_temp == NULL) ++ { ++ free (value_temp); ++ return ASN1_MEM_ALLOC_ERROR; ++ } ++ ++ _asn1_convert_integer (p->value, default_temp, ++ SIZEOF_UNSIGNED_LONG_INT, &len2); ++ } ++ else ++ { /* is an identifier like v1 */ ++ if (!(node->type & CONST_LIST)) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ p2 = node->down; ++ while (p2) ++ { ++ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p2->name, p->value)) ++ { ++ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); ++ if (default_temp == NULL) ++ { ++ free (value_temp); ++ return ASN1_MEM_ALLOC_ERROR; ++ } ++ ++ _asn1_convert_integer (p2->value, ++ default_temp, ++ SIZEOF_UNSIGNED_LONG_INT, ++ &len2); ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ if (p2 == NULL) ++ { ++ free (value_temp); ++ return ASN1_VALUE_NOT_VALID; ++ } ++ } ++ ++ ++ if ((len - k) == len2) ++ { ++ for (k2 = 0; k2 < len2; k2++) ++ if (value_temp[k + k2] != default_temp[k2]) ++ { ++ break; ++ } ++ if (k2 == len2) ++ _asn1_set_value (node, NULL, 0); ++ } ++ free (default_temp); ++ } ++ free (value_temp); ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ for (i = 0; i < _asn1_strlen (value); i++) ++ if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+')) ++ return ASN1_VALUE_NOT_VALID; ++ if (node->type & CONST_DEFAULT) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (!_asn1_strcmp (value, p->value)) ++ { ++ _asn1_set_value (node, NULL, 0); ++ break; ++ } ++ } ++ _asn1_set_value (node, value, _asn1_strlen (value) + 1); ++ break; ++ case ASN1_ETYPE_UTC_TIME: ++ { ++ len = _asn1_strlen (value); ++ if (len < 11) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 0; k < 10; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ switch (len) ++ { ++ case 11: ++ if (value[10] != 'Z') ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 13: ++ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) || ++ (value[12] != 'Z')) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 15: ++ if ((value[10] != '+') && (value[10] != '-')) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 11; k < 15; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ case 17: ++ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11]))) ++ return ASN1_VALUE_NOT_VALID; ++ if ((value[12] != '+') && (value[12] != '-')) ++ return ASN1_VALUE_NOT_VALID; ++ for (k = 13; k < 17; k++) ++ if (!c_isdigit (value[k])) ++ return ASN1_VALUE_NOT_VALID; ++ break; ++ default: ++ return ASN1_VALUE_NOT_FOUND; ++ } ++ _asn1_set_value (node, value, len); ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ len = _asn1_strlen (value); ++ _asn1_set_value (node, value, len); ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ if (len == 0) ++ len = _asn1_strlen (value); ++ _asn1_set_value_lv (node, value, len); ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ if (len == 0) ++ len = _asn1_strlen (value); ++ asn1_length_der ((len >> 3) + 2, NULL, &len2); ++ temp = malloc ((len >> 3) + 2 + len2); ++ if (temp == NULL) ++ return ASN1_MEM_ALLOC_ERROR; ++ ++ asn1_bit_der (value, len, temp, &len2); ++ _asn1_set_value_m (node, temp, len2); ++ temp = NULL; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ p = node->down; ++ while (p) ++ { ++ if (!_asn1_strcmp (p->name, value)) ++ { ++ p2 = node->down; ++ while (p2) ++ { ++ if (p2 != p) ++ { ++ asn1_delete_structure (&p2); ++ p2 = node->down; ++ } ++ else ++ p2 = p2->right; ++ } ++ break; ++ } ++ p = p->right; ++ } ++ if (!p) ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ case ASN1_ETYPE_ANY: ++ _asn1_set_value_lv (node, value, len); ++ break; ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SET_OF: ++ if (_asn1_strcmp (value, "NEW")) ++ return ASN1_VALUE_NOT_VALID; ++ _asn1_append_sequence_set (node, NULL); ++ break; ++ default: ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++#define PUT_VALUE( ptr, ptr_size, data, data_size) \ ++ *len = data_size; \ ++ if (ptr_size < data_size) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ if (ptr && data_size > 0) \ ++ memcpy (ptr, data, data_size); \ ++ } ++ ++#define PUT_STR_VALUE( ptr, ptr_size, data) \ ++ *len = _asn1_strlen (data) + 1; \ ++ if (ptr_size < *len) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcpy is checked */ \ ++ if (ptr) { \ ++ _asn1_strcpy (ptr, data); \ ++ } \ ++ } ++ ++#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \ ++ *len = data_size + 1; \ ++ if (ptr_size < *len) { \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcpy is checked */ \ ++ if (ptr) { \ ++ if (data_size > 0) \ ++ memcpy (ptr, data, data_size); \ ++ ptr[data_size] = 0; \ ++ } \ ++ } ++ ++#define ADD_STR_VALUE( ptr, ptr_size, data) \ ++ *len += _asn1_strlen(data); \ ++ if (ptr_size < (int) *len) { \ ++ (*len)++; \ ++ return ASN1_MEM_ERROR; \ ++ } else { \ ++ /* this strcat is checked */ \ ++ if (ptr) _asn1_strcat (ptr, data); \ ++ } ++ ++/** ++ * asn1_read_value: ++ * @root: pointer to a structure. ++ * @name: the name of the element inside a structure that you want to read. ++ * @ivalue: vector that will contain the element's content, must be a ++ * pointer to memory cells already allocated (may be %NULL). ++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy ++ * holds the sizeof value. ++ * ++ * Returns the value of one element inside a structure. ++ * If an element is OPTIONAL and this returns ++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present ++ * in the der encoding that created the structure. The first element ++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and ++ * so on. If the @root provided is a node to specific sequence element, ++ * then the keyword "?CURRENT" is also acceptable and indicates the ++ * current sequence element of this node. ++ * ++ * Note that there can be valid values with length zero. In these case ++ * this function will succeed and @len will be zero. ++ * ++ * INTEGER: VALUE will contain a two's complement form integer. ++ * ++ * integer=-1 -> value[0]=0xFF , len=1. ++ * integer=1 -> value[0]=0x01 , len=1. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or ++ * "FALSE" and LEN=5 or LEN=6. ++ * ++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with ++ * each number separated by a dot (i.e. "1.2.3.543.1"). ++ * ++ * LEN = strlen(VALUE)+1 ++ * ++ * UTCTime: VALUE will be a null terminated string in one of these ++ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". ++ * LEN=strlen(VALUE)+1. ++ * ++ * GeneralizedTime: VALUE will be a null terminated string in the ++ * same format used to set the value. ++ * ++ * OCTET STRING: VALUE will contain the octet string and LEN will be ++ * the number of octets. ++ * ++ * GeneralString: VALUE will contain the generalstring and LEN will ++ * be the number of octets. ++ * ++ * BIT STRING: VALUE will contain the bit string organized by bytes ++ * and LEN will be the number of bits. ++ * ++ * CHOICE: If NAME indicates a choice type, VALUE will specify the ++ * alternative selected. ++ * ++ * ANY: If NAME indicates an any type, VALUE will indicate the DER ++ * encoding of the structure actually used. ++ * ++ * Returns: %ASN1_SUCCESS if value is returned, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, ++ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element ++ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough ++ * to store the result, and in this case @len will contain the number of ++ * bytes needed. On the occasion that the stored data are of zero-length ++ * this function may return %ASN1_SUCCESS even if the provided @len is zero. ++ **/ ++int ++asn1_read_value (asn1_node_const root, const char *name, void *ivalue, int *len) ++{ ++ return asn1_read_value_type (root, name, ivalue, len, NULL); ++} ++ ++/** ++ * asn1_read_value_type: ++ * @root: pointer to a structure. ++ * @name: the name of the element inside a structure that you want to read. ++ * @ivalue: vector that will contain the element's content, must be a ++ * pointer to memory cells already allocated (may be %NULL). ++ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy ++ * holds the sizeof value. ++ * @etype: The type of the value read (ASN1_ETYPE) ++ * ++ * Returns the type and value of one element inside a structure. ++ * If an element is OPTIONAL and this returns ++ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present ++ * in the der encoding that created the structure. The first element ++ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and ++ * so on. If the @root provided is a node to specific sequence element, ++ * then the keyword "?CURRENT" is also acceptable and indicates the ++ * current sequence element of this node. ++ * ++ * Note that there can be valid values with length zero. In these case ++ * this function will succeed and @len will be zero. ++ * ++ * ++ * INTEGER: VALUE will contain a two's complement form integer. ++ * ++ * integer=-1 -> value[0]=0xFF , len=1. ++ * integer=1 -> value[0]=0x01 , len=1. ++ * ++ * ENUMERATED: As INTEGER (but only with not negative numbers). ++ * ++ * BOOLEAN: VALUE will be the null terminated string "TRUE" or ++ * "FALSE" and LEN=5 or LEN=6. ++ * ++ * OBJECT IDENTIFIER: VALUE will be a null terminated string with ++ * each number separated by a dot (i.e. "1.2.3.543.1"). ++ * ++ * LEN = strlen(VALUE)+1 ++ * ++ * UTCTime: VALUE will be a null terminated string in one of these ++ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". ++ * LEN=strlen(VALUE)+1. ++ * ++ * GeneralizedTime: VALUE will be a null terminated string in the ++ * same format used to set the value. ++ * ++ * OCTET STRING: VALUE will contain the octet string and LEN will be ++ * the number of octets. ++ * ++ * GeneralString: VALUE will contain the generalstring and LEN will ++ * be the number of octets. ++ * ++ * BIT STRING: VALUE will contain the bit string organized by bytes ++ * and LEN will be the number of bits. ++ * ++ * CHOICE: If NAME indicates a choice type, VALUE will specify the ++ * alternative selected. ++ * ++ * ANY: If NAME indicates an any type, VALUE will indicate the DER ++ * encoding of the structure actually used. ++ * ++ * Returns: %ASN1_SUCCESS if value is returned, ++ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, ++ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element ++ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough ++ * to store the result, and in this case @len will contain the number of ++ * bytes needed. On the occasion that the stored data are of zero-length ++ * this function may return %ASN1_SUCCESS even if the provided @len is zero. ++ **/ ++int ++asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue, ++ int *len, unsigned int *etype) ++{ ++ asn1_node_const node, p, p2; ++ int len2, len3, result; ++ int value_size = *len; ++ unsigned char *value = ivalue; ++ unsigned type; ++ ++ node = asn1_find_node (root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ type = type_field (node->type); ++ ++ if ((type != ASN1_ETYPE_NULL) && ++ (type != ASN1_ETYPE_CHOICE) && ++ !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) && ++ (node->value == NULL)) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ if (etype) ++ *etype = type; ++ switch (type) ++ { ++ case ASN1_ETYPE_NULL: ++ PUT_STR_VALUE (value, value_size, "NULL"); ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if (p->type & CONST_TRUE) ++ { ++ PUT_STR_VALUE (value, value_size, "TRUE"); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, "FALSE"); ++ } ++ } ++ else if (node->value[0] == 'T') ++ { ++ PUT_STR_VALUE (value, value_size, "TRUE"); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, "FALSE"); ++ } ++ break; ++ case ASN1_ETYPE_INTEGER: ++ case ASN1_ETYPE_ENUMERATED: ++ if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ if ((c_isdigit (p->value[0])) || (p->value[0] == '-') ++ || (p->value[0] == '+')) ++ { ++ result = _asn1_convert_integer ++ (p->value, value, value_size, len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ } ++ else ++ { /* is an identifier like v1 */ ++ p2 = node->down; ++ while (p2) ++ { ++ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (!_asn1_strcmp (p2->name, p->value)) ++ { ++ result = _asn1_convert_integer ++ (p2->value, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ } ++ } ++ p2 = p2->right; ++ } ++ } ++ } ++ else ++ { ++ len2 = -1; ++ result = asn1_get_octet_der ++ (node->value, node->value_len, &len2, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ } ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if (node->type & CONST_ASSIGN) ++ { ++ *len = 0; ++ if (value) ++ value[0] = 0; ++ p = node->down; ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_CONSTANT) ++ { ++ ADD_STR_VALUE (value, value_size, p->value); ++ if (p->right) ++ { ++ ADD_STR_VALUE (value, value_size, "."); ++ } ++ } ++ p = p->right; ++ } ++ (*len)++; ++ } ++ else if ((node->type & CONST_DEFAULT) && (node->value == NULL)) ++ { ++ p = node->down; ++ while (type_field (p->type) != ASN1_ETYPE_DEFAULT) ++ p = p->right; ++ PUT_STR_VALUE (value, value_size, p->value); ++ } ++ else ++ { ++ PUT_STR_VALUE (value, value_size, node->value); ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len); ++ break; ++ case ASN1_ETYPE_OCTET_STRING: ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ len2 = -1; ++ result = asn1_get_octet_der ++ (node->value, node->value_len, &len2, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ len2 = -1; ++ result = asn1_get_bit_der ++ (node->value, node->value_len, &len2, value, value_size, ++ len); ++ if (result != ASN1_SUCCESS) ++ return result; ++ break; ++ case ASN1_ETYPE_CHOICE: ++ PUT_STR_VALUE (value, value_size, node->down->name); ++ break; ++ case ASN1_ETYPE_ANY: ++ len3 = -1; ++ len2 = asn1_get_length_der (node->value, node->value_len, &len3); ++ if (len2 < 0) ++ return ASN1_DER_ERROR; ++ PUT_VALUE (value, value_size, node->value + len3, len2); ++ break; ++ default: ++ return ASN1_ELEMENT_NOT_FOUND; ++ break; ++ } ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_read_tag: ++ * @root: pointer to a structure ++ * @name: the name of the element inside a structure. ++ * @tagValue: variable that will contain the TAG value. ++ * @classValue: variable that will specify the TAG type. ++ * ++ * Returns the TAG and the CLASS of one element inside a structure. ++ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION, ++ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or ++ * %ASN1_CLASS_CONTEXT_SPECIFIC. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * @name is not a valid element. ++ **/ ++int ++asn1_read_tag (asn1_node_const root, const char *name, int *tagValue, ++ int *classValue) ++{ ++ asn1_node node, p, pTag; ++ ++ node = asn1_find_node (root, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node->down; ++ ++ /* pTag will points to the IMPLICIT TAG */ ++ pTag = NULL; ++ if (node->type & CONST_TAG) ++ { ++ while (p) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_TAG) ++ { ++ if ((p->type & CONST_IMPLICIT) && (pTag == NULL)) ++ pTag = p; ++ else if (p->type & CONST_EXPLICIT) ++ pTag = NULL; ++ } ++ p = p->right; ++ } ++ } ++ ++ if (pTag) ++ { ++ *tagValue = _asn1_strtoul (pTag->value, NULL, 10); ++ ++ if (pTag->type & CONST_APPLICATION) ++ *classValue = ASN1_CLASS_APPLICATION; ++ else if (pTag->type & CONST_UNIVERSAL) ++ *classValue = ASN1_CLASS_UNIVERSAL; ++ else if (pTag->type & CONST_PRIVATE) ++ *classValue = ASN1_CLASS_PRIVATE; ++ else ++ *classValue = ASN1_CLASS_CONTEXT_SPECIFIC; ++ } ++ else ++ { ++ unsigned type = type_field (node->type); ++ *classValue = ASN1_CLASS_UNIVERSAL; ++ ++ switch (type) ++ { ++ CASE_HANDLED_ETYPES: ++ *tagValue = _asn1_tags[type].tag; ++ break; ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_ANY: ++ *tagValue = -1; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++/** ++ * asn1_read_node_value: ++ * @node: pointer to a node. ++ * @data: a point to a asn1_data_node_st ++ * ++ * Returns the value a data node inside a asn1_node structure. ++ * The data returned should be handled as constant values. ++ * ++ * Returns: %ASN1_SUCCESS if the node exists. ++ **/ ++int ++asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data) ++{ ++ data->name = node->name; ++ data->value = node->value; ++ data->value_len = node->value_len; ++ data->type = type_field (node->type); ++ ++ return ASN1_SUCCESS; ++} +diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c +new file mode 100644 +index 0000000000..cee74daf79 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/errors.c +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include ++#ifdef STDC_HEADERS ++#include ++#endif ++ ++#define LIBTASN1_ERROR_ENTRY(name) { #name, name } ++ ++struct libtasn1_error_entry ++{ ++ const char *name; ++ int number; ++}; ++typedef struct libtasn1_error_entry libtasn1_error_entry; ++ ++static const libtasn1_error_entry error_algorithms[] = { ++ LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS), ++ LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND), ++ LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID), ++ LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT), ++ LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY), ++ LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW), ++ LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG), ++ LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY), ++ LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR), ++ LIBTASN1_ERROR_ENTRY (ASN1_RECURSION), ++ {0, 0} ++}; ++ ++/** ++ * asn1_perror: ++ * @error: is an error returned by a libtasn1 function. ++ * ++ * Prints a string to stderr with a description of an error. This ++ * function is like perror(). The only difference is that it accepts ++ * an error returned by a libtasn1 function. ++ * ++ * Since: 1.6 ++ **/ ++void ++asn1_perror (int error) ++{ ++ const char *str = asn1_strerror (error); ++ fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); ++} ++ ++/** ++ * asn1_strerror: ++ * @error: is an error returned by a libtasn1 function. ++ * ++ * Returns a string with a description of an error. This function is ++ * similar to strerror. The only difference is that it accepts an ++ * error (number) returned by a libtasn1 function. ++ * ++ * Returns: Pointer to static zero-terminated string describing error ++ * code. ++ * ++ * Since: 1.6 ++ **/ ++const char * ++asn1_strerror (int error) ++{ ++ const libtasn1_error_entry *p; ++ ++ for (p = error_algorithms; p->name != NULL; p++) ++ if (p->number == error) ++ return p->name + sizeof ("ASN1_") - 1; ++ ++ return NULL; ++} +diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c +new file mode 100644 +index 0000000000..e91a3a151c +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.c +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include ++#include "gstr.h" ++ ++/* These function are like strcat, strcpy. They only ++ * do bounds checking (they shouldn't cause buffer overruns), ++ * and they always produce null terminated strings. ++ * ++ * They should be used only with null terminated strings. ++ */ ++void ++_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) ++{ ++ size_t str_size = strlen (src); ++ size_t dest_size = strlen (dest); ++ ++ if (dest_tot_size - dest_size > str_size) ++ { ++ strcat (dest, src); ++ } ++ else ++ { ++ if (dest_tot_size - dest_size > 0) ++ { ++ strncat (dest, src, (dest_tot_size - dest_size) - 1); ++ dest[dest_tot_size - 1] = 0; ++ } ++ } ++} ++ ++/* Returns the bytes copied (not including the null terminator) */ ++unsigned int ++_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src) ++{ ++ size_t str_size = strlen (src); ++ ++ if (dest_tot_size > str_size) ++ { ++ strcpy (dest, src); ++ return str_size; ++ } ++ else ++ { ++ if (dest_tot_size > 0) ++ { ++ str_size = dest_tot_size - 1; ++ memcpy (dest, src, str_size); ++ dest[str_size] = 0; ++ return str_size; ++ } ++ else ++ return 0; ++ } ++} +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +new file mode 100644 +index 0000000000..d5dbbf8765 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.c +@@ -0,0 +1,1173 @@ ++/* ++ * Copyright (C) 2000-2016 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#include // WORD_BIT ++ ++#include "int.h" ++#include "parser_aux.h" ++#include "gstr.h" ++#include "structure.h" ++#include "element.h" ++#include "c-ctype.h" ++ ++char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ ++ ++/* Return a hash of the N bytes of X using the method described by ++ Bruno Haible in https://www.haible.de/bruno/hashfunc.html. ++ Note that while many hash functions reduce their result via modulo ++ to a 0..table_size-1 range, this function does not do that. ++ ++ This implementation has been changed from size_t -> unsigned int. */ ++ ++#ifdef __clang__ ++__attribute__((no_sanitize("integer"))) ++#endif ++_GL_ATTRIBUTE_PURE ++static unsigned int ++_asn1_hash_name (const char *x) ++{ ++ const unsigned char *s = (unsigned char *) x; ++ unsigned h = 0; ++ ++ while (*s) ++ h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9))); ++ ++ return h; ++} ++ ++/******************************************************/ ++/* Function : _asn1_add_static_node */ ++/* Description: creates a new NODE_ASN element and */ ++/* puts it in the list pointed by e_list. */ ++/* Parameters: */ ++/* e_list: of type list_type; must be NULL initially */ ++/* type: type of the new element (see ASN1_ETYPE_ */ ++/* and CONST_ constants). */ ++/* Return: pointer to the new element. */ ++/******************************************************/ ++asn1_node ++_asn1_add_static_node (list_type **e_list, unsigned int type) ++{ ++ list_type *p; ++ asn1_node punt; ++ ++ punt = calloc (1, sizeof (struct asn1_node_st)); ++ if (punt == NULL) ++ return NULL; ++ ++ p = malloc (sizeof (list_type)); ++ if (p == NULL) ++ { ++ free (punt); ++ return NULL; ++ } ++ ++ p->node = punt; ++ p->next = *e_list; ++ *e_list = p; ++ ++ punt->type = type; ++ ++ return punt; ++} ++ ++static ++int _asn1_add_static_node2 (list_type **e_list, asn1_node node) ++{ ++ list_type *p; ++ ++ p = malloc (sizeof (list_type)); ++ if (p == NULL) ++ { ++ return -1; ++ } ++ ++ p->node = node; ++ p->next = *e_list; ++ *e_list = p; ++ ++ return 0; ++} ++ ++/** ++ * asn1_find_node: ++ * @pointer: NODE_ASN element pointer. ++ * @name: null terminated string with the element's name to find. ++ * ++ * Searches for an element called @name starting from @pointer. The ++ * name is composed by different identifiers separated by dots. When ++ * *@pointer has a name, the first identifier must be the name of ++ * *@pointer, otherwise it must be the name of one child of *@pointer. ++ * ++ * Returns: the search result, or %NULL if not found. ++ **/ ++asn1_node ++asn1_find_node (asn1_node_const pointer, const char *name) ++{ ++ asn1_node_const p; ++ char *n_end, n[ASN1_MAX_NAME_SIZE + 1]; ++ const char *n_start; ++ unsigned int nsize; ++ unsigned int nhash; ++ ++ if (pointer == NULL) ++ return NULL; ++ ++ if (name == NULL) ++ return NULL; ++ ++ p = pointer; ++ n_start = name; ++ ++ if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?') ++ { /* ?CURRENT */ ++ n_start = strchr(n_start, '.'); ++ if (n_start) ++ n_start++; ++ } ++ else if (p->name[0] != 0) ++ { /* has *pointer got a name ? */ ++ n_end = strchr (n_start, '.'); /* search the first dot */ ++ if (n_end) ++ { ++ nsize = n_end - n_start; ++ if (nsize >= sizeof(n)) ++ return NULL; ++ ++ memcpy (n, n_start, nsize); ++ n[nsize] = 0; ++ n_start = n_end; ++ n_start++; ++ ++ nhash = _asn1_hash_name (n); ++ } ++ else ++ { ++ _asn1_str_cpy (n, sizeof (n), n_start); ++ nhash = _asn1_hash_name (n); ++ ++ n_start = NULL; ++ } ++ ++ while (p) ++ { ++ if (nhash == p->name_hash && (!strcmp (p->name, n))) ++ break; ++ else ++ p = p->right; ++ } /* while */ ++ ++ if (p == NULL) ++ return NULL; ++ } ++ else ++ { /* *pointer doesn't have a name */ ++ if (n_start[0] == 0) ++ return (asn1_node) p; ++ } ++ ++ while (n_start) ++ { /* Has the end of NAME been reached? */ ++ n_end = strchr (n_start, '.'); /* search the next dot */ ++ if (n_end) ++ { ++ nsize = n_end - n_start; ++ if (nsize >= sizeof(n)) ++ return NULL; ++ ++ memcpy (n, n_start, nsize); ++ n[nsize] = 0; ++ n_start = n_end; ++ n_start++; ++ ++ nhash = _asn1_hash_name (n); ++ } ++ else ++ { ++ _asn1_str_cpy (n, sizeof (n), n_start); ++ nhash = _asn1_hash_name (n); ++ n_start = NULL; ++ } ++ ++ if (p->down == NULL) ++ return NULL; ++ ++ p = p->down; ++ if (p == NULL) ++ return NULL; ++ ++ /* The identifier "?LAST" indicates the last element ++ in the right chain. */ ++ if (n[0] == '?' && n[1] == 'L') /* ?LAST */ ++ { ++ while (p->right) ++ p = p->right; ++ } ++ else ++ { /* no "?LAST" */ ++ while (p) ++ { ++ if (p->name_hash == nhash && !strcmp (p->name, n)) ++ break; ++ else ++ p = p->right; ++ } ++ } ++ if (p == NULL) ++ return NULL; ++ } /* while */ ++ ++ return (asn1_node) p; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_set_value */ ++/* Description: sets the field VALUE in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to set. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_value (asn1_node node, const void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ if (node->value) ++ { ++ if (node->value != node->small_value) ++ free (node->value); ++ node->value = NULL; ++ node->value_len = 0; ++ } ++ ++ if (!len) ++ return node; ++ ++ if (len < sizeof (node->small_value)) ++ { ++ node->value = node->small_value; ++ } ++ else ++ { ++ node->value = malloc (len); ++ if (node->value == NULL) ++ return NULL; ++ } ++ node->value_len = len; ++ ++ memcpy (node->value, value, len); ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_value_lv */ ++/* Description: sets the field VALUE in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost. The value */ ++/* given is stored as an length-value format (LV */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to set. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len) ++{ ++ int len2; ++ void *temp; ++ ++ if (node == NULL) ++ return node; ++ ++ asn1_length_der (len, NULL, &len2); ++ temp = malloc (len + len2); ++ if (temp == NULL) ++ return NULL; ++ ++ asn1_octet_der (value, len, temp, &len2); ++ return _asn1_set_value_m (node, temp, len2); ++} ++ ++/* the same as _asn1_set_value except that it sets an already malloc'ed ++ * value. ++ */ ++asn1_node ++_asn1_set_value_m (asn1_node node, void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ ++ if (node->value) ++ { ++ if (node->value != node->small_value) ++ free (node->value); ++ node->value = NULL; ++ node->value_len = 0; ++ } ++ ++ if (!len) ++ return node; ++ ++ node->value = value; ++ node->value_len = len; ++ ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_append_value */ ++/* Description: appends to the field VALUE in a NODE_ASN element. */ ++/* */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* value: pointer to the value that you want to be appended. */ ++/* len: character number of value. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_append_value (asn1_node node, const void *value, unsigned int len) ++{ ++ if (node == NULL) ++ return node; ++ ++ if (node->value == NULL) ++ return _asn1_set_value (node, value, len); ++ ++ if (len == 0) ++ return node; ++ ++ if (node->value == node->small_value) ++ { ++ /* value is in node */ ++ int prev_len = node->value_len; ++ node->value_len += len; ++ node->value = malloc (node->value_len); ++ if (node->value == NULL) ++ { ++ node->value_len = 0; ++ return NULL; ++ } ++ ++ if (prev_len > 0) ++ memcpy (node->value, node->small_value, prev_len); ++ ++ memcpy (&node->value[prev_len], value, len); ++ ++ return node; ++ } ++ else /* if (node->value != NULL && node->value != node->small_value) */ ++ { ++ /* value is allocated */ ++ int prev_len = node->value_len; ++ node->value_len += len; ++ ++ node->value = _asn1_realloc (node->value, node->value_len); ++ if (node->value == NULL) ++ { ++ node->value_len = 0; ++ return NULL; ++ } ++ ++ memcpy (&node->value[prev_len], value, len); ++ ++ return node; ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_name */ ++/* Description: sets the field NAME in a NODE_ASN element. The */ ++/* previous value (if exist) will be lost */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* name: a null terminated string with the name that you want */ ++/* to set. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_name (asn1_node node, const char *name) ++{ ++ if (node == NULL) ++ return node; ++ ++ _asn1_str_cpy (node->name, sizeof (node->name), name ? name : ""); ++ node->name_hash = _asn1_hash_name (node->name); ++ ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_cpy_name */ ++/* Description: copies the field NAME in a NODE_ASN element. */ ++/* Parameters: */ ++/* dst: a dest element pointer. */ ++/* src: a source element pointer. */ ++/* Return: pointer to the NODE_ASN element. */ ++/******************************************************************/ ++asn1_node ++_asn1_cpy_name (asn1_node dst, asn1_node_const src) ++{ ++ if (dst == NULL) ++ return dst; ++ ++ if (src == NULL) ++ { ++ dst->name[0] = 0; ++ dst->name_hash = _asn1_hash_name (dst->name); ++ return dst; ++ } ++ ++ _asn1_str_cpy (dst->name, sizeof (dst->name), src->name); ++ dst->name_hash = src->name_hash; ++ ++ return dst; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_right */ ++/* Description: sets the field RIGHT in a NODE_ASN element. */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* right: pointer to a NODE_ASN element that you want be pointed*/ ++/* by NODE. */ ++/* Return: pointer to *NODE. */ ++/******************************************************************/ ++asn1_node ++_asn1_set_right (asn1_node node, asn1_node right) ++{ ++ if (node == NULL) ++ return node; ++ node->right = right; ++ if (right) ++ right->left = node; ++ return node; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_get_last_right */ ++/* Description: return the last element along the right chain. */ ++/* Parameters: */ ++/* node: starting element pointer. */ ++/* Return: pointer to the last element along the right chain. */ ++/******************************************************************/ ++asn1_node ++_asn1_get_last_right (asn1_node_const node) ++{ ++ asn1_node_const p; ++ ++ if (node == NULL) ++ return NULL; ++ p = node; ++ while (p->right) ++ p = p->right; ++ return (asn1_node) p; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_remove_node */ ++/* Description: gets free the memory allocated for an NODE_ASN */ ++/* element (not the elements pointed by it). */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* flags: ASN1_DELETE_FLAG_* */ ++/******************************************************************/ ++void ++_asn1_remove_node (asn1_node node, unsigned int flags) ++{ ++ if (node == NULL) ++ return; ++ ++ if (node->value != NULL) ++ { ++ if (flags & ASN1_DELETE_FLAG_ZEROIZE) ++ { ++ safe_memset(node->value, 0, node->value_len); ++ } ++ ++ if (node->value != node->small_value) ++ free (node->value); ++ } ++ free (node); ++} ++ ++/******************************************************************/ ++/* Function : _asn1_find_up */ ++/* Description: return the father of the NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: Null if not found. */ ++/******************************************************************/ ++asn1_node ++_asn1_find_up (asn1_node_const node) ++{ ++ asn1_node_const p; ++ ++ if (node == NULL) ++ return NULL; ++ ++ p = node; ++ ++ while ((p->left != NULL) && (p->left->right == p)) ++ p = p->left; ++ ++ return p->left; ++} ++ ++static ++unsigned _asn1_is_up (asn1_node_const up_cand, asn1_node_const down) ++{ ++ asn1_node_const d, u; ++ ++ if (up_cand == NULL || down == NULL) ++ return 0; ++ ++ d = down; ++ ++ while ((u = _asn1_find_up(d)) != NULL && u != d) ++ { ++ if (u == up_cand) ++ return 1; ++ d = u; ++ } ++ ++ return 0; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_node_from_list */ ++/* Description: deletes the list element given */ ++/******************************************************************/ ++void ++_asn1_delete_node_from_list (list_type *list, asn1_node node) ++{ ++ list_type *p = list; ++ ++ while (p) ++ { ++ if (p->node == node) ++ p->node = NULL; ++ p = p->next; ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_list */ ++/* Description: deletes the list elements (not the elements */ ++/* pointed by them). */ ++/******************************************************************/ ++void ++_asn1_delete_list (list_type *e_list) ++{ ++ list_type *p; ++ ++ while (e_list) ++ { ++ p = e_list; ++ e_list = e_list->next; ++ free (p); ++ } ++} ++ ++/******************************************************************/ ++/* Function : _asn1_delete_list_and nodes */ ++/* Description: deletes the list elements and the elements */ ++/* pointed by them. */ ++/******************************************************************/ ++void ++_asn1_delete_list_and_nodes (list_type *e_list) ++{ ++ list_type *p; ++ ++ while (e_list) ++ { ++ p = e_list; ++ e_list = e_list->next; ++ _asn1_remove_node (p->node, 0); ++ free (p); ++ } ++} ++ ++ ++char * ++_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) ++{ ++ uint64_t d, r; ++ char temp[LTOSTR_MAX_SIZE]; ++ int count, k, start; ++ uint64_t val; ++ ++ if (v < 0) ++ { ++ str[0] = '-'; ++ start = 1; ++ val = -((uint64_t)v); ++ } ++ else ++ { ++ val = v; ++ start = 0; ++ } ++ ++ count = 0; ++ do ++ { ++ d = val / 10; ++ r = val - d * 10; ++ temp[start + count] = '0' + (char) r; ++ count++; ++ val = d; ++ } ++ while (val && ((start+count) < LTOSTR_MAX_SIZE-1)); ++ ++ for (k = 0; k < count; k++) ++ str[k + start] = temp[start + count - k - 1]; ++ str[count + start] = 0; ++ return str; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_change_integer_value */ ++/* Description: converts into DER coding the value assign to an */ ++/* INTEGER constant. */ ++/* Parameters: */ ++/* node: root of an ASN1element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_change_integer_value (asn1_node node) ++{ ++ asn1_node p; ++ unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; ++ unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1]; ++ int len; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_INTEGER) ++ && (p->type & CONST_ASSIGN)) ++ { ++ if (p->value) ++ { ++ _asn1_convert_integer (p->value, val, sizeof (val), &len); ++ asn1_octet_der (val, len, val2, &len); ++ _asn1_set_value (p, val2, len); ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { ++ if (p == node) ++ p = NULL; ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++#define MAX_CONSTANTS 1024 ++/******************************************************************/ ++/* Function : _asn1_expand_object_id */ ++/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */ ++/* Parameters: */ ++/* list: root of an object list */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_expand_object_id (list_type **list, asn1_node node) ++{ ++ asn1_node p, p2, p3, p4, p5; ++ char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1]; ++ int move, tlen, tries; ++ unsigned max_constants; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_str_cpy (name_root, sizeof (name_root), node->name); ++ ++ p = node; ++ move = DOWN; ++ tries = 0; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) ++ && (p->type & CONST_ASSIGN)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) ++ { ++ if (p2->value && !c_isdigit (p2->value[0])) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), name_root); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ p3 = asn1_find_node (node, name2); ++ if (!p3 || _asn1_is_up(p2, p3) || ++ (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || ++ !(p3->type & CONST_ASSIGN)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_set_down (p, p2->right); ++ if (p2->down) ++ _asn1_delete_structure (*list, &p2->down, 0); ++ _asn1_delete_node_from_list(*list, p2); ++ _asn1_remove_node (p2, 0); ++ p2 = p; ++ p4 = p3->down; ++ max_constants = 0; ++ while (p4) ++ { ++ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) ++ { ++ max_constants++; ++ if (max_constants == MAX_CONSTANTS) ++ return ASN1_RECURSION; ++ ++ p5 = ++ _asn1_add_single_node (ASN1_ETYPE_CONSTANT); ++ _asn1_set_name (p5, p4->name); ++ if (p4->value) ++ { ++ tlen = _asn1_strlen (p4->value); ++ if (tlen > 0) ++ _asn1_set_value (p5, p4->value, tlen + 1); ++ } ++ _asn1_add_static_node2(list, p5); ++ ++ if (p2 == p) ++ { ++ _asn1_set_right (p5, p->down); ++ _asn1_set_down (p, p5); ++ } ++ else ++ { ++ _asn1_set_right (p5, p2->right); ++ _asn1_set_right (p2, p5); ++ } ++ p2 = p5; ++ } ++ p4 = p4->right; ++ } ++ move = DOWN; ++ ++ tries++; ++ if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION) ++ return ASN1_RECURSION; ++ ++ continue; ++ } ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ tries = 0; ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ /*******************************/ ++ /* expand DEFAULT */ ++ /*******************************/ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_DEFAULT)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), name_root); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ if (p2->value) ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ p3 = asn1_find_node (node, name2); ++ if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ++ || !(p3->type & CONST_ASSIGN)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ p4 = p3->down; ++ name2[0] = 0; ++ while (p4) ++ { ++ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) ++ { ++ if (p4->value == NULL) ++ return ASN1_VALUE_NOT_FOUND; ++ ++ if (name2[0]) ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), ++ (char *) p4->value); ++ } ++ p4 = p4->right; ++ } ++ tlen = strlen (name2); ++ if (tlen > 0) ++ _asn1_set_value (p2, name2, tlen + 1); ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_type_set_config */ ++/* Description: sets the CONST_SET and CONST_NOT_USED properties */ ++/* in the fields of the SET elements. */ ++/* Parameters: */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_type_set_config (asn1_node node) ++{ ++ asn1_node p, p2; ++ int move; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_SET) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ p2->type |= CONST_SET | CONST_NOT_USED; ++ p2 = p2->right; ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p && p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_check_identifier */ ++/* Description: checks the definitions of all the identifiers */ ++/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */ ++/* The _asn1_identifierMissing global variable is filled if */ ++/* necessary. */ ++/* Parameters: */ ++/* node: root of an ASN1 element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ ++/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_check_identifier (asn1_node_const node) ++{ ++ asn1_node_const p, p2; ++ char name2[ASN1_MAX_NAME_SIZE * 2 + 2]; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p->value); ++ p2 = asn1_find_node (node, name2); ++ if (p2 == NULL) ++ { ++ if (p->value) ++ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p->value); ++ else ++ _asn1_strcpy (_asn1_identifierMissing, "(null)"); ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ } ++ } ++ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_DEFAULT)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ if (p2->value) ++ { ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); ++ } ++ else ++ _asn1_strcpy (_asn1_identifierMissing, "(null)"); ++ ++ p2 = asn1_find_node (node, name2); ++ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || ++ !(p2->type & CONST_ASSIGN)) ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ else ++ _asn1_identifierMissing[0] = 0; ++ } ++ } ++ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_ASSIGN)) ++ { ++ p2 = p->down; ++ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) ++ { ++ if (p2->value && !c_isdigit (p2->value[0])) ++ { ++ _asn1_str_cpy (name2, sizeof (name2), node->name); ++ _asn1_str_cat (name2, sizeof (name2), "."); ++ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); ++ _asn1_str_cpy (_asn1_identifierMissing, sizeof(_asn1_identifierMissing), (char*)p2->value); ++ ++ p2 = asn1_find_node (node, name2); ++ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ++ || !(p2->type & CONST_ASSIGN)) ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ else ++ _asn1_identifierMissing[0] = 0; ++ } ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (p) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_set_default_tag */ ++/* Description: sets the default IMPLICIT or EXPLICIT property in */ ++/* the tagged elements that don't have this declaration. */ ++/* Parameters: */ ++/* node: pointer to a DEFINITIONS element. */ ++/* Return: */ ++/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */ ++/* a DEFINITIONS element, */ ++/* otherwise ASN1_SUCCESS */ ++/******************************************************************/ ++int ++_asn1_set_default_tag (asn1_node node) ++{ ++ asn1_node p; ++ ++ if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS)) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_TAG) && ++ !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT)) ++ { ++ if (node->type & CONST_EXPLICIT) ++ p->type |= CONST_EXPLICIT; ++ else ++ p->type |= CONST_IMPLICIT; ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == node) ++ { ++ p = NULL; ++ break; ++ } ++ if (p && p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ return ASN1_SUCCESS; ++} +diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c +new file mode 100644 +index 0000000000..8189c56a4c +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.c +@@ -0,0 +1,1220 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++ ++/*****************************************************/ ++/* File: structure.c */ ++/* Description: Functions to create and delete an */ ++/* ASN1 tree. */ ++/*****************************************************/ ++ ++ ++#include ++#include ++#include "parser_aux.h" ++#include ++ ++ ++extern char _asn1_identifierMissing[]; ++ ++ ++/******************************************************/ ++/* Function : _asn1_add_single_node */ ++/* Description: creates a new NODE_ASN element. */ ++/* Parameters: */ ++/* type: type of the new element (see ASN1_ETYPE_ */ ++/* and CONST_ constants). */ ++/* Return: pointer to the new element. */ ++/******************************************************/ ++asn1_node ++_asn1_add_single_node (unsigned int type) ++{ ++ asn1_node punt; ++ ++ punt = calloc (1, sizeof (struct asn1_node_st)); ++ if (punt == NULL) ++ return NULL; ++ ++ punt->type = type; ++ ++ return punt; ++} ++ ++ ++/******************************************************************/ ++/* Function : _asn1_find_left */ ++/* Description: returns the NODE_ASN element with RIGHT field that*/ ++/* points the element NODE. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: NULL if not found. */ ++/******************************************************************/ ++asn1_node ++_asn1_find_left (asn1_node_const node) ++{ ++ if ((node == NULL) || (node->left == NULL) || (node->left->down == node)) ++ return NULL; ++ ++ return node->left; ++} ++ ++ ++int ++_asn1_create_static_structure (asn1_node_const pointer, char *output_file_name, ++ char *vector_name) ++{ ++ FILE *file; ++ asn1_node_const p; ++ unsigned long t; ++ ++ file = fopen (output_file_name, "w"); ++ ++ if (file == NULL) ++ return ASN1_FILE_NOT_FOUND; ++ ++ fprintf (file, "#if HAVE_CONFIG_H\n"); ++ fprintf (file, "# include \"config.h\"\n"); ++ fprintf (file, "#endif\n\n"); ++ ++ fprintf (file, "#include \n\n"); ++ ++ fprintf (file, "const asn1_static_node %s[] = {\n", vector_name); ++ ++ p = pointer; ++ ++ while (p) ++ { ++ fprintf (file, " { "); ++ ++ if (p->name[0] != 0) ++ fprintf (file, "\"%s\", ", p->name); ++ else ++ fprintf (file, "NULL, "); ++ ++ t = p->type; ++ if (p->down) ++ t |= CONST_DOWN; ++ if (p->right) ++ t |= CONST_RIGHT; ++ ++ fprintf (file, "%lu, ", t); ++ ++ if (p->value) ++ fprintf (file, "\"%s\"},\n", p->value); ++ else ++ fprintf (file, "NULL },\n"); ++ ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else if (p->right) ++ { ++ p = p->right; ++ } ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == pointer) ++ { ++ p = NULL; ++ break; ++ } ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++ ++ fprintf (file, " { NULL, 0, NULL }\n};\n"); ++ ++ fclose (file); ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_array2tree: ++ * @array: specify the array that contains ASN.1 declarations ++ * @definitions: return the pointer to the structure created by ++ * *ARRAY ASN.1 declarations ++ * @errorDescription: return the error description. ++ * ++ * Creates the structures needed to manage the ASN.1 definitions. ++ * @array is a vector created by asn1_parser2array(). ++ * ++ * Returns: %ASN1_SUCCESS if structure was created correctly, ++ * %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL, ++ * %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier ++ * that is not defined (see @errorDescription for more information), ++ * %ASN1_ARRAY_ERROR if the array pointed by @array is wrong. ++ **/ ++int ++asn1_array2tree (const asn1_static_node * array, asn1_node * definitions, ++ char *errorDescription) ++{ ++ asn1_node p, p_last = NULL; ++ unsigned long k; ++ int move; ++ int result; ++ unsigned int type; ++ list_type *e_list = NULL; ++ ++ if (errorDescription) ++ errorDescription[0] = 0; ++ ++ if (*definitions != NULL) ++ return ASN1_ELEMENT_NOT_EMPTY; ++ ++ move = UP; ++ ++ for (k = 0; array[k].value || array[k].type || array[k].name; k++) ++ { ++ type = convert_old_type (array[k].type); ++ ++ p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN)); ++ if (array[k].name) ++ _asn1_set_name (p, array[k].name); ++ if (array[k].value) ++ _asn1_set_value (p, array[k].value, strlen (array[k].value) + 1); ++ ++ if (*definitions == NULL) ++ *definitions = p; ++ ++ if (move == DOWN) ++ { ++ if (p_last && p_last->down) ++ _asn1_delete_structure (e_list, &p_last->down, 0); ++ _asn1_set_down (p_last, p); ++ } ++ else if (move == RIGHT) ++ { ++ if (p_last && p_last->right) ++ _asn1_delete_structure (e_list, &p_last->right, 0); ++ _asn1_set_right (p_last, p); ++ } ++ ++ p_last = p; ++ ++ if (type & CONST_DOWN) ++ move = DOWN; ++ else if (type & CONST_RIGHT) ++ move = RIGHT; ++ else ++ { ++ while (p_last != *definitions) ++ { ++ p_last = _asn1_find_up (p_last); ++ ++ if (p_last == NULL) ++ break; ++ ++ if (p_last->type & CONST_RIGHT) ++ { ++ p_last->type &= ~CONST_RIGHT; ++ move = RIGHT; ++ break; ++ } ++ } /* while */ ++ } ++ } /* while */ ++ ++ if (p_last == *definitions) ++ { ++ result = _asn1_check_identifier (*definitions); ++ if (result == ASN1_SUCCESS) ++ { ++ _asn1_change_integer_value (*definitions); ++ result = _asn1_expand_object_id (&e_list, *definitions); ++ } ++ } ++ else ++ { ++ result = ASN1_ARRAY_ERROR; ++ } ++ ++ if (errorDescription != NULL) ++ { ++ if (result == ASN1_IDENTIFIER_NOT_FOUND) ++ { ++ Estrcpy (errorDescription, ":: identifier '"); ++ Estrcat (errorDescription, _asn1_identifierMissing); ++ Estrcat (errorDescription, "' not found"); ++ } ++ else ++ errorDescription[0] = 0; ++ } ++ ++ if (result != ASN1_SUCCESS) ++ { ++ _asn1_delete_list_and_nodes (e_list); ++ *definitions = NULL; ++ } ++ else ++ _asn1_delete_list (e_list); ++ ++ return result; ++} ++ ++/** ++ * asn1_delete_structure: ++ * @structure: pointer to the structure that you want to delete. ++ * ++ * Deletes the structure *@structure. At the end, *@structure is set ++ * to NULL. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * *@structure was NULL. ++ **/ ++int ++asn1_delete_structure (asn1_node * structure) ++{ ++ return _asn1_delete_structure (NULL, structure, 0); ++} ++ ++/** ++ * asn1_delete_structure2: ++ * @structure: pointer to the structure that you want to delete. ++ * @flags: additional flags (see %ASN1_DELETE_FLAG) ++ * ++ * Deletes the structure *@structure. At the end, *@structure is set ++ * to NULL. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * *@structure was NULL. ++ **/ ++int ++asn1_delete_structure2 (asn1_node * structure, unsigned int flags) ++{ ++ return _asn1_delete_structure (NULL, structure, flags); ++} ++ ++int ++_asn1_delete_structure (list_type *e_list, asn1_node * structure, unsigned int flags) ++{ ++ asn1_node p, p2, p3; ++ ++ if (*structure == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = *structure; ++ while (p) ++ { ++ if (p->down) ++ { ++ p = p->down; ++ } ++ else ++ { /* no down */ ++ p2 = p->right; ++ if (p != *structure) ++ { ++ p3 = _asn1_find_up (p); ++ _asn1_set_down (p3, p2); ++ if (e_list) ++ _asn1_delete_node_from_list (e_list, p); ++ _asn1_remove_node (p, flags); ++ p = p3; ++ } ++ else ++ { /* p==root */ ++ p3 = _asn1_find_left (p); ++ if (!p3) ++ { ++ p3 = _asn1_find_up (p); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else ++ { ++ if (p->right) ++ p->right->left = NULL; ++ } ++ } ++ else ++ _asn1_set_right (p3, p2); ++ if (e_list) ++ _asn1_delete_node_from_list (e_list, p); ++ _asn1_remove_node (p, flags); ++ p = NULL; ++ } ++ } ++ } ++ ++ *structure = NULL; ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_delete_element: ++ * @structure: pointer to the structure that contains the element you ++ * want to delete. ++ * @element_name: element's name you want to delete. ++ * ++ * Deletes the element named *@element_name inside *@structure. ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * the @element_name was not found. ++ **/ ++int ++asn1_delete_element (asn1_node structure, const char *element_name) ++{ ++ asn1_node p2, p3, source_node; ++ ++ source_node = asn1_find_node (structure, element_name); ++ ++ if (source_node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p2 = source_node->right; ++ p3 = _asn1_find_left (source_node); ++ if (!p3) ++ { ++ p3 = _asn1_find_up (source_node); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else if (source_node->right) ++ source_node->right->left = NULL; ++ } ++ else ++ _asn1_set_right (p3, p2); ++ ++ return asn1_delete_structure (&source_node); ++} ++ ++#ifndef __clang_analyzer__ ++asn1_node ++_asn1_copy_structure3 (asn1_node_const source_node) ++{ ++ asn1_node_const p_s; ++ asn1_node dest_node, p_d, p_d_prev; ++ int move; ++ ++ if (source_node == NULL) ++ return NULL; ++ ++ dest_node = _asn1_add_single_node (source_node->type); ++ ++ p_s = source_node; ++ p_d = dest_node; ++ ++ move = DOWN; ++ ++ do ++ { ++ if (move != UP) ++ { ++ if (p_s->name[0] != 0) ++ _asn1_cpy_name (p_d, p_s); ++ if (p_s->value) ++ _asn1_set_value (p_d, p_s->value, p_s->value_len); ++ if (p_s->down) ++ { ++ p_s = p_s->down; ++ p_d_prev = p_d; ++ p_d = _asn1_add_single_node (p_s->type); ++ _asn1_set_down (p_d_prev, p_d); ++ continue; ++ } ++ p_d->start = p_s->start; ++ p_d->end = p_s->end; ++ } ++ ++ if (p_s == source_node) ++ break; ++ ++ if (p_s->right) ++ { ++ move = RIGHT; ++ p_s = p_s->right; ++ p_d_prev = p_d; ++ p_d = _asn1_add_single_node (p_s->type); ++ _asn1_set_right (p_d_prev, p_d); ++ } ++ else ++ { ++ move = UP; ++ p_s = _asn1_find_up (p_s); ++ p_d = _asn1_find_up (p_d); ++ } ++ } ++ while (p_s != source_node); ++ return dest_node; ++} ++#else ++ ++/* Non-production code */ ++asn1_node ++_asn1_copy_structure3 (asn1_node_const source_node) ++{ ++ return NULL; ++} ++#endif /* __clang_analyzer__ */ ++ ++ ++static asn1_node ++_asn1_copy_structure2 (asn1_node_const root, const char *source_name) ++{ ++ asn1_node source_node; ++ ++ source_node = asn1_find_node (root, source_name); ++ ++ return _asn1_copy_structure3 (source_node); ++ ++} ++ ++ ++static int ++_asn1_type_choice_config (asn1_node node) ++{ ++ asn1_node p, p2, p3, p4; ++ int move, tlen; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node; ++ move = DOWN; ++ ++ while (!((p == node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_CHOICE) ++ && (p->type & CONST_TAG)) ++ { ++ p2 = p->down; ++ while (p2) ++ { ++ if (type_field (p2->type) != ASN1_ETYPE_TAG) ++ { ++ p2->type |= CONST_TAG; ++ p3 = _asn1_find_left (p2); ++ while (p3) ++ { ++ if (type_field (p3->type) == ASN1_ETYPE_TAG) ++ { ++ p4 = _asn1_add_single_node (p3->type); ++ tlen = _asn1_strlen (p3->value); ++ if (tlen > 0) ++ _asn1_set_value (p4, p3->value, tlen + 1); ++ _asn1_set_right (p4, p2->down); ++ _asn1_set_down (p2, p4); ++ } ++ p3 = _asn1_find_left (p3); ++ } ++ } ++ p2 = p2->right; ++ } ++ p->type &= ~(CONST_TAG); ++ p2 = p->down; ++ while (p2) ++ { ++ p3 = p2->right; ++ if (type_field (p2->type) == ASN1_ETYPE_TAG) ++ asn1_delete_structure (&p2); ++ p2 = p3; ++ } ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++static int ++_asn1_expand_identifier (asn1_node * node, asn1_node_const root) ++{ ++ asn1_node p, p2, p3; ++ char name2[ASN1_MAX_NAME_SIZE + 2]; ++ int move; ++ ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = *node; ++ move = DOWN; ++ ++ while (!((p == *node) && (move == UP))) ++ { ++ if (move != UP) ++ { ++ if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER) ++ { ++ snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value); ++ p2 = _asn1_copy_structure2 (root, name2); ++ if (p2 == NULL) ++ { ++ return ASN1_IDENTIFIER_NOT_FOUND; ++ } ++ _asn1_cpy_name (p2, p); ++ p2->right = p->right; ++ p2->left = p->left; ++ if (p->right) ++ p->right->left = p2; ++ p3 = p->down; ++ if (p3) ++ { ++ while (p3->right) ++ p3 = p3->right; ++ _asn1_set_right (p3, p2->down); ++ _asn1_set_down (p2, p->down); ++ } ++ ++ p3 = _asn1_find_left (p); ++ if (p3) ++ _asn1_set_right (p3, p2); ++ else ++ { ++ p3 = _asn1_find_up (p); ++ if (p3) ++ _asn1_set_down (p3, p2); ++ else ++ { ++ p2->left = NULL; ++ } ++ } ++ ++ if (p->type & CONST_SIZE) ++ p2->type |= CONST_SIZE; ++ if (p->type & CONST_TAG) ++ p2->type |= CONST_TAG; ++ if (p->type & CONST_OPTION) ++ p2->type |= CONST_OPTION; ++ if (p->type & CONST_DEFAULT) ++ p2->type |= CONST_DEFAULT; ++ if (p->type & CONST_SET) ++ p2->type |= CONST_SET; ++ if (p->type & CONST_NOT_USED) ++ p2->type |= CONST_NOT_USED; ++ ++ if (p == *node) ++ *node = p2; ++ _asn1_remove_node (p, 0); ++ p = p2; ++ move = DOWN; ++ continue; ++ } ++ move = DOWN; ++ } ++ else ++ move = RIGHT; ++ ++ if (move == DOWN) ++ { ++ if (p->down) ++ p = p->down; ++ else ++ move = RIGHT; ++ } ++ ++ if (p == *node) ++ { ++ move = UP; ++ continue; ++ } ++ ++ if (move == RIGHT) ++ { ++ if (p->right) ++ p = p->right; ++ else ++ move = UP; ++ } ++ if (move == UP) ++ p = _asn1_find_up (p); ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_create_element: ++ * @definitions: pointer to the structure returned by "parser_asn1" function ++ * @source_name: the name of the type of the new structure (must be ++ * inside p_structure). ++ * @element: pointer to the structure created. ++ * ++ * Creates a structure of type @source_name. Example using ++ * "pkix.asn": ++ * ++ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr); ++ * ++ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if ++ * @source_name is not known. ++ **/ ++int ++asn1_create_element (asn1_node_const definitions, const char *source_name, ++ asn1_node * element) ++{ ++ asn1_node dest_node; ++ int res; ++ ++ dest_node = _asn1_copy_structure2 (definitions, source_name); ++ ++ if (dest_node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ _asn1_set_name (dest_node, ""); ++ ++ res = _asn1_expand_identifier (&dest_node, definitions); ++ _asn1_type_choice_config (dest_node); ++ ++ *element = dest_node; ++ ++ return res; ++} ++ ++ ++/** ++ * asn1_print_structure: ++ * @out: pointer to the output file (e.g. stdout). ++ * @structure: pointer to the structure that you want to visit. ++ * @name: an element of the structure ++ * @mode: specify how much of the structure to print, can be ++ * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE, ++ * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL. ++ * ++ * Prints on the @out file descriptor the structure's tree starting ++ * from the @name element inside the structure @structure. ++ **/ ++void ++asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, ++ int mode) ++{ ++ asn1_node_const p, root; ++ int k, indent = 0, len, len2, len3; ++ ++ if (out == NULL) ++ return; ++ ++ root = asn1_find_node (structure, name); ++ ++ if (root == NULL) ++ return; ++ ++ p = root; ++ while (p) ++ { ++ if (mode == ASN1_PRINT_ALL) ++ { ++ for (k = 0; k < indent; k++) ++ fprintf (out, " "); ++ fprintf (out, "name:"); ++ if (p->name[0] != 0) ++ fprintf (out, "%s ", p->name); ++ else ++ fprintf (out, "NULL "); ++ } ++ else ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_SIZE: ++ break; ++ default: ++ for (k = 0; k < indent; k++) ++ fprintf (out, " "); ++ fprintf (out, "name:"); ++ if (p->name[0] != 0) ++ fprintf (out, "%s ", p->name); ++ else ++ fprintf (out, "NULL "); ++ } ++ } ++ ++ if (mode != ASN1_PRINT_NAME) ++ { ++ unsigned type = type_field (p->type); ++ switch (type) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:CONST"); ++ break; ++ case ASN1_ETYPE_TAG: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:TAG"); ++ break; ++ case ASN1_ETYPE_SIZE: ++ if (mode == ASN1_PRINT_ALL) ++ fprintf (out, "type:SIZE"); ++ break; ++ case ASN1_ETYPE_DEFAULT: ++ fprintf (out, "type:DEFAULT"); ++ break; ++ case ASN1_ETYPE_IDENTIFIER: ++ fprintf (out, "type:IDENTIFIER"); ++ break; ++ case ASN1_ETYPE_ANY: ++ fprintf (out, "type:ANY"); ++ break; ++ case ASN1_ETYPE_CHOICE: ++ fprintf (out, "type:CHOICE"); ++ break; ++ case ASN1_ETYPE_DEFINITIONS: ++ fprintf (out, "type:DEFINITIONS"); ++ break; ++ CASE_HANDLED_ETYPES: ++ fprintf (out, "%s", _asn1_tags[type].desc); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL)) ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_TAG: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_SIZE: ++ if (mode == ASN1_PRINT_ALL) ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_DEFAULT: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ else if (p->type & CONST_TRUE) ++ fprintf (out, " value:TRUE"); ++ else if (p->type & CONST_FALSE) ++ fprintf (out, " value:FALSE"); ++ break; ++ case ASN1_ETYPE_IDENTIFIER: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_INTEGER: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:0x"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_ENUMERATED: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:0x"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_BOOLEAN: ++ if (p->value) ++ { ++ if (p->value[0] == 'T') ++ fprintf (out, " value:TRUE"); ++ else if (p->value[0] == 'F') ++ fprintf (out, " value:FALSE"); ++ } ++ break; ++ case ASN1_ETYPE_BIT_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ if (len > 0) ++ { ++ fprintf (out, " value(%i):", ++ (len - 1) * 8 - (p->value[len2])); ++ for (k = 1; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ } ++ break; ++ case ASN1_ETYPE_GENERALIZED_TIME: ++ case ASN1_ETYPE_UTC_TIME: ++ if (p->value) ++ { ++ fprintf (out, " value:"); ++ for (k = 0; k < p->value_len; k++) ++ fprintf (out, "%c", (p->value)[k]); ++ } ++ break; ++ case ASN1_ETYPE_GENERALSTRING: ++ case ASN1_ETYPE_NUMERIC_STRING: ++ case ASN1_ETYPE_IA5_STRING: ++ case ASN1_ETYPE_TELETEX_STRING: ++ case ASN1_ETYPE_PRINTABLE_STRING: ++ case ASN1_ETYPE_UNIVERSAL_STRING: ++ case ASN1_ETYPE_UTF8_STRING: ++ case ASN1_ETYPE_VISIBLE_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%c", (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_BMP_STRING: ++ case ASN1_ETYPE_OCTET_STRING: ++ if (p->value) ++ { ++ len2 = -1; ++ len = asn1_get_length_der (p->value, p->value_len, &len2); ++ fprintf (out, " value:"); ++ if (len > 0) ++ for (k = 0; k < len; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); ++ } ++ break; ++ case ASN1_ETYPE_OBJECT_ID: ++ if (p->value) ++ fprintf (out, " value:%s", p->value); ++ break; ++ case ASN1_ETYPE_ANY: ++ if (p->value) ++ { ++ len3 = -1; ++ len2 = asn1_get_length_der (p->value, p->value_len, &len3); ++ fprintf (out, " value:"); ++ if (len2 > 0) ++ for (k = 0; k < len2; k++) ++ fprintf (out, "%02x", (unsigned) (p->value)[k + len3]); ++ } ++ break; ++ case ASN1_ETYPE_SET: ++ case ASN1_ETYPE_SET_OF: ++ case ASN1_ETYPE_CHOICE: ++ case ASN1_ETYPE_DEFINITIONS: ++ case ASN1_ETYPE_SEQUENCE_OF: ++ case ASN1_ETYPE_SEQUENCE: ++ case ASN1_ETYPE_NULL: ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (mode == ASN1_PRINT_ALL) ++ { ++ if (p->type & 0x1FFFFF00) ++ { ++ fprintf (out, " attr:"); ++ if (p->type & CONST_UNIVERSAL) ++ fprintf (out, "UNIVERSAL,"); ++ if (p->type & CONST_PRIVATE) ++ fprintf (out, "PRIVATE,"); ++ if (p->type & CONST_APPLICATION) ++ fprintf (out, "APPLICATION,"); ++ if (p->type & CONST_EXPLICIT) ++ fprintf (out, "EXPLICIT,"); ++ if (p->type & CONST_IMPLICIT) ++ fprintf (out, "IMPLICIT,"); ++ if (p->type & CONST_TAG) ++ fprintf (out, "TAG,"); ++ if (p->type & CONST_DEFAULT) ++ fprintf (out, "DEFAULT,"); ++ if (p->type & CONST_TRUE) ++ fprintf (out, "TRUE,"); ++ if (p->type & CONST_FALSE) ++ fprintf (out, "FALSE,"); ++ if (p->type & CONST_LIST) ++ fprintf (out, "LIST,"); ++ if (p->type & CONST_MIN_MAX) ++ fprintf (out, "MIN_MAX,"); ++ if (p->type & CONST_OPTION) ++ fprintf (out, "OPTION,"); ++ if (p->type & CONST_1_PARAM) ++ fprintf (out, "1_PARAM,"); ++ if (p->type & CONST_SIZE) ++ fprintf (out, "SIZE,"); ++ if (p->type & CONST_DEFINED_BY) ++ fprintf (out, "DEF_BY,"); ++ if (p->type & CONST_GENERALIZED) ++ fprintf (out, "GENERALIZED,"); ++ if (p->type & CONST_UTC) ++ fprintf (out, "UTC,"); ++ if (p->type & CONST_SET) ++ fprintf (out, "SET,"); ++ if (p->type & CONST_NOT_USED) ++ fprintf (out, "NOT_USED,"); ++ if (p->type & CONST_ASSIGN) ++ fprintf (out, "ASSIGNMENT,"); ++ } ++ } ++ ++ if (mode == ASN1_PRINT_ALL) ++ { ++ fprintf (out, "\n"); ++ } ++ else ++ { ++ switch (type_field (p->type)) ++ { ++ case ASN1_ETYPE_CONSTANT: ++ case ASN1_ETYPE_TAG: ++ case ASN1_ETYPE_SIZE: ++ break; ++ default: ++ fprintf (out, "\n"); ++ } ++ } ++ ++ if (p->down) ++ { ++ p = p->down; ++ indent += 2; ++ } ++ else if (p == root) ++ { ++ p = NULL; ++ break; ++ } ++ else if (p->right) ++ p = p->right; ++ else ++ { ++ while (1) ++ { ++ p = _asn1_find_up (p); ++ if (p == root) ++ { ++ p = NULL; ++ break; ++ } ++ indent -= 2; ++ if (p->right) ++ { ++ p = p->right; ++ break; ++ } ++ } ++ } ++ } ++} ++ ++ ++ ++/** ++ * asn1_number_of_elements: ++ * @element: pointer to the root of an ASN1 structure. ++ * @name: the name of a sub-structure of ROOT. ++ * @num: pointer to an integer where the result will be stored ++ * ++ * Counts the number of elements of a sub-structure called NAME with ++ * names equal to "?1","?2", ... ++ * ++ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if ++ * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL. ++ **/ ++int ++asn1_number_of_elements (asn1_node_const element, const char *name, int *num) ++{ ++ asn1_node_const node, p; ++ ++ if (num == NULL) ++ return ASN1_GENERIC_ERROR; ++ ++ *num = 0; ++ ++ node = asn1_find_node (element, name); ++ if (node == NULL) ++ return ASN1_ELEMENT_NOT_FOUND; ++ ++ p = node->down; ++ ++ while (p) ++ { ++ if (p->name[0] == '?') ++ (*num)++; ++ p = p->right; ++ } ++ ++ return ASN1_SUCCESS; ++} ++ ++ ++/** ++ * asn1_find_structure_from_oid: ++ * @definitions: ASN1 definitions ++ * @oidValue: value of the OID to search (e.g. "1.2.3.4"). ++ * ++ * Search the structure that is defined just after an OID definition. ++ * ++ * Returns: %NULL when @oidValue not found, otherwise the pointer to a ++ * constant string that contains the element name defined just after ++ * the OID. ++ **/ ++const char * ++asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue) ++{ ++ char name[2 * ASN1_MAX_NAME_SIZE + 2]; ++ char value[ASN1_MAX_NAME_SIZE]; ++ asn1_node p; ++ int len; ++ int result; ++ const char *definitionsName; ++ ++ if ((definitions == NULL) || (oidValue == NULL)) ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++ ++ definitionsName = definitions->name; ++ ++ /* search the OBJECT_ID into definitions */ ++ p = definitions->down; ++ while (p) ++ { ++ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && ++ (p->type & CONST_ASSIGN)) ++ { ++ snprintf(name, sizeof(name), "%s.%s", definitionsName, p->name); ++ ++ len = ASN1_MAX_NAME_SIZE; ++ result = asn1_read_value (definitions, name, value, &len); ++ ++ if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value))) ++ { ++ p = p->right; ++ if (p == NULL) /* reach the end of ASN1 definitions */ ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++ ++ return p->name; ++ } ++ } ++ p = p->right; ++ } ++ ++ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ ++} ++ ++/** ++ * asn1_copy_node: ++ * @dst: Destination asn1 node. ++ * @dst_name: Field name in destination node. ++ * @src: Source asn1 node. ++ * @src_name: Field name in source node. ++ * ++ * Create a deep copy of a asn1_node variable. That ++ * function requires @dst to be expanded using asn1_create_element(). ++ * ++ * Returns: Return %ASN1_SUCCESS on success. ++ **/ ++int ++asn1_copy_node (asn1_node dst, const char *dst_name, ++ asn1_node_const src, const char *src_name) ++{ ++ int result; ++ asn1_node dst_node; ++ void *data = NULL; ++ int size = 0; ++ ++ result = asn1_der_coding (src, src_name, NULL, &size, NULL); ++ if (result != ASN1_MEM_ERROR) ++ return result; ++ ++ data = malloc (size); ++ if (data == NULL) ++ return ASN1_MEM_ERROR; ++ ++ result = asn1_der_coding (src, src_name, data, &size, NULL); ++ if (result != ASN1_SUCCESS) ++ { ++ free (data); ++ return result; ++ } ++ ++ dst_node = asn1_find_node (dst, dst_name); ++ if (dst_node == NULL) ++ { ++ free (data); ++ return ASN1_ELEMENT_NOT_FOUND; ++ } ++ ++ result = asn1_der_decoding (&dst_node, data, size, NULL); ++ ++ free (data); ++ ++ return result; ++} ++ ++/** ++ * asn1_dup_node: ++ * @src: Source asn1 node. ++ * @src_name: Field name in source node. ++ * ++ * Create a deep copy of a asn1_node variable. This function ++ * will return an exact copy of the provided structure. ++ * ++ * Returns: Return %NULL on failure. ++ **/ ++asn1_node ++asn1_dup_node (asn1_node_const src, const char *src_name) ++{ ++ return _asn1_copy_structure2(src, src_name); ++} +diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h +new file mode 100644 +index 0000000000..440a33f4bb +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/element.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2000-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef _ELEMENT_H ++#define _ELEMENT_H ++ ++ ++struct node_tail_cache_st ++{ ++ asn1_node head; /* the first element of the sequence */ ++ asn1_node tail; ++}; ++ ++int _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcached); ++ ++int _asn1_convert_integer (const unsigned char *value, ++ unsigned char *value_out, ++ int value_out_size, int *len); ++ ++void _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size); ++ ++#endif +diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h +new file mode 100644 +index 0000000000..48229844ff +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/gstr.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef GSTR_H ++# define GSTR_H ++ ++unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size, ++ const char *src); ++void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src); ++ ++#define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) ++#define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y) ++ ++inline static ++void safe_memset(void *data, int c, size_t size) ++{ ++ volatile unsigned volatile_zero = 0; ++ volatile char *vdata = (volatile char*)data; ++ ++ /* This is based on a nice trick for safe memset, ++ * sent by David Jacobson in the openssl-dev mailing list. ++ */ ++ ++ if (size > 0) do { ++ memset(data, c, size); ++ } while(vdata[volatile_zero] != c); ++} ++ ++#endif /* GSTR_H */ +diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h +new file mode 100644 +index 0000000000..ea1625786c +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/int.h +@@ -0,0 +1,221 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef INT_H ++#define INT_H ++ ++#ifdef HAVE_CONFIG_H ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_SYS_TYPES_H ++#include ++#endif ++ ++#include ++ ++#define ASN1_SMALL_VALUE_SIZE 16 ++ ++/* This structure is also in libtasn1.h, but then contains less ++ fields. You cannot make any modifications to these first fields ++ without breaking ABI. */ ++struct asn1_node_st ++{ ++ /* public fields: */ ++ char name[ASN1_MAX_NAME_SIZE + 1]; /* Node name */ ++ unsigned int name_hash; ++ unsigned int type; /* Node type */ ++ unsigned char *value; /* Node value */ ++ int value_len; ++ asn1_node down; /* Pointer to the son node */ ++ asn1_node right; /* Pointer to the brother node */ ++ asn1_node left; /* Pointer to the next list element */ ++ /* private fields: */ ++ unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */ ++ ++ /* values used during decoding/coding */ ++ int tmp_ival; ++ unsigned start; /* the start of the DER sequence - if decoded */ ++ unsigned end; /* the end of the DER sequence - if decoded */ ++}; ++ ++typedef struct tag_and_class_st ++{ ++ unsigned tag; ++ unsigned class; ++ const char *desc; ++} tag_and_class_st; ++ ++/* the types that are handled in _asn1_tags */ ++#define CASE_HANDLED_ETYPES \ ++ case ASN1_ETYPE_NULL: \ ++ case ASN1_ETYPE_BOOLEAN: \ ++ case ASN1_ETYPE_INTEGER: \ ++ case ASN1_ETYPE_ENUMERATED: \ ++ case ASN1_ETYPE_OBJECT_ID: \ ++ case ASN1_ETYPE_OCTET_STRING: \ ++ case ASN1_ETYPE_GENERALSTRING: \ ++ case ASN1_ETYPE_NUMERIC_STRING: \ ++ case ASN1_ETYPE_IA5_STRING: \ ++ case ASN1_ETYPE_TELETEX_STRING: \ ++ case ASN1_ETYPE_PRINTABLE_STRING: \ ++ case ASN1_ETYPE_UNIVERSAL_STRING: \ ++ case ASN1_ETYPE_BMP_STRING: \ ++ case ASN1_ETYPE_UTF8_STRING: \ ++ case ASN1_ETYPE_VISIBLE_STRING: \ ++ case ASN1_ETYPE_BIT_STRING: \ ++ case ASN1_ETYPE_SEQUENCE: \ ++ case ASN1_ETYPE_SEQUENCE_OF: \ ++ case ASN1_ETYPE_SET: \ ++ case ASN1_ETYPE_UTC_TIME: \ ++ case ASN1_ETYPE_GENERALIZED_TIME: \ ++ case ASN1_ETYPE_SET_OF ++ ++#define ETYPE_TAG(etype) (_asn1_tags[etype].tag) ++#define ETYPE_CLASS(etype) (_asn1_tags[etype].class) ++#define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \ ++ (etype) <= _asn1_tags_size && \ ++ _asn1_tags[(etype)].desc != NULL)?1:0) ++ ++#define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \ ++ etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \ ++ etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \ ++ etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \ ++ etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \ ++ etype == ASN1_ETYPE_OCTET_STRING)?1:0) ++ ++extern unsigned int _asn1_tags_size; ++extern const tag_and_class_st _asn1_tags[]; ++ ++#define _asn1_strlen(s) strlen((const char *) s) ++#define _asn1_strtol(n,e,b) strtol((const char *) n, e, b) ++#define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) ++#define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) ++#define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) ++#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b) ++ ++#if SIZEOF_UNSIGNED_LONG_INT == 8 ++# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) ++#else ++# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b) ++#endif ++ ++#define MAX_LOG_SIZE 1024 /* maximum number of characters of a log message */ ++ ++/* Define used for visiting trees. */ ++#define UP 1 ++#define RIGHT 2 ++#define DOWN 3 ++ ++/***********************************************************************/ ++/* List of constants to better specify the type of typedef asn1_node_st. */ ++/***********************************************************************/ ++/* Used with TYPE_TAG */ ++#define CONST_UNIVERSAL (1U<<8) ++#define CONST_PRIVATE (1U<<9) ++#define CONST_APPLICATION (1U<<10) ++#define CONST_EXPLICIT (1U<<11) ++#define CONST_IMPLICIT (1U<<12) ++ ++#define CONST_TAG (1U<<13) /* Used in ASN.1 assignement */ ++#define CONST_OPTION (1U<<14) ++#define CONST_DEFAULT (1U<<15) ++#define CONST_TRUE (1U<<16) ++#define CONST_FALSE (1U<<17) ++ ++#define CONST_LIST (1U<<18) /* Used with TYPE_INTEGER and TYPE_BIT_STRING */ ++#define CONST_MIN_MAX (1U<<19) ++ ++#define CONST_1_PARAM (1U<<20) ++ ++#define CONST_SIZE (1U<<21) ++ ++#define CONST_DEFINED_BY (1U<<22) ++ ++/* Those two are deprecated and used for backwards compatibility */ ++#define CONST_GENERALIZED (1U<<23) ++#define CONST_UTC (1U<<24) ++ ++/* #define CONST_IMPORTS (1U<<25) */ ++ ++#define CONST_NOT_USED (1U<<26) ++#define CONST_SET (1U<<27) ++#define CONST_ASSIGN (1U<<28) ++ ++#define CONST_DOWN (1U<<29) ++#define CONST_RIGHT (1U<<30) ++ ++ ++#define ASN1_ETYPE_TIME 17 ++/****************************************/ ++/* Returns the first 8 bits. */ ++/* Used with the field type of asn1_node_st */ ++/****************************************/ ++inline static unsigned int ++type_field (unsigned int ntype) ++{ ++ return (ntype & 0xff); ++} ++ ++/* To convert old types from a static structure */ ++inline static unsigned int ++convert_old_type (unsigned int ntype) ++{ ++ unsigned int type = ntype & 0xff; ++ if (type == ASN1_ETYPE_TIME) ++ { ++ if (ntype & CONST_UTC) ++ type = ASN1_ETYPE_UTC_TIME; ++ else ++ type = ASN1_ETYPE_GENERALIZED_TIME; ++ ++ ntype &= ~(CONST_UTC | CONST_GENERALIZED); ++ ntype &= 0xffffff00; ++ ntype |= type; ++ ++ return ntype; ++ } ++ else ++ return ntype; ++} ++ ++static inline ++void *_asn1_realloc(void *ptr, size_t size) ++{ ++ void *ret; ++ ++ if (size == 0) ++ return ptr; ++ ++ ret = realloc(ptr, size); ++ if (ret == NULL) ++ { ++ free(ptr); ++ } ++ return ret; ++} ++ ++#endif /* INT_H */ +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h +new file mode 100644 +index 0000000000..598e684b35 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/parser_aux.h +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2000-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++#ifndef _PARSER_AUX_H ++#define _PARSER_AUX_H ++ ++/***********************************************/ ++/* Type: list_type */ ++/* Description: type used in the list during */ ++/* the structure creation. */ ++/***********************************************/ ++typedef struct list_struct ++{ ++ asn1_node node; ++ struct list_struct *next; ++} list_type; ++ ++/***************************************/ ++/* Functions used by ASN.1 parser */ ++/***************************************/ ++asn1_node _asn1_add_static_node (list_type **e_list, unsigned int type); ++ ++void _asn1_delete_list (list_type *e_list); ++ ++void _asn1_delete_list_and_nodes (list_type *e_list); ++ ++void _asn1_delete_node_from_list (list_type *list, asn1_node node); ++ ++asn1_node ++_asn1_set_value (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len); ++ ++asn1_node ++_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node ++_asn1_append_value (asn1_node node, const void *value, unsigned int len); ++ ++asn1_node _asn1_set_name (asn1_node node, const char *name); ++ ++asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src); ++ ++asn1_node _asn1_set_right (asn1_node node, asn1_node right); ++ ++asn1_node _asn1_get_last_right (asn1_node_const node); ++ ++void _asn1_remove_node (asn1_node node, unsigned int flags); ++ ++/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */ ++#define LTOSTR_MAX_SIZE 22 ++char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]); ++ ++asn1_node _asn1_find_up (asn1_node_const node); ++ ++int _asn1_change_integer_value (asn1_node node); ++ ++#define EXPAND_OBJECT_ID_MAX_RECURSION 16 ++int _asn1_expand_object_id (list_type **list, asn1_node node); ++ ++int _asn1_type_set_config (asn1_node node); ++ ++int _asn1_check_identifier (asn1_node_const node); ++ ++int _asn1_set_default_tag (asn1_node node); ++ ++/******************************************************************/ ++/* Function : _asn1_get_right */ ++/* Description: returns the element pointed by the RIGHT field of */ ++/* a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: field RIGHT of NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_get_right (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return node->right; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_set_down */ ++/* Description: sets the field DOWN in a NODE_ASN element. */ ++/* Parameters: */ ++/* node: element pointer. */ ++/* down: pointer to a NODE_ASN element that you want be pointed */ ++/* by NODE. */ ++/* Return: pointer to *NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_set_down (asn1_node node, asn1_node down) ++{ ++ if (node == NULL) ++ return node; ++ node->down = down; ++ if (down) ++ down->left = node; ++ return node; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_get_down */ ++/* Description: returns the element pointed by the DOWN field of */ ++/* a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: field DOWN of NODE. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_get_down (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return node->down; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_get_name */ ++/* Description: returns the name of a NODE_ASN element. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* Return: a null terminated string. */ ++/******************************************************************/ ++inline static char * ++_asn1_get_name (asn1_node_const node) ++{ ++ if (node == NULL) ++ return NULL; ++ return (char *) node->name; ++} ++ ++/******************************************************************/ ++/* Function : _asn1_mod_type */ ++/* Description: change the field TYPE of an NODE_ASN element. */ ++/* The new value is the old one | (bitwise or) the */ ++/* paramener VALUE. */ ++/* Parameters: */ ++/* node: NODE_ASN element pointer. */ ++/* value: the integer value that must be or-ed with the current */ ++/* value of field TYPE. */ ++/* Return: NODE pointer. */ ++/******************************************************************/ ++inline static asn1_node ++_asn1_mod_type (asn1_node node, unsigned int value) ++{ ++ if (node == NULL) ++ return node; ++ node->type |= value; ++ return node; ++} ++ ++#endif +diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h +new file mode 100644 +index 0000000000..99e685da07 +--- /dev/null ++++ b/grub-core/lib/libtasn1/lib/structure.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * The LIBTASN1 library is free software; you can redistribute it ++ * and/or modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ */ ++ ++/*************************************************/ ++/* File: structure.h */ ++/* Description: list of exported object by */ ++/* "structure.c" */ ++/*************************************************/ ++ ++#ifndef _STRUCTURE_H ++#define _STRUCTURE_H ++ ++#include "parser_aux.h" // list_type ++ ++int _asn1_create_static_structure (asn1_node_const pointer, ++ char *output_file_name, char *vector_name); ++ ++asn1_node _asn1_copy_structure3 (asn1_node_const source_node); ++ ++asn1_node _asn1_add_single_node (unsigned int type); ++ ++asn1_node _asn1_find_left (asn1_node_const node); ++ ++int ++_asn1_delete_structure (list_type *e_list, asn1_node *structure, unsigned int flags); ++ ++#endif +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +new file mode 100644 +index 0000000000..6fd7a30dc3 +--- /dev/null ++++ b/include/grub/libtasn1.h +@@ -0,0 +1,588 @@ ++/* ++ * Copyright (C) 2002-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * LIBTASN1 is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU Lesser General Public License as ++ * published by the Free Software Foundation; either version 2.1 of ++ * the License, or (at your option) any later version. ++ * ++ * LIBTASN1 is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with LIBTASN1; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA ++ * ++ */ ++ ++/** ++ * libtasn1:Short_Description: ++ * ++ * GNU ASN.1 library ++ */ ++/** ++ * libtasn1:Long_Description: ++ * ++ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as ++ * specified by the X.680 ITU-T recommendation) parsing and structures ++ * management, and Distinguished Encoding Rules (DER, as per X.690) ++ * encoding and decoding functions. ++ */ ++ ++ ++#ifndef LIBTASN1_H ++#define LIBTASN1_H ++ ++#ifndef ASN1_API ++#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY ++#define ASN1_API __attribute__((__visibility__("default"))) ++#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC ++#define ASN1_API __declspec(dllexport) ++#elif defined _MSC_VER && ! defined ASN1_STATIC ++#define ASN1_API __declspec(dllimport) ++#else ++#define ASN1_API ++#endif ++#endif ++ ++#ifdef __GNUC__ ++# define __LIBTASN1_CONST__ __attribute__((const)) ++# define __LIBTASN1_PURE__ __attribute__((pure)) ++#else ++# define __LIBTASN1_CONST__ ++# define __LIBTASN1_PURE__ ++#endif ++ ++#include ++#include ++#include /* for FILE* */ ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++/** ++ * ASN1_VERSION: ++ * ++ * Version of the library as a string. ++ */ ++#define ASN1_VERSION "4.16.0" ++ ++/** ++ * ASN1_VERSION_MAJOR: ++ * ++ * Major version number of the library. ++ */ ++#define ASN1_VERSION_MAJOR 4 ++ ++/** ++ * ASN1_VERSION_MINOR: ++ * ++ * Minor version number of the library. ++ */ ++#define ASN1_VERSION_MINOR 16 ++ ++/** ++ * ASN1_VERSION_PATCH: ++ * ++ * Patch version number of the library. ++ */ ++#define ASN1_VERSION_PATCH 0 ++ ++/** ++ * ASN1_VERSION_NUMBER: ++ * ++ * Version number of the library as a number. ++ */ ++#define ASN1_VERSION_NUMBER 0x041000 ++ ++ ++#if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD ++# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) ++# if _ASN1_GCC_VERSION >= 30100 ++# define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__)) ++# endif ++#endif ++ ++#ifndef _ASN1_GCC_ATTR_DEPRECATED ++#define _ASN1_GCC_ATTR_DEPRECATED ++#endif ++ ++/*****************************************/ ++/* Errors returned by libtasn1 functions */ ++/*****************************************/ ++#define ASN1_SUCCESS 0 ++#define ASN1_FILE_NOT_FOUND 1 ++#define ASN1_ELEMENT_NOT_FOUND 2 ++#define ASN1_IDENTIFIER_NOT_FOUND 3 ++#define ASN1_DER_ERROR 4 ++#define ASN1_VALUE_NOT_FOUND 5 ++#define ASN1_GENERIC_ERROR 6 ++#define ASN1_VALUE_NOT_VALID 7 ++#define ASN1_TAG_ERROR 8 ++#define ASN1_TAG_IMPLICIT 9 ++#define ASN1_ERROR_TYPE_ANY 10 ++#define ASN1_SYNTAX_ERROR 11 ++#define ASN1_MEM_ERROR 12 ++#define ASN1_MEM_ALLOC_ERROR 13 ++#define ASN1_DER_OVERFLOW 14 ++#define ASN1_NAME_TOO_LONG 15 ++#define ASN1_ARRAY_ERROR 16 ++#define ASN1_ELEMENT_NOT_EMPTY 17 ++#define ASN1_TIME_ENCODING_ERROR 18 ++#define ASN1_RECURSION 19 ++ ++/*************************************/ ++/* Constants used in asn1_visit_tree */ ++/*************************************/ ++#define ASN1_PRINT_NAME 1 ++#define ASN1_PRINT_NAME_TYPE 2 ++#define ASN1_PRINT_NAME_TYPE_VALUE 3 ++#define ASN1_PRINT_ALL 4 ++ ++/*****************************************/ ++/* Constants returned by asn1_read_tag */ ++/*****************************************/ ++#define ASN1_CLASS_UNIVERSAL 0x00 /* old: 1 */ ++#define ASN1_CLASS_APPLICATION 0x40 /* old: 2 */ ++#define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /* old: 3 */ ++#define ASN1_CLASS_PRIVATE 0xC0 /* old: 4 */ ++#define ASN1_CLASS_STRUCTURED 0x20 ++ ++/*****************************************/ ++/* Constants returned by asn1_read_tag */ ++/*****************************************/ ++#define ASN1_TAG_BOOLEAN 0x01 ++#define ASN1_TAG_INTEGER 0x02 ++#define ASN1_TAG_SEQUENCE 0x10 ++#define ASN1_TAG_SET 0x11 ++#define ASN1_TAG_OCTET_STRING 0x04 ++#define ASN1_TAG_BIT_STRING 0x03 ++#define ASN1_TAG_UTCTime 0x17 ++#define ASN1_TAG_GENERALIZEDTime 0x18 ++#define ASN1_TAG_OBJECT_ID 0x06 ++#define ASN1_TAG_ENUMERATED 0x0A ++#define ASN1_TAG_NULL 0x05 ++#define ASN1_TAG_GENERALSTRING 0x1B ++#define ASN1_TAG_NUMERIC_STRING 0x12 ++#define ASN1_TAG_IA5_STRING 0x16 ++#define ASN1_TAG_TELETEX_STRING 0x14 ++#define ASN1_TAG_PRINTABLE_STRING 0x13 ++#define ASN1_TAG_UNIVERSAL_STRING 0x1C ++#define ASN1_TAG_BMP_STRING 0x1E ++#define ASN1_TAG_UTF8_STRING 0x0C ++#define ASN1_TAG_VISIBLE_STRING 0x1A ++ ++/** ++ * asn1_node: ++ * ++ * Structure definition used for the node of the tree ++ * that represents an ASN.1 DEFINITION. ++ */ ++typedef struct asn1_node_st asn1_node_st; ++ ++typedef asn1_node_st *asn1_node; ++typedef const asn1_node_st *asn1_node_const; ++ ++/** ++ * ASN1_MAX_NAME_SIZE: ++ * ++ * Maximum number of characters of a name ++ * inside a file with ASN1 definitions. ++ */ ++#define ASN1_MAX_NAME_SIZE 64 ++ ++ ++/** ++ * asn1_static_node: ++ * @name: Node name ++ * @type: Node typ ++ * @value: Node value ++ * ++ * For the on-disk format of ASN.1 trees, created by asn1_parser2array(). ++ */ ++struct asn1_static_node_st ++{ ++ const char *name; /* Node name */ ++ unsigned int type; /* Node type */ ++ const void *value; /* Node value */ ++}; ++typedef struct asn1_static_node_st asn1_static_node; ++ ++/* List of constants for field type of node_asn */ ++#define ASN1_ETYPE_INVALID 0 ++#define ASN1_ETYPE_CONSTANT 1 ++#define ASN1_ETYPE_IDENTIFIER 2 ++#define ASN1_ETYPE_INTEGER 3 ++#define ASN1_ETYPE_BOOLEAN 4 ++#define ASN1_ETYPE_SEQUENCE 5 ++#define ASN1_ETYPE_BIT_STRING 6 ++#define ASN1_ETYPE_OCTET_STRING 7 ++#define ASN1_ETYPE_TAG 8 ++#define ASN1_ETYPE_DEFAULT 9 ++#define ASN1_ETYPE_SIZE 10 ++#define ASN1_ETYPE_SEQUENCE_OF 11 ++#define ASN1_ETYPE_OBJECT_ID 12 ++#define ASN1_ETYPE_ANY 13 ++#define ASN1_ETYPE_SET 14 ++#define ASN1_ETYPE_SET_OF 15 ++#define ASN1_ETYPE_DEFINITIONS 16 ++#define ASN1_ETYPE_CHOICE 18 ++#define ASN1_ETYPE_IMPORTS 19 ++#define ASN1_ETYPE_NULL 20 ++#define ASN1_ETYPE_ENUMERATED 21 ++#define ASN1_ETYPE_GENERALSTRING 27 ++#define ASN1_ETYPE_NUMERIC_STRING 28 ++#define ASN1_ETYPE_IA5_STRING 29 ++#define ASN1_ETYPE_TELETEX_STRING 30 ++#define ASN1_ETYPE_PRINTABLE_STRING 31 ++#define ASN1_ETYPE_UNIVERSAL_STRING 32 ++#define ASN1_ETYPE_BMP_STRING 33 ++#define ASN1_ETYPE_UTF8_STRING 34 ++#define ASN1_ETYPE_VISIBLE_STRING 35 ++#define ASN1_ETYPE_UTC_TIME 36 ++#define ASN1_ETYPE_GENERALIZED_TIME 37 ++ ++/** ++ * ASN1_DELETE_FLAG_ZEROIZE: ++ * ++ * Used by: asn1_delete_structure2() ++ * ++ * Zeroize values prior to deinitialization. ++ */ ++#define ASN1_DELETE_FLAG_ZEROIZE 1 ++ ++/** ++ * ASN1_DECODE_FLAG_ALLOW_PADDING: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag would allow arbitrary data past the DER data. ++ */ ++#define ASN1_DECODE_FLAG_ALLOW_PADDING 1 ++/** ++ * ASN1_DECODE_FLAG_STRICT_DER: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag would ensure that no BER decoding takes place. ++ */ ++#define ASN1_DECODE_FLAG_STRICT_DER (1<<1) ++/** ++ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME: ++ * ++ * Used by: asn1_der_decoding2() ++ * ++ * This flag will tolerate Time encoding errors when in strict DER. ++ */ ++#define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2) ++ ++ ++/** ++ * asn1_data_node_st: ++ * @name: Node name ++ * @value: Node value ++ * @value_len: Node value size ++ * @type: Node value type (ASN1_ETYPE_*) ++ * ++ * Data node inside a #asn1_node structure. ++ */ ++struct asn1_data_node_st ++{ ++ const char *name; /* Node name */ ++ const void *value; /* Node value */ ++ unsigned int value_len; /* Node value size */ ++ unsigned int type; /* Node value type (ASN1_ETYPE_*) */ ++}; ++typedef struct asn1_data_node_st asn1_data_node_st; ++ ++/***********************************/ ++/* Fixed constants */ ++/***********************************/ ++ ++/** ++ * ASN1_MAX_ERROR_DESCRIPTION_SIZE: ++ * ++ * Maximum number of characters ++ * of a description message ++ * (null character included). ++ */ ++#define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128 ++ ++/***********************************/ ++/* Functions definitions */ ++/***********************************/ ++ ++extern ASN1_API int ++ asn1_parser2tree (const char *file, ++ asn1_node * definitions, char *error_desc); ++ ++extern ASN1_API int ++ asn1_parser2array (const char *inputFileName, ++ const char *outputFileName, ++ const char *vectorName, char *error_desc); ++ ++extern ASN1_API int ++ asn1_array2tree (const asn1_static_node * array, ++ asn1_node * definitions, char *errorDescription); ++ ++extern ASN1_API void ++ asn1_print_structure (FILE * out, asn1_node_const structure, ++ const char *name, int mode); ++ ++extern ASN1_API int ++ asn1_create_element (asn1_node_const definitions, ++ const char *source_name, asn1_node * element); ++ ++extern ASN1_API int asn1_delete_structure (asn1_node * structure); ++ ++extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int flags); ++ ++extern ASN1_API int ++ asn1_delete_element (asn1_node structure, const char *element_name); ++ ++extern ASN1_API int ++ asn1_write_value (asn1_node node_root, const char *name, ++ const void *ivalue, int len); ++ ++extern ASN1_API int ++ asn1_read_value (asn1_node_const root, const char *name, ++ void *ivalue, int *len); ++ ++extern ASN1_API int ++ asn1_read_value_type (asn1_node_const root, const char *name, ++ void *ivalue, int *len, unsigned int *etype); ++ ++extern ASN1_API int ++ asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data); ++ ++extern ASN1_API int ++ asn1_number_of_elements (asn1_node_const element, const char *name, int *num); ++ ++extern ASN1_API int ++ asn1_der_coding (asn1_node_const element, const char *name, ++ void *ider, int *len, char *ErrorDescription); ++ ++extern ASN1_API int ++ asn1_der_decoding2 (asn1_node *element, const void *ider, ++ int *max_ider_len, unsigned int flags, ++ char *errorDescription); ++ ++extern ASN1_API int ++ asn1_der_decoding (asn1_node * element, const void *ider, ++ int ider_len, char *errorDescription); ++ ++/* Do not use. Use asn1_der_decoding() instead. */ ++extern ASN1_API int ++ asn1_der_decoding_element (asn1_node * structure, ++ const char *elementName, ++ const void *ider, int len, ++ char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED; ++ ++extern ASN1_API int ++ asn1_der_decoding_startEnd (asn1_node element, ++ const void *ider, int ider_len, ++ const char *name_element, ++ int *start, int *end); ++ ++extern ASN1_API int ++ asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element); ++ ++extern ASN1_API int ++ asn1_expand_octet_string (asn1_node_const definitions, ++ asn1_node * element, ++ const char *octetName, const char *objectName); ++ ++extern ASN1_API int ++ asn1_read_tag (asn1_node_const root, const char *name, ++ int *tagValue, int *classValue); ++ ++extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const ++ definitions, ++ const char ++ *oidValue); ++ ++__LIBTASN1_PURE__ ++extern ASN1_API const char *asn1_check_version (const char *req_version); ++ ++__LIBTASN1_PURE__ ++extern ASN1_API const char *asn1_strerror (int error); ++ ++extern ASN1_API void asn1_perror (int error); ++ ++#define ASN1_MAX_TAG_SIZE 4 ++#define ASN1_MAX_LENGTH_SIZE 9 ++#define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE) ++extern ASN1_API long ++ asn1_get_length_der (const unsigned char *der, int der_len, int *len); ++ ++extern ASN1_API long ++ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len); ++ ++extern ASN1_API void ++ asn1_length_der (unsigned long int len, unsigned char *der, int *der_len); ++ ++/* Other utility functions. */ ++ ++extern ASN1_API ++ int asn1_decode_simple_der (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, ++ const unsigned char **str, ++ unsigned int *str_len); ++ ++extern ASN1_API ++ int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der, ++ unsigned int _der_len, ++ unsigned char **str, ++ unsigned int *str_len, ++ unsigned int *ber_len); ++ ++extern ASN1_API int ++ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, ++ unsigned int str_len, unsigned char *tl, ++ unsigned int *tl_len); ++ ++extern ASN1_API asn1_node ++ asn1_find_node (asn1_node_const pointer, const char *name); ++ ++extern ASN1_API int ++ asn1_copy_node (asn1_node dst, const char *dst_name, ++ asn1_node_const src, const char *src_name); ++extern ASN1_API asn1_node ++ asn1_dup_node (asn1_node_const src, const char *src_name); ++ ++/* Internal and low-level DER utility functions. */ ++ ++extern ASN1_API int ++ asn1_get_tag_der (const unsigned char *der, int der_len, ++ unsigned char *cls, int *len, unsigned long *tag); ++ ++extern ASN1_API void ++ asn1_octet_der (const unsigned char *str, int str_len, ++ unsigned char *der, int *der_len); ++ ++extern ASN1_API int ++ asn1_get_octet_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, ++ int str_size, int *str_len); ++ ++extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len, ++ unsigned char *der, int *der_len); ++ ++extern ASN1_API int ++ asn1_get_bit_der (const unsigned char *der, int der_len, ++ int *ret_len, unsigned char *str, ++ int str_size, int *bit_len); ++ ++extern ASN1_API int ++ asn1_get_object_id_der (const unsigned char *der, ++ int der_len, int *ret_len, ++ char *str, int str_size); ++ ++extern ASN1_API int ++ asn1_object_id_der (const char *str, unsigned char *der, int *der_len, ++ unsigned flags); ++ ++/* Compatibility types */ ++ ++/** ++ * asn1_retCode: ++ * ++ * Type formerly returned by libtasn1 functions. ++ * ++ * Deprecated: 3.0: Use int instead. ++ */ ++typedef int asn1_retCode; ++ ++/** ++ * node_asn_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define node_asn_struct asn1_node_st ++ ++/** ++ * node_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define node_asn asn1_node_st ++ ++/** ++ * ASN1_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_node instead. ++ */ ++#define ASN1_TYPE asn1_node ++ ++/** ++ * ASN1_TYPE_EMPTY: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use NULL instead. ++ */ ++#define ASN1_TYPE_EMPTY NULL ++ ++/** ++ * static_struct_asn: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define static_struct_asn asn1_static_node_st ++ ++/** ++ * ASN1_ARRAY_TYPE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define ASN1_ARRAY_TYPE asn1_static_node ++ ++/** ++ * asn1_static_node_t: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_static_node instead. ++ */ ++#define asn1_static_node_t asn1_static_node ++ ++/** ++ * node_data_struct: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++#define node_data_struct asn1_data_node_st ++ ++/** ++ * ASN1_DATA_NODE: ++ * ++ * Compat #define. ++ * ++ * Deprecated: 3.0: Use #asn1_data_node_st instead. ++ */ ++#define ASN1_DATA_NODE asn1_data_node_st ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* LIBTASN1_H */ +diff --git a/grub-core/lib/libtasn1/LICENSE b/grub-core/lib/libtasn1/LICENSE +new file mode 100644 +index 0000000000..e8b3628db9 +--- /dev/null ++++ b/grub-core/lib/libtasn1/LICENSE +@@ -0,0 +1,16 @@ ++LICENSING ++========= ++ ++The libtasn1 library is released under the GNU Lesser General Public ++License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER) ++for the license terms. ++ ++The GNU LGPL applies to the main libtasn1 library, while the ++included applications library are under the GNU GPL version 3. ++The libtasn1 library is located in the lib directory, while the applications ++in src/. ++ ++The documentation in doc/ is under the GNU FDL license 1.3. ++ ++For any copyright year range specified as YYYY-ZZZZ in this package ++note that the range specifies every single year in that closed interval. +diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md +new file mode 100644 +index 0000000000..50a8642296 +--- /dev/null ++++ b/grub-core/lib/libtasn1/README.md +@@ -0,0 +1,91 @@ ++|Branch|CI system|Status| ++|:----:|:-------:|-----:| ++|Master|Gitlab|[![build status](https://gitlab.com/gnutls/libtasn1/badges/master/pipeline.svg)](https://gitlab.com/gnutls/libtasn1/commits/master)[![coverage report](https://gitlab.com/gnutls/libtasn1/badges/master/coverage.svg)](https://gnutls.gitlab.io/libtasn1/coverage)| ++ ++# libtasn1 ++ ++This is GNU Libtasn1, a small ASN.1 library. ++ ++The C library (libtasn1.*) is licensed under the GNU Lesser General ++Public License version 2.1 or later. See the file COPYING.LIB. ++ ++The command line tool, self tests, examples, and other auxilliary ++files, are licensed under the GNU General Public License version 3.0 ++or later. See the file COPYING. ++ ++## Building the library ++ ++We require several tools to build the software, including: ++ ++* [Make](https://www.gnu.org/software/make/) ++* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later) ++* [Autoconf](https://www.gnu.org/software/autoconf/) ++* [Libtool](https://www.gnu.org/software/libtool/) ++* [Texinfo](https://www.gnu.org/software/texinfo/) ++* [help2man](http://www.gnu.org/software/help2man/) ++* [Tar](https://www.gnu.org/software/tar/) ++* [Gzip](https://www.gnu.org/software/gzip/) ++* [bison](https://www.gnu.org/software/bison/) ++* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual) ++* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual) ++* [Git](https://git-scm.com/) ++* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist) ++* [Valgrind](https://valgrind.org/) (optional) ++ ++The required software is typically distributed with your operating ++system, and the instructions for installing them differ. Here are ++some hints: ++ ++gNewSense/Debian/Ubuntu: ++``` ++sudo apt-get install make git-core autoconf automake libtool ++sudo apt-get install texinfo texlive texlive-generic-recommended texlive-extra-utils ++sudo apt-get install help2man gtk-doc-tools valgrind abigail-tools ++``` ++ ++The next step is to run autoreconf, ./configure, etc: ++ ++``` ++$ ./bootstrap ++``` ++ ++Then build the project normally: ++ ++``` ++$ make ++$ make check ++``` ++ ++Happy hacking! ++ ++ ++## Manual ++ ++The manual is in the `doc/` directory of the release. You can also browse ++the manual online at: ++ ++ - https://gnutls.gitlab.io/libtasn1/ ++ ++ ++## Code coverage report ++ ++The coverage report is at: ++ ++ - https://gnutls.gitlab.io/libtasn1/coverage ++ ++ ++## Issue trackers ++ ++ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues) ++ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2) ++ ++ ++## Homepage ++ ++The project homepage at the gnu site is at: ++ ++http://www.gnu.org/software/libtasn1/ ++ ++ ++For any copyright year range specified as YYYY-ZZZZ in this package ++note that the range specifies every single year in that closed interval. diff --git a/SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch b/SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch new file mode 100644 index 0000000..84dcbf0 --- /dev/null +++ b/SOURCES/0163-libtasn1-disable-code-not-needed-in-grub.patch @@ -0,0 +1,307 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 1 May 2020 17:12:23 +1000 +Subject: [PATCH] libtasn1: disable code not needed in grub + +We don't expect to be able to write ASN.1, only read it, +so we can disable some code. + +Do that with #if 0/#endif, rather than deletion. This means +that the difference between upstream and grub is smaller, +which should make updating libtasn1 easier in the future. + +With these exclusions we also avoid the need for minmax.h, +which is convenient because it means we don't have to +import it from gnulib. + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/libtasn1/lib/coding.c | 12 ++++++++++-- + grub-core/lib/libtasn1/lib/decoding.c | 2 ++ + grub-core/lib/libtasn1/lib/element.c | 4 ++-- + grub-core/lib/libtasn1/lib/errors.c | 3 +++ + grub-core/lib/libtasn1/lib/structure.c | 10 ++++++---- + include/grub/libtasn1.h | 15 +++++++++++++++ + 6 files changed, 38 insertions(+), 8 deletions(-) + +diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c +index 245ea64cf0..52def59836 100644 +--- a/grub-core/lib/libtasn1/lib/coding.c ++++ b/grub-core/lib/libtasn1/lib/coding.c +@@ -30,11 +30,11 @@ + #include "parser_aux.h" + #include + #include "element.h" +-#include "minmax.h" + #include + + #define MAX_TAG_LEN 16 + ++#if 0 + /******************************************************/ + /* Function : _asn1_error_description_value_not_found */ + /* Description: creates the ErrorDescription string */ +@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node, + Estrcat (ErrorDescription, "' not found"); + + } ++#endif + + /** + * asn1_length_der: +@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str, + return ASN1_SUCCESS; + } + ++#if 0 + /******************************************************/ + /* Function : _asn1_time_der */ + /* Description: creates the DER coding for a TIME */ +@@ -281,7 +283,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der, + + return ASN1_SUCCESS; + } +- ++#endif + + /* + void +@@ -520,6 +522,7 @@ asn1_bit_der (const unsigned char *str, int bit_len, + } + + ++#if 0 + /******************************************************/ + /* Function : _asn1_complete_explicit_tag */ + /* Description: add the length coding to the EXPLICIT */ +@@ -596,6 +599,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der, + + return ASN1_SUCCESS; + } ++#endif + + const tag_and_class_st _asn1_tags[] = { + [ASN1_ETYPE_GENERALSTRING] = +@@ -648,6 +652,8 @@ const tag_and_class_st _asn1_tags[] = { + + unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]); + ++ ++#if 0 + /******************************************************/ + /* Function : _asn1_insert_tag_der */ + /* Description: creates the DER coding of tags of one */ +@@ -1413,3 +1419,5 @@ error: + asn1_delete_structure (&node); + return err; + } ++ ++#endif +\ No newline at end of file +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +index ff04eb778c..42f9a92b5d 100644 +--- a/grub-core/lib/libtasn1/lib/decoding.c ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -1613,6 +1613,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len, + return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription); + } + ++#if 0 + /** + * asn1_der_decoding_element: + * @structure: pointer to an ASN1 structure +@@ -1643,6 +1644,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName, + { + return asn1_der_decoding(structure, ider, len, errorDescription); + } ++#endif + + /** + * asn1_der_decoding_startEnd: +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +index 997eb2725d..539008d8e9 100644 +--- a/grub-core/lib/libtasn1/lib/element.c ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) + return ASN1_SUCCESS; + } + +- ++#if 0 + /** + * asn1_write_value: + * @node_root: pointer to a structure +@@ -645,7 +645,7 @@ asn1_write_value (asn1_node node_root, const char *name, + + return ASN1_SUCCESS; + } +- ++#endif + + #define PUT_VALUE( ptr, ptr_size, data, data_size) \ + *len = data_size; \ +diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c +index cee74daf79..42785e8622 100644 +--- a/grub-core/lib/libtasn1/lib/errors.c ++++ b/grub-core/lib/libtasn1/lib/errors.c +@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = { + {0, 0} + }; + ++ ++#if 0 + /** + * asn1_perror: + * @error: is an error returned by a libtasn1 function. +@@ -73,6 +75,7 @@ asn1_perror (int error) + const char *str = asn1_strerror (error); + fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)"); + } ++#endif + + /** + * asn1_strerror: +diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c +index 8189c56a4c..fcfde01a39 100644 +--- a/grub-core/lib/libtasn1/lib/structure.c ++++ b/grub-core/lib/libtasn1/lib/structure.c +@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node) + return node->left; + } + +- ++#if 0 + int + _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name, + char *vector_name) +@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer, char *output_file_name, + + return ASN1_SUCCESS; + } +- ++#endif + + /** + * asn1_array2tree: +@@ -718,7 +718,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name, + return res; + } + +- ++#if 0 + /** + * asn1_print_structure: + * @out: pointer to the output file (e.g. stdout). +@@ -1058,7 +1058,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name, + } + } + } +- ++#endif + + + /** +@@ -1153,6 +1153,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions, const char *oidValue) + return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ + } + ++#if 0 + /** + * asn1_copy_node: + * @dst: Destination asn1 node. +@@ -1202,6 +1203,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name, + + return result; + } ++#endif + + /** + * asn1_dup_node: +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +index 6fd7a30dc3..785eda2ae3 100644 +--- a/include/grub/libtasn1.h ++++ b/include/grub/libtasn1.h +@@ -319,6 +319,8 @@ typedef struct asn1_data_node_st asn1_data_node_st; + /* Functions definitions */ + /***********************************/ + ++/* These functions are not used in grub and should not be referenced. */ ++#if 0 + extern ASN1_API int + asn1_parser2tree (const char *file, + asn1_node * definitions, char *error_desc); +@@ -327,14 +329,17 @@ extern ASN1_API int + asn1_parser2array (const char *inputFileName, + const char *outputFileName, + const char *vectorName, char *error_desc); ++#endif + + extern ASN1_API int + asn1_array2tree (const asn1_static_node * array, + asn1_node * definitions, char *errorDescription); + ++#if 0 + extern ASN1_API void + asn1_print_structure (FILE * out, asn1_node_const structure, + const char *name, int mode); ++#endif + + extern ASN1_API int + asn1_create_element (asn1_node_const definitions, +@@ -347,9 +352,11 @@ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure, unsigned int + extern ASN1_API int + asn1_delete_element (asn1_node structure, const char *element_name); + ++#if 0 + extern ASN1_API int + asn1_write_value (asn1_node node_root, const char *name, + const void *ivalue, int len); ++#endif + + extern ASN1_API int + asn1_read_value (asn1_node_const root, const char *name, +@@ -365,9 +372,11 @@ extern ASN1_API int + extern ASN1_API int + asn1_number_of_elements (asn1_node_const element, const char *name, int *num); + ++#if 0 + extern ASN1_API int + asn1_der_coding (asn1_node_const element, const char *name, + void *ider, int *len, char *ErrorDescription); ++#endif + + extern ASN1_API int + asn1_der_decoding2 (asn1_node *element, const void *ider, +@@ -378,12 +387,14 @@ extern ASN1_API int + asn1_der_decoding (asn1_node * element, const void *ider, + int ider_len, char *errorDescription); + ++#if 0 + /* Do not use. Use asn1_der_decoding() instead. */ + extern ASN1_API int + asn1_der_decoding_element (asn1_node * structure, + const char *elementName, + const void *ider, int len, + char *errorDescription) _ASN1_GCC_ATTR_DEPRECATED; ++#endif + + extern ASN1_API int + asn1_der_decoding_startEnd (asn1_node element, +@@ -408,13 +419,17 @@ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const + const char + *oidValue); + ++#if 0 + __LIBTASN1_PURE__ + extern ASN1_API const char *asn1_check_version (const char *req_version); ++#endif + + __LIBTASN1_PURE__ + extern ASN1_API const char *asn1_strerror (int error); + ++#if 0 + extern ASN1_API void asn1_perror (int error); ++#endif + + #define ASN1_MAX_TAG_SIZE 4 + #define ASN1_MAX_LENGTH_SIZE 9 diff --git a/SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch b/SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch new file mode 100644 index 0000000..7c756bd --- /dev/null +++ b/SOURCES/0164-libtasn1-changes-for-grub-compatibility.patch @@ -0,0 +1,202 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 1 May 2020 20:44:29 +1000 +Subject: [PATCH] libtasn1: changes for grub compatibility + +Do a few things to make libtasn1 compile as part of grub: + + - replace strcat. grub removed strcat so replace it with the appropriate + calls to memcpy and strlen. + + - replace c_isdigit with grub_isdigit (and don't import c-ctype from + gnulib) grub_isdigit provides the same functionality as c_isdigit: it + determines if the input is an ASCII digit without regard for locale. + + - replace GL_ATTRIBUTE_PURE with __attribute__((pure)) which been + supported since gcc-2.96. This avoids messing around with gnulib. + + - adjust libtasn1.h: drop the ASN1_API logic, it's not needed for our + modules. Unconditionally support const and pure attributes and adjust + header paths. + + - adjust header paths to "grub/libtasn1.h". + + - replace a 64 bit division with a call to grub_divmod64, preventing + creation of __udivdi3 calls on 32 bit platforms. + +Signed-off-by: Daniel Axtens +--- + grub-core/lib/libtasn1/lib/decoding.c | 11 ++++++----- + grub-core/lib/libtasn1/lib/element.c | 3 ++- + grub-core/lib/libtasn1/lib/gstr.c | 4 ++-- + grub-core/lib/libtasn1/lib/parser_aux.c | 7 ++++--- + grub-core/lib/libtasn1/lib/int.h | 4 ++-- + include/grub/libtasn1.h | 26 ++++++-------------------- + 6 files changed, 22 insertions(+), 33 deletions(-) + +diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c +index 42f9a92b5d..7856858b27 100644 +--- a/grub-core/lib/libtasn1/lib/decoding.c ++++ b/grub-core/lib/libtasn1/lib/decoding.c +@@ -32,7 +32,8 @@ + #include + #include + #include +-#include ++ ++#define c_isdigit grub_isdigit + + #ifdef DEBUG + # define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__) +@@ -2008,8 +2009,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, + (p2->type & CONST_ASSIGN)) + { + strcpy (name, definitions->name); +- strcat (name, "."); +- strcat (name, p2->name); ++ memcpy (name + strlen(name), ".", sizeof(" . ")); ++ memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1); + + len = sizeof (value); + result = asn1_read_value (definitions, name, value, &len); +@@ -2026,8 +2027,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element, + if (p2) + { + strcpy (name, definitions->name); +- strcat (name, "."); +- strcat (name, p2->name); ++ memcpy (name + strlen(name), ".", sizeof(" . ")); ++ memcpy (name + strlen(name), p2->name, strlen(p2->name) + 1); + + result = asn1_create_element (definitions, name, &aux); + if (result == ASN1_SUCCESS) +diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c +index 539008d8e9..ed761ff56b 100644 +--- a/grub-core/lib/libtasn1/lib/element.c ++++ b/grub-core/lib/libtasn1/lib/element.c +@@ -30,9 +30,10 @@ + #include "parser_aux.h" + #include + #include "structure.h" +-#include "c-ctype.h" + #include "element.h" + ++#define c_isdigit grub_isdigit ++ + void + _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) + { +diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c +index e91a3a151c..e33875c2c7 100644 +--- a/grub-core/lib/libtasn1/lib/gstr.c ++++ b/grub-core/lib/libtasn1/lib/gstr.c +@@ -36,13 +36,13 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src) + + if (dest_tot_size - dest_size > str_size) + { +- strcat (dest, src); ++ memcpy (dest + dest_size, src, str_size + 1); + } + else + { + if (dest_tot_size - dest_size > 0) + { +- strncat (dest, src, (dest_tot_size - dest_size) - 1); ++ memcpy (dest + dest_size, src, (dest_tot_size - dest_size) - 1); + dest[dest_tot_size - 1] = 0; + } + } +diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c +index d5dbbf8765..89c9be69dc 100644 +--- a/grub-core/lib/libtasn1/lib/parser_aux.c ++++ b/grub-core/lib/libtasn1/lib/parser_aux.c +@@ -26,7 +26,8 @@ + #include "gstr.h" + #include "structure.h" + #include "element.h" +-#include "c-ctype.h" ++ ++#define c_isdigit grub_isdigit + + char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ + +@@ -40,7 +41,7 @@ char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not fou + #ifdef __clang__ + __attribute__((no_sanitize("integer"))) + #endif +-_GL_ATTRIBUTE_PURE ++__attribute__((__pure__)) + static unsigned int + _asn1_hash_name (const char *x) + { +@@ -634,7 +635,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) + count = 0; + do + { +- d = val / 10; ++ d = grub_divmod64(val, 10, NULL); + r = val - d * 10; + temp[start + count] = '0' + (char) r; + count++; +diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h +index ea1625786c..4a568efee9 100644 +--- a/grub-core/lib/libtasn1/lib/int.h ++++ b/grub-core/lib/libtasn1/lib/int.h +@@ -35,7 +35,7 @@ + #include + #endif + +-#include ++#include "grub/libtasn1.h" + + #define ASN1_SMALL_VALUE_SIZE 16 + +@@ -115,7 +115,7 @@ extern const tag_and_class_st _asn1_tags[]; + #define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b) + #define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b) + #define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b) +-#define _asn1_strcat(a,b) strcat((char *)a, (const char *)b) ++#define _asn1_strcat(a,b) memcpy((char *)a + strlen((const char *)a), (const char *)b, strlen((const char *)b) + 1) + + #if SIZEOF_UNSIGNED_LONG_INT == 8 + # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b) +diff --git a/include/grub/libtasn1.h b/include/grub/libtasn1.h +index 785eda2ae3..28dbf16c4e 100644 +--- a/include/grub/libtasn1.h ++++ b/include/grub/libtasn1.h +@@ -38,29 +38,15 @@ + #ifndef LIBTASN1_H + #define LIBTASN1_H + +-#ifndef ASN1_API +-#if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY +-#define ASN1_API __attribute__((__visibility__("default"))) +-#elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC +-#define ASN1_API __declspec(dllexport) +-#elif defined _MSC_VER && ! defined ASN1_STATIC +-#define ASN1_API __declspec(dllimport) +-#else ++/* grub: ASN1_API is not used */ + #define ASN1_API +-#endif +-#endif + +-#ifdef __GNUC__ +-# define __LIBTASN1_CONST__ __attribute__((const)) +-# define __LIBTASN1_PURE__ __attribute__((pure)) +-#else +-# define __LIBTASN1_CONST__ +-# define __LIBTASN1_PURE__ +-#endif ++/* grub: all our supported compilers support these attributes */ ++#define __LIBTASN1_CONST__ __attribute__((const)) ++#define __LIBTASN1_PURE__ __attribute__((pure)) + +-#include +-#include +-#include /* for FILE* */ ++#include ++#include + + #ifdef __cplusplus + extern "C" diff --git a/SOURCES/0165-libtasn1-compile-into-asn1-module.patch b/SOURCES/0165-libtasn1-compile-into-asn1-module.patch new file mode 100644 index 0000000..0fb433f --- /dev/null +++ b/SOURCES/0165-libtasn1-compile-into-asn1-module.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 5 Jun 2020 17:47:25 +1000 +Subject: [PATCH] libtasn1: compile into asn1 module + +Create a wrapper file that specifies the module license. +Set up the makefile so it is built. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 15 +++++++++++++++ + grub-core/lib/libtasn1_wrap/wrap.c | 26 ++++++++++++++++++++++++++ + 2 files changed, 41 insertions(+) + create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 64cc758835..ea92468fa2 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2577,3 +2577,18 @@ module = { + common = commands/i386/wrmsr.c; + enable = x86; + }; ++ ++module = { ++ name = asn1; ++ common = lib/libtasn1/lib/decoding.c; ++ common = lib/libtasn1/lib/coding.c; ++ common = lib/libtasn1/lib/element.c; ++ common = lib/libtasn1/lib/structure.c; ++ common = lib/libtasn1/lib/parser_aux.c; ++ common = lib/libtasn1/lib/gstr.c; ++ common = lib/libtasn1/lib/errors.c; ++ common = lib/libtasn1_wrap/wrap.c; ++ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; ++ // -Wno-type-limits comes from libtasn1's configure.ac ++ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits'; ++}; +diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c +new file mode 100644 +index 0000000000..622ba942e3 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap.c +@@ -0,0 +1,26 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++/* ++ * libtasn1 is provided under LGPL2.1+, which is compatible ++ * with GPL3+. As Grub as a whole is under GPL3+, this module ++ * is therefore under GPL3+ also. ++ */ ++GRUB_MOD_LICENSE ("GPLv3+"); diff --git a/SOURCES/0166-test_asn1-test-module-for-libtasn1.patch b/SOURCES/0166-test_asn1-test-module-for-libtasn1.patch new file mode 100644 index 0000000..6cc13bd --- /dev/null +++ b/SOURCES/0166-test_asn1-test-module-for-libtasn1.patch @@ -0,0 +1,1457 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 10 Jun 2020 17:48:42 +1000 +Subject: [PATCH] test_asn1: test module for libtasn1 + +Import tests from libtasn1 that don't use functionality we don't +import. I have put them here rather than in the libtasn1 directory +because: + + - They need much more significant changes to run in the grub + context. + + - I don't expect they will need to be changed when updating + libtasn1: I expect the old tests will usually continue to pass on + new versions. + +This doesn't test the full decoder but that will be exercised in +test suites for coming patch sets. + +Signed-off-by: Daniel Axtens +--- + Makefile.util.def | 6 + + grub-core/Makefile.core.def | 13 ++ + .../lib/libtasn1_wrap/tests/CVE-2018-1000654.c | 61 ++++++ + grub-core/lib/libtasn1_wrap/tests/Test_overflow.c | 138 ++++++++++++++ + grub-core/lib/libtasn1_wrap/tests/Test_simple.c | 207 ++++++++++++++++++++ + grub-core/lib/libtasn1_wrap/tests/Test_strings.c | 150 +++++++++++++++ + .../lib/libtasn1_wrap/tests/object-id-decoding.c | 116 +++++++++++ + .../lib/libtasn1_wrap/tests/object-id-encoding.c | 120 ++++++++++++ + grub-core/lib/libtasn1_wrap/tests/octet-string.c | 211 +++++++++++++++++++++ + grub-core/lib/libtasn1_wrap/tests/reproducers.c | 81 ++++++++ + grub-core/lib/libtasn1_wrap/wrap_tests.c | 75 ++++++++ + .../tests/CVE-2018-1000654-1_asn1_tab.h | 32 ++++ + .../tests/CVE-2018-1000654-2_asn1_tab.h | 36 ++++ + grub-core/lib/libtasn1_wrap/wrap_tests.h | 38 ++++ + .gitignore | 1 + + tests/test_asn1.in | 12 ++ + 16 files changed, 1297 insertions(+) + create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c + create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c + create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h + create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h + create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h + create mode 100644 tests/test_asn1.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index 6366442129..d04b3fe68a 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1289,6 +1289,12 @@ script = { + common = tests/syslinux_test.in; + }; + ++script = { ++ testcase; ++ name = test_asn1; ++ common = tests/test_asn1.in; ++}; ++ + program = { + testcase; + name = example_unit_test; +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index ea92468fa2..a32e6ada59 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2592,3 +2592,16 @@ module = { + // -Wno-type-limits comes from libtasn1's configure.ac + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1/lib -Wno-type-limits'; + }; ++ ++module = { ++ name = test_asn1; ++ common = lib/libtasn1_wrap/tests/CVE-2018-1000654.c; ++ common = lib/libtasn1_wrap/tests/object-id-decoding.c; ++ common = lib/libtasn1_wrap/tests/object-id-encoding.c; ++ common = lib/libtasn1_wrap/tests/octet-string.c; ++ common = lib/libtasn1_wrap/tests/reproducers.c; ++ common = lib/libtasn1_wrap/tests/Test_overflow.c; ++ common = lib/libtasn1_wrap/tests/Test_simple.c; ++ common = lib/libtasn1_wrap/tests/Test_strings.c; ++ common = lib/libtasn1_wrap/wrap_tests.c; ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +new file mode 100644 +index 0000000000..534e304521 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2002-2018 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/****************************************************************/ ++/* Description: reproducer for CVE-2018-1000654 */ ++/****************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++#include "CVE-2018-1000654-1_asn1_tab.h" ++#include "CVE-2018-1000654-2_asn1_tab.h" ++ ++void ++test_CVE_2018_1000654 (void) ++{ ++ int result; ++ asn1_node definitions = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ result = asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_RECURSION) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++ ++ result = asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_RECURSION) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c +new file mode 100644 +index 0000000000..f48aea0ef8 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_overflow.c +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2012-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/* Written by Simon Josefsson */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++void ++test_overflow(void) ++{ ++ /* Test that values larger than long are rejected. This has worked ++ fine with all versions of libtasn1. */ ++ ++ { ++ unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"; ++ long l; ++ int len; ++ ++ l = asn1_get_length_der (der, sizeof der, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than int but smaller than long are ++ rejected. This limitation was introduced with libtasn1 2.12. */ ++#if (GRUB_LONG_MAX > GRUB_INT_MAX) ++ { ++ unsigned long num = ((long) GRUB_UINT_MAX) << 2; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l, ++ len); ++ return; ++ } ++ } ++#endif ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 64; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -4L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 1073741824; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -4L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++ ++ /* Test that values larger than would fit in the input string are ++ rejected. This problem was fixed in libtasn1 2.12. */ ++ { ++ unsigned long num = 2147483649; ++ unsigned char der[20]; ++ int der_len; ++ long l; ++ int len; ++ ++ asn1_length_der (num, der, &der_len); ++ ++ der_len = sizeof (der); ++ l = asn1_get_length_der (der, der_len, &len); ++ ++ if (l != -2L) ++ { ++ grub_fatal ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n", ++ l, len); ++ return; ++ } ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_simple.c b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c +new file mode 100644 +index 0000000000..9f01006ddf +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_simple.c +@@ -0,0 +1,207 @@ ++/* ++ * Copyright (C) 2011-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Written by Simon Josefsson ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int bitlen; ++ const char *bitstr; ++ int derlen; ++ const char *der; ++}; ++ ++static const struct tv tv[] = { ++ {0, "", 2, "\x01\x00"}, ++ {1, "\x00", 3, "\x02\x07\x00"}, ++ {2, "\x00", 3, "\x02\x06\x00"}, ++ {3, "\x00", 3, "\x02\x05\x00"}, ++ {4, "\x00", 3, "\x02\x04\x00"}, ++ {5, "\x00", 3, "\x02\x03\x00"}, ++ {6, "\x00", 3, "\x02\x02\x00"}, ++ {7, "\x00", 3, "\x02\x01\x00"}, ++ {8, "\x00\x00", 3, "\x02\x00\x00"}, ++ {9, "\x00\x00", 4, "\x03\x07\x00\x00"}, ++ {10, "\x00\x00", 4, "\x03\x06\x00\x00"}, ++ {11, "\x00\x00", 4, "\x03\x05\x00\x00"}, ++ {12, "\x00\x00", 4, "\x03\x04\x00\x00"}, ++ {13, "\x00\x00", 4, "\x03\x03\x00\x00"}, ++ {14, "\x00\x00", 4, "\x03\x02\x00\x00"}, ++ {15, "\x00\x00", 4, "\x03\x01\x00\x00"}, ++ {16, "\x00\x00", 4, "\x03\x00\x00\x00"}, ++ {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"}, ++ {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"}, ++ {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"}, ++ {1, "\xFF", 3, "\x02\x07\x80"}, ++ {2, "\xFF", 3, "\x02\x06\xc0"}, ++ {3, "\xFF", 3, "\x02\x05\xe0"}, ++ {4, "\xFF", 3, "\x02\x04\xf0"}, ++ {5, "\xFF", 3, "\x02\x03\xf8"}, ++ {6, "\xFF", 3, "\x02\x02\xfc"}, ++ {7, "\xFF", 3, "\x02\x01\xfe"}, ++ {8, "\xFF\xFF", 3, "\x02\x00\xff"}, ++ {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"}, ++ {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"}, ++ {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"}, ++ {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"}, ++ {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"}, ++ {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"}, ++ {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"}, ++ {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"}, ++ {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"}, ++ {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"}, ++ {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"}, ++}; ++ ++void ++test_simple (void) ++{ ++ int result; ++ unsigned char der[100]; ++ unsigned char str[100]; ++ int der_len = sizeof (der); ++ int str_size = sizeof (str); ++ int ret_len, bit_len; ++ grub_size_t i; ++ ++ /* Dummy test */ ++ ++ asn1_bit_der (NULL, 0, der, &der_len); ++ result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_GENERIC_ERROR) ++ { ++ grub_fatal ("asn1_get_bit_der zero\n"); ++ return; ++ } ++ ++ /* Encode short strings with increasing bit lengths */ ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Encode */ ++ ++ asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen, ++ der, &der_len); ++ ++#if 0 ++ { ++ size_t j; ++ for (j = 0; j < der_len; j++) ++ printf ("\\x%02x", der[j]); ++ printf ("\n"); ++ } ++#endif ++ ++ if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0) ++ { ++ grub_fatal ("asn1_bit_der iter %lu\n", (unsigned long) i); ++ return; ++ } ++ ++ /* Decode it */ ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, ++ str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != tv[i].derlen ++ || bit_len != tv[i].bitlen) ++ { ++ grub_fatal ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result); ++ return; ++ } ++ } ++ ++ ++ /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER, ++ and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT ++ STRING value "011011100101110111" can be any of the following, ++ among others, depending on the choice of padding bits, the form ++ of length octets [...]". ++ */ ++ ++ /* 03 04 06 6e 5d c0 DER encoding */ ++ ++ grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5); ++ der_len = 5; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != 5 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++ ++ /* 03 04 06 6e 5d e0 padded with "100000" */ ++ ++ grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5); ++ der_len = 5; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ if (result != ASN1_SUCCESS || ret_len != 5 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example padded\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++ ++ /* 03 81 04 06 6e 5d c0 long form of length octets */ ++ ++ grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6); ++ der_len = 6; ++ ++ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len); ++ ++ if (result != ASN1_SUCCESS || ret_len != 6 ++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0) ++ { ++ grub_fatal ("asn1_get_bit_der example long form\n"); ++ return; ++ } ++ ++ der_len = sizeof (der); ++ asn1_bit_der (str, bit_len, der, &der_len); ++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0) ++ { ++ grub_fatal ("asn1_bit_der example roundtrip\n"); ++ return; ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/Test_strings.c b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c +new file mode 100644 +index 0000000000..dbe1474b20 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/Test_strings.c +@@ -0,0 +1,150 @@ ++/* ++ * Copyright (C) 2012-2014 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Written by Simon Josefsson ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ unsigned int etype; ++ unsigned int str_len; ++ const void *str; ++ unsigned int der_len; ++ const void *der; ++}; ++ ++static const struct tv tv[] = { ++ {ASN1_ETYPE_IA5_STRING, 20, ++ "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72", ++ 22, ++ "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"}, ++ {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73", ++ 7, "\x13\x05\x4e\x69\x6b\x6f\x73"}, ++ {ASN1_ETYPE_UTF8_STRING, 12, "Αττική", ++ 14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"}, ++ {ASN1_ETYPE_TELETEX_STRING, 15, ++ "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e", ++ 17, ++ "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"}, ++ {ASN1_ETYPE_OCTET_STRING, 36, ++ "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A", ++ 38, ++ "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"} ++}; ++ ++#define SSTR(x) sizeof(x)-1,x ++static const struct tv ber[] = { ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")}, ++ {ASN1_ETYPE_OCTET_STRING, ++ SSTR("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"), ++ SSTR("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")}, ++}; ++ ++void ++test_strings () ++{ ++ int ret; ++ unsigned char tl[ASN1_MAX_TL_SIZE]; ++ unsigned int tl_len, der_len, str_len; ++ const unsigned char *str; ++ unsigned char *b; ++ unsigned int i; ++ ++ /* Dummy test */ ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Encode */ ++ tl_len = sizeof (tl); ++ ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len, ++ tl, &tl_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("Encoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ der_len = tl_len + tv[i].str_len; ++ ++ if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0) ++ { ++ grub_fatal ( ++ "DER encoding differs in %u! (size: %u, expected: %u)\n", ++ i, der_len, tv[i].der_len); ++ return; ++ } ++ ++ /* decoding */ ++ ret = ++ asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str, ++ &str_len); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("Decoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ ++ if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0) ++ { ++ grub_fatal ( ++ "DER decoded data differ in %u! (size: %u, expected: %u)\n", ++ i, der_len, tv[i].str_len); ++ return; ++ } ++ } ++ ++ /* BER decoding */ ++ for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++) ++ { ++ /* decoding */ ++ ret = ++ asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b, ++ &str_len, NULL); ++ if (ret != ASN1_SUCCESS) ++ { ++ grub_fatal ("BER decoding error in %u: %s\n", i, ++ asn1_strerror (ret)); ++ return; ++ } ++ ++ if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0) ++ { ++ grub_fatal ( ++ "BER decoded data differ in %u! (size: %u, expected: %u)\n", ++ i, str_len, ber[i].str_len); ++ return; ++ } ++ grub_free(b); ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c +new file mode 100644 +index 0000000000..d367bbfb5a +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c +@@ -0,0 +1,116 @@ ++/* ++ * Copyright (C) 2016 Red Hat, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int der_len; ++ const unsigned char *der; ++ const char *oid; ++ int expected_error; ++}; ++ ++static const struct tv tv[] = { ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x80\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_DER_ERROR /* leading 0x80 */ ++ }, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_DER_ERROR /* leading 0x80 */ ++ }, ++ {.der_len = 6, ++ .der = (void *) "\x06\x04\x01\x02\x03\x04", ++ .oid = "0.1.2.3.4", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x51\x02\x03", ++ .oid = "2.1.2.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x88\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d", ++ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = ++ (void *) ++ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07", ++ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7", ++ .expected_error = ASN1_SUCCESS}, ++}; ++ ++void ++test_object_id_decoding (void) ++{ ++ char str[128]; ++ int ret, ret_len; ++ grub_size_t i; ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* decode */ ++ ret = ++ asn1_get_object_id_der (tv[i].der+1, ++ tv[i].der_len-1, &ret_len, str, ++ sizeof (str)); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n", ++ __LINE__, (unsigned long) i, asn1_strerror(ret), tv[i].expected_error); ++ return; ++ } ++ ++ if (tv[i].expected_error != ASN1_SUCCESS) ++ continue; ++ ++ if (ret_len != tv[i].der_len-1) ++ { ++ grub_fatal ( ++ "%d: iter %lu: error in DER, length returned is %d, had %d\n", ++ __LINE__, (unsigned long)i, ret_len, tv[i].der_len-1); ++ return; ++ } ++ ++ if (grub_strcmp (tv[i].oid, str) != 0) ++ { ++ grub_fatal ( ++ "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n", ++ __LINE__, (unsigned long) i, str, tv[i].oid); ++ return; ++ } ++ ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c +new file mode 100644 +index 0000000000..3a83b58c59 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (C) 2019 Nikos Mavrogiannopoulos ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++struct tv ++{ ++ int der_len; ++ const unsigned char *der; ++ const char *oid; ++ int expected_error; ++}; ++ ++static const struct tv tv[] = { ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "5.999.3", ++ .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */ ++ }, ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "0.48.9", ++ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */ ++ }, ++ {.der_len = 0, ++ .der = (void *) "", ++ .oid = "1.40.9", ++ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */ ++ }, ++ {.der_len = 4, ++ .der = (void *) "\x06\x02\x4f\x63", ++ .oid = "1.39.99", ++ .expected_error = ASN1_SUCCESS, ++ }, ++ {.der_len = 6, ++ .der = (void *) "\x06\x04\x01\x02\x03\x04", ++ .oid = "0.1.2.3.4", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x51\x02\x03", ++ .oid = "2.1.2.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 5, ++ .der = (void *) "\x06\x03\x88\x37\x03", ++ .oid = "2.999.3", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 12, ++ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01", ++ .oid = "1.3.6.1.4.1.2312.9.5.1", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = (void *) "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d", ++ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109", ++ .expected_error = ASN1_SUCCESS}, ++ {.der_len = 19, ++ .der = ++ (void *) ++ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07", ++ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7", ++ .expected_error = ASN1_SUCCESS}, ++}; ++ ++void ++test_object_id_encoding(void) ++{ ++ unsigned char der[128]; ++ int ret, der_len, i; ++ ++ for (i = 0; i < (int)(sizeof (tv) / sizeof (tv[0])); i++) ++ { ++ der_len = sizeof(der); ++ ret = asn1_object_id_der(tv[i].oid, der, &der_len, 0); ++ if (ret != ASN1_SUCCESS) ++ { ++ if (ret == tv[i].expected_error) ++ continue; ++ grub_fatal ( ++ "%d: iter %lu, encoding of OID failed: %s\n", ++ __LINE__, (unsigned long) i, asn1_strerror(ret)); ++ return; ++ } ++ else if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n", ++ __LINE__, (unsigned long) i, tv[i].oid); ++ return; ++ } ++ ++ if (der_len != tv[i].der_len || grub_memcmp(der, tv[i].der, der_len) != 0) ++ { ++ grub_fatal ( ++ "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n", ++ __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len); ++ ++ return; ++ } ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/octet-string.c b/grub-core/lib/libtasn1_wrap/tests/octet-string.c +new file mode 100644 +index 0000000000..d8a049e8df +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/octet-string.c +@@ -0,0 +1,211 @@ ++/* ++ * Copyright (C) 2011-2020 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ * Written by Simon Josefsson and Nikos Mavrogiannopoulos ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++ ++struct tv ++{ ++ const char *name; ++ int der_len; ++ const unsigned char *der_str; ++ int len; ++ const unsigned char *string; ++ int expected_error; ++ int ber; ++}; ++ ++static const struct tv tv[] = { ++ {.name = "primitive octet strings", ++ .der_len = 10, ++ .der_str = ++ (void*)"\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .len = 8, ++ .string = ++ (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .ber = 0}, ++ {.der_len = 22, ++ .der_str = ++ (void*)"\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27", ++ .len = 20, ++ .string = ++ (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"}, ++ ++ {.name = "long type of length", ++ .der_len = 23, ++ .der_str = ++ (void*)"\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27", ++ .len = 20, ++ .string = ++ (void*)"\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27", ++ .ber = 1}, ++ {.der_len = 11, ++ .der_str = ++ (void*)"\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .len = 8, ++ .string = ++ (void*)"\x01\x23\x45\x67\x89\xab\xcd\xef", ++ .ber = 1}, ++ ++ {.name = "constructed - indefinite", ++ .der_len = 11, ++ .der_str = (void*)"\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00", ++ .len = 5, ++ .string = (void*)"\x01\x02\x03\x04\x05", ++ .ber = 1, ++ }, ++ ++ {.name = "constructed - definite - concat", ++ .der_len = 12, ++ .der_str = (void*)"\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f", ++ .len = 6, ++ .string = (void*)"\x0a\x0b\x0c\x0d\x0e\x0f", ++ .ber = 1, ++ }, ++ {.name = "constructed - definite - recursive", ++ .der_len = 15, ++ .der_str = (void*)"\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f", ++ .len = 5, ++ .string = (void*)"\x0a\x0b\x0c\x0d\x0f", ++ .ber = 1, ++ }, ++ {.name = "constructed - definite - single", ++ .der_len = 7, ++ .der_str = (void*)"\x24\x05\x04\x03\x01\x02\x03", ++ .len = 3, ++ .string = (void*)"\x01\x02\x03", ++ .ber = 1, ++ }, ++ ++ /* a large amount of recursive indefinite encoding */ ++ {.name = "a large amount of recursive indefinite encoding", ++ .der_len = 29325, ++ .der_str = (void*)"\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80", ++ .len = 0, ++ .ber = 1, ++ .expected_error = ASN1_DER_ERROR ++ } ++}; ++ ++void ++test_octet_string (void) ++{ ++ unsigned char str[100]; ++ unsigned char der[100]; ++ int der_len = sizeof (der); ++ int str_size = sizeof (str); ++ unsigned char *tmp = NULL; ++ int ret, ret_len; ++ grub_size_t i; ++ ++ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++) ++ { ++ /* Decode */ ++ ++ if (tv[i].ber == 0) ++ { ++ str_size = sizeof (str); ++ ret = ++ asn1_get_octet_der (tv[i].der_str + 1, ++ tv[i].der_len - 1, &ret_len, str, ++ sizeof (str), &str_size); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_get_octet_der: %s: got %d expected %d\n", ++ __LINE__, tv[i].name, ret, ++ tv[i].expected_error); ++ return; ++ } ++ if (tv[i].expected_error) ++ continue; ++ ++ if (ret_len != tv[i].der_len - 1) ++ { ++ grub_fatal ( ++ "%d: error in DER, length returned is %d, had %d\n", ++ __LINE__, ret_len, tv[i].der_len - 1); ++ return; ++ } ++ ++ if (str_size != tv[i].len ++ || grub_memcmp (tv[i].string, str, tv[i].len) != 0) ++ { ++ grub_fatal ( ++ "%d: memcmp: %s: got invalid decoding\n", ++ __LINE__, tv[i].name); ++ ++ return; ++ } ++ ++ /* Encode */ ++ der_len = sizeof (der); ++ asn1_octet_der (str, str_size, der, &der_len); ++ ++ if (der_len != tv[i].der_len - 1 ++ || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0) ++ { ++ grub_fatal ( ++ "encoding: %s: got invalid encoding\n", ++ tv[i].name); ++ return; ++ } ++ } ++ ++ ret = ++ asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING, ++ tv[i].der_str, tv[i].der_len, ++ &tmp, (unsigned int*)&str_size, (unsigned int*)&der_len); ++ if (ret != tv[i].expected_error) ++ { ++ grub_fatal ( ++ "%d: asn1_decode_simple_ber: %s: got %s expected %s\n", ++ __LINE__, tv[i].name, asn1_strerror(ret), asn1_strerror(tv[i].expected_error)); ++ return; ++ } ++ if (tv[i].expected_error) ++ continue; ++ ++ if (der_len != tv[i].der_len) ++ { ++ grub_fatal ( ++ "%d: error: %s: DER, length returned is %d, had %d\n", ++ __LINE__, tv[i].name, der_len, tv[i].der_len); ++ return; ++ } ++ ++ if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0) ++ { ++ grub_fatal ( ++ "%d: memcmp: %s: got invalid decoding\n", ++ __LINE__, tv[i].name); ++ return; ++ } ++ grub_free (tmp); ++ tmp = NULL; ++ ++ } ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/reproducers.c b/grub-core/lib/libtasn1_wrap/tests/reproducers.c +new file mode 100644 +index 0000000000..dc7268d4c6 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/reproducers.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2019 Free Software Foundation, Inc. ++ * ++ * This file is part of LIBTASN1. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ * ++ */ ++ ++/****************************************************************/ ++/* Description: run reproducers for several fixed issues */ ++/****************************************************************/ ++ ++#include ++#include ++#include ++#include "../wrap_tests.h" ++ ++#define CONST_DOWN (1U<<29) ++ ++/* produces endless loop (fixed by d4b624b2): ++ * The following translates into a single node with all pointers ++ * (right,left,down) set to NULL. */ ++const asn1_static_node endless_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 0, NULL } ++}; ++ ++/* produces memory leak (fixed by f16d1ff9): ++ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1 ++ * at 0x4837B65: calloc (vg_replace_malloc.c:762) ++ * by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71) ++ * by 0x4853AAC: asn1_array2tree (structure.c:200) ++ * by 0x10923B: main (single_node.c:67) ++ */ ++const asn1_static_node tab[] = { ++{ "a", CONST_DOWN, "" }, ++{ "b", 0, "" }, ++{ "c", 0, "" }, ++{ NULL, 0, NULL } ++}; ++ ++void ++test_reproducers (void) ++{ ++ int result; ++ asn1_node definitions = NULL; ++ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++ result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++ ++ definitions = NULL; ++ result = asn1_array2tree (tab, &definitions, errorDescription); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_fatal ("Error: %s\nErrorDescription = %s\n\n", ++ asn1_strerror (result), errorDescription); ++ return; ++ } ++ ++ asn1_delete_structure (&definitions); ++} +diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.c b/grub-core/lib/libtasn1_wrap/wrap_tests.c +new file mode 100644 +index 0000000000..75fcd21f0d +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.c +@@ -0,0 +1,75 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include "wrap_tests.h" ++ ++/* ++ * libtasn1 tests - from which this is derived - are provided under GPL3+. ++ */ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_command_t cmd; ++ ++static grub_err_t ++grub_cmd_asn1test (grub_command_t cmdd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ grub_printf ("test_CVE_2018_1000654\n"); ++ test_CVE_2018_1000654 (); ++ ++ grub_printf ("test_object_id_decoding\n"); ++ test_object_id_decoding (); ++ ++ grub_printf ("test_object_id_encoding\n"); ++ test_object_id_encoding (); ++ ++ grub_printf ("test_octet_string\n"); ++ test_octet_string (); ++ ++ grub_printf ("test_overflow\n"); ++ test_overflow (); ++ ++ grub_printf ("test_reproducers\n"); ++ test_overflow (); ++ ++ grub_printf ("test_simple\n"); ++ test_simple (); ++ ++ grub_printf ("test_strings\n"); ++ test_strings (); ++ ++ grub_printf ("ASN.1 self-tests passed\n"); ++ ++ return GRUB_ERR_NONE; ++} ++ ++ ++GRUB_MOD_INIT(test_asn1) ++{ ++ cmd = grub_register_command ("test_asn1", grub_cmd_asn1test, NULL, ++ "Run self-tests for the ASN.1 parser."); ++} ++ ++GRUB_MOD_FINI(test_asn1) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h +new file mode 100644 +index 0000000000..1e7d3d64f5 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h +@@ -0,0 +1,32 @@ ++#if HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++ ++const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 1610612748, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "identified-organization", 1073741825, "3"}, ++ { "dod", 1073741825, "6"}, ++ { "internet", 1073741825, "1"}, ++ { "security", 1073741825, "5"}, ++ { "mechanisms", 1073741825, "5"}, ++ { "pkix", 1073741825, "7"}, ++ { "id-mod", 1073741825, "0"}, ++ { "id-pkix1-implicit-88", 1, "2"}, ++ { "id-xnyTest", 1879048204, NULL }, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "1"}, ++ { "id-ix", 1880096780, "OBJECR"}, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "2"}, ++ { "id-xnyTest", 805306380, NULL }, ++ { NULL, 1073741825, "id-ix"}, ++ { NULL, 1073741825, "29"}, ++ { NULL, 1, "1"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h +new file mode 100644 +index 0000000000..e2561e5ec6 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h +@@ -0,0 +1,36 @@ ++#if HAVE_CONFIG_H ++# include "config.h" ++#endif ++ ++#include ++ ++const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = { ++ { "TEST_TREE", 536875024, NULL }, ++ { NULL, 1610612748, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "identified-organization", 1073741825, "3"}, ++ { "dod", 1073741825, "6"}, ++ { "internet", 1073741825, "1"}, ++ { "security", 1073741825, "5"}, ++ { "mechanisms", 1073741825, "5"}, ++ { "pkix", 1073741825, "7"}, ++ { "id-mod", 1073741825, "0"}, ++ { "id-pkix1-implicit-88", 1, "2"}, ++ { "id-oneTest", 1879048204, NULL }, ++ { NULL, 1073741825, "id-two"}, ++ { NULL, 1073741825, "9"}, ++ { NULL, 1, "1"}, ++ { "id-two", 1879048204, NULL }, ++ { NULL, 1073741825, "id-three"}, ++ { NULL, 1073741825, "2"}, ++ { NULL, 1, "2"}, ++ { "id-three", 1879048204, NULL }, ++ { NULL, 1073741825, "id-four"}, ++ { NULL, 1073741825, "3"}, ++ { NULL, 1, "3"}, ++ { "id-four", 805306380, NULL }, ++ { NULL, 1073741825, "id-two"}, ++ { NULL, 1073741825, "3"}, ++ { NULL, 1, "3"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/lib/libtasn1_wrap/wrap_tests.h b/grub-core/lib/libtasn1_wrap/wrap_tests.h +new file mode 100644 +index 0000000000..555e56dd20 +--- /dev/null ++++ b/grub-core/lib/libtasn1_wrap/wrap_tests.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef LIBTASN1_WRAP_TESTS_H ++#define LIBTASN1_WRAP_TESTS_H ++ ++void test_CVE_2018_1000654 (void); ++ ++void test_object_id_encoding (void); ++ ++void test_object_id_decoding (void); ++ ++void test_octet_string (void); ++ ++void test_overflow (void); ++ ++void test_reproducers (void); ++ ++void test_simple (void); ++ ++void test_strings (void); ++ ++#endif +diff --git a/.gitignore b/.gitignore +index 208d1d2325..1d005887e7 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -264,6 +264,7 @@ widthspec.bin + /stamp-h1 + /syslinux_test + /tar_test ++/test_asn1 + /test_sha512sum + /test_unset + /tests/syslinux/ubuntu10.04_grub.cfg +diff --git a/tests/test_asn1.in b/tests/test_asn1.in +new file mode 100644 +index 0000000000..8173c5c270 +--- /dev/null ++++ b/tests/test_asn1.in +@@ -0,0 +1,12 @@ ++#! @BUILD_SHEBANG@ ++set -e ++ ++. "@builddir@/grub-core/modinfo.sh" ++ ++out=`echo test_asn1 | @builddir@/grub-shell` ++ ++if [ "$(echo "$out" | tail -n 1)" != "ASN.1 self-tests passed" ]; then ++ echo "ASN.1 test failure: $out" ++ exit 1 ++fi ++ diff --git a/SOURCES/0167-grub-install-support-embedding-x509-certificates.patch b/SOURCES/0167-grub-install-support-embedding-x509-certificates.patch new file mode 100644 index 0000000..c4c35f4 --- /dev/null +++ b/SOURCES/0167-grub-install-support-embedding-x509-certificates.patch @@ -0,0 +1,253 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alastair D'Silva +Date: Mon, 6 Jul 2020 13:33:04 +1000 +Subject: [PATCH] grub-install: support embedding x509 certificates + +To support verification of appended signatures, we need a way to +embed the necessary public keys. Existing appended signature schemes +in the Linux kernel use X.509 certificates, so allow certificates to +be embedded in the grub core image in the same way as PGP keys. + +Signed-off-by: Alastair D'Silva +Signed-off-by: Daniel Axtens +--- + grub-core/commands/pgp.c | 2 +- + util/grub-install-common.c | 23 ++++++++++++++++++++++- + util/grub-mkimage.c | 15 +++++++++++++-- + util/mkimage.c | 38 ++++++++++++++++++++++++++++++++++++-- + include/grub/kernel.h | 4 +++- + include/grub/util/install.h | 7 +++++-- + 6 files changed, 80 insertions(+), 9 deletions(-) + +diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c +index 355a43844a..b81ac0ae46 100644 +--- a/grub-core/commands/pgp.c ++++ b/grub-core/commands/pgp.c +@@ -944,7 +944,7 @@ GRUB_MOD_INIT(pgp) + grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); + + /* Not an ELF module, skip. */ +- if (header->type != OBJ_TYPE_PUBKEY) ++ if (header->type != OBJ_TYPE_GPG_PUBKEY) + continue; + + pseudo_file.fs = &pseudo_fs; +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index a74fee16e2..c603f5b308 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -460,6 +460,8 @@ static char **pubkeys; + static size_t npubkeys; + static char *sbat; + static int disable_shim_lock; ++static char **x509keys; ++static size_t nx509keys; + static grub_compression_t compression; + static size_t appsig_size; + +@@ -501,6 +503,12 @@ grub_install_parse (int key, char *arg) + case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK: + disable_shim_lock = 1; + return 1; ++ case 'x': ++ x509keys = xrealloc (x509keys, ++ sizeof (x509keys[0]) ++ * (nx509keys + 1)); ++ x509keys[nx509keys++] = xstrdup (arg); ++ return 1; + + case GRUB_INSTALL_OPTIONS_VERBOSITY: + verbosity++; +@@ -627,6 +635,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + for (pk = pubkeys; pk < pubkeys + npubkeys; pk++) + slen += 20 + grub_strlen (*pk); + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ slen += 10 + grub_strlen (*pk); ++ + for (md = modules.entries; *md; md++) + { + slen += 10 + grub_strlen (*md); +@@ -655,6 +666,14 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + *p++ = ' '; + } + ++ for (pk = x509keys; pk < x509keys + nx509keys; pk++) ++ { ++ p = grub_stpcpy (p, "--x509 '"); ++ p = grub_stpcpy (p, *pk); ++ *p++ = '\''; ++ *p++ = ' '; ++ } ++ + for (md = modules.entries; *md; md++) + { + *p++ = '\''; +@@ -684,7 +703,9 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix, + + grub_install_generate_image (dir, prefix, fp, outname, + modules.entries, memdisk_path, +- pubkeys, npubkeys, config_path, tgt, ++ pubkeys, npubkeys, ++ x509keys, nx509keys, ++ config_path, tgt, + note, appsig_size, compression, dtb, sbat, + disable_shim_lock); + while (dc--) +diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c +index 8a53310548..e1f1112784 100644 +--- a/util/grub-mkimage.c ++++ b/util/grub-mkimage.c +@@ -75,7 +75,8 @@ static struct argp_option options[] = { + /* TRANSLATORS: "embed" is a verb (command description). "*/ + {"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0}, + /* TRANSLATORS: "embed" is a verb (command description). "*/ +- {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for signature checking"), 0}, ++ {"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0}, ++ {"x509", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0}, + /* TRANSLATORS: NOTE is a name of segment. */ + {"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0}, + {"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0}, +@@ -124,6 +125,8 @@ struct arguments + char *dtb; + char **pubkeys; + size_t npubkeys; ++ char **x509keys; ++ size_t nx509keys; + char *font; + char *config; + char *sbat; +@@ -206,6 +209,13 @@ argp_parser (int key, char *arg, struct argp_state *state) + arguments->pubkeys[arguments->npubkeys++] = xstrdup (arg); + break; + ++ case 'x': ++ arguments->x509keys = xrealloc (arguments->x509keys, ++ sizeof (arguments->x509keys[0]) ++ * (arguments->nx509keys + 1)); ++ arguments->x509keys[arguments->nx509keys++] = xstrdup (arg); ++ break; ++ + case 'c': + if (arguments->config) + free (arguments->config); +@@ -332,7 +342,8 @@ main (int argc, char *argv[]) + grub_install_generate_image (arguments.dir, arguments.prefix, fp, + arguments.output, arguments.modules, + arguments.memdisk, arguments.pubkeys, +- arguments.npubkeys, arguments.config, ++ arguments.npubkeys, arguments.x509keys, ++ arguments.nx509keys, arguments.config, + arguments.image_target, arguments.note, + arguments.appsig_size, arguments.comp, + arguments.dtb, arguments.sbat, +diff --git a/util/mkimage.c b/util/mkimage.c +index bab1227601..8319e8dfbd 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -867,7 +867,8 @@ void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, const char *outname, char *mods[], + char *memdisk_path, char **pubkey_paths, +- size_t npubkeys, char *config_path, ++ size_t npubkeys, char **x509key_paths, ++ size_t nx509keys, char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, grub_compression_t comp, + const char *dtb_path, const char *sbat_path, +@@ -913,6 +914,19 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i])); ++ grub_util_info ("the size of x509 public key %u is 0x%" ++ GRUB_HOST_PRIxLONG_LONG, ++ (unsigned) i, (unsigned long long) curs); ++ total_module_size += curs + sizeof (struct grub_module_header); ++ } ++ } ++ + if (memdisk_path) + { + memdisk_size = ALIGN_UP(grub_util_get_image_size (memdisk_path), 512); +@@ -1034,7 +1048,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + curs = grub_util_get_image_size (pubkey_paths[i]); + + header = (struct grub_module_header *) (kernel_img + offset); +- header->type = grub_host_to_target32 (OBJ_TYPE_PUBKEY); ++ header->type = grub_host_to_target32 (OBJ_TYPE_GPG_PUBKEY); + header->size = grub_host_to_target32 (curs + sizeof (*header)); + offset += sizeof (*header); + +@@ -1043,6 +1057,26 @@ grub_install_generate_image (const char *dir, const char *prefix, + } + } + ++ { ++ size_t i; ++ for (i = 0; i < nx509keys; i++) ++ { ++ size_t curs; ++ struct grub_module_header *header; ++ ++ curs = grub_util_get_image_size (x509key_paths[i]); ++ ++ header = (struct grub_module_header *) (kernel_img + offset); ++ header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY); ++ header->size = grub_host_to_target32 (curs + sizeof (*header)); ++ offset += sizeof (*header); ++ ++ grub_util_load_image (x509key_paths[i], kernel_img + offset); ++ offset += ALIGN_ADDR (curs); ++ } ++ } ++ ++ + if (memdisk_path) + { + struct grub_module_header *header; +diff --git a/include/grub/kernel.h b/include/grub/kernel.h +index 55849777ea..98edc0863f 100644 +--- a/include/grub/kernel.h ++++ b/include/grub/kernel.h +@@ -30,7 +30,9 @@ enum + OBJ_TYPE_PREFIX, + OBJ_TYPE_PUBKEY, + OBJ_TYPE_DTB, +- OBJ_TYPE_DISABLE_SHIM_LOCK ++ OBJ_TYPE_DISABLE_SHIM_LOCK, ++ OBJ_TYPE_GPG_PUBKEY, ++ OBJ_TYPE_X509_PUBKEY, + }; + + /* The module header. */ +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index cf4531e02b..51f3b13ac1 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -67,6 +67,8 @@ + N_("SBAT metadata"), 0 }, \ + { "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \ + N_("disable shim_lock verifier"), 0 }, \ ++ { "x509key", 'x', N_("FILE"), 0, \ ++ N_("embed FILE as an x509 certificate for signature checking"), 0}, \ + { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\ + "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \ + 1}, \ +@@ -188,8 +190,9 @@ void + grub_install_generate_image (const char *dir, const char *prefix, + FILE *out, + const char *outname, char *mods[], +- char *memdisk_path, char **pubkey_paths, +- size_t npubkeys, ++ char *memdisk_path, ++ char **pubkey_paths, size_t npubkeys, ++ char **x509key_paths, size_t nx509keys, + char *config_path, + const struct grub_install_image_target_desc *image_target, + int note, size_t appsig_size, diff --git a/SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch b/SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch new file mode 100644 index 0000000..0ebc6c7 --- /dev/null +++ b/SOURCES/0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch @@ -0,0 +1,639 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:35:10 +1000 +Subject: [PATCH] appended signatures: import GNUTLS's ASN.1 description files + +In order to parse PKCS#7 messages and X.509 certificates with libtasn1, +we need some information about how they are encoded. + +We get these from GNUTLS, which has the benefit that they support the +features we need and are well tested. + +The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing +us to import it without issue. + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/gnutls_asn1_tab.c | 121 ++++++ + grub-core/commands/appendedsig/pkix_asn1_tab.c | 484 +++++++++++++++++++++++ + 2 files changed, 605 insertions(+) + create mode 100644 grub-core/commands/appendedsig/gnutls_asn1_tab.c + create mode 100644 grub-core/commands/appendedsig/pkix_asn1_tab.c + +diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c +new file mode 100644 +index 0000000000..ddd1314e63 +--- /dev/null ++++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c +@@ -0,0 +1,121 @@ ++#include ++#include ++ ++const asn1_static_node gnutls_asn1_tab[] = { ++ { "GNUTLS", 536872976, NULL }, ++ { NULL, 1073741836, NULL }, ++ { "RSAPublicKey", 1610612741, NULL }, ++ { "modulus", 1073741827, NULL }, ++ { "publicExponent", 3, NULL }, ++ { "RSAPrivateKey", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "modulus", 1073741827, NULL }, ++ { "publicExponent", 1073741827, NULL }, ++ { "privateExponent", 1073741827, NULL }, ++ { "prime1", 1073741827, NULL }, ++ { "prime2", 1073741827, NULL }, ++ { "exponent1", 1073741827, NULL }, ++ { "exponent2", 1073741827, NULL }, ++ { "coefficient", 1073741827, NULL }, ++ { "otherPrimeInfos", 16386, "OtherPrimeInfos"}, ++ { "ProvableSeed", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "seed", 7, NULL }, ++ { "OtherPrimeInfos", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "OtherPrimeInfo"}, ++ { "OtherPrimeInfo", 1610612741, NULL }, ++ { "prime", 1073741827, NULL }, ++ { "exponent", 1073741827, NULL }, ++ { "coefficient", 3, NULL }, ++ { "AlgorithmIdentifier", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "parameters", 541081613, NULL }, ++ { "algorithm", 1, NULL }, ++ { "DigestInfo", 1610612741, NULL }, ++ { "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"}, ++ { "digest", 7, NULL }, ++ { "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, ++ { "DSAPublicKey", 1073741827, NULL }, ++ { "DSAParameters", 1610612741, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 3, NULL }, ++ { "DSASignatureValue", 1610612741, NULL }, ++ { "r", 1073741827, NULL }, ++ { "s", 3, NULL }, ++ { "DSAPrivateKey", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 1073741827, NULL }, ++ { "Y", 1073741827, NULL }, ++ { "priv", 3, NULL }, ++ { "DHParameter", 1610612741, NULL }, ++ { "prime", 1073741827, NULL }, ++ { "base", 1073741827, NULL }, ++ { "privateValueLength", 16387, NULL }, ++ { "ECParameters", 1610612754, NULL }, ++ { "namedCurve", 12, NULL }, ++ { "ECPrivateKey", 1610612741, NULL }, ++ { "Version", 1073741827, NULL }, ++ { "privateKey", 1073741831, NULL }, ++ { "parameters", 1610637314, "ECParameters"}, ++ { NULL, 2056, "0"}, ++ { "publicKey", 536895494, NULL }, ++ { NULL, 2056, "1"}, ++ { "PrincipalName", 1610612741, NULL }, ++ { "name-type", 1610620931, NULL }, ++ { NULL, 2056, "0"}, ++ { "name-string", 536879115, NULL }, ++ { NULL, 1073743880, "1"}, ++ { NULL, 27, NULL }, ++ { "KRB5PrincipalName", 1610612741, NULL }, ++ { "realm", 1610620955, NULL }, ++ { NULL, 2056, "0"}, ++ { "principalName", 536879106, "PrincipalName"}, ++ { NULL, 2056, "1"}, ++ { "RSAPSSParameters", 1610612741, NULL }, ++ { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"}, ++ { NULL, 2056, "0"}, ++ { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"}, ++ { NULL, 2056, "1"}, ++ { "saltLength", 1610653699, NULL }, ++ { NULL, 1073741833, "20"}, ++ { NULL, 2056, "2"}, ++ { "trailerField", 536911875, NULL }, ++ { NULL, 1073741833, "1"}, ++ { NULL, 2056, "3"}, ++ { "GOSTParameters", 1610612741, NULL }, ++ { "publicKeyParamSet", 1073741836, NULL }, ++ { "digestParamSet", 16396, NULL }, ++ { "GOSTParametersOld", 1610612741, NULL }, ++ { "publicKeyParamSet", 1073741836, NULL }, ++ { "digestParamSet", 1073741836, NULL }, ++ { "encryptionParamSet", 16396, NULL }, ++ { "GOSTPrivateKey", 1073741831, NULL }, ++ { "GOSTPrivateKeyOld", 1073741827, NULL }, ++ { "IssuerSignTool", 1610612741, NULL }, ++ { "signTool", 1073741858, NULL }, ++ { "cATool", 1073741858, NULL }, ++ { "signToolCert", 1073741858, NULL }, ++ { "cAToolCert", 34, NULL }, ++ { "Gost28147-89-EncryptedKey", 1610612741, NULL }, ++ { "encryptedKey", 1073741831, NULL }, ++ { "maskKey", 1610637319, NULL }, ++ { NULL, 4104, "0"}, ++ { "macKey", 7, NULL }, ++ { "SubjectPublicKeyInfo", 1610612741, NULL }, ++ { "algorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "subjectPublicKey", 6, NULL }, ++ { "GostR3410-TransportParameters", 1610612741, NULL }, ++ { "encryptionParamSet", 1073741836, NULL }, ++ { "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"}, ++ { NULL, 4104, "0"}, ++ { "ukm", 7, NULL }, ++ { "GostR3410-KeyTransport", 536870917, NULL }, ++ { "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"}, ++ { "transportParameters", 536895490, "GostR3410-TransportParameters"}, ++ { NULL, 4104, "0"}, ++ { NULL, 0, NULL } ++}; +diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c +new file mode 100644 +index 0000000000..adef69d95c +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c +@@ -0,0 +1,484 @@ ++#include ++#include ++ ++const asn1_static_node pkix_asn1_tab[] = { ++ { "PKIX1", 536875024, NULL }, ++ { NULL, 1073741836, NULL }, ++ { "PrivateKeyUsagePeriod", 1610612741, NULL }, ++ { "notBefore", 1610637349, NULL }, ++ { NULL, 4104, "0"}, ++ { "notAfter", 536895525, NULL }, ++ { NULL, 4104, "1"}, ++ { "AuthorityKeyIdentifier", 1610612741, NULL }, ++ { "keyIdentifier", 1610637319, NULL }, ++ { NULL, 4104, "0"}, ++ { "authorityCertIssuer", 1610637314, "GeneralNames"}, ++ { NULL, 4104, "1"}, ++ { "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"}, ++ { NULL, 4104, "2"}, ++ { "SubjectKeyIdentifier", 1073741831, NULL }, ++ { "KeyUsage", 1073741830, NULL }, ++ { "DirectoryString", 1610612754, NULL }, ++ { "teletexString", 1612709918, NULL }, ++ { "MAX", 524298, "1"}, ++ { "printableString", 1612709919, NULL }, ++ { "MAX", 524298, "1"}, ++ { "universalString", 1612709920, NULL }, ++ { "MAX", 524298, "1"}, ++ { "utf8String", 1612709922, NULL }, ++ { "MAX", 524298, "1"}, ++ { "bmpString", 1612709921, NULL }, ++ { "MAX", 524298, "1"}, ++ { "ia5String", 538968093, NULL }, ++ { "MAX", 524298, "1"}, ++ { "SubjectAltName", 1073741826, "GeneralNames"}, ++ { "GeneralNames", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "GeneralName"}, ++ { "GeneralName", 1610612754, NULL }, ++ { "otherName", 1610620930, "AnotherName"}, ++ { NULL, 4104, "0"}, ++ { "rfc822Name", 1610620957, NULL }, ++ { NULL, 4104, "1"}, ++ { "dNSName", 1610620957, NULL }, ++ { NULL, 4104, "2"}, ++ { "x400Address", 1610620941, NULL }, ++ { NULL, 4104, "3"}, ++ { "directoryName", 1610620939, NULL }, ++ { NULL, 1073743880, "4"}, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "ediPartyName", 1610620941, NULL }, ++ { NULL, 4104, "5"}, ++ { "uniformResourceIdentifier", 1610620957, NULL }, ++ { NULL, 4104, "6"}, ++ { "iPAddress", 1610620935, NULL }, ++ { NULL, 4104, "7"}, ++ { "registeredID", 536879116, NULL }, ++ { NULL, 4104, "8"}, ++ { "AnotherName", 1610612741, NULL }, ++ { "type-id", 1073741836, NULL }, ++ { "value", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "type-id", 1, NULL }, ++ { "IssuerAltName", 1073741826, "GeneralNames"}, ++ { "BasicConstraints", 1610612741, NULL }, ++ { "cA", 1610645508, NULL }, ++ { NULL, 131081, NULL }, ++ { "pathLenConstraint", 537411587, NULL }, ++ { "0", 10, "MAX"}, ++ { "CRLDistributionPoints", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "DistributionPoint"}, ++ { "DistributionPoint", 1610612741, NULL }, ++ { "distributionPoint", 1610637314, "DistributionPointName"}, ++ { NULL, 2056, "0"}, ++ { "reasons", 1610637314, "ReasonFlags"}, ++ { NULL, 4104, "1"}, ++ { "cRLIssuer", 536895490, "GeneralNames"}, ++ { NULL, 4104, "2"}, ++ { "DistributionPointName", 1610612754, NULL }, ++ { "fullName", 1610620930, "GeneralNames"}, ++ { NULL, 4104, "0"}, ++ { "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"}, ++ { NULL, 4104, "1"}, ++ { "ReasonFlags", 1073741830, NULL }, ++ { "ExtKeyUsageSyntax", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 12, NULL }, ++ { "AuthorityInfoAccessSyntax", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "AccessDescription"}, ++ { "AccessDescription", 1610612741, NULL }, ++ { "accessMethod", 1073741836, NULL }, ++ { "accessLocation", 2, "GeneralName"}, ++ { "Attribute", 1610612741, NULL }, ++ { "type", 1073741836, NULL }, ++ { "values", 536870927, NULL }, ++ { NULL, 13, NULL }, ++ { "AttributeTypeAndValue", 1610612741, NULL }, ++ { "type", 1073741836, NULL }, ++ { "value", 13, NULL }, ++ { "Name", 1610612754, NULL }, ++ { "rdnSequence", 536870923, NULL }, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "DistinguishedName", 1610612747, NULL }, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "RelativeDistinguishedName", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "AttributeTypeAndValue"}, ++ { "Certificate", 1610612741, NULL }, ++ { "tbsCertificate", 1073741826, "TBSCertificate"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "TBSCertificate", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "serialNumber", 1073741826, "CertificateSerialNumber"}, ++ { "signature", 1073741826, "AlgorithmIdentifier"}, ++ { "issuer", 1073741826, "Name"}, ++ { "validity", 1073741826, "Validity"}, ++ { "subject", 1073741826, "Name"}, ++ { "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"}, ++ { "issuerUniqueID", 1610637314, "UniqueIdentifier"}, ++ { NULL, 4104, "1"}, ++ { "subjectUniqueID", 1610637314, "UniqueIdentifier"}, ++ { NULL, 4104, "2"}, ++ { "extensions", 536895490, "Extensions"}, ++ { NULL, 2056, "3"}, ++ { "CertificateSerialNumber", 1073741827, NULL }, ++ { "Validity", 1610612741, NULL }, ++ { "notBefore", 1073741826, "Time"}, ++ { "notAfter", 2, "Time"}, ++ { "Time", 1610612754, NULL }, ++ { "utcTime", 1073741860, NULL }, ++ { "generalTime", 37, NULL }, ++ { "UniqueIdentifier", 1073741830, NULL }, ++ { "SubjectPublicKeyInfo", 1610612741, NULL }, ++ { "algorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "subjectPublicKey", 6, NULL }, ++ { "Extensions", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Extension"}, ++ { "Extension", 1610612741, NULL }, ++ { "extnID", 1073741836, NULL }, ++ { "critical", 1610645508, NULL }, ++ { NULL, 131081, NULL }, ++ { "extnValue", 7, NULL }, ++ { "CertificateList", 1610612741, NULL }, ++ { "tbsCertList", 1073741826, "TBSCertList"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "TBSCertList", 1610612741, NULL }, ++ { "version", 1073758211, NULL }, ++ { "signature", 1073741826, "AlgorithmIdentifier"}, ++ { "issuer", 1073741826, "Name"}, ++ { "thisUpdate", 1073741826, "Time"}, ++ { "nextUpdate", 1073758210, "Time"}, ++ { "revokedCertificates", 1610629131, NULL }, ++ { NULL, 536870917, NULL }, ++ { "userCertificate", 1073741826, "CertificateSerialNumber"}, ++ { "revocationDate", 1073741826, "Time"}, ++ { "crlEntryExtensions", 16386, "Extensions"}, ++ { "crlExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "0"}, ++ { "AlgorithmIdentifier", 1610612741, NULL }, ++ { "algorithm", 1073741836, NULL }, ++ { "parameters", 541081613, NULL }, ++ { "algorithm", 1, NULL }, ++ { "Dss-Sig-Value", 1610612741, NULL }, ++ { "r", 1073741827, NULL }, ++ { "s", 3, NULL }, ++ { "Dss-Parms", 1610612741, NULL }, ++ { "p", 1073741827, NULL }, ++ { "q", 1073741827, NULL }, ++ { "g", 3, NULL }, ++ { "pkcs-7-ContentInfo", 1610612741, NULL }, ++ { "contentType", 1073741836, NULL }, ++ { "content", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "contentType", 1, NULL }, ++ { "pkcs-7-DigestInfo", 1610612741, NULL }, ++ { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "digest", 7, NULL }, ++ { "pkcs-7-SignedData", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"}, ++ { "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"}, ++ { "certificates", 1610637314, "pkcs-7-CertificateSet"}, ++ { NULL, 4104, "0"}, ++ { "crls", 1610637314, "pkcs-7-CertificateRevocationLists"}, ++ { NULL, 4104, "1"}, ++ { "signerInfos", 2, "pkcs-7-SignerInfos"}, ++ { "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL }, ++ { NULL, 2, "AlgorithmIdentifier"}, ++ { "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL }, ++ { "eContentType", 1073741836, NULL }, ++ { "eContent", 536895501, NULL }, ++ { NULL, 2056, "0"}, ++ { "pkcs-7-CertificateRevocationLists", 1610612751, NULL }, ++ { NULL, 13, NULL }, ++ { "pkcs-7-CertificateChoices", 1610612754, NULL }, ++ { "certificate", 13, NULL }, ++ { "pkcs-7-CertificateSet", 1610612751, NULL }, ++ { NULL, 2, "pkcs-7-CertificateChoices"}, ++ { "IssuerAndSerialNumber", 1610612741, NULL }, ++ { "issuer", 1073741826, "Name"}, ++ { "serialNumber", 2, "CertificateSerialNumber"}, ++ { "pkcs-7-SignerInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "sid", 1073741826, "SignerIdentifier"}, ++ { "digestAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signedAttrs", 1610637314, "SignedAttributes"}, ++ { NULL, 4104, "0"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741831, NULL }, ++ { "unsignedAttrs", 536895490, "SignedAttributes"}, ++ { NULL, 4104, "1"}, ++ { "SignedAttributes", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Attribute"}, ++ { "SignerIdentifier", 1610612754, NULL }, ++ { "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"}, ++ { "subjectKeyIdentifier", 536879111, NULL }, ++ { NULL, 4104, "0"}, ++ { "pkcs-7-SignerInfos", 1610612751, NULL }, ++ { NULL, 2, "pkcs-7-SignerInfo"}, ++ { "pkcs-10-CertificationRequestInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "subject", 1073741826, "Name"}, ++ { "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"}, ++ { "attributes", 536879106, "Attributes"}, ++ { NULL, 4104, "0"}, ++ { "Attributes", 1610612751, NULL }, ++ { NULL, 2, "Attribute"}, ++ { "pkcs-10-CertificationRequest", 1610612741, NULL }, ++ { "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 6, NULL }, ++ { "pkcs-9-at-challengePassword", 1879048204, NULL }, ++ { "iso", 1073741825, "1"}, ++ { "member-body", 1073741825, "2"}, ++ { "us", 1073741825, "840"}, ++ { "rsadsi", 1073741825, "113549"}, ++ { "pkcs", 1073741825, "1"}, ++ { NULL, 1073741825, "9"}, ++ { NULL, 1, "7"}, ++ { "pkcs-9-challengePassword", 1610612754, NULL }, ++ { "printableString", 1073741855, NULL }, ++ { "utf8String", 34, NULL }, ++ { "pkcs-9-localKeyId", 1073741831, NULL }, ++ { "pkcs-8-PrivateKeyInfo", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "privateKey", 1073741831, NULL }, ++ { "attributes", 536895490, "Attributes"}, ++ { NULL, 4104, "0"}, ++ { "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL }, ++ { "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "encryptedData", 2, "pkcs-8-EncryptedData"}, ++ { "pkcs-8-EncryptedData", 1073741831, NULL }, ++ { "pkcs-5-des-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "8"}, ++ { "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "8"}, ++ { "pkcs-5-aes128-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "pkcs-5-aes192-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "pkcs-5-aes256-CBC-params", 1612709895, NULL }, ++ { NULL, 1048586, "16"}, ++ { "Gost28147-89-Parameters", 1610612741, NULL }, ++ { "iv", 1073741831, NULL }, ++ { "encryptionParamSet", 12, NULL }, ++ { "pkcs-5-PBE-params", 1610612741, NULL }, ++ { "salt", 1073741831, NULL }, ++ { "iterationCount", 3, NULL }, ++ { "pkcs-5-PBES2-params", 1610612741, NULL }, ++ { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"}, ++ { "encryptionScheme", 2, "AlgorithmIdentifier"}, ++ { "pkcs-5-PBKDF2-params", 1610612741, NULL }, ++ { "salt", 1610612754, NULL }, ++ { "specified", 1073741831, NULL }, ++ { "otherSource", 2, "AlgorithmIdentifier"}, ++ { "iterationCount", 1611137027, NULL }, ++ { "1", 10, "MAX"}, ++ { "keyLength", 1611153411, NULL }, ++ { "1", 10, "MAX"}, ++ { "prf", 16386, "AlgorithmIdentifier"}, ++ { "pkcs-12-PFX", 1610612741, NULL }, ++ { "version", 1610874883, NULL }, ++ { "v3", 1, "3"}, ++ { "authSafe", 1073741826, "pkcs-7-ContentInfo"}, ++ { "macData", 16386, "pkcs-12-MacData"}, ++ { "pkcs-12-PbeParams", 1610612741, NULL }, ++ { "salt", 1073741831, NULL }, ++ { "iterations", 3, NULL }, ++ { "pkcs-12-MacData", 1610612741, NULL }, ++ { "mac", 1073741826, "pkcs-7-DigestInfo"}, ++ { "macSalt", 1073741831, NULL }, ++ { "iterations", 536903683, NULL }, ++ { NULL, 9, "1"}, ++ { "pkcs-12-AuthenticatedSafe", 1610612747, NULL }, ++ { NULL, 2, "pkcs-7-ContentInfo"}, ++ { "pkcs-12-SafeContents", 1610612747, NULL }, ++ { NULL, 2, "pkcs-12-SafeBag"}, ++ { "pkcs-12-SafeBag", 1610612741, NULL }, ++ { "bagId", 1073741836, NULL }, ++ { "bagValue", 1614815245, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "badId", 1, NULL }, ++ { "bagAttributes", 536887311, NULL }, ++ { NULL, 2, "Attribute"}, ++ { "pkcs-12-CertBag", 1610612741, NULL }, ++ { "certId", 1073741836, NULL }, ++ { "certValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "certId", 1, NULL }, ++ { "pkcs-12-CRLBag", 1610612741, NULL }, ++ { "crlId", 1073741836, NULL }, ++ { "crlValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "crlId", 1, NULL }, ++ { "pkcs-12-SecretBag", 1610612741, NULL }, ++ { "secretTypeId", 1073741836, NULL }, ++ { "secretValue", 541073421, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "secretTypeId", 1, NULL }, ++ { "pkcs-7-Data", 1073741831, NULL }, ++ { "pkcs-7-EncryptedData", 1610612741, NULL }, ++ { "version", 1073741827, NULL }, ++ { "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"}, ++ { "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"}, ++ { NULL, 4104, "1"}, ++ { "pkcs-7-EncryptedContentInfo", 1610612741, NULL }, ++ { "contentType", 1073741836, NULL }, ++ { "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"}, ++ { "encryptedContent", 536895495, NULL }, ++ { NULL, 4104, "0"}, ++ { "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"}, ++ { "pkcs-7-UnprotectedAttributes", 1612709903, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "Attribute"}, ++ { "ProxyCertInfo", 1610612741, NULL }, ++ { "pCPathLenConstraint", 1611153411, NULL }, ++ { "0", 10, "MAX"}, ++ { "proxyPolicy", 2, "ProxyPolicy"}, ++ { "ProxyPolicy", 1610612741, NULL }, ++ { "policyLanguage", 1073741836, NULL }, ++ { "policy", 16391, NULL }, ++ { "certificatePolicies", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "PolicyInformation"}, ++ { "PolicyInformation", 1610612741, NULL }, ++ { "policyIdentifier", 1073741836, NULL }, ++ { "policyQualifiers", 538984459, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "PolicyQualifierInfo"}, ++ { "PolicyQualifierInfo", 1610612741, NULL }, ++ { "policyQualifierId", 1073741836, NULL }, ++ { "qualifier", 541065229, NULL }, ++ { "policyQualifierId", 1, NULL }, ++ { "CPSuri", 1073741853, NULL }, ++ { "UserNotice", 1610612741, NULL }, ++ { "noticeRef", 1073758210, "NoticeReference"}, ++ { "explicitText", 16386, "DisplayText"}, ++ { "NoticeReference", 1610612741, NULL }, ++ { "organization", 1073741826, "DisplayText"}, ++ { "noticeNumbers", 536870923, NULL }, ++ { NULL, 3, NULL }, ++ { "DisplayText", 1610612754, NULL }, ++ { "ia5String", 1612709917, NULL }, ++ { "200", 524298, "1"}, ++ { "visibleString", 1612709923, NULL }, ++ { "200", 524298, "1"}, ++ { "bmpString", 1612709921, NULL }, ++ { "200", 524298, "1"}, ++ { "utf8String", 538968098, NULL }, ++ { "200", 524298, "1"}, ++ { "OCSPRequest", 1610612741, NULL }, ++ { "tbsRequest", 1073741826, "TBSRequest"}, ++ { "optionalSignature", 536895490, "Signature"}, ++ { NULL, 2056, "0"}, ++ { "TBSRequest", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "requestorName", 1610637314, "GeneralName"}, ++ { NULL, 2056, "1"}, ++ { "requestList", 1610612747, NULL }, ++ { NULL, 2, "Request"}, ++ { "requestExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "2"}, ++ { "Signature", 1610612741, NULL }, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741830, NULL }, ++ { "certs", 536895499, NULL }, ++ { NULL, 1073743880, "0"}, ++ { NULL, 2, "Certificate"}, ++ { "Request", 1610612741, NULL }, ++ { "reqCert", 1073741826, "CertID"}, ++ { "singleRequestExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "0"}, ++ { "CertID", 1610612741, NULL }, ++ { "hashAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "issuerNameHash", 1073741831, NULL }, ++ { "issuerKeyHash", 1073741831, NULL }, ++ { "serialNumber", 2, "CertificateSerialNumber"}, ++ { "OCSPResponse", 1610612741, NULL }, ++ { "responseStatus", 1073741826, "OCSPResponseStatus"}, ++ { "responseBytes", 536895490, "ResponseBytes"}, ++ { NULL, 2056, "0"}, ++ { "OCSPResponseStatus", 1610874901, NULL }, ++ { "successful", 1073741825, "0"}, ++ { "malformedRequest", 1073741825, "1"}, ++ { "internalError", 1073741825, "2"}, ++ { "tryLater", 1073741825, "3"}, ++ { "sigRequired", 1073741825, "5"}, ++ { "unauthorized", 1, "6"}, ++ { "ResponseBytes", 1610612741, NULL }, ++ { "responseType", 1073741836, NULL }, ++ { "response", 7, NULL }, ++ { "BasicOCSPResponse", 1610612741, NULL }, ++ { "tbsResponseData", 1073741826, "ResponseData"}, ++ { "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"}, ++ { "signature", 1073741830, NULL }, ++ { "certs", 536895499, NULL }, ++ { NULL, 1073743880, "0"}, ++ { NULL, 2, "Certificate"}, ++ { "ResponseData", 1610612741, NULL }, ++ { "version", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 2056, "0"}, ++ { "responderID", 1073741826, "ResponderID"}, ++ { "producedAt", 1073741861, NULL }, ++ { "responses", 1610612747, NULL }, ++ { NULL, 2, "SingleResponse"}, ++ { "responseExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "1"}, ++ { "ResponderID", 1610612754, NULL }, ++ { "byName", 1610620939, NULL }, ++ { NULL, 1073743880, "1"}, ++ { NULL, 2, "RelativeDistinguishedName"}, ++ { "byKey", 536879111, NULL }, ++ { NULL, 2056, "2"}, ++ { "SingleResponse", 1610612741, NULL }, ++ { "certID", 1073741826, "CertID"}, ++ { "certStatus", 1073741826, "CertStatus"}, ++ { "thisUpdate", 1073741861, NULL }, ++ { "nextUpdate", 1610637349, NULL }, ++ { NULL, 2056, "0"}, ++ { "singleExtensions", 536895490, "Extensions"}, ++ { NULL, 2056, "1"}, ++ { "CertStatus", 1610612754, NULL }, ++ { "good", 1610620948, NULL }, ++ { NULL, 4104, "0"}, ++ { "revoked", 1610620930, "RevokedInfo"}, ++ { NULL, 4104, "1"}, ++ { "unknown", 536879106, "UnknownInfo"}, ++ { NULL, 4104, "2"}, ++ { "RevokedInfo", 1610612741, NULL }, ++ { "revocationTime", 1073741861, NULL }, ++ { "revocationReason", 537157653, NULL }, ++ { NULL, 1073743880, "0"}, ++ { "unspecified", 1, "0"}, ++ { "UnknownInfo", 1073741844, NULL }, ++ { "NameConstraints", 1610612741, NULL }, ++ { "permittedSubtrees", 1610637314, "GeneralSubtrees"}, ++ { NULL, 4104, "0"}, ++ { "excludedSubtrees", 536895490, "GeneralSubtrees"}, ++ { NULL, 4104, "1"}, ++ { "GeneralSubtrees", 1612709899, NULL }, ++ { "MAX", 1074266122, "1"}, ++ { NULL, 2, "GeneralSubtree"}, ++ { "GeneralSubtree", 1610612741, NULL }, ++ { "base", 1073741826, "GeneralName"}, ++ { "minimum", 1610653699, NULL }, ++ { NULL, 1073741833, "0"}, ++ { NULL, 4104, "0"}, ++ { "maximum", 536895491, NULL }, ++ { NULL, 4104, "1"}, ++ { "TlsFeatures", 536870923, NULL }, ++ { NULL, 3, NULL }, ++ { NULL, 0, NULL } ++}; diff --git a/SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch b/SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch new file mode 100644 index 0000000..5a13d5b --- /dev/null +++ b/SOURCES/0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch @@ -0,0 +1,1528 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:33:46 +1000 +Subject: [PATCH] appended signatures: parse PKCS#7 signedData and X.509 + certificates + +This code allows us to parse: + + - PKCS#7 signedData messages. Only a single signerInfo is supported, + which is all that the Linux sign-file utility supports creating + out-of-the-box. Only RSA, SHA-256 and SHA-512 are supported. + Any certificate embedded in the PKCS#7 message will be ignored. + + - X.509 certificates: at least enough to verify the signatures on the + PKCS#7 messages. We expect that the certificates embedded in grub will + be leaf certificates, not CA certificates. The parser enforces this. + +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/asn1util.c | 102 +++ + grub-core/commands/appendedsig/pkcs7.c | 305 +++++++++ + grub-core/commands/appendedsig/x509.c | 958 +++++++++++++++++++++++++++ + grub-core/commands/appendedsig/appendedsig.h | 110 +++ + 4 files changed, 1475 insertions(+) + create mode 100644 grub-core/commands/appendedsig/asn1util.c + create mode 100644 grub-core/commands/appendedsig/pkcs7.c + create mode 100644 grub-core/commands/appendedsig/x509.c + create mode 100644 grub-core/commands/appendedsig/appendedsig.h + +diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c +new file mode 100644 +index 0000000000..eff095a9df +--- /dev/null ++++ b/grub-core/commands/appendedsig/asn1util.c +@@ -0,0 +1,102 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY; ++asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY; ++ ++extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[]; ++extern const ASN1_ARRAY_TYPE pkix_asn1_tab[]; ++ ++/* ++ * Read a value from an ASN1 node, allocating memory to store it. ++ * ++ * It will work for anything where the size libtasn1 returns is right: ++ * - Integers ++ * - Octet strings ++ * - DER encoding of other structures ++ * It will _not_ work for things where libtasn1 size requires adjustment: ++ * - Strings that require an extra NULL byte at the end ++ * - Bit strings because libtasn1 returns the length in bits, not bytes. ++ * ++ * If the function returns a non-NULL value, the caller must free it. ++ */ ++void * ++grub_asn1_allocate_and_read (asn1_node node, const char *name, ++ const char *friendly_name, int *content_size) ++{ ++ int result; ++ grub_uint8_t *tmpstr = NULL; ++ int tmpstr_size = 0; ++ ++ result = asn1_read_value (node, name, NULL, &tmpstr_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ _ ++ ("Reading size of %s did not return expected status: %s"), ++ friendly_name, asn1_strerror (result)); ++ grub_errno = GRUB_ERR_BAD_FILE_TYPE; ++ return NULL; ++ } ++ ++ tmpstr = grub_malloc (tmpstr_size); ++ if (tmpstr == NULL) ++ { ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ "Could not allocate memory to store %s", friendly_name); ++ grub_errno = GRUB_ERR_OUT_OF_MEMORY; ++ return NULL; ++ } ++ ++ result = asn1_read_value (node, name, tmpstr, &tmpstr_size); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_free (tmpstr); ++ grub_snprintf (grub_errmsg, sizeof (grub_errmsg), ++ "Error reading %s: %s", ++ friendly_name, asn1_strerror (result)); ++ grub_errno = GRUB_ERR_BAD_FILE_TYPE; ++ return NULL; ++ } ++ ++ *content_size = tmpstr_size; ++ ++ return tmpstr; ++} ++ ++int ++asn1_init (void) ++{ ++ int res; ++ res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); ++ if (res != ASN1_SUCCESS) ++ { ++ return res; ++ } ++ res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL); ++ return res; ++} +diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c +new file mode 100644 +index 0000000000..dc6afe203f +--- /dev/null ++++ b/grub-core/commands/appendedsig/pkcs7.c +@@ -0,0 +1,305 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include "appendedsig.h" ++#include ++#include ++#include ++ ++ ++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++/* ++ * RFC 5652 s 5.1 ++ */ ++const char *signedData_oid = "1.2.840.113549.1.7.2"; ++ ++/* ++ * RFC 4055 s 2.1 ++ */ ++const char *sha256_oid = "2.16.840.1.101.3.4.2.1"; ++const char *sha512_oid = "2.16.840.1.101.3.4.2.3"; ++ ++static grub_err_t ++process_content (grub_uint8_t * content, int size, ++ struct pkcs7_signedData *msg) ++{ ++ int res; ++ asn1_node signed_part; ++ grub_err_t err = GRUB_ERR_NONE; ++ char algo_oid[MAX_OID_LEN]; ++ int algo_oid_size = sizeof (algo_oid); ++ int algo_count; ++ char version; ++ int version_size = sizeof (version); ++ grub_uint8_t *result_buf; ++ int result_size = 0; ++ int crls_size = 0; ++ gcry_error_t gcry_err; ++ ++ res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", ++ &signed_part); ++ if (res != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 signed part."); ++ } ++ ++ res = asn1_der_decoding2 (&signed_part, content, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 signed data: %s", asn1_error); ++ goto cleanup_signed_part; ++ } ++ ++ /* SignedData ::= SEQUENCE { ++ * version CMSVersion, ++ * digestAlgorithms DigestAlgorithmIdentifiers, ++ * encapContentInfo EncapsulatedContentInfo, ++ * certificates [0] IMPLICIT CertificateSet OPTIONAL, ++ * crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, ++ * signerInfos SignerInfos } ++ */ ++ ++ /* version per the algo in 5.1, must be 1 */ ++ res = asn1_read_value (signed_part, "version", &version, &version_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading signedData version: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (version != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected signature version v%d, only v1 supported", ++ version); ++ goto cleanup_signed_part; ++ } ++ ++ /* ++ * digestAlgorithms DigestAlgorithmIdentifiers ++ * ++ * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier ++ * DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1) ++ * ++ * RFC 4055 s 2.1: ++ * sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL } ++ * sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL } ++ * ++ * We only support 1 element in the set, and we do not check parameters atm. ++ */ ++ res = ++ asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error counting number of digest algorithms: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (algo_count != 1) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only 1 digest algorithm is supported"); ++ goto cleanup_signed_part; ++ } ++ ++ res = ++ asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid, ++ &algo_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading digest algorithm: %s", ++ asn1_strerror (res)); ++ goto cleanup_signed_part; ++ } ++ ++ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0) ++ { ++ msg->hash = grub_crypto_lookup_md_by_name ("sha512"); ++ } ++ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0) ++ { ++ msg->hash = grub_crypto_lookup_md_by_name ("sha256"); ++ } ++ else ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only SHA-256 and SHA-512 hashes are supported, found OID %s", ++ algo_oid); ++ goto cleanup_signed_part; ++ } ++ ++ if (!msg->hash) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Hash algorithm for OID %s not loaded", algo_oid); ++ goto cleanup_signed_part; ++ } ++ ++ /* ++ * We ignore the certificates, but we don't permit CRLs. ++ * A CRL entry might be revoking the certificate we're using, and we have ++ * no way of dealing with that at the moment. ++ */ ++ res = asn1_read_value (signed_part, "crls", NULL, &crls_size); ++ if (res != ASN1_ELEMENT_NOT_FOUND) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "PKCS#7 messages with embedded CRLs are not supported"); ++ goto cleanup_signed_part; ++ } ++ ++ /* read the signature */ ++ result_buf = ++ grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature", ++ "signature data", &result_size); ++ if (!result_buf) ++ { ++ err = grub_errno; ++ goto cleanup_signed_part; ++ } ++ ++ gcry_err = ++ gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error loading signature into MPI structure: %d", ++ gcry_err); ++ goto cleanup_result; ++ } ++ ++cleanup_result: ++ grub_free (result_buf); ++cleanup_signed_part: ++ asn1_delete_structure (&signed_part); ++ ++ return err; ++} ++ ++grub_err_t ++parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, ++ struct pkcs7_signedData *msg) ++{ ++ int res; ++ asn1_node content_info; ++ grub_err_t err = GRUB_ERR_NONE; ++ char content_oid[MAX_OID_LEN]; ++ grub_uint8_t *content; ++ int content_size; ++ int content_oid_size = sizeof (content_oid); ++ int size; ++ ++ if (data_size > GRUB_INT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "Cannot parse a PKCS#7 message where data size > INT_MAX"); ++ size = (int) data_size; ++ ++ res = asn1_create_element (_gnutls_pkix_asn, ++ "PKIX1.pkcs-7-ContentInfo", &content_info); ++ if (res != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for PKCS#7 data: %s", ++ asn1_strerror (res)); ++ } ++ ++ res = asn1_der_decoding2 (&content_info, sigbuf, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error decoding PKCS#7 message DER: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * ContentInfo ::= SEQUENCE { ++ * contentType ContentType, ++ * content [0] EXPLICIT ANY DEFINED BY contentType } ++ * ++ * ContentType ::= OBJECT IDENTIFIER ++ */ ++ res = ++ asn1_read_value (content_info, "contentType", content_oid, ++ &content_oid_size); ++ if (res != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Error reading PKCS#7 content type: %s", ++ asn1_strerror (res)); ++ goto cleanup; ++ } ++ ++ /* OID for SignedData defined in 5.1 */ ++ if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_SIGNATURE, ++ "Unexpected content type in PKCS#7 message: OID %s", ++ content_oid); ++ goto cleanup; ++ } ++ ++ content = ++ grub_asn1_allocate_and_read (content_info, "content", ++ "PKCS#7 message content", &content_size); ++ if (!content) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ err = process_content (content, content_size, msg); ++ grub_free (content); ++ ++cleanup: ++ asn1_delete_structure (&content_info); ++ return err; ++} ++ ++/* ++ * Release all the storage associated with the PKCS#7 message. ++ * If the caller dynamically allocated the message, it must free it. ++ */ ++void ++pkcs7_signedData_release (struct pkcs7_signedData *msg) ++{ ++ gcry_mpi_release (msg->sig_mpi); ++} +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +new file mode 100644 +index 0000000000..2b38b3670a +--- /dev/null ++++ b/grub-core/commands/appendedsig/x509.c +@@ -0,0 +1,958 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; ++ ++/* ++ * RFC 3279 2.3.1 RSA Keys ++ */ ++const char *rsaEncryption_oid = "1.2.840.113549.1.1.1"; ++ ++/* ++ * RFC 5280 Appendix A ++ */ ++const char *commonName_oid = "2.5.4.3"; ++ ++/* ++ * RFC 5280 4.2.1.3 Key Usage ++ */ ++const char *keyUsage_oid = "2.5.29.15"; ++ ++/* ++ * RFC 5280 4.2.1.9 Basic Constraints ++ */ ++const char *basicConstraints_oid = "2.5.29.19"; ++ ++/* ++ * RFC 3279 2.3.1 ++ * ++ * The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey: ++ * ++ * RSAPublicKey ::= SEQUENCE { ++ * modulus INTEGER, -- n ++ * publicExponent INTEGER } -- e ++ * ++ * where modulus is the modulus n, and publicExponent is the public ++ * exponent e. ++ */ ++static grub_err_t ++grub_parse_rsa_pubkey (grub_uint8_t * der, int dersize, ++ struct x509_certificate *certificate) ++{ ++ int result; ++ asn1_node spk = ASN1_TYPE_EMPTY; ++ grub_uint8_t *m_data, *e_data; ++ int m_size, e_size; ++ grub_err_t err = GRUB_ERR_NONE; ++ gcry_error_t gcry_err; ++ ++ result = ++ asn1_create_element (_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot create storage for public key ASN.1 data"); ++ } ++ ++ result = asn1_der_decoding2 (&spk, der, &dersize, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Cannot decode certificate public key DER: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ m_data = ++ grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size); ++ if (!m_data) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ e_data = ++ grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent", ++ &e_size); ++ if (!e_data) ++ { ++ err = grub_errno; ++ goto cleanup_m_data; ++ } ++ ++ /* ++ * convert m, e to mpi ++ * ++ * nscanned is not set for FMT_USG, it's only set for FMT_PGP, ++ * so we can't verify it ++ */ ++ gcry_err = ++ gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA modulus into MPI structure: %d", ++ gcry_err); ++ goto cleanup_e_data; ++ } ++ ++ gcry_err = ++ gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, ++ NULL); ++ if (gcry_err != GPG_ERR_NO_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error loading RSA exponent into MPI structure: %d", ++ gcry_err); ++ goto cleanup_m_mpi; ++ } ++ ++ grub_free (e_data); ++ grub_free (m_data); ++ asn1_delete_structure (&spk); ++ return GRUB_ERR_NONE; ++ ++cleanup_m_mpi: ++ gcry_mpi_release (certificate->mpis[0]); ++cleanup_e_data: ++ grub_free (e_data); ++cleanup_m_data: ++ grub_free (m_data); ++cleanup: ++ asn1_delete_structure (&spk); ++ return err; ++} ++ ++ ++/* ++ * RFC 5280: ++ * SubjectPublicKeyInfo ::= SEQUENCE { ++ * algorithm AlgorithmIdentifier, ++ * subjectPublicKey BIT STRING } ++ * ++ * AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we ++ * only support RSA Encryption. ++ */ ++ ++static grub_err_t ++grub_x509_read_subject_public_key (asn1_node asn, ++ struct x509_certificate *results) ++{ ++ int result; ++ grub_err_t err; ++ const char *algo_name = ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm"; ++ const char *params_name = ++ "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters"; ++ const char *pk_name = ++ "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey"; ++ char algo_oid[MAX_OID_LEN]; ++ int algo_size = sizeof (algo_oid); ++ char params_value[2]; ++ int params_size = sizeof (params_value); ++ grub_uint8_t *key_data = NULL; ++ int key_size = 0; ++ unsigned int key_type; ++ ++ /* algorithm: see notes for rsaEncryption_oid */ ++ result = asn1_read_value (asn, algo_name, algo_oid, &algo_size); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading x509 public key algorithm: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) ++ != 0) ++ { ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Unsupported x509 public key algorithm: %s", ++ algo_oid); ++ } ++ ++ /* ++ * RFC 3279 2.3.1 ++ * The rsaEncryption OID is intended to be used in the algorithm field ++ * of a value of type AlgorithmIdentifier. The parameters field MUST ++ * have ASN.1 type NULL for this algorithm identifier. ++ */ ++ result = asn1_read_value (asn, params_name, params_value, ¶ms_size); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading x509 public key parameters: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (params_value[0] != ASN1_TAG_NULL) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 public key parameters: expected NULL"); ++ } ++ ++ /* ++ * RFC 3279 2.3.1: The DER encoded RSAPublicKey is the value of the BIT ++ * STRING subjectPublicKey. ++ */ ++ result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type); ++ if (result != ASN1_MEM_ERROR) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of x509 public key: %s", ++ asn1_strerror (result)); ++ } ++ if (key_type != ASN1_ETYPE_BIT_STRING) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected ASN.1 type when reading x509 public key: %x", ++ key_type); ++ } ++ ++ /* length is in bits */ ++ key_size = (key_size + 7) / 8; ++ ++ key_data = grub_malloc (key_size); ++ if (!key_data) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Out of memory for x509 public key"); ++ } ++ ++ result = asn1_read_value (asn, pk_name, key_data, &key_size); ++ if (result != ASN1_SUCCESS) ++ { ++ grub_free (key_data); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading public key data"); ++ } ++ key_size = (key_size + 7) / 8; ++ ++ err = grub_parse_rsa_pubkey (key_data, key_size, results); ++ grub_free (key_data); ++ ++ return err; ++} ++ ++/* Decode a string as defined in Appendix A */ ++static grub_err_t ++decode_string (char *der, int der_size, char **string, ++ grub_size_t * string_size) ++{ ++ asn1_node strasn; ++ int result; ++ char *choice; ++ int choice_size = 0; ++ int tmp_size = 0; ++ grub_err_t err = GRUB_ERR_NONE; ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); ++ } ++ ++ result = asn1_der_decoding2 (&strasn, der, &der_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for DirectoryString: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ choice = ++ grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", ++ &choice_size); ++ if (!choice) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ if (grub_strncmp ("utf8String", choice, choice_size)) ++ { ++ err = ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Only UTF-8 DirectoryStrings are supported, got %s", ++ choice); ++ goto cleanup_choice; ++ } ++ ++ result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size); ++ if (result != ASN1_MEM_ERROR) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading size of UTF-8 string: %s", ++ asn1_strerror (result)); ++ goto cleanup_choice; ++ } ++ ++ /* read size does not include trailing null */ ++ tmp_size++; ++ ++ *string = grub_malloc (tmp_size); ++ if (!*string) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Cannot allocate memory for DirectoryString contents"); ++ goto cleanup_choice; ++ } ++ ++ result = asn1_read_value (strasn, "utf8String", *string, &tmp_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading out UTF-8 string in DirectoryString: %s", ++ asn1_strerror (result)); ++ grub_free (*string); ++ goto cleanup_choice; ++ } ++ *string_size = tmp_size + 1; ++ (*string)[tmp_size] = '\0'; ++ ++cleanup_choice: ++ grub_free (choice); ++cleanup: ++ asn1_delete_structure (&strasn); ++ return err; ++} ++ ++/* ++ * TBSCertificate ::= SEQUENCE { ++ * version [0] EXPLICIT Version DEFAULT v1, ++ * ... ++ * ++ * Version ::= INTEGER { v1(0), v2(1), v3(2) } ++ */ ++static grub_err_t ++check_version (asn1_node certificate) ++{ ++ int rc; ++ const char *name = "tbsCertificate.version"; ++ grub_uint8_t version; ++ int len = 1; ++ ++ rc = asn1_read_value (certificate, name, &version, &len); ++ ++ /* require version 3 */ ++ if (rc != ASN1_SUCCESS || len != 1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading certificate version"); ++ ++ if (version != 0x02) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Invalid x509 certificate version, expected v3 (0x02), got 0x%02x", ++ version); ++ ++ return GRUB_ERR_NONE; ++} ++ ++/* ++ * This is an X.501 Name, which is complex. ++ * ++ * For simplicity, we extract only the CN. ++ */ ++static grub_err_t ++read_name (asn1_node asn, const char *name_path, char **name, ++ grub_size_t * name_size) ++{ ++ int seq_components, set_components; ++ int result; ++ int i, j; ++ char *top_path, *set_path, *type_path, *val_path; ++ char type[MAX_OID_LEN]; ++ int type_len = sizeof (type); ++ int string_size = 0; ++ char *string_der; ++ grub_err_t err; ++ ++ *name = NULL; ++ ++ top_path = grub_xasprintf ("%s.rdnSequence", name_path); ++ if (!top_path) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name parsing path", ++ name_path); ++ ++ result = asn1_number_of_elements (asn, top_path, &seq_components); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting name components: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ for (i = 1; i <= seq_components; i++) ++ { ++ set_path = grub_xasprintf ("%s.?%d", top_path, i); ++ if (!set_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name set parsing path", ++ name_path); ++ goto cleanup_set; ++ } ++ /* this brings us, hopefully, to a set */ ++ result = asn1_number_of_elements (asn, set_path, &set_components); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting name sub-components components (element %d): %s", ++ i, asn1_strerror (result)); ++ goto cleanup_set; ++ } ++ for (j = 1; j <= set_components; j++) ++ { ++ type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j); ++ if (!type_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name component type path", ++ name_path); ++ goto cleanup_set; ++ } ++ type_len = sizeof (type); ++ result = asn1_read_value (asn, type_path, type, &type_len); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading %s name component type: %s", ++ name_path, asn1_strerror (result)); ++ goto cleanup_type; ++ } ++ ++ if (grub_strncmp (type, commonName_oid, type_len) != 0) ++ { ++ grub_free (type_path); ++ continue; ++ } ++ ++ val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j); ++ if (!val_path) ++ { ++ err = ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not allocate memory for %s name component value path", ++ name_path); ++ goto cleanup_set; ++ } ++ ++ string_der = ++ grub_asn1_allocate_and_read (asn, val_path, name_path, ++ &string_size); ++ if (!string_der) ++ { ++ err = grub_errno; ++ goto cleanup_val_path; ++ } ++ ++ err = decode_string (string_der, string_size, name, name_size); ++ if (err) ++ goto cleanup_string; ++ ++ grub_free (string_der); ++ grub_free (type_path); ++ grub_free (val_path); ++ break; ++ } ++ grub_free (set_path); ++ ++ if (*name) ++ break; ++ } ++ ++ return GRUB_ERR_NONE; ++ ++cleanup_string: ++ grub_free (string_der); ++cleanup_val_path: ++ grub_free (val_path); ++cleanup_type: ++ grub_free (type_path); ++cleanup_set: ++ grub_free (set_path); ++cleanup: ++ grub_free (top_path); ++ return err; ++} ++ ++/* ++ * details here ++ */ ++static grub_err_t ++verify_key_usage (grub_uint8_t * value, int value_size) ++{ ++ asn1_node usageasn; ++ int result; ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_uint8_t usage = 0xff; ++ int usage_size = 1; ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for key usage"); ++ } ++ ++ result = asn1_der_decoding2 (&usageasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Key Usage: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (usageasn, "", &usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Key Usage value: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ /* Only the first bit is permitted to be set */ ++ if (usage != 0x80) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected Key Usage value: %x", ++ usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&usageasn); ++ return err; ++} ++ ++/* ++ * BasicConstraints ::= SEQUENCE { ++ * cA BOOLEAN DEFAULT FALSE, ++ * pathLenConstraint INTEGER (0..MAX) OPTIONAL } ++ */ ++static grub_err_t ++verify_basic_constraints (grub_uint8_t * value, int value_size) ++{ ++ asn1_node basicasn; ++ int result; ++ grub_err_t err = GRUB_ERR_NONE; ++ char cA[6]; /* FALSE or TRUE */ ++ int cA_size = sizeof (cA); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.BasicConstraints", ++ &basicasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Basic Constraints"); ++ } ++ ++ result = asn1_der_decoding2 (&basicasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Basic Constraints: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (basicasn, "cA", cA, &cA_size); ++ if (result == ASN1_ELEMENT_NOT_FOUND) ++ { ++ /* Not present, default is False, so this is OK */ ++ err = GRUB_ERR_NONE; ++ goto cleanup; ++ } ++ else if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Basic Constraints cA value: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ /* The certificate must not be a CA certificate */ ++ if (grub_strncmp ("FALSE", cA, cA_size) != 0) ++ { ++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Unexpected CA value: %s", ++ cA); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&basicasn); ++ return err; ++} ++ ++ ++/* ++ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension ++ * ++ * Extension ::= SEQUENCE { ++ * extnID OBJECT IDENTIFIER, ++ * critical BOOLEAN DEFAULT FALSE, ++ * extnValue OCTET STRING ++ * -- contains the DER encoding of an ASN.1 value ++ * -- corresponding to the extension type identified ++ * -- by extnID ++ * } ++ * ++ * We require that a certificate: ++ * - contain the Digital Signature usage only ++ * - not be a CA ++ * - MUST not contain any other critical extensions (RFC 5280 s 4.2) ++ */ ++static grub_err_t ++verify_extensions (asn1_node cert) ++{ ++ int result; ++ int ext, num_extensions = 0; ++ int usage_present = 0, constraints_present = 0; ++ char *oid_path, *critical_path, *value_path; ++ char extnID[MAX_OID_LEN]; ++ int extnID_size; ++ grub_err_t err; ++ char critical[6]; /* we get either "TRUE" or "FALSE" */ ++ int critical_size; ++ grub_uint8_t *value; ++ int value_size; ++ ++ result = ++ asn1_number_of_elements (cert, "tbsCertificate.extensions", ++ &num_extensions); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of extensions: %s", ++ asn1_strerror (result)); ++ } ++ ++ if (num_extensions < 2) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Insufficient number of extensions for certificate, need at least 2, got %d", ++ num_extensions); ++ } ++ ++ for (ext = 1; ext <= num_extensions; ext++) ++ { ++ oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext); ++ ++ extnID_size = sizeof (extnID); ++ result = asn1_read_value (cert, oid_path, extnID, &extnID_size); ++ if (result != GRUB_ERR_NONE) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading extension OID: %s", ++ asn1_strerror (result)); ++ goto cleanup_oid_path; ++ } ++ ++ critical_path = ++ grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext); ++ critical_size = sizeof (critical); ++ result = ++ asn1_read_value (cert, critical_path, critical, &critical_size); ++ if (result == ASN1_ELEMENT_NOT_FOUND) ++ { ++ critical[0] = '\0'; ++ } ++ else if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading extension criticality: %s", ++ asn1_strerror (result)); ++ goto cleanup_critical_path; ++ } ++ ++ value_path = ++ grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext); ++ value = ++ grub_asn1_allocate_and_read (cert, value_path, ++ "certificate extension value", ++ &value_size); ++ if (!value) ++ { ++ err = grub_errno; ++ goto cleanup_value_path; ++ } ++ ++ /* ++ * Now we must see if we recognise the OID. ++ * If we have an unrecognised critical extension we MUST bail. ++ */ ++ if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ usage_present++; ++ } ++ else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_basic_constraints (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ constraints_present++; ++ } ++ else if (grub_strncmp ("TRUE", critical, critical_size) == 0) ++ { ++ /* ++ * per the RFC, we must not process a certificate with ++ * a critical extension we do not understand. ++ */ ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unhandled critical x509 extension with OID %s", ++ extnID); ++ goto cleanup_value; ++ } ++ ++ grub_free (value); ++ grub_free (value_path); ++ grub_free (critical_path); ++ grub_free (oid_path); ++ } ++ ++ if (usage_present != 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Key Usage extensions - expected 1, got %d", ++ usage_present); ++ } ++ if (constraints_present != 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of basic constraints extensions - expected 1, got %d", ++ constraints_present); ++ } ++ return GRUB_ERR_NONE; ++ ++cleanup_value: ++ grub_free (value); ++cleanup_value_path: ++ grub_free (value_path); ++cleanup_critical_path: ++ grub_free (critical_path); ++cleanup_oid_path: ++ grub_free (oid_path); ++ return err; ++} ++ ++/* ++ * Parse a certificate whose DER-encoded form is in @data, of size @data_size. ++ * Return the results in @results, which must point to an allocated x509 certificate. ++ */ ++grub_err_t ++certificate_import (void *data, grub_size_t data_size, ++ struct x509_certificate *results) ++{ ++ int result = 0; ++ asn1_node cert; ++ grub_err_t err; ++ int size; ++ int tmp_size; ++ ++ if (data_size > GRUB_INT_MAX) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "Cannot parse a certificate where data size > INT_MAX"); ++ size = (int) data_size; ++ ++ result = asn1_create_element (_gnutls_pkix_asn, "PKIX1.Certificate", &cert); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for certificate: %s", ++ asn1_strerror (result)); ++ } ++ ++ result = asn1_der_decoding2 (&cert, data, &size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Could not parse DER for certificate: %s", asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * version [0] EXPLICIT Version DEFAULT v1 ++ */ ++ err = check_version (cert); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup; ++ } ++ ++ /* ++ * serialNumber CertificateSerialNumber, ++ * ++ * CertificateSerialNumber ::= INTEGER ++ */ ++ results->serial = ++ grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber", ++ "certificate serial number", &tmp_size); ++ if (!results->serial) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ /* ++ * It's safe to cast the signed int to an unsigned here, we know ++ * length is non-negative ++ */ ++ results->serial_len = tmp_size; ++ ++ /* ++ * signature AlgorithmIdentifier, ++ * ++ * We don't load the signature or issuer at the moment, ++ * as we don't attempt x509 verification. ++ */ ++ ++ /* ++ * issuer Name, ++ * ++ * The RFC only requires the serial number to be unique within ++ * issuers, so to avoid ambiguity we _technically_ ought to make ++ * this available. ++ */ ++ ++ /* ++ * validity Validity, ++ * ++ * Validity ::= SEQUENCE { ++ * notBefore Time, ++ * notAfter Time } ++ * ++ * We can't validate this reasonably, we have no true time source on several ++ * platforms. For now we do not parse them. ++ */ ++ ++ /* ++ * subject Name, ++ * ++ * This is an X501 name, we parse out just the CN. ++ */ ++ err = ++ read_name (cert, "tbsCertificate.subject", &results->subject, ++ &results->subject_len); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_serial; ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * ... ++ * subjectPublicKeyInfo SubjectPublicKeyInfo, ++ * ... ++ */ ++ err = grub_x509_read_subject_public_key (cert, results); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_name; ++ ++ /* ++ * TBSCertificate ::= SEQUENCE { ++ * ... ++ * extensions [3] EXPLICIT Extensions OPTIONAL ++ * -- If present, version MUST be v3 ++ * } ++ */ ++ ++ err = verify_extensions (cert); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_name; ++ ++ ++ /* ++ * We do not read or check the signature on the certificate: ++ * as discussed we do not try to validate the certificate but trust ++ * it implictly. ++ */ ++ ++ asn1_delete_structure (&cert); ++ return GRUB_ERR_NONE; ++ ++ ++cleanup_name: ++ grub_free (results->subject); ++cleanup_serial: ++ grub_free (results->serial); ++cleanup: ++ asn1_delete_structure (&cert); ++ return err; ++} ++ ++/* ++ * Release all the storage associated with the x509 certificate. ++ * If the caller dynamically allocated the certificate, it must free it. ++ * The caller is also responsible for maintenance of the linked list. ++ */ ++void ++certificate_release (struct x509_certificate *cert) ++{ ++ grub_free (cert->subject); ++ grub_free (cert->serial); ++ gcry_mpi_release (cert->mpis[0]); ++ gcry_mpi_release (cert->mpis[1]); ++} +diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h +new file mode 100644 +index 0000000000..9792ef3901 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.h +@@ -0,0 +1,110 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++extern asn1_node _gnutls_gnutls_asn; ++extern asn1_node _gnutls_pkix_asn; ++ ++#define MAX_OID_LEN 32 ++ ++/* ++ * One or more x509 certificates. ++ * ++ * We do limited parsing: extracting only the serial, CN and RSA public key. ++ */ ++struct x509_certificate ++{ ++ struct x509_certificate *next; ++ ++ grub_uint8_t *serial; ++ grub_size_t serial_len; ++ ++ char *subject; ++ grub_size_t subject_len; ++ ++ /* We only support RSA public keys. This encodes [modulus, publicExponent] */ ++ gcry_mpi_t mpis[2]; ++}; ++ ++/* ++ * A PKCS#7 signedData message. ++ * ++ * We make no attempt to match intelligently, so we don't save any info about ++ * the signer. We also support only 1 signerInfo, so we only store a single ++ * MPI for the signature. ++ */ ++struct pkcs7_signedData ++{ ++ const gcry_md_spec_t *hash; ++ gcry_mpi_t sig_mpi; ++}; ++ ++ ++/* Do libtasn1 init */ ++int asn1_init (void); ++ ++/* ++ * Import a DER-encoded certificate at 'data', of size 'size'. ++ * ++ * Place the results into 'results', which must be already allocated. ++ */ ++grub_err_t ++certificate_import (void *data, grub_size_t size, ++ struct x509_certificate *results); ++ ++/* ++ * Release all the storage associated with the x509 certificate. ++ * If the caller dynamically allocated the certificate, it must free it. ++ * The caller is also responsible for maintenance of the linked list. ++ */ ++void certificate_release (struct x509_certificate *cert); ++ ++/* ++ * Parse a PKCS#7 message, which must be a signedData message. ++ * ++ * The message must be in 'sigbuf' and of size 'data_size'. The result is ++ * placed in 'msg', which must already be allocated. ++ */ ++grub_err_t ++parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size, ++ struct pkcs7_signedData *msg); ++ ++/* ++ * Release all the storage associated with the PKCS#7 message. ++ * If the caller dynamically allocated the message, it must free it. ++ */ ++void pkcs7_signedData_release (struct pkcs7_signedData *msg); ++ ++/* ++ * Read a value from an ASN1 node, allocating memory to store it. ++ * ++ * It will work for anything where the size libtasn1 returns is right: ++ * - Integers ++ * - Octet strings ++ * - DER encoding of other structures ++ * It will _not_ work for things where libtasn1 size requires adjustment: ++ * - Strings that require an extra NULL byte at the end ++ * - Bit strings because libtasn1 returns the length in bits, not bytes. ++ * ++ * If the function returns a non-NULL value, the caller must free it. ++ */ ++void *grub_asn1_allocate_and_read (asn1_node node, const char *name, ++ const char *friendly_name, ++ int *content_size); diff --git a/SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch b/SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch new file mode 100644 index 0000000..9e90d3b --- /dev/null +++ b/SOURCES/0170-appended-signatures-support-verifying-appended-signa.patch @@ -0,0 +1,718 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:35:43 +1000 +Subject: [PATCH] appended signatures: support verifying appended signatures + +Building on the parsers and the ability to embed x509 certificates, as +well as the existing gcrypt functionality, add a module for verifying +appended signatures. + +This includes a verifier that requires that Linux kernels and grub modules +have appended signatures, and commands to manage the list of trusted +certificates for verification. + +Verification must be enabled by setting check_appended_signatures. If +GRUB is locked down when the module is loaded, verification will be +enabled and locked automatically. + +As with the PGP verifier, it is not a complete secure-boot solution: +other mechanisms, such as a password or lockdown, must be used to ensure +that a user cannot drop to the grub shell and disable verification. + +Signed-off-by: Daniel Axtens +[pjones: fix missing format specifier] +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 12 + + grub-core/commands/appendedsig/appendedsig.c | 645 +++++++++++++++++++++++++++ + include/grub/file.h | 2 + + 3 files changed, 659 insertions(+) + create mode 100644 grub-core/commands/appendedsig/appendedsig.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index a32e6ada59..6404384d90 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -980,6 +980,18 @@ module = { + cppflags = '-I$(srcdir)/lib/posix_wrap'; + }; + ++module = { ++ name = appendedsig; ++ common = commands/appendedsig/appendedsig.c; ++ common = commands/appendedsig/x509.c; ++ common = commands/appendedsig/pkcs7.c; ++ common = commands/appendedsig/asn1util.c; ++ common = commands/appendedsig/gnutls_asn1_tab.c; ++ common = commands/appendedsig/pkix_asn1_tab.c; ++ cflags = '$(CFLAGS_POSIX)'; ++ cppflags = '-I$(srcdir)/lib/posix_wrap'; ++}; ++ + module = { + name = hdparm; + common = commands/hdparm.c; +diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c +new file mode 100644 +index 0000000000..bf8b18b620 +--- /dev/null ++++ b/grub-core/commands/appendedsig/appendedsig.c +@@ -0,0 +1,645 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020-2021 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appendedsig.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++const char magic[] = "~Module signature appended~\n"; ++ ++/* ++ * This structure is extracted from scripts/sign-file.c in the linux kernel ++ * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible. ++ */ ++struct module_signature ++{ ++ grub_uint8_t algo; /* Public-key crypto algorithm [0] */ ++ grub_uint8_t hash; /* Digest algorithm [0] */ ++ grub_uint8_t id_type; /* Key identifier type [PKEY_ID_PKCS7] */ ++ grub_uint8_t signer_len; /* Length of signer's name [0] */ ++ grub_uint8_t key_id_len; /* Length of key identifier [0] */ ++ grub_uint8_t __pad[3]; ++ grub_uint32_t sig_len; /* Length of signature data */ ++} GRUB_PACKED; ++ ++ ++/* This represents an entire, parsed, appended signature */ ++struct grub_appended_signature ++{ ++ grub_size_t signature_len; /* Length of PKCS#7 data + ++ * metadata + magic */ ++ ++ struct module_signature sig_metadata; /* Module signature metadata */ ++ struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */ ++}; ++ ++/* Trusted certificates for verifying appended signatures */ ++struct x509_certificate *grub_trusted_key; ++ ++/* ++ * Force gcry_rsa to be a module dependency. ++ * ++ * If we use grub_crypto_pk_rsa, then then the gcry_rsa module won't be built ++ * in if you add 'appendedsig' to grub-install --modules. You would need to ++ * add 'gcry_rsa' too. That's confusing and seems suboptimal, especially when ++ * we only support RSA. ++ * ++ * Dynamic loading also causes some concerns. We can't load gcry_rsa from the ++ * the filesystem after we install the verifier - we won't be able to verify ++ * it without having it already present. We also shouldn't load it before we ++ * install the verifier, because that would mean it wouldn't be verified - an ++ * attacker could insert any code they wanted into the module. ++ * ++ * So instead, reference the internal symbol from gcry_rsa. That creates a ++ * direct dependency on gcry_rsa, so it will be built in when this module ++ * is built in. Being built in (assuming the core image is itself signed!) ++ * also resolves our concerns about loading from the filesystem. ++ */ ++extern gcry_pk_spec_t _gcry_pubkey_spec_rsa; ++ ++static int check_sigs = 0; ++ ++static const char * ++grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)), ++ const char *val __attribute__ ((unused))) ++{ ++ if (check_sigs == 2) ++ return "forced"; ++ else if (check_sigs == 1) ++ return "enforce"; ++ else ++ return "no"; ++} ++ ++static char * ++grub_env_write_sec (struct grub_env_var *var __attribute__((unused)), ++ const char *val) ++{ ++ /* Do not allow the value to be changed if set to forced */ ++ if (check_sigs == 2) ++ return grub_strdup ("forced"); ++ ++ if ((*val == '2') || (*val == 'f')) ++ check_sigs = 2; ++ else if ((*val == '1') || (*val == 'e')) ++ check_sigs = 1; ++ else if ((*val == '0') || (*val == 'n')) ++ check_sigs = 0; ++ ++ return grub_strdup (grub_env_read_sec (NULL, NULL)); ++} ++ ++static grub_err_t ++read_cert_from_file (grub_file_t f, struct x509_certificate *certificate) ++{ ++ grub_err_t err; ++ grub_uint8_t *buf = NULL; ++ grub_ssize_t read_size; ++ grub_off_t total_read_size = 0; ++ grub_off_t file_size = grub_file_size (f); ++ ++ ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot parse a certificate file of unknown size")); ++ ++ buf = grub_zalloc (file_size); ++ if (!buf) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate buffer for certificate file contents")); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (f, &buf[total_read_size], ++ file_size - total_read_size); ++ if (read_size < 0) ++ { ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Error reading certificate file")); ++ goto cleanup_buf; ++ } ++ total_read_size += read_size; ++ } ++ ++ err = certificate_import (buf, total_read_size, certificate); ++ if (err != GRUB_ERR_NONE) ++ goto cleanup_buf; ++ ++ return GRUB_ERR_NONE; ++ ++cleanup_buf: ++ grub_free (buf); ++ return err; ++} ++ ++static grub_err_t ++extract_appended_signature (grub_uint8_t * buf, grub_size_t bufsize, ++ struct grub_appended_signature *sig) ++{ ++ grub_err_t err; ++ grub_size_t pkcs7_size; ++ grub_size_t remaining_len; ++ grub_uint8_t *appsigdata = buf + bufsize - grub_strlen (magic); ++ ++ if (bufsize < grub_strlen (magic)) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for signature magic")); ++ ++ if (grub_memcmp (appsigdata, (grub_uint8_t *) magic, grub_strlen (magic))) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Missing or invalid signature magic")); ++ ++ remaining_len = bufsize - grub_strlen (magic); ++ ++ if (remaining_len < sizeof (struct module_signature)) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for signature metadata")); ++ ++ appsigdata -= sizeof (struct module_signature); ++ ++ /* extract the metadata */ ++ grub_memcpy (&(sig->sig_metadata), appsigdata, ++ sizeof (struct module_signature)); ++ ++ remaining_len -= sizeof (struct module_signature); ++ ++ if (sig->sig_metadata.id_type != 2) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("Wrong signature type")); ++ ++#ifdef GRUB_TARGET_WORDS_BIGENDIAN ++ pkcs7_size = sig->sig_metadata.sig_len; ++#else ++ pkcs7_size = __builtin_bswap32 (sig->sig_metadata.sig_len); ++#endif ++ ++ if (pkcs7_size > remaining_len) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("File too short for PKCS#7 message")); ++ ++ grub_dprintf ("appendedsig", "sig len %" PRIuGRUB_SIZE "\n", pkcs7_size); ++ ++ sig->signature_len = ++ grub_strlen (magic) + sizeof (struct module_signature) + pkcs7_size; ++ ++ /* rewind pointer and parse pkcs7 data */ ++ appsigdata -= pkcs7_size; ++ ++ err = parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_verify_appended_signature (grub_uint8_t * buf, grub_size_t bufsize) ++{ ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_size_t datasize; ++ void *context; ++ unsigned char *hash; ++ gcry_mpi_t hashmpi; ++ gcry_err_code_t rc; ++ struct x509_certificate *pk; ++ struct grub_appended_signature sig; ++ ++ if (!grub_trusted_key) ++ return grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("No trusted keys to verify against")); ++ ++ err = extract_appended_signature (buf, bufsize, &sig); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ ++ datasize = bufsize - sig.signature_len; ++ ++ context = grub_zalloc (sig.pkcs7.hash->contextsize); ++ if (!context) ++ return grub_errno; ++ ++ sig.pkcs7.hash->init (context); ++ sig.pkcs7.hash->write (context, buf, datasize); ++ sig.pkcs7.hash->final (context); ++ hash = sig.pkcs7.hash->read (context); ++ grub_dprintf ("appendedsig", ++ "data size %" PRIxGRUB_SIZE ", hash %02x%02x%02x%02x...\n", ++ datasize, hash[0], hash[1], hash[2], hash[3]); ++ ++ err = GRUB_ERR_BAD_SIGNATURE; ++ for (pk = grub_trusted_key; pk; pk = pk->next) ++ { ++ rc = grub_crypto_rsa_pad (&hashmpi, hash, sig.pkcs7.hash, pk->mpis[0]); ++ if (rc) ++ { ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Error padding hash for RSA verification: %d"), ++ rc); ++ goto cleanup; ++ } ++ ++ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &sig.pkcs7.sig_mpi, ++ pk->mpis, NULL, NULL); ++ gcry_mpi_release (hashmpi); ++ ++ if (rc == 0) ++ { ++ grub_dprintf ("appendedsig", "verify with key '%s' succeeded\n", ++ pk->subject); ++ err = GRUB_ERR_NONE; ++ break; ++ } ++ ++ grub_dprintf ("appendedsig", "verify with key '%s' failed with %d\n", ++ pk->subject, rc); ++ } ++ ++ /* If we didn't verify, provide a neat message */ ++ if (err != GRUB_ERR_NONE) ++ err = grub_error (GRUB_ERR_BAD_SIGNATURE, ++ N_("Failed to verify signature against a trusted key")); ++ ++cleanup: ++ grub_free (context); ++ pkcs7_signedData_release (&sig.pkcs7); ++ ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_verify_signature (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_file_t f; ++ grub_err_t err = GRUB_ERR_NONE; ++ grub_uint8_t *data; ++ grub_ssize_t read_size; ++ grub_off_t file_size, total_read_size = 0; ++ ++ if (argc < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ grub_dprintf ("appendedsig", "verifying %s\n", args[0]); ++ ++ f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE); ++ if (!f) ++ { ++ err = grub_errno; ++ goto cleanup; ++ } ++ ++ file_size = grub_file_size (f); ++ if (file_size == GRUB_FILE_SIZE_UNKNOWN) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Cannot verify the signature of a file of unknown size")); ++ ++ data = grub_malloc (file_size); ++ if (!data) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate data buffer size %" ++ PRIuGRUB_UINT64_T " for verification"), file_size); ++ ++ while (total_read_size < file_size) ++ { ++ read_size = ++ grub_file_read (f, &data[total_read_size], ++ file_size - total_read_size); ++ if (read_size < 0) ++ { ++ err = grub_error (GRUB_ERR_READ_ERROR, ++ N_("Error reading file to verify")); ++ goto cleanup_data; ++ } ++ total_read_size += read_size; ++ } ++ ++ err = grub_verify_appended_signature (data, file_size); ++ ++cleanup_data: ++ grub_free (data); ++cleanup: ++ if (f) ++ grub_file_close (f); ++ return err; ++} ++ ++static grub_err_t ++grub_cmd_distrust (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ unsigned long cert_num, i; ++ struct x509_certificate *cert, *prev; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected")); ++ ++ grub_errno = GRUB_ERR_NONE; ++ cert_num = grub_strtoul (args[0], NULL, 10); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ ++ if (cert_num < 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("Certificate number too small - numbers start at 1")); ++ ++ if (cert_num == 1) ++ { ++ cert = grub_trusted_key; ++ grub_trusted_key = cert->next; ++ ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } ++ i = 2; ++ prev = grub_trusted_key; ++ cert = grub_trusted_key->next; ++ while (cert) ++ { ++ if (i == cert_num) ++ { ++ prev->next = cert->next; ++ certificate_release (cert); ++ grub_free (cert); ++ return GRUB_ERR_NONE; ++ } ++ i++; ++ prev = cert; ++ cert = cert->next; ++ } ++ ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("No certificate number %d found - only %d certificates in the store"), ++ cert_num, i - 1); ++} ++ ++static grub_err_t ++grub_cmd_trust (grub_command_t cmd __attribute__((unused)), ++ int argc, char **args) ++{ ++ grub_file_t certf; ++ struct x509_certificate *cert = NULL; ++ grub_err_t err; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ certf = grub_file_open (args[0], ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST ++ | GRUB_FILE_TYPE_NO_DECOMPRESS); ++ if (!certf) ++ return grub_errno; ++ ++ ++ cert = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!cert) ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ N_("Could not allocate memory for certificate")); ++ ++ err = read_cert_from_file (certf, cert); ++ grub_file_close (certf); ++ if (err != GRUB_ERR_NONE) ++ { ++ grub_free (cert); ++ return err; ++ } ++ grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", ++ cert->subject); ++ ++ cert->next = grub_trusted_key; ++ grub_trusted_key = cert; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_list (grub_command_t cmd __attribute__((unused)), ++ int argc __attribute__((unused)), ++ char **args __attribute__((unused))) ++{ ++ struct x509_certificate *cert; ++ int cert_num = 1; ++ grub_size_t i; ++ ++ for (cert = grub_trusted_key; cert; cert = cert->next) ++ { ++ grub_printf (N_("Certificate %d:\n"), cert_num); ++ ++ grub_printf (N_("\tSerial: ")); ++ for (i = 0; i < cert->serial_len - 1; i++) ++ { ++ grub_printf ("%02x:", cert->serial[i]); ++ } ++ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); ++ ++ grub_printf ("\tCN: %s\n\n", cert->subject); ++ cert_num++; ++ ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++appendedsig_init (grub_file_t io __attribute__((unused)), ++ enum grub_file_type type, ++ void **context __attribute__((unused)), ++ enum grub_verify_flags *flags) ++{ ++ if (!check_sigs) ++ { ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++ ++ switch (type & GRUB_FILE_TYPE_MASK) ++ { ++ case GRUB_FILE_TYPE_CERTIFICATE_TRUST: ++ /* ++ * This is a certificate to add to trusted keychain. ++ * ++ * This needs to be verified or blocked. Ideally we'd write an x509 ++ * verifier, but we lack the hubris required to take this on. Instead, ++ * require that it have an appended signature. ++ */ ++ ++ /* Fall through */ ++ ++ case GRUB_FILE_TYPE_LINUX_KERNEL: ++ case GRUB_FILE_TYPE_GRUB_MODULE: ++ /* ++ * Appended signatures are only defined for ELF binaries. ++ * Out of an abundance of caution, we only verify Linux kernels and ++ * GRUB modules at this point. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; ++ ++ case GRUB_FILE_TYPE_ACPI_TABLE: ++ case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ /* ++ * It is possible to use appended signature verification without ++ * lockdown - like the PGP verifier. When combined with an embedded ++ * config file in a signed grub binary, this could still be a meaningful ++ * secure-boot chain - so long as it isn't subverted by something like a ++ * rouge ACPI table or DT image. Defer them explicitly. ++ */ ++ *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; ++ return GRUB_ERR_NONE; ++ ++ default: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; ++ } ++} ++ ++static grub_err_t ++appendedsig_write (void *ctxt __attribute__((unused)), ++ void *buf, grub_size_t size) ++{ ++ return grub_verify_appended_signature (buf, size); ++} ++ ++struct grub_file_verifier grub_appendedsig_verifier = { ++ .name = "appendedsig", ++ .init = appendedsig_init, ++ .write = appendedsig_write, ++}; ++ ++static grub_ssize_t ++pseudo_read (struct grub_file *file, char *buf, grub_size_t len) ++{ ++ grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len); ++ return len; ++} ++ ++/* Filesystem descriptor. */ ++static struct grub_fs pseudo_fs = { ++ .name = "pseudo", ++ .fs_read = pseudo_read ++}; ++ ++static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust; ++ ++GRUB_MOD_INIT (appendedsig) ++{ ++ int rc; ++ struct grub_module_header *header; ++ ++ /* If in lockdown, immediately enter forced mode */ ++ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED) ++ check_sigs = 2; ++ ++ grub_trusted_key = NULL; ++ ++ grub_register_variable_hook ("check_appended_signatures", ++ grub_env_read_sec, ++ grub_env_write_sec); ++ grub_env_export ("check_appended_signatures"); ++ ++ rc = asn1_init (); ++ if (rc) ++ grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc, ++ asn1_strerror (rc)); ++ ++ FOR_MODULES (header) ++ { ++ struct grub_file pseudo_file; ++ struct x509_certificate *pk = NULL; ++ grub_err_t err; ++ ++ /* Not an ELF module, skip. */ ++ if (header->type != OBJ_TYPE_X509_PUBKEY) ++ continue; ++ ++ grub_memset (&pseudo_file, 0, sizeof (pseudo_file)); ++ pseudo_file.fs = &pseudo_fs; ++ pseudo_file.size = header->size - sizeof (struct grub_module_header); ++ pseudo_file.data = (char *) header + sizeof (struct grub_module_header); ++ ++ grub_dprintf ("appendedsig", ++ "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n", ++ pseudo_file.size); ++ ++ pk = grub_zalloc (sizeof (struct x509_certificate)); ++ if (!pk) ++ { ++ grub_fatal ("Out of memory loading initial certificates"); ++ } ++ ++ err = read_cert_from_file (&pseudo_file, pk); ++ if (err != GRUB_ERR_NONE) ++ grub_fatal ("Error loading initial key: %s", grub_errmsg); ++ ++ grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject); ++ ++ pk->next = grub_trusted_key; ++ grub_trusted_key = pk; ++ } ++ ++ cmd_trust = ++ grub_register_command ("trust_certificate", grub_cmd_trust, ++ N_("X509_CERTIFICATE"), ++ N_("Add X509_CERTIFICATE to trusted certificates.")); ++ cmd_list = ++ grub_register_command ("list_certificates", grub_cmd_list, 0, ++ N_("Show the list of trusted x509 certificates.")); ++ cmd_verify = ++ grub_register_command ("verify_appended", grub_cmd_verify_signature, ++ N_("FILE"), ++ N_("Verify FILE against the trusted x509 certificates.")); ++ cmd_distrust = ++ grub_register_command ("distrust_certificate", grub_cmd_distrust, ++ N_("CERT_NUMBER"), ++ N_("Remove CERT_NUMBER (as listed by list_certificates) from trusted certificates.")); ++ ++ grub_verifier_register (&grub_appendedsig_verifier); ++ grub_dl_set_persistent (mod); ++} ++ ++GRUB_MOD_FINI (appendedsig) ++{ ++ /* ++ * grub_dl_set_persistent should prevent this from actually running, but ++ * it does still run under emu. ++ */ ++ ++ grub_verifier_unregister (&grub_appendedsig_verifier); ++ grub_unregister_command (cmd_verify); ++ grub_unregister_command (cmd_list); ++ grub_unregister_command (cmd_trust); ++ grub_unregister_command (cmd_distrust); ++} +diff --git a/include/grub/file.h b/include/grub/file.h +index 31567483cc..96827a4f89 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -80,6 +80,8 @@ enum grub_file_type + GRUB_FILE_TYPE_PUBLIC_KEY, + /* File holding public key to add to trused keys. */ + GRUB_FILE_TYPE_PUBLIC_KEY_TRUST, ++ /* File holding x509 certificiate to add to trusted keys. */ ++ GRUB_FILE_TYPE_CERTIFICATE_TRUST, + /* File of which we intend to print a blocklist to the user. */ + GRUB_FILE_TYPE_PRINT_BLOCKLIST, + /* File we intend to use for test loading or testing speed. */ diff --git a/SOURCES/0171-appended-signatures-verification-tests.patch b/SOURCES/0171-appended-signatures-verification-tests.patch new file mode 100644 index 0000000..b39a5af --- /dev/null +++ b/SOURCES/0171-appended-signatures-verification-tests.patch @@ -0,0 +1,897 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 30 Jul 2020 01:31:02 +1000 +Subject: [PATCH] appended signatures: verification tests + +These tests are run through all_functional_test and test a range +of commands and behaviours. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 6 + + grub-core/tests/appended_signature_test.c | 281 +++++++++++++++ + grub-core/tests/lib/functional_test.c | 1 + + grub-core/tests/appended_signatures.h | 557 ++++++++++++++++++++++++++++++ + 4 files changed, 845 insertions(+) + create mode 100644 grub-core/tests/appended_signature_test.c + create mode 100644 grub-core/tests/appended_signatures.h + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 6404384d90..9ea5fb38f1 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -2162,6 +2162,12 @@ module = { + common = tests/setjmp_test.c; + }; + ++module = { ++ name = appended_signature_test; ++ common = tests/appended_signature_test.c; ++ common = tests/appended_signatures.h; ++}; ++ + module = { + name = signature_test; + common = tests/signature_test.c; +diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c +new file mode 100644 +index 0000000000..88a485200d +--- /dev/null ++++ b/grub-core/tests/appended_signature_test.c +@@ -0,0 +1,281 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2020 IBM Corporation. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "appended_signatures.h" ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#define DEFINE_TEST_CASE(case_name) \ ++static char * \ ++get_ ## case_name (grub_size_t *sz) \ ++{ \ ++ char *ret; \ ++ *sz = case_name ## _len; \ ++ ret = grub_malloc (*sz); \ ++ if (ret) \ ++ grub_memcpy (ret, case_name, *sz); \ ++ return ret; \ ++} \ ++\ ++static struct grub_procfs_entry case_name ## _entry = \ ++{ \ ++ .name = #case_name, \ ++ .get_contents = get_ ## case_name \ ++} ++ ++#define DO_TEST(case_name, is_valid) \ ++{ \ ++ grub_procfs_register (#case_name, &case_name ## _entry); \ ++ do_verify ("(proc)/" #case_name, is_valid); \ ++ grub_procfs_unregister (&case_name ## _entry); \ ++} ++ ++ ++DEFINE_TEST_CASE (hi_signed); ++DEFINE_TEST_CASE (hi_signed_sha256); ++DEFINE_TEST_CASE (hj_signed); ++DEFINE_TEST_CASE (short_msg); ++DEFINE_TEST_CASE (unsigned_msg); ++DEFINE_TEST_CASE (hi_signed_2nd); ++ ++static char * ++get_certificate_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_der_entry = { ++ .name = "certificate.der", ++ .get_contents = get_certificate_der ++}; ++ ++static char * ++get_certificate2_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate2_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate2_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate2_der_entry = { ++ .name = "certificate2.der", ++ .get_contents = get_certificate2_der ++}; ++ ++static char * ++get_certificate_printable_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_printable_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_printable_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_printable_der_entry = { ++ .name = "certificate_printable.der", ++ .get_contents = get_certificate_printable_der ++}; ++ ++ ++static void ++do_verify (const char *f, int is_valid) ++{ ++ grub_command_t cmd; ++ char *args[] = { (char *) f, NULL }; ++ grub_err_t err; ++ ++ cmd = grub_command_find ("verify_appended"); ++ if (!cmd) ++ { ++ grub_test_assert (0, "can't find command `%s'", "verify_appended"); ++ return; ++ } ++ err = (cmd->func) (cmd, 1, args); ++ if (is_valid) ++ { ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "verification of %s failed: %d: %s", f, grub_errno, ++ grub_errmsg); ++ } ++ else ++ { ++ grub_test_assert (err == GRUB_ERR_BAD_SIGNATURE, ++ "verification of %s unexpectedly succeeded", f); ++ } ++ grub_errno = GRUB_ERR_NONE; ++ ++} ++ ++static void ++appended_signature_test (void) ++{ ++ grub_command_t cmd_trust, cmd_distrust; ++ char *trust_args[] = { (char *) "(proc)/certificate.der", NULL }; ++ char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; ++ char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", ++ NULL }; ++ char *distrust_args[] = { (char *) "1", NULL }; ++ char *distrust2_args[] = { (char *) "2", NULL }; ++ grub_err_t err; ++ ++ grub_procfs_register ("certificate.der", &certificate_der_entry); ++ grub_procfs_register ("certificate2.der", &certificate2_der_entry); ++ grub_procfs_register ("certificate_printable.der", ++ &certificate_printable_der_entry); ++ ++ cmd_trust = grub_command_find ("trust_certificate"); ++ if (!cmd_trust) ++ { ++ grub_test_assert (0, "can't find command `%s'", "trust_certificate"); ++ return; ++ } ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "loading certificate failed: %d: %s", grub_errno, ++ grub_errmsg); ++ ++ /* If we have no certificate the remainder of the tests are meaningless */ ++ if (err != GRUB_ERR_NONE) ++ return; ++ ++ /* ++ * Reload the command: this works around some 'interesting' behaviour in the ++ * dynamic command dispatcher. The first time you call cmd->func you get a ++ * dispatcher that loads the module, finds the real cmd, calls it, and then ++ * releases some internal storage. This means it's not safe to call a second ++ * time and we need to reload it. ++ */ ++ cmd_trust = grub_command_find ("trust_certificate"); ++ ++ DO_TEST (hi_signed, 1); ++ DO_TEST (hi_signed_sha256, 1); ++ DO_TEST (hj_signed, 0); ++ DO_TEST (short_msg, 0); ++ DO_TEST (unsigned_msg, 0); ++ ++ /* ++ * in enforcing mode, we shouldn't be able to load a certificate that isn't ++ * signed by an existing trusted key. ++ * ++ * However, procfs files automatically skip the verification test, so we can't ++ * easily test this. ++ */ ++ ++ /* ++ * verify that testing with 2 trusted certs works ++ */ ++ DO_TEST (hi_signed_2nd, 0); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args2); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "loading certificate 2 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ ++ if (err != GRUB_ERR_NONE) ++ return; ++ ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 1); ++ ++ /* ++ * Check certificate removal. They're added to the _top_ of the list and ++ * removed by position in the list. Current the list looks like [#2, #1]. ++ * ++ * First test removing the second certificate in the list, which is ++ * certificate #1, giving us just [#2]. ++ */ ++ cmd_distrust = grub_command_find ("distrust_certificate"); ++ if (!cmd_distrust) ++ { ++ grub_test_assert (0, "can't find command `%s'", "distrust_certificate"); ++ return; ++ } ++ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust2_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 0); ++ ++ /* ++ * Now reload certificate #1. This will make the list look like [#1, #2] ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args); ++ ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "reloading certificate 1 failed: %d: %s", grub_errno, ++ grub_errmsg); ++ DO_TEST (hi_signed, 1); ++ ++ /* Remove the first certificate in the list, giving us just [#2] */ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 (first time) failed: %d: %s", ++ grub_errno, grub_errmsg); ++ DO_TEST (hi_signed_2nd, 1); ++ DO_TEST (hi_signed, 0); ++ ++ /* ++ * Remove the first certificate again, giving an empty list. ++ * ++ * verify_appended should fail if there are no certificates to verify against. ++ */ ++ err = (cmd_distrust->func) (cmd_distrust, 1, distrust_args); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting certificate 1 (second time) failed: %d: %s", ++ grub_errno, grub_errmsg); ++ DO_TEST (hi_signed_2nd, 0); ++ ++ /* ++ * Lastly, check a certificate that uses printableString rather than ++ * utf8String loads properly. ++ */ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "distrusting printable certificate failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ grub_procfs_unregister (&certificate_der_entry); ++ grub_procfs_unregister (&certificate2_der_entry); ++ grub_procfs_unregister (&certificate_printable_der_entry); ++} ++ ++GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); +diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c +index 96781fb39b..403fa5c789 100644 +--- a/grub-core/tests/lib/functional_test.c ++++ b/grub-core/tests/lib/functional_test.c +@@ -73,6 +73,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)), + grub_dl_load ("xnu_uuid_test"); + grub_dl_load ("pbkdf2_test"); + grub_dl_load ("signature_test"); ++ grub_dl_load ("appended_signature_test"); + grub_dl_load ("sleep_test"); + grub_dl_load ("bswap_test"); + grub_dl_load ("ctz_test"); +diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h +new file mode 100644 +index 0000000000..aa3dc6278e +--- /dev/null ++++ b/grub-core/tests/appended_signatures.h +@@ -0,0 +1,557 @@ ++unsigned char certificate_der[] = { ++ 0x30, 0x82, 0x03, 0x88, 0x30, 0x82, 0x02, 0x70, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x49, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x1f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, ++ 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, ++ 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, ++ 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, ++ 0x01, 0x16, 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, ++ 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, ++ 0x37, 0x30, 0x39, 0x30, 0x36, 0x32, 0x32, 0x30, 0x37, 0x5a, 0x18, 0x0f, ++ 0x32, 0x31, 0x32, 0x30, 0x30, 0x36, 0x31, 0x35, 0x30, 0x36, 0x32, 0x32, ++ 0x30, 0x37, 0x5a, 0x30, 0x52, 0x31, 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x28, 0x47, 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, ++ 0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, ++ 0x75, 0x72, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x31, 0x1d, 0x30, 0x1b, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x0e, 0x64, 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, ++ 0x6e, 0x65, 0x74, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, ++ 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, ++ 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, ++ 0xcd, 0xe8, 0x1c, 0x08, 0x68, 0x2e, 0xcb, 0xfe, 0x8c, 0x4b, 0x3b, 0x61, ++ 0xe7, 0x8e, 0x80, 0x58, 0x85, 0x85, 0xea, 0xc8, 0x3b, 0x42, 0xba, 0x72, ++ 0x84, 0x65, 0x20, 0xbc, 0x48, 0xa2, 0x25, 0x49, 0x6e, 0x1c, 0xb9, 0x7d, ++ 0xeb, 0xc1, 0x0c, 0xa8, 0xb7, 0xcc, 0x13, 0x78, 0xba, 0x11, 0xa4, 0x98, ++ 0xd7, 0xd0, 0x7c, 0xdd, 0xf5, 0x5a, 0xb7, 0xcd, 0x31, 0x0e, 0xcd, 0x9e, ++ 0xa7, 0x19, 0xf0, 0xbd, 0x0f, 0xa6, 0xfe, 0x8a, 0x11, 0x97, 0xed, 0x8b, ++ 0xe5, 0x16, 0xa6, 0x21, 0x13, 0x36, 0xad, 0x05, 0x49, 0xec, 0x29, 0x12, ++ 0x38, 0xa7, 0x4b, 0x0f, 0xa1, 0xfb, 0x72, 0xc0, 0xc0, 0x09, 0x67, 0x78, ++ 0xa8, 0xb6, 0xd6, 0x1a, 0x39, 0xc0, 0xa8, 0xbf, 0x5f, 0x14, 0x89, 0x5c, ++ 0xbc, 0x41, 0x0c, 0x0c, 0x5d, 0x42, 0x2e, 0x1c, 0xdf, 0x1f, 0x1d, 0xc9, ++ 0x43, 0x94, 0x5b, 0x6e, 0x8f, 0x15, 0x8c, 0x8f, 0x94, 0x73, 0x4f, 0x97, ++ 0x54, 0xf1, 0x86, 0x8a, 0xbc, 0xe4, 0xe4, 0x93, 0xc1, 0x5e, 0xc2, 0x3e, ++ 0x31, 0x5e, 0xd4, 0x85, 0x57, 0x14, 0xd0, 0x11, 0x07, 0x65, 0xf4, 0x7c, ++ 0x8f, 0x07, 0x57, 0xe1, 0x22, 0xd4, 0x78, 0x47, 0x65, 0x4e, 0xa9, 0xb3, ++ 0xaa, 0xce, 0xc7, 0x36, 0xfe, 0xda, 0x66, 0x02, 0xb6, 0x8d, 0x18, 0x2f, ++ 0x3b, 0x41, 0x8d, 0x02, 0x08, 0x72, 0x4b, 0x69, 0xbd, 0x1e, 0x58, 0xfc, ++ 0x1b, 0x64, 0x04, 0x52, 0x35, 0x35, 0xe2, 0x3d, 0x3e, 0xde, 0xd6, 0x64, ++ 0xf4, 0xec, 0x57, 0x7e, 0x65, 0x59, 0x00, 0xa6, 0xd3, 0x4b, 0x09, 0x93, ++ 0x2a, 0x95, 0x0f, 0x30, 0xb6, 0xa1, 0x8c, 0xe7, 0x8b, 0x49, 0xa4, 0x1d, ++ 0x25, 0x2d, 0x65, 0x48, 0x8a, 0x0f, 0xcf, 0x2a, 0xa2, 0xe1, 0xef, 0x72, ++ 0x92, 0xc3, 0xf5, 0x21, 0x37, 0x83, 0x9b, 0x6d, 0x0b, 0x1b, 0xb3, 0xa2, ++ 0x32, 0x38, 0x11, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, ++ 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, ++ 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, ++ 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, ++ 0x16, 0x04, 0x14, 0xe5, 0x2a, 0x4f, 0xf2, 0x84, 0x91, 0x57, 0x91, 0xaf, ++ 0x12, 0xd2, 0xf1, 0xa1, 0x87, 0x73, 0x0f, 0x90, 0x25, 0xa0, 0x7a, 0x30, ++ 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, ++ 0x56, 0xd1, 0xfd, 0xe2, 0x1e, 0x7e, 0x1c, 0x63, 0x4f, 0x47, 0xdb, 0xe4, ++ 0xc4, 0x51, 0x04, 0x03, 0x9a, 0x48, 0x35, 0x6e, 0x30, 0x0d, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, ++ 0x82, 0x01, 0x01, 0x00, 0x65, 0x82, 0xd5, 0x88, 0x30, 0xe2, 0x2c, 0x47, ++ 0xf3, 0x31, 0x39, 0xa1, 0x75, 0x9a, 0xb0, 0x8a, 0x6c, 0x4b, 0xac, 0xdf, ++ 0x09, 0x7b, 0x90, 0xb6, 0x9e, 0x76, 0x62, 0x94, 0xc1, 0x3a, 0x99, 0x49, ++ 0x68, 0x29, 0x47, 0x42, 0xc3, 0x06, 0xcb, 0x88, 0x75, 0xe6, 0x79, 0x13, ++ 0x8c, 0x4b, 0x49, 0x6a, 0xb5, 0x56, 0x95, 0xc0, 0x42, 0x21, 0x9b, 0xd4, ++ 0x61, 0xd0, 0x02, 0x41, 0xdd, 0x20, 0x61, 0xe5, 0x91, 0xdf, 0x75, 0x00, ++ 0x25, 0x0e, 0x99, 0x65, 0x5c, 0x54, 0x49, 0x32, 0xa3, 0xe2, 0xcd, 0xa1, ++ 0x5f, 0x40, 0xf3, 0xc5, 0x81, 0xd9, 0x3c, 0xa3, 0x63, 0x5a, 0x38, 0x79, ++ 0xab, 0x77, 0x98, 0xde, 0x8f, 0x4e, 0x9e, 0x26, 0xbc, 0x4e, 0x80, 0x9e, ++ 0x8f, 0xbe, 0xf1, 0x00, 0xb3, 0x78, 0xb9, 0x4b, 0x1d, 0xc7, 0xa4, 0x83, ++ 0x59, 0x56, 0x11, 0xd1, 0x11, 0x1e, 0x50, 0x39, 0xd5, 0x78, 0x14, 0xf3, ++ 0xb9, 0x1d, 0xda, 0xe4, 0xc4, 0x63, 0x74, 0x26, 0xab, 0xa3, 0xfd, 0x9d, ++ 0x58, 0xa2, 0xee, 0x7b, 0x28, 0x34, 0xa3, 0xbe, 0x85, 0x7e, 0xaa, 0x97, ++ 0xb7, 0x5b, 0x9d, 0xa9, 0x4d, 0x96, 0xdb, 0x6b, 0x21, 0xe1, 0x96, 0x5d, ++ 0xc7, 0xad, 0x23, 0x03, 0x9a, 0x16, 0xdb, 0xa4, 0x1f, 0x63, 0xef, 0xaf, ++ 0x1e, 0x4f, 0xf8, 0x27, 0xdc, 0x4b, 0xfc, 0x2b, 0x68, 0x2e, 0xa0, 0xd3, ++ 0xae, 0xf2, 0xce, 0xf5, 0xfc, 0x97, 0x92, 0xd2, 0x29, 0x0f, 0x4f, 0x4b, ++ 0x29, 0xeb, 0x06, 0xcb, 0xf8, 0x21, 0x6e, 0xbc, 0x8b, 0x5c, 0xc5, 0xc9, ++ 0xf7, 0xe2, 0x7c, 0x47, 0xcd, 0x43, 0x98, 0xc4, 0xa3, 0x9a, 0xd7, 0x3e, ++ 0xdc, 0x01, 0x13, 0x28, 0x96, 0xc4, 0x60, 0x83, 0xe2, 0x79, 0xa1, 0x46, ++ 0xef, 0xf5, 0xa4, 0x7b, 0x00, 0xe3, 0x3d, 0x7d, 0xbc, 0xa8, 0x98, 0x49, ++ 0xa8, 0xcf, 0x3b, 0x41, 0xb6, 0x09, 0x97, 0x07 ++}; ++unsigned int certificate_der_len = 908; ++ ++unsigned char hi_signed[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66, ++ 0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0, ++ 0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16, ++ 0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69, ++ 0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b, ++ 0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb, ++ 0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94, ++ 0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41, ++ 0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86, ++ 0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c, ++ 0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86, ++ 0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7, ++ 0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14, ++ 0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14, ++ 0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0, ++ 0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8, ++ 0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e, ++ 0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70, ++ 0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25, ++ 0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad, ++ 0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95, ++ 0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e, ++ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, ++ 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, ++ 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_len = 495; ++ ++unsigned char hj_signed[] = { ++ 0x68, 0x6a, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc7, 0x69, 0x35, 0x21, 0x66, ++ 0x4d, 0x50, 0xd4, 0x73, 0xde, 0xbd, 0x3a, 0xf6, 0x45, 0xe3, 0xe4, 0xd0, ++ 0xb6, 0xa1, 0xe7, 0xc0, 0xa2, 0xc9, 0xf4, 0xf0, 0x05, 0x8c, 0xa4, 0x16, ++ 0x9e, 0x81, 0x0d, 0x21, 0x68, 0xf3, 0xfe, 0x03, 0x96, 0x77, 0x31, 0x69, ++ 0x01, 0xd8, 0x26, 0xd9, 0x48, 0x95, 0xcf, 0xd1, 0x17, 0xb1, 0x0b, 0x6b, ++ 0x2c, 0xf1, 0xb0, 0xab, 0x65, 0x65, 0x56, 0xf8, 0x0c, 0xa7, 0xf7, 0xbb, ++ 0xf6, 0x5a, 0x55, 0x98, 0x14, 0x07, 0x8d, 0x2a, 0xbc, 0x16, 0x48, 0x94, ++ 0xab, 0x2f, 0x85, 0x97, 0x90, 0x51, 0x78, 0xa0, 0xda, 0x60, 0xb5, 0x41, ++ 0x4b, 0xe8, 0x78, 0xc5, 0xa6, 0x04, 0x9d, 0x54, 0x2a, 0x85, 0xfd, 0x86, ++ 0x0b, 0x6d, 0xc2, 0xd2, 0xad, 0x07, 0xff, 0x16, 0x42, 0x82, 0xe3, 0x5c, ++ 0xaa, 0x22, 0x59, 0x78, 0x92, 0xea, 0x94, 0xc3, 0x41, 0xb7, 0xa1, 0x86, ++ 0x44, 0xea, 0xd1, 0xdb, 0xe5, 0xac, 0x30, 0x32, 0xfb, 0x7d, 0x3f, 0xf7, ++ 0x8b, 0x11, 0x7f, 0x80, 0x3b, 0xe5, 0xc7, 0x82, 0x0f, 0x92, 0x07, 0x14, ++ 0x66, 0x01, 0x6e, 0x85, 0xab, 0x3a, 0x14, 0xcf, 0x76, 0xd1, 0x7e, 0x14, ++ 0x85, 0xca, 0x01, 0x73, 0x72, 0x38, 0xdc, 0xde, 0x30, 0x5c, 0xfb, 0xc0, ++ 0x3d, 0x93, 0xef, 0x9c, 0xbc, 0xf8, 0xcc, 0xd2, 0xbf, 0x47, 0xec, 0xf8, ++ 0x88, 0x9b, 0xe1, 0x43, 0xbe, 0xa7, 0x47, 0x96, 0xb6, 0x5d, 0x46, 0x0e, ++ 0x7a, 0x78, 0x38, 0x19, 0xbc, 0xb5, 0xbc, 0x9b, 0x3c, 0x39, 0x92, 0x70, ++ 0x0d, 0x9d, 0x8a, 0x35, 0xaf, 0xb4, 0x9e, 0xf4, 0xef, 0xc1, 0xb8, 0x25, ++ 0xd0, 0x14, 0x91, 0xd6, 0xc2, 0xb6, 0xc7, 0x3c, 0x72, 0x91, 0x0f, 0xad, ++ 0xde, 0xb2, 0x36, 0xf8, 0x4e, 0x59, 0xd4, 0xa4, 0x21, 0x9f, 0x03, 0x95, ++ 0x48, 0x01, 0xb4, 0x05, 0xc3, 0x39, 0x60, 0x51, 0x08, 0xd0, 0xbe, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e, ++ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, ++ 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, ++ 0x64, 0x7e, 0x0a ++}; ++unsigned int hj_signed_len = 495; ++ ++unsigned char hi_signed_sha256[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x01, 0xc0, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x01, 0xb1, 0x30, 0x82, ++ 0x01, 0xad, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x01, ++ 0x8a, 0x30, 0x82, 0x01, 0x86, 0x02, 0x01, 0x01, 0x30, 0x61, 0x30, 0x49, ++ 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x41, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x64, ++ 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, ++ 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0e, 0x64, ++ 0x6a, 0x61, 0x40, 0x61, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x2e, 0x6e, 0x65, ++ 0x74, 0x02, 0x14, 0x25, 0x2e, 0xb8, 0xfd, 0x12, 0x62, 0x2e, 0xcd, 0x5d, ++ 0xa7, 0x53, 0xd2, 0x0b, 0xc2, 0x61, 0x7c, 0x14, 0xe0, 0x0f, 0x5c, 0x30, ++ 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x7b, 0x5e, 0x82, 0x1d, 0x21, ++ 0xb6, 0x40, 0xd3, 0x33, 0x79, 0xa7, 0x52, 0x2b, 0xfc, 0x46, 0x51, 0x26, ++ 0xfe, 0x0f, 0x81, 0x90, 0x81, 0xab, 0x57, 0x5e, 0xf6, 0x45, 0x41, 0xa3, ++ 0x7b, 0x48, 0xdd, 0xd6, 0x59, 0x60, 0x51, 0x31, 0x14, 0x14, 0x7b, 0xb4, ++ 0x55, 0x7b, 0x4d, 0xfe, 0x09, 0x7a, 0x5d, 0xae, 0xc4, 0x58, 0x50, 0x80, ++ 0x75, 0xf2, 0x23, 0x20, 0x62, 0xe3, 0x7c, 0x26, 0x1d, 0x2a, 0x4d, 0x9f, ++ 0x89, 0xf0, 0x4f, 0x95, 0x8a, 0x80, 0x6e, 0x1a, 0xea, 0x87, 0xdb, 0x1f, ++ 0xf3, 0xda, 0x04, 0x91, 0x37, 0xea, 0x0a, 0xfb, 0x6c, 0xc9, 0x3d, 0x73, ++ 0xf9, 0x58, 0x7c, 0x15, 0x6b, 0xa2, 0x52, 0x5a, 0x97, 0xff, 0xd6, 0xb0, ++ 0xf1, 0xbf, 0xa5, 0x04, 0x6d, 0x91, 0xc1, 0x54, 0x05, 0xdc, 0x7f, 0x5d, ++ 0x19, 0xaf, 0x55, 0xec, 0x51, 0xfb, 0x66, 0x0a, 0xa4, 0x4e, 0x96, 0x47, ++ 0x43, 0x54, 0x7c, 0x64, 0xa8, 0xaa, 0xb4, 0x90, 0x02, 0xf3, 0xa7, 0x0b, ++ 0xb7, 0xbf, 0x06, 0xdb, 0x5e, 0x9c, 0x32, 0x6d, 0x45, 0x14, 0x1c, 0xaf, ++ 0x46, 0x30, 0x08, 0x55, 0x49, 0x78, 0xfa, 0x57, 0xda, 0x3d, 0xf5, 0xa0, ++ 0xef, 0x11, 0x0a, 0x81, 0x0d, 0x82, 0xcd, 0xaf, 0xdb, 0xda, 0x0e, 0x1a, ++ 0x44, 0xd1, 0xee, 0xc4, 0xb8, 0xde, 0x97, 0xb4, 0xda, 0xb4, 0x8b, 0x4f, ++ 0x58, 0x24, 0x59, 0xc0, 0xe0, 0x08, 0x97, 0x14, 0x68, 0xbe, 0x31, 0x09, ++ 0x5e, 0x67, 0x45, 0xf0, 0xcb, 0x81, 0x4f, 0x17, 0x44, 0x61, 0xe0, 0xe2, ++ 0xf0, 0xfc, 0x1e, 0xb9, 0x73, 0xaf, 0x42, 0xff, 0x33, 0xde, 0x61, 0x6b, ++ 0x7f, 0xc2, 0x69, 0x0d, 0x66, 0x54, 0xae, 0xf6, 0xde, 0x20, 0x47, 0x44, ++ 0x9b, 0x73, 0xd1, 0x07, 0x6e, 0x77, 0x37, 0x0a, 0xbb, 0x7f, 0xa0, 0x93, ++ 0x2d, 0x8d, 0x44, 0xba, 0xe2, 0xdd, 0x34, 0x32, 0xd7, 0x56, 0x71, 0x00, ++ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc4, 0x7e, ++ 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x61, ++ 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, 0x65, ++ 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_sha256_len = 495; ++ ++unsigned char short_msg[] = { ++ 0x68, 0x69, 0x0a ++}; ++unsigned int short_msg_len = 3; ++ ++unsigned char unsigned_msg[] = { ++ 0x53, 0x65, 0x64, 0x20, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x73, 0x70, ++ 0x69, 0x63, 0x69, 0x61, 0x74, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x64, 0x65, ++ 0x20, 0x6f, 0x6d, 0x6e, 0x69, 0x73, 0x20, 0x69, 0x73, 0x74, 0x65, 0x20, ++ 0x6e, 0x61, 0x74, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, ++ 0x73, 0x69, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x20, 0x61, 0x63, 0x63, 0x75, 0x73, 0x61, 0x6e, 0x74, 0x69, ++ 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x71, 0x75, ++ 0x65, 0x20, 0x6c, 0x61, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x69, 0x75, 0x6d, ++ 0x2c, 0x20, 0x74, 0x6f, 0x74, 0x61, 0x6d, 0x20, 0x72, 0x65, 0x6d, 0x20, ++ 0x61, 0x70, 0x65, 0x72, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x65, 0x61, 0x71, ++ 0x75, 0x65, 0x20, 0x69, 0x70, 0x73, 0x61, 0x20, 0x71, 0x75, 0x61, 0x65, ++ 0x20, 0x61, 0x62, 0x20, 0x69, 0x6c, 0x6c, 0x6f, 0x20, 0x69, 0x6e, 0x76, ++ 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x76, 0x65, 0x72, 0x69, 0x74, ++ 0x61, 0x74, 0x69, 0x73, 0x20, 0x65, 0x74, 0x20, 0x71, 0x75, 0x61, 0x73, ++ 0x69, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x6f, ++ 0x20, 0x62, 0x65, 0x61, 0x74, 0x61, 0x65, 0x20, 0x76, 0x69, 0x74, 0x61, ++ 0x65, 0x20, 0x64, 0x69, 0x63, 0x74, 0x61, 0x20, 0x73, 0x75, 0x6e, 0x74, ++ 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x62, 0x6f, 0x2e, 0x20, ++ 0x4e, 0x65, 0x6d, 0x6f, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, 0x69, 0x70, ++ 0x73, 0x61, 0x6d, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, ++ 0x70, 0x74, 0x61, 0x73, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x73, 0x70, ++ 0x65, 0x72, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x20, 0x61, 0x75, 0x74, 0x20, ++ 0x6f, 0x64, 0x69, 0x74, 0x20, 0x61, 0x75, 0x74, 0x20, 0x66, 0x75, 0x67, ++ 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, 0x20, 0x71, 0x75, 0x69, 0x61, ++ 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x75, 0x6e, 0x74, 0x75, ++ 0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, ++ 0x72, 0x65, 0x73, 0x20, 0x65, 0x6f, 0x73, 0x20, 0x71, 0x75, 0x69, 0x20, ++ 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x20, 0x76, 0x6f, 0x6c, 0x75, ++ 0x70, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x20, 0x73, 0x65, 0x71, 0x75, 0x69, ++ 0x20, 0x6e, 0x65, 0x73, 0x63, 0x69, 0x75, 0x6e, 0x74, 0x2e, 0x20, 0x4e, ++ 0x65, 0x71, 0x75, 0x65, 0x20, 0x70, 0x6f, 0x72, 0x72, 0x6f, 0x20, 0x71, ++ 0x75, 0x69, 0x73, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x73, 0x74, 0x2c, ++ 0x20, 0x71, 0x75, 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, ++ 0x20, 0x69, 0x70, 0x73, 0x75, 0x6d, 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, ++ 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, ++ 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x63, 0x74, 0x65, ++ 0x74, 0x75, 0x72, 0x2c, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x63, ++ 0x69, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x2c, 0x20, 0x73, 0x65, 0x64, ++ 0x20, 0x71, 0x75, 0x69, 0x61, 0x20, 0x6e, 0x6f, 0x6e, 0x20, 0x6e, 0x75, ++ 0x6d, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x65, 0x69, 0x75, 0x73, 0x20, 0x6d, ++ 0x6f, 0x64, 0x69, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x20, ++ 0x69, 0x6e, 0x63, 0x69, 0x64, 0x75, 0x6e, 0x74, 0x20, 0x75, 0x74, 0x20, ++ 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x65, 0x20, 0x65, 0x74, 0x20, 0x64, 0x6f, ++ 0x6c, 0x6f, 0x72, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x61, 0x6d, 0x20, ++ 0x61, 0x6c, 0x69, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x71, 0x75, 0x61, 0x65, ++ 0x72, 0x61, 0x74, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x74, ++ 0x65, 0x6d, 0x2e, 0x20, 0x55, 0x74, 0x20, 0x65, 0x6e, 0x69, 0x6d, 0x20, ++ 0x61, 0x64, 0x20, 0x6d, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0x20, 0x76, 0x65, ++ 0x6e, 0x69, 0x61, 0x6d, 0x2c, 0x20, 0x71, 0x75, 0x69, 0x73, 0x20, 0x6e, ++ 0x6f, 0x73, 0x74, 0x72, 0x75, 0x6d, 0x20, 0x65, 0x78, 0x65, 0x72, 0x63, ++ 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x6d, 0x20, 0x75, 0x6c, ++ 0x6c, 0x61, 0x6d, 0x20, 0x63, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x69, 0x73, ++ 0x20, 0x73, 0x75, 0x73, 0x63, 0x69, 0x70, 0x69, 0x74, 0x20, 0x6c, 0x61, ++ 0x62, 0x6f, 0x72, 0x69, 0x6f, 0x73, 0x61, 0x6d, 0x2c, 0x20, 0x6e, 0x69, ++ 0x73, 0x69, 0x20, 0x75, 0x74, 0x20, 0x61, 0x6c, 0x69, 0x71, 0x75, 0x69, ++ 0x64, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x6d, ++ 0x6f, 0x64, 0x69, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, ++ 0x74, 0x75, 0x72, 0x3f, 0x20, 0x51, 0x75, 0x69, 0x73, 0x20, 0x61, 0x75, ++ 0x74, 0x65, 0x6d, 0x20, 0x76, 0x65, 0x6c, 0x20, 0x65, 0x75, 0x6d, 0x20, ++ 0x69, 0x75, 0x72, 0x65, 0x20, 0x72, 0x65, 0x70, 0x72, 0x65, 0x68, 0x65, ++ 0x6e, 0x64, 0x65, 0x72, 0x69, 0x74, 0x20, 0x71, 0x75, 0x69, 0x20, 0x69, ++ 0x6e, 0x20, 0x65, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, ++ 0x74, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x69, 0x74, 0x20, 0x65, 0x73, 0x73, ++ 0x65, 0x20, 0x71, 0x75, 0x61, 0x6d, 0x20, 0x6e, 0x69, 0x68, 0x69, 0x6c, ++ 0x20, 0x6d, 0x6f, 0x6c, 0x65, 0x73, 0x74, 0x69, 0x61, 0x65, 0x20, 0x63, ++ 0x6f, 0x6e, 0x73, 0x65, 0x71, 0x75, 0x61, 0x74, 0x75, 0x72, 0x2c, 0x20, ++ 0x76, 0x65, 0x6c, 0x20, 0x69, 0x6c, 0x6c, 0x75, 0x6d, 0x20, 0x71, 0x75, ++ 0x69, 0x20, 0x64, 0x6f, 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x65, 0x75, ++ 0x6d, 0x20, 0x66, 0x75, 0x67, 0x69, 0x61, 0x74, 0x20, 0x71, 0x75, 0x6f, ++ 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x70, 0x74, 0x61, 0x73, 0x20, 0x6e, 0x75, ++ 0x6c, 0x6c, 0x61, 0x20, 0x70, 0x61, 0x72, 0x69, 0x61, 0x74, 0x75, 0x72, ++ 0x3f, 0x0a ++}; ++unsigned int unsigned_msg_len = 866; ++ ++unsigned char certificate2_der[] = { ++ 0x30, 0x82, 0x05, 0x52, 0x30, 0x82, 0x03, 0x3a, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x14, 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, ++ 0x3a, 0x91, 0x07, 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, ++ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, ++ 0x05, 0x00, 0x30, 0x3a, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, ++ 0x03, 0x0c, 0x2f, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, ++ 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, ++ 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, ++ 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, ++ 0x74, 0x79, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x37, 0x32, 0x38, ++ 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x32, ++ 0x30, 0x30, 0x37, 0x30, 0x34, 0x31, 0x33, 0x32, 0x34, 0x32, 0x39, 0x5a, ++ 0x30, 0x2b, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x20, 0x47, 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, ++ 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x53, 0x69, ++ 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x4b, 0x65, 0x79, 0x30, 0x82, 0x02, ++ 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++ 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, ++ 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xb0, 0x2f, 0x50, 0x01, 0x9c, 0x0e, ++ 0xd6, 0x8c, 0x07, 0xca, 0xc1, 0xcf, 0xbc, 0x03, 0xdd, 0xd3, 0xfa, 0xe3, ++ 0x4f, 0x71, 0xc1, 0x30, 0xaa, 0x09, 0x96, 0xe4, 0xd0, 0x6c, 0x42, 0x93, ++ 0xdb, 0x35, 0xf6, 0x7e, 0x1b, 0x67, 0xc0, 0xc2, 0x2d, 0x5b, 0xec, 0xca, ++ 0x35, 0x06, 0x32, 0x6c, 0x7b, 0x2c, 0xd3, 0x71, 0x2b, 0xe9, 0x7a, 0x19, ++ 0xd1, 0xf2, 0xa0, 0x7f, 0xd7, 0x4d, 0x6e, 0x28, 0xbb, 0xae, 0x49, 0x4a, ++ 0xbc, 0xea, 0x47, 0x67, 0xb8, 0x36, 0xa6, 0xf5, 0x0d, 0x0e, 0x20, 0x14, ++ 0x0c, 0x66, 0x67, 0x28, 0xb5, 0x97, 0x8b, 0x1f, 0x5e, 0x32, 0x06, 0x29, ++ 0x9c, 0x99, 0x92, 0x0f, 0x73, 0xac, 0xfd, 0xd2, 0x1d, 0xf2, 0xa8, 0x55, ++ 0x9d, 0x1b, 0xd8, 0x3d, 0xb0, 0x76, 0x9a, 0xb6, 0x6c, 0x9f, 0x62, 0x37, ++ 0x2f, 0xc0, 0xef, 0x44, 0xb3, 0x0d, 0x4a, 0x3e, 0x4f, 0x7d, 0xbd, 0xdb, ++ 0xd8, 0x75, 0x5f, 0x68, 0xe3, 0xf0, 0xec, 0x82, 0x66, 0x7c, 0x31, 0x70, ++ 0xa9, 0xa1, 0x6f, 0x38, 0x9f, 0xdf, 0xf5, 0xf0, 0x7d, 0x23, 0x9d, 0x34, ++ 0xa5, 0x85, 0xd3, 0xdf, 0x68, 0x41, 0xfc, 0x4f, 0x89, 0x45, 0x3c, 0x24, ++ 0x81, 0xa6, 0xf2, 0x3c, 0x02, 0x26, 0x09, 0x48, 0xdd, 0xfe, 0x4b, 0xb6, ++ 0x66, 0xbf, 0x8f, 0xe5, 0x5f, 0xf0, 0x5d, 0x8a, 0x61, 0x2e, 0x5f, 0x9f, ++ 0x80, 0xd9, 0xd5, 0xe6, 0x41, 0xd8, 0x10, 0x5e, 0x7a, 0xc6, 0xdb, 0x89, ++ 0xc7, 0xca, 0x6c, 0x5b, 0xb1, 0x4e, 0x7d, 0x0c, 0x03, 0xfd, 0x50, 0xca, ++ 0xbf, 0xbb, 0xe2, 0x69, 0x4b, 0x4e, 0xc2, 0x3d, 0x75, 0xfa, 0xd1, 0xcc, ++ 0xd6, 0xf9, 0x39, 0xb9, 0xdc, 0x53, 0xad, 0x62, 0xfb, 0x1b, 0x94, 0x26, ++ 0x7f, 0x21, 0x54, 0x5c, 0xb7, 0xdc, 0xe7, 0x96, 0x8c, 0xce, 0x75, 0xe0, ++ 0x17, 0x01, 0x3a, 0x3c, 0x77, 0x6e, 0xa4, 0x8b, 0x7a, 0x83, 0x28, 0x7a, ++ 0xf7, 0xb0, 0x5f, 0xfc, 0x7f, 0x2d, 0x2e, 0xec, 0xf5, 0xeb, 0x9c, 0x63, ++ 0x74, 0xd0, 0xe5, 0xdc, 0x19, 0xe4, 0x71, 0xc5, 0x4a, 0x8a, 0x54, 0xa4, ++ 0xe0, 0x7d, 0x4e, 0xbf, 0x53, 0x30, 0xaf, 0xd0, 0xeb, 0x96, 0xc3, 0xbb, ++ 0x65, 0xf7, 0x67, 0xf5, 0xae, 0xd3, 0x96, 0xf2, 0x63, 0xc8, 0x69, 0xf7, ++ 0x47, 0xcb, 0x27, 0x79, 0xe1, 0xff, 0x2f, 0x68, 0xdf, 0x1e, 0xb3, 0xb8, ++ 0x0c, 0xc5, 0x58, 0x73, 0xcc, 0xfe, 0x8c, 0xda, 0x4e, 0x3b, 0x01, 0x04, ++ 0xcd, 0xcb, 0xb8, 0x3e, 0x06, 0xfd, 0x4c, 0x0a, 0x9f, 0x5e, 0x76, 0x8c, ++ 0x0c, 0x83, 0x75, 0x09, 0x08, 0xb2, 0xdb, 0xf4, 0x49, 0x4e, 0xa0, 0xf2, ++ 0x0c, 0x7b, 0x87, 0x38, 0x9e, 0x22, 0x67, 0xbd, 0xd1, 0x97, 0x57, 0x24, ++ 0xf1, 0x46, 0x07, 0xf9, 0xd2, 0x1b, 0xec, 0x25, 0x5e, 0x67, 0xd9, 0x66, ++ 0x23, 0x1b, 0xd3, 0xe4, 0xaa, 0xec, 0x88, 0xf0, 0x7e, 0x15, 0x83, 0x51, ++ 0x31, 0x67, 0x51, 0x76, 0x5f, 0x55, 0xd7, 0x36, 0xdf, 0x4a, 0x84, 0x0b, ++ 0x6f, 0x5c, 0xbb, 0x5b, 0x8f, 0x37, 0x23, 0x7f, 0xf8, 0x17, 0x84, 0xa2, ++ 0x70, 0x20, 0x07, 0x0c, 0x90, 0x3a, 0x04, 0xfd, 0xf0, 0x08, 0x4a, 0xb1, ++ 0x16, 0x0f, 0xe6, 0xf6, 0x40, 0x51, 0x83, 0xd2, 0x87, 0x40, 0x9c, 0x1c, ++ 0x9f, 0x13, 0x38, 0x17, 0xd3, 0x34, 0x58, 0xad, 0x05, 0x71, 0xa0, 0x73, ++ 0xca, 0x40, 0xa6, 0xa4, 0x81, 0x02, 0xee, 0xa8, 0x72, 0x41, 0xa1, 0x41, ++ 0x18, 0x64, 0x8a, 0x86, 0x8a, 0x5d, 0xe6, 0x4f, 0x0a, 0xc5, 0x95, 0x98, ++ 0xf9, 0x78, 0xfe, 0x19, 0x0d, 0xc9, 0xb3, 0x89, 0xc1, 0x2b, 0x09, 0xbe, ++ 0xf1, 0xd2, 0x04, 0x5d, 0xcc, 0x28, 0xf5, 0x4b, 0xd2, 0x20, 0x4f, 0xc5, ++ 0x41, 0x9d, 0x8c, 0x85, 0xd8, 0xb0, 0x68, 0x5e, 0xc1, 0x0c, 0xb7, 0x24, ++ 0x4d, 0x67, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, ++ 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, ++ 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, ++ 0x07, 0x80, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, ++ 0x14, 0xac, 0xf5, 0x47, 0x17, 0xd9, 0x7d, 0xc1, 0xb1, 0xc4, 0x41, 0xe1, ++ 0x41, 0x60, 0xcb, 0x37, 0x11, 0x60, 0x28, 0x78, 0x5f, 0x30, 0x1f, 0x06, ++ 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x21, 0x94, ++ 0xfb, 0xf9, 0xb2, 0x43, 0xe9, 0x33, 0xd7, 0x50, 0x7d, 0xc7, 0x37, 0xdb, ++ 0xd5, 0x82, 0x5a, 0x4e, 0xbe, 0x1b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, ++ 0x01, 0x00, 0x96, 0x70, 0x65, 0x26, 0x42, 0xf8, 0xdc, 0x69, 0xde, 0xcf, ++ 0x41, 0x3a, 0x2e, 0x7f, 0x5b, 0xf1, 0xf9, 0x3b, 0x9b, 0xd2, 0x4e, 0x64, ++ 0x48, 0x81, 0xe4, 0x5d, 0x1e, 0x22, 0xce, 0x68, 0x63, 0x62, 0xe5, 0x1b, ++ 0x9b, 0xf2, 0xc7, 0x12, 0xda, 0x1e, 0x9b, 0x90, 0x84, 0x79, 0x48, 0x12, ++ 0xe6, 0x21, 0x6f, 0x2f, 0x7e, 0x18, 0x77, 0xdb, 0x8c, 0xc4, 0xd1, 0x0d, ++ 0x91, 0xbf, 0x39, 0x22, 0x0f, 0x64, 0xcf, 0x25, 0x2e, 0x8c, 0x1f, 0x91, ++ 0x81, 0xb5, 0xe9, 0x6c, 0x02, 0x3a, 0xf8, 0x07, 0xa2, 0x6f, 0x46, 0x5d, ++ 0x7b, 0xfd, 0x43, 0xff, 0x41, 0x0f, 0xe2, 0x57, 0x1c, 0xbd, 0x48, 0x60, ++ 0x53, 0x11, 0x48, 0x87, 0x88, 0x9d, 0x13, 0x82, 0x40, 0x68, 0x44, 0x2c, ++ 0xc6, 0xc8, 0x95, 0x27, 0x4f, 0xb6, 0xb9, 0x4a, 0x22, 0x0a, 0xfd, 0xe4, ++ 0x46, 0x8f, 0x35, 0x12, 0x98, 0x5a, 0x34, 0x6f, 0x2b, 0x57, 0x62, 0xa1, ++ 0x4d, 0x8d, 0x79, 0x37, 0xe4, 0x6b, 0x8a, 0x32, 0x5b, 0xcb, 0xef, 0x79, ++ 0x11, 0xed, 0xa7, 0xf8, 0x7a, 0x1c, 0xbd, 0x86, 0xdc, 0x0e, 0x2e, 0xfd, ++ 0xd3, 0x51, 0xbb, 0x73, 0xad, 0x00, 0xa0, 0x1b, 0xf9, 0x1d, 0xd1, 0x4a, ++ 0xe4, 0xd4, 0x02, 0x63, 0x2b, 0x39, 0x5f, 0x18, 0x08, 0x2f, 0x42, 0xb7, ++ 0x23, 0x4b, 0x48, 0x46, 0x1f, 0x63, 0x87, 0xae, 0x6d, 0xd5, 0xdb, 0x60, ++ 0xf8, 0x5f, 0xd3, 0x13, 0xec, 0xca, 0xdd, 0x60, 0x60, 0x79, 0x52, 0x70, ++ 0x47, 0xae, 0x1d, 0x38, 0x78, 0x71, 0xcf, 0xb3, 0x04, 0x03, 0xbe, 0xba, ++ 0x81, 0xba, 0x74, 0xb1, 0x30, 0x35, 0xdc, 0xea, 0x21, 0x4a, 0x9b, 0x70, ++ 0xfb, 0xd6, 0x60, 0x59, 0x78, 0x0c, 0x4d, 0x39, 0x19, 0x1d, 0xe5, 0x75, ++ 0xba, 0x07, 0xf4, 0x22, 0x37, 0x64, 0xb7, 0xf2, 0x9a, 0xc9, 0x11, 0x2d, ++ 0x8e, 0x58, 0xa6, 0xcf, 0x83, 0xf1, 0xcb, 0x6c, 0x7f, 0x02, 0xbd, 0xda, ++ 0x03, 0x92, 0xa9, 0x45, 0x24, 0x56, 0xc5, 0xbd, 0x41, 0xd1, 0x20, 0x86, ++ 0xc0, 0xb6, 0xb7, 0xe8, 0xa7, 0xb2, 0x46, 0xf7, 0x8e, 0xa9, 0x38, 0x0e, ++ 0x23, 0x77, 0x3c, 0x0d, 0x66, 0x83, 0x6a, 0x1a, 0x6b, 0x7f, 0x54, 0x11, ++ 0x58, 0x0d, 0x4a, 0xb5, 0x74, 0x60, 0xca, 0xed, 0xff, 0x91, 0x47, 0xd9, ++ 0x29, 0xe0, 0xaa, 0x8c, 0xa8, 0x8f, 0x10, 0x4c, 0x15, 0x7d, 0xce, 0x95, ++ 0xf9, 0x87, 0x1e, 0x18, 0x38, 0x18, 0xfc, 0xcc, 0xaf, 0x91, 0x17, 0x3f, ++ 0xfa, 0xf0, 0x8a, 0x09, 0x6f, 0xba, 0x4e, 0x53, 0xf7, 0xfa, 0x4f, 0x20, ++ 0xa3, 0xf4, 0x4a, 0x5a, 0xde, 0x17, 0x1c, 0x29, 0x6a, 0x6f, 0x03, 0x48, ++ 0xdf, 0xad, 0x4f, 0xe4, 0xbc, 0x71, 0xc4, 0x72, 0x32, 0x11, 0x84, 0xac, ++ 0x09, 0xd2, 0x18, 0x44, 0x35, 0xf1, 0xcd, 0xaf, 0xa8, 0x98, 0xe0, 0x8b, ++ 0xec, 0xa0, 0x83, 0x37, 0xc3, 0x35, 0x85, 0xd6, 0xd8, 0x1b, 0xe0, 0x75, ++ 0xdc, 0xfd, 0xde, 0xc9, 0xeb, 0xd5, 0x18, 0x0f, 0xd3, 0x4c, 0x2f, 0x71, ++ 0xdc, 0x48, 0xe3, 0x14, 0xeb, 0xda, 0x00, 0x24, 0x24, 0x9e, 0xa3, 0x8e, ++ 0x3e, 0x08, 0x6f, 0x22, 0x24, 0xd6, 0xc4, 0x85, 0x8f, 0x68, 0x00, 0x4a, ++ 0x82, 0x4c, 0x33, 0x6e, 0xa5, 0x35, 0x7b, 0xeb, 0x4b, 0xdc, 0xa0, 0xa6, ++ 0x65, 0x6f, 0x5a, 0x7a, 0xdf, 0x8a, 0x01, 0x52, 0xa1, 0x6c, 0xff, 0x59, ++ 0x22, 0x7f, 0xe1, 0x96, 0x1b, 0x19, 0xb8, 0xf9, 0x5d, 0x44, 0x9f, 0x91, ++ 0x03, 0x3c, 0x3d, 0xa1, 0x2a, 0xb6, 0x5a, 0x51, 0xa0, 0xce, 0x4a, 0x88, ++ 0x22, 0x72, 0x9c, 0xdc, 0xc0, 0x47, 0x76, 0x35, 0x84, 0x75, 0x9b, 0x87, ++ 0x5c, 0xd3, 0xcf, 0xe7, 0xdd, 0xa3, 0x57, 0x14, 0xdf, 0x00, 0xfd, 0x19, ++ 0x2a, 0x7d, 0x89, 0x27, 0x1c, 0x78, 0x97, 0x04, 0x58, 0x48 ++}; ++unsigned int certificate2_der_len = 1366; ++ ++unsigned char hi_signed_2nd[] = { ++ 0x68, 0x69, 0x0a, 0x30, 0x82, 0x02, 0xb1, 0x06, 0x09, 0x2a, 0x86, 0x48, ++ 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x02, 0xa2, 0x30, 0x82, ++ 0x02, 0x9e, 0x02, 0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, ++ 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0b, 0x06, 0x09, ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x31, 0x82, 0x02, ++ 0x7b, 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x01, 0x30, 0x52, 0x30, 0x3a, ++ 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x47, ++ 0x72, 0x75, 0x62, 0x20, 0x32, 0x6e, 0x64, 0x20, 0x43, 0x65, 0x72, 0x74, ++ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x54, 0x65, 0x73, 0x74, ++ 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, ++ 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x02, 0x14, ++ 0x5b, 0x5e, 0x59, 0xf2, 0x5f, 0x75, 0x4c, 0x8e, 0xc5, 0x3a, 0x91, 0x07, ++ 0xe9, 0xe7, 0x6d, 0x3c, 0xd0, 0x7f, 0x91, 0xff, 0x30, 0x0b, 0x06, 0x09, ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30, 0x0d, 0x06, ++ 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, ++ 0x04, 0x82, 0x02, 0x00, 0x0e, 0xc2, 0x30, 0x38, 0x81, 0x23, 0x68, 0x90, ++ 0xae, 0x5f, 0xce, 0xf7, 0x27, 0xb1, 0x8c, 0x2e, 0x12, 0x10, 0xc6, 0x99, ++ 0xdc, 0x4d, 0x4b, 0x79, 0xda, 0xe4, 0x32, 0x10, 0x46, 0x1c, 0x16, 0x07, ++ 0x87, 0x66, 0x55, 0xff, 0x64, 0x1c, 0x61, 0x25, 0xd5, 0xb9, 0xe1, 0xfe, ++ 0xea, 0x5a, 0xcd, 0x56, 0xa5, 0xc3, 0xbe, 0xb1, 0x61, 0xc7, 0x6f, 0x5f, ++ 0x69, 0x20, 0x64, 0x50, 0x6f, 0x12, 0x78, 0xb6, 0x0c, 0x72, 0x44, 0x4f, ++ 0x60, 0x0f, 0x9f, 0xa2, 0x83, 0x3b, 0xc2, 0x83, 0xd5, 0x14, 0x1f, 0x6f, ++ 0x3e, 0xb2, 0x47, 0xb5, 0x58, 0xc5, 0xa7, 0xb4, 0x82, 0x53, 0x2e, 0x53, ++ 0x95, 0x4e, 0x3d, 0xe4, 0x62, 0xe8, 0xa1, 0xaf, 0xae, 0xbf, 0xa9, 0xd2, ++ 0x22, 0x07, 0xbe, 0x71, 0x37, 0x2c, 0x5a, 0xa7, 0x6c, 0xaf, 0x14, 0xc0, ++ 0x6c, 0x2f, 0xbf, 0x4f, 0x15, 0xc2, 0x0f, 0x8b, 0xdc, 0x68, 0x45, 0xdf, ++ 0xf3, 0xa5, 0x7f, 0x11, 0x6a, 0x54, 0xcd, 0x67, 0xb9, 0x2e, 0x7d, 0x05, ++ 0xe3, 0x1c, 0x1d, 0xcc, 0x77, 0x8e, 0x97, 0xb1, 0xa0, 0x11, 0x09, 0x3d, ++ 0x90, 0x54, 0xfc, 0x7e, 0xbb, 0xbb, 0x21, 0x23, 0x03, 0x44, 0xbf, 0x7d, ++ 0x2c, 0xc9, 0x15, 0x42, 0xe5, 0xa0, 0x3b, 0xa2, 0xd1, 0x5b, 0x73, 0x81, ++ 0xff, 0xfa, 0x90, 0xfc, 0x27, 0x7b, 0x2f, 0x86, 0x9c, 0x1d, 0x14, 0x36, ++ 0x94, 0xa2, 0x6e, 0xe8, 0x9d, 0xa0, 0x5f, 0xfc, 0x5a, 0x0d, 0xa4, 0xd5, ++ 0x2f, 0x8d, 0xd6, 0x00, 0xfa, 0x93, 0x5b, 0x09, 0x7f, 0x42, 0x78, 0xcc, ++ 0x8c, 0x49, 0xda, 0xd9, 0xf6, 0x43, 0xe7, 0xe1, 0x3c, 0xa2, 0xe2, 0x70, ++ 0xe2, 0x6a, 0x99, 0xc5, 0xd6, 0xa2, 0xe3, 0x0b, 0xd4, 0x09, 0xac, 0x94, ++ 0xaf, 0xb7, 0xf0, 0xb3, 0x0c, 0x1e, 0xf5, 0x16, 0x4f, 0x53, 0x9a, 0xe3, ++ 0xcc, 0xe2, 0x0c, 0x4a, 0xb9, 0xe6, 0x06, 0xbb, 0xf7, 0x41, 0x43, 0x20, ++ 0x04, 0xee, 0x99, 0x2f, 0xd8, 0x9f, 0xda, 0x3f, 0xfd, 0x49, 0xb8, 0xc2, ++ 0xbd, 0xd9, 0xc5, 0x72, 0xfd, 0xe3, 0xce, 0x1c, 0xbc, 0xe4, 0x39, 0xac, ++ 0x2a, 0x99, 0xe9, 0xb4, 0x3e, 0x74, 0x10, 0xeb, 0xd5, 0x14, 0xcc, 0xdb, ++ 0xf1, 0x04, 0x63, 0x36, 0xfb, 0x1f, 0x2b, 0xe2, 0x73, 0xd4, 0xd8, 0x49, ++ 0x31, 0xa8, 0x55, 0xcc, 0xa7, 0x76, 0x36, 0x6e, 0x18, 0xdc, 0xb9, 0xb0, ++ 0x29, 0x99, 0xcf, 0x49, 0xbf, 0xf9, 0xdb, 0x7f, 0x24, 0x42, 0x02, 0xcb, ++ 0xc1, 0xaa, 0xcb, 0xba, 0x18, 0x85, 0x86, 0xc7, 0xf4, 0x1c, 0x62, 0x76, ++ 0xbc, 0x73, 0xfb, 0xe4, 0x15, 0xb8, 0xdd, 0x5d, 0xa6, 0x68, 0x39, 0xa5, ++ 0x3d, 0x33, 0xaf, 0xd5, 0x92, 0x4d, 0x48, 0xdb, 0x22, 0xc0, 0xdc, 0x49, ++ 0x5f, 0x7b, 0xa8, 0xd2, 0x62, 0x2d, 0xa7, 0x39, 0x93, 0x48, 0xe7, 0x6b, ++ 0x23, 0xba, 0xd4, 0xe0, 0xc1, 0x29, 0x55, 0xc4, 0x34, 0xe3, 0xac, 0x25, ++ 0xa7, 0x15, 0xad, 0xab, 0xb3, 0xb7, 0x25, 0xca, 0x37, 0x88, 0x40, 0x2e, ++ 0x47, 0x6e, 0x92, 0x20, 0x09, 0x2e, 0x5a, 0xec, 0xf2, 0xfb, 0xb3, 0xa0, ++ 0x16, 0xb6, 0x93, 0xf2, 0xf5, 0x8b, 0xfe, 0xaf, 0x25, 0xee, 0x2e, 0x98, ++ 0x6c, 0x0a, 0xfe, 0xae, 0x0b, 0x57, 0xf5, 0x9f, 0x3c, 0x80, 0xe9, 0x8b, ++ 0xaf, 0x92, 0x8a, 0xad, 0xe7, 0xa0, 0xe4, 0xe6, 0x0a, 0xa0, 0xc7, 0x83, ++ 0xb5, 0x48, 0x58, 0x5f, 0x55, 0x9e, 0x9b, 0x27, 0xcd, 0x31, 0x1f, 0x3e, ++ 0x50, 0x5a, 0x91, 0xad, 0x21, 0x1b, 0x97, 0x5b, 0xe8, 0xfa, 0x29, 0x8a, ++ 0xa4, 0x17, 0xe8, 0xab, 0x87, 0x02, 0xd6, 0x18, 0x8c, 0x9f, 0x65, 0xb7, ++ 0x2a, 0xfa, 0xde, 0x5f, 0x77, 0x30, 0x6c, 0x04, 0x22, 0xe6, 0x58, 0x26, ++ 0x14, 0x0d, 0x9c, 0x41, 0x0a, 0x82, 0x77, 0xdb, 0x40, 0xa1, 0x58, 0xac, ++ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xb5, ++ 0x7e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x20, 0x73, 0x69, 0x67, 0x6e, ++ 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x61, 0x70, 0x70, 0x65, 0x6e, 0x64, ++ 0x65, 0x64, 0x7e, 0x0a ++}; ++unsigned int hi_signed_2nd_len = 736; ++ ++unsigned char certificate_printable_der[] = { ++ 0x30, 0x82, 0x03, 0x39, 0x30, 0x82, 0x02, 0x21, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xde, 0xf6, 0x22, 0xc4, 0xf2, 0xf1, 0x86, 0x02, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x2a, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x13, 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x32, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, ++ 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x30, 0x33, 0x31, 0x31, 0x34, 0x31, ++ 0x39, 0x32, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x37, 0x31, 0x30, 0x32, 0x35, ++ 0x31, 0x34, 0x31, 0x39, 0x32, 0x33, 0x5a, 0x30, 0x2f, 0x31, 0x2d, 0x30, ++ 0x2b, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x24, 0x52, 0x65, 0x64, 0x20, ++ 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, ++ 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, ++ 0x33, 0x20, 0x28, 0x62, 0x65, 0x74, 0x61, 0x29, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xbd, 0xda, 0xa1, 0xed, 0x8d, 0x8e, 0x15, ++ 0x5c, 0xf8, 0x01, 0x77, 0x48, 0x4a, 0x60, 0x96, 0xf9, 0x27, 0xfa, 0xe2, ++ 0xb1, 0x69, 0x0f, 0x51, 0x19, 0x52, 0x7e, 0xc4, 0x34, 0x8e, 0xe1, 0x9b, ++ 0x9c, 0xa4, 0xb1, 0x5c, 0xd6, 0x81, 0x98, 0x78, 0xfe, 0xa9, 0xe5, 0x0b, ++ 0x00, 0xba, 0x9c, 0x64, 0x7e, 0xc7, 0xcc, 0x72, 0xb1, 0x73, 0x4b, 0x11, ++ 0x07, 0x52, 0xf0, 0x20, 0x96, 0x8b, 0x99, 0x39, 0xde, 0xdb, 0xfa, 0x3d, ++ 0x45, 0xe2, 0x98, 0x7b, 0x0c, 0x41, 0xe4, 0x0c, 0xb5, 0x5d, 0x92, 0x74, ++ 0x39, 0x96, 0xe1, 0x97, 0x97, 0xa1, 0xad, 0x2e, 0xcc, 0xd0, 0x1b, 0x4d, ++ 0x9d, 0xbd, 0x3e, 0xa9, 0x36, 0x8e, 0xcc, 0xc7, 0x5f, 0x6a, 0x7d, 0x39, ++ 0x5e, 0x0b, 0x8d, 0xca, 0xe4, 0x83, 0xe9, 0x3b, 0x5c, 0x86, 0x47, 0xd4, ++ 0xba, 0x7d, 0x98, 0x26, 0xa1, 0xf4, 0xe8, 0x90, 0x6b, 0x0f, 0xf1, 0x6b, ++ 0x8c, 0xe3, 0xa2, 0x80, 0x3c, 0x96, 0xf1, 0x0a, 0xb6, 0x66, 0xc0, 0x4b, ++ 0x61, 0xf7, 0x74, 0xcd, 0xd3, 0x7b, 0x8e, 0x5e, 0x39, 0xda, 0x99, 0x20, ++ 0x33, 0x93, 0xd3, 0xf0, 0x7f, 0xad, 0x35, 0xe9, 0x88, 0x8d, 0x9c, 0xbf, ++ 0x65, 0xf1, 0x47, 0x02, 0xf9, 0x7c, 0xed, 0x27, 0x5f, 0x4a, 0x65, 0x3c, ++ 0xcf, 0x5f, 0x0e, 0x88, 0x95, 0x74, 0xde, 0xfb, 0x9e, 0x2e, 0x91, 0x9b, ++ 0x45, 0x37, 0xc8, 0x85, 0xff, 0xe3, 0x41, 0x70, 0xfe, 0xd5, 0xef, 0x0e, ++ 0x82, 0x22, 0x08, 0xb7, 0x3b, 0x44, 0x3e, 0xdc, 0x5b, 0x7f, 0xba, 0xbf, ++ 0xe6, 0x58, 0x9d, 0x02, 0x6e, 0x75, 0xbf, 0x50, 0xec, 0xcf, 0x3f, 0xa5, ++ 0x91, 0x0a, 0xe2, 0x59, 0x2c, 0xc3, 0xe7, 0x05, 0x03, 0xe8, 0xf2, 0x6f, ++ 0x2a, 0x04, 0x68, 0x9a, 0x31, 0x32, 0x8f, 0x04, 0x35, 0xcd, 0x1f, 0x34, ++ 0xcc, 0x4f, 0x79, 0x5a, 0x99, 0x8d, 0x9d, 0x5c, 0xf5, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x5d, 0x30, 0x5b, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x1d, 0x06, ++ 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x65, 0xc5, 0xbe, 0xca, ++ 0xe6, 0x59, 0x6a, 0xfd, 0x6c, 0x71, 0xc4, 0xa7, 0x98, 0xc6, 0x25, 0x8d, ++ 0x7b, 0x67, 0x05, 0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, ++ 0x18, 0x30, 0x16, 0x80, 0x14, 0x81, 0xf8, 0xee, 0x47, 0x5c, 0x3e, 0xed, ++ 0xfb, 0xce, 0xa5, 0x84, 0xbe, 0xd7, 0xae, 0xdb, 0xd3, 0x7d, 0x64, 0xb3, ++ 0x2a, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, ++ 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x66, 0x1e, 0x3d, ++ 0x1d, 0x53, 0x33, 0xde, 0x4e, 0xc7, 0xc4, 0xf4, 0xdf, 0xda, 0x18, 0x19, ++ 0x8a, 0xa9, 0xff, 0xe2, 0x63, 0x2b, 0xbe, 0xf2, 0x61, 0x63, 0xe2, 0xf6, ++ 0xed, 0x47, 0x1a, 0x71, 0x02, 0xec, 0x2a, 0xef, 0x89, 0x77, 0xe3, 0xfd, ++ 0x86, 0x69, 0xf1, 0x3f, 0x0d, 0xf9, 0x6e, 0xf9, 0x3b, 0xad, 0x26, 0x47, ++ 0xb7, 0xf2, 0x0d, 0xad, 0x23, 0xa3, 0x67, 0x3b, 0xcb, 0x6d, 0x9e, 0x03, ++ 0x0f, 0xbc, 0x69, 0x73, 0x9f, 0xd4, 0xa5, 0x0f, 0x6f, 0xf8, 0xab, 0x4d, ++ 0x36, 0xd1, 0xe0, 0xe0, 0x5d, 0x20, 0x43, 0x90, 0xc4, 0x65, 0x61, 0x93, ++ 0xe2, 0x0f, 0x51, 0x59, 0x0a, 0xf7, 0x88, 0x70, 0x57, 0xb9, 0x04, 0xa9, ++ 0x32, 0x57, 0x9c, 0xb3, 0x57, 0x38, 0x8b, 0x8e, 0x46, 0xc8, 0x32, 0x6c, ++ 0xb4, 0xf3, 0x96, 0x7f, 0x4b, 0xf0, 0x88, 0xf9, 0x7f, 0xe2, 0x71, 0xe1, ++ 0x8b, 0xe2, 0x14, 0xf1, 0x4b, 0x25, 0x00, 0x48, 0x1c, 0x7e, 0xe5, 0x8d, ++ 0x65, 0x2d, 0xeb, 0x72, 0x4f, 0x92, 0x44, 0xf3, 0xe6, 0xe0, 0xd0, 0xdf, ++ 0x85, 0xa8, 0x13, 0x4a, 0xfb, 0x99, 0xca, 0x14, 0x2c, 0x97, 0x80, 0x93, ++ 0x27, 0xd3, 0x20, 0xf8, 0x6d, 0x29, 0x28, 0x2c, 0xb9, 0x77, 0xea, 0xb1, ++ 0x63, 0xbd, 0x7d, 0x53, 0xfd, 0x4a, 0x62, 0x64, 0x0b, 0x98, 0xa8, 0xae, ++ 0x11, 0xfc, 0x6e, 0x8d, 0x63, 0xd4, 0x15, 0x55, 0xc6, 0x4c, 0x74, 0xf5, ++ 0x5f, 0xa0, 0xb9, 0x2c, 0x2d, 0x9a, 0x7a, 0x87, 0x6e, 0xf0, 0x5e, 0x25, ++ 0xed, 0xfc, 0xd8, 0xc4, 0x34, 0x33, 0x32, 0xad, 0x01, 0xd4, 0x4b, 0x49, ++ 0x51, 0xc2, 0x07, 0x7f, 0x90, 0x6d, 0xea, 0xf5, 0x4c, 0x41, 0x71, 0x64, ++ 0xeb, 0x1f, 0x29, 0xa3, 0x1f, 0x64, 0xa2, 0x1e, 0x0e, 0x6f, 0xa1, 0x67, ++ 0x99, 0x8d, 0x98, 0x1c, 0xb8, 0x53, 0x9d, 0x30, 0x1d, 0xae, 0x32, 0x56, ++ 0xd2 ++}; ++unsigned int certificate_printable_der_len = 829; diff --git a/SOURCES/0172-appended-signatures-documentation.patch b/SOURCES/0172-appended-signatures-documentation.patch new file mode 100644 index 0000000..eb58046 --- /dev/null +++ b/SOURCES/0172-appended-signatures-documentation.patch @@ -0,0 +1,341 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 1 Oct 2020 13:02:09 +1000 +Subject: [PATCH] appended signatures: documentation + +This explains how appended signatures can be used to form part of +a secure boot chain, and documents the commands and variables +introduced. + +Signed-off-by: Daniel Axtens +--- + docs/grub.texi | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 182 insertions(+), 17 deletions(-) + +diff --git a/docs/grub.texi b/docs/grub.texi +index afbde7c1f7..4816be8561 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -3214,6 +3214,7 @@ These variables have special meaning to GRUB. + + @menu + * biosnum:: ++* check_appended_signatures:: + * check_signatures:: + * chosen:: + * cmdpath:: +@@ -3273,11 +3274,18 @@ For an alternative approach which also changes BIOS drive mappings for the + chain-loaded system, @pxref{drivemap}. + + ++@node check_appended_signatures ++@subsection check_appended_signatures ++ ++This variable controls whether GRUB enforces appended signature validation on ++certain loaded files. @xref{Using appended signatures}. ++ ++ + @node check_signatures + @subsection check_signatures + +-This variable controls whether GRUB enforces digital signature +-validation on loaded files. @xref{Using digital signatures}. ++This variable controls whether GRUB enforces GPG-style digital signature ++validation on loaded files. @xref{Using GPG-style digital signatures}. + + @node chosen + @subsection chosen +@@ -3994,6 +4002,7 @@ you forget a command, you can run the command @command{help} + * date:: Display or set current date and time + * devicetree:: Load a device tree blob + * distrust:: Remove a pubkey from trusted keys ++* distrust_certificate:: Remove a certificate from the list of trusted certificates + * drivemap:: Map a drive to another + * echo:: Display a line of text + * eval:: Evaluate agruments as GRUB commands +@@ -4010,6 +4019,7 @@ you forget a command, you can run the command @command{help} + * keystatus:: Check key modifier status + * linux:: Load a Linux kernel + * linux16:: Load a Linux kernel (16-bit mode) ++* list_certificates:: List trusted certificates + * list_env:: List variables in environment block + * list_trusted:: List trusted public keys + * load_env:: Load variables from environment block +@@ -4047,8 +4057,10 @@ you forget a command, you can run the command @command{help} + * test:: Check file types and compare values + * true:: Do nothing, successfully + * trust:: Add public key to list of trusted keys ++* trust_certificate:: Add an x509 certificate to the list of trusted certificates + * unset:: Unset an environment variable + @comment * vbeinfo:: List available video modes ++* verify_appended:: Verify appended digital signature + * verify_detached:: Verify detached digital signature + * videoinfo:: List available video modes + @comment * xen_*:: Xen boot commands for AArch64 +@@ -4376,9 +4388,28 @@ These keys are used to validate signatures when environment variable + @code{check_signatures} is set to @code{enforce} + (@pxref{check_signatures}), and by some invocations of + @command{verify_detached} (@pxref{verify_detached}). @xref{Using +-digital signatures}, for more information. ++GPG-style digital signatures}, for more information. + @end deffn + ++ ++@node distrust_certificate ++@subsection distrust_certificate ++ ++@deffn Command distrust_certificate cert_number ++Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of ++trusted x509 certificates for verifying appended signatures. ++ ++@var{cert_number} is the certificate number as listed by ++@command{list_certificates} (@pxref{list_certificates}). ++ ++These certificates are used to validate appended signatures when environment ++variable @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced} (@pxref{check_appended_signatures}), and by ++@command{verify_appended} (@pxref{verify_appended}). See ++@xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node drivemap + @subsection drivemap + +@@ -4636,6 +4667,21 @@ This command is only available on x86 systems. + @end deffn + + ++@node list_certificates ++@subsection list_certificates ++ ++@deffn Command list_certificates ++List all x509 certificates trusted by GRUB for validating appended signatures. ++The output is a numbered list of certificates, showing the certificate's serial ++number and Common Name. ++ ++The certificate number can be used as an argument to ++@command{distrust_certificate} (@pxref{distrust_certificate}). ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node list_env + @subsection list_env + +@@ -4655,7 +4701,7 @@ The output is in GPG's v4 key fingerprint format (i.e., the output of + @code{gpg --fingerprint}). The least significant four bytes (last + eight hexadecimal digits) can be used as an argument to + @command{distrust} (@pxref{distrust}). +-@xref{Using digital signatures}, for more information about uses for ++@xref{Using GPG-style digital signatures}, for more information about uses for + these keys. + @end deffn + +@@ -4690,8 +4736,13 @@ When used with care, @option{--skip-sig} and the whitelist enable an + administrator to configure a system to boot only signed + configurations, but to allow the user to select from among multiple + configurations, and to enable ``one-shot'' boot attempts and +-``savedefault'' behavior. @xref{Using digital signatures}, for more ++``savedefault'' behavior. @xref{Using GPG-style digital signatures}, for more + information. ++ ++Extra care should be taken when combining this command with appended signatures ++(@pxref{Using appended signatures}), as this file is not validated by an ++appended signature and could set @code{check_appended_signatures=no} if GRUB is ++not in @pxref{Lockdown} mode. + @end deffn + + +@@ -4987,7 +5038,7 @@ read. It is possible to modify a digitally signed environment block + file from within GRUB using this command, such that its signature will + no longer be valid on subsequent boots. Care should be taken in such + advanced configurations to avoid rendering the system +-unbootable. @xref{Using digital signatures}, for more information. ++unbootable. @xref{Using GPG-style digital signatures}, for more information. + @end deffn + + +@@ -5387,11 +5438,32 @@ signatures when environment variable @code{check_signatures} is set to + must itself be properly signed. The @option{--skip-sig} option can be + used to disable signature-checking when reading @var{pubkey_file} + itself. It is expected that @option{--skip-sig} is useful for testing +-and manual booting. @xref{Using digital signatures}, for more ++and manual booting. @xref{Using GPG-style digital signatures}, for more + information. + @end deffn + + ++@node trust_certificate ++@subsection trust_certificate ++ ++@deffn Command trust_certificate x509_certificate ++Read an DER-formatted x509 certificate from the file @var{x509_certificate} ++and add it to GRUB's internal list of trusted x509 certificates. These ++certificates are used to validate appended signatures when the environment ++variable @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced}. ++ ++Note that if @code{check_appended_signatures} is set to @code{enforce} or ++@code{forced} when @command{trust_certificate} is executed, then ++@var{x509_certificate} must itself bear an appended signature. (It is not ++sufficient that @var{x509_certificate} be signed by a trusted certificate ++according to the x509 rules: grub does not include support for validating ++signatures within x509 certificates themselves.) ++ ++See @xref{Using appended signatures} for more information. ++@end deffn ++ ++ + @node unset + @subsection unset + +@@ -5410,6 +5482,18 @@ only on PC BIOS platforms. + @end deffn + @end ignore + ++@node verify_appended ++@subsection verify_appended ++ ++@deffn Command verify_appended file ++Verifies an appended signature on @var{file} against the trusted certificates ++known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and ++@pxref{distrust_certificate}). ++ ++Exit code @code{$?} is set to 0 if the signature validates ++successfully. If validation fails, it is set to a non-zero value. ++See @xref{Using appended signatures}, for more information. ++@end deffn + + @node verify_detached + @subsection verify_detached +@@ -5428,7 +5512,7 @@ tried. + + Exit code @code{$?} is set to 0 if the signature validates + successfully. If validation fails, it is set to a non-zero value. +-@xref{Using digital signatures}, for more information. ++@xref{Using GPG-style digital signatures}, for more information. + @end deffn + + @node videoinfo +@@ -5811,13 +5895,14 @@ environment variables and commands are listed in the same order. + @chapter Security + + @menu +-* Authentication and authorisation:: Users and access control +-* Using digital signatures:: Booting digitally signed code +-* UEFI secure boot and shim:: Booting digitally signed PE files +-* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation +-* Measured Boot:: Measuring boot components +-* Lockdown:: Lockdown when booting on a secure setup +-* Signing GRUB itself:: Ensuring the integrity of the GRUB core image ++* Authentication and authorisation:: Users and access control ++* Using GPG-style digital signatures:: Booting digitally signed code ++* Using appended signatures:: An alternative approach to booting digitally signed code ++* UEFI secure boot and shim:: Booting digitally signed PE files ++* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation ++* Measured Boot:: Measuring boot components ++* Lockdown:: Lockdown when booting on a secure setup ++* Signing GRUB itself:: Ensuring the integrity of the GRUB core image + @end menu + + @node Authentication and authorisation +@@ -5891,8 +5976,8 @@ generating configuration files with authentication. You can use + adding @kbd{set superusers=} and @kbd{password} or @kbd{password_pbkdf2} + commands. + +-@node Using digital signatures +-@section Using digital signatures in GRUB ++@node Using GPG-style digital signatures ++@section Using GPG-style digital signatures in GRUB + + GRUB's @file{core.img} can optionally provide enforcement that all files + subsequently read from disk are covered by a valid digital signature. +@@ -5985,6 +6070,86 @@ or BIOS) configuration to cause the machine to boot from a different + (attacker-controlled) device. GRUB is at best only one link in a + secure boot chain. + ++@node Using appended signatures ++@section Using appended signatures in GRUB ++ ++GRUB supports verifying Linux-style 'appended signatures' for secure boot. ++Appended signatures are PKCS#7 messages containing a signature over the ++contents of a file, plus some metadata, appended to the end of a file. A file ++with an appended signature ends with the magic string: ++ ++@example ++~Module signature appended~\n ++@end example ++ ++where @code{\n} represents the line-feed character, @code{0x0a}. ++ ++Certificates can be managed at boot time using the @pxref{trust_certificate}, ++@pxref{distrust_certificate} and @pxref{list_certificates} commands. ++Certificates can also be built in to the core image using the @code{--x509} ++parameter to @command{grub-install} or @command{grub-mkimage}. ++ ++A file can be explictly verified using the @pxref{verify_appended} command. ++ ++Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported, ++and only RSA signatures are supported. ++ ++A file can be signed with the @command{sign-file} utility supplied with the ++Linux kernel source. For example, if you have @code{signing.key} as the private ++key and @code{certificate.der} as the x509 certificate containing the public key: ++ ++@example ++sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed ++@end example ++ ++Enforcement of signature verification is controlled by the ++@code{check_appended_signatures} variable. ++ ++@itemize ++@item @samp{no}: no verification is performed. This is the default when GRUB ++ is not in @pxref{Lockdown} mode. ++@item @samp{enforce}: verification is performed. Verification can be disabled ++ by setting the variable back to @samp{no}. ++@item @samp{forced}: verification is performed and cannot be disabled. This is ++ set when GRUB is in Lockdown when the appendedsig module is loaded. ++@end itemize ++ ++Unlike GPG-style signatures, not all files loaded by GRUB are required to be ++signed. Once verification is turned on, the following file types will have ++appended signatures verified: ++ ++@itemize ++@item Linux kernels ++@item GRUB modules, except those built into the core image ++@item Any new certificate files to be trusted ++@end itemize ++ ++ACPI tables and Device Tree images will not be checked for appended signatures ++but must be verified by another mechanism such as GPG-style signatures before ++they will be loaded. ++ ++Unless lockdown mode is enabled, signature checking does @strong{not} ++stop an attacker with console access from dropping manually to the GRUB ++console and executing: ++ ++@example ++set check_appended_signatures=no ++@end example ++ ++Refer to the section on password-protecting GRUB (@pxref{Authentication ++and authorisation}) for more information on preventing this. ++ ++Additionally, unless lockdown mode is enabled: ++ ++@itemize ++@item Special care must be taken around the @command{loadenv} command, which ++ can be used to turn off @code{check_appended_signature}. ++ ++@item If the grub configuration file is loaded from the disk, anyone who can ++ modify the file on disk can turn off @code{check_appended_signature}. ++ Consider embedding the configuration into the core grub image. ++@end itemize ++ + @node UEFI secure boot and shim + @section UEFI secure boot and shim support + diff --git a/SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch b/SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch new file mode 100644 index 0000000..c90cc7e --- /dev/null +++ b/SOURCES/0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch @@ -0,0 +1,109 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Sep 2020 11:11:17 +1000 +Subject: [PATCH] ieee1275: enter lockdown based on /ibm,secure-boot + +If the 'ibm,secure-boot' property of the root node is 2 or greater, +enter lockdown. + +Signed-off-by: Daniel Axtens +--- + grub-core/Makefile.core.def | 1 + + grub-core/kern/ieee1275/init.c | 27 +++++++++++++++++++++++++++ + include/grub/lockdown.h | 3 ++- + docs/grub.texi | 4 ++-- + 4 files changed, 32 insertions(+), 3 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 9ea5fb38f1..4a57de975e 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -323,6 +323,7 @@ kernel = { + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; ++ powerpc_ieee1275 = kern/lockdown.c; + + sparc64_ieee1275 = kern/sparc64/cache.S; + sparc64_ieee1275 = kern/sparc64/dl.c; +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 937c1bc44c..fc7d971272 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -44,6 +44,7 @@ + #ifdef __sparc__ + #include + #endif ++#include + + /* The minimal heap size we can live with. */ + #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) +@@ -271,6 +272,30 @@ grub_parse_cmdline (void) + } + } + ++static void ++grub_get_ieee1275_secure_boot (void) ++{ ++ grub_ieee1275_phandle_t root; ++ int rc; ++ grub_uint32_t is_sb; ++ ++ grub_ieee1275_finddevice ("/", &root); ++ ++ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb, ++ sizeof (is_sb), 0); ++ ++ /* ibm,secure-boot: ++ * 0 - disabled ++ * 1 - audit ++ * 2 - enforce ++ * 3 - enforce + OS-specific behaviour ++ * ++ * We only support enforce. ++ */ ++ if (rc >= 0 && is_sb >= 2) ++ grub_lockdown (); ++} ++ + grub_addr_t grub_modbase; + + void +@@ -296,6 +321,8 @@ grub_machine_init (void) + #else + grub_install_get_time_ms (grub_rtc_get_time_ms); + #endif ++ ++ grub_get_ieee1275_secure_boot (); + } + + void +diff --git a/include/grub/lockdown.h b/include/grub/lockdown.h +index 40531fa823..ebfee4bf06 100644 +--- a/include/grub/lockdown.h ++++ b/include/grub/lockdown.h +@@ -24,7 +24,8 @@ + #define GRUB_LOCKDOWN_DISABLED 0 + #define GRUB_LOCKDOWN_ENABLED 1 + +-#ifdef GRUB_MACHINE_EFI ++#if defined(GRUB_MACHINE_EFI) || \ ++ (defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)) + extern void + EXPORT_FUNC (grub_lockdown) (void); + extern int +diff --git a/docs/grub.texi b/docs/grub.texi +index 4816be8561..a4da9c2a1b 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6227,8 +6227,8 @@ Measured boot is currently only supported on EFI platforms. + @section Lockdown when booting on a secure setup + + The GRUB can be locked down when booted on a secure boot environment, for example +-if the UEFI secure boot is enabled. On a locked down configuration, the GRUB will +-be restricted and some operations/commands cannot be executed. ++if UEFI or Power secure boot is enabled. On a locked down configuration, the ++GRUB will be restricted and some operations/commands cannot be executed. + + The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down. + Otherwise it does not exit. diff --git a/SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch b/SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch new file mode 100644 index 0000000..a40caea --- /dev/null +++ b/SOURCES/0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 14 Apr 2021 20:10:23 +1000 +Subject: [PATCH] ieee1275: drop HEAP_MAX_ADDR, HEAP_MIN_SIZE + +HEAP_MAX_ADDR is confusing. Currently it is set to 32MB, except +on ieee1275 on x86, where it is 64MB. + +There is a comment which purports to explain it: + +/* If possible, we will avoid claiming heap above this address, because it + seems to cause relocation problems with OSes that link at 4 MiB */ + +This doesn't make a lot of sense when the constants are well above 4MB +already. It was not always this way. Prior to +commit 7b5d0fe4440c ("Increase heap limit") in 2010, HEAP_MAX_SIZE and +HEAP_MAX_ADDR were indeed 4MB. However, when the constants were increased +the comment was left unchanged. + +It's been over a decade. It doesn't seem like we have problems with +claims over 4MB on powerpc or x86 ieee1275. (sparc does things completely +differently and never used the constant.) + +Drop the constant and the check. + +The only use of HEAP_MIN_SIZE was to potentially override the +HEAP_MAX_ADDR check. It is now unused. Remove it. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/ieee1275/init.c | 17 ----------------- + 1 file changed, 17 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index fc7d971272..0dcd114ce5 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -46,9 +46,6 @@ + #endif + #include + +-/* The minimal heap size we can live with. */ +-#define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) +- + /* The maximum heap size we're going to claim */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) +@@ -56,14 +53,6 @@ + #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) + #endif + +-/* If possible, we will avoid claiming heap above this address, because it +- seems to cause relocation problems with OSes that link at 4 MiB */ +-#ifdef __i386__ +-#define HEAP_MAX_ADDR (unsigned long) (64 * 1024 * 1024) +-#else +-#define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) +-#endif +- + extern char _end[]; + + #ifdef __sparc__ +@@ -185,12 +174,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + if (*total + len > HEAP_MAX_SIZE) + len = HEAP_MAX_SIZE - *total; + +- /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */ +- if ((addr < HEAP_MAX_ADDR) && /* if it's too late, don't bother */ +- (addr + len > HEAP_MAX_ADDR) && /* if it wasn't available anyway, don't bother */ +- (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE)) /* only limit ourselves when we can afford to */ +- len = HEAP_MAX_ADDR - addr; +- + /* In theory, firmware should already prevent this from happening by not + listing our own image in /memory/available. The check below is intended + as a safeguard in case that doesn't happen. However, it doesn't protect diff --git a/SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch b/SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch new file mode 100644 index 0000000..5728f26 --- /dev/null +++ b/SOURCES/0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch @@ -0,0 +1,315 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Sat, 8 May 2021 02:27:58 +0200 +Subject: [PATCH] appendedsig/x509: Also handle the Extended Key Usage + extension + +Red Hat certificates have both Key Usage and Extended Key Usage extensions +present, but the appended signatures x509 parser doesn't handle the latter +and so buils due finding an unrecognised critical extension: + +Error loading initial key: +../../grub-core/commands/appendedsig/x509.c:780:Unhandled critical x509 extension with OID 2.5.29.37 + +Fix this by also parsing the Extended Key Usage extension and handle it by +verifying that the certificate has a single purpose, that is code signing. + +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Daniel Axtens +--- + grub-core/commands/appendedsig/x509.c | 94 ++++++++++++++++++++++++++++++- + grub-core/tests/appended_signature_test.c | 29 +++++++++- + grub-core/tests/appended_signatures.h | 81 ++++++++++++++++++++++++++ + 3 files changed, 201 insertions(+), 3 deletions(-) + +diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c +index 2b38b3670a..42ec65c54a 100644 +--- a/grub-core/commands/appendedsig/x509.c ++++ b/grub-core/commands/appendedsig/x509.c +@@ -47,6 +47,12 @@ const char *keyUsage_oid = "2.5.29.15"; + */ + const char *basicConstraints_oid = "2.5.29.19"; + ++/* ++ * RFC 5280 4.2.1.12 Extended Key Usage ++ */ ++const char *extendedKeyUsage_oid = "2.5.29.37"; ++const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3"; ++ + /* + * RFC 3279 2.3.1 + * +@@ -637,6 +643,77 @@ cleanup: + return err; + } + ++/* ++ * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId ++ * ++ * KeyPurposeId ::= OBJECT IDENTIFIER ++ */ ++static grub_err_t ++verify_extended_key_usage (grub_uint8_t * value, int value_size) ++{ ++ asn1_node extendedasn; ++ int result, count; ++ grub_err_t err = GRUB_ERR_NONE; ++ char usage[MAX_OID_LEN]; ++ int usage_size = sizeof (usage); ++ ++ result = ++ asn1_create_element (_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", ++ &extendedasn); ++ if (result != ASN1_SUCCESS) ++ { ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Could not create ASN.1 structure for Extended Key Usage"); ++ } ++ ++ result = asn1_der_decoding2 (&extendedasn, value, &value_size, ++ ASN1_DECODE_FLAG_STRICT_DER, asn1_error); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error parsing DER for Extended Key Usage: %s", ++ asn1_error); ++ goto cleanup; ++ } ++ ++ /* ++ * If EKUs are present, there must be exactly 1 and it must be a ++ * codeSigning usage. ++ */ ++ result = asn1_number_of_elements(extendedasn, "", &count); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error counting number of Extended Key Usages: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ result = asn1_read_value (extendedasn, "?1", usage, &usage_size); ++ if (result != ASN1_SUCCESS) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Error reading Extended Key Usage: %s", ++ asn1_strerror (result)); ++ goto cleanup; ++ } ++ ++ if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) != 0) ++ { ++ err = ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected Extended Key Usage OID, got: %s", ++ usage); ++ goto cleanup; ++ } ++ ++cleanup: ++ asn1_delete_structure (&extendedasn); ++ return err; ++} + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension +@@ -660,7 +737,7 @@ verify_extensions (asn1_node cert) + { + int result; + int ext, num_extensions = 0; +- int usage_present = 0, constraints_present = 0; ++ int usage_present = 0, constraints_present = 0, extended_usage_present = 0; + char *oid_path, *critical_path, *value_path; + char extnID[MAX_OID_LEN]; + int extnID_size; +@@ -754,6 +831,15 @@ verify_extensions (asn1_node cert) + } + constraints_present++; + } ++ else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0) ++ { ++ err = verify_extended_key_usage (value, value_size); ++ if (err != GRUB_ERR_NONE) ++ { ++ goto cleanup_value; ++ } ++ extended_usage_present++; ++ } + else if (grub_strncmp ("TRUE", critical, critical_size) == 0) + { + /* +@@ -785,6 +871,12 @@ verify_extensions (asn1_node cert) + "Unexpected number of basic constraints extensions - expected 1, got %d", + constraints_present); + } ++ if (extended_usage_present > 1) ++ { ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "Unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d", ++ extended_usage_present); ++ } + return GRUB_ERR_NONE; + + cleanup_value: +diff --git a/grub-core/tests/appended_signature_test.c b/grub-core/tests/appended_signature_test.c +index 88a485200d..dbba061662 100644 +--- a/grub-core/tests/appended_signature_test.c ++++ b/grub-core/tests/appended_signature_test.c +@@ -111,6 +111,22 @@ static struct grub_procfs_entry certificate_printable_der_entry = { + .get_contents = get_certificate_printable_der + }; + ++static char * ++get_certificate_eku_der (grub_size_t * sz) ++{ ++ char *ret; ++ *sz = certificate_eku_der_len; ++ ret = grub_malloc (*sz); ++ if (ret) ++ grub_memcpy (ret, certificate_eku_der, *sz); ++ return ret; ++} ++ ++static struct grub_procfs_entry certificate_eku_der_entry = { ++ .name = "certificate_eku.der", ++ .get_contents = get_certificate_eku_der ++}; ++ + + static void + do_verify (const char *f, int is_valid) +@@ -149,6 +165,7 @@ appended_signature_test (void) + char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL }; + char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", + NULL }; ++ char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL }; + char *distrust_args[] = { (char *) "1", NULL }; + char *distrust2_args[] = { (char *) "2", NULL }; + grub_err_t err; +@@ -157,6 +174,7 @@ appended_signature_test (void) + grub_procfs_register ("certificate2.der", &certificate2_der_entry); + grub_procfs_register ("certificate_printable.der", + &certificate_printable_der_entry); ++ grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry); + + cmd_trust = grub_command_find ("trust_certificate"); + if (!cmd_trust) +@@ -266,16 +284,23 @@ appended_signature_test (void) + + /* + * Lastly, check a certificate that uses printableString rather than +- * utf8String loads properly. ++ * utf8String loads properly, and that a certificate with an appropriate ++ * extended key usage loads. + */ + err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable); + grub_test_assert (err == GRUB_ERR_NONE, +- "distrusting printable certificate failed: %d: %s", ++ "trusting printable certificate failed: %d: %s", ++ grub_errno, grub_errmsg); ++ ++ err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku); ++ grub_test_assert (err == GRUB_ERR_NONE, ++ "trusting certificate with extended key usage failed: %d: %s", + grub_errno, grub_errmsg); + + grub_procfs_unregister (&certificate_der_entry); + grub_procfs_unregister (&certificate2_der_entry); + grub_procfs_unregister (&certificate_printable_der_entry); ++ grub_procfs_unregister (&certificate_eku_der_entry); + } + + GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test); +diff --git a/grub-core/tests/appended_signatures.h b/grub-core/tests/appended_signatures.h +index aa3dc6278e..2e5ebd7d8b 100644 +--- a/grub-core/tests/appended_signatures.h ++++ b/grub-core/tests/appended_signatures.h +@@ -555,3 +555,84 @@ unsigned char certificate_printable_der[] = { + 0xd2 + }; + unsigned int certificate_printable_der_len = 829; ++ ++unsigned char certificate_eku_der[] = { ++ 0x30, 0x82, 0x03, 0x90, 0x30, 0x82, 0x02, 0x78, 0xa0, 0x03, 0x02, 0x01, ++ 0x02, 0x02, 0x09, 0x00, 0xd3, 0x9c, 0x41, 0x33, 0xdd, 0x6b, 0x5f, 0x45, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x0b, 0x05, 0x00, 0x30, 0x47, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x04, 0x03, 0x0c, 0x18, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, ++ 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, ++ 0x43, 0x41, 0x20, 0x36, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, ++ 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x73, 0x65, 0x63, ++ 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, ++ 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x32, ++ 0x31, 0x35, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, 0x17, 0x0d, 0x33, ++ 0x38, 0x30, 0x31, 0x31, 0x37, 0x31, 0x34, 0x30, 0x30, 0x34, 0x34, 0x5a, ++ 0x30, 0x4e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, ++ 0x1f, 0x52, 0x65, 0x64, 0x20, 0x48, 0x61, 0x74, 0x20, 0x53, 0x65, 0x63, ++ 0x75, 0x72, 0x65, 0x20, 0x42, 0x6f, 0x6f, 0x74, 0x20, 0x53, 0x69, 0x67, ++ 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x36, 0x30, 0x32, 0x31, 0x22, 0x30, 0x20, ++ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, ++ 0x13, 0x73, 0x65, 0x63, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x40, 0x72, 0x65, ++ 0x64, 0x68, 0x61, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, ++ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, ++ 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, ++ 0x02, 0x82, 0x01, 0x01, 0x00, 0xaa, 0x6f, 0xbb, 0x92, 0x77, 0xd7, 0x15, ++ 0xef, 0x88, 0x80, 0x88, 0xc0, 0xe7, 0x89, 0xeb, 0x35, 0x76, 0xf4, 0x85, ++ 0x05, 0x0f, 0x19, 0xe4, 0x5f, 0x25, 0xdd, 0xc1, 0xa2, 0xe5, 0x5c, 0x06, ++ 0xfb, 0xf1, 0x06, 0xb5, 0x65, 0x45, 0xcb, 0xbd, 0x19, 0x33, 0x54, 0xb5, ++ 0x1a, 0xcd, 0xe4, 0xa8, 0x35, 0x2a, 0xfe, 0x9c, 0x53, 0xf4, 0xc6, 0x76, ++ 0xdb, 0x1f, 0x8a, 0xd4, 0x7b, 0x18, 0x11, 0xaf, 0xa3, 0x90, 0xd4, 0xdd, ++ 0x4d, 0xd5, 0x42, 0xcc, 0x14, 0x9a, 0x64, 0x6b, 0xc0, 0x7f, 0xaa, 0x1c, ++ 0x94, 0x47, 0x4d, 0x79, 0xbd, 0x57, 0x9a, 0xbf, 0x99, 0x4e, 0x96, 0xa9, ++ 0x31, 0x2c, 0xa9, 0xe7, 0x14, 0x65, 0x86, 0xc8, 0xac, 0x79, 0x5e, 0x78, ++ 0xa4, 0x3c, 0x00, 0x24, 0xd3, 0xf7, 0xe1, 0xf5, 0x12, 0xad, 0xa0, 0x29, ++ 0xe5, 0xfe, 0x80, 0xae, 0xf8, 0xaa, 0x60, 0x36, 0xe7, 0xe8, 0x94, 0xcb, ++ 0xe9, 0xd1, 0xcc, 0x0b, 0x4d, 0xf7, 0xde, 0xeb, 0x52, 0xd2, 0x73, 0x09, ++ 0x28, 0xdf, 0x48, 0x99, 0x53, 0x9f, 0xc5, 0x9a, 0xd4, 0x36, 0xa3, 0xc6, ++ 0x5e, 0x8d, 0xbe, 0xd5, 0xdc, 0x76, 0xb4, 0x74, 0xb8, 0x26, 0x18, 0x27, ++ 0xfb, 0xf2, 0xfb, 0xd0, 0x9b, 0x3d, 0x7f, 0x10, 0xe2, 0xab, 0x44, 0xc7, ++ 0x88, 0x7f, 0xb4, 0x3d, 0x3e, 0xa3, 0xff, 0x6d, 0x06, 0x4b, 0x3e, 0x55, ++ 0xb2, 0x84, 0xf4, 0xad, 0x54, 0x88, 0x81, 0xc3, 0x9c, 0xf8, 0xb6, 0x68, ++ 0x96, 0x38, 0x8b, 0xcd, 0x90, 0x6d, 0x25, 0x4b, 0xbf, 0x0c, 0x44, 0x90, ++ 0xa5, 0x5b, 0x98, 0xd0, 0x40, 0x2f, 0xbb, 0x0d, 0xa8, 0x4b, 0x8a, 0x62, ++ 0x82, 0x46, 0x46, 0x18, 0x38, 0xae, 0x82, 0x07, 0xd0, 0xb4, 0x2f, 0x16, ++ 0x79, 0x55, 0x9f, 0x1b, 0xc5, 0x08, 0x6d, 0x85, 0xdf, 0x3f, 0xa9, 0x9b, ++ 0x4b, 0xc6, 0x28, 0xd3, 0x58, 0x72, 0x3d, 0x37, 0x11, 0x02, 0x03, 0x01, ++ 0x00, 0x01, 0xa3, 0x78, 0x30, 0x76, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, ++ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, ++ 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, ++ 0x30, 0x16, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x01, 0x01, 0xff, 0x04, 0x0c, ++ 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x03, ++ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x6c, ++ 0xe4, 0x6c, 0x27, 0xaa, 0xcd, 0x0d, 0x4b, 0x74, 0x21, 0xa4, 0xf6, 0x5f, ++ 0x87, 0xb5, 0x31, 0xfe, 0x10, 0xbb, 0xa7, 0x30, 0x1f, 0x06, 0x03, 0x55, ++ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xe8, 0x6a, 0x1c, 0xab, ++ 0x2c, 0x48, 0xf9, 0x60, 0x36, 0xa2, 0xf0, 0x7b, 0x8e, 0xd2, 0x9d, 0xb4, ++ 0x2a, 0x28, 0x98, 0xc8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, ++ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, ++ 0x55, 0x34, 0xe2, 0xfa, 0xf6, 0x89, 0x86, 0xad, 0x92, 0x21, 0xec, 0xb9, ++ 0x54, 0x0e, 0x18, 0x47, 0x0d, 0x1b, 0xa7, 0x58, 0xad, 0x69, 0xe4, 0xef, ++ 0x3b, 0xe6, 0x8d, 0xdd, 0xda, 0x0c, 0x45, 0xf6, 0xe8, 0x96, 0xa4, 0x29, ++ 0x0f, 0xbb, 0xcf, 0x16, 0xae, 0x93, 0xd0, 0xcb, 0x2a, 0x26, 0x1a, 0x7b, ++ 0xfc, 0x51, 0x22, 0x76, 0x98, 0x31, 0xa7, 0x0f, 0x29, 0x35, 0x79, 0xbf, ++ 0xe2, 0x4f, 0x0f, 0x14, 0xf5, 0x1f, 0xcb, 0xbf, 0x87, 0x65, 0x13, 0x32, ++ 0xa3, 0x19, 0x4a, 0xd1, 0x3f, 0x45, 0xd4, 0x4b, 0xe2, 0x00, 0x26, 0xa9, ++ 0x3e, 0xd7, 0xa5, 0x37, 0x9f, 0xf5, 0xad, 0x61, 0xe2, 0x40, 0xa9, 0x74, ++ 0x24, 0x53, 0xf2, 0x78, 0xeb, 0x10, 0x9b, 0x2c, 0x27, 0x88, 0x46, 0xcb, ++ 0xe4, 0x60, 0xca, 0xf5, 0x06, 0x24, 0x40, 0x2a, 0x97, 0x3a, 0xcc, 0xd0, ++ 0x81, 0xb1, 0x15, 0xa3, 0x4f, 0xd0, 0x2b, 0x4f, 0xca, 0x6e, 0xaa, 0x24, ++ 0x31, 0xb3, 0xac, 0xa6, 0x75, 0x05, 0xfe, 0x8a, 0xf4, 0x41, 0xc4, 0x06, ++ 0x8a, 0xc7, 0x0a, 0x83, 0x4e, 0x49, 0xd4, 0x3f, 0x83, 0x50, 0xec, 0x57, ++ 0x04, 0x97, 0x14, 0x49, 0xf5, 0xe1, 0xb1, 0x7a, 0x9c, 0x09, 0x4f, 0x61, ++ 0x87, 0xc3, 0x97, 0x22, 0x17, 0xc2, 0xeb, 0xcc, 0x32, 0x81, 0x31, 0x21, ++ 0x3f, 0x10, 0x57, 0x5b, 0x43, 0xbe, 0xcd, 0x68, 0x82, 0xbe, 0xe5, 0xc1, ++ 0x65, 0x94, 0x7e, 0xc2, 0x34, 0x76, 0x2b, 0xcf, 0x89, 0x3c, 0x2b, 0x81, ++ 0x23, 0x72, 0x95, 0xcf, 0xc9, 0x67, 0x19, 0x2a, 0xd5, 0x5c, 0xca, 0xa3, ++ 0x46, 0xbd, 0x48, 0x06, 0x0b, 0xa6, 0xa3, 0x96, 0x50, 0x28, 0xc7, 0x7e, ++ 0xcf, 0x62, 0xf2, 0xfa, 0xc4, 0xf2, 0x53, 0xe3, 0xc9, 0xe8, 0x2e, 0xdd, ++ 0x29, 0x37, 0x07, 0x47, 0xff, 0xff, 0x8a, 0x32, 0xbd, 0xa2, 0xb7, 0x21, ++ 0x89, 0xa0, 0x55, 0xf7 ++}; ++unsigned int certificate_eku_der_len = 916; diff --git a/SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch b/SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch new file mode 100644 index 0000000..9149773 --- /dev/null +++ b/SOURCES/0176-ieee1275-ofdisk-retry-on-open-failure.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Wed, 10 Mar 2021 14:17:52 -0500 +Subject: [PATCH] ieee1275/ofdisk: retry on open failure + +This patch aims to make grub more robust when booting from SAN/Multipath disks. + +If a path is failing intermittently so grub will retry the OPEN and READ the +disk (grub_ieee1275_open and grub_ieee1275_read) until the total amount of times +specified in MAX_RETRIES. + +Signed-off-by: Diego Domingos +--- + grub-core/disk/ieee1275/ofdisk.c | 25 ++++++++++++++++++++----- + include/grub/ieee1275/ofdisk.h | 8 ++++++++ + 2 files changed, 28 insertions(+), 5 deletions(-) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index ea7f78ac7d..55346849d3 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -225,7 +225,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + char *buf, *bufptr; + unsigned i; + +- if (grub_ieee1275_open (alias->path, &ihandle)) ++ ++ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle) ++ if (! ihandle) + return; + + /* This method doesn't need memory allocation for the table. Open +@@ -305,7 +307,9 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) + return; + } + +- if (grub_ieee1275_open (alias->path, &ihandle)) ++ RETRY_IEEE1275_OFDISK_OPEN(alias->path, &ihandle); ++ ++ if (! ihandle) + { + grub_free (buf); + grub_free (table); +@@ -495,7 +499,7 @@ grub_ofdisk_open (const char *name, grub_disk_t disk) + last_ihandle = 0; + last_devpath = NULL; + +- grub_ieee1275_open (op->open_path, &last_ihandle); ++ RETRY_IEEE1275_OFDISK_OPEN(op->open_path, &last_ihandle); + if (! last_ihandle) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + last_devpath = op->open_path; +@@ -571,7 +575,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector) + last_ihandle = 0; + last_devpath = NULL; + +- grub_ieee1275_open (disk->data, &last_ihandle); ++ RETRY_IEEE1275_OFDISK_OPEN(disk->data, &last_ihandle); + if (! last_ihandle) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + last_devpath = disk->data; +@@ -598,12 +602,23 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector, + return err; + grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, + &actual); +- if (actual != (grub_ssize_t) (size << disk->log_sector_size)) ++ int i = 0; ++ while(actual != (grub_ssize_t) (size << disk->log_sector_size)){ ++ if (i>MAX_RETRIES){ + return grub_error (GRUB_ERR_READ_ERROR, N_("failure reading sector 0x%llx " + "from `%s'"), + (unsigned long long) sector, + disk->name); ++ } ++ last_devpath = NULL; ++ err = grub_ofdisk_prepare (disk, sector); ++ if (err) ++ return err; + ++ grub_ieee1275_read (last_ihandle, buf, size << disk->log_sector_size, ++ &actual); ++ i++; ++ } + return 0; + } + +diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h +index 2f69e3f191..7d2d540930 100644 +--- a/include/grub/ieee1275/ofdisk.h ++++ b/include/grub/ieee1275/ofdisk.h +@@ -22,4 +22,12 @@ + extern void grub_ofdisk_init (void); + extern void grub_ofdisk_fini (void); + ++#define MAX_RETRIES 20 ++ ++ ++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \ ++ if(!grub_ieee1275_open(device, last_ihandle)) \ ++ break; \ ++ grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } ++ + #endif /* ! GRUB_INIT_HEADER */ diff --git a/SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch b/SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch new file mode 100644 index 0000000..c3101e1 --- /dev/null +++ b/SOURCES/0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 11 Jun 2021 13:51:20 +0200 +Subject: [PATCH] Allow chainloading EFI apps from loop mounts. + +Signed-off-by: Dimitri John Ledkov +Signed-off-by: Robbie Harwood +--- + grub-core/disk/loopback.c | 9 +-------- + grub-core/loader/efi/chainloader.c | 23 +++++++++++++++++++++++ + include/grub/loopback.h | 30 ++++++++++++++++++++++++++++++ + 3 files changed, 54 insertions(+), 8 deletions(-) + create mode 100644 include/grub/loopback.h + +diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c +index 41bebd14fe..99f47924ec 100644 +--- a/grub-core/disk/loopback.c ++++ b/grub-core/disk/loopback.c +@@ -21,20 +21,13 @@ + #include + #include + #include ++#include + #include + #include + #include + + GRUB_MOD_LICENSE ("GPLv3+"); + +-struct grub_loopback +-{ +- char *devname; +- grub_file_t file; +- struct grub_loopback *next; +- unsigned long id; +-}; +- + static struct grub_loopback *loopback_list; + static unsigned long last_id = 0; + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index d41e8ea14a..3af6b12292 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -901,6 +902,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; ++ grub_device_t orig_dev = 0; + grub_efi_device_path_t *dp = 0; + char *filename; + void *boot_image = 0; +@@ -958,6 +960,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + if (! dev) + goto fail; + ++ /* if device is loopback, use underlying dev */ ++ if (dev->disk->dev->id == GRUB_DISK_DEVICE_LOOPBACK_ID) ++ { ++ struct grub_loopback *d; ++ orig_dev = dev; ++ d = dev->disk->data; ++ dev = d->file->device; ++ } ++ + if (dev->disk) + dev_handle = grub_efidisk_get_device_handle (dev->disk); + else if (dev->net && dev->net->server) +@@ -1065,6 +1076,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ if (orig_dev) ++ { ++ dev = orig_dev; ++ orig_dev = 0; ++ } ++ + rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); + grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); + if (rc > 0) +@@ -1087,6 +1104,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + // -1 fall-through to fail + + fail: ++ if (orig_dev) ++ { ++ dev = orig_dev; ++ orig_dev = 0; ++ } ++ + if (dev) + grub_device_close (dev); + +diff --git a/include/grub/loopback.h b/include/grub/loopback.h +new file mode 100644 +index 0000000000..3b9a9e32e8 +--- /dev/null ++++ b/include/grub/loopback.h +@@ -0,0 +1,30 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2019 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_LOOPBACK_HEADER ++#define GRUB_LOOPBACK_HEADER 1 ++ ++struct grub_loopback ++{ ++ char *devname; ++ grub_file_t file; ++ struct grub_loopback *next; ++ unsigned long id; ++}; ++ ++#endif /* ! GRUB_LOOPBACK_HEADER */ diff --git a/SOURCES/0178-efinet-Add-DHCP-proxy-support.patch b/SOURCES/0178-efinet-Add-DHCP-proxy-support.patch new file mode 100644 index 0000000..eed2dbb --- /dev/null +++ b/SOURCES/0178-efinet-Add-DHCP-proxy-support.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ian Page Hands +Date: Tue, 8 Jun 2021 13:48:56 -0400 +Subject: [PATCH] efinet: Add DHCP proxy support + +If a proxyDHCP configuration is used, the server name, server IP and boot +file values should be taken from the DHCP proxy offer instead of the DHCP +server ack packet. Currently that case is not handled, add support for it. + +Signed-off-by: Ian Page Hands +Signed-off-by: Robbie Harwood +--- + grub-core/net/drivers/efi/efinet.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c +index e11d759f19..1a24f38a21 100644 +--- a/grub-core/net/drivers/efi/efinet.c ++++ b/grub-core/net/drivers/efi/efinet.c +@@ -850,10 +850,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device, + else + { + grub_dprintf ("efinet", "using ipv4 and dhcp\n"); ++ ++ struct grub_net_bootp_packet *dhcp_ack = &pxe_mode->dhcp_ack; ++ ++ if (pxe_mode->proxy_offer_received) ++ { ++ grub_dprintf ("efinet", "proxy offer receive"); ++ struct grub_net_bootp_packet *proxy_offer = &pxe_mode->proxy_offer; ++ ++ if (proxy_offer && dhcp_ack->boot_file[0] == '\0') ++ { ++ grub_dprintf ("efinet", "setting values from proxy offer"); ++ /* Here we got a proxy offer and the dhcp_ack has a nil boot_file ++ * Copy the proxy DHCP offer details into the bootp_packet we are ++ * sending forward as they are the deatils we need. ++ */ ++ *dhcp_ack->server_name = *proxy_offer->server_name; ++ *dhcp_ack->boot_file = *proxy_offer->boot_file; ++ dhcp_ack->server_ip = proxy_offer->server_ip; ++ } ++ } ++ + grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) +- packet_buf, +- packet_bufsz, ++ &pxe_mode->dhcp_ack, ++ sizeof (pxe_mode->dhcp_ack), + 1, device, path); + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + } diff --git a/SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch b/SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch new file mode 100644 index 0000000..3d7c641 --- /dev/null +++ b/SOURCES/0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Fri, 11 Jun 2021 00:01:29 +0200 +Subject: [PATCH] fs/ext2: Ignore checksum seed incompat feature + +This incompat feature is used to denote that the filesystem stored its +metadata checksum seed in the superblock. This is used to allow tune2fs +to change the UUID on a mounted metadata_csum filesystem without having +to rewrite all the disk metadata. + +But GRUB doesn't use the metadata checksum in anyway, so can just ignore +this feature if is enabled. This is consistent with GRUB filesystem code +in general which just does a best effort to access the filesystem's data. + +It may be removed from the ignored list in the future if supports to do +metadata checksumming verification is added to the read-only FS driver. + +Suggested-by: Eric Sandeen +Suggested-by: Lukas Czerner +Signed-off-by: Javier Martinez Canillas +--- + grub-core/fs/ext2.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c +index e7dd78e663..731d346f88 100644 +--- a/grub-core/fs/ext2.c ++++ b/grub-core/fs/ext2.c +@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 + #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 + #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 ++#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 + #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 + + /* The set of back-incompatible features this driver DOES support. Add (OR) +@@ -123,9 +124,16 @@ GRUB_MOD_LICENSE ("GPLv3+"); + * mmp: Not really back-incompatible - was added as such to + * avoid multiple read-write mounts. Safe to ignore for this + * RO driver. ++ * checksum seed: Not really back-incompatible - was added to allow tools ++ * such as tune2fs to change the UUID on a mounted metadata ++ * checksummed filesystem. Safe to ignore for now since the ++ * driver doesn't support checksum verification. But it must ++ * be removed from this list if that support is added later. ++ * + */ + #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \ +- | EXT4_FEATURE_INCOMPAT_MMP) ++ | EXT4_FEATURE_INCOMPAT_MMP \ ++ | EXT4_FEATURE_INCOMPAT_CSUM_SEED) + + + #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U diff --git a/SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch b/SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch new file mode 100644 index 0000000..b2783d1 --- /dev/null +++ b/SOURCES/0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Thu, 17 Jun 2021 14:31:42 +0200 +Subject: [PATCH] Don't update the cmdline when generating legacy menuentry + commands + +On OPAL ppc64le machines with an old petitboot version that doesn't have +support to parse BLS snippets, the grub2-mkconfig script is executed to +generate menuentry commands from the BLS snippets. + +In this case, the script is executed with the --no-grubenv-update option +that indicates that no side effects should happen when running the script. + +But the options field in the BLS snippets are updated regardless, only do +the update if --no-grubenv-update was not used. + +Signed-off-by: Javier Martinez Canillas +--- + util/grub.d/10_linux.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index e490e1a43a..865af3d6c4 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -256,7 +256,9 @@ if [ -z "\${kernelopts}" ]; then + fi + EOF + +- update_bls_cmdline ++ if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ update_bls_cmdline ++ fi + + if [ "x${BLS_POPULATE_MENU}" = "xtrue" ]; then + populate_menu diff --git a/SOURCES/0181-Suppress-gettext-error-message.patch b/SOURCES/0181-Suppress-gettext-error-message.patch new file mode 100644 index 0000000..64b219a --- /dev/null +++ b/SOURCES/0181-Suppress-gettext-error-message.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paulo Flabiano Smorigo +Date: Tue, 29 Jun 2021 13:17:42 +0200 +Subject: [PATCH] Suppress gettext error message + +Colin Watson's patch from comment #11 on the upstream bug: +https://savannah.gnu.org/bugs/?35880#comment11 + +Resolves: rhbz#1592124 + +Signed-off-by: Paulo Flabiano Smorigo +--- + grub-core/gettext/gettext.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 4d02e62c10..7ec81ca0b4 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -424,6 +424,13 @@ grub_gettext_init_ext (struct grub_gettext_context *ctx, + grub_free (lang); + } + ++ /* If no translations are available, fall back to untranslated text. */ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ + if (locale[0] == 'e' && locale[1] == 'n' + && (locale[2] == '\0' || locale[2] == '_')) + grub_errno = err = GRUB_ERR_NONE; diff --git a/SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch b/SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch new file mode 100644 index 0000000..b5d5e5c --- /dev/null +++ b/SOURCES/0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 5 Jul 2021 18:24:22 +0200 +Subject: [PATCH] grub-set-password: Always use /boot/grub2/user.cfg as + password default + +The GRUB configuration file is always placed in /boot/grub2/ now, even for +EFI. But the tool is still creating the user.cfg in the ESP and not there. + +Resolves: rhbz#1955294 + +Signed-off-by: Javier Martinez Canillas +--- + util/grub-set-password.in | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/util/grub-set-password.in b/util/grub-set-password.in +index c0b5ebbfdc..d8005e5a14 100644 +--- a/util/grub-set-password.in ++++ b/util/grub-set-password.in +@@ -1,11 +1,6 @@ + #!/bin/sh -e + +-EFIDIR=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') +-if [ -d /sys/firmware/efi/efivars/ ]; then +- grubdir=`echo "/@bootdirname@/efi/EFI/${EFIDIR}/" | sed 's,//*,/,g'` +-else +- grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` +-fi ++grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + + PACKAGE_VERSION="@PACKAGE_VERSION@" + PACKAGE_NAME="@PACKAGE_NAME@" +@@ -116,8 +111,6 @@ if [ -z "${MYPASS}" ]; then + exit 1 + fi + +-# on the ESP, these will fail to set the permissions, but it's okay because +-# the directory is protected. + install -m 0600 /dev/null "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : + chmod 0600 "${OUTPUT_PATH}/user.cfg" 2>/dev/null || : + echo "GRUB2_PASSWORD=${MYPASS}" > "${OUTPUT_PATH}/user.cfg" diff --git a/SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch b/SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch new file mode 100644 index 0000000..265b967 --- /dev/null +++ b/SOURCES/0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Jul 2021 00:38:40 +0200 +Subject: [PATCH] templates: Check for EFI at runtime instead of config + generation time + +The 30_uefi-firmware template checks if an OsIndicationsSupported UEFI var +exists and EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, to decide whether +a "fwsetup" menu entry would be added or not to the GRUB menu. + +But this has the problem that it will only work if the configuration file +was created on an UEFI machine that supports booting to a firmware UI. + +This for example doesn't support creating GRUB config files when executing +on systems that support both UEFI and legacy BIOS booting. Since creating +the config file from legacy BIOS wouldn't allow to access the firmware UI. + +To prevent this, make the template to unconditionally create the grub.cfg +snippet but check at runtime if was booted through UEFI to decide if this +entry should be added. That way it won't be added when booting with BIOS. + +There's no need to check if EFI_OS_INDICATIONS_BOOT_TO_FW_UI bit is set, +since that's already done by the "fwsetup" command when is executed. + +Resolves: rhbz#1823864 + +Signed-off-by: Javier Martinez Canillas +--- + util/grub.d/30_uefi-firmware.in | 21 ++++++++------------- + 1 file changed, 8 insertions(+), 13 deletions(-) + +diff --git a/util/grub.d/30_uefi-firmware.in b/util/grub.d/30_uefi-firmware.in +index d344d3883d..b6041b55e2 100644 +--- a/util/grub.d/30_uefi-firmware.in ++++ b/util/grub.d/30_uefi-firmware.in +@@ -26,19 +26,14 @@ export TEXTDOMAINDIR="@localedir@" + + . "$pkgdatadir/grub-mkconfig_lib" + +-EFI_VARS_DIR=/sys/firmware/efi/efivars +-EFI_GLOBAL_VARIABLE=8be4df61-93ca-11d2-aa0d-00e098032b8c +-OS_INDICATIONS="$EFI_VARS_DIR/OsIndicationsSupported-$EFI_GLOBAL_VARIABLE" ++LABEL="UEFI Firmware Settings" + +-if [ -e "$OS_INDICATIONS" ] && \ +- [ "$(( $(printf 0x%x \'"$(cat $OS_INDICATIONS | cut -b5)"\') & 1 ))" = 1 ]; then +- LABEL="UEFI Firmware Settings" ++gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 + +- gettext_printf "Adding boot menu entry for UEFI Firmware Settings ...\n" >&2 +- +- cat << EOF +-menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { +- fwsetup +-} +-EOF ++cat << EOF ++if [ "\$grub_platform" = "efi" ]; then ++ menuentry '$LABEL' \$menuentry_id_option 'uefi-firmware' { ++ fwsetup ++ } + fi ++EOF diff --git a/SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch b/SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch new file mode 100644 index 0000000..3b1a219 --- /dev/null +++ b/SOURCES/0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Tue, 6 Jul 2021 01:10:18 +0200 +Subject: [PATCH] efi: Print an error if boot to firmware setup is not + supported + +The "fwsetup" command is only registered if the firmware supports booting +to the firmware setup UI. But it could be possible that the GRUB config +already contains a "fwsetup" entry, because it was generated in a machine +that has support for this feature. + +To prevent users getting a "can't find command `fwsetup`" error if it is +not supported by the firmware, let's just always register the command but +print a more accurate message if the firmware doesn't support this option. + +Resolves: rhbz#1823864 + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/commands/efi/efifwsetup.c | 43 ++++++++++++++++++++----------------- + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c +index eaca032838..328c45e82e 100644 +--- a/grub-core/commands/efi/efifwsetup.c ++++ b/grub-core/commands/efi/efifwsetup.c +@@ -27,6 +27,25 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + ++static grub_efi_boolean_t ++efifwsetup_is_supported (void) ++{ ++ grub_efi_uint64_t *os_indications_supported = NULL; ++ grub_size_t oi_size = 0; ++ grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; ++ ++ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, ++ (void **) &os_indications_supported); ++ ++ if (!os_indications_supported) ++ return 0; ++ ++ if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) ++ return 1; ++ ++ return 0; ++} ++ + static grub_err_t + grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), +@@ -38,6 +57,10 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + grub_size_t oi_size; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + ++ if (!efifwsetup_is_supported ()) ++ return grub_error (GRUB_ERR_INVALID_COMMAND, ++ N_("Reboot to firmware setup is not supported")); ++ + grub_efi_get_variable ("OsIndications", &global, &oi_size, + (void **) &old_os_indications); + +@@ -56,28 +79,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + + static grub_command_t cmd = NULL; + +-static grub_efi_boolean_t +-efifwsetup_is_supported (void) +-{ +- grub_efi_uint64_t *os_indications_supported = NULL; +- grub_size_t oi_size = 0; +- grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; +- +- grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, +- (void **) &os_indications_supported); +- +- if (!os_indications_supported) +- return 0; +- +- if (*os_indications_supported & GRUB_EFI_OS_INDICATIONS_BOOT_TO_FW_UI) +- return 1; +- +- return 0; +-} +- + GRUB_MOD_INIT (efifwsetup) + { +- if (efifwsetup_is_supported ()) + cmd = grub_register_command ("fwsetup", grub_cmd_fwsetup, NULL, + N_("Reboot into firmware setup menu.")); + diff --git a/SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch b/SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch new file mode 100644 index 0000000..cc5458c --- /dev/null +++ b/SOURCES/0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch @@ -0,0 +1,218 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Benjamin Herrenschmidt +Date: Mon, 2 Aug 2021 23:10:01 +1000 +Subject: [PATCH] arm64: Fix EFI loader kernel image allocation + +We are currently allocating just enough memory for the file size, +which means that the kernel BSS is in limbo (and not even zeroed). + +We are also not honoring the alignment specified in the image +PE header. + +This makes us use the PE optional header in which the kernel puts the +actual size it needs, including BSS, and make sure we clear it, and +honors the specified alignment for the image. + +Signed-off-by: Benjamin Herrenschmidt +[pjones: arm: check for the PE magic for the compiled arch] +Signed-off-by: Peter Jones +Signed-off-by: Robbie Harwood +--- + grub-core/loader/arm64/linux.c | 100 +++++++++++++++++++++++++++-------------- + include/grub/arm/linux.h | 1 + + include/grub/arm64/linux.h | 1 + + 3 files changed, 68 insertions(+), 34 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 47f8cf0d84..f18d90bd74 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -41,6 +41,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + static grub_dl_t my_mod; + static int loaded; + ++static void *kernel_alloc_addr; ++static grub_uint32_t kernel_alloc_pages; + static void *kernel_addr; + static grub_uint64_t kernel_size; + static grub_uint32_t handover_offset; +@@ -204,9 +206,8 @@ grub_linux_unload (void) + GRUB_EFI_BYTES_TO_PAGES (initrd_end - initrd_start)); + initrd_start = initrd_end = 0; + grub_free (linux_args); +- if (kernel_addr) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + grub_fdt_unload (); + return GRUB_ERR_NONE; + } +@@ -311,14 +312,35 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + return grub_errno; + } + ++static grub_err_t ++parse_pe_header (void *kernel, grub_uint64_t *total_size, ++ grub_uint32_t *entry_offset, ++ grub_uint32_t *alignment) ++{ ++ struct linux_arch_kernel_header *lh = kernel; ++ struct grub_armxx_linux_pe_header *pe; ++ ++ pe = (void *)((unsigned long)kernel + lh->hdr_offset); ++ ++ if (pe->opt.magic != GRUB_PE32_PEXX_MAGIC) ++ return grub_error(GRUB_ERR_BAD_OS, "Invalid PE optional header magic"); ++ ++ *total_size = pe->opt.image_size; ++ *entry_offset = pe->opt.entry_addr; ++ *alignment = pe->opt.section_alignment; ++ ++ return GRUB_ERR_NONE; ++} ++ + static grub_err_t + grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) + { + grub_file_t file = 0; +- struct linux_arch_kernel_header lh; +- struct grub_armxx_linux_pe_header *pe; + grub_err_t err; ++ grub_off_t filelen; ++ grub_uint32_t align; ++ void *kernel = NULL; + int rc; + + grub_dl_ref (my_mod); +@@ -333,40 +355,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (!file) + goto fail; + +- kernel_size = grub_file_size (file); +- +- if (grub_file_read (file, &lh, sizeof (lh)) < (long) sizeof (lh)) +- return grub_errno; +- +- if (grub_arch_efi_linux_check_image (&lh) != GRUB_ERR_NONE) +- goto fail; +- +- grub_loader_unset(); +- +- grub_dprintf ("linux", "kernel file size: %lld\n", (long long) kernel_size); +- kernel_addr = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- grub_dprintf ("linux", "kernel numpages: %lld\n", +- (long long) GRUB_EFI_BYTES_TO_PAGES (kernel_size)); +- if (!kernel_addr) ++ filelen = grub_file_size (file); ++ kernel = grub_malloc(filelen); ++ if (!kernel) + { +- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel load buffer")); + goto fail; + } + +- grub_file_seek (file, 0); +- if (grub_file_read (file, kernel_addr, kernel_size) +- < (grub_int64_t) kernel_size) ++ if (grub_file_read (file, kernel, filelen) < (grub_ssize_t)filelen) + { +- if (!grub_errno) +- grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]); ++ grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), ++ argv[0]); + goto fail; + } + +- grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); +- + if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { +- rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size); ++ rc = grub_linuxefi_secure_validate (kernel, filelen); + if (rc <= 0) + { + grub_error (GRUB_ERR_INVALID_COMMAND, +@@ -375,8 +381,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + } + +- pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); +- handover_offset = pe->opt.entry_addr; ++ if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) ++ goto fail; ++ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) ++ goto fail; ++ grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); ++ grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); ++ grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); ++ ++ grub_loader_unset(); ++ ++ kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); ++ kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages); ++ grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); ++ if (!kernel_alloc_addr) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); ++ ++ grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); ++ grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); ++ if (kernel_size > filelen) ++ grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); ++ grub_free(kernel); ++ kernel = NULL; + + cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); + linux_args = grub_malloc (cmdline_size); +@@ -400,6 +430,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + + fail: ++ if (kernel) ++ grub_free (kernel); ++ + if (file) + grub_file_close (file); + +@@ -412,9 +445,8 @@ fail: + if (linux_args && !loaded) + grub_free (linux_args); + +- if (kernel_addr && !loaded) +- grub_efi_free_pages ((grub_addr_t) kernel_addr, +- GRUB_EFI_BYTES_TO_PAGES (kernel_size)); ++ if (kernel_alloc_addr && !loaded) ++ grub_efi_free_pages ((grub_addr_t) kernel_alloc_addr, kernel_alloc_pages); + + return grub_errno; + } +diff --git a/include/grub/arm/linux.h b/include/grub/arm/linux.h +index b582f67f66..966a5074f5 100644 +--- a/include/grub/arm/linux.h ++++ b/include/grub/arm/linux.h +@@ -44,6 +44,7 @@ struct grub_arm_linux_pe_header + + #if defined(__arm__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM_MAGIC_SIGNATURE ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC + # define linux_arch_kernel_header linux_arm_kernel_header + # define grub_armxx_linux_pe_header grub_arm_linux_pe_header + #endif +diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h +index ea030312df..422bf2bf24 100644 +--- a/include/grub/arm64/linux.h ++++ b/include/grub/arm64/linux.h +@@ -48,6 +48,7 @@ struct grub_arm64_linux_pe_header + + #if defined(__aarch64__) + # define GRUB_LINUX_ARMXX_MAGIC_SIGNATURE GRUB_LINUX_ARM64_MAGIC_SIGNATURE ++# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC + # define linux_arch_kernel_header linux_arm64_kernel_header + # define grub_armxx_linux_pe_header grub_arm64_linux_pe_header + #endif diff --git a/SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch b/SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch new file mode 100644 index 0000000..2c9ca3a --- /dev/null +++ b/SOURCES/0186-normal-main-Discover-the-device-to-read-the-config-f.patch @@ -0,0 +1,123 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Javier Martinez Canillas +Date: Mon, 30 Aug 2021 12:31:18 +0200 +Subject: [PATCH] normal/main: Discover the device to read the config from as a + fallback + +The GRUB core.img is generated locally, when this is done the grub2-probe +tool figures out the device and partition that needs to be read to parse +the GRUB configuration file. + +But in some cases the core.img can't be generated on the host and instead +has to be done at package build time. For example, if needs to get signed +with a key that's only available on the package building infrastructure. + +If that's the case, the prefix variable won't have a device and partition +but only a directory path. So there's no way for GRUB to know from which +device has to read the configuration file. + +To allow GRUB to continue working on that scenario, fallback to iterating +over all the available devices, if reading the config failed when using +the prefix and fw_path variables. + +Signed-off-by: Javier Martinez Canillas +--- + grub-core/normal/main.c | 58 +++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 51 insertions(+), 7 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 7de9e4c36d..8f5fd81003 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -337,18 +337,13 @@ grub_enter_normal_mode (const char *config) + } + + static grub_err_t +-grub_try_normal (const char *variable) ++grub_try_normal_prefix (const char *prefix) + { + char *config; +- const char *prefix; + grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; + const char *net_search_cfg; + int disable_net_search = 0; + +- prefix = grub_env_get (variable); +- if (!prefix) +- return GRUB_ERR_FILE_NOT_FOUND; +- + net_search_cfg = grub_env_get ("feature_net_search_cfg"); + if (net_search_cfg && net_search_cfg[0] == 'n') + disable_net_search = 1; +@@ -362,7 +357,7 @@ grub_try_normal (const char *variable) + config = grub_malloc (config_len); + + if (! config) +- return GRUB_ERR_FILE_NOT_FOUND; ++ return err; + + grub_snprintf (config, config_len, "%s/grub.cfg", prefix); + err = grub_net_search_config_file (config); +@@ -391,6 +386,53 @@ grub_try_normal (const char *variable) + return err; + } + ++static int ++grub_try_normal_dev (const char *name, void *data) ++{ ++ grub_err_t err; ++ const char *prefix = grub_xasprintf ("(%s)%s", name, (char *)data); ++ ++ if (!prefix) ++ return 0; ++ ++ err = grub_try_normal_prefix (prefix); ++ if (err == GRUB_ERR_NONE) ++ return 1; ++ ++ return 0; ++} ++ ++static grub_err_t ++grub_try_normal_discover (void) ++{ ++ char *prefix = grub_env_get ("prefix"); ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ ++ if (!prefix) ++ return err; ++ ++ if (grub_device_iterate (grub_try_normal_dev, (void *)prefix)) ++ return GRUB_ERR_NONE; ++ ++ return err; ++} ++ ++static grub_err_t ++grub_try_normal (const char *variable) ++{ ++ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND; ++ const char *prefix; ++ ++ if (!variable) ++ return err; ++ ++ prefix = grub_env_get (variable); ++ if (!prefix) ++ return err; ++ ++ return grub_try_normal_prefix (prefix); ++} ++ + /* Enter normal mode from rescue mode. */ + static grub_err_t + grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), +@@ -405,6 +447,8 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + err = grub_try_normal ("fw_path"); + if (err == GRUB_ERR_FILE_NOT_FOUND) + err = grub_try_normal ("prefix"); ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal_discover (); + if (err == GRUB_ERR_FILE_NOT_FOUND) + grub_enter_normal_mode (0); + } diff --git a/SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch b/SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch new file mode 100644 index 0000000..b9bc140 --- /dev/null +++ b/SOURCES/0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 19 Jul 2021 14:35:55 +1000 +Subject: [PATCH] powerpc: adjust setting of prefix for signed binary case + +On RHEL-signed powerpc grub, we sign a grub with -p /grub2 and expect +that there's a boot partition. + +Unfortunately grub_set_prefix_and_root tries to convert this to +($fwdevice)/grub2. This ends up being (ieee1275/disk)/grub2 and that +falls apart pretty quickly - there's no file-system on ieee1275/disk, +and it makes the search routine try things like +(ieee1275/disk,msdos2)(ieee1275/disk)/grub2 which also doesn't work. + +Detect if we would be about to create (ieee1275/disk)/path and don't: +preserve a prefix of /path instead and hope the search later finds us. + +Related: rhbz#1899864 + +Signed-off-by: Daniel Axtens +[rharwood@redhat.com: squash in fixup commit] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/main.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 44 insertions(+), 5 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index b573be6650..3fc3401472 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -216,13 +216,52 @@ grub_set_prefix_and_root (void) + if (device) + { + char *prefix_set; +- +- prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); +- if (prefix_set) ++ ++#ifdef __powerpc__ ++ /* We have to be careful here on powerpc-ieee1275 + signed grub. We ++ will have signed something with a prefix that doesn't have a device ++ because we cannot know in advance what partition we're on. ++ ++ We will have had !device earlier, so we will have set device=fwdevice ++ However, we want to make sure we do not end up setting prefix to be ++ ($fwdevice)/path, because we will then end up trying to boot or search ++ based on a prefix of (ieee1275/disk)/path, which will not work because ++ it's missing a partition. ++ ++ Also: ++ - You can end up with a device with an FS directly on it, without ++ a partition, e.g. ieee1275/cdrom. ++ ++ - powerpc-ieee1275 + grub-install sets e.g. prefix=(,gpt2)/path, ++ which will have now been extended to device=$fwdisk,partition ++ and path=/path ++ ++ - PowerVM will give us device names like ++ ieee1275//vdevice/v-scsi@3000006c/disk@8100000000000000 ++ and we don't want to try to encode some sort of truth table about ++ what sorts of paths represent disks with partition tables and those ++ without partition tables. ++ ++ So we act unless there is a comma in the device, which would indicate ++ a partition has already been specified. ++ ++ (If we only have a path, the code in normal to discover config files ++ will try both without partitions and then with any partitions so we ++ will cover both CDs and HDs.) ++ */ ++ if (grub_strchr (device, ',') == NULL) ++ grub_env_set ("prefix", path); ++ else ++#endif + { +- grub_env_set ("prefix", prefix_set); +- grub_free (prefix_set); ++ prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); ++ if (prefix_set) ++ { ++ grub_env_set ("prefix", prefix_set); ++ grub_free (prefix_set); ++ } + } ++ + grub_env_set ("root", device); + } + diff --git a/SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch b/SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch new file mode 100644 index 0000000..7fc40f1 --- /dev/null +++ b/SOURCES/0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Erwan Velu +Date: Wed, 25 Aug 2021 15:31:52 +0200 +Subject: [PATCH] fs/xfs: Fix unreadable filesystem with v4 superblock + +The commit 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) +introduced the bigtime support by adding some features in v3 inodes. +This change extended grub_xfs_inode struct by 76 bytes but also changed +the computation of XFS_V2_INODE_SIZE and XFS_V3_INODE_SIZE. Prior this +commit, XFS_V2_INODE_SIZE was 100 bytes. After the commit it's 84 bytes +XFS_V2_INODE_SIZE becomes 16 bytes too small. + +As a result, the data structures aren't properly aligned and the GRUB +generates "attempt to read or write outside of partition" errors when +trying to read the XFS filesystem: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (739521961424144223) - 344365866970255880, 3840 + error: attempt to read or write outside of partition. + +This commit change the XFS_V2_INODE_SIZE computation by subtracting 76 +bytes instead of 92 bytes from the actual size of grub_xfs_inode struct. +This 76 bytes value comes from added members: + 20 grub_uint8_t unused5 + 1 grub_uint64_t flags2 + 48 grub_uint8_t unused6 + +This patch explicitly splits the v2 and v3 parts of the structure. +The unused4 is still ending of the v2 structures and the v3 starts +at unused5. Thanks to this we will avoid future corruptions of v2 +or v3 inodes. + +The XFS_V2_INODE_SIZE is returning to its expected size and the +filesystem is back to a readable state: + + GNU GRUB version 2.11 + .... + grub> set debug=efi,gpt,xfs + grub> insmod part_gpt + grub> ls (hd0,gpt1)/ + partmap/gpt.c:93: Read a valid GPT header + partmap/gpt.c:115: GPT entry 0: start=4096, length=1953125 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:931: Reading sb + fs/xfs.c:270: Validating superblock + fs/xfs.c:295: XFS v4 superblock detected + fs/xfs.c:962: Reading root ino 128 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (128) - 64, 0 + fs/xfs.c:515: Reading inode (131) - 64, 768 + efi/ fs/xfs.c:515: Reading inode (3145856) - 1464904, 0 + grub2/ fs/xfs.c:515: Reading inode (132) - 64, 1024 + grub/ fs/xfs.c:515: Reading inode (139) - 64, 2816 + grub> + +Fixes: 8b1e5d193 (fs/xfs: Add bigtime incompat feature support) + +Signed-off-by: Erwan Velu +Tested-by: Carlos Maiolino +Reviewed-by: Daniel Kiper +(cherry picked from commit a4b495520e4dc41a896a8b916a64eda9970c50ea) +--- + grub-core/fs/xfs.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 0f524c3a8a..e3816d1ec4 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -192,6 +192,11 @@ struct grub_xfs_time_legacy + grub_uint32_t nanosec; + } GRUB_PACKED; + ++/* ++ * The struct grub_xfs_inode layout was taken from the ++ * struct xfs_dinode_core which is described here: ++ * https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf ++ */ + struct grub_xfs_inode + { + grub_uint8_t magic[2]; +@@ -208,14 +213,15 @@ struct grub_xfs_inode + grub_uint32_t nextents; + grub_uint16_t unused3; + grub_uint8_t fork_offset; +- grub_uint8_t unused4[37]; ++ grub_uint8_t unused4[17]; /* Last member of inode v2. */ ++ grub_uint8_t unused5[20]; /* First member of inode v3. */ + grub_uint64_t flags2; +- grub_uint8_t unused5[48]; ++ grub_uint8_t unused6[48]; /* Last member of inode v3. */ + } GRUB_PACKED; + + #define XFS_V3_INODE_SIZE sizeof(struct grub_xfs_inode) +-/* Size of struct grub_xfs_inode until fork_offset (included). */ +-#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 92) ++/* Size of struct grub_xfs_inode v2, up to unused4 member included. */ ++#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + + struct grub_xfs_dirblock_tail + { diff --git a/SOURCES/0189-Print-module-name-on-license-check-failure.patch b/SOURCES/0189-Print-module-name-on-license-check-failure.patch new file mode 100644 index 0000000..5c30859 --- /dev/null +++ b/SOURCES/0189-Print-module-name-on-license-check-failure.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 12 Oct 2021 12:34:23 -0400 +Subject: [PATCH] Print module name on license check failure + +At the very least, this will make it easier to track down the problem +module - or, if something else has gone wrong, provide more information +for debugging. + +Signed-off-by: Robbie Harwood +--- + grub-core/kern/dl.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 9557254035..f304494574 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -528,14 +528,16 @@ grub_dl_find_section_index (Elf_Ehdr *e, const char *name) + Be sure to understand your license obligations. + */ + static grub_err_t +-grub_dl_check_license (Elf_Ehdr *e) ++grub_dl_check_license (grub_dl_t mod, Elf_Ehdr *e) + { + Elf_Shdr *s = grub_dl_find_section (e, ".module_license"); + if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0 + || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0 + || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0)) + return GRUB_ERR_NONE; +- return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license"); ++ return grub_error (GRUB_ERR_BAD_MODULE, ++ "incompatible license in module %s: %s", mod->name, ++ (char *) e + s->sh_offset); + } + + static grub_err_t +@@ -743,8 +745,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + constitutes linking) and GRUB core being licensed under GPLv3+. + Be sure to understand your license obligations. + */ +- if (grub_dl_check_license (e) +- || grub_dl_resolve_name (mod, e) ++ if (grub_dl_resolve_name (mod, e) ++ || grub_dl_check_license (mod, e) + || grub_dl_resolve_dependencies (mod, e) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) diff --git a/SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch b/SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch new file mode 100644 index 0000000..216418b --- /dev/null +++ b/SOURCES/0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 22 Oct 2021 09:53:15 +1100 +Subject: [PATCH] powerpc-ieee1275: load grub at 4MB, not 2MB + +This was first reported under PFW but reproduces under SLOF. + + - The core.elf was 2126152 = 0x207148 bytes in size with the following + program headers (per readelf): + +Entry point 0x200000 +There are 4 program headers, starting at offset 52 + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + LOAD 0x000160 0x00200000 0x00200000 0x21f98 0x2971c RWE 0x8 + GNU_STACK 0x0220f8 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4 + LOAD 0x0220f8 0x00232000 0x00232000 0x1e4e50 0x1e4e50 RWE 0x4 + NOTE 0x206f48 0x00000000 0x00000000 0x00200 0x00000 R 0x4 + + - SLOF places the ELF file at 0x4000 (after the reserved space for + interrupt handlers etc.) upwards. The image was 2126152 = 0x207148 + bytes in size, so it runs from 0x4000 - 0x20b148. We'll call 0x4000 the + load address. + +0x0 0x4000 0x20b148 + |----------|--------------| + | reserved | ELF contents | + + - SLOF then copies the first LOAD program header (for .text). That runs + for 0x21f98 bytes. It runs from + (load addr + 0x160) to (load addr + 0x160 + 0x21f98) + = 0x4160 to 0x260f8 + and we copy it to 0x200000 to 0x221f98. This overwrites the end of the + image: + +0x0 0x4000 0x200000 0x221f98 + |----------|------------|---------------| + | reserved | ELF cont.. | .text section | + + - SLOF zeros the bss up to PhysAddr + MemSize = 0x22971c + +0x0 0x4000 0x200000 0x221f98 0x22971c + |----------|------------|---------------|--------| + | reserved | ELF cont.. | .text section | bss 0s | + + - SLOF then goes to fulfil the next LOAD header (for mods), which is + for 0x1e4e50 bytes. We copy from + (load addr + 0x220f8) to (load addr + 0x220f8 + 0x1e4e50) + = 0x260f8 to 0x20af48 + and we copy it to 0x232000 to 0x416e50: + +0x0 0x4000 0x200000 0x221f98 0x22971c + |----------|------------|---------------|--------| + | reserved | ELF cont.. | .text section | bss 0s | + |-------------| + | copied area | + 0x260f8 0x20af48 + + This goes poorly: + +0x0 0x4000 0x200000 0x221f98 0x22971c 0x232000 0x40bf08 0x416e50 + |----------|------------|---------------|--------|-----|-----------|-------------| + | reserved | ELF cont.. | .text section | bss 0s | pad | some mods | .text start | + +This matches the observations on the running system - 0x40bf08 was where +the contents of memory no longer matched the contents of the ELF file. + +This was reported as a license verification failure on SLOF as the +last module's .module_license section fell past where the corruption +began. + +Signed-off-by: Daniel Axtens +[rharwood@redhat.com: trim very detailed commit message] +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 2 +- + include/grub/offsets.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 4a57de975e..08ac0fb15f 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -89,7 +89,7 @@ kernel = { + i386_xen_pvh_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x100000'; + + mips_loongson_ldflags = '-Wl,-Ttext,0x80200000'; +- powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x200000'; ++ powerpc_ieee1275_ldflags = '-Wl,-Ttext,0x400000'; + sparc64_ieee1275_ldflags = '-Wl,-Ttext,0x4400'; + mips_arc_ldflags = '-Wl,-Ttext,$(TARGET_LINK_ADDR)'; + mips_qemu_mips_ldflags = '-Wl,-Ttext,0x80200000'; +diff --git a/include/grub/offsets.h b/include/grub/offsets.h +index 871e1cd4c3..69211aa798 100644 +--- a/include/grub/offsets.h ++++ b/include/grub/offsets.h +@@ -63,7 +63,7 @@ + #define GRUB_KERNEL_SPARC64_IEEE1275_LINK_ADDR 0x4400 + + #define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ALIGN 4 +-#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x200000 ++#define GRUB_KERNEL_POWERPC_IEEE1275_LINK_ADDR 0x400000 + + #define GRUB_KERNEL_MIPS_LOONGSON_LINK_ADDR 0x80200000 + diff --git a/SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch b/SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch new file mode 100644 index 0000000..76b73f5 --- /dev/null +++ b/SOURCES/0191-grub-mkconfig-restore-umask-for-grub.cfg.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang via Grub-devel +Date: Fri, 3 Dec 2021 16:13:28 +0800 +Subject: [PATCH] grub-mkconfig: restore umask for grub.cfg + +Since commit: + + ab2e53c8a grub-mkconfig: Honor a symlink when generating configuration +by grub-mkconfig + +has inadvertently discarded umask for creating grub.cfg in the process +of grub-mkconfig. The resulting wrong permission (0644) would allow +unprivileged users to read grub's configuration file content. This +presents a low confidentiality risk as grub.cfg may contain non-secured +plain-text passwords. + +This patch restores the missing umask and set the file mode of creation +to 0600 preventing unprivileged access. + +Fixes: CVE-2021-3981 + +Signed-off-by: Michael Chang +--- + util/grub-mkconfig.in | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index f55339a3f6..520a672cd2 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -311,7 +311,9 @@ and /etc/grub.d/* files or please file a bug report with + exit 1 + else + # none of the children aborted with error, install the new grub.cfg ++ oldumask=$(umask); umask 077 + cat ${grub_cfg}.new > ${grub_cfg} ++ umask $oldumask + rm -f ${grub_cfg}.new + fi + fi diff --git a/SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch b/SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch new file mode 100644 index 0000000..3f7198f --- /dev/null +++ b/SOURCES/0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Mon, 13 Dec 2021 14:25:49 +0800 +Subject: [PATCH] fs/btrfs: Use full btrfs bootloader area + +Up to now GRUB can only embed to the first 64 KiB before primary +superblock of btrfs, effectively limiting the GRUB core size. That +could consequently pose restrictions to feature enablement like +advanced zstd compression. + +This patch attempts to utilize full unused area reserved by btrfs for +the bootloader outlined in the document [1]: + + The first 1MiB on each device is unused with the exception of primary + superblock that is on the offset 64KiB and spans 4KiB. + +Apart from that, adjacent sectors to superblock and first block group +are not used for embedding in case of overflow and logged access to +adjacent sectors could be useful for tracing it up. + +This patch has been tested to provide out of the box support for btrfs +zstd compression with which GRUB has been installed to the partition. + +[1] https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT + +Signed-off-by: Michael Chang +Reviewed-by: Daniel Kiper +(cherry picked from commit b0f06a81c6f31b6fa20be67a96b6683bba8210c9) +--- + grub-core/fs/btrfs.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-------- + include/grub/disk.h | 2 ++ + 2 files changed, 79 insertions(+), 13 deletions(-) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 4cc86e9b79..07c0ff874b 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2476,6 +2476,33 @@ grub_btrfs_label (grub_device_t device, char **label) + } + + #ifdef GRUB_UTIL ++ ++struct embed_region { ++ unsigned int start; ++ unsigned int secs; ++}; ++ ++/* ++ * https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT ++ * The first 1 MiB on each device is unused with the exception of primary ++ * superblock that is on the offset 64 KiB and spans 4 KiB. ++ */ ++ ++static const struct { ++ struct embed_region available; ++ struct embed_region used[6]; ++} btrfs_head = { ++ .available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */ ++ .used = { ++ {0, 1}, /* boot.S. */ ++ {GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */ ++ {GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */ ++ {GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */ ++ {GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */ ++ {0, 0} /* Array terminator. */ ++ } ++}; ++ + static grub_err_t + grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + unsigned int *nsectors, +@@ -2483,25 +2510,62 @@ grub_btrfs_embed (grub_device_t device __attribute__ ((unused)), + grub_embed_type_t embed_type, + grub_disk_addr_t **sectors) + { +- unsigned i; ++ unsigned int i, j, n = 0; ++ const struct embed_region *u; ++ grub_disk_addr_t *map; + + if (embed_type != GRUB_EMBED_PCBIOS) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "BtrFS currently supports only PC-BIOS embedding"); + +- if (64 * 2 - 1 < *nsectors) +- return grub_error (GRUB_ERR_OUT_OF_RANGE, +- N_("your core.img is unusually large. " +- "It won't fit in the embedding area")); +- +- *nsectors = 64 * 2 - 1; +- if (*nsectors > max_nsectors) +- *nsectors = max_nsectors; +- *sectors = grub_calloc (*nsectors, sizeof (**sectors)); +- if (!*sectors) ++ map = grub_calloc (btrfs_head.available.secs, sizeof (*map)); ++ if (map == NULL) + return grub_errno; +- for (i = 0; i < *nsectors; i++) +- (*sectors)[i] = i + 1; ++ ++ /* ++ * Populating the map array so that it can be used to index if a disk ++ * address is available to embed: ++ * - 0: available, ++ * - 1: unavailable. ++ */ ++ for (u = btrfs_head.used; u->secs; ++u) ++ { ++ unsigned int end = u->start + u->secs; ++ ++ if (end > btrfs_head.available.secs) ++ end = btrfs_head.available.secs; ++ for (i = u->start; i < end; ++i) ++ map[i] = 1; ++ } ++ ++ /* Adding up n until it matches total size of available embedding area. */ ++ for (i = 0; i < btrfs_head.available.secs; ++i) ++ if (map[i] == 0) ++ n++; ++ ++ if (n < *nsectors) ++ { ++ grub_free (map); ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("your core.img is unusually large. " ++ "It won't fit in the embedding area")); ++ } ++ ++ if (n > max_nsectors) ++ n = max_nsectors; ++ ++ /* ++ * Populating the array so that it can used to index disk block address for ++ * an image file's offset to be embedded on disk (the unit is in sectors): ++ * - i: The disk block address relative to btrfs_head.available.start, ++ * - j: The offset in image file. ++ */ ++ for (i = 0, j = 0; i < btrfs_head.available.secs && j < n; ++i) ++ if (map[i] == 0) ++ map[j++] = btrfs_head.available.start + i; ++ ++ *nsectors = n; ++ *sectors = map; + + return GRUB_ERR_NONE; + } +diff --git a/include/grub/disk.h b/include/grub/disk.h +index f95aca929a..06210a7049 100644 +--- a/include/grub/disk.h ++++ b/include/grub/disk.h +@@ -182,6 +182,8 @@ typedef struct grub_disk_memberlist *grub_disk_memberlist_t; + /* Return value of grub_disk_native_sectors() in case disk size is unknown. */ + #define GRUB_DISK_SIZE_UNKNOWN 0xffffffffffffffffULL + ++#define GRUB_DISK_KiB_TO_SECTORS(x) ((x) << (10 - GRUB_DISK_SECTOR_BITS)) ++ + /* Convert sector number from one sector size to another. */ + static inline grub_disk_addr_t + grub_convert_sector (grub_disk_addr_t sector, diff --git a/SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch b/SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch new file mode 100644 index 0000000..070fc24 --- /dev/null +++ b/SOURCES/0193-Add-Fedora-location-of-DejaVu-SANS-font.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: fluteze +Date: Sat, 27 Nov 2021 10:54:44 -0600 +Subject: [PATCH] Add Fedora location of DejaVu SANS font + +In Fedora 35, and possibly earlier, grub would fail to configure with a +complaint about DejaVu being "not found" even though it was installed. +The DejaVu sans font search path is updated to reflect the +distribution's current install path. + +Signed-off-by: Erik Edwards +[rharwood@redhat.com: slight commit message edits] +Signed-off-by: Robbie Harwood +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index ab0d326f00..40c4338bce 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1784,7 +1784,7 @@ fi + + if test x"$starfield_excuse" = x; then + for ext in pcf pcf.gz bdf bdf.gz ttf ttf.gz; do +- for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype; do ++ for dir in . /usr/src /usr/share/fonts/X11/misc /usr/share/fonts/truetype/ttf-dejavu /usr/share/fonts/dejavu /usr/share/fonts/truetype /usr/share/fonts/dejavu-sans-fonts; do + if test -f "$dir/DejaVuSans.$ext"; then + DJVU_FONT_SOURCE="$dir/DejaVuSans.$ext" + break 2 diff --git a/SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch b/SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch new file mode 100644 index 0000000..200cd51 --- /dev/null +++ b/SOURCES/0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 11:30:32 +0100 +Subject: [PATCH] normal/menu: Don't show "Booting `%s'" msg when auto-booting + with TIMEOUT_STYLE_HIDDEN + +When the user has asked the menu code to be hidden/quiet and the current +entry is being autobooted because the timeout has expired don't show +the "Booting `%s'" msg. + +This is necessary to let flicker-free boots really be flicker free, +otherwise the "Booting `%s'" msg will kick the EFI fb into text mode +and show the msg, breaking the flicker-free experience. + +Signed-off-by: Hans de Goede +--- + grub-core/normal/menu.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c +index ec0c92bade..c8516a5a08 100644 +--- a/grub-core/normal/menu.c ++++ b/grub-core/normal/menu.c +@@ -606,13 +606,15 @@ print_countdown (struct grub_term_coordinate *pos, int n) + entry to be executed is a result of an automatic default selection because + of the timeout. */ + static int +-run_menu (grub_menu_t menu, int nested, int *auto_boot) ++run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + { + grub_uint64_t saved_time; + int default_entry, current_entry; + int timeout; + enum timeout_style timeout_style; + ++ *notify_boot = 1; ++ + default_entry = get_entry_number (menu, "default"); + + /* If DEFAULT_ENTRY is not within the menu entries, fall back to +@@ -687,6 +689,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + if (timeout == 0) + { + *auto_boot = 1; ++ *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN; + return default_entry; + } + +@@ -840,12 +843,16 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot) + + /* Callback invoked immediately before a menu entry is executed. */ + static void +-notify_booting (grub_menu_entry_t entry, +- void *userdata __attribute__((unused))) ++notify_booting (grub_menu_entry_t entry, void *userdata) + { +- grub_printf (" "); +- grub_printf_ (N_("Booting `%s'"), entry->title); +- grub_printf ("\n\n"); ++ int *notify_boot = userdata; ++ ++ if (*notify_boot) ++ { ++ grub_printf (" "); ++ grub_printf_ (N_("Booting `%s'"), entry->title); ++ grub_printf ("\n\n"); ++ } + } + + /* Callback invoked when a default menu entry executed because of a timeout +@@ -893,8 +900,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + int boot_entry; + grub_menu_entry_t e; + int auto_boot; ++ int notify_boot; + +- boot_entry = run_menu (menu, nested, &auto_boot); ++ boot_entry = run_menu (menu, nested, &auto_boot, ¬ify_boot); + if (boot_entry < 0) + break; + +@@ -906,7 +914,7 @@ show_menu (grub_menu_t menu, int nested, int autobooted) + + if (auto_boot) + grub_menu_execute_with_fallback (menu, e, autobooted, +- &execution_callback, 0); ++ &execution_callback, ¬ify_boot); + else + grub_menu_execute_entry (e, 0); + if (autobooted) diff --git a/SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch b/SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch new file mode 100644 index 0000000..0f99c22 --- /dev/null +++ b/SOURCES/0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 11:30:33 +0100 +Subject: [PATCH] EFI: suppress the "Welcome to GRUB!" message in EFI builds + +Grub EFI builds are now often used in combination with flicker-free +boot, but this breaks with upstream grub because the "Welcome to GRUB!" +message will kick the EFI fb into text mode and show the msg, +breaking the flicker-free experience. + +EFI systems are so fast, that when the menu or the countdown are enabled +the message will be immediately overwritten, so in these cases not +printing the message does not matter. + +And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN, +the user has asked grub to be quiet (for example to allow flickfree +boot) annd thus the message should not be printed. + +Signed-off-by: Hans de Goede +--- + grub-core/kern/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 3fc3401472..993b8a8598 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -317,10 +317,13 @@ grub_main (void) + + grub_boot_time ("After machine init."); + ++ /* This breaks flicker-free boot on EFI systems, so disable it there. */ ++#ifndef GRUB_MACHINE_EFI + /* Hello. */ + grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); + grub_printf ("Welcome to GRUB!\n\n"); + grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); ++#endif + + /* Init verifiers API. */ + grub_verifiers_init (); diff --git a/SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch b/SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch new file mode 100644 index 0000000..ade6aae --- /dev/null +++ b/SOURCES/0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 12:43:48 +0100 +Subject: [PATCH] EFI: console: Do not set colorstate until the first text + output + +GRUB_MOD_INIT(normal) does an unconditional: + +grub_env_set ("color_normal", "light-gray/black"); + +which triggers a grub_term_setcolorstate() call. The original version +of the "efi/console: Do not set text-mode until we actually need it" patch: +https://lists.gnu.org/archive/html/grub-devel/2018-03/msg00125.html + +Protected against this by caching the requested state in +grub_console_setcolorstate () and then only applying it when the first +text output actually happens. During refactoring to move the +grub_console_setcolorstate () up higher in the grub-core/term/efi/console.c +file the code to cache the color-state + bail early was accidentally +dropped. + +Restore the cache the color-state + bail early behavior from the original. + +Cc: Javier Martinez Canillas +Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") +Signed-off-by: Hans de Goede +--- + grub-core/term/efi/console.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c +index 2f1ae85ba7..c44b2ac318 100644 +--- a/grub-core/term/efi/console.c ++++ b/grub-core/term/efi/console.c +@@ -82,6 +82,16 @@ grub_console_setcolorstate (struct grub_term_output *term + { + grub_efi_simple_text_output_interface_t *o; + ++ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) ++ { ++ /* ++ * Cache colorstate changes before the first text-output, this avoids ++ * "color_normal" environment writes causing a switch to textmode. ++ */ ++ text_colorstate = state; ++ return; ++ } ++ + if (grub_efi_is_finished) + return; + diff --git a/SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch b/SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch new file mode 100644 index 0000000..5fab5db --- /dev/null +++ b/SOURCES/0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 28 Jan 2022 12:43:49 +0100 +Subject: [PATCH] EFI: console: Do not set cursor until the first text output + +To allow flickerfree boot the EFI console code does not call +grub_efi_set_text_mode (1) until some text is actually output. + +Depending on if the output text is because of an error loading +e.g. the .cfg file; or because of showing the menu the cursor needs +to be on or off when the first text is shown. + +So far the cursor was hardcoded to being on, but this is causing +drawing artifacts + slow drawing of the menu as reported here: +https://bugzilla.redhat.com/show_bug.cgi?id=1946969 + +Handle the cursorstate in the same way as the colorstate to fix this, +when no text has been output yet, just cache the cursorstate and +then use the last set value when the first text is output. + +Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it") +Signed-off-by: Hans de Goede +--- + grub-core/term/efi/console.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c +index c44b2ac318..a3622e4fe5 100644 +--- a/grub-core/term/efi/console.c ++++ b/grub-core/term/efi/console.c +@@ -31,7 +31,15 @@ typedef enum { + } + grub_text_mode; + ++typedef enum { ++ GRUB_CURSOR_MODE_UNDEFINED = -1, ++ GRUB_CURSOR_MODE_OFF = 0, ++ GRUB_CURSUR_MODE_ON ++} ++grub_cursor_mode; ++ + static grub_text_mode text_mode = GRUB_TEXT_MODE_UNDEFINED; ++static grub_cursor_mode cursor_mode = GRUB_CURSOR_MODE_UNDEFINED; + static grub_term_color_state text_colorstate = GRUB_TERM_COLOR_UNDEFINED; + + static grub_uint32_t +@@ -119,8 +127,12 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)), + { + grub_efi_simple_text_output_interface_t *o; + +- if (grub_efi_is_finished) +- return; ++ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE) ++ { ++ /* Cache cursor changes before the first text-output */ ++ cursor_mode = on; ++ return; ++ } + + o = grub_efi_system_table->con_out; + efi_call_2 (o->enable_cursor, o, on); +@@ -143,7 +155,8 @@ grub_prepare_for_text_output (struct grub_term_output *term) + return GRUB_ERR_BAD_DEVICE; + } + +- grub_console_setcursor (term, 1); ++ if (cursor_mode != GRUB_CURSOR_MODE_UNDEFINED) ++ grub_console_setcursor (term, cursor_mode); + if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED) + grub_console_setcolorstate (term, text_colorstate); + text_mode = GRUB_TEXT_MODE_AVAILABLE; diff --git a/SOURCES/0198-Use-visual-indentation-in-config.h.in.patch b/SOURCES/0198-Use-visual-indentation-in-config.h.in.patch new file mode 100644 index 0000000..978eb07 --- /dev/null +++ b/SOURCES/0198-Use-visual-indentation-in-config.h.in.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 15 Dec 2021 15:46:13 -0500 +Subject: [PATCH] Use visual indentation in config.h.in + +Signed-off-by: Robbie Harwood +(cherry picked from commit de8051f34de0aa55c921a510974e5bb27e39c17b) +[rharwood: GRUB_RPM_CONFIG presence] +--- + config.h.in | 58 +++++++++++++++++++++++++++++----------------------------- + 1 file changed, 29 insertions(+), 29 deletions(-) + +diff --git a/config.h.in b/config.h.in +index c80e3e0aba..f2ed0066ec 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -23,47 +23,47 @@ + #define MINILZO_CFG_SKIP_LZO1X_DECOMPRESS 1 + + #if defined (GRUB_BUILD) +-#undef ENABLE_NLS +-#define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@ +-#define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@ +-#if defined __APPLE__ +-# if defined __BIG_ENDIAN__ +-# define BUILD_WORDS_BIGENDIAN 1 +-# else +-# define BUILD_WORDS_BIGENDIAN 0 +-# endif +-#else +-#define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@ +-#endif ++# undef ENABLE_NLS ++# define BUILD_SIZEOF_LONG @BUILD_SIZEOF_LONG@ ++# define BUILD_SIZEOF_VOID_P @BUILD_SIZEOF_VOID_P@ ++# if defined __APPLE__ ++# if defined __BIG_ENDIAN__ ++# define BUILD_WORDS_BIGENDIAN 1 ++# else ++# define BUILD_WORDS_BIGENDIAN 0 ++# endif ++# else /* !defined __APPLE__ */ ++# define BUILD_WORDS_BIGENDIAN @BUILD_WORDS_BIGENDIAN@ ++# endif /* !defined __APPLE__ */ + #elif defined (GRUB_UTIL) || !defined (GRUB_MACHINE) +-#include +-#else +-#define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@ ++# include ++#else /* !defined GRUB_UTIL && defined GRUB_MACHINE */ ++# define HAVE_FONT_SOURCE @HAVE_FONT_SOURCE@ + /* Define if C symbols get an underscore after compilation. */ +-#define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ ++# define HAVE_ASM_USCORE @HAVE_ASM_USCORE@ + /* Define it to one of __bss_start, edata and _edata. */ +-#define BSS_START_SYMBOL @BSS_START_SYMBOL@ ++# define BSS_START_SYMBOL @BSS_START_SYMBOL@ + /* Define it to either end or _end. */ +-#define END_SYMBOL @END_SYMBOL@ ++# define END_SYMBOL @END_SYMBOL@ + /* Name of package. */ +-#define PACKAGE "@PACKAGE@" ++# define PACKAGE "@PACKAGE@" + /* Version number of package. */ +-#define VERSION "@VERSION@" ++# define VERSION "@VERSION@" + /* Define to the full name and version of this package. */ +-#define PACKAGE_STRING "@PACKAGE_STRING@" ++# define PACKAGE_STRING "@PACKAGE_STRING@" + /* Define to the version of this package. */ +-#define PACKAGE_VERSION "@PACKAGE_VERSION@" ++# define PACKAGE_VERSION "@PACKAGE_VERSION@" + /* Define to the full name of this package. */ +-#define PACKAGE_NAME "@PACKAGE_NAME@" ++# define PACKAGE_NAME "@PACKAGE_NAME@" + /* Define to the address where bug reports for this package should be sent. */ +-#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" ++# define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +-#define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" +-#define GRUB_PLATFORM "@GRUB_PLATFORM@" +-#define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" ++# define GRUB_TARGET_CPU "@GRUB_TARGET_CPU@" ++# define GRUB_PLATFORM "@GRUB_PLATFORM@" ++# define GRUB_RPM_VERSION "@GRUB_RPM_VERSION@" + +-#define RE_ENABLE_I18N 1 ++# define RE_ENABLE_I18N 1 + +-#define _GNU_SOURCE 1 ++# define _GNU_SOURCE 1 + + #endif diff --git a/SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch b/SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch new file mode 100644 index 0000000..22c2d9c --- /dev/null +++ b/SOURCES/0199-Where-present-ensure-config-util.h-precedes-config.h.patch @@ -0,0 +1,275 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 22 Feb 2022 16:57:54 -0500 +Subject: [PATCH] Where present, ensure config-util.h precedes config.h + +gnulib defines go in config-util.h, and we need to know whether to +provide duplicates in config.h or not. + +Signed-off-by: Robbie Harwood +(cherry picked from commit 46e82b28e1a75703d0424c7e13d009171310c6cd) +[rharwood: gensymlist isn't part of tarballs] +--- + grub-core/disk/host.c | 2 +- + grub-core/kern/emu/argp_common.c | 2 +- + grub-core/kern/emu/main.c | 2 +- + grub-core/osdep/aros/config.c | 2 +- + grub-core/osdep/basic/emunet.c | 2 +- + grub-core/osdep/basic/init.c | 2 +- + grub-core/osdep/haiku/getroot.c | 2 +- + grub-core/osdep/linux/emunet.c | 2 +- + grub-core/osdep/unix/config.c | 2 +- + grub-core/osdep/unix/cputime.c | 2 +- + grub-core/osdep/unix/dl.c | 2 +- + grub-core/osdep/unix/emuconsole.c | 2 +- + grub-core/osdep/unix/getroot.c | 2 +- + grub-core/osdep/windows/config.c | 2 +- + grub-core/osdep/windows/cputime.c | 2 +- + grub-core/osdep/windows/dl.c | 2 +- + grub-core/osdep/windows/emuconsole.c | 2 +- + grub-core/osdep/windows/init.c | 2 +- + 18 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/grub-core/disk/host.c b/grub-core/disk/host.c +index c151d225df..f34529f86a 100644 +--- a/grub-core/disk/host.c ++++ b/grub-core/disk/host.c +@@ -20,8 +20,8 @@ + /* When using the disk, make a reference to this module. Otherwise + the user will end up with a useless module :-). */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/kern/emu/argp_common.c b/grub-core/kern/emu/argp_common.c +index 1668858703..8cb4608c3d 100644 +--- a/grub-core/kern/emu/argp_common.c ++++ b/grub-core/kern/emu/argp_common.c +@@ -17,8 +17,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #pragma GCC diagnostic ignored "-Wmissing-prototypes" + #pragma GCC diagnostic ignored "-Wmissing-declarations" +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 55ea5a11cc..12277c34d2 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/aros/config.c b/grub-core/osdep/aros/config.c +index c82d0ea8e7..55f5728efc 100644 +--- a/grub-core/osdep/aros/config.c ++++ b/grub-core/osdep/aros/config.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/basic/emunet.c b/grub-core/osdep/basic/emunet.c +index 6362e5cfbb..dbfd316d61 100644 +--- a/grub-core/osdep/basic/emunet.c ++++ b/grub-core/osdep/basic/emunet.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/basic/init.c b/grub-core/osdep/basic/init.c +index c54c710dbc..b104c7e162 100644 +--- a/grub-core/osdep/basic/init.c ++++ b/grub-core/osdep/basic/init.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/haiku/getroot.c b/grub-core/osdep/haiku/getroot.c +index 4e123c0903..927a1ebc94 100644 +--- a/grub-core/osdep/haiku/getroot.c ++++ b/grub-core/osdep/haiku/getroot.c +@@ -1,5 +1,5 @@ +-#include + #include ++#include + #include + #include + #include +diff --git a/grub-core/osdep/linux/emunet.c b/grub-core/osdep/linux/emunet.c +index 19b188f09e..d5a6417355 100644 +--- a/grub-core/osdep/linux/emunet.c ++++ b/grub-core/osdep/linux/emunet.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c +index 46a881530c..0ce0e309ac 100644 +--- a/grub-core/osdep/unix/config.c ++++ b/grub-core/osdep/unix/config.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/cputime.c b/grub-core/osdep/unix/cputime.c +index cff359a3b9..fb6ff55a1a 100644 +--- a/grub-core/osdep/unix/cputime.c ++++ b/grub-core/osdep/unix/cputime.c +@@ -1,5 +1,5 @@ +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/dl.c b/grub-core/osdep/unix/dl.c +index 562b101a28..99b189bc1c 100644 +--- a/grub-core/osdep/unix/dl.c ++++ b/grub-core/osdep/unix/dl.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/emuconsole.c b/grub-core/osdep/unix/emuconsole.c +index 7308798efe..cac159424d 100644 +--- a/grub-core/osdep/unix/emuconsole.c ++++ b/grub-core/osdep/unix/emuconsole.c +@@ -17,8 +17,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c +index 46d7116c6e..4f436284ce 100644 +--- a/grub-core/osdep/unix/getroot.c ++++ b/grub-core/osdep/unix/getroot.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/config.c b/grub-core/osdep/windows/config.c +index 928ab1a49b..2bb8a2fd88 100644 +--- a/grub-core/osdep/windows/config.c ++++ b/grub-core/osdep/windows/config.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/cputime.c b/grub-core/osdep/windows/cputime.c +index 3568aa2d35..5d06d79dd5 100644 +--- a/grub-core/osdep/windows/cputime.c ++++ b/grub-core/osdep/windows/cputime.c +@@ -1,5 +1,5 @@ +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/dl.c b/grub-core/osdep/windows/dl.c +index eec6a24ad7..8eab7057e4 100644 +--- a/grub-core/osdep/windows/dl.c ++++ b/grub-core/osdep/windows/dl.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c +index 4fb3693cc0..17a44de469 100644 +--- a/grub-core/osdep/windows/emuconsole.c ++++ b/grub-core/osdep/windows/emuconsole.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + + #include + #include +diff --git a/grub-core/osdep/windows/init.c b/grub-core/osdep/windows/init.c +index 6297de6326..51a9647dde 100644 +--- a/grub-core/osdep/windows/init.c ++++ b/grub-core/osdep/windows/init.c +@@ -16,8 +16,8 @@ + * along with GRUB. If not, see . + */ + +-#include + #include ++#include + #include + #include + #include diff --git a/SOURCES/0200-Drop-gnulib-fix-base64.patch.patch b/SOURCES/0200-Drop-gnulib-fix-base64.patch.patch new file mode 100644 index 0000000..054e476 --- /dev/null +++ b/SOURCES/0200-Drop-gnulib-fix-base64.patch.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Thu, 28 Oct 2021 15:07:50 -0400 +Subject: [PATCH] Drop gnulib fix-base64.patch + +Originally added in 9fbdec2f6b4fa8b549daa4d49134d1fe89d95ef9 and +subsequently modified in 552c9fd08122a3036c724ce96dfe68aa2f75705f, +fix-base64.patch handled two problems we have using gnulib, which are +exerciesd by the base64 module but not directly caused by it. + +First, grub2 defines its own bool type, while gnulib expects the +equivalent of stdbool.h to be present. Rather than patching gnulib, +instead use gnulib's stdbool module to provide a bool type if needed. +(Suggested by Simon Josefsson.) + +Second, our config.h doesn't always inherit config-util.h, which is +where gnulib-related options like _GL_ATTRIBUTE_CONST end up. +fix-base64.h worked around this by defining the attribute away, but this +workaround is better placed in config.h itself, not a gnulib patch. + +Signed-off-by: Robbie Harwood +(cherry picked from commit 54fd1c3301dd15f6b6212c12887265e8a6cbc076) +--- + grub-core/lib/posix_wrap/sys/types.h | 7 +++---- + grub-core/lib/xzembed/xz.h | 5 +---- + bootstrap.conf | 3 ++- + conf/Makefile.extra-dist | 1 - + config.h.in | 4 ++++ + grub-core/lib/gnulib-patches/fix-base64.patch | 21 --------------------- + 6 files changed, 10 insertions(+), 31 deletions(-) + delete mode 100644 grub-core/lib/gnulib-patches/fix-base64.patch + +diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h +index f63412c8da..2f3e865495 100644 +--- a/grub-core/lib/posix_wrap/sys/types.h ++++ b/grub-core/lib/posix_wrap/sys/types.h +@@ -23,11 +23,10 @@ + + #include + ++/* Provided by gnulib if not present. */ ++#include ++ + typedef grub_ssize_t ssize_t; +-#ifndef GRUB_POSIX_BOOL_DEFINED +-typedef enum { false = 0, true = 1 } bool; +-#define GRUB_POSIX_BOOL_DEFINED 1 +-#endif + + typedef grub_uint8_t uint8_t; + typedef grub_uint16_t uint16_t; +diff --git a/grub-core/lib/xzembed/xz.h b/grub-core/lib/xzembed/xz.h +index f7b32d8003..d1417039aa 100644 +--- a/grub-core/lib/xzembed/xz.h ++++ b/grub-core/lib/xzembed/xz.h +@@ -29,10 +29,7 @@ + #include + #include + #include +- +-#ifndef GRUB_POSIX_BOOL_DEFINED +-typedef enum { false = 0, true = 1 } bool; +-#endif ++#include + + /** + * enum xz_ret - Return codes +diff --git a/bootstrap.conf b/bootstrap.conf +index 52d4af44be..645e3a459c 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -35,6 +35,7 @@ gnulib_modules=" + realloc-gnu + regex + save-cwd ++ stdbool + " + + gnulib_tool_option_extras="\ +@@ -79,7 +80,7 @@ cp -a INSTALL INSTALL.grub + + bootstrap_post_import_hook () { + set -e +- for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ ++ for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ + fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do + patch -d grub-core/lib/gnulib -p2 \ + < "grub-core/lib/gnulib-patches/$patchname.patch" +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index ad235de7fc..f4791dc6ca 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,7 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh + EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-base64.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch +diff --git a/config.h.in b/config.h.in +index f2ed0066ec..9c7b4afaaa 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -66,4 +66,8 @@ + + # define _GNU_SOURCE 1 + ++# ifndef _GL_INLINE_HEADER_BEGIN ++# define _GL_ATTRIBUTE_CONST __attribute__ ((const)) ++# endif /* !_GL_INLINE_HEADER_BEGIN */ ++ + #endif +diff --git a/grub-core/lib/gnulib-patches/fix-base64.patch b/grub-core/lib/gnulib-patches/fix-base64.patch +deleted file mode 100644 +index 985db12797..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-base64.patch ++++ /dev/null +@@ -1,21 +0,0 @@ +-diff --git a/lib/base64.h b/lib/base64.h +-index 9cd0183b8..185a2afa1 100644 +---- a/lib/base64.h +-+++ b/lib/base64.h +-@@ -21,8 +21,14 @@ +- /* Get size_t. */ +- # include +- +--/* Get bool. */ +--# include +-+#ifndef GRUB_POSIX_BOOL_DEFINED +-+typedef enum { false = 0, true = 1 } bool; +-+#define GRUB_POSIX_BOOL_DEFINED 1 +-+#endif +-+ +-+#ifndef _GL_ATTRIBUTE_CONST +-+# define _GL_ATTRIBUTE_CONST /* empty */ +-+#endif +- +- # ifdef __cplusplus +- extern "C" { diff --git a/SOURCES/0201-Drop-gnulib-no-abort.patch.patch b/SOURCES/0201-Drop-gnulib-no-abort.patch.patch new file mode 100644 index 0000000..a12789f --- /dev/null +++ b/SOURCES/0201-Drop-gnulib-no-abort.patch.patch @@ -0,0 +1,97 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 5 Jan 2022 16:42:11 -0500 +Subject: [PATCH] Drop gnulib no-abort.patch + +Originally added in db7337a3d353a817ffe9eb4a3702120527100be9, this +patched out all relevant invocations of abort() in gnulib. While it was +not documented why at the time, testing suggests that there's no abort() +implementation available for gnulib to use. + +gnulib's position is that the use of abort() is correct here, since it +happens when input violates a "shall" from POSIX. Additionally, the +code in question is probably not reachable. Since abort() is more +friendly to user-space, they prefer to make no change, so we can just +carry a define instead. (Suggested by Paul Eggert.) + +Signed-off-by: Robbie Harwood +(cherry picked from commit 5137c8eb3ec11c3217acea1a93a3f88f3fa4cbca) +--- + bootstrap.conf | 2 +- + conf/Makefile.extra-dist | 1 - + config.h.in | 3 +++ + grub-core/lib/gnulib-patches/no-abort.patch | 26 -------------------------- + 4 files changed, 4 insertions(+), 28 deletions(-) + delete mode 100644 grub-core/lib/gnulib-patches/no-abort.patch + +diff --git a/bootstrap.conf b/bootstrap.conf +index 645e3a459c..71ce943c7d 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -81,7 +81,7 @@ cp -a INSTALL INSTALL.grub + bootstrap_post_import_hook () { + set -e + for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ +- fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do ++ fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do + patch -d grub-core/lib/gnulib -p2 \ + < "grub-core/lib/gnulib-patches/$patchname.patch" + done +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index f4791dc6ca..5eef708338 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -38,7 +38,6 @@ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/no-abort.patch + + EXTRA_DIST += grub-core/lib/libgcrypt + EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic +diff --git a/config.h.in b/config.h.in +index 9c7b4afaaa..c3134309c6 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -68,6 +68,9 @@ + + # ifndef _GL_INLINE_HEADER_BEGIN + # define _GL_ATTRIBUTE_CONST __attribute__ ((const)) ++ ++/* We don't have an abort() for gnulib to call in regexp. */ ++# define abort __builtin_unreachable + # endif /* !_GL_INLINE_HEADER_BEGIN */ + + #endif +diff --git a/grub-core/lib/gnulib-patches/no-abort.patch b/grub-core/lib/gnulib-patches/no-abort.patch +deleted file mode 100644 +index e469c4762e..0000000000 +--- a/grub-core/lib/gnulib-patches/no-abort.patch ++++ /dev/null +@@ -1,26 +0,0 @@ +-diff --git a/lib/regcomp.c b/lib/regcomp.c +-index cc85f35ac..de45ebb5c 100644 +---- a/lib/regcomp.c +-+++ b/lib/regcomp.c +-@@ -528,9 +528,9 @@ regerror (int errcode, const regex_t *__restrict preg, char *__restrict errbuf, +- to this routine. If we are given anything else, or if other regex +- code generates an invalid error code, then the program has a bug. +- Dump core so we can fix it. */ +-- abort (); +-- +-- msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); +-+ msg = gettext ("unknown regexp error"); +-+ else +-+ msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); +- +- msg_size = strlen (msg) + 1; /* Includes the null. */ +- +-@@ -1136,7 +1136,7 @@ optimize_utf8 (re_dfa_t *dfa) +- } +- break; +- default: +-- abort (); +-+ break; +- } +- +- if (mb_chars || has_period) diff --git a/SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch b/SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch new file mode 100644 index 0000000..c2c50f1 --- /dev/null +++ b/SOURCES/0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch @@ -0,0 +1,832 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 15 Dec 2021 15:07:50 -0500 +Subject: [PATCH] Update gnulib version and drop most gnulib patches + +In addition to the changes carried in our gnulib patches, several +Coverity and code hygiene fixes that were previously downstream are also +included in this 3-year gnulib increment. + +Unfortunately, fix-width.patch is retained. + +Bump minimum autoconf version from 2.63 to 2.64 and automake from 1.11 +to 1.14, as required by gnulib. + +Sync bootstrap script itself with gnulib. + +Update regexp module for new dynarray dependency. + +Fix various new warnings. + +Signed-off-by: Robbie Harwood +(cherry picked from commit deb18ff931c3133c2aa536a92bd92e50d6615303) +[rharwood: backport around requirements in INSTALL] +--- + configure.ac | 2 +- + grub-core/Makefile.core.def | 3 + + grub-core/disk/luks2.c | 4 +- + grub-core/lib/posix_wrap/limits.h | 6 +- + include/grub/compiler.h | 4 +- + include/grub/list.h | 2 +- + INSTALL | 2 +- + bootstrap | 291 ++++++++++++--------- + bootstrap.conf | 22 +- + conf/Makefile.extra-dist | 6 - + config.h.in | 68 +++++ + grub-core/lib/gnulib-patches/fix-null-deref.patch | 13 - + .../lib/gnulib-patches/fix-null-state-deref.patch | 12 - + .../gnulib-patches/fix-regcomp-uninit-token.patch | 15 -- + .../gnulib-patches/fix-regexec-null-deref.patch | 12 - + .../lib/gnulib-patches/fix-uninit-structure.patch | 11 - + .../lib/gnulib-patches/fix-unused-value.patch | 14 - + 17 files changed, 262 insertions(+), 225 deletions(-) + delete mode 100644 grub-core/lib/gnulib-patches/fix-null-deref.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-null-state-deref.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-uninit-structure.patch + delete mode 100644 grub-core/lib/gnulib-patches/fix-unused-value.patch + +diff --git a/configure.ac b/configure.ac +index 40c4338bce..79f45ef1e1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -49,7 +49,7 @@ AC_CANONICAL_TARGET + program_prefix="${save_program_prefix}" + + AM_INIT_AUTOMAKE([1.11]) +-AC_PREREQ(2.63) ++AC_PREREQ(2.64) + AC_CONFIG_SRCDIR([include/grub/dl.h]) + AC_CONFIG_HEADER([config-util.h]) + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 08ac0fb15f..ec1ec5083b 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -762,6 +762,9 @@ module = { + name = regexp; + common = commands/regexp.c; + common = commands/wildcard.c; ++ common = lib/gnulib/malloc/dynarray_finalize.c; ++ common = lib/gnulib/malloc/dynarray_emplace_enlarge.c; ++ common = lib/gnulib/malloc/dynarray_resize.c; + common = lib/gnulib/regex.c; + cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)'; + cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; +diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c +index 371a53b837..c917a5f91e 100644 +--- a/grub-core/disk/luks2.c ++++ b/grub-core/disk/luks2.c +@@ -389,7 +389,7 @@ luks2_verify_key (grub_luks2_digest_t *d, grub_uint8_t *candidate_key, + { + grub_uint8_t candidate_digest[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN], salt[GRUB_CRYPTODISK_MAX_KEYLEN]; +- grub_size_t saltlen = sizeof (salt), digestlen = sizeof (digest); ++ idx_t saltlen = sizeof (salt), digestlen = sizeof (digest); + const gcry_md_spec_t *hash; + gcry_err_code_t gcry_ret; + +@@ -428,7 +428,7 @@ luks2_decrypt_key (grub_uint8_t *out_key, + grub_uint8_t area_key[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t *split_key = NULL; +- grub_size_t saltlen = sizeof (salt); ++ idx_t saltlen = sizeof (salt); + char cipher[32], *p; + const gcry_md_spec_t *hash; + gcry_err_code_t gcry_ret; +diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h +index 591dbf3289..4be7b40806 100644 +--- a/grub-core/lib/posix_wrap/limits.h ++++ b/grub-core/lib/posix_wrap/limits.h +@@ -25,7 +25,11 @@ + #define USHRT_MAX GRUB_USHRT_MAX + #define UINT_MAX GRUB_UINT_MAX + #define ULONG_MAX GRUB_ULONG_MAX +-#define SIZE_MAX GRUB_SIZE_MAX ++ ++/* gnulib also defines this type */ ++#ifndef SIZE_MAX ++# define SIZE_MAX GRUB_SIZE_MAX ++#endif + + #define SCHAR_MIN GRUB_SCHAR_MIN + #define SCHAR_MAX GRUB_SCHAR_MAX +diff --git a/include/grub/compiler.h b/include/grub/compiler.h +index ebafec6895..441a9eca07 100644 +--- a/include/grub/compiler.h ++++ b/include/grub/compiler.h +@@ -30,10 +30,10 @@ + + /* Does this compiler support compile-time error attributes? */ + #if GNUC_PREREQ(4,3) +-# define ATTRIBUTE_ERROR(msg) \ ++# define GRUB_ATTRIBUTE_ERROR(msg) \ + __attribute__ ((__error__ (msg))) + #else +-# define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) ++# define GRUB_ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn)) + #endif + + #if GNUC_PREREQ(4,4) +diff --git a/include/grub/list.h b/include/grub/list.h +index b13acb9624..21f4b4b44a 100644 +--- a/include/grub/list.h ++++ b/include/grub/list.h +@@ -40,7 +40,7 @@ void EXPORT_FUNC(grub_list_remove) (grub_list_t item); + + static inline void * + grub_bad_type_cast_real (int line, const char *file) +- ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); ++ GRUB_ATTRIBUTE_ERROR ("bad type cast between incompatible grub types"); + + static inline void * + grub_bad_type_cast_real (int line, const char *file) +diff --git a/INSTALL b/INSTALL +index 79a0af7d93..ee9f536f76 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -42,7 +42,7 @@ If you use a development snapshot or want to hack on GRUB you may + need the following. + + * Python 2.6 or later +-* Autoconf 2.63 or later ++* Autoconf 2.64 or later + * Automake 1.11 or later + + Prerequisites for make-check: +diff --git a/bootstrap b/bootstrap +index 5b08e7e2d4..dc2238f4ad 100755 +--- a/bootstrap ++++ b/bootstrap +@@ -1,10 +1,10 @@ + #! /bin/sh + # Print a version string. +-scriptversion=2019-01-04.17; # UTC ++scriptversion=2022-01-26.05; # UTC + + # Bootstrap this package from checked-out sources. + +-# Copyright (C) 2003-2019 Free Software Foundation, Inc. ++# Copyright (C) 2003-2022 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -47,7 +47,7 @@ PERL="${PERL-perl}" + + me=$0 + +-default_gnulib_url=git://git.sv.gnu.org/gnulib ++default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git + + usage() { + cat </dev/null) ++if test -z "$package"; then ++ package=$(sed -n "$extract_package_name" configure.ac) \ ++ || die 'cannot find package name in configure.ac' ++fi + gnulib_name=lib$package + + build_aux=build-aux +@@ -290,6 +313,116 @@ find_tool () + eval "export $find_tool_envvar" + } + ++# Strip blank and comment lines to leave significant entries. ++gitignore_entries() { ++ sed '/^#/d; /^$/d' "$@" ++} ++ ++# If $STR is not already on a line by itself in $FILE, insert it at the start. ++# Entries are inserted at the start of the ignore list to ensure existing ++# entries starting with ! are not overridden. Such entries support ++# whitelisting exceptions after a more generic blacklist pattern. ++insert_if_absent() { ++ file=$1 ++ str=$2 ++ test -f $file || touch $file ++ test -r $file || die "Error: failed to read ignore file: $file" ++ duplicate_entries=$(gitignore_entries $file | sort | uniq -d) ++ if [ "$duplicate_entries" ] ; then ++ die "Error: Duplicate entries in $file: " $duplicate_entries ++ fi ++ linesold=$(gitignore_entries $file | wc -l) ++ linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) ++ if [ $linesold != $linesnew ] ; then ++ { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ ++ || die "insert_if_absent $file $str: failed" ++ fi ++} ++ ++# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with ++# insert_if_absent. ++insert_vc_ignore() { ++ vc_ignore_file="$1" ++ pattern="$2" ++ case $vc_ignore_file in ++ *.gitignore) ++ # A .gitignore entry that does not start with '/' applies ++ # recursively to subdirectories, so prepend '/' to every ++ # .gitignore entry. ++ pattern=$(echo "$pattern" | sed s,^,/,);; ++ esac ++ insert_if_absent "$vc_ignore_file" "$pattern" ++} ++ ++symlink_to_dir() ++{ ++ src=$1/$2 ++ dst=${3-$2} ++ ++ test -f "$src" && { ++ ++ # If the destination directory doesn't exist, create it. ++ # This is required at least for "lib/uniwidth/cjk.h". ++ dst_dir=$(dirname "$dst") ++ if ! test -d "$dst_dir"; then ++ mkdir -p "$dst_dir" ++ ++ # If we've just created a directory like lib/uniwidth, ++ # tell version control system(s) it's ignorable. ++ # FIXME: for now, this does only one level ++ parent=$(dirname "$dst_dir") ++ for dot_ig in x $vc_ignore; do ++ test $dot_ig = x && continue ++ ig=$parent/$dot_ig ++ insert_vc_ignore $ig "${dst_dir##*/}" ++ done ++ fi ++ ++ if $copy; then ++ { ++ test ! -h "$dst" || { ++ echo "$me: rm -f $dst" && ++ rm -f "$dst" ++ } ++ } && ++ test -f "$dst" && ++ cmp -s "$src" "$dst" || { ++ echo "$me: cp -fp $src $dst" && ++ cp -fp "$src" "$dst" ++ } ++ else ++ # Leave any existing symlink alone, if it already points to the source, ++ # so that broken build tools that care about symlink times ++ # aren't confused into doing unnecessary builds. Conversely, if the ++ # existing symlink's timestamp is older than the source, make it afresh, ++ # so that broken tools aren't confused into skipping needed builds. See ++ # . ++ test -h "$dst" && ++ src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && ++ dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && ++ test "$src_i" = "$dst_i" && ++ both_ls=$(ls -dt "$src" "$dst") && ++ test "X$both_ls" = "X$dst$nl$src" || { ++ dot_dots= ++ case $src in ++ /*) ;; ++ *) ++ case /$dst/ in ++ *//* | */../* | */./* | /*/*/*/*/*/) ++ die "invalid symlink calculation: $src -> $dst";; ++ /*/*/*/*/) dot_dots=../../../;; ++ /*/*/*/) dot_dots=../../;; ++ /*/*/) dot_dots=../;; ++ esac;; ++ esac ++ ++ echo "$me: ln -fs $dot_dots$src $dst" && ++ ln -fs "$dot_dots$src" "$dst" ++ } ++ fi ++ } ++} ++ + # Override the default configuration, if necessary. + # Make sure that bootstrap.conf is sourced from the current directory + # if we were invoked as "sh bootstrap". +@@ -320,6 +453,12 @@ do + --help) + usage + exit;; ++ --version) ++ set -e ++ echo "bootstrap $scriptversion" ++ echo "$copyright" ++ exit 0 ++ ;; + --gnulib-srcdir=*) + GNULIB_SRCDIR=${option#--gnulib-srcdir=};; + --skip-po) +@@ -335,7 +474,7 @@ do + --no-git) + use_git=false;; + *) +- die "$option: unknown option";; ++ bootstrap_option_hook $option || die "$option: unknown option";; + esac + done + +@@ -346,47 +485,6 @@ if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then + die "Bootstrapping from a non-checked-out distribution is risky." + fi + +-# Strip blank and comment lines to leave significant entries. +-gitignore_entries() { +- sed '/^#/d; /^$/d' "$@" +-} +- +-# If $STR is not already on a line by itself in $FILE, insert it at the start. +-# Entries are inserted at the start of the ignore list to ensure existing +-# entries starting with ! are not overridden. Such entries support +-# whitelisting exceptions after a more generic blacklist pattern. +-insert_if_absent() { +- file=$1 +- str=$2 +- test -f $file || touch $file +- test -r $file || die "Error: failed to read ignore file: $file" +- duplicate_entries=$(gitignore_entries $file | sort | uniq -d) +- if [ "$duplicate_entries" ] ; then +- die "Error: Duplicate entries in $file: " $duplicate_entries +- fi +- linesold=$(gitignore_entries $file | wc -l) +- linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) +- if [ $linesold != $linesnew ] ; then +- { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ +- || die "insert_if_absent $file $str: failed" +- fi +-} +- +-# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with +-# insert_if_absent. +-insert_vc_ignore() { +- vc_ignore_file="$1" +- pattern="$2" +- case $vc_ignore_file in +- *.gitignore) +- # A .gitignore entry that does not start with '/' applies +- # recursively to subdirectories, so prepend '/' to every +- # .gitignore entry. +- pattern=$(echo "$pattern" | sed s,^,/,);; +- esac +- insert_if_absent "$vc_ignore_file" "$pattern" +-} +- + # Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac. + found_aux_dir=no + grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \ +@@ -665,9 +763,25 @@ if $use_gnulib; then + shallow= + if test -z "$GNULIB_REVISION"; then + git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' ++ git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ ++ || cleanup_gnulib ++ else ++ git fetch -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' ++ mkdir -p "$gnulib_path" ++ # Only want a shallow checkout of $GNULIB_REVISION, but git does not ++ # support cloning by commit hash. So attempt a shallow fetch by commit ++ # hash to minimize the amount of data downloaded and changes needed to ++ # be processed, which can drastically reduce download and processing ++ # time for checkout. If the fetch by commit fails, a shallow fetch can ++ # not be performed because we do not know what the depth of the commit ++ # is without fetching all commits. So fallback to fetching all commits. ++ git -C "$gnulib_path" init ++ git -C "$gnulib_path" remote add origin ${GNULIB_URL:-$default_gnulib_url} ++ git -C "$gnulib_path" fetch $shallow origin "$GNULIB_REVISION" \ ++ || git -C "$gnulib_path" fetch origin \ ++ || cleanup_gnulib ++ git -C "$gnulib_path" reset --hard FETCH_HEAD + fi +- git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ +- || cleanup_gnulib + + trap - 1 2 13 15 + fi +@@ -784,75 +898,6 @@ case $SKIP_PO in + fi;; + esac + +-symlink_to_dir() +-{ +- src=$1/$2 +- dst=${3-$2} +- +- test -f "$src" && { +- +- # If the destination directory doesn't exist, create it. +- # This is required at least for "lib/uniwidth/cjk.h". +- dst_dir=$(dirname "$dst") +- if ! test -d "$dst_dir"; then +- mkdir -p "$dst_dir" +- +- # If we've just created a directory like lib/uniwidth, +- # tell version control system(s) it's ignorable. +- # FIXME: for now, this does only one level +- parent=$(dirname "$dst_dir") +- for dot_ig in x $vc_ignore; do +- test $dot_ig = x && continue +- ig=$parent/$dot_ig +- insert_vc_ignore $ig "${dst_dir##*/}" +- done +- fi +- +- if $copy; then +- { +- test ! -h "$dst" || { +- echo "$me: rm -f $dst" && +- rm -f "$dst" +- } +- } && +- test -f "$dst" && +- cmp -s "$src" "$dst" || { +- echo "$me: cp -fp $src $dst" && +- cp -fp "$src" "$dst" +- } +- else +- # Leave any existing symlink alone, if it already points to the source, +- # so that broken build tools that care about symlink times +- # aren't confused into doing unnecessary builds. Conversely, if the +- # existing symlink's timestamp is older than the source, make it afresh, +- # so that broken tools aren't confused into skipping needed builds. See +- # . +- test -h "$dst" && +- src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && +- dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && +- test "$src_i" = "$dst_i" && +- both_ls=$(ls -dt "$src" "$dst") && +- test "X$both_ls" = "X$dst$nl$src" || { +- dot_dots= +- case $src in +- /*) ;; +- *) +- case /$dst/ in +- *//* | */../* | */./* | /*/*/*/*/*/) +- die "invalid symlink calculation: $src -> $dst";; +- /*/*/*/*/) dot_dots=../../../;; +- /*/*/*/) dot_dots=../../;; +- /*/*/) dot_dots=../;; +- esac;; +- esac +- +- echo "$me: ln -fs $dot_dots$src $dst" && +- ln -fs "$dot_dots$src" "$dst" +- } +- fi +- } +-} +- + version_controlled_file() { + parent=$1 + file=$2 +@@ -970,7 +1015,7 @@ bootstrap_post_import_hook \ + # Uninitialized submodules are listed with an initial dash. + if $use_git && git submodule | grep '^-' >/dev/null; then + die "some git submodules are not initialized. " \ +- "Run 'git submodule init' and bootstrap again." ++ "Run 'git submodule update --init' and bootstrap again." + fi + + # Remove any dangling symlink matching "*.m4" or "*.[ch]" in some +@@ -1064,7 +1109,7 @@ bootstrap_epilogue + + echo "$0: done. Now you can run './configure'." + +-# Local variables: ++# Local Variables: + # eval: (add-hook 'before-save-hook 'time-stamp) + # time-stamp-start: "scriptversion=" + # time-stamp-format: "%:y-%02m-%02d.%02H" +diff --git a/bootstrap.conf b/bootstrap.conf +index 71ce943c7d..e4e5f3750a 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -1,6 +1,6 @@ + # Bootstrap configuration. + +-# Copyright (C) 2006-2019 Free Software Foundation, Inc. ++# Copyright (C) 2006-2022 Free Software Foundation, Inc. + + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by +@@ -16,11 +16,10 @@ + # along with this program. If not, see . + + +-GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263 ++GNULIB_REVISION=9f48fb992a3d7e96610c4ce8be969cff2d61a01b + + # gnulib modules used by this package. +-# mbswidth is used by gnulib-fix-width.diff's changes to argp rather than +-# directly. ++# mbswidth is used by fix-width.diff's changes to argp rather than directly. + gnulib_modules=" + argp + base64 +@@ -67,8 +66,8 @@ SKIP_PO=t + + # Build prerequisites + buildreq="\ +-autoconf 2.63 +-automake 1.11 ++autoconf 2.64 ++automake 1.14 + gettext 0.18.3 + git 1.5.5 + tar - +@@ -80,11 +79,12 @@ cp -a INSTALL INSTALL.grub + + bootstrap_post_import_hook () { + set -e +- for patchname in fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ +- fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width; do +- patch -d grub-core/lib/gnulib -p2 \ +- < "grub-core/lib/gnulib-patches/$patchname.patch" +- done ++ ++ # Instead of patching our gnulib and therefore maintaining a fork, submit ++ # changes to gnulib and update the hash above when they've merged. Do not ++ # add new patches here. ++ patch -d grub-core/lib/gnulib -p2 < grub-core/lib/gnulib-patches/fix-width.patch ++ + for patchname in \ + 0001-Support-POTFILES-shell \ + 0002-Handle-gettext_printf-shell-function \ +diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist +index 5eef708338..26ac8765e3 100644 +--- a/conf/Makefile.extra-dist ++++ b/conf/Makefile.extra-dist +@@ -31,12 +31,6 @@ EXTRA_DIST += grub-core/gensymlist.sh + EXTRA_DIST += grub-core/genemuinit.sh + EXTRA_DIST += grub-core/genemuinitheader.sh + +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-deref.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-null-state-deref.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-uninit-structure.patch +-EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch + EXTRA_DIST += grub-core/lib/gnulib-patches/fix-width.patch + + EXTRA_DIST += grub-core/lib/libgcrypt +diff --git a/config.h.in b/config.h.in +index c3134309c6..512d1bbe13 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -67,10 +67,78 @@ + # define _GNU_SOURCE 1 + + # ifndef _GL_INLINE_HEADER_BEGIN ++/* gnulib gets configured against the host, not the target, and the rest of ++ * our buildsystem works around that. This is difficult to avoid as gnulib's ++ * detection requires a more capable system than our target. Instead, we ++ * reach in and set values appropriately - intentionally setting more than the ++ * bare minimum. If, when updating gnulib, something breaks, there's probably ++ * a change needed here or in grub-core/Makefile.core.def. */ ++# define SIZE_MAX ((size_t) -1) ++# define _GL_ATTRIBUTE_ALLOC_SIZE(args) \ ++ __attribute__ ((__alloc_size__ args)) ++# define _GL_ATTRIBUTE_ALWAYS_INLINE __attribute__ ((__always_inline__)) ++# define _GL_ATTRIBUTE_ARTIFICIAL __attribute__ ((__artificial__)) ++# define _GL_ATTRIBUTE_COLD __attribute__ ((cold)) + # define _GL_ATTRIBUTE_CONST __attribute__ ((const)) ++# define _GL_ATTRIBUTE_DEALLOC(f, i) __attribute ((__malloc__ (f, i))) ++# define _GL_ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC (free, 1) ++# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) ++# define _GL_ATTRIBUTE_ERROR(msg) __attribute__ ((__error__ (msg))) ++# define _GL_ATTRIBUTE_EXTERNALLY_VISIBLE \ ++ __attribute__ ((externally_visible)) ++# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) ++# define _GL_ATTRIBUTE_LEAF __attribute__ ((__leaf__)) ++# define _GL_ATTRIBUTE_MALLOC __attribute__ ((malloc)) ++# define _GL_ATTRIBUTE_MAYBE_UNUSED _GL_ATTRIBUTE_UNUSED ++# define _GL_ATTRIBUTE_MAY_ALIAS __attribute__ ((__may_alias__)) ++# define _GL_ATTRIBUTE_NODISCARD __attribute__ ((__warn_unused_result__)) ++# define _GL_ATTRIBUTE_NOINLINE __attribute__ ((__noinline__)) ++# define _GL_ATTRIBUTE_NONNULL(args) __attribute__ ((__nonnull__ args)) ++# define _GL_ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__)) ++# define _GL_ATTRIBUTE_PACKED __attribute__ ((__packed__)) ++# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) ++# define _GL_ATTRIBUTE_RETURNS_NONNULL \ ++ __attribute__ ((__returns_nonnull__)) ++# define _GL_ATTRIBUTE_SENTINEL(pos) __attribute__ ((__sentinel__ pos)) ++# define _GL_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) ++# define _GL_ATTRIBUTE_WARNING(msg) __attribute__ ((__warning__ (msg))) ++# define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) ++# define _GL_GNUC_PREREQ GNUC_PREREQ ++# define _GL_INLINE inline ++# define _GL_UNUSED_LABEL _GL_ATTRIBUTE_UNUSED ++ ++/* We can't use __has_attribute for these because gcc-5.1 is too old for ++ * that. Everything above is present in that version, though. */ ++# if __GNUC__ >= 7 ++# define _GL_ATTRIBUTE_FALLTHROUGH __attribute__ ((fallthrough)) ++# else ++# define _GL_ATTRIBUTE_FALLTHROUGH /* empty */ ++# endif ++ ++# ifndef ASM_FILE ++typedef __INT_FAST32_TYPE__ int_fast32_t; ++typedef __UINT_FAST32_TYPE__ uint_fast32_t; ++# endif ++ ++/* Ensure ialloc nests static/non-static inline properly. */ ++# define IALLOC_INLINE static inline ++ ++/* gnulib uses these for blocking out warnings they can't/won't fix. gnulib ++ * also makes the decision about whether to provide a declaration for ++ * reallocarray() at compile-time, so this is a convenient place to override - ++ * it's used by the ialloc module, which is used by base64. */ ++# define _GL_INLINE_HEADER_BEGIN _Pragma ("GCC diagnostic push") \ ++ void * \ ++ reallocarray (void *ptr, unsigned int nmemb, unsigned int size); ++# define _GL_INLINE_HEADER_END _Pragma ("GCC diagnostic pop") + + /* We don't have an abort() for gnulib to call in regexp. */ + # define abort __builtin_unreachable + # endif /* !_GL_INLINE_HEADER_BEGIN */ + ++/* gnulib doesn't build cleanly with older compilers. */ ++# if __GNUC__ < 11 ++_Pragma ("GCC diagnostic ignored \"-Wtype-limits\"") ++# endif ++ + #endif +diff --git a/grub-core/lib/gnulib-patches/fix-null-deref.patch b/grub-core/lib/gnulib-patches/fix-null-deref.patch +deleted file mode 100644 +index 8fafa153a4..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-null-deref.patch ++++ /dev/null +@@ -1,13 +0,0 @@ +-diff --git a/lib/argp-parse.c b/lib/argp-parse.c +-index 6dec57310..900adad54 100644 +---- a/lib/argp-parse.c +-+++ b/lib/argp-parse.c +-@@ -940,7 +940,7 @@ weak_alias (__argp_parse, argp_parse) +- void * +- __argp_input (const struct argp *argp, const struct argp_state *state) +- { +-- if (state) +-+ if (state && state->pstate) +- { +- struct group *group; +- struct parser *parser = state->pstate; +diff --git a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch b/grub-core/lib/gnulib-patches/fix-null-state-deref.patch +deleted file mode 100644 +index 813ec09c8a..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-null-state-deref.patch ++++ /dev/null +@@ -1,12 +0,0 @@ +---- a/lib/argp-help.c 2020-10-28 14:32:19.189215988 +0000 +-+++ b/lib/argp-help.c 2020-10-28 14:38:21.204673940 +0000 +-@@ -145,7 +145,8 @@ +- if (*(int *)((char *)upptr + up->uparams_offs) >= upptr->rmargin) +- { +- __argp_failure (state, 0, 0, +-- dgettext (state->root_argp->argp_domain, +-+ dgettext (state == NULL ? NULL +-+ : state->root_argp->argp_domain, +- "\ +- ARGP_HELP_FMT: %s value is less than or equal to %s"), +- "rmargin", up->name); +diff --git a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch b/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch +deleted file mode 100644 +index 02e06315df..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-regcomp-uninit-token.patch ++++ /dev/null +@@ -1,15 +0,0 @@ +---- a/lib/regcomp.c 2020-11-24 17:06:08.159223858 +0000 +-+++ b/lib/regcomp.c 2020-11-24 17:06:15.630253923 +0000 +-@@ -3808,11 +3808,7 @@ +- create_tree (re_dfa_t *dfa, bin_tree_t *left, bin_tree_t *right, +- re_token_type_t type) +- { +-- re_token_t t; +--#if defined GCC_LINT || defined lint +-- memset (&t, 0, sizeof t); +--#endif +-- t.type = type; +-+ re_token_t t = { .type = type }; +- return create_token_tree (dfa, left, right, &t); +- } +- +diff --git a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch b/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch +deleted file mode 100644 +index db6dac9c9e..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-regexec-null-deref.patch ++++ /dev/null +@@ -1,12 +0,0 @@ +---- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 +-+++ b/lib/regexec.c 2020-11-05 10:55:09.621542984 +0000 +-@@ -1692,6 +1692,9 @@ +- { +- Idx top = mctx->state_log_top; +- +-+ if (mctx->state_log == NULL) +-+ return REG_NOERROR; +-+ +- if ((next_state_log_idx >= mctx->input.bufs_len +- && mctx->input.bufs_len < mctx->input.len) +- || (next_state_log_idx >= mctx->input.valid_len +diff --git a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch b/grub-core/lib/gnulib-patches/fix-uninit-structure.patch +deleted file mode 100644 +index 7b4d9f67af..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-uninit-structure.patch ++++ /dev/null +@@ -1,11 +0,0 @@ +---- a/lib/regcomp.c 2020-10-22 13:49:06.770168928 +0000 +-+++ b/lib/regcomp.c 2020-10-22 13:50:37.026528298 +0000 +-@@ -3662,7 +3662,7 @@ +- Idx alloc = 0; +- #endif /* not RE_ENABLE_I18N */ +- reg_errcode_t ret; +-- re_token_t br_token; +-+ re_token_t br_token = {0}; +- bin_tree_t *tree; +- +- sbcset = (re_bitset_ptr_t) calloc (sizeof (bitset_t), 1); +diff --git a/grub-core/lib/gnulib-patches/fix-unused-value.patch b/grub-core/lib/gnulib-patches/fix-unused-value.patch +deleted file mode 100644 +index ba51f1bf22..0000000000 +--- a/grub-core/lib/gnulib-patches/fix-unused-value.patch ++++ /dev/null +@@ -1,14 +0,0 @@ +---- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000 +-+++ b/lib/regexec.c 2020-10-21 14:32:07.961765604 +0000 +-@@ -828,7 +828,11 @@ +- break; +- if (__glibc_unlikely (err != REG_NOMATCH)) +- goto free_return; +-+#ifdef DEBUG +-+ /* Only used for assertion below when DEBUG is set, otherwise +-+ it will be over-written when we loop around. */ +- match_last = -1; +-+#endif +- } +- else +- break; /* We found a match. */ diff --git a/SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch b/SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch new file mode 100644 index 0000000..4f7feb9 --- /dev/null +++ b/SOURCES/0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Tue, 8 Feb 2022 08:39:10 +0100 +Subject: [PATCH] commands/search: Fix bug stopping iteration when --no-floppy + is used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When using --no-floppy and a floppy was encountered, iterate_device() +was returning 1, causing the iteration to stop instead of continuing. + +Signed-off-by: Renaud Métrich +Reviewed-by: Daniel Kiper +(cherry picked from commit 68ba54c2298604146be83cae144dafd1cfd1fe2d) +Signed-off-by: Robbie Harwood +--- + grub-core/commands/search.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index ed090b3af8..51656e361c 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -64,7 +64,7 @@ iterate_device (const char *name, void *data) + /* Skip floppy drives when requested. */ + if (ctx->no_floppy && + name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') +- return 1; ++ return 0; + + #ifdef DO_SEARCH_FS_UUID + #define compare_fn grub_strcasecmp diff --git a/SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch b/SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch new file mode 100644 index 0000000..3f6194a --- /dev/null +++ b/SOURCES/0204-search-new-efidisk-only-option-on-EFI-systems.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Tue, 8 Feb 2022 08:39:11 +0100 +Subject: [PATCH] search: new --efidisk-only option on EFI systems +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When using 'search' on EFI systems, we sometimes want to exclude devices +that are not EFI disks (e.g. md, lvm). +This is typically used when wanting to chainload when having a software +raid (md) for EFI partition: +with no option, 'search --file /EFI/redhat/shimx64.efi' sets root envvar +to 'md/boot_efi' which cannot be used for chainloading since there is no +effective EFI device behind. + +This commit also refactors handling of --no-floppy option. + +Signed-off-by: Renaud Métrich +[rharwood: apply rmetrich's flags initialization fix] +Signed-off-by: Robbie Harwood +--- + grub-core/commands/search.c | 27 +++++++++++++++++++++++---- + grub-core/commands/search_wrap.c | 18 ++++++++++++------ + include/grub/search.h | 15 ++++++++++++--- + 3 files changed, 47 insertions(+), 13 deletions(-) + +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index 51656e361c..57d26ced8a 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -47,7 +47,7 @@ struct search_ctx + { + const char *key; + const char *var; +- int no_floppy; ++ enum search_flags flags; + char **hints; + unsigned nhints; + int count; +@@ -62,10 +62,29 @@ iterate_device (const char *name, void *data) + int found = 0; + + /* Skip floppy drives when requested. */ +- if (ctx->no_floppy && ++ if (ctx->flags & SEARCH_FLAGS_NO_FLOPPY && + name[0] == 'f' && name[1] == 'd' && name[2] >= '0' && name[2] <= '9') + return 0; + ++ /* Limit to EFI disks when requested. */ ++ if (ctx->flags & SEARCH_FLAGS_EFIDISK_ONLY) ++ { ++ grub_device_t dev; ++ dev = grub_device_open (name); ++ if (! dev) ++ { ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ if (! dev->disk || dev->disk->dev->id != GRUB_DISK_DEVICE_EFIDISK_ID) ++ { ++ grub_device_close (dev); ++ grub_errno = GRUB_ERR_NONE; ++ return 0; ++ } ++ grub_device_close (dev); ++ } ++ + #ifdef DO_SEARCH_FS_UUID + #define compare_fn grub_strcasecmp + #else +@@ -261,13 +280,13 @@ try (struct search_ctx *ctx) + } + + void +-FUNC_NAME (const char *key, const char *var, int no_floppy, ++FUNC_NAME (const char *key, const char *var, enum search_flags flags, + char **hints, unsigned nhints) + { + struct search_ctx ctx = { + .key = key, + .var = var, +- .no_floppy = no_floppy, ++ .flags = flags, + .hints = hints, + .nhints = nhints, + .count = 0, +diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c +index 47fc8eb996..0b62acf853 100644 +--- a/grub-core/commands/search_wrap.c ++++ b/grub-core/commands/search_wrap.c +@@ -40,6 +40,7 @@ static const struct grub_arg_option options[] = + N_("Set a variable to the first device found."), N_("VARNAME"), + ARG_TYPE_STRING}, + {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, ++ {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, + {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, +@@ -73,6 +74,7 @@ enum options + SEARCH_FS_UUID, + SEARCH_SET, + SEARCH_NO_FLOPPY, ++ SEARCH_EFIDISK_ONLY, + SEARCH_HINT, + SEARCH_HINT_IEEE1275, + SEARCH_HINT_BIOS, +@@ -89,6 +91,7 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + const char *id = 0; + int i = 0, j = 0, nhints = 0; + char **hints = NULL; ++ enum search_flags flags = 0; + + if (state[SEARCH_HINT].set) + for (i = 0; state[SEARCH_HINT].args[i]; i++) +@@ -180,15 +183,18 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + goto out; + } + ++ if (state[SEARCH_NO_FLOPPY].set) ++ flags |= SEARCH_FLAGS_NO_FLOPPY; ++ ++ if (state[SEARCH_EFIDISK_ONLY].set) ++ flags |= SEARCH_FLAGS_EFIDISK_ONLY; ++ + if (state[SEARCH_LABEL].set) +- grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, +- hints, nhints); ++ grub_search_label (id, var, flags, hints, nhints); + else if (state[SEARCH_FS_UUID].set) +- grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set, +- hints, nhints); ++ grub_search_fs_uuid (id, var, flags, hints, nhints); + else if (state[SEARCH_FILE].set) +- grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, +- hints, nhints); ++ grub_search_fs_file (id, var, flags, hints, nhints); + else + grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type"); + +diff --git a/include/grub/search.h b/include/grub/search.h +index d80347df34..4190aeb2cb 100644 +--- a/include/grub/search.h ++++ b/include/grub/search.h +@@ -19,11 +19,20 @@ + #ifndef GRUB_SEARCH_HEADER + #define GRUB_SEARCH_HEADER 1 + +-void grub_search_fs_file (const char *key, const char *var, int no_floppy, ++enum search_flags ++ { ++ SEARCH_FLAGS_NO_FLOPPY = 1, ++ SEARCH_FLAGS_EFIDISK_ONLY = 2 ++ }; ++ ++void grub_search_fs_file (const char *key, const char *var, ++ enum search_flags flags, + char **hints, unsigned nhints); +-void grub_search_fs_uuid (const char *key, const char *var, int no_floppy, ++void grub_search_fs_uuid (const char *key, const char *var, ++ enum search_flags flags, + char **hints, unsigned nhints); +-void grub_search_label (const char *key, const char *var, int no_floppy, ++void grub_search_label (const char *key, const char *var, ++ enum search_flags flags, + char **hints, unsigned nhints); + + #endif diff --git a/SOURCES/0205-efi-new-connectefi-command.patch b/SOURCES/0205-efi-new-connectefi-command.patch new file mode 100644 index 0000000..f80de22 --- /dev/null +++ b/SOURCES/0205-efi-new-connectefi-command.patch @@ -0,0 +1,395 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Tue, 15 Feb 2022 14:05:22 +0100 +Subject: [PATCH] efi: new 'connectefi' command +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When efi.quickboot is enabled on VMWare (which is the default for +hardware release 16 and later), it may happen that not all EFI devices +are connected. Due to this, browsing the devices in make_devices() just +fails to find devices, in particular disks or partitions for a given +disk. +This typically happens when network booting, then trying to chainload to +local disk (this is used in deployment tools such as Red Hat Satellite), +which is done through using the following grub.cfg snippet: +-------- 8< ---------------- 8< ---------------- 8< -------- +unset prefix +search --file --set=prefix /EFI/redhat/grubx64.efi +if [ -n "$prefix" ]; then + chainloader ($prefix)/EFI/redhat/grubx64/efi +... +-------- 8< ---------------- 8< ---------------- 8< -------- + +With efi.quickboot, none of the devices are connected, causing "search" +to fail. Sometimes devices are connected but not the partition of the +disk matching $prefix, causing partition to not be found by +"chainloader". + +This patch introduces a new "connectefi pciroot|scsi" command which +recursively connects all EFI devices starting from a given controller +type: +- if 'pciroot' is specified, recursion is performed for all PCI root + handles +- if 'scsi' is specified, recursion is performed for all SCSI I/O + handles (recommended usage to avoid connecting unwanted handles which + may impact Grub performances) + +Typical grub.cfg snippet would then be: +-------- 8< ---------------- 8< ---------------- 8< -------- +connectefi scsi +unset prefix +search --file --set=prefix /EFI/redhat/grubx64.efi +if [ -n "$prefix" ]; then + chainloader ($prefix)/EFI/redhat/grubx64/efi +... +-------- 8< ---------------- 8< ---------------- 8< -------- + +The code is easily extensible to handle other arguments in the future if +needed. + +Signed-off-by: Renaud Métrich +Signed-off-by: Robbie Harwood +--- + grub-core/Makefile.core.def | 6 ++ + grub-core/commands/efi/connectefi.c | 205 ++++++++++++++++++++++++++++++++++++ + grub-core/commands/efi/lsefi.c | 1 + + grub-core/disk/efi/efidisk.c | 13 +++ + grub-core/kern/efi/efi.c | 13 +++ + include/grub/efi/disk.h | 2 + + include/grub/efi/efi.h | 5 + + NEWS | 2 +- + 8 files changed, 246 insertions(+), 1 deletion(-) + create mode 100644 grub-core/commands/efi/connectefi.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index ec1ec5083b..741a033978 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -836,6 +836,12 @@ module = { + enable = efi; + }; + ++module = { ++ name = connectefi; ++ common = commands/efi/connectefi.c; ++ enable = efi; ++}; ++ + module = { + name = blocklist; + common = commands/blocklist.c; +diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c +new file mode 100644 +index 0000000000..8ab75bd51b +--- /dev/null ++++ b/grub-core/commands/efi/connectefi.c +@@ -0,0 +1,205 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++typedef struct handle_list ++{ ++ grub_efi_handle_t handle; ++ struct handle_list *next; ++} handle_list_t; ++ ++static handle_list_t *already_handled = NULL; ++ ++static grub_err_t ++add_handle (grub_efi_handle_t handle) ++{ ++ handle_list_t *e; ++ e = grub_malloc (sizeof (*e)); ++ if (! e) ++ return grub_errno; ++ e->handle = handle; ++ e->next = already_handled; ++ already_handled = e; ++ return GRUB_ERR_NONE; ++} ++ ++static int ++is_in_list (grub_efi_handle_t handle) ++{ ++ handle_list_t *e; ++ for (e = already_handled; e != NULL; e = e->next) ++ if (e->handle == handle) ++ return 1; ++ return 0; ++} ++ ++static void ++free_handle_list (void) ++{ ++ handle_list_t *e; ++ while ((e = already_handled) != NULL) ++ { ++ already_handled = already_handled->next; ++ grub_free (e); ++ } ++} ++ ++typedef enum searched_item_flag ++{ ++ SEARCHED_ITEM_FLAG_LOOP = 1, ++ SEARCHED_ITEM_FLAG_RECURSIVE = 2 ++} searched_item_flags; ++ ++typedef struct searched_item ++{ ++ grub_efi_guid_t guid; ++ const char *name; ++ searched_item_flags flags; ++} searched_items; ++ ++static grub_err_t ++grub_cmd_connectefi (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ unsigned s; ++ searched_items pciroot_items[] = ++ { ++ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", SEARCHED_ITEM_FLAG_RECURSIVE } ++ }; ++ searched_items scsi_items[] = ++ { ++ { GRUB_EFI_PCI_ROOT_IO_GUID, "PCI root", 0 }, ++ { GRUB_EFI_PCI_IO_GUID, "PCI", SEARCHED_ITEM_FLAG_LOOP }, ++ { GRUB_EFI_SCSI_IO_PROTOCOL_GUID, "SCSI I/O", SEARCHED_ITEM_FLAG_RECURSIVE } ++ }; ++ searched_items *items = NULL; ++ unsigned nitems = 0; ++ grub_err_t grub_err = GRUB_ERR_NONE; ++ unsigned total_connected = 0; ++ ++ if (argc != 1) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected")); ++ ++ if (grub_strcmp(args[0], N_("pciroot")) == 0) ++ { ++ items = pciroot_items; ++ nitems = ARRAY_SIZE (pciroot_items); ++ } ++ else if (grub_strcmp(args[0], N_("scsi")) == 0) ++ { ++ items = scsi_items; ++ nitems = ARRAY_SIZE (scsi_items); ++ } ++ else ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, ++ N_("unexpected argument `%s'"), args[0]); ++ ++ for (s = 0; s < nitems; s++) ++ { ++ grub_efi_handle_t *handles; ++ grub_efi_uintn_t num_handles; ++ unsigned i, connected = 0, loop = 0; ++ ++loop: ++ loop++; ++ grub_dprintf ("efi", "step '%s' loop %d:\n", items[s].name, loop); ++ ++ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, ++ &items[s].guid, 0, &num_handles); ++ ++ if (!handles) ++ continue; ++ ++ for (i = 0; i < num_handles; i++) ++ { ++ grub_efi_handle_t handle = handles[i]; ++ grub_efi_status_t status; ++ unsigned j; ++ ++ /* Skip already handled handles */ ++ if (is_in_list (handle)) ++ { ++ grub_dprintf ("efi", " handle %p: already processed\n", ++ handle); ++ continue; ++ } ++ ++ status = grub_efi_connect_controller(handle, NULL, NULL, ++ items[s].flags & SEARCHED_ITEM_FLAG_RECURSIVE ? 1 : 0); ++ if (status == GRUB_EFI_SUCCESS) ++ { ++ connected++; ++ total_connected++; ++ grub_dprintf ("efi", " handle %p: connected\n", handle); ++ } ++ else ++ grub_dprintf ("efi", " handle %p: failed to connect (%d)\n", ++ handle, (grub_efi_int8_t) status); ++ ++ if ((grub_err = add_handle (handle)) != GRUB_ERR_NONE) ++ break; /* fatal */ ++ } ++ ++ grub_free (handles); ++ if (grub_err != GRUB_ERR_NONE) ++ break; /* fatal */ ++ ++ if (items[s].flags & SEARCHED_ITEM_FLAG_LOOP && connected) ++ { ++ connected = 0; ++ goto loop; ++ } ++ ++ free_handle_list (); ++ } ++ ++ free_handle_list (); ++ ++ if (total_connected) ++ grub_efidisk_reenumerate_disks (); ++ ++ return grub_err; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(connectefi) ++{ ++ cmd = grub_register_command ("connectefi", grub_cmd_connectefi, ++ N_("pciroot|scsi"), ++ N_("Connect EFI handles." ++ " If 'pciroot' is specified, connect PCI" ++ " root EFI handles recursively." ++ " If 'scsi' is specified, connect SCSI" ++ " I/O EFI handles recursively.")); ++} ++ ++GRUB_MOD_FINI(connectefi) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/commands/efi/lsefi.c b/grub-core/commands/efi/lsefi.c +index d1ce99af43..f2d2430e66 100644 +--- a/grub-core/commands/efi/lsefi.c ++++ b/grub-core/commands/efi/lsefi.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c +index fe8ba6e6c9..062143dfff 100644 +--- a/grub-core/disk/efi/efidisk.c ++++ b/grub-core/disk/efi/efidisk.c +@@ -396,6 +396,19 @@ enumerate_disks (void) + free_devices (devices); + } + ++void ++grub_efidisk_reenumerate_disks (void) ++{ ++ free_devices (fd_devices); ++ free_devices (hd_devices); ++ free_devices (cd_devices); ++ fd_devices = 0; ++ hd_devices = 0; ++ cd_devices = 0; ++ ++ enumerate_disks (); ++} ++ + static int + grub_efidisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, + grub_disk_pull_t pull) +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 14bc10eb56..7fcca69c17 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -95,6 +95,19 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, + return buffer; + } + ++grub_efi_status_t ++grub_efi_connect_controller (grub_efi_handle_t controller_handle, ++ grub_efi_handle_t *driver_image_handle, ++ grub_efi_device_path_protocol_t *remaining_device_path, ++ grub_efi_boolean_t recursive) ++{ ++ grub_efi_boot_services_t *b; ++ ++ b = grub_efi_system_table->boot_services; ++ return efi_call_4 (b->connect_controller, controller_handle, ++ driver_image_handle, remaining_device_path, recursive); ++} ++ + void * + grub_efi_open_protocol (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, +diff --git a/include/grub/efi/disk.h b/include/grub/efi/disk.h +index 254475c842..6845c2f1fd 100644 +--- a/include/grub/efi/disk.h ++++ b/include/grub/efi/disk.h +@@ -27,6 +27,8 @@ grub_efi_handle_t + EXPORT_FUNC(grub_efidisk_get_device_handle) (grub_disk_t disk); + char *EXPORT_FUNC(grub_efidisk_get_device_name) (grub_efi_handle_t *handle); + ++void EXPORT_FUNC(grub_efidisk_reenumerate_disks) (void); ++ + void grub_efidisk_init (void); + void grub_efidisk_fini (void); + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 8dfc89a33b..ec52083c49 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -41,6 +41,11 @@ EXPORT_FUNC(grub_efi_locate_handle) (grub_efi_locate_search_type_t search_type, + grub_efi_guid_t *protocol, + void *search_key, + grub_efi_uintn_t *num_handles); ++grub_efi_status_t ++EXPORT_FUNC(grub_efi_connect_controller) (grub_efi_handle_t controller_handle, ++ grub_efi_handle_t *driver_image_handle, ++ grub_efi_device_path_protocol_t *remaining_device_path, ++ grub_efi_boolean_t recursive); + void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle, + grub_efi_guid_t *protocol, + grub_efi_uint32_t attributes); +diff --git a/NEWS b/NEWS +index 73b8492bc4..d7c1d23aed 100644 +--- a/NEWS ++++ b/NEWS +@@ -98,7 +98,7 @@ New in 2.02: + * Prefer pmtimer for TSC calibration. + + * New/improved platform support: +- * New `efifwsetup' and `lsefi' commands on EFI platforms. ++ * New `efifwsetup', `lsefi' and `connectefi` commands on EFI platforms. + * New `cmosdump' and `cmosset' commands on platforms with CMOS support. + * New command `pcidump' for PCI platforms. + * Improve opcode parsing in ACPI halt implementation. diff --git a/SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch b/SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch new file mode 100644 index 0000000..4fe8adf --- /dev/null +++ b/SOURCES/0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Thu, 3 Mar 2022 13:10:56 +0100 +Subject: [PATCH] grub-core/loader/i386/efi/linux.c: do not validate kernels + twice + +On codebases that have shim-lock-verifier built into the grub core +(like 2.06 upstream), shim-lock-verifier is in enforcing mode when +booted with secureboot. It means that grub_cmd_linux() command +attempts to perform shim validate upon opening linux kernel image, +including kernel measurement. And the verifier correctly returns file +open error when shim validate protocol is not present or shim fails to +validate the kernel. + +This makes the call to grub_linuxefi_secure_validate() redundant, but +also harmful. As validating the kernel image twice, extends the PCRs +with the same measurement twice. Which breaks existing sealing +policies when upgrading from grub2.04+rhboot+sb+linuxefi to +grub2.06+rhboot+sb+linuxefi builds. It is also incorrect to measure +the kernel twice. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +This patch is tested to ensure that unsigned kernels are not possible +to boot in secureboot mode when shim rejects kernel, or shim protocol +is missing, and that the measurements become stable once again. The +above also ensures that CVE-2020-15705 is not reintroduced. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/i386/efi/linux.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3cf0f9b330..941df6400b 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -30,7 +30,6 @@ + #include + #include + #include +-#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -278,7 +277,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_ssize_t start, filelen; + void *kernel = NULL; + int setup_header_end_offset; +- int rc; + + grub_dl_ref (my_mod); + +@@ -308,17 +306,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) +- { +- rc = grub_linuxefi_secure_validate (kernel, filelen); +- if (rc <= 0) +- { +- grub_error (GRUB_ERR_INVALID_COMMAND, +- N_("%s has invalid signature"), argv[0]); +- goto fail; +- } +- } +- + lh = (struct linux_i386_kernel_header *)kernel; + grub_dprintf ("linux", "original lh is at %p\n", kernel); + diff --git a/SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch b/SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch new file mode 100644 index 0000000..5b450f9 --- /dev/null +++ b/SOURCES/0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 4 Mar 2022 11:29:31 +0100 +Subject: [PATCH] grub-core/loader/arm64/linux.c: do not validate kernel twice + +Call to grub_file_open(, GRUB_FILE_TYPE_LINUX_KERNEL) already passes +the kernel file through shim-lock verifier when secureboot is on. Thus +there is no need to validate the kernel image again. And when doing so +again, duplicate PCR measurement is performed, breaking measurements +compatibility with 2.04+linuxefi. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/arm64/linux.c | 13 ------------- + 1 file changed, 13 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index f18d90bd74..d2af47c2c0 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -34,7 +34,6 @@ + #include + #include + #include +-#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -341,7 +340,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_off_t filelen; + grub_uint32_t align; + void *kernel = NULL; +- int rc; + + grub_dl_ref (my_mod); + +@@ -370,17 +368,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) +- { +- rc = grub_linuxefi_secure_validate (kernel, filelen); +- if (rc <= 0) +- { +- grub_error (GRUB_ERR_INVALID_COMMAND, +- N_("%s has invalid signature"), argv[0]); +- goto fail; +- } +- } +- + if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) + goto fail; + if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) diff --git a/SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch b/SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch new file mode 100644 index 0000000..4c56d60 --- /dev/null +++ b/SOURCES/0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 4 Mar 2022 09:31:43 +0100 +Subject: [PATCH] grub-core/loader/efi/chainloader.c: do not validate + chainloader twice + +On secureboot systems, with shimlock verifier, call to +grub_file_open(, GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE) will already +pass the chainloader target through shim-lock protocol verify +call. And create a TPM measurement. If verification fails, +grub_cmd_chainloader will fail at file open time. + +This makes previous code paths for negative, and zero return codes +from grub_linuxefi_secure_validate unreachable under secureboot. But +also breaking measurements compatibility with 2.04+linuxefi codebases, +as the chainloader file is passed through shim_lock->verify() twice +(via verifier & direct call to grub_linuxefi_secure_validate) +extending the PCRs twice. + +This reduces grub_loader options to perform +grub_secureboot_chainloader when secureboot is on, and otherwise +attempt grub_chainloader_boot. + +It means that booting with secureboot off, yet still with shim (which +always verifies things successfully), will stop choosing +grub_secureboot_chainloader, and opting for a more regular +loadimage/startimage codepath. If we want to use the +grub_secureboot_chainloader codepath in such scenarios we should adapt +the code to simply check for shim_lock protocol presence / +shim_lock->context() success?! But I am not sure if that is necessary. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/efi/chainloader.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 3af6b12292..644cd2e56f 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -906,7 +906,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_device_path_t *dp = 0; + char *filename; + void *boot_image = 0; +- int rc; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1082,9 +1081,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + orig_dev = 0; + } + +- rc = grub_linuxefi_secure_validate((void *)(unsigned long)address, fsize); +- grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); +- if (rc > 0) ++ if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { + grub_file_close (file); + grub_device_close (dev); +@@ -1092,7 +1089,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_secureboot_chainloader_unload, 0); + return 0; + } +- else if (rc == 0) ++ else + { + grub_load_and_start_image(boot_image); + grub_file_close (file); +@@ -1101,7 +1098,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + return 0; + } +- // -1 fall-through to fail + + fail: + if (orig_dev) diff --git a/SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch b/SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch new file mode 100644 index 0000000..c683fcb --- /dev/null +++ b/SOURCES/0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dimitri John Ledkov +Date: Fri, 4 Mar 2022 11:36:09 +0100 +Subject: [PATCH] grub-core/loader/efi/linux.c: drop now unused + grub_linuxefi_secure_validate + +Drop the now unused grub_linuxefi_secure_validate() as all prior users +of this API now rely on the shim-lock-verifier codepath instead. + +This patch must not be ported to older editions of grub code bases +that do not have verifiers framework, or it is not builtin, or +shim-lock-verifier is an optional module. + +Signed-off-by: Dimitri John Ledkov +--- + grub-core/loader/efi/linux.c | 40 ---------------------------------------- + include/grub/efi/linux.h | 2 -- + 2 files changed, 42 deletions(-) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 9260731c10..9265cf4200 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -24,46 +24,6 @@ + #include + #include + +-#define SHIM_LOCK_GUID \ +- { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} } +- +-struct grub_efi_shim_lock +-{ +- grub_efi_status_t (*verify) (void *buffer, grub_uint32_t size); +-}; +-typedef struct grub_efi_shim_lock grub_efi_shim_lock_t; +- +-// Returns 1 on success, -1 on error, 0 when not available +-int +-grub_linuxefi_secure_validate (void *data, grub_uint32_t size) +-{ +- grub_efi_guid_t guid = SHIM_LOCK_GUID; +- grub_efi_shim_lock_t *shim_lock; +- grub_efi_status_t status; +- +- shim_lock = grub_efi_locate_protocol(&guid, NULL); +- grub_dprintf ("secureboot", "shim_lock: %p\n", shim_lock); +- if (!shim_lock) +- { +- grub_dprintf ("secureboot", "shim not available\n"); +- return 0; +- } +- +- grub_dprintf ("secureboot", "Asking shim to verify kernel signature\n"); +- status = shim_lock->verify (data, size); +- grub_dprintf ("secureboot", "shim_lock->verify(): %ld\n", (long int)status); +- if (status == GRUB_EFI_SUCCESS) +- { +- grub_dprintf ("secureboot", "Kernel signature verification passed\n"); +- return 1; +- } +- +- grub_dprintf ("secureboot", "Kernel signature verification failed (0x%lx)\n", +- (unsigned long) status); +- +- return -1; +-} +- + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index 0033d9305a..887b02fd9f 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -22,8 +22,6 @@ + #include + #include + +-int +-EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size); + grub_err_t + EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, + void *kernel_param); diff --git a/SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch b/SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch new file mode 100644 index 0000000..1c16fd3 --- /dev/null +++ b/SOURCES/0210-powerpc-prefix-detection-support-device-names-with-c.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 24 Mar 2022 14:34:32 +1100 +Subject: [PATCH] powerpc: prefix detection: support device names with commas + +Frustratingly, the device name itself can contain an embedded comma: +e.g /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b + +So my previous approach was wrong: we cannot rely upon the presence +of a comma to say that a partition has been specified! + +It turns out for prefixes like (,gpt2)/grub2 we really want to make +up a full (device,partition)/patch prefix, because root discovery code +in 10_linux will reset the root variable and use search to fill it again. +If you have run grub-install, you probably don't have search built in, +and if you don't have prefix containing (device,partition), grub will +construct ($root)$prefix/powerpc-ieee1275/search.mod - but because $root +has just been changed, this will no longer work, and the boot will fail! + +Retain the gist of the logic, but instead of looking for a comma, look for +a leading '('. This matches the earlier code better anyway. + +There's certainly a better fix to be had. But any time you chose to build +with a bare prefix like '/grub2', you're almost certainly going to build in +search anyway, so this will do. + +Signed-off-by: Daniel Axtens +--- + grub-core/kern/main.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c +index 993b8a8598..e94a2f78fb 100644 +--- a/grub-core/kern/main.c ++++ b/grub-core/kern/main.c +@@ -242,14 +242,29 @@ grub_set_prefix_and_root (void) + what sorts of paths represent disks with partition tables and those + without partition tables. + +- So we act unless there is a comma in the device, which would indicate +- a partition has already been specified. ++ - Frustratingly, the device name itself can contain an embedded comma: ++ /pci@800000020000015/pci1014,034A@0/sas/disk@5000c50098a0ee8b ++ So we cannot even rely upon the presence of a comma to say that a ++ partition has been specified! + +- (If we only have a path, the code in normal to discover config files +- will try both without partitions and then with any partitions so we +- will cover both CDs and HDs.) ++ If we only have a path in $prefix, the code in normal to discover ++ config files will try all disks, both without partitions and then with ++ any partitions so we will cover both CDs and HDs. ++ ++ However, it doesn't then set the prefix to be something like ++ (discovered partition)/path, and so it is fragile against runtime ++ changes to $root. For example some of the stuff done in 10_linux to ++ reload $root sets root differently and then uses search to find it ++ again. If the search module is not built in, when we change root, grub ++ will look in (new root)/path/powerpc-ieee1275, that won't work, and we ++ will not be able to load the search module and the boot will fail. ++ ++ This is particularly likely to hit us in the grub-install ++ (,msdos2)/grub2 case, so we act unless the supplied prefix starts with ++ '(', which would likely indicate a partition has already been ++ specified. + */ +- if (grub_strchr (device, ',') == NULL) ++ if (prefix && prefix[0] != '(') + grub_env_set ("prefix", path); + else + #endif diff --git a/SOURCES/0211-make-ofdisk_retries-optional.patch b/SOURCES/0211-make-ofdisk_retries-optional.patch new file mode 100644 index 0000000..fce9702 --- /dev/null +++ b/SOURCES/0211-make-ofdisk_retries-optional.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Thu, 24 Mar 2022 13:14:42 -0400 +Subject: [PATCH] make ofdisk_retries optional + +The feature Retry on Fail added to GRUB can cause a LPM to take +longer if the SAN is slow. + +When a LPM to external site occur, the path of the disk can change +and thus the disk search function on grub can take some time since +it is used as a hint. This can cause the Retry on Fail feature to +try to access the disk 20x times (since this is hardcoded number) +and, if the SAN is slow, the boot time can increase a lot. +In some situations not acceptable. + +The following patch enables a configuration at user space of the +maximum number of retries we want for this feature. + +The variable ofdisk_retries should be set using grub2-editenv +and will be checked by retry function. If the variable is not set, +so the default number of retries will be used instead. +--- + include/grub/ieee1275/ofdisk.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/include/grub/ieee1275/ofdisk.h b/include/grub/ieee1275/ofdisk.h +index 7d2d540930..0074d55eee 100644 +--- a/include/grub/ieee1275/ofdisk.h ++++ b/include/grub/ieee1275/ofdisk.h +@@ -25,7 +25,12 @@ extern void grub_ofdisk_fini (void); + #define MAX_RETRIES 20 + + +-#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) unsigned retry_i=0;for(retry_i=0; retry_i < MAX_RETRIES; retry_i++){ \ ++#define RETRY_IEEE1275_OFDISK_OPEN(device, last_ihandle) \ ++ unsigned max_retries = MAX_RETRIES; \ ++ if(grub_env_get("ofdisk_retries") != NULL) \ ++ max_retries = grub_strtoul(grub_env_get("ofdisk_retries"), 0, 10)+1; \ ++ grub_dprintf("ofdisk","MAX_RETRIES set to %u\n",max_retries); \ ++ unsigned retry_i=0;for(retry_i=0; retry_i < max_retries; retry_i++){ \ + if(!grub_ieee1275_open(device, last_ihandle)) \ + break; \ + grub_dprintf("ofdisk","Opening disk %s failed. Retrying...\n",device); } diff --git a/SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch b/SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch new file mode 100644 index 0000000..f61ed28 --- /dev/null +++ b/SOURCES/0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 28 Apr 2022 21:53:36 +0100 +Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't + load and start + +grub_load_and_start_image only loads an image - it still requires the +caller to start it. This renames it to grub_load_image. + +It's called from 2 places: +- grub_cmd_chainloader when not using the shim protocol. +- grub_secureboot_chainloader_boot if handle_image returns an error. +In this case, the image is loaded and then nothing else happens which +seems strange. I assume the intention is that it falls back to LoadImage +and StartImage if handle_image fails, so I've made it do that. + +Signed-off-by: Chris Coulson +(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6) +--- + grub-core/loader/efi/chainloader.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 644cd2e56f..d3bf02ed8a 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -841,7 +841,7 @@ grub_secureboot_chainloader_unload (void) + } + + static grub_err_t +-grub_load_and_start_image(void *boot_image) ++grub_load_image(void *boot_image) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -883,13 +883,23 @@ grub_load_and_start_image(void *boot_image) + static grub_err_t + grub_secureboot_chainloader_boot (void) + { ++ grub_efi_boot_services_t *b; + int rc; ++ + rc = handle_image ((void *)(unsigned long)address, fsize); + if (rc == 0) + { +- grub_load_and_start_image((void *)(unsigned long)address); ++ /* We weren't able to attempt to execute the image, so fall back ++ * to LoadImage / StartImage. ++ */ ++ rc = grub_load_image((void *)(unsigned long)address); ++ if (rc == 0) ++ grub_chainloader_boot (); + } + ++ b = grub_efi_system_table->boot_services; ++ efi_call_1 (b->unload_image, image_handle); ++ + grub_loader_unset (); + return grub_errno; + } +@@ -1091,7 +1101,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + else + { +- grub_load_and_start_image(boot_image); ++ grub_load_image(boot_image); + grub_file_close (file); + grub_device_close (dev); + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); diff --git a/SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch b/SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch new file mode 100644 index 0000000..205124e --- /dev/null +++ b/SOURCES/0213-loader-efi-chainloader-simplify-the-loader-state.patch @@ -0,0 +1,330 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:13:08 +0100 +Subject: [PATCH] loader/efi/chainloader: simplify the loader state + +When not using the shim lock protocol, the chainloader command retains +the source buffer and device path passed to LoadImage, requiring the +unload hook passed to grub_loader_set to free them. It isn't required +to retain this state though - they aren't required by StartImage or +anything else in the boot hook, so clean them up before +grub_cmd_chainloader finishes. + +This also wraps the loader state when using the shim lock protocol +inside a struct. + +Signed-off-by: Chris Coulson +(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046) +[rharwood: fix unitialized handle and double-frees of file/dev] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++-------------- + 1 file changed, 102 insertions(+), 58 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index d3bf02ed8a..3342492ff1 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -48,38 +48,21 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_physical_address_t address; +-static grub_efi_uintn_t pages; +-static grub_ssize_t fsize; +-static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; +-static grub_efi_char16_t *cmdline; +-static grub_ssize_t cmdline_len; +-static grub_efi_handle_t dev_handle; + +-static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); ++struct grub_secureboot_chainloader_context { ++ grub_efi_physical_address_t address; ++ grub_efi_uintn_t pages; ++ grub_ssize_t fsize; ++ grub_efi_device_path_t *file_path; ++ grub_efi_char16_t *cmdline; ++ grub_ssize_t cmdline_len; ++ grub_efi_handle_t dev_handle; ++}; ++static struct grub_secureboot_chainloader_context *sb_context; + + static grub_err_t +-grub_chainloader_unload (void) +-{ +- grub_efi_boot_services_t *b; +- +- b = grub_efi_system_table->boot_services; +- efi_call_1 (b->unload_image, image_handle); +- grub_efi_free_pages (address, pages); +- +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; +- +- grub_dl_unref (my_mod); +- return GRUB_ERR_NONE; +-} +- +-static grub_err_t +-grub_chainloader_boot (void) ++grub_start_image (grub_efi_handle_t handle) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -87,7 +70,7 @@ grub_chainloader_boot (void) + grub_efi_char16_t *exit_data = NULL; + + b = grub_efi_system_table->boot_services; +- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); ++ status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data); + if (status != GRUB_EFI_SUCCESS) + { + if (exit_data) +@@ -111,11 +94,37 @@ grub_chainloader_boot (void) + if (exit_data) + grub_efi_free_pool (exit_data); + +- grub_loader_unset (); +- + return grub_errno; + } + ++static grub_err_t ++grub_chainloader_unload (void) ++{ ++ grub_efi_loaded_image_t *loaded_image; ++ grub_efi_boot_services_t *b; ++ ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (loaded_image != NULL) ++ grub_free (loaded_image->load_options); ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_1 (b->unload_image, image_handle); ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_chainloader_boot (void) ++{ ++ grub_err_t err; ++ ++ err = grub_start_image (image_handle); ++ ++ grub_loader_unset (); ++ return err; ++} ++ + static grub_err_t + copy_file_path (grub_efi_file_path_device_path_t *fp, + const char *str, grub_efi_uint16_t len) +@@ -150,7 +159,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + char *dir_start; + char *dir_end; + grub_size_t size; +- grub_efi_device_path_t *d; ++ grub_efi_device_path_t *d, *file_path; + + dir_start = grub_strchr (filename, ')'); + if (! dir_start) +@@ -526,10 +535,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) + } + + static grub_efi_boolean_t +-handle_image (void *data, grub_efi_uint32_t datasize) ++handle_image (struct grub_secureboot_chainloader_context *load_context) + { + grub_efi_loaded_image_t *li, li_bak; + grub_efi_status_t efi_status; ++ void *data = (void *)(unsigned long)load_context->address; ++ grub_efi_uint32_t datasize = load_context->fsize; + void *buffer = NULL; + char *buffer_aligned = NULL; + grub_efi_uint32_t i; +@@ -540,6 +551,7 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_uint32_t buffer_size; + int found_entry_point = 0; + int rc; ++ grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); + + rc = read_header (data, datasize, &context); + if (rc < 0) +@@ -797,10 +809,10 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); + li->image_base = buffer_aligned; + li->image_size = context.image_size; +- li->load_options = cmdline; +- li->load_options_size = cmdline_len; +- li->file_path = grub_efi_get_media_file_path (file_path); +- li->device_handle = dev_handle; ++ li->load_options = load_context->cmdline; ++ li->load_options_size = load_context->cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (load_context->file_path); ++ li->device_handle = load_context->dev_handle; + if (!li->file_path) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); +@@ -829,19 +841,22 @@ error_exit: + static grub_err_t + grub_secureboot_chainloader_unload (void) + { +- grub_efi_free_pages (address, pages); +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; ++ grub_efi_free_pages (sb_context->address, sb_context->pages); ++ grub_free (sb_context->file_path); ++ grub_free (sb_context->cmdline); ++ grub_free (sb_context); ++ ++ sb_context = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } + + static grub_err_t +-grub_load_image(void *boot_image) ++grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, ++ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle, ++ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len, ++ grub_efi_handle_t *image_handle_out) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -850,7 +865,7 @@ grub_load_image(void *boot_image) + b = grub_efi_system_table->boot_services; + + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- boot_image, fsize, &image_handle); ++ boot_image, image_size, image_handle_out); + if (status != GRUB_EFI_SUCCESS) + { + if (status == GRUB_EFI_OUT_OF_RESOURCES) +@@ -863,7 +878,7 @@ grub_load_image(void *boot_image) + /* LoadImage does not set a device handler when the image is + loaded from memory, so it is necessary to set it explicitly here. + This is a mess. */ +- loaded_image = grub_efi_get_loaded_image (image_handle); ++ loaded_image = grub_efi_get_loaded_image (*image_handle_out); + if (! loaded_image) + { + grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); +@@ -885,20 +900,25 @@ grub_secureboot_chainloader_boot (void) + { + grub_efi_boot_services_t *b; + int rc; ++ grub_efi_handle_t handle = 0; + +- rc = handle_image ((void *)(unsigned long)address, fsize); ++ rc = handle_image (sb_context); + if (rc == 0) + { + /* We weren't able to attempt to execute the image, so fall back + * to LoadImage / StartImage. + */ +- rc = grub_load_image((void *)(unsigned long)address); ++ rc = grub_load_image(sb_context->file_path, ++ (void *)(unsigned long)sb_context->address, ++ sb_context->fsize, sb_context->dev_handle, ++ sb_context->cmdline, sb_context->cmdline_len, ++ &handle); + if (rc == 0) +- grub_chainloader_boot (); ++ grub_start_image (handle); + } + + b = grub_efi_system_table->boot_services; +- efi_call_1 (b->unload_image, image_handle); ++ efi_call_1 (b->unload_image, handle); + + grub_loader_unset (); + return grub_errno; +@@ -913,9 +933,15 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_boot_services_t *b; + grub_device_t dev = 0; + grub_device_t orig_dev = 0; +- grub_efi_device_path_t *dp = 0; ++ grub_efi_device_path_t *dp = 0, *file_path = 0; + char *filename; + void *boot_image = 0; ++ grub_efi_physical_address_t address = 0; ++ grub_ssize_t fsize; ++ grub_efi_uintn_t pages = 0; ++ grub_efi_char16_t *cmdline = 0; ++ grub_ssize_t cmdline_len = 0; ++ grub_efi_handle_t dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -923,12 +949,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- /* Initialize some global variables. */ +- address = 0; +- image_handle = 0; +- file_path = 0; +- dev_handle = 0; +- + b = grub_efi_system_table->boot_services; + + if (argc > 1) +@@ -1093,17 +1113,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + { ++ sb_context = grub_malloc (sizeof (*sb_context)); ++ if (sb_context == NULL) ++ goto fail; ++ sb_context->address = address; ++ sb_context->fsize = fsize; ++ sb_context->pages = pages; ++ sb_context->file_path = file_path; ++ sb_context->cmdline = cmdline; ++ sb_context->cmdline_len = cmdline_len; ++ sb_context->dev_handle = dev_handle; ++ + grub_file_close (file); + grub_device_close (dev); ++ + grub_loader_set (grub_secureboot_chainloader_boot, + grub_secureboot_chainloader_unload, 0); + return 0; + } + else + { +- grub_load_image(boot_image); ++ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline, ++ cmdline_len, &image_handle); + grub_file_close (file); + grub_device_close (dev); ++ ++ /* We're finished with the source image buffer and file path now */ ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + + return 0; +@@ -1130,6 +1168,12 @@ fail: + if (cmdline) + grub_free (cmdline); + ++ if (image_handle != 0) ++ { ++ efi_call_1 (b->unload_image, image_handle); ++ image_handle = 0; ++ } ++ + grub_dl_unref (my_mod); + + return grub_errno; diff --git a/SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch b/SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch new file mode 100644 index 0000000..63a2d76 --- /dev/null +++ b/SOURCES/0214-commands-boot-Add-API-to-pass-context-to-loader.patch @@ -0,0 +1,158 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:16:02 +0100 +Subject: [PATCH] commands/boot: Add API to pass context to loader + +Loaders rely on global variables for saving context which is consumed +in the boot hook and freed in the unload hook. In the case where a loader +command is executed twice, calling grub_loader_set a second time executes +the unload hook, but in some cases this runs when the loader's global +context has already been updated, resulting in the updated context being +freed and potential use-after-free bugs when the boot hook is subsequently +called. + +This adds a new API (grub_loader_set_ex) which allows a loader to specify +context that is passed to its boot and unload hooks. This is an alternative +to requiring that loaders call grub_loader_unset before mutating their +global context. + +Signed-off-by: Chris Coulson +(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3) +--- + grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------ + include/grub/loader.h | 5 ++++ + 2 files changed, 63 insertions(+), 8 deletions(-) + +diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c +index bbca81e947..53691a62d9 100644 +--- a/grub-core/commands/boot.c ++++ b/grub-core/commands/boot.c +@@ -27,10 +27,20 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-static grub_err_t (*grub_loader_boot_func) (void); +-static grub_err_t (*grub_loader_unload_func) (void); ++static grub_err_t (*grub_loader_boot_func) (void *); ++static grub_err_t (*grub_loader_unload_func) (void *); ++static void *grub_loader_context; + static int grub_loader_flags; + ++struct grub_simple_loader_hooks ++{ ++ grub_err_t (*boot) (void); ++ grub_err_t (*unload) (void); ++}; ++ ++/* Don't heap allocate this to avoid making grub_loader_set fallible. */ ++static struct grub_simple_loader_hooks simple_loader_hooks; ++ + struct grub_preboot + { + grub_err_t (*preboot_func) (int); +@@ -44,6 +54,29 @@ static int grub_loader_loaded; + static struct grub_preboot *preboots_head = 0, + *preboots_tail = 0; + ++static grub_err_t ++grub_simple_boot_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ return hooks->boot (); ++} ++ ++static grub_err_t ++grub_simple_unload_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ grub_err_t ret; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ ++ ret = hooks->unload (); ++ grub_memset (hooks, 0, sizeof (*hooks)); ++ ++ return ret; ++} ++ + int + grub_loader_is_loaded (void) + { +@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) + } + + void +-grub_loader_set (grub_err_t (*boot) (void), +- grub_err_t (*unload) (void), +- int flags) ++grub_loader_set_ex (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = boot; + grub_loader_unload_func = unload; ++ grub_loader_context = context; + grub_loader_flags = flags; + + grub_loader_loaded = 1; + } + ++void ++grub_loader_set (grub_err_t (*boot) (void), ++ grub_err_t (*unload) (void), ++ int flags) ++{ ++ grub_loader_set_ex (grub_simple_boot_hook, ++ grub_simple_unload_hook, ++ &simple_loader_hooks, ++ flags); ++ ++ simple_loader_hooks.boot = boot; ++ simple_loader_hooks.unload = unload; ++} ++ + void + grub_loader_unset(void) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = 0; + grub_loader_unload_func = 0; ++ grub_loader_context = 0; + + grub_loader_loaded = 0; + } +@@ -158,7 +208,7 @@ grub_loader_boot (void) + return err; + } + } +- err = (grub_loader_boot_func) (); ++ err = (grub_loader_boot_func) (grub_loader_context); + + for (cur = preboots_tail; cur; cur = cur->prev) + if (! err) +diff --git a/include/grub/loader.h b/include/grub/loader.h +index b208642821..1846fa6c5f 100644 +--- a/include/grub/loader.h ++++ b/include/grub/loader.h +@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int flags); + ++void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags); ++ + /* Unset current loader, if any. */ + void EXPORT_FUNC (grub_loader_unset) (void); + diff --git a/SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..fc15b84 --- /dev/null +++ b/SOURCES/0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch @@ -0,0 +1,147 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:30:56 +0100 +Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex + +This ports the EFI chainloader to use grub_loader_set_ex in order to fix +a use-after-free bug that occurs when grub_cmd_chainloader is executed +more than once before a boot attempt is performed. + +Signed-off-by: Chris Coulson +(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9) +[rharwood: context sludge from other change] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++---------------- + 1 file changed, 22 insertions(+), 16 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 3342492ff1..fb874f1855 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -48,8 +48,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_handle_t image_handle; +- + struct grub_secureboot_chainloader_context { + grub_efi_physical_address_t address; + grub_efi_uintn_t pages; +@@ -59,7 +57,6 @@ struct grub_secureboot_chainloader_context { + grub_ssize_t cmdline_len; + grub_efi_handle_t dev_handle; + }; +-static struct grub_secureboot_chainloader_context *sb_context; + + static grub_err_t + grub_start_image (grub_efi_handle_t handle) +@@ -98,11 +95,14 @@ grub_start_image (grub_efi_handle_t handle) + } + + static grub_err_t +-grub_chainloader_unload (void) ++grub_chainloader_unload (void *context) + { ++ grub_efi_handle_t image_handle; + grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + ++ image_handle = (grub_efi_handle_t) context; ++ + loaded_image = grub_efi_get_loaded_image (image_handle); + if (loaded_image != NULL) + grub_free (loaded_image->load_options); +@@ -115,10 +115,12 @@ grub_chainloader_unload (void) + } + + static grub_err_t +-grub_chainloader_boot (void) ++grub_chainloader_boot (void *context) + { ++ grub_efi_handle_t image_handle; + grub_err_t err; + ++ image_handle = (grub_efi_handle_t) context; + err = grub_start_image (image_handle); + + grub_loader_unset (); +@@ -839,15 +841,17 @@ error_exit: + } + + static grub_err_t +-grub_secureboot_chainloader_unload (void) ++grub_secureboot_chainloader_unload (void *context) + { ++ struct grub_secureboot_chainloader_context *sb_context; ++ ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ + grub_efi_free_pages (sb_context->address, sb_context->pages); + grub_free (sb_context->file_path); + grub_free (sb_context->cmdline); + grub_free (sb_context); + +- sb_context = 0; +- + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } +@@ -896,12 +900,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, + } + + static grub_err_t +-grub_secureboot_chainloader_boot (void) ++grub_secureboot_chainloader_boot (void *context) + { ++ struct grub_secureboot_chainloader_context *sb_context; + grub_efi_boot_services_t *b; + int rc; + grub_efi_handle_t handle = 0; + ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ + rc = handle_image (sb_context); + if (rc == 0) + { +@@ -942,6 +949,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_char16_t *cmdline = 0; + grub_ssize_t cmdline_len = 0; + grub_efi_handle_t dev_handle = 0; ++ grub_efi_handle_t image_handle = 0; ++ struct grub_secureboot_chainloader_context *sb_context = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1127,8 +1136,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (file); + grub_device_close (dev); + +- grub_loader_set (grub_secureboot_chainloader_boot, +- grub_secureboot_chainloader_unload, 0); ++ grub_loader_set_ex (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, sb_context, 0); + return 0; + } + else +@@ -1142,7 +1151,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + grub_free (file_path); + +- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + + return 0; + } +@@ -1169,10 +1178,7 @@ fail: + grub_free (cmdline); + + if (image_handle != 0) +- { +- efi_call_1 (b->unload_image, image_handle); +- image_handle = 0; +- } ++ efi_call_1 (b->unload_image, image_handle); + + grub_dl_unref (my_mod); + diff --git a/SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch b/SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch new file mode 100644 index 0000000..b79c78c --- /dev/null +++ b/SOURCES/0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Mon, 2 May 2022 14:39:31 +0200 +Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi + loader + +In some error paths in grub_cmd_linux, the pointer to lh may be +dereferenced after the buffer it points to has been freed. There aren't +any security implications from this because nothing else uses the +allocator after the buffer is freed and before the pointer is +dereferenced, but fix it anyway. + +Signed-off-by: Chris Coulson +(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2) +--- + grub-core/loader/i386/efi/linux.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 941df6400b..27bc2aa161 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -465,9 +465,6 @@ fail: + if (file) + grub_file_close (file); + +- if (kernel) +- grub_free (kernel); +- + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); +@@ -483,6 +480,8 @@ fail: + kernel_free (params, sizeof(*params)); + } + ++ grub_free (kernel); ++ + return grub_errno; + } + diff --git a/SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch b/SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..1a129db --- /dev/null +++ b/SOURCES/0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch @@ -0,0 +1,296 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Mon, 2 May 2022 17:04:23 +0200 +Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex + +This ports the linuxefi loader to use grub_loader_set_ex in order to fix +a use-after-fre bug that occurs when grub_cmd_linux is executed more than +once before a boot attempt is performed. + +This is more complicated than for the chainloader command, as the initrd +command needs access to the loader state. To solve this, the linuxefi +module registers a dummy initrd command at startup that returns an error. +The linuxefi command then registers a proper initrd command with a higher +priority that is passed the loader state. + +Signed-off-by: Chris Coulson +(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc) +[rharwood/pjones: set kernel_size in context] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++--------------- + 1 file changed, 87 insertions(+), 59 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 27bc2aa161..e3c2d6fe0b 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -34,13 +34,19 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; +-static int loaded; +-static void *kernel_mem; +-static grub_uint64_t kernel_size; +-static void *initrd_mem; +-static grub_uint32_t handover_offset; +-struct linux_kernel_params *params; +-static char *linux_cmdline; ++ ++static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linuxefi, cmd_initrdefi; ++ ++struct grub_linuxefi_context { ++ void *kernel_mem; ++ grub_uint64_t kernel_size; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params; ++ char *cmdline; ++ ++ void *initrd_mem; ++}; + + #define MIN(a, b) \ + ({ typeof (a) _a = (a); \ +@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + } + + static grub_err_t +-grub_linuxefi_boot (void) ++grub_linuxefi_boot (void *data) + { ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)kernel_mem, +- handover_offset, +- params); ++ return grub_efi_linux_boot ((char *)context->kernel_mem, ++ context->handover_offset, ++ context->params); + } + + static grub_err_t +-grub_linuxefi_unload (void) ++grub_linuxefi_unload (void *data) + { ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ struct linux_kernel_params *params = context->params; ++ + grub_dl_unref (my_mod); +- loaded = 0; + +- kernel_free(initrd_mem, params->ramdisk_size); +- kernel_free(linux_cmdline, params->cmdline_size + 1); +- kernel_free(kernel_mem, kernel_size); +- kernel_free(params, sizeof(*params)); ++ kernel_free (context->initrd_mem, params->ramdisk_size); ++ kernel_free (context->cmdline, params->cmdline_size + 1); ++ kernel_free (context->kernel_mem, context->kernel_size); ++ kernel_free (params, sizeof(*params)); ++ cmd_initrd->data = 0; ++ cmd_initrdefi->data = 0; ++ grub_free (context); + + return GRUB_ERR_NONE; + } +@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) + + static grub_err_t +-grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), +- int argc, char *argv[]) ++grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + { + grub_file_t *files = 0; + int i, nfiles = 0; + grub_size_t size = 0; + grub_uint8_t *ptr; ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; ++ struct linux_kernel_params *params; + + if (argc == 0) + { +@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (!loaded) ++ if (!context) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); + goto fail; + } + ++ params = context->params; ++ + files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; +@@ -225,19 +241,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + } + } + +- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +- if (initrd_mem == NULL) ++ context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (context->initrd_mem == NULL) + goto fail; +- grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); ++ grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); + + params->ramdisk_size = LOW_U32(size); +- params->ramdisk_image = LOW_U32(initrd_mem); ++ params->ramdisk_image = LOW_U32(context->initrd_mem); + #if defined(__x86_64__) + params->ext_ramdisk_size = HIGH_U32(size); +- params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++ params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); + #endif + +- ptr = initrd_mem; ++ ptr = context->initrd_mem; + + for (i = 0; i < nfiles; i++) + { +@@ -261,8 +277,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (files[i]); + grub_free (files); + +- if (initrd_mem && grub_errno) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, ++ if (context->initrd_mem && grub_errno) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, + BYTES_TO_PAGES(size)); + + return grub_errno; +@@ -277,6 +293,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_ssize_t start, filelen; + void *kernel = NULL; + int setup_header_end_offset; ++ void *kernel_mem = 0; ++ grub_uint64_t kernel_size = 0; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params = 0; ++ char *cmdline = 0; ++ struct grub_linuxefi_context *context = 0; + + grub_dl_ref (my_mod); + +@@ -390,27 +412,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); +- if (!linux_cmdline) ++ cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); ++ if (!cmdline) + goto fail; +- grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); ++ grub_dprintf ("linux", "cmdline = %p\n", cmdline); + +- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, +- linux_cmdline + sizeof (LINUX_IMAGE) - 1, ++ cmdline + sizeof (LINUX_IMAGE) - 1, + lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + +- grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); ++ grub_dprintf ("linux", "cmdline:%s\n", cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- LOW_U32(linux_cmdline)); +- lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++ LOW_U32(cmdline)); ++ lh->cmd_line_ptr = LOW_U32(cmdline); + #if defined(__x86_64__) +- if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ if ((grub_efi_uintn_t)cmdline > 0xffffffffull) + { + grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", +- HIGH_U32(linux_cmdline)); +- params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ HIGH_U32(cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(cmdline); + } + #endif + +@@ -435,16 +457,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; +- kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ kernel_size = lh->init_size; ++ kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + +- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- +- loaded = 1; +- + grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", + LOW_U32(kernel_mem)); + lh->code32_start = LOW_U32(kernel_mem); +@@ -461,33 +480,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", + params->ext_loader_type, params->ext_loader_ver); + ++ context = grub_zalloc (sizeof (*context)); ++ if (!context) ++ goto fail; ++ context->kernel_mem = kernel_mem; ++ context->kernel_size = kernel_size; ++ context->handover_offset = handover_offset; ++ context->params = params; ++ context->cmdline = cmdline; ++ ++ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); ++ ++ cmd_initrd->data = context; ++ cmd_initrdefi->data = context; ++ ++ grub_file_close (file); ++ grub_free (kernel); ++ return 0; ++ + fail: + if (file) + grub_file_close (file); + +- if (grub_errno != GRUB_ERR_NONE) +- { +- grub_dl_unref (my_mod); +- loaded = 0; +- } ++ grub_dl_unref (my_mod); + +- if (!loaded) +- { +- if (lh) +- kernel_free (linux_cmdline, lh->cmdline_size + 1); ++ if (lh) ++ kernel_free (cmdline, lh->cmdline_size + 1); + +- kernel_free (kernel_mem, kernel_size); +- kernel_free (params, sizeof(*params)); +- } ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); + ++ grub_free (context); + grub_free (kernel); + + return grub_errno; + } + +-static grub_command_t cmd_linux, cmd_initrd; +-static grub_command_t cmd_linuxefi, cmd_initrdefi; +- + GRUB_MOD_INIT(linux) + { + cmd_linux = diff --git a/SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch b/SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch new file mode 100644 index 0000000..51953fd --- /dev/null +++ b/SOURCES/0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 3 May 2022 09:47:35 +0200 +Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd + command + +Subsequent invocations of the initrd command result in the previous +initrd being leaked, so fix that. + +Signed-off-by: Chris Coulson +(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0) +--- + grub-core/loader/i386/efi/linux.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index e3c2d6fe0b..9e5c11ac69 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + grub_uint8_t *ptr; + struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; + struct linux_kernel_params *params; ++ void *initrd_mem = 0; + + if (argc == 0) + { +@@ -241,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +- if (context->initrd_mem == NULL) ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) + goto fail; +- grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = LOW_U32(size); +- params->ramdisk_image = LOW_U32(context->initrd_mem); ++ params->ramdisk_image = LOW_U32(initrd_mem); + #if defined(__x86_64__) + params->ext_ramdisk_size = HIGH_U32(size); +- params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); + #endif + +- ptr = context->initrd_mem; ++ ptr = initrd_mem; + + for (i = 0; i < nfiles; i++) + { +@@ -270,6 +271,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + ptr += ALIGN_UP_OVERHEAD (cursize, 4); + } + ++ kernel_free(context->initrd_mem, params->ramdisk_size); ++ ++ context->initrd_mem = initrd_mem; + params->ramdisk_size = size; + + fail: +@@ -277,9 +281,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + grub_file_close (files[i]); + grub_free (files); + +- if (context->initrd_mem && grub_errno) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, +- BYTES_TO_PAGES(size)); ++ if (initrd_mem && grub_errno) ++ kernel_free (initrd_mem, size); + + return grub_errno; + } diff --git a/SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch b/SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch new file mode 100644 index 0000000..715e6e1 --- /dev/null +++ b/SOURCES/0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Julian Andres Klode +Date: Thu, 2 Dec 2021 15:03:53 +0100 +Subject: [PATCH] kern/efi/sb: Reject non-kernel files in the shim_lock + verifier + +We must not allow other verifiers to pass things like the GRUB modules. +Instead of maintaining a blocklist, maintain an allowlist of things +that we do not care about. + +This allowlist really should be made reusable, and shared by the +lockdown verifier, but this is the minimal patch addressing +security concerns where the TPM verifier was able to mark modules +as verified (or the OpenPGP verifier for that matter), when it +should not do so on shim-powered secure boot systems. + +Fixes: CVE-2022-28735 + +Signed-off-by: Julian Andres Klode +Reviewed-by: Daniel Kiper +(cherry picked from commit fa61ad69861c1cb3f68bf853d78fae7fd93986a0) +--- + grub-core/kern/efi/sb.c | 39 ++++++++++++++++++++++++++++++++++++--- + include/grub/verify.h | 1 + + 2 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index c52ec6226a..89c4bb3fd1 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -119,10 +119,11 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + void **context __attribute__ ((unused)), + enum grub_verify_flags *flags) + { +- *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ *flags = GRUB_VERIFY_FLAGS_NONE; + + switch (type & GRUB_FILE_TYPE_MASK) + { ++ /* Files we check. */ + case GRUB_FILE_TYPE_LINUX_KERNEL: + case GRUB_FILE_TYPE_MULTIBOOT_KERNEL: + case GRUB_FILE_TYPE_BSD_KERNEL: +@@ -130,11 +131,43 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_PLAN9_KERNEL: + case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: + *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK; ++ return GRUB_ERR_NONE; + +- /* Fall through. */ ++ /* Files that do not affect secureboot state. */ ++ case GRUB_FILE_TYPE_NONE: ++ case GRUB_FILE_TYPE_LOOPBACK: ++ case GRUB_FILE_TYPE_LINUX_INITRD: ++ case GRUB_FILE_TYPE_OPENBSD_RAMDISK: ++ case GRUB_FILE_TYPE_XNU_RAMDISK: ++ case GRUB_FILE_TYPE_SIGNATURE: ++ case GRUB_FILE_TYPE_PUBLIC_KEY: ++ case GRUB_FILE_TYPE_PUBLIC_KEY_TRUST: ++ case GRUB_FILE_TYPE_PRINT_BLOCKLIST: ++ case GRUB_FILE_TYPE_TESTLOAD: ++ case GRUB_FILE_TYPE_GET_SIZE: ++ case GRUB_FILE_TYPE_FONT: ++ case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: ++ case GRUB_FILE_TYPE_CAT: ++ case GRUB_FILE_TYPE_HEXCAT: ++ case GRUB_FILE_TYPE_CMP: ++ case GRUB_FILE_TYPE_HASHLIST: ++ case GRUB_FILE_TYPE_TO_HASH: ++ case GRUB_FILE_TYPE_KEYBOARD_LAYOUT: ++ case GRUB_FILE_TYPE_PIXMAP: ++ case GRUB_FILE_TYPE_GRUB_MODULE_LIST: ++ case GRUB_FILE_TYPE_CONFIG: ++ case GRUB_FILE_TYPE_THEME: ++ case GRUB_FILE_TYPE_GETTEXT_CATALOG: ++ case GRUB_FILE_TYPE_FS_SEARCH: ++ case GRUB_FILE_TYPE_LOADENV: ++ case GRUB_FILE_TYPE_SAVEENV: ++ case GRUB_FILE_TYPE_VERIFY_SIGNATURE: ++ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; ++ return GRUB_ERR_NONE; + ++ /* Other files. */ + default: +- return GRUB_ERR_NONE; ++ return grub_error (GRUB_ERR_ACCESS_DENIED, N_("prohibited by secure boot policy")); + } + } + +diff --git a/include/grub/verify.h b/include/grub/verify.h +index cd129c398f..672ae16924 100644 +--- a/include/grub/verify.h ++++ b/include/grub/verify.h +@@ -24,6 +24,7 @@ + + enum grub_verify_flags + { ++ GRUB_VERIFY_FLAGS_NONE = 0, + GRUB_VERIFY_FLAGS_SKIP_VERIFICATION = 1, + GRUB_VERIFY_FLAGS_SINGLE_CHUNK = 2, + /* Defer verification to another authority. */ diff --git a/SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch new file mode 100644 index 0000000..59f9471 --- /dev/null +++ b/SOURCES/0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 25 Jun 2021 02:19:05 +1000 +Subject: [PATCH] kern/file: Do not leak device_name on error in + grub_file_open() + +If we have an error in grub_file_open() before we free device_name, we +will leak it. + +Free device_name in the error path and null out the pointer in the good +path once we free it there. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea) +--- + grub-core/kern/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index ec10e54fc0..db938e099d 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -84,6 +84,7 @@ grub_file_open (const char *name, enum grub_file_type type) + + device = grub_device_open (device_name); + grub_free (device_name); ++ device_name = NULL; + if (! device) + goto fail; + +@@ -138,6 +139,7 @@ grub_file_open (const char *name, enum grub_file_type type) + return file; + + fail: ++ grub_free (device_name); + if (device) + grub_device_close (device); + diff --git a/SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch new file mode 100644 index 0000000..385d3ed --- /dev/null +++ b/SOURCES/0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch @@ -0,0 +1,198 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:02:55 +1000 +Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494) +--- + grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++------- + 1 file changed, 47 insertions(+), 8 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 0157ff7420..e2a6b1cf3c 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -142,6 +142,7 @@ static grub_uint8_t + grub_png_get_byte (struct grub_png_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read = 0; + + if ((data->inside_idat) && (data->idat_remain == 0)) + { +@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data) + } + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: unexpected end of data"); ++ return 0; ++ } + + if (data->inside_idat) + data->idat_remain--; +@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data, + if (len == 0) + return GRUB_ERR_NONE; + +- for (i = 0; 3 * i < len && i < 256; i++) ++ grub_errno = GRUB_ERR_NONE; ++ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++) + for (j = 0; j < 3; j++) + data->palette[i][j] = grub_png_get_byte (data); +- for (i *= 3; i < len; i++) ++ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_get_byte (data); + + grub_png_get_dword (data); + +- return GRUB_ERR_NONE; ++ return grub_errno; + } + + static grub_err_t +@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); + + color_bits = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + data->is_16bit = (color_bits == 16); + + color_type = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* According to PNG spec, no other types are valid. */ + if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) +@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data) + if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: compression method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: filter method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: interlace method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* Skip crc checksum. */ + grub_png_get_dword (data); +@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht) + int code, i; + + code = 0; +- for (i = 0; i < ht->max_length; i++) ++ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++) + { + code = (code << 1) + grub_png_get_bits (data, 1); + if (code < ht->maxval[i]) +@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + grub_uint8_t lens[DEFLATE_HCLEN_MAX]; + + nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || + (nb > DEFLATE_HCLEN_MAX)) +@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + data->dist_offset); + + prev = 0; +- for (i = 0; i < nl + nd; i++) ++ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++) + { + int n, code; + struct huff_table *ht; +@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + pos = data->wp - dist; + if (pos < 0) + pos += WSIZE; + +- while (len > 0) ++ while (len > 0 && grub_errno == GRUB_ERR_NONE) + { + data->slide[data->wp] = data->slide[pos]; + grub_png_output_byte (data, data->slide[data->wp]); +@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int final; + + cmf = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + flg = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((cmf & 0xF) != Z_DEFLATED) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int block_type; + + final = grub_png_get_bits (data, 1); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + block_type = grub_png_get_bits (data, 2); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + switch (block_type) + { +@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data) + grub_png_get_byte (data); + grub_png_get_byte (data); + +- for (i = 0; i < len; i++) ++ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_output_byte (data, grub_png_get_byte (data)); + + break; +@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data) + + len = grub_png_get_dword (data); + type = grub_png_get_dword (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ break; + data->next_offset = data->file->offset + len + 4; + + switch (type) diff --git a/SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch new file mode 100644 index 0000000..9168fe5 --- /dev/null +++ b/SOURCES/0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:13:40 +1000 +Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers + +This causes the bitmap to be leaked. Do not permit multiple image headers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb) +--- + grub-core/video/readers/png.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index e2a6b1cf3c..8955b8ecfd 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data) + int color_bits; + enum grub_video_blit_format blt; + ++ if (data->image_width || data->image_height) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found"); ++ + data->image_width = grub_png_get_dword (data); + data->image_height = grub_png_get_dword (data); + diff --git a/SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch new file mode 100644 index 0000000..4529cb8 --- /dev/null +++ b/SOURCES/0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch @@ -0,0 +1,170 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 18:51:35 +1000 +Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap + out-of-bounds write + +A 16-bit greyscale PNG without alpha is processed in the following loop: + + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 4, d2 += 2) + { + d1[R3] = d2[1]; + d1[G3] = d2[1]; + d1[B3] = d2[1]; + } + +The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration, +but there are only 3 bytes allocated for storage. This means that image +data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes +out of every 4 following the end of the image. + +This has existed since greyscale support was added in 2013 in commit +3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale). + +Saving starfield.png as a 16-bit greyscale image without alpha in the gimp +and attempting to load it causes grub-emu to crash - I don't think this code +has ever worked. + +Delete all PNG greyscale support. + +Fixes: CVE-2021-3695 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9) +[rharwood: context conflict] +Signed-off-by: Robbie Harwood +--- + grub-core/video/readers/png.c | 85 +++---------------------------------------- + 1 file changed, 6 insertions(+), 79 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 8955b8ecfd..a3161e25b6 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -100,7 +100,7 @@ struct grub_png_data + + unsigned image_width, image_height; + int bpp, is_16bit; +- int raw_bytes, is_gray, is_alpha, is_palette; ++ int raw_bytes, is_alpha, is_palette; + int row_bytes, color_bits; + grub_uint8_t *image_data; + +@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + data->bpp = 3; + else + { +- data->is_gray = 1; +- data->bpp = 1; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: color type not supported"); + } + + if ((color_bits != 8) && (color_bits != 16) + && (color_bits != 4 +- || !(data->is_gray || data->is_palette))) ++ || !data->is_palette)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: bit depth must be 8 or 16"); + +@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data) + } + + #ifndef GRUB_CPU_WORDS_BIGENDIAN +- if (data->is_16bit || data->is_gray || data->is_palette) ++ if (data->is_16bit || data->is_palette) + #endif + { + data->image_data = grub_calloc (data->image_height, data->row_bytes); +@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data) + int shift; + int mask = (1 << data->color_bits) - 1; + unsigned j; +- if (data->is_gray) +- { +- /* Generic formula is +- (0xff * i) / ((1U << data->color_bits) - 1) +- but for allowed bit depth of 1, 2 and for it's +- equivalent to +- (0xff / ((1U << data->color_bits) - 1)) * i +- Precompute the multipliers to avoid division. +- */ + +- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; +- for (i = 0; i < (1U << data->color_bits); i++) +- { +- grub_uint8_t col = multipliers[data->color_bits] * i; +- palette[i][0] = col; +- palette[i][1] = col; +- palette[i][2] = col; +- } +- } +- else +- grub_memcpy (palette, data->palette, 3 << data->color_bits); ++ grub_memcpy (palette, data->palette, 3 << data->color_bits); + d1c = d1; + d2c = d2; + for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, +@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data) + } + return; + } +- +- if (data->is_gray) +- { +- switch (data->bpp) +- { +- case 4: +- /* 16-bit gray with alpha. */ +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 4) +- { +- d1[R4] = d2[3]; +- d1[G4] = d2[3]; +- d1[B4] = d2[3]; +- d1[A4] = d2[1]; +- } +- break; +- case 2: +- if (data->is_16bit) +- /* 16-bit gray without alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R3] = d2[1]; +- d1[G3] = d2[1]; +- d1[B3] = d2[1]; +- } +- } +- else +- /* 8-bit gray with alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R4] = d2[1]; +- d1[G4] = d2[1]; +- d1[B4] = d2[1]; +- d1[A4] = d2[0]; +- } +- } +- break; +- /* 8-bit gray without alpha. */ +- case 1: +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 3, d2++) +- { +- d1[R3] = d2[0]; +- d1[G3] = d2[0]; +- d1[B3] = d2[0]; +- } +- break; +- } +- return; +- } + + { + /* Only copy the upper 8 bit. */ diff --git a/SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch new file mode 100644 index 0000000..51dddfe --- /dev/null +++ b/SOURCES/0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 23:25:07 +1000 +Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table + items + +In fuzzing we observed crashes where a code would attempt to be inserted +into a huffman table before the start, leading to a set of heap OOB reads +and writes as table entries with negative indices were shifted around and +the new code written in. + +Catch the case where we would underflow the array and bail. + +Fixes: CVE-2021-3696 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa) +--- + grub-core/video/readers/png.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index a3161e25b6..d7ed5aa6cf 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len) + for (i = len; i < ht->max_length; i++) + n += ht->maxval[i]; + ++ if (n > ht->num_values) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: out of range inserting huffman table item"); ++ return; ++ } ++ + for (i = 0; i < n; i++) + ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; + diff --git a/SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch b/SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch new file mode 100644 index 0000000..c9cef25 --- /dev/null +++ b/SOURCES/0225-video-readers-png-Sanity-check-some-huffman-codes.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 19:19:11 +1000 +Subject: [PATCH] video/readers/png: Sanity check some huffman codes + +ASAN picked up two OOB global reads: we weren't checking if some code +values fit within the cplens or cpdext arrays. Check and throw an error +if not. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117) +--- + grub-core/video/readers/png.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index d7ed5aa6cf..7f2ba7849b 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + int len, dist, pos; + + n -= 257; ++ if (((unsigned int) n) >= ARRAY_SIZE (cplens)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); +@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); ++ if (((unsigned int) n) >= ARRAY_SIZE (cpdist)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); diff --git a/SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch new file mode 100644 index 0000000..5491816 --- /dev/null +++ b/SOURCES/0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch @@ -0,0 +1,255 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:14 +1000 +Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c) +--- + grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 70 insertions(+), 16 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index e31602f766..10225abd53 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -109,9 +109,17 @@ static grub_uint8_t + grub_jpeg_get_byte (struct grub_jpeg_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return r; + } +@@ -120,9 +128,17 @@ static grub_uint16_t + grub_jpeg_get_word (struct grub_jpeg_data *data) + { + grub_uint16_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ ++ if (bytes_read != sizeof (grub_uint16_t)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return grub_be_to_cpu16 (r); + } +@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + if (data->bit_mask == 0) + { + data->bit_save = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: file read error"); ++ return 0; ++ } + if (data->bit_save == JPEG_ESC_CHAR) + { + if (grub_jpeg_get_byte (data) != 0) +@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + "jpeg: invalid 0xFF in data stream"); + return 0; + } ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error"); ++ return 0; ++ } + } + data->bit_mask = 0x80; + } +@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) + return 0; + + msb = value = grub_jpeg_get_bit (data); +- for (i = 1; i < num; i++) ++ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++) + value = (value << 1) + (grub_jpeg_get_bit (data) != 0); + if (!msb) + value += 1 - (1 << num); +@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + while (data->file->offset + sizeof (count) + 1 <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ac = (id >> 4) & 1; + id &= 0xF; + if (id > 1) +@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (next_marker > data->file->size) + { +@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (id >= 0x10) /* Upper 4-bit is precision. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (grub_jpeg_get_byte (data) != 8) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + + ss = grub_jpeg_get_byte (data); /* Sampling factor. */ ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (!id) + { + grub_uint8_t vs, hs; +@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) + } + } + +-static void ++static grub_err_t + grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + { + int h1, h2, qt; +@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + data->dc_value[id] += + grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; + pos = 1; + while (pos < ARRAY_SIZE (data->quan_table[qt])) +@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + num >>= 4; + pos += num; + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) + { +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: invalid position in zigzag order!?"); +- return; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: invalid position in zigzag order!?"); + } + + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; +@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + } + + grub_jpeg_idct_transform (du); ++ return GRUB_ERR_NONE; + } + + static void +@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + data_offset += grub_jpeg_get_word (data); + + cc = grub_jpeg_get_byte (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (cc != 3 && cc != 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: component count must be 1 or 3"); +@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + id = grub_jpeg_get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ht = grub_jpeg_get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; +@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || + (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + } + + grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ + grub_jpeg_get_word (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + +@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; + int rst = data->dri; ++ grub_err_t err = GRUB_ERR_NONE; + + vb = 8 << data->log_vs; + hb = 8 << data->log_hs; +@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + + for (r2 = 0; r2 < (1U << data->log_vs); r2++) + for (c2 = 0; c2 < (1U << data->log_hs); c2++) +- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ { ++ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } + + if (data->color_components >= 3) + { +- grub_jpeg_decode_du (data, 1, data->cbdu); +- grub_jpeg_decode_du (data, 2, data->crdu); ++ err = grub_jpeg_decode_du (data, 1, data->cbdu); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ err = grub_jpeg_decode_du (data, 2, data->crdu); ++ if (err != GRUB_ERR_NONE) ++ return err; + } + +- if (grub_errno) +- return grub_errno; +- + nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; + nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; + diff --git a/SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch new file mode 100644 index 0000000..199ec32 --- /dev/null +++ b/SOURCES/0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:58 +1000 +Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table + +Fix a memory leak where an invalid file could cause us to reallocate +memory for a huffman table we had already allocated memory for. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9) +--- + grub-core/video/readers/jpeg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 10225abd53..caa211f06d 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + n += count[i]; + + id += ac * 2; ++ if (data->huff_value[id] != NULL) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempt to reallocate huffman table"); + data->huff_value[id] = grub_malloc (n); + if (grub_errno) + return grub_errno; diff --git a/SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch new file mode 100644 index 0000000..179238b --- /dev/null +++ b/SOURCES/0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:25:17 +1000 +Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of + streams + +An invalid file could contain multiple start of stream blocks, which +would cause us to reallocate and leak our bitmap. Refuse to handle +multiple start of streams. + +Additionally, fix a grub_error() call formatting. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f) +--- + grub-core/video/readers/jpeg.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index caa211f06d..1df1171d78 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + ++ if (*data->bitmap) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks"); ++ + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_RGB_888)) +@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); + + if (data->bitmap_ptr == NULL) +- return grub_error(GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: attempted to decode data before start of stream"); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempted to decode data before start of stream"); + + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) diff --git a/SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch new file mode 100644 index 0000000..99eeb62 --- /dev/null +++ b/SOURCES/0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 7 Jul 2021 15:38:19 +1000 +Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write + +Certain 1 px wide images caused a wild pointer write in +grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(), +we have the following loop: + +for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + +We did not check if vb * width >= hb * nc1. + +On a 64-bit platform, if that turns out to be negative, it will underflow, +be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so +we see data->bitmap_ptr jump, e.g.: + +0x6180_0000_0480 to +0x6181_0000_0498 + ^ + ~--- carry has occurred and this pointer is now far away from + any object. + +On a 32-bit platform, it will decrement the pointer, creating a pointer +that won't crash but will overwrite random data. + +Catch the underflow and error out. + +Fixes: CVE-2021-3697 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5) +--- + grub-core/video/readers/jpeg.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 1df1171d78..2da04094b3 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: attempted to decode data before start of stream"); + ++ if (vb * data->image_width <= hb * nc1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: cannot decode image with these dimensions"); ++ + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); diff --git a/SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch new file mode 100644 index 0000000..6e64ed8 --- /dev/null +++ b/SOURCES/0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 13 Jul 2021 13:24:38 +1000 +Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode + for display + +In some cases attempting to display arbitrary binary strings leads +to ASAN splats reading the widthspec array out of bounds. + +Check the index. If it would be out of bounds, return a width of 1. +I don't know if that's strictly correct, but we're not really expecting +great display of arbitrary binary data, and it's certainly not worse than +an OOB read. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d) +--- + grub-core/normal/charset.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 4dfcc31078..7a5a7c153c 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c) + { + if (grub_unicode_get_comb_type (c->base)) + return 0; ++ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec)) ++ return 1; + if (widthspec[c->base >> 3] & (1 << (c->base & 7))) + return 2; + else diff --git a/SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch b/SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch new file mode 100644 index 0000000..2e10d49 --- /dev/null +++ b/SOURCES/0231-net-netbuff-Block-overly-large-netbuff-allocs.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 23:47:46 +1100 +Subject: [PATCH] net/netbuff: Block overly large netbuff allocs + +A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment +reassembly. + +This helps avoid some bugs (and provides a spot to instrument to catch +them at their source). + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57) +--- + grub-core/net/netbuff.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c +index dbeeefe478..d5e9e9a0d7 100644 +--- a/grub-core/net/netbuff.c ++++ b/grub-core/net/netbuff.c +@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len) + + COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); + ++ /* ++ * The largest size of a TCP packet is 64 KiB, and everything else ++ * should be a lot smaller - most MTUs are 1500 or less. Cap data ++ * size at 64 KiB + a buffer. ++ */ ++ if (len > 0xffffUL + 0x1000UL) ++ { ++ grub_error (GRUB_ERR_BUG, ++ "attempted to allocate a packet that is too big"); ++ return NULL; ++ } ++ + if (len < NETBUFFMINLEN) + len = NETBUFFMINLEN; + + len = ALIGN_UP (len, NETBUFF_ALIGN); ++ + #ifdef GRUB_MACHINE_EMU + data = grub_malloc (len + sizeof (*nb)); + #else diff --git a/SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch b/SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch new file mode 100644 index 0000000..118448d --- /dev/null +++ b/SOURCES/0232-net-ip-Do-IP-fragment-maths-safely.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 19:41:21 +1100 +Subject: [PATCH] net/ip: Do IP fragment maths safely + +This avoids an underflow and subsequent unpleasantness. + +Fixes: CVE-2022-28733 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936) +--- + grub-core/net/ip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index ce6bdc75c6..cf74f1f794 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + struct iphdr { +@@ -551,7 +552,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb, + { + rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb->tail - nb->data)); +- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); ++ ++ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t), ++ &rsm->total_len)) ++ { ++ grub_dprintf ("net", "IP reassembly size underflow\n"); ++ return GRUB_ERR_NONE; ++ } ++ + rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); + if (!rsm->asm_netbuff) + { diff --git a/SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch new file mode 100644 index 0000000..19701b6 --- /dev/null +++ b/SOURCES/0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 16 Sep 2021 01:29:54 +1000 +Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response + +grub_net_dns_lookup() takes as inputs a pointer to an array of addresses +("addresses") for the given name, and pointer to a number of addresses +("naddresses"). grub_net_dns_lookup() is responsible for allocating +"addresses", and the caller is responsible for freeing it if +"naddresses" > 0. + +The DNS recv_hook will sometimes set and free the addresses array, +for example if the packet is too short: + + if (ptr + 10 >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + +Later on the nslookup command code unconditionally frees the "addresses" +array. Normally this is fine: the array is either populated with valid +data or is NULL. But in these sorts of error cases it is neither NULL +nor valid and we get a double-free. + +Only free "addresses" if "naddresses" > 0. + +It looks like the other use of grub_net_dns_lookup() is not affected. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1) +--- + grub-core/net/dns.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 906ec7d678..135faac035 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), + grub_net_addr_to_str (&addresses[i], buf); + grub_printf ("%s\n", buf); + } +- grub_free (addresses); + if (naddresses) +- return GRUB_ERR_NONE; ++ { ++ grub_free (addresses); ++ return GRUB_ERR_NONE; ++ } + return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); + } + diff --git a/SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch new file mode 100644 index 0000000..ab0d471 --- /dev/null +++ b/SOURCES/0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 21:55:43 +1100 +Subject: [PATCH] net/dns: Don't read past the end of the string we're checking + against + +I don't really understand what's going on here but fuzzing found +a bug where we read past the end of check_with. That's a C string, +so use grub_strlen() to make sure we don't overread it. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21) +--- + grub-core/net/dns.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 135faac035..17961a9f18 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + int *length, char *set) + { + const char *readable_ptr = check_with; ++ int readable_len; + const grub_uint8_t *ptr; + char *optr = set; + int bytes_processed = 0; + if (length) + *length = 0; ++ ++ if (readable_ptr != NULL) ++ readable_len = grub_strlen (readable_ptr); ++ else ++ readable_len = 0; ++ + for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) + { + /* End marker. */ +@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); + continue; + } +- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) ++ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)) + return 0; + if (grub_memchr (ptr + 1, 0, *ptr) + || grub_memchr (ptr + 1, '.', *ptr)) + return 0; + if (readable_ptr) +- readable_ptr += *ptr; ++ { ++ readable_ptr += *ptr; ++ readable_len -= *ptr; ++ } + if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) + return 0; + bytes_processed += *ptr + 1; +@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + if (optr) + *optr++ = '.'; + if (readable_ptr && *readable_ptr) +- readable_ptr++; ++ { ++ readable_ptr++; ++ readable_len--; ++ } + ptr += *ptr + 1; + } + return 0; diff --git a/SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch new file mode 100644 index 0000000..3ff7b6b --- /dev/null +++ b/SOURCES/0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Sep 2021 01:12:24 +1000 +Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek + +A malicious tftp server can cause UAFs and a double free. + +An attempt to read from a network file is handled by grub_net_fs_read(). If +the read is at an offset other than the current offset, grub_net_seek_real() +is invoked. + +In grub_net_seek_real(), if a backwards seek cannot be satisfied from the +currently received packets, and the underlying transport does not provide +a seek method, then grub_net_seek_real() will close and reopen the network +protocol layer. + +For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t +file->data. The file->data pointer is not nulled out after the free. + +If the ->open() call fails, the file->data will not be reallocated and will +continue point to a freed memory block. This could happen from a server +refusing to send the requisite ack to the new tftp request, for example. + +The seek and the read will then fail, but the grub_file continues to exist: +the failed seek does not necessarily cause the entire file to be thrown +away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc., +a read failure is interpreted as a decompressor passing on the file, not as +an invalidation of the entire grub_file_t structure). + +This means subsequent attempts to read or seek the file will use the old +file->data after free. Eventually, the file will be close()d again and +file->data will be freed again. + +Mark a net_fs file that doesn't reopen as broken. Do not permit read() or +close() on a broken file (seek is not exposed directly to the file API - +it is only called as part of read, so this blocks seeks as well). + +As an additional defence, null out the ->data pointer if tftp_open() fails. +That would have lead to a simple null pointer dereference rather than +a mess of UAFs. + +This may affect other protocols, I haven't checked. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81) +--- + grub-core/net/net.c | 11 +++++++++-- + grub-core/net/tftp.c | 1 + + include/grub/net.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 55aed92722..1001c611d1 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file) + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } +- file->device->net->protocol->close (file); ++ if (!file->device->net->broken) ++ file->device->net->protocol->close (file); + grub_free (file->device->net->name); + return GRUB_ERR_NONE; + } +@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + file->device->net->stall = 0; + err = file->device->net->protocol->open (file, file->device->net->name); + if (err) +- return err; ++ { ++ file->device->net->broken = 1; ++ return err; ++ } + grub_net_fs_read_real (file, NULL, offset); + return grub_errno; + } +@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + static grub_ssize_t + grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) + { ++ if (file->device->net->broken) ++ return -1; ++ + if (file->offset != file->device->net->offset) + { + grub_err_t err; +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index d54b13f09f..788ad1dc44 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -408,6 +408,7 @@ tftp_open (struct grub_file *file, const char *filename) + { + grub_net_udp_close (data->sock); + grub_free (data); ++ file->data = NULL; + return grub_errno; + } + +diff --git a/include/grub/net.h b/include/grub/net.h +index 42af7de250..9e4898cc6b 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -280,6 +280,7 @@ typedef struct grub_net + grub_fs_t fs; + int eof; + int stall; ++ int broken; + } *grub_net_t; + + extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); diff --git a/SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch b/SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch new file mode 100644 index 0000000..4ec3b56 --- /dev/null +++ b/SOURCES/0236-net-tftp-Avoid-a-trivial-UAF.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 18 Jan 2022 14:29:20 +1100 +Subject: [PATCH] net/tftp: Avoid a trivial UAF + +Under tftp errors, we print a tftp error message from the tftp header. +However, the tftph pointer is a pointer inside nb, the netbuff. Previously, +we were freeing the nb and then dereferencing it. Don't do that, use it +and then free it later. + +This isn't really _bad_ per se, especially as we're single-threaded, but +it trips up fuzzers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5) +--- + grub-core/net/tftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 788ad1dc44..a95766dcbd 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -251,9 +251,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + return GRUB_ERR_NONE; + case TFTP_ERROR: + data->have_oack = 1; +- grub_netbuff_free (nb); + grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); + grub_error_save (&data->save_err); ++ grub_netbuff_free (nb); + return GRUB_ERR_NONE; + default: + grub_netbuff_free (nb); diff --git a/SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch new file mode 100644 index 0000000..186f0c3 --- /dev/null +++ b/SOURCES/0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 1 Mar 2022 23:14:15 +1100 +Subject: [PATCH] net/http: Do not tear down socket if it's already been torn + down + +It's possible for data->sock to get torn down in tcp error handling. +If we unconditionally tear it down again we will end up doing writes +to an offset of the NULL pointer when we go to tear it down again. + +Detect if it has been torn down and don't do it again. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85) +--- + grub-core/net/http.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 7f878b5615..19cb8768e3 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + return err; + } + +- for (i = 0; !data->headers_recv && i < 100; i++) ++ for (i = 0; data->sock && !data->headers_recv && i < 100; i++) + { + grub_net_tcp_retransmit (); + grub_net_poll_cards (300, &data->headers_recv); +@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + + if (!data->headers_recv) + { +- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); ++ if (data->sock) ++ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->err) + { + char *str = data->errmsg; diff --git a/SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch b/SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch new file mode 100644 index 0000000..f22960b --- /dev/null +++ b/SOURCES/0238-net-http-Fix-OOB-write-for-split-http-headers.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 18:17:03 +1100 +Subject: [PATCH] net/http: Fix OOB write for split http headers + +GRUB has special code for handling an http header that is split +across two packets. + +The code tracks the end of line by looking for a "\n" byte. The +code for split headers has always advanced the pointer just past the +end of the line, whereas the code that handles unsplit headers does +not advance the pointer. This extra advance causes the length to be +one greater, which breaks an assumption in parse_line(), leading to +it writing a NUL byte one byte past the end of the buffer where we +reconstruct the line from the two packets. + +It's conceivable that an attacker controlled set of packets could +cause this to zero out the first byte of the "next" pointer of the +grub_mm_region structure following the current_line buffer. + +Do not advance the pointer in the split header case. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617) +--- + grub-core/net/http.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 19cb8768e3..58546739a2 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + int have_line = 1; + char *t; + ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); +- if (ptr) +- ptr++; +- else ++ if (ptr == NULL) + { + have_line = 0; + ptr = (char *) nb->tail; diff --git a/SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch b/SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch new file mode 100644 index 0000000..b73c169 --- /dev/null +++ b/SOURCES/0239-net-http-Error-out-on-headers-with-LF-without-CR.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 19:04:40 +1100 +Subject: [PATCH] net/http: Error out on headers with LF without CR + +In a similar vein to the previous patch, parse_line() would write +a NUL byte past the end of the buffer if there was an HTTP header +with a LF rather than a CRLF. + +RFC-2616 says: + + Many HTTP/1.1 header field values consist of words separated by LWS + or special characters. These special characters MUST be in a quoted + string to be used within a parameter value (as defined in section 3.6). + +We don't support quoted sections or continuation lines, etc. + +If we see an LF that's not part of a CRLF, bail out. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de) +--- + grub-core/net/http.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 58546739a2..57d2721719 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + char *end = ptr + len; + while (end > ptr && *(end - 1) == '\r') + end--; ++ ++ /* LF without CR. */ ++ if (end == ptr + len) ++ { ++ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR")); ++ return GRUB_ERR_NONE; ++ } + *end = 0; ++ + /* Trailing CRLF. */ + if (data->in_chunk_len == 1) + { diff --git a/SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch new file mode 100644 index 0000000..79df1c2 --- /dev/null +++ b/SOURCES/0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:03:37 +0530 +Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries + +A corrupt f2fs file system could specify a nat journal entry count +that is beyond the maximum NAT_JOURNAL_ENTRIES. + +Check if the specified nat journal entry count before accessing the +array, and throw an error if it is too large. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e) +--- + grub-core/fs/f2fs.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8a9992ca9e..63702214b0 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data) + return err; + } + +-static grub_uint32_t +-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) ++static grub_err_t ++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, ++ grub_uint32_t *blkaddr) + { + grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); +- grub_uint32_t blkaddr = 0; + grub_uint16_t i; + ++ if (n >= NAT_JOURNAL_ENTRIES) ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid number of nat journal entries"); ++ + for (i = 0; i < n; i++) + { + if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) + { +- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); ++ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); + break; + } + } + +- return blkaddr; ++ return GRUB_ERR_NONE; + } + + static grub_uint32_t +@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + { + struct grub_f2fs_nat_block *nat_block; + grub_uint32_t seg_off, block_off, entry_off, block_addr; +- grub_uint32_t blkaddr; ++ grub_uint32_t blkaddr = 0; + grub_err_t err; + +- blkaddr = get_blkaddr_from_nat_journal (data, nid); ++ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); ++ if (err != GRUB_ERR_NONE) ++ return 0; ++ + if (blkaddr) + return blkaddr; + diff --git a/SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch new file mode 100644 index 0000000..855e882 --- /dev/null +++ b/SOURCES/0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch @@ -0,0 +1,132 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:49:09 +0530 +Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap + +A corrupt f2fs filesystem could have a block offset or a bitmap +offset that would cause us to read beyond the bounds of the nat +bitmap. + +Introduce the nat_bitmap_size member in grub_f2fs_data which holds +the size of nat bitmap. + +Set the size when loading the nat bitmap in nat_bitmap_ptr(), and +catch when an invalid offset would create a pointer past the end of +the allocated space. + +Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid +reading past the end of the nat bitmap. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e) +--- + grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 63702214b0..8898b235e0 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ + + #define MAX_VOLUME_NAME 512 ++#define MAX_NAT_BITMAP_SIZE 3900 + + enum FILE_TYPE + { +@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint + grub_uint32_t checksum_offset; + grub_uint64_t elapsed_time; + grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; +- grub_uint8_t sit_nat_version_bitmap[3900]; ++ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; + grub_uint32_t checksum; + } GRUB_PACKED; + +@@ -302,6 +303,7 @@ struct grub_f2fs_data + + struct grub_f2fs_nat_journal nat_j; + char *nat_bitmap; ++ grub_uint32_t nat_bitmap_size; + + grub_disk_t disk; + struct grub_f2fs_node *inode; +@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) + } + + static void * +-nat_bitmap_ptr (struct grub_f2fs_data *data) ++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) + { + struct grub_f2fs_checkpoint *ckpt = &data->ckpt; + grub_uint32_t offset; ++ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; + + if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) + return ckpt->sit_nat_version_bitmap; + + offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); ++ if (offset >= MAX_NAT_BITMAP_SIZE) ++ return NULL; ++ ++ *nat_bitmap_size = *nat_bitmap_size - offset; + + return ckpt->sit_nat_version_bitmap + offset; + } +@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) + } + + static int +-grub_f2fs_test_bit (grub_uint32_t nr, const char *p) ++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) + { + int mask; ++ grub_uint32_t shifted_nr = (nr >> 3); + +- p += (nr >> 3); ++ if (shifted_nr >= len) ++ return -1; ++ ++ p += shifted_nr; + mask = 1 << (7 - (nr & 0x07)); + + return mask & *p; +@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + grub_uint32_t seg_off, block_off, entry_off, block_addr; + grub_uint32_t blkaddr = 0; + grub_err_t err; ++ int result_bit; + + err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); + if (err != GRUB_ERR_NONE) +@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + ((seg_off * data->blocks_per_seg) << 1) + + (block_off & (data->blocks_per_seg - 1)); + +- if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) ++ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, ++ data->nat_bitmap_size); ++ if (result_bit > 0) + block_addr += data->blocks_per_seg; ++ else if (result_bit == -1) ++ { ++ grub_free (nat_block); ++ return 0; ++ } + + err = grub_f2fs_block_read (data, block_addr, nat_block); + if (err) +@@ -833,7 +852,9 @@ grub_f2fs_mount (grub_disk_t disk) + if (err) + goto fail; + +- data->nat_bitmap = nat_bitmap_ptr (data); ++ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); ++ if (data->nat_bitmap == NULL) ++ goto fail; + + err = get_nat_journal (data); + if (err) diff --git a/SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch new file mode 100644 index 0000000..0553d60 --- /dev/null +++ b/SOURCES/0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:17:43 +0530 +Subject: [PATCH] fs/f2fs: Do not copy file names that are too long + +A corrupt f2fs file system might specify a name length which is greater +than the maximum name length supported by the GRUB f2fs driver. + +We will allocate enough memory to store the overly long name, but there +are only F2FS_NAME_LEN bytes in the source, so we would read past the end +of the source. + +While checking directory entries, do not copy a file name with an invalid +length. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a) +--- + grub-core/fs/f2fs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 8898b235e0..df6beb544c 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -1003,6 +1003,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + + ftype = ctx->dentry[i].file_type; + name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); ++ ++ if (name_len >= F2FS_NAME_LEN) ++ return 0; ++ + filename = grub_malloc (name_len + 1); + if (!filename) + return 0; diff --git a/SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch new file mode 100644 index 0000000..7ff5821 --- /dev/null +++ b/SOURCES/0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 10:49:56 +0000 +Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item + sizing + +According to the btrfs code in Linux, the structure of a directory item +leaf should be of the form: + + |struct btrfs_dir_item|name|data| + +in GRUB the name len and data len are in the grub_btrfs_dir_item +structure's n and m fields respectively. + +The combined size of the structure, name and data should be less than +the allocated memory, a difference to the Linux kernel's struct +btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for +where the name is stored, so we adjust for that too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0) +[rharwood: we've an extra variable here] +Signed-off-by: Robbie Harwood +--- + grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 07c0ff874b..2fcfb738fe 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -2254,6 +2254,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, + grub_uint64_t tree; + grub_uint8_t type; + char *new_path = NULL; ++ grub_size_t est_size = 0; + + if (!data) + return grub_errno; +@@ -2320,6 +2321,18 @@ grub_btrfs_dir (grub_device_t device, const char *path, + break; + } + ++ if (direl == NULL || ++ grub_add (grub_le_to_cpu16 (direl->n), ++ grub_le_to_cpu16 (direl->m), &est_size) || ++ grub_add (est_size, sizeof (*direl), &est_size) || ++ grub_sub (est_size, sizeof (direl->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; +@@ -2330,6 +2343,19 @@ grub_btrfs_dir (grub_device_t device, const char *path, + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; ++ ++ if (cdirel == NULL || ++ grub_add (grub_le_to_cpu16 (cdirel->n), ++ grub_le_to_cpu16 (cdirel->m), &est_size) || ++ grub_add (est_size, sizeof (*cdirel), &est_size) || ++ grub_sub (est_size, sizeof (cdirel->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); diff --git a/SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch b/SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch new file mode 100644 index 0000000..d638c11 --- /dev/null +++ b/SOURCES/0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch @@ -0,0 +1,134 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 15:52:46 +0000 +Subject: [PATCH] fs/btrfs: Fix more ASAN and SEGV issues found with fuzzing + +The fuzzer is generating btrfs file systems that have chunks with +invalid combinations of stripes and substripes for the given RAID +configurations. + +After examining the Linux kernel fs/btrfs/tree-checker.c code, it +appears that sub-stripes should only be applied to RAID10, and in that +case there should only ever be 2 of them. + +Similarly, RAID single should only have 1 stripe, and RAID1/1C3/1C4 +should have 2. 3 or 4 stripes respectively, which is what redundancy +corresponds. + +Some of the chunks ended up with a size of 0, which grub_malloc() still +returned memory for and in turn generated ASAN errors later when +accessed. + +While it would be possible to specifically limit the number of stripes, +a more correct test was on the combination of the chunk item, and the +number of stripes by the size of the chunk stripe structure in +comparison to the size of the chunk itself. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit 3849647b4b98a4419366708fc4b7f339c6f55ec7) +--- + grub-core/fs/btrfs.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 55 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 2fcfb738fe..0e9b450413 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -941,6 +941,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + ++ if (!chsize) ++ { ++ grub_dprintf ("btrfs", "zero-size chunk\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid zero-size chunk"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -999,6 +1005,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + nstripes, + NULL); ++ ++ /* For single, there should be exactly 1 stripe. */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != 1) ++ { ++ grub_dprintf ("btrfs", "invalid RAID_SINGLE: nstripes != 1 (%u)\n", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID_SINGLE: nstripes != 1 (%u)", ++ grub_le_to_cpu16 (chunk->nstripes)); ++ } + if (stripe_length == 0) + stripe_length = 512; + stripen = grub_divmod64 (off, stripe_length, &stripe_offset); +@@ -1018,6 +1034,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripen = 0; + stripe_offset = off; + csize = grub_le_to_cpu64 (chunk->size) - off; ++ ++ /* ++ * Redundancy, and substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nstripes) != redundancy) ++ { ++ grub_dprintf ("btrfs", "invalid RAID1: nstripes != %u (%u)\n", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID1: nstripes != %u (%u)", ++ redundancy, grub_le_to_cpu16 (chunk->nstripes)); ++ } + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: +@@ -1054,6 +1083,20 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + stripe_offset = low + chunk_stripe_length + * high; + csize = chunk_stripe_length - low; ++ ++ /* ++ * Substripes only apply to RAID10, and there ++ * should be exactly 2 sub-stripes. ++ */ ++ if (grub_le_to_cpu16 (chunk->nsubstripes) != 2) ++ { ++ grub_dprintf ("btrfs", "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid RAID10: nsubstripes != 2 (%u)", ++ grub_le_to_cpu16 (chunk->nsubstripes)); ++ } ++ + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID5: +@@ -1153,6 +1196,8 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + + for (j = 0; j < 2; j++) + { ++ grub_size_t est_chunk_alloc = 0; ++ + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T + " (%d stripes (%d substripes) of %" +@@ -1165,6 +1210,16 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T "\n", + addr); + ++ if (grub_mul (sizeof (struct grub_btrfs_chunk_stripe), ++ grub_le_to_cpu16 (chunk->nstripes), &est_chunk_alloc) || ++ grub_add (est_chunk_alloc, ++ sizeof (struct grub_btrfs_chunk_item), &est_chunk_alloc) || ++ est_chunk_alloc > chunk->size) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch b/SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch new file mode 100644 index 0000000..2e5145f --- /dev/null +++ b/SOURCES/0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Thu, 7 Apr 2022 15:18:12 +0000 +Subject: [PATCH] fs/btrfs: Fix more fuzz issues related to chunks + +The corpus we generating issues in grub_btrfs_read_logical() when +attempting to iterate over nstripes entries in the boot mapping. + +In most cases the reason for the failure was that the number of strips +exceeded the possible space statically allocated in superblock bootmapping +space. Each stripe entry in the bootmapping block consists of +a grub_btrfs_key followed by a grub_btrfs_chunk_stripe. + +Another issue that came up was that while calculating the chunk size, +in an earlier piece of code in that function, depending on the data +provided in the btrfs file system, it would end up calculating a size +that was too small to contain even 1 grub_btrfs_chunk_item, which is +obviously invalid too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit e00cd76cbadcc897a9cc4087cb2fcb5dbe15e596) +--- + grub-core/fs/btrfs.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 0e9b450413..47325f6ad7 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -947,6 +947,17 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + return grub_error (GRUB_ERR_BAD_FS, + "got an invalid zero-size chunk"); + } ++ ++ /* ++ * The space being allocated for a chunk should at least be able to ++ * contain one chunk item. ++ */ ++ if (chsize < sizeof (struct grub_btrfs_chunk_item)) ++ { ++ grub_dprintf ("btrfs", "chunk-size too small\n"); ++ return grub_error (GRUB_ERR_BAD_FS, ++ "got an invalid chunk size"); ++ } + chunk = grub_malloc (chsize); + if (!chunk) + return grub_errno; +@@ -1194,6 +1205,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + if (csize > (grub_uint64_t) size) + csize = size; + ++ /* ++ * The space for a chunk stripe is limited to the space provide in the super-block's ++ * bootstrap mapping with an initial btrfs key at the start of each chunk. ++ */ ++ grub_size_t avail_stripes = sizeof (data->sblock.bootstrap_mapping) / ++ (sizeof (struct grub_btrfs_key) + sizeof (struct grub_btrfs_chunk_stripe)); ++ + for (j = 0; j < 2; j++) + { + grub_size_t est_chunk_alloc = 0; +@@ -1220,6 +1238,12 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_disk_addr_t addr, + break; + } + ++ if (grub_le_to_cpu16 (chunk->nstripes) > avail_stripes) ++ { ++ err = GRUB_ERR_BAD_FS; ++ break; ++ } ++ + if (is_raid56) + { + err = btrfs_read_from_chunk (data, chunk, stripen, diff --git a/SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch b/SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch new file mode 100644 index 0000000..eb2e8fd --- /dev/null +++ b/SOURCES/0246-misc-Make-grub_min-and-grub_max-more-resilient.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 16:06:10 -0400 +Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient. + +grub_min(a,b) and grub_max(a,b) use a relatively naive implementation +which leads to several problems: +- they evaluate their parameters more than once +- the naive way to address this, to declare temporary variables in a + statement-expression, isn't resilient against nested uses, because + MIN(a,MIN(b,c)) results in the temporary variables being declared in + two nested scopes, which may result in a build warning depending on + your build options. + +This patch changes our implementation to use a statement-expression +inside a helper macro, and creates the symbols for the temporary +variables with __COUNTER__ (A GNU C cpp extension) and token pasting to +create uniquely named internal variables. + +Signed-off-by: Peter Jones +--- + grub-core/loader/multiboot_elfxx.c | 4 +--- + include/grub/misc.h | 25 +++++++++++++++++++++++-- + 2 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c +index f2318e0d16..87f6e31aa6 100644 +--- a/grub-core/loader/multiboot_elfxx.c ++++ b/grub-core/loader/multiboot_elfxx.c +@@ -35,9 +35,7 @@ + #endif + + #include +- +-#define CONCAT(a,b) CONCAT_(a, b) +-#define CONCAT_(a,b) a ## b ++#include + + #pragma GCC diagnostic ignored "-Wcast-align" + +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 6c4aa85ac5..cf84aec1db 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -35,6 +35,14 @@ + #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } + ++#ifndef CONCAT_ ++#define CONCAT_(a, b) a ## b ++#endif ++ ++#ifndef CONCAT ++#define CONCAT(a, b) CONCAT_(a, b) ++#endif ++ + #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) + + void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); +@@ -498,8 +506,21 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + #define grub_boot_time(...) + #endif + +-#define grub_max(a, b) (((a) > (b)) ? (a) : (b)) +-#define grub_min(a, b) (((a) < (b)) ? (a) : (b)) ++#define _grub_min(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++#define grub_min(a, b) _grub_min(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) ++ ++#define _grub_max(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a > _b ? _a : _b; }) ++#define grub_max(a, b) _grub_max(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) + + #define grub_log2ull(n) (GRUB_TYPE_BITS (grub_uint64_t) - __builtin_clzll (n) - 1) + diff --git a/SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch b/SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch new file mode 100644 index 0000000..0707af3 --- /dev/null +++ b/SOURCES/0247-ReiserFS-switch-to-using-grub_min-grub_max.patch @@ -0,0 +1,92 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 21 Apr 2022 16:31:17 -0400 +Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max() + +This is a minor cleanup patch to remove the bespoke MIN() and MAX() +definitions from the reiserfs driver, and uses grub_min() / grub_max() +instead. + +Signed-off-by: Peter Jones +--- + grub-core/fs/reiserfs.c | 28 +++++++++------------------- + 1 file changed, 9 insertions(+), 19 deletions(-) + +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index af6a226a7f..b8253da7fe 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -42,16 +42,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- +-#define MAX(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a > _b ? _a : _b; }) +- + #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 + #define REISERFS_MAGIC_LEN 12 + #define REISERFS_MAGIC_STRING "ReIsEr" +@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); + initial_position = off; + current_position = 0; +- final_position = MIN (len + initial_position, node->size); ++ final_position = grub_min (len + initial_position, node->size); + grub_dprintf ("reiserfs", + "Reading from %lld to %lld (%lld instead of requested %ld)\n", + (unsigned long long) initial_position, +@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); + if (initial_position < current_position + item_size) + { +- offset = MAX ((signed) (initial_position - current_position), 0); +- length = (MIN (item_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), 0); ++ length = (grub_min (item_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading direct block %u from %u to %u...\n", +@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); + if (current_position + block_size >= initial_position) + { +- offset = MAX ((signed) (initial_position - current_position), +- 0); +- length = (MIN (block_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), ++ 0); ++ length = (grub_min (block_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading indirect block %u from %u to %u...\n", +@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + switch (found.type) + { + case GRUB_REISERFS_DIRECT: +- read_length = MIN (len, item_size - file->offset); ++ read_length = grub_min (len, item_size - file->offset); + grub_disk_read (found.data->disk, + (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE, + grub_le_to_cpu16 (found.header.item_location) + file->offset, +@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + item_size, (char *) indirect_block_ptr); + if (grub_errno) + goto fail; +- len = MIN (len, file->size - file->offset); ++ len = grub_min (len, file->size - file->offset); + for (indirect_block = file->offset / block_size; + indirect_block < indirect_block_count && read_length < len; + indirect_block++) + { +- read = MIN (block_size, len - read_length); ++ read = grub_min (block_size, len - read_length); + grub_disk_read (found.data->disk, + (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE, + file->offset % block_size, read, diff --git a/SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch b/SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch new file mode 100644 index 0000000..a7ac6f2 --- /dev/null +++ b/SOURCES/0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Mar 2022 14:40:01 -0400 +Subject: [PATCH] misc: make grub_boot_time() also call + grub_dprintf("boot",...) + +Currently grub_boot_time() includes valuable debugging messages, but if +you build without BOOT_TIME_STATS enabled, they are silently and +confusingly compiled away. + +This patch changes grub_boot_time() to also log when "boot" is enabled +in DEBUG, regardless of BOOT_TIME_STATS. + +Signed-off-by: Peter Jones +--- + grub-core/kern/misc.c | 3 ++- + include/grub/misc.h | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index a186ad3dd4..cb45461402 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1334,7 +1334,8 @@ grub_real_boot_time (const char *file, + n->next = 0; + + va_start (args, fmt); +- n->msg = grub_xvasprintf (fmt, args); ++ n->msg = grub_xvasprintf (fmt, args); ++ grub_dprintf ("boot", "%s\n", n->msg); + va_end (args); + + *boot_time_last = n; +diff --git a/include/grub/misc.h b/include/grub/misc.h +index cf84aec1db..faae0ae860 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -503,7 +503,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); + #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) + #else +-#define grub_boot_time(...) ++#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__) + #endif + + #define _grub_min(a, b, _a, _b) \ diff --git a/SOURCES/0249-modules-make-.module_license-read-only.patch b/SOURCES/0249-modules-make-.module_license-read-only.patch new file mode 100644 index 0000000..ba3b313 --- /dev/null +++ b/SOURCES/0249-modules-make-.module_license-read-only.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Feb 2022 16:32:51 -0500 +Subject: [PATCH] modules: make .module_license read-only + +Currently .module_license is set writable (that is, the section has the +SHF_WRITE flag set) in the module's ELF headers. This probably never +actually matters, but it can't possibly be correct. + +This patch sets that data as "const", which causes that flag not to be +set. + +Signed-off-by: Peter Jones +--- + include/grub/dl.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 20d870f2a4..618ae6f474 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -121,7 +121,7 @@ grub_mod_fini (void) + #define ATTRIBUTE_USED __unused__ + #endif + #define GRUB_MOD_LICENSE(license) \ +- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; ++ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; + #define GRUB_MOD_DEP(name) \ + static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name diff --git a/SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch b/SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch new file mode 100644 index 0000000..9f26115 --- /dev/null +++ b/SOURCES/0250-modules-strip-.llvm_addrsig-sections-and-similar.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Feb 2022 16:40:11 -0500 +Subject: [PATCH] modules: strip .llvm_addrsig sections and similar. + +Currently grub modules built with clang or gcc have several sections +which we don't actually need or support. + +We already have a list of section to skip in genmod.sh, and this patch +adds the following sections to that list (as well as a few newlines): + +.note.gnu.property +.llvm* + +Note that the glob there won't work without a new enough linker, but the +failure is just reversion to the status quo, so that's not a big problem. + +Signed-off-by: Peter Jones +--- + grub-core/genmod.sh.in | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in +index 1250589b3f..c2c5280d75 100644 +--- a/grub-core/genmod.sh.in ++++ b/grub-core/genmod.sh.in +@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then + @TARGET_STRIP@ --strip-unneeded \ + -K grub_mod_init -K grub_mod_fini \ + -K _grub_mod_init -K _grub_mod_fini \ +- -R .note.gnu.gold-version -R .note.GNU-stack \ ++ -R .note.GNU-stack \ ++ -R .note.gnu.gold-version \ ++ -R .note.gnu.property \ + -R .gnu.build.attributes \ ++ -R '.llvm*' \ + -R .rel.gnu.build.attributes \ + -R .rela.gnu.build.attributes \ + -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \ diff --git a/SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch b/SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch new file mode 100644 index 0000000..d07d838 --- /dev/null +++ b/SOURCES/0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 16:56:10 -0400 +Subject: [PATCH] modules: Don't allocate space for non-allocable sections. + +Currently when loading grub modules, we allocate space for all sections, +including those without SHF_ALLOC set. We then copy the sections that +/do/ have SHF_ALLOC set into the allocated memory, leaving some of our +allocation untouched forever. Additionally, on platforms with GOT +fixups and trampolines, we currently compute alignment round-ups for the +sections and sections with sh_size = 0. + +This patch removes the extra space from the allocation computation, and +makes the allocation computation loop skip empty sections as the loading +loop does. + +Signed-off-by: Peter Jones +--- + grub-core/kern/dl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index f304494574..aef8af8aa7 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -289,6 +289,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { ++ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ + tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; + if (talign < s->sh_addralign) + talign = s->sh_addralign; diff --git a/SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch b/SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch new file mode 100644 index 0000000..ef51214 --- /dev/null +++ b/SOURCES/0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 25 Mar 2022 15:40:12 -0400 +Subject: [PATCH] pe: add the DOS header struct and fix some bad naming. + +In order to properly validate a loaded kernel's support for being loaded +without a writable stack or executable, we need to be able to properly +parse arbitrary PE headers. + +Currently, pe32.h is written in such a way that the MS-DOS header that +tells us where to find the PE header in the binary can't be accessed. +Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC". + +This patch adds the structure for the DOS header, renames the DOS magic +define, and adds defines for the actual PE magic. + +Signed-off-by: Peter Jones +--- + grub-core/loader/arm64/linux.c | 2 +- + include/grub/efi/pe32.h | 28 ++++++++++++++++++++++++++-- + 2 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index d2af47c2c0..cc67f43906 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -58,7 +58,7 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) + return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); + +- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) ++ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); + +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index a43adf2746..2a5e1ee003 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -46,7 +46,30 @@ + + #define GRUB_PE32_MSDOS_STUB_SIZE 0x80 + +-#define GRUB_PE32_MAGIC 0x5a4d ++#define GRUB_DOS_MAGIC 0x5a4d ++ ++struct grub_dos_header ++{ ++ grub_uint16_t magic; ++ grub_uint16_t cblp; ++ grub_uint16_t cp; ++ grub_uint16_t crlc; ++ grub_uint16_t cparhdr; ++ grub_uint16_t minalloc; ++ grub_uint16_t maxalloc; ++ grub_uint16_t ss; ++ grub_uint16_t sp; ++ grub_uint16_t csum; ++ grub_uint16_t ip; ++ grub_uint16_t cs; ++ grub_uint16_t lfarlc; ++ grub_uint16_t ovno; ++ grub_uint16_t res0[4]; ++ grub_uint16_t oemid; ++ grub_uint16_t oeminfo; ++ grub_uint16_t res1[10]; ++ grub_uint32_t lfanew; ++}; + + /* According to the spec, the minimal alignment is 512 bytes... + But some examples (such as EFI drivers in the Intel +@@ -280,7 +303,8 @@ struct grub_pe32_section_table + + + +-#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE "PE\0\0" + + struct grub_pe32_header + { diff --git a/SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch b/SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch new file mode 100644 index 0000000..c6688cd --- /dev/null +++ b/SOURCES/0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 9 Feb 2022 16:08:20 -0500 +Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of + EFI_LOADER_DATA. + +On some of the firmwares with more security mitigations, EFI_LOADER_DATA +doesn't get you executable memory, and we take a fault and reboot when +we enter kernel. + +This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE +rather than EFI_LOADER_DATA. + +Signed-off-by: Peter Jones +[rharwood: use kernel_size] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 9e5c11ac69..92b2fb5091 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size) + } + + static void * +-kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++kernel_alloc(grub_efi_uintn_t size, ++ grub_efi_memory_type_t memtype, ++ const char * const errmsg) + { + void *addr = 0; + unsigned int i; +@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, + max_addresses[i].alloc_type, +- GRUB_EFI_LOADER_DATA); ++ memtype); + if (addr) + grub_dprintf ("linux", "Allocated at %p\n", addr); + } +@@ -242,7 +244,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); +@@ -393,7 +396,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); ++ params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, ++ "cannot allocate kernel parameters"); + if (!params) + goto fail; + grub_dprintf ("linux", "params = %p\n", params); +@@ -415,7 +419,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); ++ cmdline = kernel_alloc (lh->cmdline_size + 1, ++ GRUB_EFI_RUNTIME_SERVICES_DATA, ++ N_("can't allocate cmdline")); + if (!cmdline) + goto fail; + grub_dprintf ("linux", "cmdline = %p\n", cmdline); +@@ -461,7 +467,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; +- kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); ++ kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, ++ N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) + goto fail; diff --git a/SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch b/SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch new file mode 100644 index 0000000..eb171f5 --- /dev/null +++ b/SOURCES/0254-modules-load-module-sections-at-page-aligned-address.patch @@ -0,0 +1,378 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 17:45:40 -0400 +Subject: [PATCH] modules: load module sections at page-aligned addresses + +Currently we load module sections at whatever alignment gcc+ld happened +to dump into the ELF section header, which is often pretty useless. For +example, by default time.mod has these sections on a current x86_64 +build: + +$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13 +Section Headers: +[Nr] Name Type Addr Off Size ES Flags Lk Inf Al +[ 0] NULL 0 00000000 00000000 0 0 0 0 +[ 1] .text PROGBITS 0 00000040 0000015e 0 AX 0 0 1 +[ 2] .rela.text RELA 0 00000458 000001e0 24 I 8 1 8 +[ 3] .rodata.str1.1 PROGBITS 0 0000019e 000000a1 1 AMS 0 0 1 +[ 4] .module_license PROGBITS 0 00000240 0000000f 0 A 0 0 8 +[ 5] .data PROGBITS 0 0000024f 00000000 0 WA 0 0 1 +[ 6] .bss NOBITS 0 00000250 00000008 0 WA 0 0 8 +[ 7] .modname PROGBITS 0 00000250 00000005 0 0 0 1 +[ 8] .symtab SYMTAB 0 00000258 00000150 24 9 6 8 +[ 9] .strtab STRTAB 0 000003a8 000000ab 0 0 0 1 +[10] .shstrtab STRTAB 0 00000638 00000059 0 0 0 1 + +With NX protections being page based, loading sections with either a 1 +or 8 *byte* alignment does absolutely nothing to help us out. + +This patch switches most EFI platforms to load module sections at 4kB +page-aligned addresses. To do so, it adds an new per-arch function, +grub_arch_dl_min_alignment(), which returns the alignment needed for +dynamically loaded sections (in bytes). Currently it sets it to 4096 +when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and +1-byte alignment on everything else. + +It then changes the allocation size computation and the loader code in +grub_dl_load_segments() to align the locations and sizes up to these +boundaries, and fills any added padding with zeros. + +All of this happens before relocations are applied, so the relocations +factor that in with no change. + +As an aside, initially Daniel Kiper and I thought that it might be a +better idea to split the modules up into top-level sections as +.text.modules, .rodata.modules, .data.modules, etc., so that their page +permissions would get set by the loader that's loading grub itself. +This turns out to have two significant downsides: 1) either in mkimage +or in grub_dl_relocate_symbols(), you wind up having to dynamically +process the relocations to accommodate the moved module sections, and 2) +you then need to change the permissions on the modules and change them +back while relocating them in grub_dl_relocate_symbols(), which means +that any loader that /does/ honor the section flags but does /not/ +generally support NX with the memory attributes API will cause grub to +fail. + +Signed-off-by: Peter Jones +--- + grub-core/kern/arm/dl.c | 13 +++++++++++++ + grub-core/kern/arm64/dl.c | 13 +++++++++++++ + grub-core/kern/dl.c | 29 +++++++++++++++++++++-------- + grub-core/kern/emu/full.c | 13 +++++++++++++ + grub-core/kern/i386/dl.c | 13 +++++++++++++ + grub-core/kern/ia64/dl.c | 9 +++++++++ + grub-core/kern/mips/dl.c | 8 ++++++++ + grub-core/kern/powerpc/dl.c | 9 +++++++++ + grub-core/kern/riscv/dl.c | 13 +++++++++++++ + grub-core/kern/sparc64/dl.c | 9 +++++++++ + grub-core/kern/x86_64/dl.c | 13 +++++++++++++ + include/grub/dl.h | 2 ++ + docs/grub-dev.texi | 6 +++--- + 13 files changed, 139 insertions(+), 11 deletions(-) + +diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c +index eab9d17ff2..9260737936 100644 +--- a/grub-core/kern/arm/dl.c ++++ b/grub-core/kern/arm/dl.c +@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr) + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c +index 512e5a80b0..0d4a26857f 100644 +--- a/grub-core/kern/arm64/dl.c ++++ b/grub-core/kern/arm64/dl.c +@@ -196,3 +196,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index aef8af8aa7..8c7aacef39 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -277,7 +277,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + unsigned i; + const Elf_Shdr *s; +- grub_size_t tsize = 0, talign = 1; ++ grub_size_t tsize = 0, talign = 1, arch_addralign = 1; + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) + grub_size_t tramp; + grub_size_t got; +@@ -285,16 +285,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + #endif + char *ptr; + ++ arch_addralign = grub_arch_dl_min_alignment (); ++ + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign; ++ grub_size_t sh_size; ++ + if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) + continue; + +- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; +- if (talign < s->sh_addralign) +- talign = s->sh_addralign; ++ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ ++ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size; ++ if (talign < sh_addralign) ++ talign = sh_addralign; + } + + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) +@@ -323,6 +331,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ + if (s->sh_flags & SHF_ALLOC) + { + grub_dl_segment_t seg; +@@ -335,17 +346,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + void *addr; + +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign); + addr = ptr; +- ptr += s->sh_size; ++ ptr += sh_size; + + switch (s->sh_type) + { + case SHT_PROGBITS: + grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); ++ grub_memset ((char *)addr + s->sh_size, 0, ++ sh_size - s->sh_size); + break; + case SHT_NOBITS: +- grub_memset (addr, 0, s->sh_size); ++ grub_memset (addr, 0, sh_size); + break; + } + +@@ -354,7 +367,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + else + seg->addr = 0; + +- seg->size = s->sh_size; ++ seg->size = sh_size; + seg->section = i; + seg->next = mod->segment; + mod->segment = seg; +diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c +index e8d63b1f5f..1de1c28eb0 100644 +--- a/grub-core/kern/emu/full.c ++++ b/grub-core/kern/emu/full.c +@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void) + } + #endif + ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c +index 1346da5cc9..d6b4681fc9 100644 +--- a/grub-core/kern/i386/dl.c ++++ b/grub-core/kern/i386/dl.c +@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c +index db59300fea..92d82c5750 100644 +--- a/grub-core/kern/ia64/dl.c ++++ b/grub-core/kern/ia64/dl.c +@@ -148,3 +148,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + } + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c +index 5d7d299c74..6d83bd71e9 100644 +--- a/grub-core/kern/mips/dl.c ++++ b/grub-core/kern/mips/dl.c +@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void) + grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0); + } + ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c +index cdd61b305f..5d9ba2e158 100644 +--- a/grub-core/kern/powerpc/dl.c ++++ b/grub-core/kern/powerpc/dl.c +@@ -167,3 +167,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/riscv/dl.c b/grub-core/kern/riscv/dl.c +index f26b12aaa4..aa18f9e990 100644 +--- a/grub-core/kern/riscv/dl.c ++++ b/grub-core/kern/riscv/dl.c +@@ -343,3 +343,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c +index f3d960186b..f054f08241 100644 +--- a/grub-core/kern/sparc64/dl.c ++++ b/grub-core/kern/sparc64/dl.c +@@ -189,3 +189,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c +index e5a8bdcf4f..a105dc50ce 100644 +--- a/grub-core/kern/x86_64/dl.c ++++ b/grub-core/kern/x86_64/dl.c +@@ -119,3 +119,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 618ae6f474..f36ed5cb17 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr); + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg); ++grub_size_t ++grub_arch_dl_min_alignment (void); + #endif + + #if defined (_mips) +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 19f708ee66..7b2455a8fe 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -755,9 +755,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files + (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). + At this stage you will also need to add dummy dl.c and cache.S with functions + grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and +-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They +-won't be used for now. ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t ++grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void ++*address, grub_size_t len) (cache.S). They won't be used for now. + + You will need to create directory include/$cpu/$platform and a file + include/$cpu/types.h. The later folowing this template: diff --git a/SOURCES/0255-nx-add-memory-attribute-get-set-API.patch b/SOURCES/0255-nx-add-memory-attribute-get-set-API.patch new file mode 100644 index 0000000..91c9d2f --- /dev/null +++ b/SOURCES/0255-nx-add-memory-attribute-get-set-API.patch @@ -0,0 +1,317 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:56:21 -0400 +Subject: [PATCH] nx: add memory attribute get/set API + +For NX, we need to set the page access permission attributes for write +and execute permissions. + +This patch adds two new primitives, grub_set_mem_attrs() and +grub_clear_mem_attrs(), and associated constant definitions, to be used +for that purpose. + +For most platforms, it adds a dummy implementation that returns +GRUB_ERR_NONE. On EFI platforms, it adds a common helper function, +grub_efi_status_to_err(), which translates EFI error codes to grub error +codes, adds headers for the EFI Memory Attribute Protocol (still pending +standardization), and an implementation of the grub nx primitives using +it. + +Signed-off-by: Peter Jones +[rharwood: add pjones's none/nyi fixup] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/efi/efi.c | 36 +++++++++++++ + grub-core/kern/efi/mm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 25 +++++++++ + include/grub/efi/efi.h | 2 + + include/grub/mm.h | 32 ++++++++++++ + 5 files changed, 226 insertions(+) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 7fcca69c17..4ac2b2754e 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -1096,3 +1096,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, + + return 0; + } ++ ++grub_err_t ++grub_efi_status_to_err (grub_efi_status_t status) ++{ ++ grub_err_t err; ++ switch (status) ++ { ++ case GRUB_EFI_SUCCESS: ++ err = GRUB_ERR_NONE; ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ default: ++ err = GRUB_ERR_BAD_ARGUMENT; ++ break; ++ case GRUB_EFI_OUT_OF_RESOURCES: ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ break; ++ case GRUB_EFI_DEVICE_ERROR: ++ err = GRUB_ERR_IO; ++ break; ++ case GRUB_EFI_WRITE_PROTECTED: ++ err = GRUB_ERR_WRITE_ERROR; ++ break; ++ case GRUB_EFI_SECURITY_VIOLATION: ++ err = GRUB_ERR_ACCESS_DENIED; ++ break; ++ case GRUB_EFI_NOT_FOUND: ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ break; ++ case GRUB_EFI_ABORTED: ++ err = GRUB_ERR_WAIT; ++ break; ++ } ++ ++ return err; ++} +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index e84961d078..2c33758ed7 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -738,3 +738,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + return GRUB_ERR_NONE; + } + #endif ++ ++static inline grub_uint64_t ++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_EFI_MEMORY_RP | ++ GRUB_EFI_MEMORY_RO | ++ GRUB_EFI_MEMORY_XP; ++ ++ if (attrs & GRUB_MEM_ATTR_R) ++ ret &= ~GRUB_EFI_MEMORY_RP; ++ ++ if (attrs & GRUB_MEM_ATTR_W) ++ ret &= ~GRUB_EFI_MEMORY_RO; ++ ++ if (attrs & GRUB_MEM_ATTR_X) ++ ret &= ~GRUB_EFI_MEMORY_XP; ++ ++ return ret; ++} ++ ++static inline grub_uint64_t ++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ ++ if (attrs & GRUB_EFI_MEMORY_RP) ++ ret &= ~GRUB_MEM_ATTR_R; ++ ++ if (attrs & GRUB_EFI_MEMORY_RO) ++ ret &= ~GRUB_MEM_ATTR_W; ++ ++ if (attrs & GRUB_EFI_MEMORY_XP) ++ ret &= ~GRUB_MEM_ATTR_X; ++ ++ return ret; ++} ++ ++grub_err_t ++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n", ++ __func__, physaddr, physaddr+size-1, attrs); ++ return 0; ++ } ++ ++ efi_status = efi_call_4(proto->get_memory_attributes, ++ proto, physaddr, size, attrs); ++ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs); ++ ++ return grub_efi_status_to_err (efi_status); ++} ++ ++grub_err_t ++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size, ++ grub_uint64_t set_attrs, grub_uint64_t clear_attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS; ++ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; ++ grub_err_t err; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NONE; ++ ++ err = grub_get_mem_attrs (addr, size, &before); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &before, err); ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n", ++ __func__, physaddr, physaddr + size - 1, ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ return 0; ++ } ++ ++ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs); ++ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); ++ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs); ++ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); ++ if (uefi_set_attrs) ++ efi_status = efi_call_4(proto->set_memory_attributes, ++ proto, physaddr, size, uefi_set_attrs); ++ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) ++ efi_status = efi_call_4(proto->clear_memory_attributes, ++ proto, physaddr, size, uefi_clear_attrs); ++ ++ err = grub_get_mem_attrs (addr, size, &after); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &after, err); ++ ++ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ addr, addr + size - 1, ++ (before & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (before & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (before & GRUB_MEM_ATTR_X) ? 'x' : '-', ++ (after & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (after & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (after & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ ++ return grub_efi_status_to_err (efi_status); ++} +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index f431f49973..464842ba37 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -363,6 +363,11 @@ + { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + ++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \ ++ { 0xf4560cf6, 0x40ec, 0x4b4a, \ ++ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -2102,6 +2107,26 @@ struct grub_efi_ip6_config_manual_address { + }; + typedef struct grub_efi_ip6_config_manual_address grub_efi_ip6_config_manual_address_t; + ++struct grub_efi_memory_attribute_protocol ++{ ++ grub_efi_status_t (*get_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t *attributes); ++ grub_efi_status_t (*set_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++ grub_efi_status_t (*clear_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++}; ++typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ + || defined(__riscv) +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index ec52083c49..34825c4adc 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -164,4 +164,6 @@ struct grub_net_card; + grub_efi_handle_t + grub_efinet_get_device_handle (struct grub_net_card *card); + ++grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status); ++ + #endif /* ! GRUB_EFI_EFI_HEADER */ +diff --git a/include/grub/mm.h b/include/grub/mm.h +index 9c38dd3ca5..d81623d226 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -22,6 +22,7 @@ + + #include + #include ++#include + #include + + #ifndef NULL +@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); + void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); + #endif + ++#define GRUB_MEM_ATTR_R 0x0000000000000004LLU ++#define GRUB_MEM_ATTR_W 0x0000000000000002LLU ++#define GRUB_MEM_ATTR_X 0x0000000000000001LLU ++ ++#ifdef GRUB_MACHINE_EFI ++grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t *attrs); ++grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t set_attrs, ++ grub_uint64_t clear_attrs); ++#else /* !GRUB_MACHINE_EFI */ ++static inline grub_err_t ++grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t *attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++ ++static inline grub_err_t ++grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t set_attrs __attribute__((__unused__)), ++ grub_uint64_t clear_attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++#endif /* GRUB_MACHINE_EFI */ ++ + void grub_mm_check_real (const char *file, int line); + #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); + diff --git a/SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch b/SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch new file mode 100644 index 0000000..9e0aebb --- /dev/null +++ b/SOURCES/0256-nx-set-page-permissions-for-loaded-modules.patch @@ -0,0 +1,263 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 17:46:35 -0400 +Subject: [PATCH] nx: set page permissions for loaded modules. + +For NX, we need to set write and executable permissions on the sections +of grub modules when we load them. + +On sections with SHF_ALLOC set, which is typically everything except +.modname and the symbol and string tables, this patch clears the Read +Only flag on sections that have the ELF flag SHF_WRITE set, and clears +the No eXecute flag on sections with SHF_EXECINSTR set. In all other +cases it sets both flags. + +Signed-off-by: Peter Jones +[rharwood: arm tgptr -> tgaddr] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++------------- + include/grub/dl.h | 44 +++++++++++++++++++ + 2 files changed, 134 insertions(+), 30 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 8c7aacef39..d5de80186f 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -285,6 +285,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + #endif + char *ptr; + ++ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name); ++ + arch_addralign = grub_arch_dl_min_alignment (); + + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); +@@ -384,6 +386,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + ptr += got; + #endif + ++ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } + +@@ -517,23 +520,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) + return s; + return NULL; + } +-static long +-grub_dl_find_section_index (Elf_Ehdr *e, const char *name) +-{ +- Elf_Shdr *s; +- const char *str; +- unsigned i; +- +- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); +- str = (char *) e + s->sh_offset; +- +- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); +- i < e->e_shnum; +- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +- if (grub_strcmp (str + s->sh_name, name) == 0) +- return (long)i; +- return -1; +-} + + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. +@@ -662,6 +648,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + Elf_Shdr *s; + unsigned i; + ++ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +@@ -670,24 +657,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + grub_dl_segment_t seg; + grub_err_t err; + +- /* Find the target segment. */ +- for (seg = mod->segment; seg; seg = seg->next) +- if (seg->section == s->sh_info) +- break; ++ seg = grub_dl_find_segment(mod, s->sh_info); ++ if (!seg) ++ continue; + +- if (seg) +- { +- if (!mod->symtab) +- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); ++ if (!mod->symtab) ++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); + +- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); +- if (err) +- return err; +- } ++ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); ++ if (err) ++ return err; + } + ++ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } ++ ++static grub_err_t ++grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) ++{ ++ unsigned i; ++ const Elf_Shdr *s; ++ const Elf_Ehdr *e = ehdr; ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ grub_size_t arch_addralign = grub_arch_dl_min_alignment (); ++ grub_addr_t tgaddr; ++ grub_uint64_t tgsz; ++#endif ++ ++ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n", ++ mod->name); ++ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) ++ { ++ grub_dl_segment_t seg; ++ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R; ++ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X; ++ ++ seg = grub_dl_find_segment(mod, i); ++ if (!seg) ++ continue; ++ ++ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ ++ if (s->sh_flags & SHF_WRITE) ++ { ++ set_attrs |= GRUB_MEM_ATTR_W; ++ clear_attrs &= ~GRUB_MEM_ATTR_W; ++ } ++ ++ if (s->sh_flags & SHF_EXECINSTR) ++ { ++ set_attrs |= GRUB_MEM_ATTR_X; ++ clear_attrs &= ~GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n", ++ grub_dl_get_section_name(e, s), ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs); ++ } ++ ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got); ++ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr; ++ ++ if (tgsz) ++ { ++ tgsz = ALIGN_UP(tgsz, arch_addralign); ++ ++ grub_dprintf ("modules", "updating attributes for GOT and trampolines\n", ++ mod->name); ++ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, ++ GRUB_MEM_ATTR_W); ++ } ++#endif ++ ++ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n", ++ mod->name); ++ ++ return GRUB_ERR_NONE; ++} ++ + static void + grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) + { +@@ -753,6 +811,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + mod->ref_count = 1; + + grub_dprintf ("modules", "relocating to %p\n", mod); ++ + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally +@@ -766,7 +825,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + || grub_dl_resolve_dependencies (mod, e) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) +- || grub_dl_relocate_symbols (mod, e)) ++ || grub_dl_relocate_symbols (mod, e) ++ || grub_dl_set_mem_attrs (mod, e)) + { + mod->fini = 0; + grub_dl_unload (mod); +diff --git a/include/grub/dl.h b/include/grub/dl.h +index f36ed5cb17..45ac8e339f 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #endif + + /* +@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod) + return mod->persistent; + } + ++static inline const char * ++grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s) ++{ ++ Elf_Shdr *str_s; ++ const char *str; ++ ++ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + str_s->sh_offset; ++ ++ return str + s->sh_name; ++} ++ ++static inline long ++grub_dl_find_section_index (Elf_Ehdr *e, const char *name) ++{ ++ Elf_Shdr *s; ++ const char *str; ++ unsigned i; ++ ++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + s->sh_offset; ++ ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (grub_strcmp (str + s->sh_name, name) == 0) ++ return (long)i; ++ return -1; ++} ++ ++/* Return the segment for a section of index N */ ++static inline grub_dl_segment_t ++grub_dl_find_segment (grub_dl_t mod, unsigned n) ++{ ++ grub_dl_segment_t seg; ++ ++ for (seg = mod->segment; seg; seg = seg->next) ++ if (seg->section == n) ++ return seg; ++ ++ return NULL; ++} ++ + #endif + + void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); diff --git a/SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch b/SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch new file mode 100644 index 0000000..514df1f --- /dev/null +++ b/SOURCES/0257-nx-set-attrs-in-our-kernel-loaders.patch @@ -0,0 +1,565 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:57:07 -0400 +Subject: [PATCH] nx: set attrs in our kernel loaders + +For NX, our kernel loaders need to set write and execute page +permissions on allocated pages and the stack. + +This patch adds those calls. + +Signed-off-by: Peter Jones +[rharwood: fix stack_attrs undefined, fix aarch64 callsites] +Signed-off-by: Robbie Harwood +--- + grub-core/kern/efi/mm.c | 77 +++++++++++++++++ + grub-core/loader/arm64/linux.c | 16 +++- + grub-core/loader/arm64/xen_boot.c | 4 +- + grub-core/loader/efi/chainloader.c | 11 +++ + grub-core/loader/efi/linux.c | 164 ++++++++++++++++++++++++++++++++++++- + grub-core/loader/i386/efi/linux.c | 26 +++++- + grub-core/loader/i386/linux.c | 5 ++ + include/grub/efi/efi.h | 6 +- + include/grub/efi/linux.h | 16 +++- + include/grub/efi/pe32.h | 2 + + 10 files changed, 312 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 2c33758ed7..e460b072e6 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -610,6 +610,81 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + #endif + ++grub_addr_t grub_stack_addr = (grub_addr_t)-1ll; ++grub_size_t grub_stack_size = 0; ++ ++static void ++grub_nx_init (void) ++{ ++ grub_uint64_t attrs, stack_attrs; ++ grub_err_t err; ++ grub_addr_t stack_current, stack_end; ++ const grub_uint64_t page_size = 4096; ++ const grub_uint64_t page_mask = ~(page_size - 1); ++ ++ /* ++ * These are to confirm that the flags are working as expected when ++ * debugging. ++ */ ++ attrs = 0; ++ stack_current = (grub_addr_t)grub_nx_init & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n", ++ grub_dl_load_core, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ ++ stack_current = (grub_addr_t)&stack_current & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ { ++ attrs = stack_attrs; ++ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n", ++ &attrs, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ } ++ for (stack_end = stack_current + page_size ; ++ !(attrs & GRUB_MEM_ATTR_R); ++ stack_end += page_size) ++ { ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ break; ++ } ++ } ++ if (stack_end > stack_current) ++ { ++ grub_stack_addr = stack_current; ++ grub_stack_size = stack_end - stack_current; ++ grub_dprintf ("nx", ++ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1); ++ } ++} ++ + void + grub_efi_mm_init (void) + { +@@ -623,6 +698,8 @@ grub_efi_mm_init (void) + grub_efi_uint64_t required_pages; + int mm_status; + ++ grub_nx_init (); ++ + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index cc67f43906..de85583487 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -172,7 +172,8 @@ free_params (void) + } + + grub_err_t +-grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) ++grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, ++ int nx_supported) + { + grub_err_t retval; + +@@ -182,7 +183,8 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) + + grub_dprintf ("linux", "linux command line: '%s'\n", args); + +- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr); ++ retval = grub_efi_linux_boot (addr, size, handover_offset, ++ (void *)addr, nx_supported); + + /* Never reached... */ + free_params(); +@@ -192,7 +194,10 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, char *args) + static grub_err_t + grub_linux_boot (void) + { +- return (grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args)); ++ return grub_arch_efi_linux_boot_image((grub_addr_t)kernel_addr, ++ (grub_size_t)kernel_size, ++ linux_args, ++ 0); + } + + static grub_err_t +@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_off_t filelen; + grub_uint32_t align; + void *kernel = NULL; ++ int nx_supported = 1; + + grub_dl_ref (my_mod); + +@@ -376,6 +382,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); + grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); + ++ err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ + grub_loader_unset(); + + kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index d9b7a9ba40..6e7e920416 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -266,7 +266,9 @@ xen_boot (void) + return err; + + return grub_arch_efi_linux_boot_image (xen_hypervisor->start, +- xen_hypervisor->cmdline); ++ xen_hypervisor->size, ++ xen_hypervisor->cmdline, ++ 0); + } + + static void +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index fb874f1855..dd31ac9bb3 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -1070,6 +1070,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ /* ++ * The OS kernel is going to set its own permissions when it takes over ++ * paging a few million instructions from now, and load_image() will set up ++ * anything that's needed based on the section headers, so there's no point ++ * in doing anything but clearing the protection bits here. ++ */ ++ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n", ++ (void *)(grub_addr_t)address, fsize, 0llu); ++ grub_update_mem_attrs (address, fsize, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0); ++ + #if defined (__i386__) || defined (__x86_64__) + if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 9265cf4200..277f352e0c 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -26,16 +26,127 @@ + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" ++#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" ++ ++grub_err_t ++grub_efi_check_nx_image_support (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported) ++{ ++ struct grub_dos_header *doshdr; ++ grub_size_t sz = sizeof (*doshdr); ++ ++ struct grub_pe32_header_32 *pe32; ++ struct grub_pe32_header_64 *pe64; ++ ++ int image_is_compatible = 0; ++ int is_64_bit; ++ ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ doshdr = (void *)kernel_addr; ++ ++ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid")); ++ ++ sz = doshdr->lfanew + sizeof (*pe32); ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew); ++ pe64 = (struct grub_pe32_header_64 *)pe32; ++ ++ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ switch (pe32->coff_header.machine) ++ { ++ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED: ++ case GRUB_PE32_MACHINE_I386: ++ case GRUB_PE32_MACHINE_RISCV32: ++ is_64_bit = 0; ++ break; ++ case GRUB_PE32_MACHINE_ARM64: ++ case GRUB_PE32_MACHINE_IA64: ++ case GRUB_PE32_MACHINE_RISCV64: ++ case GRUB_PE32_MACHINE_X86_64: ++ is_64_bit = 1; ++ break; ++ default: ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"), ++ pe32->coff_header.machine); ++ } ++ ++ if (is_64_bit) ++ { ++ sz = doshdr->lfanew + sizeof (*pe64); ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ else ++ { ++ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ ++ *nx_supported = image_is_compatible; ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_efi_check_nx_required (int *nx_required) ++{ ++ grub_efi_status_t status; ++ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID; ++ grub_size_t mok_policy_sz = 0; ++ char *mok_policy = NULL; ++ grub_uint32_t mok_policy_attrs = 0; ++ ++ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid, ++ &mok_policy_sz, ++ (void **)&mok_policy, ++ &mok_policy_attrs); ++ if (status == GRUB_EFI_NOT_FOUND || ++ mok_policy_sz == 0 || ++ mok_policy == NULL) ++ { ++ *nx_required = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ *nx_required = 0; ++ if (mok_policy_sz < 1 || ++ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) || ++ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED)) ++ *nx_required = 1; ++ ++ return GRUB_ERR_NONE; ++} + + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, +- void *kernel_params) ++grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, ++ grub_off_t handover_offset, void *kernel_params, ++ int nx_supported) + { + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; ++ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ grub_uint64_t stack_clear_attrs = 0; ++ grub_uint64_t kernel_set_attrs = stack_set_attrs; ++ grub_uint64_t kernel_clear_attrs = stack_clear_attrs; ++ grub_uint64_t attrs; ++ int nx_required = 0; + + #ifdef __x86_64__ + offset = 512; +@@ -48,12 +159,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + */ + loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (loaded_image) +- loaded_image->image_base = kernel_addr; ++ loaded_image->image_base = (void *)kernel_addr; + else + grub_dprintf ("linux", "Loaded Image base address could not be set\n"); + + grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); ++ (void *)kernel_addr, (void *)handover_offset, kernel_params); ++ ++ ++ if (nx_required && !nx_supported) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); ++ ++ if (nx_supported) ++ { ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ stack_set_attrs &= ~GRUB_MEM_ATTR_X; ++ stack_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", ++ kernel_addr, kernel_addr + kernel_size - 1, ++ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); ++ grub_update_mem_attrs (kernel_addr, kernel_size, ++ kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (kernel_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ (grub_addr_t)kernel_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ if (grub_stack_addr != (grub_addr_t)-1ll) ++ { ++ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, ++ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, ++ stack_set_attrs, stack_clear_attrs); ++ ++ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ grub_stack_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++#if defined(__i386__) || defined(__x86_64__) ++ asm volatile ("cli"); ++#endif ++ + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 92b2fb5091..91ae274299 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -44,7 +44,7 @@ struct grub_linuxefi_context { + grub_uint32_t handover_offset; + struct linux_kernel_params *params; + char *cmdline; +- ++ int nx_supported; + void *initrd_mem; + }; + +@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size, + pages = BYTES_TO_PAGES(size); + grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", + (unsigned long)pages, (void *)(unsigned long)max); ++ size = pages * GRUB_EFI_PAGE_SIZE; + + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, + max_addresses[i].alloc_type, + memtype); + if (addr) +- grub_dprintf ("linux", "Allocated at %p\n", addr); ++ { ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ grub_update_mem_attrs ((grub_addr_t)addr, size, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, ++ GRUB_MEM_ATTR_X); ++ } + } + + while (grub_error_pop ()) +@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data) + + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)context->kernel_mem, ++ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, ++ context->kernel_size, + context->handover_offset, +- context->params); ++ context->params, ++ context->nx_supported); + } + + static grub_err_t +@@ -304,7 +312,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_uint32_t handover_offset; + struct linux_kernel_params *params = 0; + char *cmdline = 0; ++ int nx_supported = 1; + struct grub_linuxefi_context *context = 0; ++ grub_err_t err; + + grub_dl_ref (my_mod); + +@@ -334,6 +344,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen, ++ &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ grub_dprintf ("linux", "nx is%s supported by this kernel\n", ++ nx_supported ? "" : " not"); ++ + lh = (struct linux_i386_kernel_header *)kernel; + grub_dprintf ("linux", "original lh is at %p\n", kernel); + +@@ -498,6 +515,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + context->handover_offset = handover_offset; + context->params = params; + context->cmdline = cmdline; ++ context->nx_supported = nx_supported; + + grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 4aeb0e4b9a..3c1ff64763 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -805,6 +805,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_offset += len; + } + ++ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n", ++ &linux_params, sizeof (lh) + len); ++ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X); ++ + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; + linux_params.kernel_alignment = (1 << align); + linux_params.ps_mouse = linux_params.padding11 = 0; +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 34825c4adc..449e55269f 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -140,12 +140,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + char **device, + char **path); + ++extern grub_addr_t EXPORT_VAR(grub_stack_addr); ++extern grub_size_t EXPORT_VAR(grub_stack_size); ++ + #if defined(__arm__) || defined(__aarch64__) || defined(__riscv) + void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); + grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); + #include + grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header *lh); +-grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, char *args); ++grub_err_t grub_arch_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, ++ char *args, int nx_enabled); + #endif + + grub_addr_t grub_efi_section_addr (const char *section); +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index 887b02fd9f..b82f71006a 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -22,8 +22,20 @@ + #include + #include + ++#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 ++ + grub_err_t +-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, +- void *kernel_param); ++EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, ++ grub_size_t kernel_size, ++ grub_off_t handover_offset, ++ void *kernel_param, int nx_enabled); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); + + #endif /* ! GRUB_EFI_LINUX_HEADER */ +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index 2a5e1ee003..a5e623eb04 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -181,6 +181,8 @@ struct grub_pe32_optional_header + struct grub_pe32_data_directory reserved_entry; + }; + ++#define GRUB_PE32_NX_COMPAT 0x0100 ++ + struct grub_pe64_optional_header + { + grub_uint16_t magic; diff --git a/SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch new file mode 100644 index 0000000..7da75a8 --- /dev/null +++ b/SOURCES/0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:57:20 -0400 +Subject: [PATCH] nx: set the nx compatible flag in EFI grub images + +For NX, we need the grub binary to announce that it is compatible with +the NX feature. This implies that when loading the executable grub +image, several attributes are true: + +- the binary doesn't need an executable stack +- the binary doesn't need sections to be both executable and writable +- the binary knows how to use the EFI Memory Attributes protocol on code + it is loading. + +This patch adds a definition for the PE DLL Characteristics flag +GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag. + +Signed-off-by: Peter Jones +--- + util/mkimage.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 8319e8dfbd..c3d33aaac8 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1418,6 +1418,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + section = (struct grub_pe32_section_table *)(o64 + 1); + } + ++ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT); + PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); + PE_OHDR (o32, o64, image_base) = 0; diff --git a/SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch b/SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch new file mode 100644 index 0000000..4e9d7cc --- /dev/null +++ b/SOURCES/0259-grub-probe-document-the-behavior-of-multiple-v.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Jul 2022 15:49:25 -0400 +Subject: [PATCH] grub-probe: document the behavior of multiple -v + +Signed-off-by: Robbie Harwood +(cherry picked from commit 51a55233eed08f7f12276afd6b3724b807a0b680) +--- + util/grub-probe.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/util/grub-probe.c b/util/grub-probe.c +index c6fac732b4..ba867319a7 100644 +--- a/util/grub-probe.c ++++ b/util/grub-probe.c +@@ -732,7 +732,8 @@ static struct argp_option options[] = { + {"device-map", 'm', N_("FILE"), 0, + N_("use FILE as the device map [default=%s]"), 0}, + {"target", 't', N_("TARGET"), 0, 0, 0}, +- {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, ++ {"verbose", 'v', 0, 0, ++ N_("print verbose messages (pass twice to enable debug printing)."), 0}, + {0, '0', 0, 0, N_("separate items in output using ASCII NUL characters"), 0}, + { 0, 0, 0, 0, 0, 0 } + }; diff --git a/SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch b/SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch new file mode 100644 index 0000000..1455ae4 --- /dev/null +++ b/SOURCES/0260-grub_fs_probe-dprint-errors-from-filesystems.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Jul 2022 15:39:41 -0400 +Subject: [PATCH] grub_fs_probe(): dprint errors from filesystems + +When filesystem detection fails, all that's currently debug-logged is a +series of messages like: + + grub-core/kern/fs.c:56:fs: Detecting ntfs... + grub-core/kern/fs.c:76:fs: ntfs detection failed. + +repeated for each filesystem. Any messages provided to grub_error() by +the filesystem are lost, and one has to break out gdb to figure out what +went wrong. + +With this change, one instead sees: + + grub-core/kern/fs.c:56:fs: Detecting fat... + grub-core/osdep/hostdisk.c:357:hostdisk: reusing open device + `/path/to/device' + grub-core/kern/fs.c:77:fs: error: invalid modification timestamp for /. + grub-core/kern/fs.c:79:fs: fat detection failed. + +in the debug prints. + +Signed-off-by: Robbie Harwood +(cherry picked from commit 838c79d658797d0662ee7f9e033e38ee88059e02) +--- + grub-core/kern/fs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/kern/fs.c b/grub-core/kern/fs.c +index c698295bcb..b58e2ae1d2 100644 +--- a/grub-core/kern/fs.c ++++ b/grub-core/kern/fs.c +@@ -74,6 +74,7 @@ grub_fs_probe (grub_device_t device) + if (grub_errno == GRUB_ERR_NONE) + return p; + ++ grub_dprintf ("fs", _("error: %s.\n"), grub_errmsg); + grub_error_push (); + grub_dprintf ("fs", "%s detection failed.\n", p->name); + grub_error_pop (); diff --git a/SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch b/SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch new file mode 100644 index 0000000..f014f6c --- /dev/null +++ b/SOURCES/0261-fs-fat-don-t-error-when-mtime-is-0.patch @@ -0,0 +1,64 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Fri, 15 Jul 2022 15:42:41 -0400 +Subject: [PATCH] fs/fat: don't error when mtime is 0 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In the wild, we occasionally see valid ESPs where some file modification times +are 0. For instance: + + ├── [Dec 31 1979] EFI + │ ├── [Dec 31 1979] BOOT + │ │ ├── [Dec 31 1979] BOOTX64.EFI + │ │ └── [Dec 31 1979] fbx64.efi + │ └── [Jun 27 02:41] fedora + │ ├── [Dec 31 1979] BOOTX64.CSV + │ ├── [Dec 31 1979] fonts + │ ├── [Mar 14 03:35] fw + │ │ ├── [Mar 14 03:35] fwupd-359c1169-abd6-4a0d-8bce-e4d4713335c1.cap + │ │ ├── [Mar 14 03:34] fwupd-9d255c4b-2d88-4861-860d-7ee52ade9463.cap + │ │ └── [Mar 14 03:34] fwupd-b36438d8-9128-49d2-b280-487be02d948b.cap + │ ├── [Dec 31 1979] fwupdx64.efi + │ ├── [May 10 10:47] grub.cfg + │ ├── [Jun 3 12:38] grub.cfg.new.new + │ ├── [May 10 10:41] grub.cfg.old + │ ├── [Jun 27 02:41] grubenv + │ ├── [Dec 31 1979] grubx64.efi + │ ├── [Dec 31 1979] mmx64.efi + │ ├── [Dec 31 1979] shim.efi + │ ├── [Dec 31 1979] shimx64.efi + │ └── [Dec 31 1979] shimx64-fedora.efi + └── [Dec 31 1979] FSCK0000.REC + + 5 directories, 17 files + +This causes grub-probe failure, which in turn causes grub-mkconfig +failure. They are valid filesystems that appear intact, and the Linux +FAT stack is able to mount and manipulate them without complaint. + +The check for mtime of 0 has been present since +20def1a3c3952982395cd7c3ea7e78638527962b ("fat: support file +modification times"). + +Signed-off-by: Robbie Harwood +(cherry picked from commit 0615c4887352e32d7bb7198e9ad0d695f9dc2c31) +--- + grub-core/fs/fat.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c +index dd82e4ee35..ff6200c5be 100644 +--- a/grub-core/fs/fat.c ++++ b/grub-core/fs/fat.c +@@ -1027,9 +1027,6 @@ grub_fat_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, + grub_le_to_cpu16 (ctxt.dir.w_date), + &info.mtime); + #endif +- if (info.mtimeset == 0) +- grub_error (GRUB_ERR_OUT_OF_RANGE, +- "invalid modification timestamp for %s", path); + + if (hook (ctxt.filename, &info, hook_data)) + break; diff --git a/SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch b/SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch new file mode 100644 index 0000000..78bc095 --- /dev/null +++ b/SOURCES/0262-Make-debug-file-show-which-file-filters-get-run.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 29 Jul 2022 15:56:00 -0400 +Subject: [PATCH] Make debug=file show which file filters get run. + +If one of the file filters breaks things, it's hard to figure out where +it has happened. + +This makes grub log which filter is being run, which makes it easier to +figure out where you are in the sequence of events. + +Signed-off-by: Peter Jones +--- + grub-core/kern/file.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index db938e099d..868ce3b63e 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -30,6 +30,14 @@ void (*EXPORT_VAR (grub_grubnet_fini)) (void); + + grub_file_filter_t grub_file_filters[GRUB_FILE_FILTER_MAX]; + ++static const char *filter_names[] = { ++ [GRUB_FILE_FILTER_VERIFY] = "GRUB_FILE_FILTER_VERIFY", ++ [GRUB_FILE_FILTER_GZIO] = "GRUB_FILE_FILTER_GZIO", ++ [GRUB_FILE_FILTER_XZIO] = "GRUB_FILE_FILTER_XZIO", ++ [GRUB_FILE_FILTER_LZOPIO] = "GRUB_FILE_FILTER_LZOPIO", ++ [GRUB_FILE_FILTER_MAX] = "GRUB_FILE_FILTER_MAX" ++}; ++ + /* Get the device part of the filename NAME. It is enclosed by parentheses. */ + char * + grub_file_get_device_name (const char *name) +@@ -124,6 +132,9 @@ grub_file_open (const char *name, enum grub_file_type type) + if (grub_file_filters[filter]) + { + last_file = file; ++ if (filter < GRUB_FILE_FILTER_MAX) ++ grub_dprintf ("file", "Running %s file filter\n", ++ filter_names[filter]); + file = grub_file_filters[filter] (file, type); + if (file && file != last_file) + { diff --git a/SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch b/SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch new file mode 100644 index 0000000..206e3a6 --- /dev/null +++ b/SOURCES/0263-efi-use-enumerated-array-positions-for-our-allocatio.patch @@ -0,0 +1,81 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 14:06:30 -0400 +Subject: [PATCH] efi: use enumerated array positions for our allocation + choices + +In our kernel allocator on EFI systems, we currently have a growing +amount of code that references the various allocation policies by +position in the array, and of course maintenance of this code scales +very poorly. + +This patch changes them to be enumerated, so they're easier to refer to +farther along in the code without confusion. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 31 ++++++++++++++++++++----------- + 1 file changed, 20 insertions(+), 11 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 91ae274299..8daa070132 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -60,17 +60,26 @@ struct allocation_choice { + grub_efi_allocate_type_t alloc_type; + }; + +-static struct allocation_choice max_addresses[4] = ++enum { ++ KERNEL_PREF_ADDRESS, ++ KERNEL_4G_LIMIT, ++ KERNEL_NO_LIMIT, ++}; ++ ++static struct allocation_choice max_addresses[] = + { + /* the kernel overrides this one with pref_address and + * GRUB_EFI_ALLOCATE_ADDRESS */ +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ [KERNEL_PREF_ADDRESS] = ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* If the flag in params is set, this one gets changed to be above 4GB. */ ++ [KERNEL_4G_LIMIT] = ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + /* this one is always below 4GB, which we still *prefer* even if the flag + * is set. */ +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, +- /* If the flag in params is set, this one gets changed to be above 4GB. */ +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, +- { 0, 0 } ++ [KERNEL_NO_LIMIT] = ++ { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { NO_MEM, 0, 0 } + }; + static struct allocation_choice saved_addresses[4]; + +@@ -405,7 +414,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) + { + grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); +- max_addresses[2].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; + } + else + { +@@ -478,11 +487,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "lh->pref_address: %p\n", (void *)(grub_addr_t)lh->pref_address); + if (lh->pref_address < (grub_uint64_t)GRUB_EFI_MAX_ALLOCATION_ADDRESS) + { +- max_addresses[0].addr = lh->pref_address; +- max_addresses[0].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; ++ max_addresses[KERNEL_PREF_ADDRESS].addr = lh->pref_address; ++ max_addresses[KERNEL_PREF_ADDRESS].alloc_type = GRUB_EFI_ALLOCATE_ADDRESS; + } +- max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; +- max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; + kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, + N_("can't allocate kernel")); diff --git a/SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch b/SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch new file mode 100644 index 0000000..d25cf30 --- /dev/null +++ b/SOURCES/0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 14:24:39 -0400 +Subject: [PATCH] efi: split allocation policy for kernel vs initrd memories. + +Currently in our kernel allocator, we use the same set of choices for +all of our various kernel and initramfs allocations, though they do not +have exactly the same constraints. + +This patch adds the concept of an allocation purpose, which currently +can be KERNEL_MEM or INITRD_MEM, and updates kernel_alloc() calls +appropriately, but does not change any current policy decision. It +also adds a few debug prints. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 35 +++++++++++++++++++++++++++-------- + 1 file changed, 27 insertions(+), 8 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 8daa070132..e6b8998e5e 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -55,7 +55,14 @@ struct grub_linuxefi_context { + + #define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) + ++typedef enum { ++ NO_MEM, ++ KERNEL_MEM, ++ INITRD_MEM, ++} kernel_alloc_purpose_t; ++ + struct allocation_choice { ++ kernel_alloc_purpose_t purpose; + grub_efi_physical_address_t addr; + grub_efi_allocate_type_t alloc_type; + }; +@@ -64,6 +71,7 @@ enum { + KERNEL_PREF_ADDRESS, + KERNEL_4G_LIMIT, + KERNEL_NO_LIMIT, ++ INITRD_MAX_ADDRESS, + }; + + static struct allocation_choice max_addresses[] = +@@ -71,14 +79,17 @@ static struct allocation_choice max_addresses[] = + /* the kernel overrides this one with pref_address and + * GRUB_EFI_ALLOCATE_ADDRESS */ + [KERNEL_PREF_ADDRESS] = +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + /* If the flag in params is set, this one gets changed to be above 4GB. */ + [KERNEL_4G_LIMIT] = +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + /* this one is always below 4GB, which we still *prefer* even if the flag + * is set. */ + [KERNEL_NO_LIMIT] = +- { GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ { KERNEL_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, ++ /* this is for the initrd */ ++ [INITRD_MAX_ADDRESS] = ++ { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { NO_MEM, 0, 0 } + }; + static struct allocation_choice saved_addresses[4]; +@@ -95,7 +106,8 @@ kernel_free(void *addr, grub_efi_uintn_t size) + } + + static void * +-kernel_alloc(grub_efi_uintn_t size, ++kernel_alloc(kernel_alloc_purpose_t purpose, ++ grub_efi_uintn_t size, + grub_efi_memory_type_t memtype, + const char * const errmsg) + { +@@ -108,6 +120,9 @@ kernel_alloc(grub_efi_uintn_t size, + grub_uint64_t max = max_addresses[i].addr; + grub_efi_uintn_t pages; + ++ if (purpose != max_addresses[i].purpose) ++ continue; ++ + /* + * When we're *not* loading the kernel, or >4GB allocations aren't + * supported, these entries are basically all the same, so don't re-try +@@ -261,7 +276,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ grub_dprintf ("linux", "Trying to allocate initrd mem\n"); ++ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA, + N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; +@@ -422,7 +438,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, ++ params = kernel_alloc (KERNEL_MEM, sizeof(*params), ++ GRUB_EFI_RUNTIME_SERVICES_DATA, + "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -445,7 +462,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- cmdline = kernel_alloc (lh->cmdline_size + 1, ++ cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, + GRUB_EFI_RUNTIME_SERVICES_DATA, + N_("can't allocate cmdline")); + if (!cmdline) +@@ -493,7 +510,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + max_addresses[KERNEL_4G_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; +- kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, ++ grub_dprintf ("linux", "Trying to allocate kernel mem\n"); ++ kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, ++ GRUB_EFI_RUNTIME_SERVICES_CODE, + N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) diff --git a/SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch b/SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch new file mode 100644 index 0000000..47e31e2 --- /dev/null +++ b/SOURCES/0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 14:07:50 -0400 +Subject: [PATCH] efi: allocate the initrd within the bounds expressed by the + kernel + +Currently on x86, only linux kernels built with CONFIG_RELOCATABLE for +x86_64 can be loaded above 4G, but the maximum address for the initramfs +is specified via a HdrS field. This allows us to utilize that value, +and unless loading the kernel above 4G, uses the value present there. +If loading kernel above 4G is allowed, we assume loading the initramfs +above 4G also works; in practice this has been true in the kernel code +for quite some time. + +Resolves: rhbz#2112134 + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index e6b8998e5e..d003b474ee 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -190,6 +190,8 @@ grub_linuxefi_unload (void *data) + cmd_initrdefi->data = 0; + grub_free (context); + ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ + return GRUB_ERR_NONE; + } + +@@ -426,11 +428,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + ++ max_addresses[INITRD_MAX_ADDRESS].addr = lh->initrd_addr_max; + #if defined(__x86_64__) + if (lh->xloadflags & LINUX_XLF_CAN_BE_LOADED_ABOVE_4G) + { + grub_dprintf ("linux", "Loading kernel above 4GB is supported; enabling.\n"); + max_addresses[KERNEL_NO_LIMIT].addr = GRUB_EFI_MAX_USABLE_ADDRESS; ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_USABLE_ADDRESS; + } + else + { +@@ -560,6 +564,8 @@ fail: + + grub_dl_unref (my_mod); + ++ max_addresses[INITRD_MAX_ADDRESS].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; ++ + if (lh) + kernel_free (cmdline, lh->cmdline_size + 1); + diff --git a/SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch b/SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch new file mode 100644 index 0000000..8451dbf --- /dev/null +++ b/SOURCES/0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 1 Aug 2022 13:04:43 -0400 +Subject: [PATCH] efi: use EFI_LOADER_(CODE|DATA) for kernel and initrd + allocations + +At some point due to an erroneous kernel warning, we switched kernel and +initramfs to being loaded in EFI_RUNTIME_SERVICES_CODE and +EFI_RUNTIME_SERVICES_DATA memory pools. This doesn't appear to be +correct according to the spec, and that kernel warning has gone away. + +This patch puts them back in EFI_LOADER_CODE and EFI_LOADER_DATA +allocations, respectively. + +Resolves: rhbz#2108456 + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index d003b474ee..ac5ef50bdb 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -279,7 +279,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + + grub_dprintf ("linux", "Trying to allocate initrd mem\n"); +- initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ initrd_mem = kernel_alloc(INITRD_MEM, size, GRUB_EFI_LOADER_DATA, + N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; +@@ -443,7 +443,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + #endif + + params = kernel_alloc (KERNEL_MEM, sizeof(*params), +- GRUB_EFI_RUNTIME_SERVICES_DATA, ++ GRUB_EFI_LOADER_DATA, + "cannot allocate kernel parameters"); + if (!params) + goto fail; +@@ -467,7 +467,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "setting up cmdline\n"); + cmdline = kernel_alloc (KERNEL_MEM, lh->cmdline_size + 1, +- GRUB_EFI_RUNTIME_SERVICES_DATA, ++ GRUB_EFI_LOADER_DATA, + N_("can't allocate cmdline")); + if (!cmdline) + goto fail; +@@ -516,7 +516,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_size = lh->init_size; + grub_dprintf ("linux", "Trying to allocate kernel mem\n"); + kernel_mem = kernel_alloc (KERNEL_MEM, kernel_size, +- GRUB_EFI_RUNTIME_SERVICES_CODE, ++ GRUB_EFI_LOADER_CODE, + N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) diff --git a/SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch b/SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch new file mode 100644 index 0000000..50ba0fb --- /dev/null +++ b/SOURCES/0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 2 Aug 2022 15:56:28 -0400 +Subject: [PATCH] BLS: create /etc/kernel/cmdline during mkconfig + +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_linux.in | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 865af3d6c4..9ebff661a9 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,6 +161,12 @@ update_bls_cmdline() + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + ++ if [[ ! -f /etc/kernel/cmdline ]]; then ++ # anaconda has the correct information to do this during install; ++ # afterward, grubby will take care of syncing on updates. ++ echo "$cmdline rhgb quiet" > /etc/kernel/cmdline ++ fi ++ + for bls in "${files[@]}"; do + local options="${cmdline}" + if [ -z "${bls##*debug*}" ]; then diff --git a/SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch b/SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch new file mode 100644 index 0000000..67073ec --- /dev/null +++ b/SOURCES/0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 17 Aug 2022 10:26:07 -0400 +Subject: [PATCH] squish: don't dup rhgb quiet, check mtimes + +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_linux.in | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 9ebff661a9..41c6cb1dc2 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,10 +161,16 @@ update_bls_cmdline() + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + +- if [[ ! -f /etc/kernel/cmdline ]]; then +- # anaconda has the correct information to do this during install; +- # afterward, grubby will take care of syncing on updates. +- echo "$cmdline rhgb quiet" > /etc/kernel/cmdline ++ if [[ ! -f /etc/kernel/cmdline ]] || ++ [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then ++ # anaconda has the correct information to create this during install; ++ # afterward, grubby will take care of syncing on updates. If the user ++ # has modified /etc/default/grub, try to cope. ++ if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then ++ # ensure these only show up once ++ cmdline="$cmdline rhgb quiet" ++ fi ++ echo "$cmdline" > /etc/kernel/cmdline + fi + + for bls in "${files[@]}"; do diff --git a/SOURCES/0269-squish-give-up-on-rhgb-quiet.patch b/SOURCES/0269-squish-give-up-on-rhgb-quiet.patch new file mode 100644 index 0000000..5858c91 --- /dev/null +++ b/SOURCES/0269-squish-give-up-on-rhgb-quiet.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 17 Aug 2022 11:30:30 -0400 +Subject: [PATCH] squish: give up on rhgb quiet + +Signed-off-by: Robbie Harwood +--- + util/grub.d/10_linux.in | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 41c6cb1dc2..5d1fa072f2 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -166,10 +166,6 @@ update_bls_cmdline() + # anaconda has the correct information to create this during install; + # afterward, grubby will take care of syncing on updates. If the user + # has modified /etc/default/grub, try to cope. +- if [[ ! "$cmdline" =~ "rhgb quiet" ]]; then +- # ensure these only show up once +- cmdline="$cmdline rhgb quiet" +- fi + echo "$cmdline" > /etc/kernel/cmdline + fi + diff --git a/SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch b/SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch new file mode 100644 index 0000000..d5ac923 --- /dev/null +++ b/SOURCES/0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jonathan Lebon +Date: Wed, 17 Aug 2022 10:26:03 -0400 +Subject: [PATCH] squish: BLS: only write /etc/kernel/cmdline if writable + +On OSTree systems, `grub2-mkconfig` is run with `/etc` mounted read-only +because as part of the promise of transactional updates, we want to make +sure that we're not modifying the current deployment's state (`/etc` or +`/var`). + +This conflicts with 0837dcdf1 ("BLS: create /etc/kernel/cmdline during +mkconfig") which wants to write to `/etc/kernel/cmdline`. I'm not +exactly sure on the background there, but based on the comment I think +the intent is to fulfill grubby's expectation that the file exists. + +However, in systems like Silverblue, kernel arguments are managed by the +rpm-ostree stack and grubby is not shipped at all. + +Adjust the script slightly so that we only write `/etc/kernel/cmdline` +if the parent directory is writable. + +In the future, we're hoping to simplify things further on rpm-ostree +systems by not running `grub2-mkconfig` at all since libostree already +directly writes BLS entries. Doing that would also have avoided this, +but ratcheting it into existing systems needs more careful thought. + +Signed-off-by: Jonathan Lebon + +Fixes: https://github.com/fedora-silverblue/issue-tracker/issues/322 +--- + util/grub.d/10_linux.in | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 5d1fa072f2..4795a63b4c 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -161,12 +161,13 @@ update_bls_cmdline() + local cmdline="root=${LINUX_ROOT_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" + local -a files=($(get_sorted_bls)) + +- if [[ ! -f /etc/kernel/cmdline ]] || +- [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then +- # anaconda has the correct information to create this during install; +- # afterward, grubby will take care of syncing on updates. If the user +- # has modified /etc/default/grub, try to cope. +- echo "$cmdline" > /etc/kernel/cmdline ++ if [ -w /etc/kernel ] && ++ [[ ! -f /etc/kernel/cmdline || ++ /etc/kernel/cmdline -ot /etc/default/grub ]]; then ++ # anaconda has the correct information to create this during install; ++ # afterward, grubby will take care of syncing on updates. If the user ++ # has modified /etc/default/grub, try to cope. ++ echo "$cmdline" > /etc/kernel/cmdline + fi + + for bls in "${files[@]}"; do diff --git a/SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch b/SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch new file mode 100644 index 0000000..3fe8baf --- /dev/null +++ b/SOURCES/0271-blscfg-Don-t-root-device-in-emu-builds.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Thu, 25 Aug 2022 17:57:55 -0400 +Subject: [PATCH] blscfg: Don't root device in emu builds + +Otherwise, we end up looking for kernel/initrd in /boot/boot which +doesn't work at all. Non-emu builds need to be looking in +($root)/boot/, which is what this is for. + +Signed-off-by: Robbie Harwood +--- + grub-core/commands/blscfg.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +index e907a6a5d2..dbd0899acf 100644 +--- a/grub-core/commands/blscfg.c ++++ b/grub-core/commands/blscfg.c +@@ -41,7 +41,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + #define GRUB_BLS_CONFIG_PATH "/loader/entries/" + #ifdef GRUB_MACHINE_EMU +-#define GRUB_BOOT_DEVICE "/boot" ++#define GRUB_BOOT_DEVICE "" + #else + #define GRUB_BOOT_DEVICE "($root)" + #endif diff --git a/SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch b/SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch new file mode 100644 index 0000000..faaa071 --- /dev/null +++ b/SOURCES/0272-loader-arm64-linux-Remove-magic-number-header-field-.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ard Biesheuvel +Date: Thu, 11 Aug 2022 16:51:57 +0200 +Subject: [PATCH] loader/arm64/linux: Remove magic number header field check + +The "ARM\x64" magic number in the file header identifies an image as one +that implements the bare metal boot protocol, allowing the loader to +simply move the file to a suitably aligned address in memory, with +sufficient headroom for the trailing .bss segment (the required memory +size is described in the header as well). + +Note of this matters for GRUB, as it only supports EFI boot. EFI does +not care about this magic number, and nor should GRUB: this prevents us +from booting other PE linux images, such as the generic EFI zboot +decompressor, which is a pure PE/COFF image, and does not implement the +bare metal boot protocol. + +So drop the magic number check. + +Signed-off-by: Ard Biesheuvel +Reviewed-by: Daniel Kiper +Resolves: rhbz#2125069 +Signed-off-by: Jeremy Linton +(cherry-picked from commit 69edb31205602c29293a8c6e67363bba2a4a1e66) +Signed-off-by: Robbie Harwood +--- + grub-core/loader/arm64/linux.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index de85583487..489d0c7173 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -55,9 +55,6 @@ static grub_addr_t initrd_end; + grub_err_t + grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh) + { +- if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) +- return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); +- + if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); diff --git a/SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch b/SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch new file mode 100644 index 0000000..4f9a2b7 --- /dev/null +++ b/SOURCES/0273-Correct-BSS-zeroing-on-aarch64.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jeremy Linton +Date: Tue, 6 Sep 2022 15:33:03 -0500 +Subject: [PATCH] Correct BSS zeroing on aarch64 + +The aarch64 loader doesn't use efi bootservices, and +therefor it has a very minimal loader which makes a lot +of assumptions about the kernel layout. With the ZBOOT +changes, the layout has changed a bit and we not should +really be parsing the PE sections to determine how much +data to copy, otherwise the BSS won't be setup properly. + +This code still makes a lot of assumptions about the +the kernel layout, so its far from ideal, but it works. + +Resolves: rhbz#2125069 + +Signed-off-by: Jeremy Linton +--- + grub-core/loader/arm64/linux.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 489d0c7173..419f2201df 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -316,10 +316,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + static grub_err_t + parse_pe_header (void *kernel, grub_uint64_t *total_size, + grub_uint32_t *entry_offset, +- grub_uint32_t *alignment) ++ grub_uint32_t *alignment,grub_uint32_t *code_size) + { + struct linux_arch_kernel_header *lh = kernel; + struct grub_armxx_linux_pe_header *pe; ++ grub_uint16_t i; ++ struct grub_pe32_section_table *sections; + + pe = (void *)((unsigned long)kernel + lh->hdr_offset); + +@@ -329,6 +331,19 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size, + *total_size = pe->opt.image_size; + *entry_offset = pe->opt.entry_addr; + *alignment = pe->opt.section_alignment; ++ *code_size = pe->opt.section_alignment; ++ ++ sections = (struct grub_pe32_section_table *) ((char *)&pe->opt + ++ pe->coff.optional_header_size); ++ grub_dprintf ("linux", "num_sections : %d\n", pe->coff.num_sections ); ++ for (i = 0 ; i < pe->coff.num_sections; i++) ++ { ++ grub_dprintf ("linux", "raw_size : %lld\n", ++ (long long) sections[i].raw_data_size); ++ grub_dprintf ("linux", "virt_size : %lld\n", ++ (long long) sections[i].virtual_size); ++ *code_size += sections[i].raw_data_size; ++ } + + return GRUB_ERR_NONE; + } +@@ -341,6 +356,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_err_t err; + grub_off_t filelen; + grub_uint32_t align; ++ grub_uint32_t code_size; + void *kernel = NULL; + int nx_supported = 1; + +@@ -373,11 +389,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE) + goto fail; +- if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE) ++ if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE) + goto fail; + grub_dprintf ("linux", "kernel mem size : %lld\n", (long long) kernel_size); + grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset); + grub_dprintf ("linux", "kernel alignment : 0x%x\n", align); ++ grub_dprintf ("linux", "kernel size : 0x%x\n", code_size); + + err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported); + if (err != GRUB_ERR_NONE) +@@ -396,9 +413,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align); + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); +- grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size)); +- if (kernel_size > filelen) +- grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen); ++ grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size)); ++ if (kernel_size > code_size) ++ grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size); + grub_free(kernel); + kernel = NULL; + diff --git a/SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch b/SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch new file mode 100644 index 0000000..eff155d --- /dev/null +++ b/SOURCES/0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: dann frazier +Date: Thu, 25 Aug 2022 17:08:09 -0600 +Subject: [PATCH] linuxefi: Invalidate i-cache before starting the kernel + +We need to flush the memory range of the code we are about to execute +from the instruction cache before we can safely execute it. Not doing +so appears to be the source of rare synchronous exceptions a user +is seeing on a Cortex-A72-based platform while executing the Linux EFI +stub. Notably they seem to correlate with an instruction on a cache +line boundary. + +Signed-off-by: dann frazier +--- + grub-core/loader/efi/linux.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 277f352e0c..e413bdcc23 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -16,6 +16,7 @@ + * along with GRUB. If not, see . + */ + ++#include + #include + #include + #include +@@ -210,6 +211,9 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, + asm volatile ("cli"); + #endif + ++ /* Invalidate the instruction cache */ ++ grub_arch_sync_caches((void *)kernel_addr, kernel_size); ++ + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); + diff --git a/SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch b/SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch new file mode 100644 index 0000000..0079750 --- /dev/null +++ b/SOURCES/0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 11 Oct 2022 17:00:50 -0400 +Subject: [PATCH] x86-efi: Fix an incorrect array size in kernel allocation + +In 81a6ebf62bbe166ddc968463df2e8bd481bf697c ("efi: split allocation +policy for kernel vs initrd memories."), I introduced a split in the +kernel allocator to allow for different dynamic policies for the kernel +and the initrd allocations. + +Unfortunately, that change increased the size of the policy data used to +make decisions, but did not change the size of the temporary storage we +use to back it up and restore. This results in some of .data getting +clobbered at runtime, and hilarity ensues. + +This patch makes the size of the backup storage be based on the size of +the initial policy data. + +Signed-off-by: Peter Jones +--- + grub-core/loader/i386/efi/linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index ac5ef50bdb..9854b0defa 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -92,7 +92,7 @@ static struct allocation_choice max_addresses[] = + { INITRD_MEM, GRUB_EFI_MAX_ALLOCATION_ADDRESS, GRUB_EFI_ALLOCATE_MAX_ADDRESS }, + { NO_MEM, 0, 0 } + }; +-static struct allocation_choice saved_addresses[4]; ++static struct allocation_choice saved_addresses[sizeof(max_addresses) / sizeof(max_addresses[0])]; + + #define save_addresses() grub_memcpy(saved_addresses, max_addresses, sizeof(max_addresses)) + #define restore_addresses() grub_memcpy(max_addresses, saved_addresses, sizeof(max_addresses)) diff --git a/SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch b/SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch new file mode 100644 index 0000000..896e49b --- /dev/null +++ b/SOURCES/0276-commands-efi-tpm-Refine-the-status-of-log-event.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:10 +0800 +Subject: [PATCH] commands/efi/tpm: Refine the status of log event + +1. Use macro GRUB_ERR_NONE instead of hard code 0. +2. Keep lowercase of the first char for the status string of log event. + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +(cherry picked from commit 922898573e37135f5dedc16f3e15a1d1d4c53f8a) +--- + grub-core/commands/efi/tpm.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index a97d85368a..7acf510499 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -135,17 +135,17 @@ grub_efi_log_event_status (grub_efi_status_t status) + switch (status) + { + case GRUB_EFI_SUCCESS: +- return 0; ++ return GRUB_ERR_NONE; + case GRUB_EFI_DEVICE_ERROR: +- return grub_error (GRUB_ERR_IO, N_("Command failed")); ++ return grub_error (GRUB_ERR_IO, N_("command failed")); + case GRUB_EFI_INVALID_PARAMETER: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid parameter")); + case GRUB_EFI_BUFFER_TOO_SMALL: +- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Output buffer too small")); ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("output buffer too small")); + case GRUB_EFI_NOT_FOUND: + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("TPM unavailable")); + default: +- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("Unknown TPM error")); ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unknown TPM error")); + } + } + diff --git a/SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch b/SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch new file mode 100644 index 0000000..e04dcbc --- /dev/null +++ b/SOURCES/0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:11 +0800 +Subject: [PATCH] commands/efi/tpm: Use grub_strcpy() instead of grub_memcpy() + +The event description is a string, so using grub_strcpy() is cleaner than +using grub_memcpy(). + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +(cherry picked from commit ef8679b645a63eb9eb191bb9539d7d25a9d6ff3b) +--- + grub-core/commands/efi/tpm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index 7acf510499..bb59599721 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -175,7 +175,7 @@ grub_tpm1_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->PCRIndex = pcr; + event->EventType = EV_IPL; + event->EventSize = grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, event->EventSize); ++ grub_strcpy ((char *) event->Event, description); + + algorithm = TCG_ALG_SHA; + status = efi_call_7 (tpm->log_extend_event, tpm, (grub_addr_t) buf, (grub_uint64_t) size, +@@ -212,7 +212,7 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + event->Header.EventType = EV_IPL; + event->Size = + sizeof (*event) - sizeof (event->Event) + grub_strlen (description) + 1; +- grub_memcpy (event->Event, description, grub_strlen (description) + 1); ++ grub_strcpy ((char *) event->Event, description); + + status = efi_call_5 (tpm->hash_log_extend_event, tpm, 0, (grub_addr_t) buf, + (grub_uint64_t) size, event); diff --git a/SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch b/SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch new file mode 100644 index 0000000..610c81a --- /dev/null +++ b/SOURCES/0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lu Ken +Date: Wed, 13 Jul 2022 10:06:12 +0800 +Subject: [PATCH] efi/tpm: Add EFI_CC_MEASUREMENT_PROTOCOL support + +The EFI_CC_MEASUREMENT_PROTOCOL abstracts the measurement for virtual firmware +in confidential computing environment. It is similar to the EFI_TCG2_PROTOCOL. +It was proposed by Intel and ARM and approved by UEFI organization. + +It is defined in Intel GHCI specification: https://cdrdv2.intel.com/v1/dl/getContent/726790 . +The EDKII header file is available at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/CcMeasurement.h . + +Signed-off-by: Lu Ken +Reviewed-by: Daniel Kiper +(cherry picked from commit 4c76565b6cb885b7e144dc27f3612066844e2d19) +--- + grub-core/commands/efi/tpm.c | 48 ++++++++++++++ + include/grub/efi/cc.h | 151 +++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 199 insertions(+) + create mode 100644 include/grub/efi/cc.h + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index bb59599721..ae09c1bf8b 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -31,6 +32,7 @@ typedef TCG_PCR_EVENT grub_tpm_event_t; + + static grub_efi_guid_t tpm_guid = EFI_TPM_GUID; + static grub_efi_guid_t tpm2_guid = EFI_TPM2_GUID; ++static grub_efi_guid_t cc_measurement_guid = GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID; + + static grub_efi_handle_t *grub_tpm_handle; + static grub_uint8_t grub_tpm_version; +@@ -221,6 +223,50 @@ grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf, + return grub_efi_log_event_status (status); + } + ++static void ++grub_cc_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ grub_efi_cc_event_t *event; ++ grub_efi_status_t status; ++ grub_efi_cc_protocol_t *cc; ++ grub_efi_cc_mr_index_t mr; ++ ++ cc = grub_efi_locate_protocol (&cc_measurement_guid, NULL); ++ if (cc == NULL) ++ return; ++ ++ status = efi_call_3 (cc->map_pcr_to_mr_index, cc, pcr, &mr); ++ if (status != GRUB_EFI_SUCCESS) ++ { ++ grub_efi_log_event_status (status); ++ return; ++ } ++ ++ event = grub_zalloc (sizeof (grub_efi_cc_event_t) + ++ grub_strlen (description) + 1); ++ if (event == NULL) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate CC event buffer")); ++ return; ++ } ++ ++ event->Header.HeaderSize = sizeof (grub_efi_cc_event_header_t); ++ event->Header.HeaderVersion = GRUB_EFI_CC_EVENT_HEADER_VERSION; ++ event->Header.MrIndex = mr; ++ event->Header.EventType = EV_IPL; ++ event->Size = sizeof (*event) + grub_strlen (description) + 1; ++ grub_strcpy ((char *) event->Event, description); ++ ++ status = efi_call_5 (cc->hash_log_extend_event, cc, 0, ++ (grub_efi_physical_address_t)(grub_addr_t) buf, ++ (grub_efi_uint64_t) size, event); ++ grub_free (event); ++ ++ if (status != GRUB_EFI_SUCCESS) ++ grub_efi_log_event_status (status); ++} ++ + grub_err_t + grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) +@@ -228,6 +274,8 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + grub_efi_handle_t tpm_handle; + grub_efi_uint8_t protocol_version; + ++ grub_cc_log_event(buf, size, pcr, description); ++ + if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) + return 0; + +diff --git a/include/grub/efi/cc.h b/include/grub/efi/cc.h +new file mode 100644 +index 0000000000..8960306890 +--- /dev/null ++++ b/include/grub/efi/cc.h +@@ -0,0 +1,151 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_CC_H ++#define GRUB_EFI_CC_H 1 ++ ++#include ++#include ++#include ++ ++#define GRUB_EFI_CC_MEASUREMENT_PROTOCOL_GUID \ ++ { 0x96751a3d, 0x72f4, 0x41a6, \ ++ { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b } \ ++ }; ++ ++struct grub_efi_cc_version ++{ ++ grub_efi_uint8_t Major; ++ grub_efi_uint8_t Minor; ++}; ++typedef struct grub_efi_cc_version grub_efi_cc_version_t; ++ ++/* EFI_CC Type/SubType definition. */ ++#define GRUB_EFI_CC_TYPE_NONE 0 ++#define GRUB_EFI_CC_TYPE_SEV 1 ++#define GRUB_EFI_CC_TYPE_TDX 2 ++ ++struct grub_efi_cc_type ++{ ++ grub_efi_uint8_t Type; ++ grub_efi_uint8_t SubType; ++}; ++typedef struct grub_efi_cc_type grub_efi_cc_type_t; ++ ++typedef grub_efi_uint32_t grub_efi_cc_event_log_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_log_format_t; ++typedef grub_efi_uint32_t grub_efi_cc_event_algorithm_bitmap_t; ++typedef grub_efi_uint32_t grub_efi_cc_mr_index_t; ++ ++/* Intel TDX measure register index. */ ++#define GRUB_TDX_MR_INDEX_MRTD 0 ++#define GRUB_TDX_MR_INDEX_RTMR0 1 ++#define GRUB_TDX_MR_INDEX_RTMR1 2 ++#define GRUB_TDX_MR_INDEX_RTMR2 3 ++#define GRUB_TDX_MR_INDEX_RTMR3 4 ++ ++#define GRUB_EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 ++#define GRUB_EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define GRUB_EFI_CC_EVENT_HEADER_VERSION 1 ++ ++struct grub_efi_cc_event_header ++{ ++ /* Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)). */ ++ grub_efi_uint32_t HeaderSize; ++ ++ /* ++ * Header version. For this version of this specification, ++ * the value shall be 1. ++ */ ++ grub_efi_uint16_t HeaderVersion; ++ ++ /* Index of the MR that shall be extended. */ ++ grub_efi_cc_mr_index_t MrIndex; ++ ++ /* Type of the event that shall be extended (and optionally logged). */ ++ grub_efi_uint32_t EventType; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event_header grub_efi_cc_event_header_t; ++ ++struct grub_efi_cc_event ++{ ++ /* Total size of the event including the Size component, the header and the Event data. */ ++ grub_efi_uint32_t Size; ++ grub_efi_cc_event_header_t Header; ++ grub_efi_uint8_t Event[0]; ++} GRUB_PACKED; ++typedef struct grub_efi_cc_event grub_efi_cc_event_t; ++ ++struct grub_efi_cc_boot_service_capability ++{ ++ /* Allocated size of the structure. */ ++ grub_efi_uint8_t Size; ++ ++ /* ++ * Version of the grub_efi_cc_boot_service_capability_t structure itself. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t StructureVersion; ++ ++ /* ++ * Version of the EFI TD protocol. ++ * For this version of the protocol, the Major version shall be set to 1 ++ * and the Minor version shall be set to 1. ++ */ ++ grub_efi_cc_version_t ProtocolVersion; ++ ++ /* Supported hash algorithms. */ ++ grub_efi_cc_event_algorithm_bitmap_t HashAlgorithmBitmap; ++ ++ /* Bitmap of supported event log formats. */ ++ grub_efi_cc_event_log_bitmap_t SupportedEventLogs; ++ ++ /* Indicates the CC type. */ ++ grub_efi_cc_type_t CcType; ++}; ++typedef struct grub_efi_cc_boot_service_capability grub_efi_cc_boot_service_capability_t; ++ ++struct grub_efi_cc_protocol ++{ ++ grub_efi_status_t ++ (*get_capability) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_boot_service_capability_t *ProtocolCapability); ++ ++ grub_efi_status_t ++ (*get_event_log) (struct grub_efi_cc_protocol *this, ++ grub_efi_cc_event_log_format_t EventLogFormat, ++ grub_efi_physical_address_t *EventLogLocation, ++ grub_efi_physical_address_t *EventLogLastEntry, ++ grub_efi_boolean_t *EventLogTruncated); ++ ++ grub_efi_status_t ++ (*hash_log_extend_event) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint64_t Flags, ++ grub_efi_physical_address_t DataToHash, ++ grub_efi_uint64_t DataToHashLen, ++ grub_efi_cc_event_t *EfiCcEvent); ++ ++ grub_efi_status_t ++ (*map_pcr_to_mr_index) (struct grub_efi_cc_protocol *this, ++ grub_efi_uint32_t PcrIndex, ++ grub_efi_cc_mr_index_t *MrIndex); ++}; ++typedef struct grub_efi_cc_protocol grub_efi_cc_protocol_t; ++ ++#endif diff --git a/SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch b/SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch new file mode 100644 index 0000000..e0dd347 --- /dev/null +++ b/SOURCES/0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Wed, 3 Aug 2022 19:45:33 +0800 +Subject: [PATCH] font: Reject glyphs exceeds font->max_glyph_width or + font->max_glyph_height + +Check glyph's width and height against limits specified in font's +metadata. Reject the glyph (and font) if such limits are exceeded. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 5760fcfd466cc757540ea0d591bad6a08caeaa16) +--- + grub-core/font/font.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index d09bb38d89..2f09a4a55b 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -760,7 +760,9 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + || read_be_uint16 (font->file, &height) != 0 + || read_be_int16 (font->file, &xoff) != 0 + || read_be_int16 (font->file, &yoff) != 0 +- || read_be_int16 (font->file, &dwidth) != 0) ++ || read_be_int16 (font->file, &dwidth) != 0 ++ || width > font->max_char_width ++ || height > font->max_char_height) + { + remove_font (font); + return 0; diff --git a/SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch b/SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch new file mode 100644 index 0000000..b5f10f6 --- /dev/null +++ b/SOURCES/0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 00:51:20 +0800 +Subject: [PATCH] font: Fix size overflow in grub_font_get_glyph_internal() + +The length of memory allocation and file read may overflow. This patch +fixes the problem by using safemath macros. + +There is a lot of code repetition like "(x * y + 7) / 8". It is unsafe +if overflow happens. This patch introduces grub_video_bitmap_calc_1bpp_bufsz(). +It is safe replacement for such code. It has safemath-like prototype. + +This patch also introduces grub_cast(value, pointer), it casts value to +typeof(*pointer) then store the value to *pointer. It returns true when +overflow occurs or false if there is no overflow. The semantics of arguments +and return value are designed to be consistent with other safemath macros. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 941d10ad6f1dcbd12fb613002249e29ba035f985) +--- + grub-core/font/font.c | 17 +++++++++++++---- + include/grub/bitmap.h | 18 ++++++++++++++++++ + include/grub/safemath.h | 2 ++ + 3 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 2f09a4a55b..6a3fbebbd8 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -739,7 +739,8 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + grub_int16_t xoff; + grub_int16_t yoff; + grub_int16_t dwidth; +- int len; ++ grub_ssize_t len; ++ grub_size_t sz; + + if (index_entry->glyph) + /* Return cached glyph. */ +@@ -768,9 +769,17 @@ grub_font_get_glyph_internal (grub_font_t font, grub_uint32_t code) + return 0; + } + +- len = (width * height + 7) / 8; +- glyph = grub_malloc (sizeof (struct grub_font_glyph) + len); +- if (!glyph) ++ /* Calculate real struct size of current glyph. */ ++ if (grub_video_bitmap_calc_1bpp_bufsz (width, height, &len) || ++ grub_add (sizeof (struct grub_font_glyph), len, &sz)) ++ { ++ remove_font (font); ++ return 0; ++ } ++ ++ /* Allocate and initialize the glyph struct. */ ++ glyph = grub_malloc (sz); ++ if (glyph == NULL) + { + remove_font (font); + return 0; +diff --git a/include/grub/bitmap.h b/include/grub/bitmap.h +index 5728f8ca3a..0d9603f619 100644 +--- a/include/grub/bitmap.h ++++ b/include/grub/bitmap.h +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + struct grub_video_bitmap + { +@@ -79,6 +80,23 @@ grub_video_bitmap_get_height (struct grub_video_bitmap *bitmap) + return bitmap->mode_info.height; + } + ++/* ++ * Calculate and store the size of data buffer of 1bit bitmap in result. ++ * Equivalent to "*result = (width * height + 7) / 8" if no overflow occurs. ++ * Return true when overflow occurs or false if there is no overflow. ++ * This function is intentionally implemented as a macro instead of ++ * an inline function. Although a bit awkward, it preserves data types for ++ * safemath macros and reduces macro side effects as much as possible. ++ * ++ * XXX: Will report false overflow if width * height > UINT64_MAX. ++ */ ++#define grub_video_bitmap_calc_1bpp_bufsz(width, height, result) \ ++({ \ ++ grub_uint64_t _bitmap_pixels; \ ++ grub_mul ((width), (height), &_bitmap_pixels) ? 1 : \ ++ grub_cast (_bitmap_pixels / GRUB_CHAR_BIT + !!(_bitmap_pixels % GRUB_CHAR_BIT), (result)); \ ++}) ++ + void EXPORT_FUNC (grub_video_bitmap_get_mode_info) (struct grub_video_bitmap *bitmap, + struct grub_video_mode_info *mode_info); + +diff --git a/include/grub/safemath.h b/include/grub/safemath.h +index c17b89bba1..bb0f826de1 100644 +--- a/include/grub/safemath.h ++++ b/include/grub/safemath.h +@@ -30,6 +30,8 @@ + #define grub_sub(a, b, res) __builtin_sub_overflow(a, b, res) + #define grub_mul(a, b, res) __builtin_mul_overflow(a, b, res) + ++#define grub_cast(a, res) grub_add ((a), 0, (res)) ++ + #else + #error gcc 5.1 or newer or clang 3.8 or newer is required + #endif diff --git a/SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch b/SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch new file mode 100644 index 0000000..3c76eb4 --- /dev/null +++ b/SOURCES/0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch @@ -0,0 +1,79 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 01:58:27 +0800 +Subject: [PATCH] font: Fix several integer overflows in + grub_font_construct_glyph() + +This patch fixes several integer overflows in grub_font_construct_glyph(). +Glyphs of invalid size, zero or leading to an overflow, are rejected. +The inconsistency between "glyph" and "max_glyph_size" when grub_malloc() +returns NULL is fixed too. + +Fixes: CVE-2022-2601 + +Reported-by: Zhang Boyang +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit b1805f251b31a9d3cfae5c3572ddfa630145dbbf) +--- + grub-core/font/font.c | 29 +++++++++++++++++------------ + 1 file changed, 17 insertions(+), 12 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 6a3fbebbd8..1fa181d4ca 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1517,6 +1517,7 @@ grub_font_construct_glyph (grub_font_t hinted_font, + struct grub_video_signed_rect bounds; + static struct grub_font_glyph *glyph = 0; + static grub_size_t max_glyph_size = 0; ++ grub_size_t cur_glyph_size; + + ensure_comb_space (glyph_id); + +@@ -1533,29 +1534,33 @@ grub_font_construct_glyph (grub_font_t hinted_font, + if (!glyph_id->ncomb && !glyph_id->attributes) + return main_glyph; + +- if (max_glyph_size < sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) ++ if (grub_video_bitmap_calc_1bpp_bufsz (bounds.width, bounds.height, &cur_glyph_size) || ++ grub_add (sizeof (*glyph), cur_glyph_size, &cur_glyph_size)) ++ return main_glyph; ++ ++ if (max_glyph_size < cur_glyph_size) + { + grub_free (glyph); +- max_glyph_size = (sizeof (*glyph) + (bounds.width * bounds.height + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT) * 2; +- if (max_glyph_size < 8) +- max_glyph_size = 8; +- glyph = grub_malloc (max_glyph_size); ++ if (grub_mul (cur_glyph_size, 2, &max_glyph_size)) ++ max_glyph_size = 0; ++ glyph = max_glyph_size > 0 ? grub_malloc (max_glyph_size) : NULL; + } + if (!glyph) + { ++ max_glyph_size = 0; + grub_errno = GRUB_ERR_NONE; + return main_glyph; + } + +- grub_memset (glyph, 0, sizeof (*glyph) +- + (bounds.width * bounds.height +- + GRUB_CHAR_BIT - 1) / GRUB_CHAR_BIT); ++ grub_memset (glyph, 0, cur_glyph_size); + + glyph->font = main_glyph->font; +- glyph->width = bounds.width; +- glyph->height = bounds.height; +- glyph->offset_x = bounds.x; +- glyph->offset_y = bounds.y; ++ if (bounds.width == 0 || bounds.height == 0 || ++ grub_cast (bounds.width, &glyph->width) || ++ grub_cast (bounds.height, &glyph->height) || ++ grub_cast (bounds.x, &glyph->offset_x) || ++ grub_cast (bounds.y, &glyph->offset_y)) ++ return main_glyph; + + if (glyph_id->attributes & GRUB_UNICODE_GLYPH_ATTRIBUTE_MIRROR) + grub_font_blit_glyph_mirror (glyph, main_glyph, diff --git a/SOURCES/0282-font-Remove-grub_font_dup_glyph.patch b/SOURCES/0282-font-Remove-grub_font_dup_glyph.patch new file mode 100644 index 0000000..4c3db92 --- /dev/null +++ b/SOURCES/0282-font-Remove-grub_font_dup_glyph.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 02:13:29 +0800 +Subject: [PATCH] font: Remove grub_font_dup_glyph() + +Remove grub_font_dup_glyph() since nobody is using it since 2013, and +I'm too lazy to fix the integer overflow problem in it. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 25ad31c19c331aaa2dbd9bd2b2e2655de5766a9d) +--- + grub-core/font/font.c | 14 -------------- + 1 file changed, 14 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 1fa181d4ca..a115a63b0c 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1055,20 +1055,6 @@ grub_font_get_glyph_with_fallback (grub_font_t font, grub_uint32_t code) + return best_glyph; + } + +-#if 0 +-static struct grub_font_glyph * +-grub_font_dup_glyph (struct grub_font_glyph *glyph) +-{ +- static struct grub_font_glyph *ret; +- ret = grub_malloc (sizeof (*ret) + (glyph->width * glyph->height + 7) / 8); +- if (!ret) +- return NULL; +- grub_memcpy (ret, glyph, sizeof (*ret) +- + (glyph->width * glyph->height + 7) / 8); +- return ret; +-} +-#endif +- + /* FIXME: suboptimal. */ + static void + grub_font_blit_glyph (struct grub_font_glyph *target, diff --git a/SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch b/SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch new file mode 100644 index 0000000..6b73038 --- /dev/null +++ b/SOURCES/0283-font-Fix-integer-overflow-in-ensure_comb_space.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 5 Aug 2022 02:27:05 +0800 +Subject: [PATCH] font: Fix integer overflow in ensure_comb_space() + +In fact it can't overflow at all because glyph_id->ncomb is only 8-bit +wide. But let's keep safe if somebody changes the width of glyph_id->ncomb +in the future. This patch also fixes the inconsistency between +render_max_comb_glyphs and render_combining_glyphs when grub_malloc() +returns NULL. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit b2740b7e4a03bb8331d48b54b119afea76bb9d5f) +--- + grub-core/font/font.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index a115a63b0c..d0e6340404 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1468,14 +1468,18 @@ ensure_comb_space (const struct grub_unicode_glyph *glyph_id) + if (glyph_id->ncomb <= render_max_comb_glyphs) + return; + +- render_max_comb_glyphs = 2 * glyph_id->ncomb; +- if (render_max_comb_glyphs < 8) ++ if (grub_mul (glyph_id->ncomb, 2, &render_max_comb_glyphs)) ++ render_max_comb_glyphs = 0; ++ if (render_max_comb_glyphs > 0 && render_max_comb_glyphs < 8) + render_max_comb_glyphs = 8; + grub_free (render_combining_glyphs); +- render_combining_glyphs = grub_malloc (render_max_comb_glyphs +- * sizeof (render_combining_glyphs[0])); ++ render_combining_glyphs = (render_max_comb_glyphs > 0) ? ++ grub_calloc (render_max_comb_glyphs, sizeof (render_combining_glyphs[0])) : NULL; + if (!render_combining_glyphs) +- grub_errno = 0; ++ { ++ render_max_comb_glyphs = 0; ++ grub_errno = GRUB_ERR_NONE; ++ } + } + + int diff --git a/SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch b/SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch new file mode 100644 index 0000000..5e10699 --- /dev/null +++ b/SOURCES/0284-font-Fix-integer-overflow-in-BMP-index.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Mon, 15 Aug 2022 02:04:58 +0800 +Subject: [PATCH] font: Fix integer overflow in BMP index + +The BMP index (font->bmp_idx) is designed as a reverse lookup table of +char entries (font->char_index), in order to speed up lookups for BMP +chars (i.e. code < 0x10000). The values in BMP index are the subscripts +of the corresponding char entries, stored in grub_uint16_t, while 0xffff +means not found. + +This patch fixes the problem of large subscript truncated to grub_uint16_t, +leading BMP index to return wrong char entry or report false miss. The +code now checks for bounds and uses BMP index as a hint, and fallbacks +to binary-search if necessary. + +On the occasion add a comment about BMP index is initialized to 0xffff. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit afda8b60ba0712abe01ae1e64c5f7a067a0e6492) +--- + grub-core/font/font.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index d0e6340404..b208a28717 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -300,6 +300,8 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + font->bmp_idx = grub_malloc (0x10000 * sizeof (grub_uint16_t)); + if (!font->bmp_idx) + return 1; ++ ++ /* Init the BMP index array to 0xffff. */ + grub_memset (font->bmp_idx, 0xff, 0x10000 * sizeof (grub_uint16_t)); + + +@@ -328,7 +330,7 @@ load_font_index (grub_file_t file, grub_uint32_t sect_length, struct + return 1; + } + +- if (entry->code < 0x10000) ++ if (entry->code < 0x10000 && i < 0xffff) + font->bmp_idx[entry->code] = i; + + last_code = entry->code; +@@ -696,9 +698,12 @@ find_glyph (const grub_font_t font, grub_uint32_t code) + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) + { +- if (font->bmp_idx[code] == 0xffff) +- return 0; +- return &table[font->bmp_idx[code]]; ++ if (font->bmp_idx[code] < 0xffff) ++ return &table[font->bmp_idx[code]]; ++ /* ++ * When we are here then lookup in BMP index result in miss, ++ * fallthough to binary-search. ++ */ + } + + /* Do a binary search in `char_index', which is ordered by code point. */ diff --git a/SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch b/SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch new file mode 100644 index 0000000..e81824b --- /dev/null +++ b/SOURCES/0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 14 Aug 2022 18:09:38 +0800 +Subject: [PATCH] font: Fix integer underflow in binary search of char index + +If search target is less than all entries in font->index then "hi" +variable is set to -1, which translates to SIZE_MAX and leads to errors. + +This patch fixes the problem by replacing the entire binary search code +with the libstdc++'s std::lower_bound() implementation. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit c140a086838e7c9af87842036f891b8393a8c4bc) +--- + grub-core/font/font.c | 40 ++++++++++++++++++++++------------------ + 1 file changed, 22 insertions(+), 18 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index b208a28717..193dfec045 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -688,12 +688,12 @@ read_be_int16 (grub_file_t file, grub_int16_t * value) + static inline struct char_index_entry * + find_glyph (const grub_font_t font, grub_uint32_t code) + { +- struct char_index_entry *table; +- grub_size_t lo; +- grub_size_t hi; +- grub_size_t mid; ++ struct char_index_entry *table, *first, *end; ++ grub_size_t len; + + table = font->char_index; ++ if (table == NULL) ++ return NULL; + + /* Use BMP index if possible. */ + if (code < 0x10000 && font->bmp_idx) +@@ -706,25 +706,29 @@ find_glyph (const grub_font_t font, grub_uint32_t code) + */ + } + +- /* Do a binary search in `char_index', which is ordered by code point. */ +- lo = 0; +- hi = font->num_chars - 1; ++ /* ++ * Do a binary search in char_index which is ordered by code point. ++ * The code below is the same as libstdc++'s std::lower_bound(). ++ */ ++ first = table; ++ len = font->num_chars; ++ end = first + len; + +- if (!table) +- return 0; +- +- while (lo <= hi) ++ while (len > 0) + { +- mid = lo + (hi - lo) / 2; +- if (code < table[mid].code) +- hi = mid - 1; +- else if (code > table[mid].code) +- lo = mid + 1; ++ grub_size_t half = len >> 1; ++ struct char_index_entry *middle = first + half; ++ ++ if (middle->code < code) ++ { ++ first = middle + 1; ++ len = len - half - 1; ++ } + else +- return &table[mid]; ++ len = half; + } + +- return 0; ++ return (first < end && first->code == code) ? first : NULL; + } + + /* Get a glyph for the Unicode character CODE in FONT. The glyph is loaded diff --git a/SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch b/SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch new file mode 100644 index 0000000..1a381b0 --- /dev/null +++ b/SOURCES/0286-kern-efi-sb-Enforce-verification-of-font-files.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 14 Aug 2022 15:51:54 +0800 +Subject: [PATCH] kern/efi/sb: Enforce verification of font files + +As a mitigation and hardening measure enforce verification of font +files. Then only trusted font files can be load. This will reduce the +attack surface at cost of losing the ability of end-users to customize +fonts if e.g. UEFI Secure Boot is enabled. Vendors can always customize +fonts because they have ability to pack fonts into their GRUB bundles. + +This goal is achieved by: + + * Removing GRUB_FILE_TYPE_FONT from shim lock verifier's + skip-verification list. + + * Adding GRUB_FILE_TYPE_FONT to lockdown verifier's defer-auth list, + so font files must be verified by a verifier before they can be loaded. + +Suggested-by: Daniel Kiper +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 630deb8c0d8b02b670ced4b7030414bcf17aa080) +--- + grub-core/kern/efi/sb.c | 1 - + grub-core/kern/lockdown.c | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index 89c4bb3fd1..db42c2539f 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -145,7 +145,6 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_PRINT_BLOCKLIST: + case GRUB_FILE_TYPE_TESTLOAD: + case GRUB_FILE_TYPE_GET_SIZE: +- case GRUB_FILE_TYPE_FONT: + case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY: + case GRUB_FILE_TYPE_CAT: + case GRUB_FILE_TYPE_HEXCAT: +diff --git a/grub-core/kern/lockdown.c b/grub-core/kern/lockdown.c +index 0bc70fd42d..af6d493cd3 100644 +--- a/grub-core/kern/lockdown.c ++++ b/grub-core/kern/lockdown.c +@@ -51,6 +51,7 @@ lockdown_verifier_init (grub_file_t io __attribute__ ((unused)), + case GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE: + case GRUB_FILE_TYPE_ACPI_TABLE: + case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE: ++ case GRUB_FILE_TYPE_FONT: + *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH; + + /* Fall through. */ diff --git a/SOURCES/0287-fbutil-Fix-integer-overflow.patch b/SOURCES/0287-fbutil-Fix-integer-overflow.patch new file mode 100644 index 0000000..4d32dbd --- /dev/null +++ b/SOURCES/0287-fbutil-Fix-integer-overflow.patch @@ -0,0 +1,83 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Tue, 6 Sep 2022 03:03:21 +0800 +Subject: [PATCH] fbutil: Fix integer overflow + +Expressions like u64 = u32 * u32 are unsafe because their products are +truncated to u32 even if left hand side is u64. This patch fixes all +problems like that one in fbutil. + +To get right result not only left hand side have to be u64 but it's also +necessary to cast at least one of the operands of all leaf operators of +right hand side to u64, e.g. u64 = u32 * u32 + u32 * u32 should be +u64 = (u64)u32 * u32 + (u64)u32 * u32. + +For 1-bit bitmaps grub_uint64_t have to be used. It's safe because any +combination of values in (grub_uint64_t)u32 * u32 + u32 expression will +not overflow grub_uint64_t. + +Other expressions like ptr + u32 * u32 + u32 * u32 are also vulnerable. +They should be ptr + (grub_addr_t)u32 * u32 + (grub_addr_t)u32 * u32. + +This patch also adds a comment to grub_video_fb_get_video_ptr() which +says it's arguments must be valid and no sanity check is performed +(like its siblings in grub-core/video/fb/fbutil.c). + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 50a11a81bc842c58962244a2dc86bbd31a426e12) +--- + grub-core/video/fb/fbutil.c | 4 ++-- + include/grub/fbutil.h | 13 +++++++++---- + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/grub-core/video/fb/fbutil.c b/grub-core/video/fb/fbutil.c +index b98bb51fe8..25ef39f47d 100644 +--- a/grub-core/video/fb/fbutil.c ++++ b/grub-core/video/fb/fbutil.c +@@ -67,7 +67,7 @@ get_pixel (struct grub_video_fbblit_info *source, + case 1: + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + { +- int bit_index = y * source->mode_info->width + x; ++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x; + grub_uint8_t *ptr = source->data + bit_index / 8; + int bit_pos = 7 - bit_index % 8; + color = (*ptr >> bit_pos) & 0x01; +@@ -138,7 +138,7 @@ set_pixel (struct grub_video_fbblit_info *source, + case 1: + if (source->mode_info->blit_format == GRUB_VIDEO_BLIT_FORMAT_1BIT_PACKED) + { +- int bit_index = y * source->mode_info->width + x; ++ grub_uint64_t bit_index = (grub_uint64_t) y * source->mode_info->width + x; + grub_uint8_t *ptr = source->data + bit_index / 8; + int bit_pos = 7 - bit_index % 8; + *ptr = (*ptr & ~(1 << bit_pos)) | ((color & 0x01) << bit_pos); +diff --git a/include/grub/fbutil.h b/include/grub/fbutil.h +index 4205eb917f..78a1ab3b45 100644 +--- a/include/grub/fbutil.h ++++ b/include/grub/fbutil.h +@@ -31,14 +31,19 @@ struct grub_video_fbblit_info + grub_uint8_t *data; + }; + +-/* Don't use for 1-bit bitmaps, addressing needs to be done at the bit level +- and it doesn't make sense, in general, to ask for a pointer +- to a particular pixel's data. */ ++/* ++ * Don't use for 1-bit bitmaps, addressing needs to be done at the bit level ++ * and it doesn't make sense, in general, to ask for a pointer ++ * to a particular pixel's data. ++ * ++ * This function assumes that bounds checking has been done in previous phase ++ * and they are opted out in here. ++ */ + static inline void * + grub_video_fb_get_video_ptr (struct grub_video_fbblit_info *source, + unsigned int x, unsigned int y) + { +- return source->data + y * source->mode_info->pitch + x * source->mode_info->bytes_per_pixel; ++ return source->data + (grub_addr_t) y * source->mode_info->pitch + (grub_addr_t) x * source->mode_info->bytes_per_pixel; + } + + /* Advance pointer by VAL bytes. If there is no unaligned access available, diff --git a/SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch b/SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch new file mode 100644 index 0000000..72f4308 --- /dev/null +++ b/SOURCES/0288-font-Fix-an-integer-underflow-in-blit_comb.patch @@ -0,0 +1,89 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Mon, 24 Oct 2022 08:05:35 +0800 +Subject: [PATCH] font: Fix an integer underflow in blit_comb() + +The expression (ctx.bounds.height - combining_glyphs[i]->height) / 2 may +evaluate to a very big invalid value even if both ctx.bounds.height and +combining_glyphs[i]->height are small integers. For example, if +ctx.bounds.height is 10 and combining_glyphs[i]->height is 12, this +expression evaluates to 2147483647 (expected -1). This is because +coordinates are allowed to be negative but ctx.bounds.height is an +unsigned int. So, the subtraction operates on unsigned ints and +underflows to a very big value. The division makes things even worse. +The quotient is still an invalid value even if converted back to int. + +This patch fixes the problem by casting ctx.bounds.height to int. As +a result the subtraction will operate on int and grub_uint16_t which +will be promoted to an int. So, the underflow will no longer happen. Other +uses of ctx.bounds.height (and ctx.bounds.width) are also casted to int, +to ensure coordinates are always calculated on signed integers. + +Fixes: CVE-2022-3775 + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 6d2668dea3774ed74c4cd1eadd146f1b846bc3d4) +--- + grub-core/font/font.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 193dfec045..12a5f0d08c 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1203,12 +1203,12 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + ctx.bounds.height = main_glyph->height; + + above_rightx = main_glyph->offset_x + main_glyph->width; +- above_righty = ctx.bounds.y + ctx.bounds.height; ++ above_righty = ctx.bounds.y + (int) ctx.bounds.height; + + above_leftx = main_glyph->offset_x; +- above_lefty = ctx.bounds.y + ctx.bounds.height; ++ above_lefty = ctx.bounds.y + (int) ctx.bounds.height; + +- below_rightx = ctx.bounds.x + ctx.bounds.width; ++ below_rightx = ctx.bounds.x + (int) ctx.bounds.width; + below_righty = ctx.bounds.y; + + comb = grub_unicode_get_comb (glyph_id); +@@ -1221,7 +1221,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + + if (!combining_glyphs[i]) + continue; +- targetx = (ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; ++ targetx = ((int) ctx.bounds.width - combining_glyphs[i]->width) / 2 + ctx.bounds.x; + /* CGJ is to avoid diacritics reordering. */ + if (comb[i].code + == GRUB_UNICODE_COMBINING_GRAPHEME_JOINER) +@@ -1231,8 +1231,8 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + case GRUB_UNICODE_COMB_OVERLAY: + do_blit (combining_glyphs[i], + targetx, +- (ctx.bounds.height - combining_glyphs[i]->height) / 2 +- - (ctx.bounds.height + ctx.bounds.y), &ctx); ++ ((int) ctx.bounds.height - combining_glyphs[i]->height) / 2 ++ - ((int) ctx.bounds.height + ctx.bounds.y), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; + break; +@@ -1305,7 +1305,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + /* Fallthrough. */ + case GRUB_UNICODE_STACK_ATTACHED_ABOVE: + do_blit (combining_glyphs[i], targetx, +- -(ctx.bounds.height + ctx.bounds.y + space ++ -((int) ctx.bounds.height + ctx.bounds.y + space + + combining_glyphs[i]->height), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; +@@ -1313,7 +1313,7 @@ blit_comb (const struct grub_unicode_glyph *glyph_id, + + case GRUB_UNICODE_COMB_HEBREW_DAGESH: + do_blit (combining_glyphs[i], targetx, +- -(ctx.bounds.height / 2 + ctx.bounds.y ++ -((int) ctx.bounds.height / 2 + ctx.bounds.y + + combining_glyphs[i]->height / 2), &ctx); + if (min_devwidth < combining_glyphs[i]->width) + min_devwidth = combining_glyphs[i]->width; diff --git a/SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch b/SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch new file mode 100644 index 0000000..5207c12 --- /dev/null +++ b/SOURCES/0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Mon, 24 Oct 2022 07:15:41 +0800 +Subject: [PATCH] font: Harden grub_font_blit_glyph() and + grub_font_blit_glyph_mirror() + +As a mitigation and hardening measure add sanity checks to +grub_font_blit_glyph() and grub_font_blit_glyph_mirror(). This patch +makes these two functions do nothing if target blitting area isn't fully +contained in target bitmap. Therefore, if complex calculations in caller +overflows and malicious coordinates are given, we are still safe because +any coordinates which result in out-of-bound-write are rejected. However, +this patch only checks for invalid coordinates, and doesn't provide any +protection against invalid source glyph or destination glyph, e.g. +mismatch between glyph size and buffer size. + +This hardening measure is designed to mitigate possible overflows in +blit_comb(). If overflow occurs, it may return invalid bounding box +during dry run and call grub_font_blit_glyph() with malicious +coordinates during actual blitting. However, we are still safe because +the scratch glyph itself is valid, although its size makes no sense, and +any invalid coordinates are rejected. + +It would be better to call grub_fatal() if illegal parameter is detected. +However, doing this may end up in a dangerous recursion because grub_fatal() +would print messages to the screen and we are in the progress of drawing +characters on the screen. + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit fcd7aa0c278f7cf3fb9f93f1a3966e1792339eb6) +--- + grub-core/font/font.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 12a5f0d08c..29fbb94294 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -1069,8 +1069,15 @@ static void + grub_font_blit_glyph (struct grub_font_glyph *target, + struct grub_font_glyph *src, unsigned dx, unsigned dy) + { ++ grub_uint16_t max_x, max_y; + unsigned src_bit, tgt_bit, src_byte, tgt_byte; + unsigned i, j; ++ ++ /* Harden against out-of-bound writes. */ ++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) || ++ (grub_add (dy, src->height, &max_y) || max_y > target->height)) ++ return; ++ + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i) % 8; +@@ -1102,9 +1109,16 @@ grub_font_blit_glyph_mirror (struct grub_font_glyph *target, + struct grub_font_glyph *src, + unsigned dx, unsigned dy) + { ++ grub_uint16_t max_x, max_y; + unsigned tgt_bit, src_byte, tgt_byte; + signed src_bit; + unsigned i, j; ++ ++ /* Harden against out-of-bound writes. */ ++ if ((grub_add (dx, src->width, &max_x) || max_x > target->width) || ++ (grub_add (dy, src->height, &max_y) || max_y > target->height)) ++ return; ++ + for (i = 0; i < src->height; i++) + { + src_bit = (src->width * i + src->width - 1) % 8; diff --git a/SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch b/SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch new file mode 100644 index 0000000..c2bcc18 --- /dev/null +++ b/SOURCES/0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 28 Oct 2022 17:29:16 +0800 +Subject: [PATCH] font: Assign null_font to glyphs in ascii_font_glyph[] + +The calculations in blit_comb() need information from glyph's font, e.g. +grub_font_get_xheight(main_glyph->font). However, main_glyph->font is +NULL if main_glyph comes from ascii_font_glyph[]. Therefore +grub_font_get_*() crashes because of NULL pointer. + +There is already a solution, the null_font. So, assign it to those glyphs +in ascii_font_glyph[]. + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit dd539d695482069d28b40f2d3821f710cdcf6ee6) +--- + grub-core/font/font.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index 29fbb94294..e6616e610c 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -137,7 +137,7 @@ ascii_glyph_lookup (grub_uint32_t code) + ascii_font_glyph[current]->offset_x = 0; + ascii_font_glyph[current]->offset_y = -2; + ascii_font_glyph[current]->device_width = 8; +- ascii_font_glyph[current]->font = NULL; ++ ascii_font_glyph[current]->font = &null_font; + + grub_memcpy (ascii_font_glyph[current]->bitmap, + &ascii_bitmaps[current * ASCII_BITMAP_SIZE], diff --git a/SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch b/SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch new file mode 100644 index 0000000..ec2184f --- /dev/null +++ b/SOURCES/0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Fri, 28 Oct 2022 21:31:39 +0800 +Subject: [PATCH] normal/charset: Fix an integer overflow in + grub_unicode_aglomerate_comb() + +The out->ncomb is a bit-field of 8 bits. So, the max possible value is 255. +However, code in grub_unicode_aglomerate_comb() doesn't check for an +overflow when incrementing out->ncomb. If out->ncomb is already 255, +after incrementing it will get 0 instead of 256, and cause illegal +memory access in subsequent processing. + +This patch introduces GRUB_UNICODE_NCOMB_MAX to represent the max +acceptable value of ncomb. The code now checks for this limit and +ignores additional combining characters when limit is reached. + +Reported-by: Daniel Axtens +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit da90d62316a3b105d2fbd7334d6521936bd6dcf6) +--- + grub-core/normal/charset.c | 3 +++ + include/grub/unicode.h | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index 7a5a7c153c..c243ca6dae 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -472,6 +472,9 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen, + if (!haveout) + continue; + ++ if (out->ncomb == GRUB_UNICODE_NCOMB_MAX) ++ continue; ++ + if (comb_type == GRUB_UNICODE_COMB_MC + || comb_type == GRUB_UNICODE_COMB_ME + || comb_type == GRUB_UNICODE_COMB_MN) +diff --git a/include/grub/unicode.h b/include/grub/unicode.h +index 4de986a857..c4f6fca043 100644 +--- a/include/grub/unicode.h ++++ b/include/grub/unicode.h +@@ -147,7 +147,9 @@ struct grub_unicode_glyph + grub_uint8_t bidi_level:6; /* minimum: 6 */ + enum grub_bidi_type bidi_type:5; /* minimum: :5 */ + ++#define GRUB_UNICODE_NCOMB_MAX ((1 << 8) - 1) + unsigned ncomb:8; ++ + /* Hint by unicode subsystem how wide this character usually is. + Real width is determined by font. Set only in UTF-8 stream. */ + int estimated_width:8; diff --git a/SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch b/SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch new file mode 100644 index 0000000..bad9d90 --- /dev/null +++ b/SOURCES/0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Wed, 16 Nov 2022 14:40:04 +0000 +Subject: [PATCH] font: Try opening fonts from the bundled memdisk + +Signed-off-by: Robbie Harwood +--- + grub-core/font/font.c | 48 +++++++++++++++++++++++++++++++----------------- + 1 file changed, 31 insertions(+), 17 deletions(-) + +diff --git a/grub-core/font/font.c b/grub-core/font/font.c +index e6616e610c..e421d1ae6f 100644 +--- a/grub-core/font/font.c ++++ b/grub-core/font/font.c +@@ -409,6 +409,27 @@ read_section_as_short (struct font_file_section *section, + return 0; + } + ++static grub_file_t ++try_open_from_prefix (const char *prefix, const char *filename) ++{ ++ grub_file_t file; ++ char *fullname, *ptr; ++ ++ fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1 ++ + sizeof ("/fonts/") + sizeof (".pf2")); ++ if (!fullname) ++ return 0; ++ ptr = grub_stpcpy (fullname, prefix); ++ ptr = grub_stpcpy (ptr, "/fonts/"); ++ ptr = grub_stpcpy (ptr, filename); ++ ptr = grub_stpcpy (ptr, ".pf2"); ++ *ptr = 0; ++ ++ file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); ++ grub_free (fullname); ++ return file; ++} ++ + /* Load a font and add it to the beginning of the global font list. + Returns 0 upon success, nonzero upon failure. */ + grub_font_t +@@ -427,25 +448,18 @@ grub_font_load (const char *filename) + file = grub_buffile_open (filename, GRUB_FILE_TYPE_FONT, 1024); + else + { +- const char *prefix = grub_env_get ("prefix"); +- char *fullname, *ptr; +- if (!prefix) ++ file = try_open_from_prefix ("(memdisk)", filename); ++ if (!file) + { +- grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), +- "prefix"); +- goto fail; ++ const char *prefix = grub_env_get ("prefix"); ++ if (!prefix) ++ { ++ grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), ++ "prefix"); ++ goto fail; ++ } ++ file = try_open_from_prefix (prefix, filename); + } +- fullname = grub_malloc (grub_strlen (prefix) + grub_strlen (filename) + 1 +- + sizeof ("/fonts/") + sizeof (".pf2")); +- if (!fullname) +- goto fail; +- ptr = grub_stpcpy (fullname, prefix); +- ptr = grub_stpcpy (ptr, "/fonts/"); +- ptr = grub_stpcpy (ptr, filename); +- ptr = grub_stpcpy (ptr, ".pf2"); +- *ptr = 0; +- file = grub_buffile_open (fullname, GRUB_FILE_TYPE_FONT, 1024); +- grub_free (fullname); + } + if (!file) + goto fail; diff --git a/SOURCES/0293-mm-Clarify-grub_real_malloc.patch b/SOURCES/0293-mm-Clarify-grub_real_malloc.patch new file mode 100644 index 0000000..0a99c08 --- /dev/null +++ b/SOURCES/0293-mm-Clarify-grub_real_malloc.patch @@ -0,0 +1,183 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:46 +1100 +Subject: [PATCH] mm: Clarify grub_real_malloc() + +When iterating through the singly linked list of free blocks, +grub_real_malloc() uses p and q for the current and previous blocks +respectively. This isn't super clear, so swap to using prev and cur. + +This makes another quirk more obvious. The comment at the top of +grub_real_malloc() might lead you to believe that the function will +allocate from *first if there is space in that block. + +It actually doesn't do that, and it can't do that with the current +data structures. If we used up all of *first, we would need to change +the ->next of the previous block to point to *first->next, but we +can't do that because it's a singly linked list and we don't have +access to *first's previous block. + +What grub_real_malloc() actually does is set *first to the initial +previous block, and *first->next is the block we try to allocate +from. That allows us to keep all the data structures consistent. + +Document that. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 246ad6a44c281bb13486ddea0a26bb661db73106) +--- + grub-core/kern/mm.c | 76 +++++++++++++++++++++++++++++------------------------ + 1 file changed, 41 insertions(+), 35 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index d8c8377578..fb20e93acf 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -178,13 +178,20 @@ grub_mm_init_region (void *addr, grub_size_t size) + } + + /* Allocate the number of units N with the alignment ALIGN from the ring +- buffer starting from *FIRST. ALIGN must be a power of two. Both N and +- ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful, +- otherwise return NULL. */ ++ * buffer given in *FIRST. ALIGN must be a power of two. Both N and ++ * ALIGN are in units of GRUB_MM_ALIGN. Return a non-NULL if successful, ++ * otherwise return NULL. ++ * ++ * Note: because in certain circumstances we need to adjust the ->next ++ * pointer of the previous block, we iterate over the singly linked ++ * list with the pair (prev, cur). *FIRST is our initial previous, and ++ * *FIRST->next is our initial current pointer. So we will actually ++ * allocate from *FIRST->next first and *FIRST itself last. ++ */ + static void * + grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + { +- grub_mm_header_t p, q; ++ grub_mm_header_t cur, prev; + + /* When everything is allocated side effect is that *first will have alloc + magic marked, meaning that there is no room in this region. */ +@@ -192,24 +199,24 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + return 0; + + /* Try to search free slot for allocation in this memory region. */ +- for (q = *first, p = q->next; ; q = p, p = p->next) ++ for (prev = *first, cur = prev->next; ; prev = cur, cur = cur->next) + { + grub_off_t extra; + +- extra = ((grub_addr_t) (p + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1); ++ extra = ((grub_addr_t) (cur + 1) >> GRUB_MM_ALIGN_LOG2) & (align - 1); + if (extra) + extra = align - extra; + +- if (! p) ++ if (! cur) + grub_fatal ("null in the ring"); + +- if (p->magic != GRUB_MM_FREE_MAGIC) +- grub_fatal ("free magic is broken at %p: 0x%x", p, p->magic); ++ if (cur->magic != GRUB_MM_FREE_MAGIC) ++ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic); + +- if (p->size >= n + extra) ++ if (cur->size >= n + extra) + { +- extra += (p->size - extra - n) & (~(align - 1)); +- if (extra == 0 && p->size == n) ++ extra += (cur->size - extra - n) & (~(align - 1)); ++ if (extra == 0 && cur->size == n) + { + /* There is no special alignment requirement and memory block + is complete match. +@@ -222,9 +229,9 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + | alloc, size=n | | + +---------------+ v + */ +- q->next = p->next; ++ prev->next = cur->next; + } +- else if (align == 1 || p->size == n + extra) ++ else if (align == 1 || cur->size == n + extra) + { + /* There might be alignment requirement, when taking it into + account memory block fits in. +@@ -241,23 +248,22 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + | alloc, size=n | | + +---------------+ v + */ +- +- p->size -= n; +- p += p->size; ++ cur->size -= n; ++ cur += cur->size; + } + else if (extra == 0) + { + grub_mm_header_t r; + +- r = p + extra + n; ++ r = cur + extra + n; + r->magic = GRUB_MM_FREE_MAGIC; +- r->size = p->size - extra - n; +- r->next = p->next; +- q->next = r; ++ r->size = cur->size - extra - n; ++ r->next = cur->next; ++ prev->next = r; + +- if (q == p) ++ if (prev == cur) + { +- q = r; ++ prev = r; + r->next = r; + } + } +@@ -284,32 +290,32 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + */ + grub_mm_header_t r; + +- r = p + extra + n; ++ r = cur + extra + n; + r->magic = GRUB_MM_FREE_MAGIC; +- r->size = p->size - extra - n; +- r->next = p; ++ r->size = cur->size - extra - n; ++ r->next = cur; + +- p->size = extra; +- q->next = r; +- p += extra; ++ cur->size = extra; ++ prev->next = r; ++ cur += extra; + } + +- p->magic = GRUB_MM_ALLOC_MAGIC; +- p->size = n; ++ cur->magic = GRUB_MM_ALLOC_MAGIC; ++ cur->size = n; + + /* Mark find as a start marker for next allocation to fasten it. + This will have side effect of fragmenting memory as small + pieces before this will be un-used. */ + /* So do it only for chunks under 64K. */ + if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2) +- || *first == p) +- *first = q; ++ || *first == cur) ++ *first = prev; + +- return p + 1; ++ return cur + 1; + } + + /* Search was completed without result. */ +- if (p == *first) ++ if (cur == *first) + break; + } + diff --git a/SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch b/SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch new file mode 100644 index 0000000..a5601c9 --- /dev/null +++ b/SOURCES/0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:47 +1100 +Subject: [PATCH] mm: grub_real_malloc(): Make small allocs comment match code + +Small allocations move the region's *first pointer. The comment +says that this happens for allocations under 64K. The code says +it's for allocations under 32K. Commit 45bf8b3a7549 changed the +code intentionally: make the comment match. + +Fixes: 45bf8b3a7549 (* grub-core/kern/mm.c (grub_real_malloc): Decrease cut-off of moving the) + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a847895a8d000bdf27ad4d4326f883a0eed769ca) +--- + grub-core/kern/mm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index fb20e93acf..db7e0b2a5b 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -306,7 +306,7 @@ grub_real_malloc (grub_mm_header_t *first, grub_size_t n, grub_size_t align) + /* Mark find as a start marker for next allocation to fasten it. + This will have side effect of fragmenting memory as small + pieces before this will be un-used. */ +- /* So do it only for chunks under 64K. */ ++ /* So do it only for chunks under 32K. */ + if (n < (0x8000 >> GRUB_MM_ALIGN_LOG2) + || *first == cur) + *first = prev; diff --git a/SOURCES/0295-mm-Document-grub_free.patch b/SOURCES/0295-mm-Document-grub_free.patch new file mode 100644 index 0000000..6c9b7cc --- /dev/null +++ b/SOURCES/0295-mm-Document-grub_free.patch @@ -0,0 +1,120 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:48 +1100 +Subject: [PATCH] mm: Document grub_free() + +The grub_free() possesses a surprising number of quirks, and also +uses single-letter variable names confusingly to iterate through +the free list. + +Document what's going on. + +Use prev and cur to iterate over the free list. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1f8d0b01738e49767d662d6426af3570a64565f0) +--- + grub-core/kern/mm.c | 63 ++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 41 insertions(+), 22 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index db7e0b2a5b..0351171cf9 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -446,54 +446,73 @@ grub_free (void *ptr) + } + else + { +- grub_mm_header_t q, s; ++ grub_mm_header_t cur, prev; + + #if 0 +- q = r->first; ++ cur = r->first; + do + { + grub_printf ("%s:%d: q=%p, q->size=0x%x, q->magic=0x%x\n", +- GRUB_FILE, __LINE__, q, q->size, q->magic); +- q = q->next; ++ GRUB_FILE, __LINE__, cur, cur->size, cur->magic); ++ cur = cur->next; + } +- while (q != r->first); ++ while (cur != r->first); + #endif +- +- for (s = r->first, q = s->next; q <= p || q->next >= p; s = q, q = s->next) ++ /* Iterate over all blocks in the free ring. ++ * ++ * The free ring is arranged from high addresses to low ++ * addresses, modulo wraparound. ++ * ++ * We are looking for a block with a higher address than p or ++ * whose next address is lower than p. ++ */ ++ for (prev = r->first, cur = prev->next; cur <= p || cur->next >= p; ++ prev = cur, cur = prev->next) + { +- if (q->magic != GRUB_MM_FREE_MAGIC) +- grub_fatal ("free magic is broken at %p: 0x%x", q, q->magic); ++ if (cur->magic != GRUB_MM_FREE_MAGIC) ++ grub_fatal ("free magic is broken at %p: 0x%x", cur, cur->magic); + +- if (q <= q->next && (q > p || q->next < p)) ++ /* Deal with wrap-around */ ++ if (cur <= cur->next && (cur > p || cur->next < p)) + break; + } + ++ /* mark p as free and insert it between cur and cur->next */ + p->magic = GRUB_MM_FREE_MAGIC; +- p->next = q->next; +- q->next = p; ++ p->next = cur->next; ++ cur->next = p; + ++ /* ++ * If the block we are freeing can be merged with the next ++ * free block, do that. ++ */ + if (p->next + p->next->size == p) + { + p->magic = 0; + + p->next->size += p->size; +- q->next = p->next; ++ cur->next = p->next; + p = p->next; + } + +- r->first = q; ++ r->first = cur; + +- if (q == p + p->size) ++ /* Likewise if can be merged with the preceeding free block */ ++ if (cur == p + p->size) + { +- q->magic = 0; +- p->size += q->size; +- if (q == s) +- s = p; +- s->next = p; +- q = s; ++ cur->magic = 0; ++ p->size += cur->size; ++ if (cur == prev) ++ prev = p; ++ prev->next = p; ++ cur = prev; + } + +- r->first = q; ++ /* ++ * Set r->first such that the just free()d block is tried first. ++ * (An allocation is tried from *first->next, and cur->next == p.) ++ */ ++ r->first = cur; + } + } + diff --git a/SOURCES/0296-mm-Document-grub_mm_init_region.patch b/SOURCES/0296-mm-Document-grub_mm_init_region.patch new file mode 100644 index 0000000..0173f04 --- /dev/null +++ b/SOURCES/0296-mm-Document-grub_mm_init_region.patch @@ -0,0 +1,73 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:49 +1100 +Subject: [PATCH] mm: Document grub_mm_init_region() + +The grub_mm_init_region() does some things that seem magical, especially +around region merging. Make it a bit clearer. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 246d69b7ea619fc1e77dcc5960e37aea45a9808c) +--- + grub-core/kern/mm.c | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 0351171cf9..1cbf98c7ab 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -128,23 +128,52 @@ grub_mm_init_region (void *addr, grub_size_t size) + if (((grub_addr_t) addr + 0x1000) > ~(grub_addr_t) size) + size = ((grub_addr_t) -0x1000) - (grub_addr_t) addr; + ++ /* Attempt to merge this region with every existing region */ + for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p) ++ /* ++ * Is the new region immediately below an existing region? That ++ * is, is the address of the memory we're adding now (addr) + size ++ * of the memory we're adding (size) + the bytes we couldn't use ++ * at the start of the region we're considering (q->pre_size) ++ * equal to the address of q? In other words, does the memory ++ * looks like this? ++ * ++ * addr q ++ * |----size-----|-q->pre_size-|| ++ */ + if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) + { ++ /* ++ * Yes, we can merge the memory starting at addr into the ++ * existing region from below. Align up addr to GRUB_MM_ALIGN ++ * so that our new region has proper alignment. ++ */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); ++ /* Copy the region data across */ + *r = *q; ++ /* Consider all the new size as pre-size */ + r->pre_size += size; +- ++ ++ /* ++ * If we have enough pre-size to create a block, create a ++ * block with it. Mark it as allocated and pass it to ++ * grub_free (), which will sort out getting it into the free ++ * list. ++ */ + if (r->pre_size >> GRUB_MM_ALIGN_LOG2) + { + h = (grub_mm_header_t) (r + 1); ++ /* block size is pre-size converted to cells */ + h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); + h->magic = GRUB_MM_ALLOC_MAGIC; ++ /* region size grows by block size converted back to bytes */ + r->size += h->size << GRUB_MM_ALIGN_LOG2; ++ /* adjust pre_size to be accurate */ + r->pre_size &= (GRUB_MM_ALIGN - 1); + *p = r; + grub_free (h + 1); + } ++ /* Replace the old region with the new region */ + *p = r; + return; + } diff --git a/SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch b/SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch new file mode 100644 index 0000000..c793926 --- /dev/null +++ b/SOURCES/0297-mm-Document-GRUB-internal-memory-management-structur.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 25 Nov 2021 02:22:45 +1100 +Subject: [PATCH] mm: Document GRUB internal memory management structures + +I spent more than a trivial quantity of time figuring out pre_size and +whether a memory region's size contains the header cell or not. + +Document the meanings of all the properties. Hopefully now no-one else +has to figure it out! + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a6c5c52ccffd2674d43db25fb4baa9c528526aa0) +--- + include/grub/mm_private.h | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index c2c4cb1511..203533cc3d 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -21,15 +21,27 @@ + + #include + ++/* For context, see kern/mm.c */ ++ + /* Magic words. */ + #define GRUB_MM_FREE_MAGIC 0x2d3c2808 + #define GRUB_MM_ALLOC_MAGIC 0x6db08fa4 + ++/* A header describing a block of memory - either allocated or free */ + typedef struct grub_mm_header + { ++ /* ++ * The 'next' free block in this region's circular free list. ++ * Only meaningful if the block is free. ++ */ + struct grub_mm_header *next; ++ /* The block size, not in bytes but the number of cells of ++ * GRUB_MM_ALIGN bytes. Includes the header cell. ++ */ + grub_size_t size; ++ /* either free or alloc magic, depending on the block type. */ + grub_size_t magic; ++ /* pad to cell size: see the top of kern/mm.c. */ + #if GRUB_CPU_SIZEOF_VOID_P == 4 + char padding[4]; + #elif GRUB_CPU_SIZEOF_VOID_P == 8 +@@ -48,11 +60,27 @@ typedef struct grub_mm_header + + #define GRUB_MM_ALIGN (1 << GRUB_MM_ALIGN_LOG2) + ++/* A region from which we can make allocations. */ + typedef struct grub_mm_region + { ++ /* The first free block in this region. */ + struct grub_mm_header *first; ++ ++ /* ++ * The next region in the linked list of regions. Regions are initially ++ * sorted in order of increasing size, but can grow, in which case the ++ * ordering may not be preserved. ++ */ + struct grub_mm_region *next; ++ ++ /* ++ * A grub_mm_region will always be aligned to cell size. The pre-size is ++ * the number of bytes we were given but had to skip in order to get that ++ * alignment. ++ */ + grub_size_t pre_size; ++ ++ /* How many bytes are in this region? (free and allocated) */ + grub_size_t size; + } + *grub_mm_region_t; diff --git a/SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch b/SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch new file mode 100644 index 0000000..2893784 --- /dev/null +++ b/SOURCES/0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Apr 2022 15:24:14 +1000 +Subject: [PATCH] mm: Assert that we preserve header vs region alignment + +grub_mm_region_init() does: + + h = (grub_mm_header_t) (r + 1); + +where h is a grub_mm_header_t and r is a grub_mm_region_t. + +Cells are supposed to be GRUB_MM_ALIGN aligned, but while grub_mm_dump +ensures this vs the region header, grub_mm_region_init() does not. + +It's better to be explicit than implicit here: rather than changing +grub_mm_region_init() to ALIGN_UP(), require that the struct is +explicitly a multiple of the header size. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 1df8fe66c57087eb33bd6dc69f786ed124615aa7) +--- + include/grub/mm_private.h | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index 203533cc3d..a688b92a83 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -20,6 +20,7 @@ + #define GRUB_MM_PRIVATE_H 1 + + #include ++#include + + /* For context, see kern/mm.c */ + +@@ -89,4 +90,17 @@ typedef struct grub_mm_region + extern grub_mm_region_t EXPORT_VAR (grub_mm_base); + #endif + ++static inline void ++grub_mm_size_sanity_check (void) { ++ /* Ensure we preserve alignment when doing h = (grub_mm_header_t) (r + 1). */ ++ COMPILE_TIME_ASSERT ((sizeof (struct grub_mm_region) % ++ sizeof (struct grub_mm_header)) == 0); ++ ++ /* ++ * GRUB_MM_ALIGN is supposed to represent cell size, and a mm_header is ++ * supposed to be 1 cell. ++ */ ++ COMPILE_TIME_ASSERT (sizeof (struct grub_mm_header) == GRUB_MM_ALIGN); ++} ++ + #endif diff --git a/SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch b/SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch new file mode 100644 index 0000000..52cfeee --- /dev/null +++ b/SOURCES/0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch @@ -0,0 +1,203 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Apr 2022 15:24:15 +1000 +Subject: [PATCH] mm: When adding a region, merge with region after as well as + before + +On x86_64-efi (at least) regions seem to be added from top down. The mm +code will merge a new region with an existing region that comes +immediately before the new region. This allows larger allocations to be +satisfied that would otherwise be the case. + +On powerpc-ieee1275, however, regions are added from bottom up. So if +we add 3x 32MB regions, we can still only satisfy a 32MB allocation, +rather than the 96MB allocation we might otherwise be able to satisfy. + + * Define 'post_size' as being bytes lost to the end of an allocation + due to being given weird sizes from firmware that are not multiples + of GRUB_MM_ALIGN. + + * Allow merging of regions immediately _after_ existing regions, not + just before. As with the other approach, we create an allocated + block to represent the new space and the pass it to grub_free() to + get the metadata right. + +Signed-off-by: Daniel Axtens +Tested-by: Stefan Berger +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 052e6068be622ff53f1238b449c300dbd0a8abcd) +--- + grub-core/kern/mm.c | 128 +++++++++++++++++++++++++++++----------------- + include/grub/mm_private.h | 9 ++++ + 2 files changed, 91 insertions(+), 46 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 1cbf98c7ab..7be33e23bf 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -130,53 +130,88 @@ grub_mm_init_region (void *addr, grub_size_t size) + + /* Attempt to merge this region with every existing region */ + for (p = &grub_mm_base, q = *p; q; p = &(q->next), q = *p) +- /* +- * Is the new region immediately below an existing region? That +- * is, is the address of the memory we're adding now (addr) + size +- * of the memory we're adding (size) + the bytes we couldn't use +- * at the start of the region we're considering (q->pre_size) +- * equal to the address of q? In other words, does the memory +- * looks like this? +- * +- * addr q +- * |----size-----|-q->pre_size-|| +- */ +- if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) +- { +- /* +- * Yes, we can merge the memory starting at addr into the +- * existing region from below. Align up addr to GRUB_MM_ALIGN +- * so that our new region has proper alignment. +- */ +- r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); +- /* Copy the region data across */ +- *r = *q; +- /* Consider all the new size as pre-size */ +- r->pre_size += size; ++ { ++ /* ++ * Is the new region immediately below an existing region? That ++ * is, is the address of the memory we're adding now (addr) + size ++ * of the memory we're adding (size) + the bytes we couldn't use ++ * at the start of the region we're considering (q->pre_size) ++ * equal to the address of q? In other words, does the memory ++ * looks like this? ++ * ++ * addr q ++ * |----size-----|-q->pre_size-|| ++ */ ++ if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) ++ { ++ /* ++ * Yes, we can merge the memory starting at addr into the ++ * existing region from below. Align up addr to GRUB_MM_ALIGN ++ * so that our new region has proper alignment. ++ */ ++ r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); ++ /* Copy the region data across */ ++ *r = *q; ++ /* Consider all the new size as pre-size */ ++ r->pre_size += size; + +- /* +- * If we have enough pre-size to create a block, create a +- * block with it. Mark it as allocated and pass it to +- * grub_free (), which will sort out getting it into the free +- * list. +- */ +- if (r->pre_size >> GRUB_MM_ALIGN_LOG2) +- { +- h = (grub_mm_header_t) (r + 1); +- /* block size is pre-size converted to cells */ +- h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); +- h->magic = GRUB_MM_ALLOC_MAGIC; +- /* region size grows by block size converted back to bytes */ +- r->size += h->size << GRUB_MM_ALIGN_LOG2; +- /* adjust pre_size to be accurate */ +- r->pre_size &= (GRUB_MM_ALIGN - 1); +- *p = r; +- grub_free (h + 1); +- } +- /* Replace the old region with the new region */ +- *p = r; +- return; +- } ++ /* ++ * If we have enough pre-size to create a block, create a ++ * block with it. Mark it as allocated and pass it to ++ * grub_free (), which will sort out getting it into the free ++ * list. ++ */ ++ if (r->pre_size >> GRUB_MM_ALIGN_LOG2) ++ { ++ h = (grub_mm_header_t) (r + 1); ++ /* block size is pre-size converted to cells */ ++ h->size = (r->pre_size >> GRUB_MM_ALIGN_LOG2); ++ h->magic = GRUB_MM_ALLOC_MAGIC; ++ /* region size grows by block size converted back to bytes */ ++ r->size += h->size << GRUB_MM_ALIGN_LOG2; ++ /* adjust pre_size to be accurate */ ++ r->pre_size &= (GRUB_MM_ALIGN - 1); ++ *p = r; ++ grub_free (h + 1); ++ } ++ /* Replace the old region with the new region */ ++ *p = r; ++ return; ++ } ++ ++ /* ++ * Is the new region immediately above an existing region? That ++ * is: ++ * q addr ++ * ||-q->post_size-|----size-----| ++ */ ++ if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size == ++ (grub_uint8_t *) addr) ++ { ++ /* ++ * Yes! Follow a similar pattern to above, but simpler. ++ * Our header starts at address - post_size, which should align us ++ * to a cell boundary. ++ * ++ * Cast to (void *) first to avoid the following build error: ++ * kern/mm.c: In function ‘grub_mm_init_region’: ++ * kern/mm.c:211:15: error: cast increases required alignment of target type [-Werror=cast-align] ++ * 211 | h = (grub_mm_header_t) ((grub_uint8_t *) addr - q->post_size); ++ * | ^ ++ * It is safe to do that because proper alignment is enforced in grub_mm_size_sanity_check(). ++ */ ++ h = (grub_mm_header_t)(void *) ((grub_uint8_t *) addr - q->post_size); ++ /* our size is the allocated size plus post_size, in cells */ ++ h->size = (size + q->post_size) >> GRUB_MM_ALIGN_LOG2; ++ h->magic = GRUB_MM_ALLOC_MAGIC; ++ /* region size grows by block size converted back to bytes */ ++ q->size += h->size << GRUB_MM_ALIGN_LOG2; ++ /* adjust new post_size to be accurate */ ++ q->post_size = (q->post_size + size) & (GRUB_MM_ALIGN - 1); ++ grub_free (h + 1); ++ return; ++ } ++ } + + /* Allocate a region from the head. */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); +@@ -195,6 +230,7 @@ grub_mm_init_region (void *addr, grub_size_t size) + r->first = h; + r->pre_size = (grub_addr_t) r - (grub_addr_t) addr; + r->size = (h->size << GRUB_MM_ALIGN_LOG2); ++ r->post_size = size - r->size; + + /* Find where to insert this region. Put a smaller one before bigger ones, + to prevent fragmentation. */ +diff --git a/include/grub/mm_private.h b/include/grub/mm_private.h +index a688b92a83..96c2d816be 100644 +--- a/include/grub/mm_private.h ++++ b/include/grub/mm_private.h +@@ -81,8 +81,17 @@ typedef struct grub_mm_region + */ + grub_size_t pre_size; + ++ /* ++ * Likewise, the post-size is the number of bytes we wasted at the end ++ * of the allocation because it wasn't a multiple of GRUB_MM_ALIGN ++ */ ++ grub_size_t post_size; ++ + /* How many bytes are in this region? (free and allocated) */ + grub_size_t size; ++ ++ /* pad to a multiple of cell size */ ++ char padding[3 * GRUB_CPU_SIZEOF_VOID_P]; + } + *grub_mm_region_t; + diff --git a/SOURCES/0300-mm-Debug-support-for-region-operations.patch b/SOURCES/0300-mm-Debug-support-for-region-operations.patch new file mode 100644 index 0000000..f434260 --- /dev/null +++ b/SOURCES/0300-mm-Debug-support-for-region-operations.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 21 Apr 2022 15:24:16 +1000 +Subject: [PATCH] mm: Debug support for region operations + +This is handy for debugging. Enable with "set debug=regions". + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 8afa5ef45b797ba5d8147ceee85ac2c59dcc7f09) +--- + grub-core/kern/mm.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 7be33e23bf..38bfb01df9 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -115,9 +115,8 @@ grub_mm_init_region (void *addr, grub_size_t size) + grub_mm_header_t h; + grub_mm_region_t r, *p, q; + +-#if 0 +- grub_printf ("Using memory for heap: start=%p, end=%p\n", addr, addr + (unsigned int) size); +-#endif ++ grub_dprintf ("regions", "Using memory for heap: start=%p, end=%p\n", ++ addr, (char *) addr + (unsigned int) size); + + /* Exclude last 4K to avoid overflows. */ + /* If addr + 0x1000 overflows then whole region is in excluded zone. */ +@@ -142,8 +141,14 @@ grub_mm_init_region (void *addr, grub_size_t size) + * addr q + * |----size-----|-q->pre_size-|| + */ ++ grub_dprintf ("regions", "Can we extend into region above?" ++ " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", ++ (grub_uint8_t *) addr, size, q->pre_size, (grub_uint8_t *) q); + if ((grub_uint8_t *) addr + size + q->pre_size == (grub_uint8_t *) q) + { ++ grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", ++ q, (grub_uint8_t *) q + sizeof (*q) + q->size, ++ addr, (grub_uint8_t *) q + sizeof (*q) + q->size); + /* + * Yes, we can merge the memory starting at addr into the + * existing region from below. Align up addr to GRUB_MM_ALIGN +@@ -185,9 +190,15 @@ grub_mm_init_region (void *addr, grub_size_t size) + * q addr + * ||-q->post_size-|----size-----| + */ ++ grub_dprintf ("regions", "Can we extend into region below?" ++ " %p + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " + %" PRIxGRUB_SIZE " ?=? %p\n", ++ (grub_uint8_t *) q, sizeof(*q), q->size, q->post_size, (grub_uint8_t *) addr); + if ((grub_uint8_t *) q + sizeof (*q) + q->size + q->post_size == + (grub_uint8_t *) addr) + { ++ grub_dprintf ("regions", "Yes: extending a region: (%p -> %p) -> (%p -> %p)\n", ++ q, (grub_uint8_t *) q + sizeof (*q) + q->size, ++ q, (grub_uint8_t *) addr + size); + /* + * Yes! Follow a similar pattern to above, but simpler. + * Our header starts at address - post_size, which should align us +@@ -213,6 +224,8 @@ grub_mm_init_region (void *addr, grub_size_t size) + } + } + ++ grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n", ++ addr, size); + /* Allocate a region from the head. */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); + diff --git a/SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch b/SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch new file mode 100644 index 0000000..a18d912 --- /dev/null +++ b/SOURCES/0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch @@ -0,0 +1,80 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:17 +1000 +Subject: [PATCH] mm: Drop unused unloading of modules on OOM + +In grub_memalign(), there's a commented section which would allow for +unloading of unneeded modules in case where there is not enough free +memory available to satisfy a request. Given that this code is never +compiled in, let's remove it together with grub_dl_unload_unneeded(). + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 139fd9b134a01e0b5fe0ebefafa7f48d1ffb6d60) +--- + grub-core/kern/dl.c | 20 -------------------- + grub-core/kern/mm.c | 8 -------- + include/grub/dl.h | 1 - + 3 files changed, 29 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index d5de80186f..ab9101a5ad 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -998,23 +998,3 @@ grub_dl_unload (grub_dl_t mod) + grub_free (mod); + return 1; + } +- +-/* Unload unneeded modules. */ +-void +-grub_dl_unload_unneeded (void) +-{ +- /* Because grub_dl_remove modifies the list of modules, this +- implementation is tricky. */ +- grub_dl_t p = grub_dl_head; +- +- while (p) +- { +- if (grub_dl_unload (p)) +- { +- p = grub_dl_head; +- continue; +- } +- +- p = p->next; +- } +-} +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 38bfb01df9..1825dc8289 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -444,14 +444,6 @@ grub_memalign (grub_size_t align, grub_size_t size) + count++; + goto again; + +-#if 0 +- case 1: +- /* Unload unneeded modules. */ +- grub_dl_unload_unneeded (); +- count++; +- goto again; +-#endif +- + default: + break; + } +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 45ac8e339f..6bc2560bf0 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -206,7 +206,6 @@ grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); + grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); + grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); + int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); +-extern void grub_dl_unload_unneeded (void); + extern int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); + extern int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); + extern int EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); diff --git a/SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch b/SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch new file mode 100644 index 0000000..d225c10 --- /dev/null +++ b/SOURCES/0302-mm-Allow-dynamically-requesting-additional-memory-re.patch @@ -0,0 +1,130 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:18 +1000 +Subject: [PATCH] mm: Allow dynamically requesting additional memory regions + +Currently, all platforms will set up their heap on initialization of the +platform code. While this works mostly fine, it poses some limitations +on memory management on us. Most notably, allocating big chunks of +memory in the gigabyte range would require us to pre-request this many +bytes from the firmware and add it to the heap from the beginning on +some platforms like EFI. As this isn't needed for most configurations, +it is inefficient and may even negatively impact some usecases when, +e.g., chainloading. Nonetheless, allocating big chunks of memory is +required sometimes, where one example is the upcoming support for the +Argon2 key derival function in LUKS2. + +In order to avoid pre-allocating big chunks of memory, this commit +implements a runtime mechanism to add more pages to the system. When +a given allocation cannot be currently satisfied, we'll call a given +callback set up by the platform's own memory management subsystem, +asking it to add a memory area with at least "n" bytes. If this +succeeds, we retry searching for a valid memory region, which should +now succeed. + +If this fails, we try asking for "n" bytes, possibly spread across +multiple regions, in hopes that region merging means that we end up +with enough memory for things to work out. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Tested-by: Stefan Berger +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 887f98f0db43e33fba4ec1f85e42fae1185700bc) +--- + grub-core/kern/mm.c | 30 ++++++++++++++++++++++++++++++ + include/grub/mm.h | 18 ++++++++++++++++++ + 2 files changed, 48 insertions(+) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index 1825dc8289..f2e27f263b 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -28,6 +28,9 @@ + - multiple regions may be used as free space. They may not be + contiguous. + ++ - if existing regions are insufficient to satisfy an allocation, a new ++ region can be requested from firmware. ++ + Regions are managed by a singly linked list, and the meta information is + stored in the beginning of each region. Space after the meta information + is used to allocate memory. +@@ -81,6 +84,7 @@ + + + grub_mm_region_t grub_mm_base; ++grub_mm_add_region_func_t grub_mm_add_region_fn; + + /* Get a header from the pointer PTR, and set *P and *R to a pointer + to the header and a pointer to its region, respectively. PTR must +@@ -444,6 +448,32 @@ grub_memalign (grub_size_t align, grub_size_t size) + count++; + goto again; + ++ case 1: ++ /* Request additional pages, contiguous */ ++ count++; ++ ++ if (grub_mm_add_region_fn != NULL && ++ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) ++ goto again; ++ ++ /* fallthrough */ ++ ++ case 2: ++ /* Request additional pages, anything at all */ ++ count++; ++ ++ if (grub_mm_add_region_fn != NULL) ++ { ++ /* ++ * Try again even if this fails, in case it was able to partially ++ * satisfy the request ++ */ ++ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); ++ goto again; ++ } ++ ++ /* fallthrough */ ++ + default: + break; + } +diff --git a/include/grub/mm.h b/include/grub/mm.h +index d81623d226..7c6f925ffd 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -20,6 +20,7 @@ + #ifndef GRUB_MM_H + #define GRUB_MM_H 1 + ++#include + #include + #include + #include +@@ -29,6 +30,23 @@ + # define NULL ((void *) 0) + #endif + ++#define GRUB_MM_ADD_REGION_NONE 0 ++#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0) ++ ++/* ++ * Function used to request memory regions of `grub_size_t` bytes. The second ++ * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags. ++ */ ++typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int); ++ ++/* ++ * Set this function pointer to enable adding memory-regions at runtime in case ++ * a memory allocation cannot be satisfied with existing regions. ++ */ ++#ifndef GRUB_MACHINE_EMU ++extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn); ++#endif ++ + void grub_mm_init_region (void *addr, grub_size_t size); + void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size); + void *EXPORT_FUNC(grub_malloc) (grub_size_t size); diff --git a/SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch b/SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch new file mode 100644 index 0000000..6fa378c --- /dev/null +++ b/SOURCES/0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:19 +1000 +Subject: [PATCH] kern/efi/mm: Always request a fixed number of pages on init + +When initializing the EFI memory subsystem, we will by default request +a quarter of the available memory, bounded by a minimum/maximum value. +Given that we're about to extend the EFI memory system to dynamically +request additional pages from the firmware as required, this scaling of +requested memory based on available memory will not make a lot of sense +anymore. + +Remove this logic as a preparatory patch such that we'll instead defer +to the runtime memory allocator. Note that ideally, we'd want to change +this after dynamic requesting of pages has been implemented for the EFI +platform. But because we'll need to split up initialization of the +memory subsystem and the request of pages from the firmware, we'd have +to duplicate quite some logic at first only to remove it afterwards +again. This seems quite pointless, so we instead have patches slightly +out of order. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 938c3760b8c0fca759140be48307179b50107ff6) +--- + grub-core/kern/efi/mm.c | 35 +++-------------------------------- + 1 file changed, 3 insertions(+), 32 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index e460b072e6..782a1365a1 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -38,9 +38,8 @@ + a multiplier of 4KB. */ + #define MEMORY_MAP_SIZE 0x3000 + +-/* The minimum and maximum heap size for GRUB itself. */ +-#define MIN_HEAP_SIZE 0x100000 +-#define MAX_HEAP_SIZE (1600 * 0x100000) ++/* The default heap size for GRUB itself in bytes. */ ++#define DEFAULT_HEAP_SIZE 0x100000 + + static void *finish_mmap_buf = 0; + static grub_efi_uintn_t finish_mmap_size = 0; +@@ -514,23 +513,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + return filtered_desc; + } + +-/* Return the total number of pages. */ +-static grub_efi_uint64_t +-get_total_pages (grub_efi_memory_descriptor_t *memory_map, +- grub_efi_uintn_t desc_size, +- grub_efi_memory_descriptor_t *memory_map_end) +-{ +- grub_efi_memory_descriptor_t *desc; +- grub_efi_uint64_t total = 0; +- +- for (desc = memory_map; +- desc < memory_map_end; +- desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) +- total += desc->num_pages; +- +- return total; +-} +- + /* Add memory regions. */ + static void + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, +@@ -694,8 +676,6 @@ grub_efi_mm_init (void) + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; +- grub_efi_uint64_t total_pages; +- grub_efi_uint64_t required_pages; + int mm_status; + + grub_nx_init (); +@@ -737,22 +717,13 @@ grub_efi_mm_init (void) + filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map, + desc_size, memory_map_end); + +- /* By default, request a quarter of the available memory. */ +- total_pages = get_total_pages (filtered_memory_map, desc_size, +- filtered_memory_map_end); +- required_pages = (total_pages >> 2); +- if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE)) +- required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE); +- else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE)) +- required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE); +- + /* Sort the filtered descriptors, so that GRUB can allocate pages + from smaller regions. */ + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, required_pages); ++ filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); + + #if 0 + /* For debug. */ diff --git a/SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch b/SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch new file mode 100644 index 0000000..28cf2e7 --- /dev/null +++ b/SOURCES/0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:20 +1000 +Subject: [PATCH] kern/efi/mm: Extract function to add memory regions + +In preparation of support for runtime-allocating additional memory +region, this patch extracts the function to retrieve the EFI memory +map and add a subset of it to GRUB's own memory regions. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 96a7ea29e3cb61b6c2302e260e8e6a6117e17fa3) +[rharwood: backport around our nx] +--- + grub-core/kern/efi/mm.c | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 782a1365a1..a1d3b51fe6 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -667,8 +667,8 @@ grub_nx_init (void) + } + } + +-void +-grub_efi_mm_init (void) ++static grub_err_t ++grub_efi_mm_add_regions (grub_size_t required_bytes) + { + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; +@@ -683,7 +683,7 @@ grub_efi_mm_init (void) + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +- grub_fatal ("cannot allocate memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map"); + + /* Obtain descriptors for available memory. */ + map_size = MEMORY_MAP_SIZE; +@@ -701,14 +701,14 @@ grub_efi_mm_init (void) + + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size)); + if (! memory_map) +- grub_fatal ("cannot allocate memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map"); + + mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0, + &desc_size, 0); + } + + if (mm_status < 0) +- grub_fatal ("cannot get memory map"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI"); + + memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size); + +@@ -723,7 +723,7 @@ grub_efi_mm_init (void) + + /* Allocate memory regions for GRUB's memory management. */ + add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE)); ++ filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); + + #if 0 + /* For debug. */ +@@ -741,6 +741,15 @@ grub_efi_mm_init (void) + /* Release the memory maps. */ + grub_efi_free_pages ((grub_addr_t) memory_map, + 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); ++ ++ return GRUB_ERR_NONE; ++} ++ ++void ++grub_efi_mm_init (void) ++{ ++ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) ++ grub_fatal ("%s", grub_errmsg); + } + + #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) diff --git a/SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch b/SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch new file mode 100644 index 0000000..b4b7891 --- /dev/null +++ b/SOURCES/0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:21 +1000 +Subject: [PATCH] kern/efi/mm: Pass up errors from add_memory_regions() + +The function add_memory_regions() is currently only called on system +initialization to allocate a fixed amount of pages. As such, it didn't +need to return any errors: in case it failed, we cannot proceed anyway. +This will change with the upcoming support for requesting more memory +from the firmware at runtime, where it doesn't make sense anymore to +fail hard. + +Refactor the function to return an error to prepare for this. Note that +this does not change the behaviour when initializing the memory system +because grub_efi_mm_init() knows to call grub_fatal() in case +grub_efi_mm_add_regions() returns an error. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 15a015698921240adc1ac266a3b5bc5fcbd81521) +--- + grub-core/kern/efi/mm.c | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index a1d3b51fe6..e0ebc65dba 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -514,7 +514,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + + /* Add memory regions. */ +-static void ++static grub_err_t + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, +@@ -542,9 +542,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + GRUB_EFI_ALLOCATE_ADDRESS, + GRUB_EFI_LOADER_CODE); + if (! addr) +- grub_fatal ("cannot allocate conventional memory %p with %u pages", +- (void *) ((grub_addr_t) start), +- (unsigned) pages); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "Memory starting at %p (%u pages) marked as free, but EFI would not allocate", ++ (void *) ((grub_addr_t) start), (unsigned) pages); + + grub_mm_init_region (addr, PAGES_TO_BYTES (pages)); + +@@ -554,7 +554,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + } + + if (required_pages > 0) +- grub_fatal ("too little memory"); ++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, ++ "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map", ++ required_pages); ++ ++ return GRUB_ERR_NONE; + } + + void +@@ -676,6 +680,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + grub_efi_memory_descriptor_t *filtered_memory_map_end; + grub_efi_uintn_t map_size; + grub_efi_uintn_t desc_size; ++ grub_err_t err; + int mm_status; + + grub_nx_init (); +@@ -722,8 +727,11 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end); + + /* Allocate memory regions for GRUB's memory management. */ +- add_memory_regions (filtered_memory_map, desc_size, +- filtered_memory_map_end, BYTES_TO_PAGES (required_bytes)); ++ err = add_memory_regions (filtered_memory_map, desc_size, ++ filtered_memory_map_end, ++ BYTES_TO_PAGES (required_bytes)); ++ if (err != GRUB_ERR_NONE) ++ return err; + + #if 0 + /* For debug. */ diff --git a/SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch b/SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch new file mode 100644 index 0000000..1f52581 --- /dev/null +++ b/SOURCES/0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Patrick Steinhardt +Date: Thu, 21 Apr 2022 15:24:22 +1000 +Subject: [PATCH] kern/efi/mm: Implement runtime addition of pages + +Adjust the interface of grub_efi_mm_add_regions() to take a set of +GRUB_MM_ADD_REGION_* flags, which most notably is currently only the +GRUB_MM_ADD_REGION_CONSECUTIVE flag. This allows us to set the function +up as callback for the memory subsystem and have it call out to us in +case there's not enough pages available in the current heap. + +Signed-off-by: Patrick Steinhardt +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +Tested-by: Patrick Steinhardt +(cherry picked from commit 1df2934822df4c1170dde069d97cfbf7a9572bba) +--- + grub-core/kern/efi/mm.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index e0ebc65dba..016ba6cf2f 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -518,7 +518,8 @@ static grub_err_t + add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + grub_efi_uintn_t desc_size, + grub_efi_memory_descriptor_t *memory_map_end, +- grub_efi_uint64_t required_pages) ++ grub_efi_uint64_t required_pages, ++ unsigned int flags) + { + grub_efi_memory_descriptor_t *desc; + +@@ -532,6 +533,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map, + + start = desc->physical_start; + pages = desc->num_pages; ++ ++ if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE)) ++ continue; ++ + if (pages > required_pages) + { + start += PAGES_TO_BYTES (pages - required_pages); +@@ -672,7 +677,7 @@ grub_nx_init (void) + } + + static grub_err_t +-grub_efi_mm_add_regions (grub_size_t required_bytes) ++grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags) + { + grub_efi_memory_descriptor_t *memory_map; + grub_efi_memory_descriptor_t *memory_map_end; +@@ -729,7 +734,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + /* Allocate memory regions for GRUB's memory management. */ + err = add_memory_regions (filtered_memory_map, desc_size, + filtered_memory_map_end, +- BYTES_TO_PAGES (required_bytes)); ++ BYTES_TO_PAGES (required_bytes), ++ flags); + if (err != GRUB_ERR_NONE) + return err; + +@@ -756,8 +762,9 @@ grub_efi_mm_add_regions (grub_size_t required_bytes) + void + grub_efi_mm_init (void) + { +- if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE) ++ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE) + grub_fatal ("%s", grub_errmsg); ++ grub_mm_add_region_fn = grub_efi_mm_add_regions; + } + + #if defined (__aarch64__) || defined (__arm__) || defined (__riscv) diff --git a/SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch b/SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch new file mode 100644 index 0000000..b70c3cc --- /dev/null +++ b/SOURCES/0307-efi-Increase-default-memory-allocation-to-32-MiB.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 20 Sep 2022 00:30:30 +1000 +Subject: [PATCH] efi: Increase default memory allocation to 32 MiB + +We have multiple reports of things being slower with a 1 MiB initial static +allocation, and a report (more difficult to nail down) of a boot failure +as a result of the smaller initial allocation. + +Make the initial memory allocation 32 MiB. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 75e38e86e7d9202f050b093f20500d9ad4c6dad9) +--- + grub-core/kern/efi/mm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 016ba6cf2f..b27e966e1f 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -39,7 +39,7 @@ + #define MEMORY_MAP_SIZE 0x3000 + + /* The default heap size for GRUB itself in bytes. */ +-#define DEFAULT_HEAP_SIZE 0x100000 ++#define DEFAULT_HEAP_SIZE 0x2000000 + + static void *finish_mmap_buf = 0; + static grub_efi_uintn_t finish_mmap_size = 0; diff --git a/SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch b/SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch new file mode 100644 index 0000000..c919891 --- /dev/null +++ b/SOURCES/0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch @@ -0,0 +1,57 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sat, 15 Oct 2022 22:15:11 +0800 +Subject: [PATCH] mm: Try invalidate disk caches last when out of memory + +Every heap grow will cause all disk caches invalidated which decreases +performance severely. This patch moves disk cache invalidation code to +the last of memory squeezing measures. So, disk caches are released only +when there are no other ways to get free memory. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +Reviewed-by: Patrick Steinhardt +(cherry picked from commit 17975d10a80e2457e5237f87fa58a7943031983e) +--- + grub-core/kern/mm.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index f2e27f263b..da1ac9427c 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -443,12 +443,6 @@ grub_memalign (grub_size_t align, grub_size_t size) + switch (count) + { + case 0: +- /* Invalidate disk caches. */ +- grub_disk_cache_invalidate_all (); +- count++; +- goto again; +- +- case 1: + /* Request additional pages, contiguous */ + count++; + +@@ -458,7 +452,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + + /* fallthrough */ + +- case 2: ++ case 1: + /* Request additional pages, anything at all */ + count++; + +@@ -474,6 +468,12 @@ grub_memalign (grub_size_t align, grub_size_t size) + + /* fallthrough */ + ++ case 2: ++ /* Invalidate disk caches. */ ++ grub_disk_cache_invalidate_all (); ++ count++; ++ goto again; ++ + default: + break; + } diff --git a/SOURCES/0309-ppc64le-signed-boot-media-changes.patch b/SOURCES/0309-ppc64le-signed-boot-media-changes.patch new file mode 100644 index 0000000..bd71437 --- /dev/null +++ b/SOURCES/0309-ppc64le-signed-boot-media-changes.patch @@ -0,0 +1,125 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 25 Jan 2023 16:10:58 -0500 +Subject: [PATCH] ppc64le: signed boot media changes + +Skip mdraid < 1.1 on isos since mdraid* can't even + +Prior to this change, on ppc64le with part_msdos and the mdraid* modules +enabled, we see: + + disk/diskfilter.c:191: scanning ieee1275/cdrom + kern/disk.c:196: Opening `ieee1275/cdrom'... + disk/ieee1275/ofdisk.c:477: Opening `cdrom'. + disk/ieee1275/ofdisk.c:502: MAX_RETRIES set to 20 + kern/disk.c:288: Opening `ieee1275/cdrom' succeeded. + disk/diskfilter.c:136: Scanning for DISKFILTER devices on disk ieee1275/cdrom + partmap/msdos.c:184: partition 0: flag 0x80, type 0x96, start 0x0, len + 0x6a5d70 + disk/diskfilter.c:136: Scanning for DISKFILTER devices on disk ieee1275/cdrom + SCSI-DISK: Access beyond end of device ! + SCSI-DISK: Access beyond end of device ! + SCSI-DISK: Access beyond end of device ! + SCSI-DISK: Access beyond end of device ! + SCSI-DISK: Access beyond end of device ! + disk/ieee1275/ofdisk.c:578: MAX_RETRIES set to 20 + +These latter two lines repeat many times, eventually ending in: + + kern/disk.c:388: ieee1275/cdrom read failed + error: ../../grub-core/disk/ieee1275/ofdisk.c:608:failure reading sector + 0x1a9720 from `ieee1275/cdrom'. + +and the system drops to a "grub>" prompt. + +Prior to 1.1, mdraid stored the superblock offset from the end of the +disk, and the firmware really doesn't like reads there. Best guess was +that the firmware and the iso image appear to diagree on the blocksize +(512 vs. 2048), and the diskfilter RAID probing is too much for it. +It's tempting to just skip probing for cdroms, but unfortunately isos +can be virtualized elsewhere - such as regular disks. + +Also fix detection of root, and try the chrp path as a fallback if the +built prefix doesn't work. + +Signed-off-by: Robbie Harwood + +wip +--- + grub-core/disk/mdraid1x_linux.c | 8 +++++++- + grub-core/disk/mdraid_linux.c | 5 +++++ + grub-core/kern/ieee1275/openfw.c | 2 +- + grub-core/normal/main.c | 5 +++++ + 4 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/grub-core/disk/mdraid1x_linux.c b/grub-core/disk/mdraid1x_linux.c +index 38444b02c7..08c57ae16e 100644 +--- a/grub-core/disk/mdraid1x_linux.c ++++ b/grub-core/disk/mdraid1x_linux.c +@@ -129,7 +129,13 @@ grub_mdraid_detect (grub_disk_t disk, + grub_uint32_t level; + struct grub_diskfilter_vg *array; + char *uuid; +- ++ ++#ifdef __powerpc__ ++ /* Firmware will yell at us for reading too far. */ ++ if (minor_version == 0) ++ continue; ++#endif ++ + if (size == GRUB_DISK_SIZE_UNKNOWN && minor_version == 0) + continue; + +diff --git a/grub-core/disk/mdraid_linux.c b/grub-core/disk/mdraid_linux.c +index e40216f511..98fcfb1be6 100644 +--- a/grub-core/disk/mdraid_linux.c ++++ b/grub-core/disk/mdraid_linux.c +@@ -189,6 +189,11 @@ grub_mdraid_detect (grub_disk_t disk, + grub_uint32_t level; + struct grub_diskfilter_vg *ret; + ++#ifdef __powerpc__ ++ /* Firmware will yell at us for reading too far. */ ++ return NULL; ++#endif ++ + /* The sector where the mdraid 0.90 superblock is stored, if available. */ + size = grub_disk_native_sectors (disk); + if (size == GRUB_DISK_SIZE_UNKNOWN) +diff --git a/grub-core/kern/ieee1275/openfw.c b/grub-core/kern/ieee1275/openfw.c +index 3a6689abb1..0278054c61 100644 +--- a/grub-core/kern/ieee1275/openfw.c ++++ b/grub-core/kern/ieee1275/openfw.c +@@ -499,7 +499,7 @@ grub_ieee1275_encode_devname (const char *path) + *optr++ ='\\'; + *optr++ = *iptr++; + } +- if (partition && partition[0]) ++ if (partition && partition[0] >= '0' && partition[0] <= '9') + { + unsigned int partno = grub_strtoul (partition, 0, 0); + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index 8f5fd81003..d59145f861 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -372,6 +372,7 @@ grub_try_normal_prefix (const char *prefix) + file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); + if (file) + { ++ grub_env_set ("prefix", prefix); + grub_file_close (file); + err = GRUB_ERR_NONE; + } +@@ -447,6 +448,10 @@ grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)), + err = grub_try_normal ("fw_path"); + if (err == GRUB_ERR_FILE_NOT_FOUND) + err = grub_try_normal ("prefix"); ++#ifdef __powerpc__ ++ if (err == GRUB_ERR_FILE_NOT_FOUND) ++ err = grub_try_normal_prefix ("/boot/grub"); ++#endif + if (err == GRUB_ERR_FILE_NOT_FOUND) + err = grub_try_normal_discover (); + if (err == GRUB_ERR_FILE_NOT_FOUND) diff --git a/SOURCES/0310-core-Fix-several-implicit-function-declarations.patch b/SOURCES/0310-core-Fix-several-implicit-function-declarations.patch new file mode 100644 index 0000000..48c5bb0 --- /dev/null +++ b/SOURCES/0310-core-Fix-several-implicit-function-declarations.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Sun, 5 Feb 2023 11:13:55 +0100 +Subject: [PATCH] core: Fix several implicit function declarations + +These #include lines ensure that grub2 continues to build with C99 +where implicit function declarations are removed. + +Related to: + + + +--- + grub-core/commands/efi/connectefi.c | 1 + + grub-core/net/http.c | 1 + + grub-core/term/at_keyboard.c | 1 + + 3 files changed, 3 insertions(+) + +diff --git a/grub-core/commands/efi/connectefi.c b/grub-core/commands/efi/connectefi.c +index 8ab75bd51b..3752ae17ed 100644 +--- a/grub-core/commands/efi/connectefi.c ++++ b/grub-core/commands/efi/connectefi.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 57d2721719..5f956b743e 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c +index dac0f946fe..de3e4abe44 100644 +--- a/grub-core/term/at_keyboard.c ++++ b/grub-core/term/at_keyboard.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + diff --git a/SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch b/SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch new file mode 100644 index 0000000..65834d8 --- /dev/null +++ b/SOURCES/0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch @@ -0,0 +1,431 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Raymund Will +Date: Mon, 24 Oct 2022 14:33:50 -0400 +Subject: [PATCH] loader: Add support for grub-emu to kexec Linux menu entries + +The GRUB emulator is used as a debugging utility but it could also be +used as a user-space bootloader if there is support to boot an operating +system. + +The Linux kernel is already able to (re)boot another kernel via the +kexec boot mechanism. So the grub-emu tool could rely on this feature +and have linux and initrd commands that are used to pass a kernel, +initramfs image and command line parameters to kexec for booting +a selected menu entry. + +By default the systemctl kexec option is used so systemd can shutdown +all of the running services before doing a reboot using kexec. But if +this is not present, it can fall back to executing the kexec user-space +tool directly. The ability to force a kexec-reboot when systemctl kexec +fails must only be used in controlled environments to avoid possible +filesystem corruption and data loss. + +Signed-off-by: Raymund Will +Signed-off-by: John Jolly +Signed-off-by: Javier Martinez Canillas +Signed-off-by: Robbie Harwood +Reviewed-by: Daniel Kiper +(cherry picked from commit e364307f6acc2f631b4c1fefda0791b9ce1f205f) +[rharwood: conflicts around makefile and grub_exit return code] +--- + grub-core/Makefile.core.def | 3 - + grub-core/kern/emu/main.c | 4 + + grub-core/kern/emu/misc.c | 18 ++++- + grub-core/loader/emu/linux.c | 178 +++++++++++++++++++++++++++++++++++++++++++ + include/grub/emu/exec.h | 4 +- + include/grub/emu/hostfile.h | 3 +- + include/grub/emu/misc.h | 3 + + docs/grub.texi | 30 ++++++-- + grub-core/Makefile.am | 1 + + 9 files changed, 230 insertions(+), 14 deletions(-) + create mode 100644 grub-core/loader/emu/linux.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 741a033978..f21da23213 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1864,11 +1864,8 @@ module = { + riscv32 = loader/riscv/linux.c; + riscv64 = loader/riscv/linux.c; + emu = loader/emu/linux.c; +- + common = loader/linux.c; + common = lib/cmdline.c; +- enable = noemu; +- + efi = loader/efi/linux.c; + }; + +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 12277c34d2..68e2b283bb 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -107,6 +107,7 @@ static struct argp_option options[] = { + N_("use GRUB files in the directory DIR [default=%s]"), 0}, + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, ++ {"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -164,6 +165,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + case 'v': + verbosity++; + break; ++ case 'X': ++ grub_util_set_kexecute (); ++ break; + + case ARGP_KEY_ARG: + { +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index d278c2921f..02d27c3440 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -39,6 +39,7 @@ + #include + + int verbosity; ++int kexecute; + + void + grub_util_warn (const char *fmt, ...) +@@ -82,7 +83,7 @@ grub_util_error (const char *fmt, ...) + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, ".\n"); +- exit (1); ++ grub_exit (1); + } + + void * +@@ -154,6 +155,9 @@ void + __attribute__ ((noreturn)) + grub_exit (int rc) + { ++#if defined (GRUB_KERNEL) ++ grub_reboot (); ++#endif + exit (rc < 0 ? 1 : rc); + } + #endif +@@ -215,3 +219,15 @@ grub_util_load_image (const char *path, char *buf) + + fclose (fp); + } ++ ++void ++grub_util_set_kexecute (void) ++{ ++ kexecute++; ++} ++ ++int ++grub_util_get_kexecute (void) ++{ ++ return kexecute; ++} +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +new file mode 100644 +index 0000000000..0cf378a376 +--- /dev/null ++++ b/grub-core/loader/emu/linux.c +@@ -0,0 +1,178 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_dl_t my_mod; ++ ++static char *kernel_path; ++static char *initrd_path; ++static char *boot_cmdline; ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ grub_err_t rc = GRUB_ERR_NONE; ++ char *initrd_param; ++ const char *kexec[] = {"kexec", "-la", kernel_path, boot_cmdline, NULL, NULL}; ++ const char *systemctl[] = {"systemctl", "kexec", NULL}; ++ int kexecute = grub_util_get_kexecute (); ++ ++ if (initrd_path) ++ { ++ initrd_param = grub_xasprintf ("--initrd=%s", initrd_path); ++ kexec[3] = initrd_param; ++ kexec[4] = boot_cmdline; ++ } ++ else ++ initrd_param = grub_xasprintf ("%s", ""); ++ ++ grub_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n", ++ (kexecute) ? "P" : "Not p", ++ kernel_path, initrd_param, boot_cmdline); ++ ++ if (kexecute) ++ rc = grub_util_exec (kexec); ++ ++ grub_free (initrd_param); ++ ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_error (rc, N_("error trying to perform kexec load operation")); ++ grub_sleep (3); ++ return rc; ++ } ++ ++ if (kexecute < 1) ++ grub_fatal (N_("use '"PACKAGE"-emu --kexec' to force a system restart")); ++ ++ grub_dprintf ("linux", "Performing 'systemctl kexec' (%s) ", ++ (kexecute==1) ? "do-or-die" : "just-in-case"); ++ rc = grub_util_exec (systemctl); ++ ++ if (kexecute == 1) ++ grub_fatal (N_("error trying to perform 'systemctl kexec': %d"), rc); ++ ++ /* ++ * WARNING: forcible reset should only be used in read-only environments. ++ * grub-emu cannot check for these - users beware. ++ */ ++ grub_dprintf ("linux", "Performing 'kexec -ex'"); ++ kexec[1] = "-ex"; ++ kexec[2] = NULL; ++ rc = grub_util_exec (kexec); ++ if (rc != GRUB_ERR_NONE) ++ grub_fatal (N_("error trying to directly perform 'kexec -ex': %d"), rc); ++ ++ return rc; ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ /* Unloading: we're no longer in use. */ ++ grub_dl_unref (my_mod); ++ grub_free (boot_cmdline); ++ boot_cmdline = NULL; ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char *argv[]) ++{ ++ int i; ++ char *tempstr; ++ ++ /* Mark ourselves as in-use. */ ++ grub_dl_ref (my_mod); ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if (!grub_util_is_regular (argv[0])) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("cannot find kernel file %s"), argv[0]); ++ ++ grub_free (kernel_path); ++ kernel_path = grub_xasprintf ("%s", argv[0]); ++ ++ grub_free (boot_cmdline); ++ boot_cmdline = NULL; ++ ++ if (argc > 1) ++ { ++ boot_cmdline = grub_xasprintf ("--command-line=%s", argv[1]); ++ for (i = 2; i < argc; i++) ++ { ++ tempstr = grub_xasprintf ("%s %s", boot_cmdline, argv[i]); ++ grub_free (boot_cmdline); ++ boot_cmdline = tempstr; ++ } ++ } ++ ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, ++ char *argv[]) ++{ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if (!grub_util_is_regular (argv[0])) ++ return grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ N_("Cannot find initrd file %s"), argv[0]); ++ ++ grub_free (initrd_path); ++ initrd_path = grub_xasprintf ("%s", argv[0]); ++ ++ /* We are done - mark ourselves as on longer in use. */ ++ grub_dl_unref (my_mod); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT (linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0, ++ N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0, ++ N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI (linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h +index d1073ef86a..1b61b4a2e5 100644 +--- a/include/grub/emu/exec.h ++++ b/include/grub/emu/exec.h +@@ -23,6 +23,8 @@ + #include + + #include ++#include ++ + pid_t + grub_util_exec_pipe (const char *const *argv, int *fd); + pid_t +@@ -32,7 +34,7 @@ int + grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file, + const char *stdout_file, const char *stderr_file); + int +-grub_util_exec (const char *const *argv); ++EXPORT_FUNC(grub_util_exec) (const char *const *argv); + int + grub_util_exec_redirect (const char *const *argv, const char *stdin_file, + const char *stdout_file); +diff --git a/include/grub/emu/hostfile.h b/include/grub/emu/hostfile.h +index cfb1e2b566..a61568e36e 100644 +--- a/include/grub/emu/hostfile.h ++++ b/include/grub/emu/hostfile.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + int +@@ -29,7 +30,7 @@ grub_util_is_directory (const char *path); + int + grub_util_is_special_file (const char *path); + int +-grub_util_is_regular (const char *path); ++EXPORT_FUNC(grub_util_is_regular) (const char *path); + + char * + grub_util_path_concat (size_t n, ...); +diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h +index ff9c48a649..01056954b9 100644 +--- a/include/grub/emu/misc.h ++++ b/include/grub/emu/misc.h +@@ -57,6 +57,9 @@ void EXPORT_FUNC(grub_util_warn) (const char *fmt, ...) __attribute__ ((format ( + void EXPORT_FUNC(grub_util_info) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); + void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2), noreturn)); + ++void EXPORT_FUNC(grub_util_set_kexecute) (void); ++int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT; ++ + grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); + + #ifdef HAVE_DEVICE_MAPPER +diff --git a/docs/grub.texi b/docs/grub.texi +index a4da9c2a1b..1750b72ee9 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -923,17 +923,17 @@ magic. + @node General boot methods + @section How to boot operating systems + +-GRUB has two distinct boot methods. One of the two is to load an +-operating system directly, and the other is to chain-load another boot +-loader which then will load an operating system actually. Generally +-speaking, the former is more desirable, because you don't need to +-install or maintain other boot loaders and GRUB is flexible enough to +-load an operating system from an arbitrary disk/partition. However, +-the latter is sometimes required, since GRUB doesn't support all the +-existing operating systems natively. ++GRUB has three distinct boot methods: loading an operating system ++directly, using kexec from userspace, and chainloading another ++bootloader. Generally speaking, the first two are more desirable ++because you don't need to install or maintain other boot loaders and ++GRUB is flexible enough to load an operating system from an arbitrary ++disk/partition. However, chainloading is sometimes required, as GRUB ++doesn't support all existing operating systems natively. + + @menu + * Loading an operating system directly:: ++* Kexec:: + * Chain-loading:: + @end menu + +@@ -959,6 +959,20 @@ use more complicated instructions. @xref{DOS/Windows}, for more + information. + + ++@node Kexec ++@subsection Kexec with grub2-emu ++ ++GRUB can be run in userspace by invoking the grub2-emu tool. It will ++read all configuration scripts as if booting directly (see @xref{Loading ++an operating system directly}). With the @code{--kexec} flag, and ++kexec(8) support from the operating system, the @command{linux} command ++will directly boot the target image. For systems that lack working ++systemctl(1) support for kexec, passing the @code{--kexec} flag twice ++will fallback to invoking kexec(8) directly; note however that this ++fallback may be unsafe outside read-only environments, as it does not ++invoke shutdown machinery. ++ ++ + @node Chain-loading + @subsection Chain-loading an OS + +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index c2e8a82bce..dd49939aaa 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -309,6 +309,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/net.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostdisk.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/hostfile.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/exec.h + if COND_GRUB_EMU_SDL + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/sdl.h + endif diff --git a/SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch b/SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch new file mode 100644 index 0000000..735075a --- /dev/null +++ b/SOURCES/0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 6 Sep 2021 15:46:12 +1000 +Subject: [PATCH] powerpc: Drop Open Hack'Ware - remove + GRUB_IEEE1275_FLAG_FORCE_CLAIM + +Open Hack'Ware was the only user. It added a lot of complexity. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 333e63b356f1ce833cda1937ed8351618cbdf9d3) +--- + grub-core/kern/ieee1275/init.c | 6 +----- + grub-core/lib/ieee1275/relocator.c | 4 ---- + grub-core/loader/powerpc/ieee1275/linux.c | 14 -------------- + include/grub/ieee1275/ieee1275.h | 11 ----------- + 4 files changed, 1 insertion(+), 34 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 0dcd114ce5..6581c2c996 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -207,11 +207,7 @@ grub_claim_heap (void) + { + unsigned long total = 0; + +- if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) +- heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, +- 1, &total); +- else +- grub_machine_mmap_iterate (heap_init, &total); ++ grub_machine_mmap_iterate (heap_init, &total); + } + #endif + +diff --git a/grub-core/lib/ieee1275/relocator.c b/grub-core/lib/ieee1275/relocator.c +index c6dd8facb0..d1bb45c75e 100644 +--- a/grub-core/lib/ieee1275/relocator.c ++++ b/grub-core/lib/ieee1275/relocator.c +@@ -38,8 +38,6 @@ grub_relocator_firmware_get_max_events (void) + { + int counter = 0; + +- if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) +- return 0; + grub_machine_mmap_iterate (count, &counter); + return 2 * counter; + } +@@ -92,8 +90,6 @@ grub_relocator_firmware_fill_events (struct grub_relocator_mmap_event *events) + .counter = 0 + }; + +- if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) +- return 0; + grub_machine_mmap_iterate (grub_relocator_firmware_fill_events_iter, &ctx); + return ctx.counter; + } +diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c +index 818b2a86d1..6fdd863130 100644 +--- a/grub-core/loader/powerpc/ieee1275/linux.c ++++ b/grub-core/loader/powerpc/ieee1275/linux.c +@@ -111,20 +111,6 @@ grub_linux_claimmap_iterate (grub_addr_t target, grub_size_t size, + .found_addr = (grub_addr_t) -1 + }; + +- if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) +- { +- grub_uint64_t addr = target; +- if (addr < GRUB_IEEE1275_STATIC_HEAP_START +- + GRUB_IEEE1275_STATIC_HEAP_LEN) +- addr = GRUB_IEEE1275_STATIC_HEAP_START +- + GRUB_IEEE1275_STATIC_HEAP_LEN; +- addr = ALIGN_UP (addr, align); +- if (grub_claimmap (addr, size) == GRUB_ERR_NONE) +- return addr; +- return (grub_addr_t) -1; +- } +- +- + grub_machine_mmap_iterate (alloc_mem, &ctx); + + return ctx.found_addr; +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index b5a1d49bbc..6a1d3e5d70 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -85,14 +85,6 @@ extern grub_ieee1275_ihandle_t EXPORT_VAR(grub_ieee1275_mmu); + + extern int (* EXPORT_VAR(grub_ieee1275_entry_fn)) (void *) GRUB_IEEE1275_ENTRY_FN_ATTRIBUTE; + +-/* Static heap, used only if FORCE_CLAIM is set, +- happens on Open Hack'Ware. Should be in platform-specific +- header but is used only on PPC anyway. +-*/ +-#define GRUB_IEEE1275_STATIC_HEAP_START 0x1000000 +-#define GRUB_IEEE1275_STATIC_HEAP_LEN 0x1000000 +- +- + enum grub_ieee1275_flag + { + /* Old World Macintosh firmware fails seek when "dev:0" is opened. */ +@@ -119,9 +111,6 @@ enum grub_ieee1275_flag + /* Open Hack'Ware stops when grub_ieee1275_interpret is used. */ + GRUB_IEEE1275_FLAG_CANNOT_INTERPRET, + +- /* Open Hack'Ware has no memory map, just claim what we need. */ +- GRUB_IEEE1275_FLAG_FORCE_CLAIM, +- + /* Open Hack'Ware don't support the ANSI sequence. */ + GRUB_IEEE1275_FLAG_NO_ANSI, + diff --git a/SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch b/SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch new file mode 100644 index 0000000..4e95630 --- /dev/null +++ b/SOURCES/0313-ieee1275-request-memory-with-ibm-client-architecture.patch @@ -0,0 +1,308 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 6 Feb 2023 10:03:20 -0500 +Subject: [PATCH] ieee1275: request memory with ibm, + client-architecture-support + +On PowerVM, the first time we boot a Linux partition, we may only get +256MB of real memory area, even if the partition has more memory. + +This isn't enough to reliably verify a kernel. Fortunately, the Power +Architecture Platform Reference (PAPR) defines a method we can call to ask +for more memory: the broad and powerful ibm,client-architecture-support +(CAS) method. + +CAS can do an enormous amount of things on a PAPR platform: as well as +asking for memory, you can set the supported processor level, the interrupt +controller, hash vs radix mmu, and so on. + +If: + + - we are running under what we think is PowerVM (compatible property of / + begins with "IBM"), and + + - the full amount of RMA is less than 512MB (as determined by the reg + property of /memory) + +then call CAS as follows: (refer to the Linux on Power Architecture +Reference, LoPAR, which is public, at B.5.2.3): + + - Use the "any" PVR value and supply 2 option vectors. + + - Set option vector 1 (PowerPC Server Processor Architecture Level) + to "ignore". + + - Set option vector 2 with default or Linux-like options, including a + min-rma-size of 512MB. + + - Set option vector 3 to request Floating Point, VMX and Decimal Floating + point, but don't abort the boot if we can't get them. + + - Set option vector 4 to request a minimum VP percentage to 1%, which is + what Linux requests, and is below the default of 10%. Without this, + some systems with very large or very small configurations fail to boot. + +This will cause a CAS reboot and the partition will restart with 512MB +of RMA. Importantly, grub will notice the 512MB and not call CAS again. + +Notes about the choices of parameters: + + - A partition can be configured with only 256MB of memory, which would + mean this request couldn't be satisfied, but PFW refuses to load with + only 256MB of memory, so it's a bit moot. SLOF will run fine with 256MB, + but we will never call CAS under qemu/SLOF because /compatible won't + begin with "IBM".) + + - unspecified CAS vectors take on default values. Some of these values + might restrict the ability of certain hardware configurations to boot. + This is why we need to specify the VP percentage in vector 4, which is + in turn why we need to specify vector 3. + +Finally, we should have enough memory to verify a kernel, and we will +reach Linux. One of the first things Linux does while still running under +OpenFirmware is to call CAS with a much fuller set of options (including +asking for 512MB of memory). Linux includes a much more restrictive set of +PVR values and processor support levels, and this CAS invocation will likely +induce another reboot. On this reboot grub will again notice the higher RMA, +and not call CAS. We will get to Linux again, Linux will call CAS again, but +because the values are now set for Linux this will not induce another CAS +reboot and we will finally boot all the way to userspace. + +On all subsequent boots, everything will be configured with 512MB of RMA, +so there will be no further CAS reboots from grub. (phyp is super sticky +with the RMA size - it persists even on cold boots. So if you've ever booted +Linux in a partition, you'll probably never have grub call CAS. It'll only +ever fire the first time a partition loads grub, or if you deliberately lower +the amount of memory your partition has below 512MB.) + +Signed-off-by: Daniel Axtens +Signed-off-by: Stefan Berger +Reviewed-by: Daniel Kiper +(cherry picked from commit d5571590b7de61887efac1c298901455697ba307) +--- + grub-core/kern/ieee1275/cmain.c | 5 ++ + grub-core/kern/ieee1275/init.c | 167 ++++++++++++++++++++++++++++++++++++++- + include/grub/ieee1275/ieee1275.h | 12 ++- + 3 files changed, 182 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c +index 04df9d2c66..dce7b84922 100644 +--- a/grub-core/kern/ieee1275/cmain.c ++++ b/grub-core/kern/ieee1275/cmain.c +@@ -127,6 +127,11 @@ grub_ieee1275_find_options (void) + break; + } + } ++ ++#if defined(__powerpc__) ++ if (grub_strncmp (tmp, "IBM,", 4) == 0) ++ grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY); ++#endif + } + + if (is_smartfirmware) +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 6581c2c996..8ae405bc79 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -202,11 +202,176 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + return 0; + } + +-static void ++/* ++ * How much memory does OF believe it has? (regardless of whether ++ * it's accessible or not) ++ */ ++static grub_err_t ++grub_ieee1275_total_mem (grub_uint64_t *total) ++{ ++ grub_ieee1275_phandle_t root; ++ grub_ieee1275_phandle_t memory; ++ grub_uint32_t reg[4]; ++ grub_ssize_t reg_size; ++ grub_uint32_t address_cells = 1; ++ grub_uint32_t size_cells = 1; ++ grub_uint64_t size; ++ ++ /* If we fail to get to the end, report 0. */ ++ *total = 0; ++ ++ /* Determine the format of each entry in `reg'. */ ++ if (grub_ieee1275_finddevice ("/", &root)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node"); ++ if (grub_ieee1275_get_integer_property (root, "#address-cells", &address_cells, ++ sizeof (address_cells), 0)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #address-cells"); ++ if (grub_ieee1275_get_integer_property (root, "#size-cells", &size_cells, ++ sizeof (size_cells), 0)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine #size-cells"); ++ ++ if (size_cells > address_cells) ++ address_cells = size_cells; ++ ++ /* Load `/memory/reg'. */ ++ if (grub_ieee1275_finddevice ("/memory", &memory)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find /memory node"); ++ if (grub_ieee1275_get_integer_property (memory, "reg", reg, ++ sizeof (reg), ®_size)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /memory/reg property"); ++ if (reg_size < 0 || (grub_size_t) reg_size > sizeof (reg)) ++ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "/memory response buffer exceeded"); ++ ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_BROKEN_ADDRESS_CELLS)) ++ { ++ address_cells = 1; ++ size_cells = 1; ++ } ++ ++ /* Decode only the size */ ++ size = reg[address_cells]; ++ if (size_cells == 2) ++ size = (size << 32) | reg[address_cells + 1]; ++ ++ *total = size; ++ ++ return grub_errno; ++} ++ ++#if defined(__powerpc__) ++ ++/* See PAPR or arch/powerpc/kernel/prom_init.c */ ++struct option_vector2 ++{ ++ grub_uint8_t byte1; ++ grub_uint16_t reserved; ++ grub_uint32_t real_base; ++ grub_uint32_t real_size; ++ grub_uint32_t virt_base; ++ grub_uint32_t virt_size; ++ grub_uint32_t load_base; ++ grub_uint32_t min_rma; ++ grub_uint32_t min_load; ++ grub_uint8_t min_rma_percent; ++ grub_uint8_t max_pft_size; ++} GRUB_PACKED; ++ ++struct pvr_entry ++{ ++ grub_uint32_t mask; ++ grub_uint32_t entry; ++}; ++ ++struct cas_vector ++{ ++ struct ++ { ++ struct pvr_entry terminal; ++ } pvr_list; ++ grub_uint8_t num_vecs; ++ grub_uint8_t vec1_size; ++ grub_uint8_t vec1; ++ grub_uint8_t vec2_size; ++ struct option_vector2 vec2; ++ grub_uint8_t vec3_size; ++ grub_uint16_t vec3; ++ grub_uint8_t vec4_size; ++ grub_uint16_t vec4; ++} GRUB_PACKED; ++ ++/* ++ * Call ibm,client-architecture-support to try to get more RMA. ++ * We ask for 512MB which should be enough to verify a distro kernel. ++ * We ignore most errors: if we don't succeed we'll proceed with whatever ++ * memory we have. ++ */ ++static void ++grub_ieee1275_ibm_cas (void) ++{ ++ int rc; ++ grub_ieee1275_ihandle_t root; ++ struct cas_args ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_ihandle_t ihandle; ++ grub_ieee1275_cell_t cas_addr; ++ grub_ieee1275_cell_t result; ++ } args; ++ struct cas_vector vector = ++ { ++ .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ ++ .num_vecs = 4 - 1, ++ .vec1_size = 0, ++ .vec1 = 0x80, /* ignore */ ++ .vec2_size = 1 + sizeof (struct option_vector2) - 2, ++ .vec2 = { ++ 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48 ++ }, ++ .vec3_size = 2 - 1, ++ .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */ ++ .vec4_size = 2 - 1, ++ .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ ++ }; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); ++ args.method = (grub_ieee1275_cell_t) "ibm,client-architecture-support"; ++ rc = grub_ieee1275_open ("/", &root); ++ if (rc) ++ { ++ grub_error (GRUB_ERR_IO, "could not open root when trying to call CAS"); ++ return; ++ } ++ args.ihandle = root; ++ args.cas_addr = (grub_ieee1275_cell_t) &vector; ++ ++ grub_printf ("Calling ibm,client-architecture-support from grub..."); ++ IEEE1275_CALL_ENTRY_FN (&args); ++ grub_printf ("done\n"); ++ ++ grub_ieee1275_close (root); ++} ++ ++#endif /* __powerpc__ */ ++ ++static void + grub_claim_heap (void) + { + unsigned long total = 0; + ++#if defined(__powerpc__) ++ if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) ++ { ++ grub_uint64_t rma_size; ++ grub_err_t err; ++ ++ err = grub_ieee1275_total_mem (&rma_size); ++ /* if we have an error, don't call CAS, just hope for the best */ ++ if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024)) ++ grub_ieee1275_ibm_cas (); ++ } ++#endif ++ + grub_machine_mmap_iterate (heap_init, &total); + } + #endif +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index 6a1d3e5d70..560c968460 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -138,7 +138,17 @@ enum grub_ieee1275_flag + + GRUB_IEEE1275_FLAG_RAW_DEVNAMES, + +- GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT ++ GRUB_IEEE1275_FLAG_DISABLE_VIDEO_SUPPORT, ++ ++#if defined(__powerpc__) ++ /* ++ * On PFW, the first time we boot a Linux partition, we may only get 256MB of ++ * real memory area, even if the partition has more memory. Set this flag if ++ * we think we're running under PFW. Then, if this flag is set, and the RMA is ++ * only 256MB in size, try asking for more with CAS. ++ */ ++ GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY, ++#endif + }; + + extern int EXPORT_FUNC(grub_ieee1275_test_flag) (enum grub_ieee1275_flag flag); diff --git a/SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch b/SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch new file mode 100644 index 0000000..4ce064b --- /dev/null +++ b/SOURCES/0314-ieee1275-drop-len-1-quirk-in-heap_init.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 6 Feb 2023 10:03:21 -0500 +Subject: [PATCH] ieee1275: drop len -= 1 quirk in heap_init + +This was apparently 'required by some firmware': commit dc9468500919 +("2007-02-12 Hollis Blanchard "). + +It's not clear what firmware that was, and what platform from 14 years ago +which exhibited the bug then is still both in use and buggy now. + +It doesn't cause issues on qemu (mac99 or pseries) or under PFW for Power8. + +I don't have access to old Mac hardware, but if anyone feels especially +strongly we can put it under some feature flag. I really want to disable +it under pseries because it will mess with region merging. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit fc639d430297321ee4f77c5d2d698f698cec0dc7) +--- + grub-core/kern/ieee1275/init.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 8ae405bc79..c8d551759d 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -168,7 +168,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + addr = 0x180000; + } + } +- len -= 1; /* Required for some firmware. */ + + /* Never exceed HEAP_MAX_SIZE */ + if (*total + len > HEAP_MAX_SIZE) diff --git a/SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch b/SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch new file mode 100644 index 0000000..17ad61d --- /dev/null +++ b/SOURCES/0315-ieee1275-support-runtime-memory-claiming.patch @@ -0,0 +1,435 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 6 Feb 2023 10:03:22 -0500 +Subject: [PATCH] ieee1275: support runtime memory claiming + +On powerpc-ieee1275, we are running out of memory trying to verify +anything. This is because: + + - we have to load an entire file into memory to verify it. This is + difficult to change with appended signatures. + - We only have 32MB of heap. + - Distro kernels are now often around 30MB. + +So we want to be able to claim more memory from OpenFirmware for our heap +at runtime. + +There are some complications: + + - The grub mm code isn't the only thing that will make claims on + memory from OpenFirmware: + + * PFW/SLOF will have claimed some for their own use. + + * The ieee1275 loader will try to find other bits of memory that we + haven't claimed to place the kernel and initrd when we go to boot. + + * Once we load Linux, it will also try to claim memory. It claims + memory without any reference to /memory/available, it just starts + at min(top of RMO, 768MB) and works down. So we need to avoid this + area. See arch/powerpc/kernel/prom_init.c as of v5.11. + + - The smallest amount of memory a ppc64 KVM guest can have is 256MB. + It doesn't work with distro kernels but can work with custom kernels. + We should maintain support for that. (ppc32 can boot with even less, + and we shouldn't break that either.) + + - Even if a VM has more memory, the memory OpenFirmware makes available + as Real Memory Area can be restricted. Even with our CAS work, an LPAR + on a PowerVM box is likely to have only 512MB available to OpenFirmware + even if it has many gigabytes of memory allocated. + +What should we do? + +We don't know in advance how big the kernel and initrd are going to be, +which makes figuring out how much memory we can take a bit tricky. + +To figure out how much memory we should leave unused, I looked at: + + - an Ubuntu 20.04.1 ppc64le pseries KVM guest: + vmlinux: ~30MB + initrd: ~50MB + + - a RHEL8.2 ppc64le pseries KVM guest: + vmlinux: ~30MB + initrd: ~30MB + +So to give us a little wriggle room, I think we want to leave at least +128MB for the loader to put vmlinux and initrd in memory and leave Linux +with space to satisfy its early allocations. + +Allow other space to be allocated at runtime. + +Tested-by: Stefan Berger +Signed-off-by: Daniel Axtens +(cherry picked from commit a5c710789ccdd27a84ae4a34c7d453bd585e2b66) +[rharwood: _start?] +--- + grub-core/kern/ieee1275/init.c | 270 ++++++++++++++++++++++++++++++++++++++--- + docs/grub-dev.texi | 7 +- + 2 files changed, 257 insertions(+), 20 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index c8d551759d..85af8fa97b 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -46,13 +46,26 @@ + #endif + #include + +-/* The maximum heap size we're going to claim */ ++/* The maximum heap size we're going to claim at boot. Not used by sparc. */ + #ifdef __i386__ + #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) +-#else ++#else /* __powerpc__ */ + #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) + #endif + ++/* RMO max. address at 768 MB */ ++#define RMO_ADDR_MAX (grub_uint64_t) (768 * 1024 * 1024) ++ ++/* ++ * The amount of OF space we will not claim here so as to leave space for ++ * the loader and linux to service early allocations. ++ * ++ * In 2021, Daniel Axtens claims that we should leave at least 128MB to ++ * ensure we can load a stock kernel and initrd on a pseries guest with ++ * a 512MB real memory area under PowerVM. ++ */ ++#define RUNTIME_MIN_SPACE (128UL * 1024 * 1024) ++ + extern char _end[]; + + #ifdef __sparc__ +@@ -147,16 +160,52 @@ grub_claim_heap (void) + + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); + } + #else +-/* Helper for grub_claim_heap. */ ++/* Helpers for mm on powerpc. */ ++ ++/* ++ * How much memory does OF believe exists in total? ++ * ++ * This isn't necessarily the true total. It can be the total memory ++ * accessible in real mode for a pseries guest, for example. ++ */ ++static grub_uint64_t rmo_top; ++ + static int +-heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, +- void *data) ++count_free (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, ++ void *data) + { +- unsigned long *total = data; ++ if (type != GRUB_MEMORY_AVAILABLE) ++ return 0; ++ ++ /* Do not consider memory beyond 4GB */ ++ if (addr > 0xffffffffULL) ++ return 0; ++ ++ if (addr + len > 0xffffffffULL) ++ len = 0xffffffffULL - addr; ++ ++ *(grub_uint32_t *) data += len; ++ ++ return 0; ++} ++ ++static int ++regions_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, ++ unsigned int flags, void *data) ++{ ++ grub_uint32_t total = *(grub_uint32_t *) data; ++ grub_uint64_t linux_rmo_save; + + if (type != GRUB_MEMORY_AVAILABLE) + return 0; + ++ /* Do not consider memory beyond 4GB */ ++ if (addr > 0xffffffffULL) ++ return 0; ++ ++ if (addr + len > 0xffffffffULL) ++ len = 0xffffffffULL - addr; ++ + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) + { + if (addr + len <= 0x180000) +@@ -169,10 +218,6 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + } + } + +- /* Never exceed HEAP_MAX_SIZE */ +- if (*total + len > HEAP_MAX_SIZE) +- len = HEAP_MAX_SIZE - *total; +- + /* In theory, firmware should already prevent this from happening by not + listing our own image in /memory/available. The check below is intended + as a safeguard in case that doesn't happen. However, it doesn't protect +@@ -184,6 +229,108 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + len = 0; + } + ++ /* ++ * Linux likes to claim memory at min(RMO top, 768MB) and works down ++ * without reference to /memory/available. (See prom_init.c::alloc_down) ++ * ++ * If this block contains min(RMO top, 768MB), do not claim below that for ++ * at least a few MB (this is where RTAS, SML and potentially TCEs live). ++ * ++ * We also need to leave enough space for the DT in the RMA. (See ++ * prom_init.c::alloc_up) ++ * ++ * Finally, we also want to make sure that when grub loads the kernel, ++ * it isn't going to use up all the memory we're trying to reserve! So ++ * enforce our entire RUNTIME_MIN_SPACE here: ++ * ++ * |---------- Top of memory ----------| ++ * | | ++ * | available | ++ * | | ++ * |---------- 768 MB ----------| ++ * | | ++ * | reserved | ++ * | | ++ * |--- 768 MB - runtime min space ---| ++ * | | ++ * | available | ++ * | | ++ * |---------- 0 MB ----------| ++ * ++ * Edge cases: ++ * ++ * - Total memory less than RUNTIME_MIN_SPACE: only claim up to HEAP_MAX_SIZE. ++ * (enforced elsewhere) ++ * ++ * - Total memory between RUNTIME_MIN_SPACE and 768MB: ++ * ++ * |---------- Top of memory ----------| ++ * | | ++ * | reserved | ++ * | | ++ * |---- top - runtime min space ----| ++ * | | ++ * | available | ++ * | | ++ * |---------- 0 MB ----------| ++ * ++ * This by itself would not leave us with RUNTIME_MIN_SPACE of free bytes: if ++ * rmo_top < 768MB, we will almost certainly have FW claims in the reserved ++ * region. We try to address that elsewhere: grub_ieee1275_mm_add_region will ++ * not call us if the resulting free space would be less than RUNTIME_MIN_SPACE. ++ */ ++ linux_rmo_save = grub_min (RMO_ADDR_MAX, rmo_top) - RUNTIME_MIN_SPACE; ++ if (rmo_top > RUNTIME_MIN_SPACE) ++ { ++ if (rmo_top <= RMO_ADDR_MAX) ++ { ++ if (addr > linux_rmo_save) ++ { ++ grub_dprintf ("ieee1275", "rejecting region in RUNTIME_MIN_SPACE reservation (%llx)\n", ++ addr); ++ return 0; ++ } ++ else if (addr + len > linux_rmo_save) ++ { ++ grub_dprintf ("ieee1275", "capping region: (%llx -> %llx) -> (%llx -> %llx)\n", ++ addr, addr + len, addr, rmo_top - RUNTIME_MIN_SPACE); ++ len = linux_rmo_save - addr; ++ } ++ } ++ else ++ { ++ /* ++ * we order these cases to prefer higher addresses and avoid some ++ * splitting issues ++ */ ++ if (addr < RMO_ADDR_MAX && (addr + len) > RMO_ADDR_MAX) ++ { ++ grub_dprintf ("ieee1275", ++ "adjusting region for RUNTIME_MIN_SPACE: (%llx -> %llx) -> (%llx -> %llx)\n", ++ addr, addr + len, RMO_ADDR_MAX, addr + len); ++ len = (addr + len) - RMO_ADDR_MAX; ++ addr = RMO_ADDR_MAX; ++ } ++ else if ((addr < linux_rmo_save) && ((addr + len) > linux_rmo_save)) ++ { ++ grub_dprintf ("ieee1275", "capping region: (%llx -> %llx) -> (%llx -> %llx)\n", ++ addr, addr + len, addr, linux_rmo_save); ++ len = linux_rmo_save - addr; ++ } ++ else if (addr >= linux_rmo_save && (addr + len) <= RMO_ADDR_MAX) ++ { ++ grub_dprintf ("ieee1275", "rejecting region in RUNTIME_MIN_SPACE reservation (%llx)\n", ++ addr); ++ return 0; ++ } ++ } ++ } ++ if (flags & GRUB_MM_ADD_REGION_CONSECUTIVE && len < total) ++ return 0; ++ ++ if (len > total) ++ len = total; ++ + if (len) + { + grub_err_t err; +@@ -192,15 +339,95 @@ heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + if (err) + return err; + grub_mm_init_region ((void *) (grub_addr_t) addr, len); ++ total -= len; + } + +- *total += len; +- if (*total >= HEAP_MAX_SIZE) ++ *(grub_uint32_t *) data = total; ++ ++ if (total == 0) + return 1; + + return 0; + } + ++static int ++heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, ++ void *data) ++{ ++ return regions_claim (addr, len, type, GRUB_MM_ADD_REGION_NONE, data); ++} ++ ++static int ++region_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, ++ void *data) ++{ ++ return regions_claim (addr, len, type, GRUB_MM_ADD_REGION_CONSECUTIVE, data); ++} ++ ++static grub_err_t ++grub_ieee1275_mm_add_region (grub_size_t size, unsigned int flags) ++{ ++ grub_uint32_t free_memory = 0; ++ grub_uint32_t avail = 0; ++ grub_uint32_t total; ++ ++ grub_dprintf ("ieee1275", "mm requested region of size %x, flags %x\n", ++ size, flags); ++ ++ /* ++ * Update free memory each time, which is a bit inefficient but guards us ++ * against a situation where some OF driver goes out to firmware for ++ * memory and we don't realise. ++ */ ++ grub_machine_mmap_iterate (count_free, &free_memory); ++ ++ /* Ensure we leave enough space to boot. */ ++ if (free_memory <= RUNTIME_MIN_SPACE + size) ++ { ++ grub_dprintf ("ieee1275", "Cannot satisfy allocation and retain minimum runtime space\n"); ++ return GRUB_ERR_OUT_OF_MEMORY; ++ } ++ ++ if (free_memory > RUNTIME_MIN_SPACE) ++ avail = free_memory - RUNTIME_MIN_SPACE; ++ ++ grub_dprintf ("ieee1275", "free = 0x%x available = 0x%x\n", free_memory, avail); ++ ++ if (flags & GRUB_MM_ADD_REGION_CONSECUTIVE) ++ { ++ /* first try rounding up hard for the sake of speed */ ++ total = grub_max (ALIGN_UP (size, 1024 * 1024) + 1024 * 1024, 32 * 1024 * 1024); ++ total = grub_min (avail, total); ++ ++ grub_dprintf ("ieee1275", "looking for %x bytes of memory (%x requested)\n", total, size); ++ ++ grub_machine_mmap_iterate (region_claim, &total); ++ grub_dprintf ("ieee1275", "get memory from fw %s\n", total == 0 ? "succeeded" : "failed"); ++ ++ if (total != 0) ++ { ++ total = grub_min (avail, size); ++ ++ grub_dprintf ("ieee1275", "fallback for %x bytes of memory (%x requested)\n", total, size); ++ ++ grub_machine_mmap_iterate (region_claim, &total); ++ grub_dprintf ("ieee1275", "fallback from fw %s\n", total == 0 ? "succeeded" : "failed"); ++ } ++ } ++ else ++ { ++ /* provide padding for a grub_mm_header_t and region */ ++ total = grub_min (avail, size); ++ grub_machine_mmap_iterate (heap_init, &total); ++ grub_dprintf ("ieee1275", "get noncontig memory from fw %s\n", total == 0 ? "succeeded" : "failed"); ++ } ++ ++ if (total == 0) ++ return GRUB_ERR_NONE; ++ else ++ return GRUB_ERR_OUT_OF_MEMORY; ++} ++ + /* + * How much memory does OF believe it has? (regardless of whether + * it's accessible or not) +@@ -356,17 +583,24 @@ grub_ieee1275_ibm_cas (void) + static void + grub_claim_heap (void) + { +- unsigned long total = 0; ++ grub_err_t err; ++ grub_uint32_t total = HEAP_MAX_SIZE; ++ ++ err = grub_ieee1275_total_mem (&rmo_top); ++ ++ /* ++ * If we cannot size the available memory, we can't be sure we're leaving ++ * space for the kernel, initrd and things Linux loads early in boot. So only ++ * allow further allocations from firmware on success ++ */ ++ if (err == GRUB_ERR_NONE) ++ grub_mm_add_region_fn = grub_ieee1275_mm_add_region; + + #if defined(__powerpc__) + if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY)) + { +- grub_uint64_t rma_size; +- grub_err_t err; +- +- err = grub_ieee1275_total_mem (&rma_size); + /* if we have an error, don't call CAS, just hope for the best */ +- if (err == GRUB_ERR_NONE && rma_size < (512 * 1024 * 1024)) ++ if (err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024)) + grub_ieee1275_ibm_cas (); + } + #endif +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 7b2455a8fe..7edc5b7e2b 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -1047,7 +1047,10 @@ space is limited to 4GiB. GRUB allocates pages from EFI for its heap, at most + 1.6 GiB. + + On i386-ieee1275 and powerpc-ieee1275 GRUB uses same stack as IEEE1275. +-It allocates at most 32MiB for its heap. ++ ++On i386-ieee1275 and powerpc-ieee1275, GRUB will allocate 32MiB for its heap on ++startup. It may allocate more at runtime, as long as at least 128MiB remain free ++in OpenFirmware. + + On sparc64-ieee1275 stack is 256KiB and heap is 2MiB. + +@@ -1075,7 +1078,7 @@ In short: + @item i386-qemu @tab 60 KiB @tab < 4 GiB + @item *-efi @tab ? @tab < 1.6 GiB + @item i386-ieee1275 @tab ? @tab < 32 MiB +-@item powerpc-ieee1275 @tab ? @tab < 32 MiB ++@item powerpc-ieee1275 @tab ? @tab available memory - 128MiB + @item sparc64-ieee1275 @tab 256KiB @tab 2 MiB + @item arm-uboot @tab 256KiB @tab 2 MiB + @item mips(el)-qemu_mips @tab 2MiB @tab 253 MiB diff --git a/SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch b/SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch new file mode 100644 index 0000000..fad39db --- /dev/null +++ b/SOURCES/0316-ieee1275-implement-vec5-for-cas-negotiation.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Diego Domingos +Date: Mon, 6 Feb 2023 10:03:23 -0500 +Subject: [PATCH] ieee1275: implement vec5 for cas negotiation + +As a legacy support, if the vector 5 is not implemented, Power Hypervisor will +consider the max CPUs as 64 instead 256 currently supported during +client-architecture-support negotiation. + +This patch implements the vector 5 and set the MAX CPUs to 256 while setting the +others values to 0 (default). + +Signed-off-by: Diego Domingos +Acked-by: Daniel Axtens +Signed-off-by: Stefan Berger +Signed-off-by: Avnish Chouhan +(cherry picked from commit 942f19959fe7465fb52a1da39ff271a7ab704892) +--- + grub-core/kern/ieee1275/init.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 85af8fa97b..72d4fed312 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -502,6 +502,19 @@ struct option_vector2 + grub_uint8_t max_pft_size; + } GRUB_PACKED; + ++struct option_vector5 ++{ ++ grub_uint8_t byte1; ++ grub_uint8_t byte2; ++ grub_uint8_t byte3; ++ grub_uint8_t cmo; ++ grub_uint8_t associativity; ++ grub_uint8_t bin_opts; ++ grub_uint8_t micro_checkpoint; ++ grub_uint8_t reserved0; ++ grub_uint32_t max_cpus; ++} GRUB_PACKED; ++ + struct pvr_entry + { + grub_uint32_t mask; +@@ -523,6 +536,8 @@ struct cas_vector + grub_uint16_t vec3; + grub_uint8_t vec4_size; + grub_uint16_t vec4; ++ grub_uint8_t vec5_size; ++ struct option_vector5 vec5; + } GRUB_PACKED; + + /* +@@ -547,7 +562,7 @@ grub_ieee1275_ibm_cas (void) + struct cas_vector vector = + { + .pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */ +- .num_vecs = 4 - 1, ++ .num_vecs = 5 - 1, + .vec1_size = 0, + .vec1 = 0x80, /* ignore */ + .vec2_size = 1 + sizeof (struct option_vector2) - 2, +@@ -558,6 +573,10 @@ grub_ieee1275_ibm_cas (void) + .vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */ + .vec4_size = 2 - 1, + .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ ++ .vec5_size = 1 + sizeof (struct option_vector5) - 2, ++ .vec5 = { ++ 0, 192, 0, 128, 0, 0, 0, 0, 256 ++ } + }; + + INIT_IEEE1275_COMMON (&args.common, "call-method", 3, 2); diff --git a/SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch b/SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch new file mode 100644 index 0000000..02c0282 --- /dev/null +++ b/SOURCES/0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch @@ -0,0 +1,246 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Mon, 6 Feb 2023 10:03:25 -0500 +Subject: [PATCH] ibmvtpm: Add support for trusted boot using a vTPM 2.0 + +Add support for trusted boot using a vTPM 2.0 on the IBM IEEE1275 +PowerPC platform. With this patch grub now measures text and binary data +into the TPM's PCRs 8 and 9 in the same way as the x86_64 platform +does. + +This patch requires Daniel Axtens's patches for claiming more memory. + +Note: The tpm_init() function cannot be called from GRUB_MOD_INIT() since +it does not find the device nodes upon module initialization and +therefore the call to tpm_init() must be deferred to grub_tpm_measure(). + +For vTPM support to work on PowerVM, system driver levels 1010.30 +or 1020.00 are required. + +Note: Previous versions of firmware levels with the 2hash-ext-log +API call have a bug that, once this API call is invoked, has the +effect of disabling the vTPM driver under Linux causing an error +message to be displayed in the Linux kernel log. Those users will +have to update their machines to the firmware levels mentioned +above. + +Cc: Eric Snowberg +Signed-off-by: Stefan Berger +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 2aa5ef83743dfea79377309ff4f5e9c9a55de355) +--- + grub-core/Makefile.core.def | 7 ++ + grub-core/commands/ieee1275/ibmvtpm.c | 155 ++++++++++++++++++++++++++++++++++ + include/grub/ieee1275/ieee1275.h | 3 + + docs/grub.texi | 3 +- + 4 files changed, 167 insertions(+), 1 deletion(-) + create mode 100644 grub-core/commands/ieee1275/ibmvtpm.c + +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index f21da23213..02ea718652 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -1175,6 +1175,13 @@ module = { + enable = powerpc_ieee1275; + }; + ++module = { ++ name = tpm; ++ common = commands/tpm.c; ++ ieee1275 = commands/ieee1275/ibmvtpm.c; ++ enable = powerpc_ieee1275; ++}; ++ + module = { + name = terminal; + common = commands/terminal.c; +diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c +new file mode 100644 +index 0000000000..239942d27e +--- /dev/null ++++ b/grub-core/commands/ieee1275/ibmvtpm.c +@@ -0,0 +1,155 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2022 Free Software Foundation, Inc. ++ * Copyright (C) 2022 IBM Corporation ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ * ++ * IBM vTPM support code. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static grub_ieee1275_ihandle_t tpm_ihandle; ++static grub_uint8_t tpm_version; ++ ++#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0) ++ ++static void ++tpm_get_tpm_version (void) ++{ ++ grub_ieee1275_phandle_t vtpm; ++ char buffer[20]; ++ ++ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) && ++ !grub_ieee1275_get_property (vtpm, "compatible", buffer, ++ sizeof (buffer), NULL) && ++ !grub_strcmp (buffer, "IBM,vtpm20")) ++ tpm_version = 2; ++} ++ ++static grub_err_t ++tpm_init (void) ++{ ++ static int init_success = 0; ++ ++ if (!init_success) ++ { ++ if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0) ++ { ++ tpm_ihandle = IEEE1275_IHANDLE_INVALID; ++ return GRUB_ERR_UNKNOWN_DEVICE; ++ } ++ ++ init_success = 1; ++ ++ tpm_get_tpm_version (); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++static int ++ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex, ++ grub_uint32_t eventtype, ++ const char *description, ++ grub_size_t description_size, ++ void *buf, grub_size_t size) ++{ ++ struct tpm_2hash_ext_log ++ { ++ struct grub_ieee1275_common_hdr common; ++ grub_ieee1275_cell_t method; ++ grub_ieee1275_cell_t ihandle; ++ grub_ieee1275_cell_t size; ++ grub_ieee1275_cell_t buf; ++ grub_ieee1275_cell_t description_size; ++ grub_ieee1275_cell_t description; ++ grub_ieee1275_cell_t eventtype; ++ grub_ieee1275_cell_t pcrindex; ++ grub_ieee1275_cell_t catch_result; ++ grub_ieee1275_cell_t rc; ++ }; ++ struct tpm_2hash_ext_log args; ++ ++ INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2); ++ args.method = (grub_ieee1275_cell_t) "2hash-ext-log"; ++ args.ihandle = tpm_ihandle; ++ args.pcrindex = pcrindex; ++ args.eventtype = eventtype; ++ args.description = (grub_ieee1275_cell_t) description; ++ args.description_size = description_size; ++ args.buf = (grub_ieee1275_cell_t) buf; ++ args.size = (grub_ieee1275_cell_t) size; ++ ++ if (IEEE1275_CALL_ENTRY_FN (&args) == -1) ++ return -1; ++ ++ /* ++ * catch_result is set if firmware does not support 2hash-ext-log ++ * rc is GRUB_IEEE1275_CELL_FALSE (0) on failure ++ */ ++ if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE) ++ return -1; ++ ++ return 0; ++} ++ ++static grub_err_t ++tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ static int error_displayed = 0; ++ int rc; ++ ++ rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL, ++ description, grub_strlen(description) + 1, ++ buf, size); ++ if (rc && !error_displayed) ++ { ++ error_displayed++; ++ return grub_error (GRUB_ERR_BAD_DEVICE, ++ "2HASH-EXT-LOG failed: Firmware is likely too old.\n"); ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, ++ const char *description) ++{ ++ /* ++ * Call tpm_init() 'late' rather than from GRUB_MOD_INIT() so that device nodes ++ * can be found. ++ */ ++ grub_err_t err = tpm_init (); ++ ++ /* Absence of a TPM isn't a failure. */ ++ if (err != GRUB_ERR_NONE) ++ return GRUB_ERR_NONE; ++ ++ grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", ++ pcr, size, description); ++ ++ if (tpm_version == 2) ++ return tpm2_log_event (buf, size, pcr, description); ++ ++ return GRUB_ERR_NONE; ++} +diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h +index 560c968460..27b9cf259b 100644 +--- a/include/grub/ieee1275/ieee1275.h ++++ b/include/grub/ieee1275/ieee1275.h +@@ -24,6 +24,9 @@ + #include + #include + ++#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0) ++#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1) ++ + struct grub_ieee1275_mem_region + { + unsigned int start; +diff --git a/docs/grub.texi b/docs/grub.texi +index 1750b72ee9..825278a7f3 100644 +--- a/docs/grub.texi ++++ b/docs/grub.texi +@@ -6235,7 +6235,8 @@ tpm module is loaded. As such it is recommended that the tpm module be built + into @file{core.img} in order to avoid a potential gap in measurement between + @file{core.img} being loaded and the tpm module being loaded. + +-Measured boot is currently only supported on EFI platforms. ++Measured boot is currently only supported on EFI and IBM IEEE1275 PowerPC ++platforms. + + @node Lockdown + @section Lockdown when booting on a secure setup diff --git a/SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch b/SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch new file mode 100644 index 0000000..1d201d3 --- /dev/null +++ b/SOURCES/0318-powerpc-Drop-Open-Hack-Ware.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 6 Sep 2021 15:46:11 +1000 +Subject: [PATCH] powerpc: Drop Open Hack'Ware + +Open Hack'Ware was an alternative firmware of powerpc under QEMU. + +The last commit to any Open Hack'Ware repo I can find is from 2014 [1]. + +Open Hack'Ware was used for the QEMU "prep" machine type, which was +deprecated in QEMU in commit 54c86f5a4844 (hw/ppc: deprecate the +machine type 'prep', replaced by '40p') in QEMU v3.1, and had reportedly +been broken for years before without anyone noticing. Support was removed +in February 2020 by commit b2ce76a0730e (hw/ppc/prep: Remove the +deprecated "prep" machine and the OpenHackware BIOS). + +Open Hack'Ware's limitations require some messy code in GRUB. This +complexity is not worth carrying any more. + +Remove detection of Open Hack'Ware. We will clean up the feature flags +in following commits. + +[1]: https://github.com/qemu/openhackware and + https://repo.or.cz/w/openhackware.git are QEMU submodules. They have + only small changes on top of OHW v0.4.1, which was imported into + QEMU SCM in 2010. I can't find anything resembling an official repo + any more. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit f9ce538eec88c5cffbfde021c4e8a95a5e9d0e8f) +--- + grub-core/kern/ieee1275/cmain.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/grub-core/kern/ieee1275/cmain.c b/grub-core/kern/ieee1275/cmain.c +index dce7b84922..cb42f60ebe 100644 +--- a/grub-core/kern/ieee1275/cmain.c ++++ b/grub-core/kern/ieee1275/cmain.c +@@ -49,7 +49,6 @@ grub_ieee1275_find_options (void) + grub_ieee1275_phandle_t root; + grub_ieee1275_phandle_t options; + grub_ieee1275_phandle_t openprom; +- grub_ieee1275_phandle_t bootrom; + int rc; + grub_uint32_t realmode = 0; + char tmp[256]; +@@ -198,21 +197,6 @@ grub_ieee1275_find_options (void) + + grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_HAS_CURSORONOFF); + } +- +- if (! grub_ieee1275_finddevice ("/rom/boot-rom", &bootrom) +- || ! grub_ieee1275_finddevice ("/boot-rom", &bootrom)) +- { +- rc = grub_ieee1275_get_property (bootrom, "model", tmp, sizeof (tmp), 0); +- if (rc >= 0 && !grub_strncmp (tmp, "PPC Open Hack'Ware", +- sizeof ("PPC Open Hack'Ware") - 1)) +- { +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_BROKEN_OUTPUT); +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_SET_COLORS); +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_CANNOT_INTERPRET); +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM); +- grub_ieee1275_set_flag (GRUB_IEEE1275_FLAG_NO_ANSI); +- } +- } + } + + void diff --git a/SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch b/SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch new file mode 100644 index 0000000..6e7b17f --- /dev/null +++ b/SOURCES/0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mukesh Kumar Chaurasiya +Date: Thu, 9 Feb 2023 13:09:16 +0530 +Subject: [PATCH] osdep/linux/hostdisk: Modify sector by sysfs as disk sector + +The disk sector size provided by sysfs file system considers the sector +size of 512 irrespective of disk sector size, thus causing the read by +the GRUB to an incorrect offset from what was originally intended. + +Considering the 512 sector size of sysfs data the actual sector needs to +be modified corresponding to disk sector size. + +Signed-off-by: Mukesh Kumar Chaurasiya +Reviewed-by: Daniel Kiper +(cherry picked from commit f7564844f82b57078d601befadc438b5bc1fa01b) +--- + grub-core/osdep/linux/hostdisk.c | 7 ++++--- + include/grub/disk.h | 7 +++++++ + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c +index 7bc99ac1c1..a9ea0bb465 100644 +--- a/grub-core/osdep/linux/hostdisk.c ++++ b/grub-core/osdep/linux/hostdisk.c +@@ -240,7 +240,8 @@ have_devfs (void) + #pragma GCC diagnostic ignored "-Wformat-nonliteral" + + static int +-grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector) ++grub_hostdisk_linux_find_partition (const grub_disk_t disk, char *dev, ++ grub_disk_addr_t sector) + { + size_t len = strlen (dev); + const char *format; +@@ -305,7 +306,7 @@ grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector) + if (fstat (fd, &st) < 0 + || !grub_util_device_is_mapped_stat (&st) + || !grub_util_get_dm_node_linear_info (st.st_rdev, 0, 0, &start)) +- start = grub_util_find_partition_start_os (real_dev); ++ start = grub_disk_to_native_sector (disk, grub_util_find_partition_start_os (real_dev)); + /* We don't care about errors here. */ + grub_errno = GRUB_ERR_NONE; + +@@ -386,7 +387,7 @@ grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int f + && strncmp (dev, "/dev/", 5) == 0) + { + if (sector >= part_start) +- is_partition = grub_hostdisk_linux_find_partition (dev, part_start); ++ is_partition = grub_hostdisk_linux_find_partition (disk, dev, part_start); + else + *max = part_start - sector; + } +diff --git a/include/grub/disk.h b/include/grub/disk.h +index 06210a7049..881addcc77 100644 +--- a/include/grub/disk.h ++++ b/include/grub/disk.h +@@ -208,6 +208,13 @@ grub_disk_from_native_sector (grub_disk_t disk, grub_disk_addr_t sector) + return sector << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); + } + ++/* Convert from GRUB native disk sized sector to disk sized sector. */ ++static inline grub_disk_addr_t ++grub_disk_to_native_sector (grub_disk_t disk, grub_disk_addr_t sector) ++{ ++ return sector >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); ++} ++ + /* This is called from the memory manager. */ + void grub_disk_cache_invalidate_all (void); + diff --git a/SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch b/SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch new file mode 100644 index 0000000..456f8f7 --- /dev/null +++ b/SOURCES/0320-mm-Adjust-new-region-size-to-take-management-overhea.patch @@ -0,0 +1,145 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 29 Jan 2023 19:49:31 +0800 +Subject: [PATCH] mm: Adjust new region size to take management overhead into + account + +When grub_memalign() encounters out-of-memory, it will try +grub_mm_add_region_fn() to request more memory from system firmware. +However, the size passed to it doesn't take region management overhead +into account. Adding a memory area of "size" bytes may result in a heap +region of less than "size" bytes really available. Thus, the new region +may not be adequate for current allocation request, confusing +out-of-memory handling code. + +This patch introduces GRUB_MM_MGMT_OVERHEAD to address the region +management overhead (e.g. metadata, padding). The value of this new +constant must be large enough to make sure grub_memalign(align, size) +always succeeds after a successful call to + grub_mm_init_region(addr, size + align + GRUB_MM_MGMT_OVERHEAD), +for any given addr and size (assuming no integer overflow). + +The size passed to grub_mm_add_region_fn() is now correctly adjusted, +thus if grub_mm_add_region_fn() succeeded, current allocation request +can always succeed. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 2282cbfe5aa1ff6c1bbcbdcd2003089ad7c03ba3) +--- + grub-core/kern/mm.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 61 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index da1ac9427c..f29a3e5cbd 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -83,6 +83,46 @@ + + + ++/* ++ * GRUB_MM_MGMT_OVERHEAD is an upper bound of management overhead of ++ * each region, with any possible padding taken into account. ++ * ++ * The value must be large enough to make sure grub_memalign(align, size) ++ * always succeeds after a successful call to ++ * grub_mm_init_region(addr, size + align + GRUB_MM_MGMT_OVERHEAD), ++ * for any given addr, align and size (assuming no interger overflow). ++ * ++ * The worst case which has maximum overhead is shown in the figure below: ++ * ++ * +-- addr ++ * v |<- size + align ->| ++ * +---------+----------------+----------------+------------------+---------+ ++ * | padding | grub_mm_region | grub_mm_header | usable bytes | padding | ++ * +---------+----------------+----------------+------------------+---------+ ++ * |<- a ->|<- b ->|<- c ->|<- d ->|<- e ->| ++ * ^ ++ * b == sizeof (struct grub_mm_region) | / Assuming no other suitable ++ * c == sizeof (struct grub_mm_header) | | block is available, then: ++ * d == size + align +-| If align == 0, this will be ++ * | the pointer returned by next ++ * Assuming addr % GRUB_MM_ALIGN == 1, then: | grub_memalign(align, size). ++ * a == GRUB_MM_ALIGN - 1 | If align > 0, this chunk may ++ * | need to be split to fulfill ++ * Assuming d % GRUB_MM_ALIGN == 1, then: | alignment requirements, and ++ * e == GRUB_MM_ALIGN - 1 | the returned pointer may be ++ * \ inside these usable bytes. ++ * Therefore, the maximum overhead is: ++ * a + b + c + e == (GRUB_MM_ALIGN - 1) + sizeof (struct grub_mm_region) ++ * + sizeof (struct grub_mm_header) + (GRUB_MM_ALIGN - 1) ++ */ ++#define GRUB_MM_MGMT_OVERHEAD ((GRUB_MM_ALIGN - 1) \ ++ + sizeof (struct grub_mm_region) \ ++ + sizeof (struct grub_mm_header) \ ++ + (GRUB_MM_ALIGN - 1)) ++ ++/* The size passed to grub_mm_add_region_fn() is aligned up by this value. */ ++#define GRUB_MM_HEAP_GROW_ALIGN 4096 ++ + grub_mm_region_t grub_mm_base; + grub_mm_add_region_func_t grub_mm_add_region_fn; + +@@ -230,6 +270,11 @@ grub_mm_init_region (void *addr, grub_size_t size) + + grub_dprintf ("regions", "No: considering a new region at %p of size %" PRIxGRUB_SIZE "\n", + addr, size); ++ /* ++ * If you want to modify the code below, please also take a look at ++ * GRUB_MM_MGMT_OVERHEAD and make sure it is synchronized with the code. ++ */ ++ + /* Allocate a region from the head. */ + r = (grub_mm_region_t) ALIGN_UP ((grub_addr_t) addr, GRUB_MM_ALIGN); + +@@ -410,6 +455,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + { + grub_mm_region_t r; + grub_size_t n = ((size + GRUB_MM_ALIGN - 1) >> GRUB_MM_ALIGN_LOG2) + 1; ++ grub_size_t grow; + int count = 0; + + if (!grub_mm_base) +@@ -418,10 +464,22 @@ grub_memalign (grub_size_t align, grub_size_t size) + if (size > ~(grub_size_t) align) + goto fail; + ++ /* ++ * Pre-calculate the necessary size of heap growth (if applicable), ++ * with region management overhead taken into account. ++ */ ++ if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow)) ++ goto fail; ++ ++ /* Align up heap growth to make it friendly to CPU/MMU. */ ++ if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) ++ goto fail; ++ grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN); ++ + /* We currently assume at least a 32-bit grub_size_t, + so limiting allocations to - 1MiB + in name of sanity is beneficial. */ +- if ((size + align) > ~(grub_size_t) 0x100000) ++ if (grow > ~(grub_size_t) 0x100000) + goto fail; + + align = (align >> GRUB_MM_ALIGN_LOG2); +@@ -447,7 +505,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + count++; + + if (grub_mm_add_region_fn != NULL && +- grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) ++ grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) + goto again; + + /* fallthrough */ +@@ -462,7 +520,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + * Try again even if this fails, in case it was able to partially + * satisfy the request + */ +- grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE); ++ grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_NONE); + goto again; + } + diff --git a/SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch b/SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch new file mode 100644 index 0000000..291092d --- /dev/null +++ b/SOURCES/0321-mm-Preallocate-some-space-when-adding-new-regions.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 29 Jan 2023 19:49:32 +0800 +Subject: [PATCH] mm: Preallocate some space when adding new regions + +When grub_memalign() encounters out-of-memory, it will try +grub_mm_add_region_fn() to request more memory from system firmware. +However, it doesn't preallocate memory space for future allocation +requests. In extreme cases, it requires one call to +grub_mm_add_region_fn() for each memory allocation request. This can +be very slow. + +This patch introduces GRUB_MM_HEAP_GROW_EXTRA, the minimal heap growth +granularity. The new region size is now set to the bigger one of its +original value and GRUB_MM_HEAP_GROW_EXTRA. Thus, it will result in some +memory space preallocated if current allocations request is small. + +The value of GRUB_MM_HEAP_GROW_EXTRA is set to 1MB. If this value is +smaller, the cost of small memory allocations will be higher. If this +value is larger, more memory will be wasted and it might cause +out-of-memory on machines with small amount of RAM. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 21869baec15239b6d99122b32b14a778af4c754f) +--- + grub-core/kern/mm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index f29a3e5cbd..cc8a4703bc 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -123,6 +123,9 @@ + /* The size passed to grub_mm_add_region_fn() is aligned up by this value. */ + #define GRUB_MM_HEAP_GROW_ALIGN 4096 + ++/* Minimal heap growth granularity when existing heap space is exhausted. */ ++#define GRUB_MM_HEAP_GROW_EXTRA 0x100000 ++ + grub_mm_region_t grub_mm_base; + grub_mm_add_region_func_t grub_mm_add_region_fn; + +@@ -471,6 +474,9 @@ grub_memalign (grub_size_t align, grub_size_t size) + if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow)) + goto fail; + ++ /* Preallocate some extra space if heap growth is small. */ ++ grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); ++ + /* Align up heap growth to make it friendly to CPU/MMU. */ + if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) + goto fail; diff --git a/SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch b/SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch new file mode 100644 index 0000000..fe6b3e1 --- /dev/null +++ b/SOURCES/0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhang Boyang +Date: Sun, 29 Jan 2023 19:49:33 +0800 +Subject: [PATCH] mm: Avoid complex heap growth math in hot path + +We do a lot of math about heap growth in hot path of grub_memalign(). +However, the result is only used if out of memory is encountered, which +is seldom. + +This patch moves these calculations away from hot path. These +calculations are now only done if out of memory is encountered. This +change can also help compiler to optimize integer overflow checks away. + +Signed-off-by: Zhang Boyang +Reviewed-by: Daniel Kiper +(cherry picked from commit 65bc45963014773e2062ccc63ff34a089d2e352e) +--- + grub-core/kern/mm.c | 34 ++++++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c +index cc8a4703bc..630d7be0e2 100644 +--- a/grub-core/kern/mm.c ++++ b/grub-core/kern/mm.c +@@ -467,20 +467,7 @@ grub_memalign (grub_size_t align, grub_size_t size) + if (size > ~(grub_size_t) align) + goto fail; + +- /* +- * Pre-calculate the necessary size of heap growth (if applicable), +- * with region management overhead taken into account. +- */ +- if (grub_add (size + align, GRUB_MM_MGMT_OVERHEAD, &grow)) +- goto fail; +- +- /* Preallocate some extra space if heap growth is small. */ +- grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); +- +- /* Align up heap growth to make it friendly to CPU/MMU. */ +- if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) +- goto fail; +- grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN); ++ grow = size + align; + + /* We currently assume at least a 32-bit grub_size_t, + so limiting allocations to - 1MiB +@@ -510,6 +497,25 @@ grub_memalign (grub_size_t align, grub_size_t size) + /* Request additional pages, contiguous */ + count++; + ++ /* ++ * Calculate the necessary size of heap growth (if applicable), ++ * with region management overhead taken into account. ++ */ ++ if (grub_add (grow, GRUB_MM_MGMT_OVERHEAD, &grow)) ++ goto fail; ++ ++ /* Preallocate some extra space if heap growth is small. */ ++ grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); ++ ++ /* Align up heap growth to make it friendly to CPU/MMU. */ ++ if (grow > ~(grub_size_t) (GRUB_MM_HEAP_GROW_ALIGN - 1)) ++ goto fail; ++ grow = ALIGN_UP (grow, GRUB_MM_HEAP_GROW_ALIGN); ++ ++ /* Do the same sanity check again. */ ++ if (grow > ~(grub_size_t) 0x100000) ++ goto fail; ++ + if (grub_mm_add_region_fn != NULL && + grub_mm_add_region_fn (grow, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE) + goto again; diff --git a/SOURCES/0323-hostdisk-work-around-proc-not-reporting-size.patch b/SOURCES/0323-hostdisk-work-around-proc-not-reporting-size.patch new file mode 100644 index 0000000..5f2fa08 --- /dev/null +++ b/SOURCES/0323-hostdisk-work-around-proc-not-reporting-size.patch @@ -0,0 +1,93 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Thu, 9 Mar 2023 11:18:19 -0500 +Subject: [PATCH] hostdisk: work around /proc not reporting size + +fstat(2) of files in /proc will yield st_size == 0 regardless of file +contents. Use a negative value in grub_file_t's size to denote "ignore" +and plumb through. + +Signed-off-by: Robbie Harwood +--- + grub-core/kern/file.c | 28 ++++++++++++++++------------ + grub-core/lib/progress.c | 2 +- + grub-core/osdep/unix/hostdisk.c | 6 ++++++ + 3 files changed, 23 insertions(+), 13 deletions(-) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 868ce3b63e..4ea6d1ce95 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -172,26 +172,30 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) + grub_disk_read_hook_t read_hook; + void *read_hook_data; + +- if (file->offset > file->size) +- { +- grub_error (GRUB_ERR_OUT_OF_RANGE, +- N_("attempt to read past the end of file")); +- return -1; +- } +- + if (len == 0) + return 0; + +- if (len > file->size - file->offset) +- len = file->size - file->offset; ++#ifdef GRUB_MACHINE_EMU ++ if (file->size >= 0) ++ { ++#endif ++ if (file->offset > file->size) ++ { ++ grub_error (GRUB_ERR_OUT_OF_RANGE, ++ N_("attempt to read past the end of file")); ++ return -1; ++ } ++ ++ if (len > file->size - file->offset) ++ len = file->size - file->offset; ++#ifdef GRUB_MACHINE_EMU ++ } ++#endif + + /* Prevent an overflow. */ + if ((grub_ssize_t) len < 0) + len >>= 1; + +- if (len == 0) +- return 0; +- + read_hook = file->read_hook; + read_hook_data = file->read_hook_data; + if (!file->read_hook) +diff --git a/grub-core/lib/progress.c b/grub-core/lib/progress.c +index 4b7cbbca6d..f3226b6898 100644 +--- a/grub-core/lib/progress.c ++++ b/grub-core/lib/progress.c +@@ -71,7 +71,7 @@ grub_file_progress_hook_real (grub_disk_addr_t sector __attribute__ ((unused)), + * 100ULL * 1000ULL, + now - file->last_progress_time, 0); + +- if (file->size == 0) ++ if (file->size <= 0) + percent = 100; + else + percent = grub_divmod64 (100 * file->progress_offset, +diff --git a/grub-core/osdep/unix/hostdisk.c b/grub-core/osdep/unix/hostdisk.c +index 3a00d7451a..e5f4b4d5f9 100644 +--- a/grub-core/osdep/unix/hostdisk.c ++++ b/grub-core/osdep/unix/hostdisk.c +@@ -71,6 +71,12 @@ grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsiz + if (log_secsize) + *log_secsize = 9; + ++#ifdef GRUB_MACHINE_EMU ++ /* /proc doesn't behave itself and gives 0 for file sizes to stat. */ ++ if (st.st_size == 0 && !grub_strncmp ("/proc", name, 5)) ++ return -1; ++#endif ++ + return st.st_size; + } + diff --git a/SOURCES/0324-blscfg-check-for-mounted-boot-in-emu.patch b/SOURCES/0324-blscfg-check-for-mounted-boot-in-emu.patch new file mode 100644 index 0000000..69ebe15 --- /dev/null +++ b/SOURCES/0324-blscfg-check-for-mounted-boot-in-emu.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Tue, 7 Mar 2023 18:59:40 -0500 +Subject: [PATCH] blscfg: check for mounted /boot in emu + +Irritatingly, BLS defines paths relatives to the mountpoint of the +filesystem which contains its snippets, not / or any other fixed +location. So grub2-emu needs to know whether /boot is a separate +filesysem from / and conditionally prepend a path. + +Signed-off-by: Robbie Harwood +--- + grub-core/commands/blscfg.c | 54 ++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 49 insertions(+), 5 deletions(-) + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +index dbd0899acf..6e398fc175 100644 +--- a/grub-core/commands/blscfg.c ++++ b/grub-core/commands/blscfg.c +@@ -40,8 +40,9 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #include "loadenv.h" + + #define GRUB_BLS_CONFIG_PATH "/loader/entries/" ++ + #ifdef GRUB_MACHINE_EMU +-#define GRUB_BOOT_DEVICE "" ++#define GRUB_BOOT_DEVICE "/boot" + #else + #define GRUB_BOOT_DEVICE "($root)" + #endif +@@ -54,8 +55,50 @@ struct keyval + + static struct bls_entry *entries = NULL; + ++/* Cache probing in frob_boot_device(). Used for linux entry also. ++ * Always true in non-emu, meaning to prefix things with GRUB_BOOT_DEVICE. */ ++static int separate_boot = -1; ++ + #define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries) + ++/* BLS appears to make paths relative to the filesystem that snippets are ++ * on, not /. Attempt to cope. */ ++static char *frob_boot_device(char *tmp) ++{ ++#ifdef GRUB_MACHINE_EMU ++ grub_file_t f; ++ char *line = NULL; ++ ++ if (separate_boot != -1) ++ goto probed; ++ ++ separate_boot = 0; ++ ++ f = grub_file_open ("/proc/mounts", GRUB_FILE_TYPE_CONFIG); ++ if (f == NULL) ++ goto probed; ++ ++ while ((line = grub_file_getline (f))) ++ { ++ if (grub_strstr (line, " " GRUB_BOOT_DEVICE " ")) ++ { ++ separate_boot = 1; ++ grub_free (line); ++ break; ++ } ++ ++ grub_free(line); ++ } ++ ++ grub_file_close (f); ++ probed: ++ if (!separate_boot) ++ return grub_stpcpy (tmp, " "); ++#endif ++ ++ return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++} ++ + static int bls_add_keyval(struct bls_entry *entry, char *key, char *val) + { + char *k, *v; +@@ -842,7 +885,7 @@ static void create_entry (struct bls_entry *entry) + for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++) + { + grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]); +- tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++ tmp = frob_boot_device (tmp); + tmp = grub_stpcpy (tmp, initrd_prefix); + tmp = grub_stpcpy (tmp, early_initrds[i]); + grub_free(early_initrds[i]); +@@ -851,7 +894,7 @@ static void create_entry (struct bls_entry *entry) + for (i = 0; initrds != NULL && initrds[i] != NULL; i++) + { + grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]); +- tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++ tmp = frob_boot_device (tmp); + tmp = grub_stpcpy (tmp, initrds[i]); + } + tmp = grub_stpcpy (tmp, "\n"); +@@ -888,7 +931,7 @@ static void create_entry (struct bls_entry *entry) + } + char *tmp = dt; + tmp = grub_stpcpy (dt, "devicetree"); +- tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE); ++ tmp = frob_boot_device (tmp); + if (add_dt_prefix) + tmp = grub_stpcpy (tmp, prefix); + tmp = grub_stpcpy (tmp, devicetree); +@@ -907,7 +950,8 @@ static void create_entry (struct bls_entry *entry) + "linux %s%s%s%s\n" + "%s%s", + savedefault ? "savedefault\n" : "", +- GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "", ++ separate_boot ? GRUB_BOOT_DEVICE : "", ++ clinux, options ? " " : "", options ? options : "", + initrd ? initrd : "", dt ? dt : ""); + + grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry); diff --git a/SOURCES/0325-emu-linux-work-around-systemctl-kexec-returning.patch b/SOURCES/0325-emu-linux-work-around-systemctl-kexec-returning.patch new file mode 100644 index 0000000..eaef5ff --- /dev/null +++ b/SOURCES/0325-emu-linux-work-around-systemctl-kexec-returning.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 22 Mar 2023 14:19:43 -0400 +Subject: [PATCH] emu/linux: work around systemctl kexec returning + +Per systemctl(1), it "is asynchronous; it will return after the reboot +operation is enqueued, without waiting for it to complete". This +differs from kexec(8), which calls reboot(2) and therefore does not +return. + +When not using fallback, this results in the confusing-but-harmless: + + error trying to perform 'systemctl kexec': 0 + Aborted. Press any key to exit. + +on screen for a bit, followed by successful kexec. + +To reduce the liklihood of hitting this case, add a delay on succesful +return. Ultimately, the systemd interface is racy: we can't avoid it +entirely unless we never fallback on success. + +Signed-off-by: Robbie Harwood +--- + grub-core/loader/emu/linux.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +index 0cf378a376..7de3f7f861 100644 +--- a/grub-core/loader/emu/linux.c ++++ b/grub-core/loader/emu/linux.c +@@ -74,6 +74,10 @@ grub_linux_boot (void) + (kexecute==1) ? "do-or-die" : "just-in-case"); + rc = grub_util_exec (systemctl); + ++ /* `systemctl kexec` is "asynchronous" and will return even on success. */ ++ if (rc == 0) ++ grub_sleep (10); ++ + if (kexecute == 1) + grub_fatal (N_("error trying to perform 'systemctl kexec': %d"), rc); + diff --git a/SOURCES/0326-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch b/SOURCES/0326-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch new file mode 100644 index 0000000..ca82e33 --- /dev/null +++ b/SOURCES/0326-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +Date: Mon, 27 Mar 2023 12:25:39 +0530 +Subject: [PATCH] kern/ieee1275/init: Convert plain numbers to constants in + Vec5 + +This patch converts the plain numbers used in Vec5 properties to constants. + +1. LPAR: Client program supports logical partitioning and + associated hcall()s. +2. SPLPAR: Client program supports the Shared + Processor LPAR Option. +3. CMO: Enables the Cooperative Memory Over-commitment Option. +4. MAX_CPU: Defines maximum number of CPUs supported. + +Signed-off-by: Avnish Chouhan +Reviewed-by: Daniel Kiper +(cherry picked from commit 8406cfe4774eb2da3db4bf0bc2b2ff6592ecbdaf) +--- + grub-core/kern/ieee1275/init.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 72d4fed312..5d79580341 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -72,6 +72,12 @@ extern char _end[]; + grub_addr_t grub_ieee1275_original_stack; + #endif + ++#define LPAR 0x80 ++#define SPLPAR 0x40 ++#define BYTE2 (LPAR | SPLPAR) ++#define CMO 0x80 ++#define MAX_CPU 256 ++ + void + grub_exit (int rc __attribute__((unused))) + { +@@ -575,7 +581,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ + .vec5_size = 1 + sizeof (struct option_vector5) - 2, + .vec5 = { +- 0, 192, 0, 128, 0, 0, 0, 0, 256 ++ 0, BYTE2, 0, CMO, 0, 0, 0, 0, MAX_CPU + } + }; + diff --git a/SOURCES/0327-kern-ieee1275-init-Extended-support-in-Vec5.patch b/SOURCES/0327-kern-ieee1275-init-Extended-support-in-Vec5.patch new file mode 100644 index 0000000..b8b481f --- /dev/null +++ b/SOURCES/0327-kern-ieee1275-init-Extended-support-in-Vec5.patch @@ -0,0 +1,127 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Avnish Chouhan +Date: Mon, 27 Mar 2023 12:25:40 +0530 +Subject: [PATCH] kern/ieee1275/init: Extended support in Vec5 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch enables multiple options in Vec5 which are required and +solves the boot issues seen on some machines which are looking for +these specific options. + +1. LPAR: Client program supports logical partitioning and + associated hcall()s. +2. SPLPAR: Client program supports the Shared + Processor LPAR Option. +3. DYN_RCON_MEM: Client program supports the + “ibm,dynamic-reconfiguration-memory” property and it may be + presented in the device tree. +4. LARGE_PAGES: Client supports pages larger than 4 KB. +5. DONATE_DCPU_CLS: Client supports donating dedicated processor cycles. +6. PCI_EXP: Client supports PCI Express implementations + utilizing Message Signaled Interrupts (MSIs). + +7. CMOC: Enables the Cooperative Memory Over-commitment Option. +8. EXT_CMO: Enables the Extended Cooperative Memory Over-commit Option. + +9. ASSOC_REF: Enables “ibm,associativity” and + “ibm,associativity-reference-points” properties. +10. AFFINITY: Enables Platform Resource Reassignment Notification. +11. NUMA: Supports NUMA Distance Lookup Table Option. + +12. HOTPLUG_INTRPT: Supports Hotplug Interrupts. +13. HPT_RESIZE: Enable Hash Page Table Resize Option. + +14. MAX_CPU: Defines maximum number of CPUs supported. + +15. PFO_HWRNG: Supports Random Number Generator. +16. PFO_HW_COMP: Supports Compression Engine. +17. PFO_ENCRYPT: Supports Encryption Engine. + +18. SUB_PROCESSORS: Supports Sub-Processors. + +19. DY_MEM_V2: Client program supports the “ibm,dynamic-memory-v2” property in the + “ibm,dynamic-reconfiguration-memory” node and it may be presented in the device tree. +20. DRC_INFO: Client program supports the “ibm,drc-info” property definition and it may be + presented in the device tree. + +Signed-off-by: Avnish Chouhan +Reviewed-by: Daniel Kiper +(cherry picked from commit 98d0df0351fbff7a4acc64c7594d538889a43e2d) +--- + grub-core/kern/ieee1275/init.c | 47 ++++++++++++++++++++++++++++++++++++------ + 1 file changed, 41 insertions(+), 6 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 5d79580341..3d4ad9d1f1 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -72,11 +72,41 @@ extern char _end[]; + grub_addr_t grub_ieee1275_original_stack; + #endif + +-#define LPAR 0x80 +-#define SPLPAR 0x40 +-#define BYTE2 (LPAR | SPLPAR) +-#define CMO 0x80 +-#define MAX_CPU 256 ++/* Options vector5 properties. */ ++ ++#define LPAR 0x80 ++#define SPLPAR 0x40 ++#define DYN_RCON_MEM 0x20 ++#define LARGE_PAGES 0x10 ++#define DONATE_DCPU_CLS 0x02 ++#define PCI_EXP 0x01 ++#define BYTE2 (LPAR | SPLPAR | DYN_RCON_MEM | LARGE_PAGES | DONATE_DCPU_CLS | PCI_EXP) ++ ++#define CMOC 0x80 ++#define EXT_CMO 0x40 ++#define CMO (CMOC | EXT_CMO) ++ ++#define ASSOC_REF 0x80 ++#define AFFINITY 0x40 ++#define NUMA 0x20 ++#define ASSOCIATIVITY (ASSOC_REF | AFFINITY | NUMA) ++ ++#define HOTPLUG_INTRPT 0x04 ++#define HPT_RESIZE 0x01 ++#define BIN_OPTS (HOTPLUG_INTRPT | HPT_RESIZE) ++ ++#define MAX_CPU 256 ++ ++#define PFO_HWRNG 0x80000000 ++#define PFO_HW_COMP 0x40000000 ++#define PFO_ENCRYPT 0x20000000 ++#define PLATFORM_FACILITIES (PFO_HWRNG | PFO_HW_COMP | PFO_ENCRYPT) ++ ++#define SUB_PROCESSORS 1 ++ ++#define DY_MEM_V2 0x80 ++#define DRC_INFO 0x40 ++#define BYTE22 (DY_MEM_V2 | DRC_INFO) + + void + grub_exit (int rc __attribute__((unused))) +@@ -519,6 +549,11 @@ struct option_vector5 + grub_uint8_t micro_checkpoint; + grub_uint8_t reserved0; + grub_uint32_t max_cpus; ++ grub_uint16_t base_papr; ++ grub_uint16_t mem_reference; ++ grub_uint32_t platform_facilities; ++ grub_uint8_t sub_processors; ++ grub_uint8_t byte22; + } GRUB_PACKED; + + struct pvr_entry +@@ -581,7 +616,7 @@ grub_ieee1275_ibm_cas (void) + .vec4 = 0x0001, /* set required minimum capacity % to the lowest value */ + .vec5_size = 1 + sizeof (struct option_vector5) - 2, + .vec5 = { +- 0, BYTE2, 0, CMO, 0, 0, 0, 0, MAX_CPU ++ 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22 + } + }; + diff --git a/SOURCES/0328-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch b/SOURCES/0328-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch new file mode 100644 index 0000000..9c2522c --- /dev/null +++ b/SOURCES/0328-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Chang +Date: Wed, 22 Mar 2023 12:25:43 +0800 +Subject: [PATCH] tpm: Disable the tpm verifier if the TPM device is not + present + +When the tpm module is loaded, the verifier reads entire file into +memory, measures it and uses verified content as a backing buffer for +file accesses. However, this process may result in high memory +utilization for file operations, sometimes causing a system to run out +of memory which may finally lead to boot failure. To address this issue, +among others, the commit 887f98f0d (mm: Allow dynamically requesting +additional memory regions) have optimized memory management by +dynamically allocating heap space to maximize memory usage and reduce +threat of memory exhaustion. But in some cases problems may still arise, +e.g., when large ISO images are mounted using loopback or when dealing +with embedded systems with limited memory resources. + +Unfortunately current implementation of the tpm module doesn't allow +elimination of the back buffer once it is loaded. Even if the TPM device +is not present or it has been explicitly disabled. This may unnecessary +allocate a lot memory. To solve this issue, a patch has been developed +to detect the TPM status at module load and skip verifier registration +if the device is missing or deactivated. This prevents allocation of +memory for the back buffer, avoiding wasting memory when no real measure +boot functionality is performed. Disabling the TPM device in the system +can reduce memory usage in the GRUB. It is useful in scenarios where +high memory utilization is a concern and measurements of loaded +artifacts are not necessary. + +Signed-off-by: Michael Chang +Signed-off-by: Stefan Berger +Reviewed-by: Daniel Kiper +(cherry picked from commit 30708dfe3bebd62a5487437554da8a24253f519f) +--- + grub-core/commands/efi/tpm.c | 37 +++++++++++++++++++++++++++++++++++ + grub-core/commands/ieee1275/ibmvtpm.c | 20 +++++++++---------- + grub-core/commands/tpm.c | 10 ++++++++++ + include/grub/tpm.h | 1 + + 4 files changed, 58 insertions(+), 10 deletions(-) + +diff --git a/grub-core/commands/efi/tpm.c b/grub-core/commands/efi/tpm.c +index ae09c1bf8b..e1f343fea3 100644 +--- a/grub-core/commands/efi/tpm.c ++++ b/grub-core/commands/efi/tpm.c +@@ -287,3 +287,40 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + else + return grub_tpm2_log_event (tpm_handle, buf, size, pcr, description); + } ++ ++int ++grub_tpm_present (void) ++{ ++ grub_efi_handle_t tpm_handle; ++ grub_efi_uint8_t protocol_version; ++ ++ if (!grub_tpm_handle_find (&tpm_handle, &protocol_version)) ++ return 0; ++ ++ if (protocol_version == 1) ++ { ++ grub_efi_tpm_protocol_t *tpm; ++ ++ tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm) ++ { ++ grub_dprintf ("tpm", "Cannot open TPM protocol\n"); ++ return 0; ++ } ++ return grub_tpm1_present (tpm); ++ } ++ else ++ { ++ grub_efi_tpm2_protocol_t *tpm; ++ ++ tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid, ++ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); ++ if (!tpm) ++ { ++ grub_dprintf ("tpm", "Cannot open TPM protocol\n"); ++ return 0; ++ } ++ return grub_tpm2_present (tpm); ++ } ++} +diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c +index 239942d27e..a6fee5c516 100644 +--- a/grub-core/commands/ieee1275/ibmvtpm.c ++++ b/grub-core/commands/ieee1275/ibmvtpm.c +@@ -135,16 +135,6 @@ grub_err_t + grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + const char *description) + { +- /* +- * Call tpm_init() 'late' rather than from GRUB_MOD_INIT() so that device nodes +- * can be found. +- */ +- grub_err_t err = tpm_init (); +- +- /* Absence of a TPM isn't a failure. */ +- if (err != GRUB_ERR_NONE) +- return GRUB_ERR_NONE; +- + grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n", + pcr, size, description); + +@@ -153,3 +143,13 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr, + + return GRUB_ERR_NONE; + } ++ ++int ++grub_tpm_present (void) ++{ ++ /* ++ * Call tpm_init() "late" rather than from GRUB_MOD_INIT() so that device nodes ++ * can be found. ++ */ ++ return tpm_init() == GRUB_ERR_NONE; ++} +diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c +index e287d042e6..5839053d3d 100644 +--- a/grub-core/commands/tpm.c ++++ b/grub-core/commands/tpm.c +@@ -86,10 +86,20 @@ struct grub_file_verifier grub_tpm_verifier = { + + GRUB_MOD_INIT (tpm) + { ++ /* ++ * Even though this now calls ibmvtpm's grub_tpm_present() from GRUB_MOD_INIT(), ++ * it does seem to call it late enough in the initialization sequence so ++ * that whatever discovered "device nodes" before this GRUB_MOD_INIT() is ++ * called, enables the ibmvtpm driver to see the device nodes. ++ */ ++ if (!grub_tpm_present()) ++ return; + grub_verifier_register (&grub_tpm_verifier); + } + + GRUB_MOD_FINI (tpm) + { ++ if (!grub_tpm_present()) ++ return; + grub_verifier_unregister (&grub_tpm_verifier); + } +diff --git a/include/grub/tpm.h b/include/grub/tpm.h +index 5c285cbc52..c19fcbd0a6 100644 +--- a/include/grub/tpm.h ++++ b/include/grub/tpm.h +@@ -36,4 +36,5 @@ + + grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size, + grub_uint8_t pcr, const char *description); ++int grub_tpm_present (void); + #endif diff --git a/SOURCES/0329-grub_dl_set_mem_attrs-fix-format-string.patch b/SOURCES/0329-grub_dl_set_mem_attrs-fix-format-string.patch new file mode 100644 index 0000000..ee50591 --- /dev/null +++ b/SOURCES/0329-grub_dl_set_mem_attrs-fix-format-string.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 7 Apr 2023 14:54:35 +0200 +Subject: [PATCH] grub_dl_set_mem_attrs(): fix format string + +The grub_dprintf() call for printing the message + + updating attributes for GOT and trampolines + +passes the argument "mod->name", but the format string doesn't accept that +argument. + +Print the module name too. + +Example output: + +> kern/dl.c:736: updating attributes for GOT and trampolines ("video_fb") + +Fixes: ad1b904d325b (nx: set page permissions for loaded modules.) +Signed-off-by: Laszlo Ersek +--- + grub-core/kern/dl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index ab9101a5ad..a97f4a8b13 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -733,7 +733,8 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) + { + tgsz = ALIGN_UP(tgsz, arch_addralign); + +- grub_dprintf ("modules", "updating attributes for GOT and trampolines\n", ++ grub_dprintf ("modules", ++ "updating attributes for GOT and trampolines (\"%s\")\n", + mod->name); + grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, + GRUB_MEM_ATTR_W); diff --git a/SOURCES/0330-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch b/SOURCES/0330-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch new file mode 100644 index 0000000..b95e678 --- /dev/null +++ b/SOURCES/0330-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch @@ -0,0 +1,140 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 7 Apr 2023 16:21:54 +0200 +Subject: [PATCH] grub_dl_set_mem_attrs(): add self-check for the tramp/GOT + sizes + +On aarch64 UEFI, we currently have a crasher: + + grub_dl_load_core() + grub_dl_load_core_noinit() + + /* independent allocation: must remain writable */ + mod = grub_zalloc(); + + /* allocates module image with incorrect tail alignment */ + grub_dl_load_segments() + + /* write-protecting the module image makes "mod" read-only! */ + grub_dl_set_mem_attrs() + grub_update_mem_attrs() + + grub_dl_init() + /* page fault, crash */ + mod->next = ...; + +- Commit 887f1d8fa976 ("modules: load module sections at page-aligned + addresses", 2023-02-08) forgot to page-align the allocation of the + trampolines and GOT areas of grub2 modules, in grub_dl_load_segments(). + +- Commit ad1b904d325b ("nx: set page permissions for loaded modules.", + 2023-02-08) calculated a common bounding box for the trampolines and GOT + areas in grub_dl_set_mem_attrs(), rounded the box size up to a whole + multiple of EFI page size ("arch_addralign"), and write-protected the + resultant page range. + +Consequently, grub_dl_load_segments() places the module image in memory +such that its tail -- the end of the trampolines and GOT areas -- lands at +the head of a page whose tail in turn contains independent memory +allocations, such as "mod". grub_dl_set_mem_attrs() will then unwittingly +write-protect these other allocations too. + +But "mod" must remain writable: we assign "mod->next" in grub_dl_init() +subsequently. Currently we crash there with a page fault / permission +fault. + +(The crash is not trivial to hit: the tramp/GOT areas are irrelevant on +x86_64, plus the page protection depends on the UEFI platform firmware +providing EFI_MEMORY_ATTRIBUTE_PROTOCOL. In practice, the crash is +restricted to aarch64 edk2 (ArmVirtQemu) builds containing commit +1c4dfadb4611, "ArmPkg/CpuDxe: Implement EFI memory attributes protocol", +2023-03-16.) + +Example log before the patch: + +> kern/dl.c:736: updating attributes for GOT and trampolines ("video_fb") +> kern/efi/mm.c:927: set +rx -w on 0x13b88b000-0x13b88bfff before:rwx after:r-x +> kern/dl.c:744: done updating module memory attributes for "video_fb" +> kern/dl.c:639: flushing 0xe4f0 bytes at 0x13b87d000 +> kern/arm64/cache.c:42: D$ line size: 64 +> kern/arm64/cache.c:43: I$ line size: 64 +> kern/dl.c:839: module name: video_fb +> kern/dl.c:840: init function: 0x0 +> kern/dl.c:865: Initing module video_fb +> +> Synchronous Exception at 0x000000013B8A76EC +> PC 0x00013B8A76EC +> +> X0 0x000000013B88B960 X1 0x0000000000000000 X2 0x000000013F93587C X3 0x0000000000000075 +> +> SP 0x00000000470745C0 ELR 0x000000013B8A76EC SPSR 0x60000205 FPSR 0x00000000 +> ESR 0x9600004F FAR 0x000000013B88B9D0 +> +> ESR : EC 0x25 IL 0x1 ISS 0x0000004F +> +> Data abort: Permission fault, third level + +Note the following: + +- The whole 4K page at 0x1_3B88_B000 is write-protected. + +- The "video_fb" module actually lives at [0x1_3B87_D000, 0x1_3B88_B4F0) + -- left-inclusive, right-exclusive --; that is, in the last page (at + 0x1_3B88_B000), it only occupies the first 0x4F0 bytes. + +- The instruction at 0x1_3B8A_76EC faults. Not shown here, but it is a + store instruction, which writes to the field at offset 0x70 of the + structure pointed-to by the X0 register. This is the "mod->next" + assignment from grub_dl_init(). + +- The faulting address is therefore (X0 + 0x70), i.e., 0x1_3B88_B9D0. This + is indeed the value held in the FAR register. + +- The faulting address 0x1_3B88_B9D0 falls in the above-noted page (at + 0x1_3B88_B000), namely at offset 0x9D0. This is *beyond* the first 0x4F0 + bytes that the very tail of the "video_fb" module occupies at the front + of that page. + +For now, add a self-check that reports this bug (and prevents the crash by +skipping the write protection). + +Example log after the patch: + +> kern/dl.c:742:BUG: trying to protect pages outside of module allocation +> ("video_fb"): module base 0x13b87d000, size 0xe4f0; tramp/GOT base +> 0x13b88b000, size 0x1000 + +Signed-off-by: Laszlo Ersek +--- + grub-core/kern/dl.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index a97f4a8b13..3b66fa410e 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -682,7 +682,7 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) + grub_size_t arch_addralign = grub_arch_dl_min_alignment (); + grub_addr_t tgaddr; +- grub_uint64_t tgsz; ++ grub_size_t tgsz; + #endif + + grub_dprintf ("modules", "updating memory attributes for \"%s\"\n", +@@ -736,6 +736,15 @@ grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) + grub_dprintf ("modules", + "updating attributes for GOT and trampolines (\"%s\")\n", + mod->name); ++ if (tgaddr < (grub_addr_t)mod->base || ++ tgsz > (grub_addr_t)-1 - tgaddr || ++ tgaddr + tgsz > (grub_addr_t)mod->base + mod->sz) ++ return grub_error (GRUB_ERR_BUG, ++ "BUG: trying to protect pages outside of module " ++ "allocation (\"%s\"): module base %p, size 0x%" ++ PRIxGRUB_SIZE "; tramp/GOT base 0x%" PRIxGRUB_ADDR ++ ", size 0x%" PRIxGRUB_SIZE, ++ mod->name, mod->base, mod->sz, tgaddr, tgsz); + grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, + GRUB_MEM_ATTR_W); + } diff --git a/SOURCES/0331-grub_dl_load_segments-page-align-the-tramp-GOT-areas.patch b/SOURCES/0331-grub_dl_load_segments-page-align-the-tramp-GOT-areas.patch new file mode 100644 index 0000000..f29609d --- /dev/null +++ b/SOURCES/0331-grub_dl_load_segments-page-align-the-tramp-GOT-areas.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Fri, 7 Apr 2023 16:56:09 +0200 +Subject: [PATCH] grub_dl_load_segments(): page-align the tramp/GOT areas too + +The tramp/GOT write-protection in grub_dl_set_mem_attrs() requires that +the tramp/GOT areas of the module image *not* share a page with any other +memory allocations. Page-align the tramp/GOT areas, while satisfying their +intrinsic alignment requirements too. + +Fixes: 887f1d8fa976 (modules: load module sections at page-aligned addresses) +Fixes: ad1b904d325b (nx: set page permissions for loaded modules.) +Signed-off-by: Laszlo Ersek +--- + grub-core/kern/dl.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 3b66fa410e..f3cdb9e0ba 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -280,7 +280,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + grub_size_t tsize = 0, talign = 1, arch_addralign = 1; + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) + grub_size_t tramp; ++ grub_size_t tramp_align; + grub_size_t got; ++ grub_size_t got_align; + grub_err_t err; + #endif + char *ptr; +@@ -311,12 +313,18 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got); + if (err) + return err; +- tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN); +- if (talign < GRUB_ARCH_DL_TRAMP_ALIGN) +- talign = GRUB_ARCH_DL_TRAMP_ALIGN; +- tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN); +- if (talign < GRUB_ARCH_DL_GOT_ALIGN) +- talign = GRUB_ARCH_DL_GOT_ALIGN; ++ tramp_align = GRUB_ARCH_DL_TRAMP_ALIGN; ++ if (tramp_align < arch_addralign) ++ tramp_align = arch_addralign; ++ tsize += ALIGN_UP (tramp, tramp_align); ++ if (talign < tramp_align) ++ talign = tramp_align; ++ got_align = GRUB_ARCH_DL_GOT_ALIGN; ++ if (got_align < arch_addralign) ++ got_align = arch_addralign; ++ tsize += ALIGN_UP (got, got_align); ++ if (talign < got_align) ++ talign = got_align; + #endif + + #ifdef GRUB_MACHINE_EMU +@@ -376,11 +384,11 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + } + } + #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, tramp_align); + mod->tramp = ptr; + mod->trampptr = ptr; + ptr += tramp; +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, got_align); + mod->got = ptr; + mod->gotptr = ptr; + ptr += got; diff --git a/SOURCES/0332-emu-Add-switch-root-to-grub-emu.patch b/SOURCES/0332-emu-Add-switch-root-to-grub-emu.patch new file mode 100644 index 0000000..2a0f34b --- /dev/null +++ b/SOURCES/0332-emu-Add-switch-root-to-grub-emu.patch @@ -0,0 +1,330 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Fri, 31 Mar 2023 20:47:58 +0200 +Subject: [PATCH] emu: Add switch-root to grub-emu + +If the kernel running grub emu is the same as the one we want to +boot, it makes sense that we just switch-root instead of kexec +the same kernel again by doing grub2-emu --switch-root + +Signed-off-by: Nicolas Frayer +--- + grub-core/kern/emu/main.c | 5 +- + grub-core/kern/emu/misc.c | 13 +++ + grub-core/loader/emu/linux.c | 209 +++++++++++++++++++++++++++++++++++++++++-- + include/grub/emu/exec.h | 2 +- + include/grub/emu/misc.h | 2 + + 5 files changed, 223 insertions(+), 8 deletions(-) + +diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c +index 68e2b283bb..ccb2863f5b 100644 +--- a/grub-core/kern/emu/main.c ++++ b/grub-core/kern/emu/main.c +@@ -108,6 +108,7 @@ static struct argp_option options[] = { + {"verbose", 'v', 0, 0, N_("print verbose messages."), 0}, + {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0}, + {"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0}, ++ {"switch-root", 'W', 0, 0, N_("use switch-root to only switch root filesystem without restarting the kernel."), 0}, + { 0, 0, 0, 0, 0, 0 } + }; + +@@ -168,7 +169,9 @@ argp_parser (int key, char *arg, struct argp_state *state) + case 'X': + grub_util_set_kexecute (); + break; +- ++ case 'W': ++ grub_util_set_switch_root (); ++ break; + case ARGP_KEY_ARG: + { + /* Too many arguments. */ +diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c +index 02d27c3440..4b5123ef96 100644 +--- a/grub-core/kern/emu/misc.c ++++ b/grub-core/kern/emu/misc.c +@@ -40,6 +40,7 @@ + + int verbosity; + int kexecute; ++int switchroot = 0; + + void + grub_util_warn (const char *fmt, ...) +@@ -231,3 +232,15 @@ grub_util_get_kexecute (void) + { + return kexecute; + } ++ ++void ++grub_util_set_switch_root (void) ++{ ++ switchroot = 1; ++} ++ ++int ++grub_util_get_switch_root (void) ++{ ++ return switchroot; ++} +diff --git a/grub-core/loader/emu/linux.c b/grub-core/loader/emu/linux.c +index 7de3f7f861..6feb0412c5 100644 +--- a/grub-core/loader/emu/linux.c ++++ b/grub-core/loader/emu/linux.c +@@ -15,7 +15,6 @@ + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ +- + #include + #include + #include +@@ -33,6 +32,196 @@ static char *kernel_path; + static char *initrd_path; + static char *boot_cmdline; + ++static grub_err_t ++grub_switch_root (void) ++{ ++ char *tmp = NULL; ++ char *options_cmd = NULL; ++ char *options = NULL; ++ char *subvol = NULL; ++ char *root_uuid = NULL; ++ char *kernel_release = NULL; ++ grub_err_t rc = GRUB_ERR_NONE; ++ const char *subvol_param = "subvol="; ++ const char *kernel_release_prefix = "/boot/vmlinuz-"; ++ const char *root_prefix = "root="; ++ const char *systemctl[] = {"systemctl", "--force", "switch-root", "/sysroot", NULL}; ++ const char *mountrootfs[] = {"mount", root_uuid, "/sysroot", options_cmd, options, NULL}; ++ const char *unamer[] = {"uname", "-r", NULL}; ++ char *uname_buf = NULL; ++ int i = 0; ++ ++ /* Extract the kernel release tag from kernel_path */ ++ if (!kernel_path) ++ { ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ grub_dprintf ("linux", "switch_root: No kernel_path found\n"); ++ goto out; ++ } ++ ++ if ((kernel_release = grub_xasprintf ("%s", (kernel_path + grub_strlen (kernel_release_prefix)))) == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocate memory\n"); ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ goto out; ++ } ++ ++ ++ /* Check for kernel mismatch */ ++ /* Retrieve the current kernel relase tag */ ++ grub_util_exec_redirect (unamer, NULL, "/tmp/version"); ++ ++ grub_file_t f = grub_file_open ("/tmp/version", GRUB_FILE_TYPE_FS_SEARCH); ++ ++ if (f == NULL) ++ { ++ grub_dprintf ("linux", "failed opening file.\n"); ++ rc = GRUB_ERR_FILE_NOT_FOUND; ++ goto out; ++ } ++ ++ if ((uname_buf = grub_malloc (f->size)) == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocate memory\n"); ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ if (grub_file_read (f, uname_buf, f->size) < 0) ++ { ++ grub_dprintf ("linux", "switch_root: failed to read from file\n"); ++ rc = GRUB_ERR_FILE_READ_ERROR; ++ goto out; ++ } ++ ++ grub_file_close (f); ++ ++ if (grub_strstr (uname_buf, kernel_release) == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: kernel mismatch, not performing switch-root ...\n"); ++ rc = GRUB_ERR_NO_KERNEL; ++ goto out; ++ } ++ ++ /* Extract the root partition from boot_cmdline */ ++ if (!boot_cmdline) ++ { ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ goto out; ++ } ++ ++ tmp = grub_strdup (boot_cmdline); ++ ++ if (tmp == NULL) ++ { ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ if ((root_uuid = grub_strstr (tmp, root_prefix)) == NULL) ++ { ++ rc = GRUB_ERR_BAD_ARGUMENT; ++ grub_dprintf ("linux", "switch_root: Can't find rootfs\n"); ++ goto out; ++ } ++ ++ root_uuid += grub_strlen (root_prefix); ++ ++ while (root_uuid[i] != ' ' && root_uuid[i] != '\0') ++ i++; ++ ++ root_uuid[i] = '\0'; ++ ++ /* Allocate a new buffer holding root_uuid */ ++ root_uuid = grub_xasprintf ("%s", root_uuid); ++ ++ if (root_uuid == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocated memory\n"); ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ /* Check for subvol parameter */ ++ grub_strcpy (tmp, boot_cmdline); ++ ++ if ((subvol = grub_strstr(tmp, subvol_param)) != NULL) ++ { ++ i = 0; ++ ++ while (subvol[i] != ' ' && subvol[i] != '\0') ++ i++; ++ ++ subvol[i] = '\0'; ++ ++ /* Allocate a new buffer holding subvol */ ++ subvol = grub_xasprintf("%s", subvol); ++ ++ if (subvol == NULL) ++ { ++ grub_dprintf ("linux", "switch_root: Failed to allocated memory\n"); ++ rc = GRUB_ERR_OUT_OF_MEMORY; ++ goto out; ++ } ++ ++ options_cmd = grub_xasprintf("%s", "-o"); ++ options = grub_xasprintf("%s", subvol); ++ } ++ ++ if (options == NULL) ++ { ++ mountrootfs[3] = NULL; ++ } ++ else ++ { ++ mountrootfs[3] = options_cmd; ++ mountrootfs[4] = options; ++ } ++ ++ mountrootfs[1] = root_uuid; ++ ++ grub_dprintf ("linux", "Executing:\n"); ++ grub_dprintf ("linux", "%s %s %s %s %s\n", mountrootfs[0], mountrootfs[1], ++ mountrootfs[2], mountrootfs[3], mountrootfs[4]); ++ ++ /* Mount the rootfs */ ++ rc = grub_util_exec (mountrootfs); ++ ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("linux", "switch_root: Failed.\n"); ++ rc = GRUB_ERR_INVALID_COMMAND; ++ goto out; ++ } ++ ++ grub_dprintf ("linux", "Done.\n"); ++ ++ grub_dprintf ("linux", "%s %s %s %s\n", systemctl[0], systemctl[1], ++ systemctl[2], systemctl[3]); ++ ++ /* Switch root */ ++ rc = grub_util_exec (systemctl); ++ ++ if (rc != GRUB_ERR_NONE) ++ { ++ grub_dprintf ("linux", "switch_root: Failed.\n"); ++ rc = GRUB_ERR_INVALID_COMMAND; ++ goto out; ++ } ++ ++ grub_dprintf ("linux", "Done.\n"); ++ ++out: ++ grub_free (tmp); ++ grub_free (options_cmd); ++ grub_free (options); ++ grub_free (subvol); ++ grub_free (root_uuid); ++ grub_free (uname_buf); ++ grub_free (kernel_release); ++ return rc; ++} ++ + static grub_err_t + grub_linux_boot (void) + { +@@ -51,12 +240,20 @@ grub_linux_boot (void) + else + initrd_param = grub_xasprintf ("%s", ""); + +- grub_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n", +- (kexecute) ? "P" : "Not p", +- kernel_path, initrd_param, boot_cmdline); ++ if (grub_util_get_switch_root() == 1) ++ { ++ rc = grub_switch_root(); ++ if (rc != GRUB_ERR_NONE) ++ grub_fatal (N_("Failed to execute switch_root\n")); ++ } ++ else if (kexecute) ++ { ++ grub_dprintf ("linux", "%serforming 'kexec -la %s %s %s'\n", ++ (kexecute) ? "P" : "Not p", ++ kernel_path, initrd_param, boot_cmdline); + +- if (kexecute) +- rc = grub_util_exec (kexec); ++ rc = grub_util_exec (kexec); ++ } + + grub_free (initrd_param); + +diff --git a/include/grub/emu/exec.h b/include/grub/emu/exec.h +index 1b61b4a2e5..e82f13215e 100644 +--- a/include/grub/emu/exec.h ++++ b/include/grub/emu/exec.h +@@ -36,7 +36,7 @@ grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file, + int + EXPORT_FUNC(grub_util_exec) (const char *const *argv); + int +-grub_util_exec_redirect (const char *const *argv, const char *stdin_file, ++EXPORT_FUNC(grub_util_exec_redirect) (const char *const *argv, const char *stdin_file, + const char *stdout_file); + int + grub_util_exec_redirect_null (const char *const *argv); +diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h +index 01056954b9..f3a712a8b2 100644 +--- a/include/grub/emu/misc.h ++++ b/include/grub/emu/misc.h +@@ -59,6 +59,8 @@ void EXPORT_FUNC(grub_util_error) (const char *fmt, ...) __attribute__ ((format + + void EXPORT_FUNC(grub_util_set_kexecute) (void); + int EXPORT_FUNC(grub_util_get_kexecute) (void) WARN_UNUSED_RESULT; ++void EXPORT_FUNC(grub_util_set_switch_root) (void); ++int EXPORT_FUNC(grub_util_get_switch_root) (void); + + grub_uint64_t EXPORT_FUNC (grub_util_get_cpu_time_ms) (void); + diff --git a/SOURCES/0333-util-Enable-default-kernel-for-updates.patch b/SOURCES/0333-util-Enable-default-kernel-for-updates.patch new file mode 100644 index 0000000..ac9ef0b --- /dev/null +++ b/SOURCES/0333-util-Enable-default-kernel-for-updates.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marta Lewandowska +Date: Wed, 24 May 2023 11:22:47 +0200 +Subject: [PATCH] util: Enable default kernel for updates + +Several kernel variants can be installed on a system in parallel. +In order to allow the user to choose which kernel will be set to +default after an update, re-enable grub's usage of DEFAULTKERNEL as +set in /etc/sysconfig/kernel + +Signed-off-by: Marta Lewandowska +--- + util/grub-get-kernel-settings.in | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/util/grub-get-kernel-settings.in b/util/grub-get-kernel-settings.in +index 7e87dfccc0e4..f71bc64360b0 100644 +--- a/util/grub-get-kernel-settings.in ++++ b/util/grub-get-kernel-settings.in +@@ -68,6 +68,14 @@ if test -f /etc/sysconfig/kernel ; then + . /etc/sysconfig/kernel + fi + ++GRUB_DEFAULT_KERNEL_TYPE=${DEFAULTKERNEL/-core/} ++if [ "$GRUB_DEFAULT_KERNEL_TYPE" != "kernel" ]; then ++ echo GRUB_NON_STANDARD_KERNEL=true ++ echo export GRUB_NON_STANDARD_KERNEL ++ GRUB_DEFAULT_KERNEL_TYPE=${GRUB_DEFAULT_KERNEL_TYPE/kernel-/} ++fi ++echo GRUB_DEFAULT_KERNEL_TYPE=$GRUB_DEFAULT_KERNEL_TYPE ++echo export GRUB_DEFAULT_KERNEL_TYPE + if [ "$MAKEDEBUG" = "yes" ]; then + echo GRUB_LINUX_MAKE_DEBUG=true + echo export GRUB_LINUX_MAKE_DEBUG diff --git a/SOURCES/0334-efi-http-change-uint32_t-to-uintn_t.patch b/SOURCES/0334-efi-http-change-uint32_t-to-uintn_t.patch new file mode 100644 index 0000000..f970eb1 --- /dev/null +++ b/SOURCES/0334-efi-http-change-uint32_t-to-uintn_t.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Keng-Yu Lin +Date: Wed, 26 Apr 2023 01:43:16 -0400 +Subject: [PATCH] efi/http: change uint32_t to uintn_t + +Modify UINT32 to UINTN in EFI_HTTP_MESSAGE to +be UEFI 2.9 compliant. + +Signed-off-by: Keng-Yu Lin +Signed-off-by: Nicolas Frayer +--- + include/grub/efi/http.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/grub/efi/http.h b/include/grub/efi/http.h +index c5e9a89f5050..ad164ba1913d 100644 +--- a/include/grub/efi/http.h ++++ b/include/grub/efi/http.h +@@ -171,9 +171,9 @@ typedef struct { + grub_efi_http_request_data_t *request; + grub_efi_http_response_data_t *response; + } data; +- grub_efi_uint32_t header_count; ++ grub_efi_uintn_t header_count; + grub_efi_http_header_t *headers; +- grub_efi_uint32_t body_length; ++ grub_efi_uintn_t body_length; + void *body; + } grub_efi_http_message_t; + diff --git a/SOURCES/0335-Add-Install-section-to-aux-systemd-units.patch b/SOURCES/0335-Add-Install-section-to-aux-systemd-units.patch new file mode 100644 index 0000000..c726850 --- /dev/null +++ b/SOURCES/0335-Add-Install-section-to-aux-systemd-units.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christian Glombek +Date: Wed, 9 Aug 2023 18:11:25 +0200 +Subject: [PATCH] Add [Install] section to aux systemd units + +Currently in Fedora, these services are statically enabled by symlinks, +with no other way to disable them than to manually delete those symlinks. +This is problematic in Fedora IoT, where grub-boot-success.timer is +not supposed to be enabled. + +This change adds `[Install]` sections to all systemd units that are +currently enabled statically, so that they can be enabled dynamically +via presets or manually instead. +--- + docs/grub-boot-indeterminate.service | 3 +++ + docs/grub-boot-success.timer | 3 +++ + util/systemd/grub-systemd-integration.service.in | 3 +++ + 3 files changed, 9 insertions(+) + +diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service +index 6c8dcb186b63..5bcb474a3d31 100644 +--- a/docs/grub-boot-indeterminate.service ++++ b/docs/grub-boot-indeterminate.service +@@ -9,3 +9,6 @@ Before=system-update-pre.target + [Service] + Type=oneshot + ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate ++ ++[Install] ++WantedBy=system-update.target +diff --git a/docs/grub-boot-success.timer b/docs/grub-boot-success.timer +index 406f17200560..1d124cccc146 100644 +--- a/docs/grub-boot-success.timer ++++ b/docs/grub-boot-success.timer +@@ -5,3 +5,6 @@ ConditionVirtualization=!container + + [Timer] + OnActiveSec=2min ++ ++[Install] ++WantedBy=timers.target +diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in +index c81fb594ce17..22ca1ca4885e 100644 +--- a/util/systemd/grub-systemd-integration.service.in ++++ b/util/systemd/grub-systemd-integration.service.in +@@ -6,3 +6,6 @@ ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu + + [Service] + ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh ++ ++[Install] ++WantedBy=reboot.target diff --git a/SOURCES/0336-arm64-Use-proper-memory-type-for-kernel-allocation.patch b/SOURCES/0336-arm64-Use-proper-memory-type-for-kernel-allocation.patch new file mode 100644 index 0000000..e77fcbf --- /dev/null +++ b/SOURCES/0336-arm64-Use-proper-memory-type-for-kernel-allocation.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Tue, 28 Jun 2022 23:06:46 +0200 +Subject: [PATCH] arm64: Use proper memory type for kernel allocation + +Currently, the kernel pages are allocated with type EFI_LOADER_DATA. +While the vast majority of systems will happily execute code from those +pages (i.e. don't care about memory protection), the Microsoft Surface +Pro X stalls, as this memory is not designated as "executable". + +Therefore, allocate the kernel pages as EFI_LOADER_CODE to request +memory that is actually executable. + +Signed-off-by: Maximilian Luz +--- + grub-core/loader/arm64/linux.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 419f2201df8b..a3a193c255e9 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -26,7 +26,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + #include +@@ -403,7 +405,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_loader_unset(); + + kernel_alloc_pages = GRUB_EFI_BYTES_TO_PAGES (kernel_size + align - 1); +- kernel_alloc_addr = grub_efi_allocate_any_pages (kernel_alloc_pages); ++ kernel_alloc_addr = grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, ++ kernel_alloc_pages, ++ GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++ GRUB_EFI_LOADER_CODE); + grub_dprintf ("linux", "kernel numpages: %d\n", kernel_alloc_pages); + if (!kernel_alloc_addr) + { diff --git a/SOURCES/0337-Fix-missing-include-in-ofdisk.c.patch b/SOURCES/0337-Fix-missing-include-in-ofdisk.c.patch new file mode 100644 index 0000000..84a1240 --- /dev/null +++ b/SOURCES/0337-Fix-missing-include-in-ofdisk.c.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 29 Sep 2023 10:56:11 -0400 +Subject: [PATCH] Fix missing #include in ofdisk.c + +Recently we started building with -Werror=implicit-function-declaration, +and discovered that ofdisk.c is missing an include to declare +grub_env_get(). + +This patch adds that #include. + +Signed-off-by: Peter Jones +--- + grub-core/disk/ieee1275/ofdisk.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c +index 5534684..6e33d5d 100644 +--- a/grub-core/disk/ieee1275/ofdisk.c ++++ b/grub-core/disk/ieee1275/ofdisk.c +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + static char *last_devpath; + static grub_ieee1275_ihandle_t last_ihandle; diff --git a/SOURCES/0338-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch b/SOURCES/0338-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch new file mode 100644 index 0000000..5c7e1a3 --- /dev/null +++ b/SOURCES/0338-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch @@ -0,0 +1,226 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 25 Jul 2023 13:23:10 -0400 +Subject: [PATCH] kern/ieee1275/init: ppc64: Restrict high memory in presence + of fadump + +When a kernel dump is present then restrict the high memory regions to +avoid allocating memory where the kernel dump resides. Use the +ibm,kernel-dump node under /rtas to determine whether a kernel dump exists +and up to which limit grub can use available memory. Set the +upper_mem_limit to the size of the kernel dump section of type +'REAL_MODE_REGION' and therefore only allow grub's memory usage for high +addresses from RMO_ADDR_MAX to 'upper_mem_limit'. This means that grub can +use high memory in the range of RMO_ADDR_MAX (768MB) to upper_mem_limit and +the kernel-dump memory regions above 'upper_mem_limit' remain untouched. +This change has no effect on memory allocations below 'linux_rmo_save' +(typically at 640MB). + +Also, fall back to allocating below rmo_linux_save in case the chunk of +memory there would be larger than the chunk of memory above RMO_ADDR_MAX. +This can for example occur if a free memory area is found starting at 300MB +extending up to 1GB but a kernel dump is located at 768MB and therefore +does not allow the allocation of the high memory area but requiring to use +the chunk starting at 300MB to avoid an unnecessary out-of-memory +condition. + +Signed-off-by: Stefan Berger +Reviewed-by: Hari Bathini +Cc: Pavithra Prakash +Cc: Michael Ellerman +Cc: Carolyn Scherrer +Cc: Mahesh Salgaonkar +Cc: Sourabh Jain +--- + grub-core/kern/ieee1275/init.c | 144 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 142 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c +index 3d4ad9d1f162..8e7f742fad46 100644 +--- a/grub-core/kern/ieee1275/init.c ++++ b/grub-core/kern/ieee1275/init.c +@@ -17,6 +17,8 @@ + * along with GRUB. If not, see . + */ + ++#include /* offsetof() */ ++ + #include + #include + #include +@@ -198,6 +200,96 @@ grub_claim_heap (void) + #else + /* Helpers for mm on powerpc. */ + ++/* ibm,kernel-dump data structures */ ++struct kd_section ++{ ++ grub_uint32_t flags; ++ grub_uint16_t src_datatype; ++#define KD_SRC_DATATYPE_REAL_MODE_REGION 0x0011 ++ grub_uint16_t error_flags; ++ grub_uint64_t src_address; ++ grub_uint64_t num_bytes; ++ grub_uint64_t act_bytes; ++ grub_uint64_t dst_address; ++} GRUB_PACKED; ++ ++#define MAX_KD_SECTIONS 10 ++ ++struct kernel_dump ++{ ++ grub_uint32_t format; ++ grub_uint16_t num_sections; ++ grub_uint16_t status_flags; ++ grub_uint32_t offset_1st_section; ++ grub_uint32_t num_blocks; ++ grub_uint64_t start_block; ++ grub_uint64_t num_blocks_avail; ++ grub_uint32_t offet_path_string; ++ grub_uint32_t max_time_allowed; ++ struct kd_section kds[MAX_KD_SECTIONS]; /* offset_1st_section should point to kds[0] */ ++} GRUB_PACKED; ++ ++/* ++ * Determine if a kernel dump exists and if it does, then determine the highest ++ * address that grub can use for memory allocations. ++ * The caller must have initialized *highest to rmo_top. *highest will not ++ * be modified if no kernel dump is found. ++ */ ++static void ++check_kernel_dump (grub_uint64_t *highest) ++{ ++ struct kernel_dump kernel_dump; ++ grub_ssize_t kernel_dump_size; ++ grub_ieee1275_phandle_t rtas; ++ struct kd_section *kds; ++ grub_size_t i; ++ ++ /* If there's a kernel-dump it must have at least one section */ ++ if (grub_ieee1275_finddevice ("/rtas", &rtas) || ++ grub_ieee1275_get_property (rtas, "ibm,kernel-dump", &kernel_dump, ++ sizeof (kernel_dump), &kernel_dump_size) || ++ kernel_dump_size <= (grub_ssize_t) offsetof (struct kernel_dump, kds[1])) ++ return; ++ ++ kernel_dump_size = grub_min (kernel_dump_size, (grub_ssize_t) sizeof (kernel_dump)); ++ ++ if (grub_be_to_cpu32 (kernel_dump.format) != 1) ++ { ++ grub_printf (_("Error: ibm,kernel-dump has an unexpected format version '%u'\n"), ++ grub_be_to_cpu32 (kernel_dump.format)); ++ return; ++ } ++ ++ if (grub_be_to_cpu16 (kernel_dump.num_sections) > MAX_KD_SECTIONS) ++ { ++ grub_printf (_("Error: Too many kernel dump sections: %d\n"), ++ grub_be_to_cpu32 (kernel_dump.num_sections)); ++ return; ++ } ++ ++ for (i = 0; i < grub_be_to_cpu16 (kernel_dump.num_sections); i++) ++ { ++ kds = (struct kd_section *) ((grub_addr_t) &kernel_dump + ++ grub_be_to_cpu32 (kernel_dump.offset_1st_section) + ++ i * sizeof (struct kd_section)); ++ /* sanity check the address is within the 'kernel_dump' struct */ ++ if ((grub_addr_t) kds > (grub_addr_t) &kernel_dump + kernel_dump_size + sizeof (*kds)) ++ { ++ grub_printf (_("Error: 'kds' address beyond last available section\n")); ++ return; ++ } ++ ++ if ((grub_be_to_cpu16 (kds->src_datatype) == KD_SRC_DATATYPE_REAL_MODE_REGION) && ++ (grub_be_to_cpu64 (kds->src_address) == 0)) ++ { ++ *highest = grub_min (*highest, grub_be_to_cpu64 (kds->num_bytes)); ++ break; ++ } ++ } ++ ++ return; ++} ++ + /* + * How much memory does OF believe exists in total? + * +@@ -277,10 +369,31 @@ regions_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + * + * Finally, we also want to make sure that when grub loads the kernel, + * it isn't going to use up all the memory we're trying to reserve! So +- * enforce our entire RUNTIME_MIN_SPACE here: ++ * enforce our entire RUNTIME_MIN_SPACE here (no fadump): ++ * ++ * | Top of memory == upper_mem_limit -| ++ * | | ++ * | available | ++ * | | ++ * |---------- 768 MB ----------| ++ * | | ++ * | reserved | ++ * | | ++ * |--- 768 MB - runtime min space ---| ++ * | | ++ * | available | ++ * | | ++ * |---------- 0 MB ----------| ++ * ++ * In case fadump is used, we allow the following: + * + * |---------- Top of memory ----------| + * | | ++ * | unavailable | ++ * | (kernel dump area) | ++ * | | ++ * |--------- upper_mem_limit ---------| ++ * | | + * | available | + * | | + * |---------- 768 MB ----------| +@@ -335,17 +448,44 @@ regions_claim (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, + } + else + { ++ grub_uint64_t upper_mem_limit = rmo_top; ++ grub_uint64_t orig_addr = addr; ++ ++ check_kernel_dump (&upper_mem_limit); ++ + /* + * we order these cases to prefer higher addresses and avoid some + * splitting issues ++ * The following shows the order of variables: ++ * no kernel dump: linux_rmo_save < RMO_ADDR_MAX <= upper_mem_limit == rmo_top ++ * with kernel dump: liuxx_rmo_save < RMO_ADDR_MAX <= upper_mem_limit <= rmo_top + */ +- if (addr < RMO_ADDR_MAX && (addr + len) > RMO_ADDR_MAX) ++ if (addr < RMO_ADDR_MAX && (addr + len) > RMO_ADDR_MAX && upper_mem_limit >= RMO_ADDR_MAX) + { + grub_dprintf ("ieee1275", + "adjusting region for RUNTIME_MIN_SPACE: (%llx -> %llx) -> (%llx -> %llx)\n", + addr, addr + len, RMO_ADDR_MAX, addr + len); + len = (addr + len) - RMO_ADDR_MAX; + addr = RMO_ADDR_MAX; ++ ++ /* We must not exceed the upper_mem_limit (assuming it's >= RMO_ADDR_MAX) */ ++ if (addr + len > upper_mem_limit) ++ { ++ /* take the bigger chunk from either below linux_rmo_save or above upper_mem_limit */ ++ len = upper_mem_limit - addr; ++ if (orig_addr < linux_rmo_save && linux_rmo_save - orig_addr > len) ++ { ++ /* lower part is bigger */ ++ addr = orig_addr; ++ len = linux_rmo_save - addr; ++ } ++ ++ grub_dprintf ("ieee1275", "re-adjusted region to: (%llx -> %llx)\n", ++ addr, addr + len); ++ ++ if (len == 0) ++ return 0; ++ } + } + else if ((addr < linux_rmo_save) && ((addr + len) > linux_rmo_save)) + { diff --git a/SOURCES/0339-grub-install-on-EFI-if-forced.patch b/SOURCES/0339-grub-install-on-EFI-if-forced.patch new file mode 100644 index 0000000..ad231ac --- /dev/null +++ b/SOURCES/0339-grub-install-on-EFI-if-forced.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marta Lewandowska +Date: Fri, 13 Oct 2023 09:13:41 +0200 +Subject: [PATCH] grub-install on EFI if forced + +UEFI Secure Boot requires signed grub binaries to work, so grub- +install should not be used. However, users who have Secure Boot +disabled and wish to use the command should not be prevented from +doing so if they invoke --force. + +fixes bz#1917213 / bz#2240994 + +Signed-off-by: Marta Lewandowska +--- + util/grub-install.c | 42 ++++++++++++++++++++++++++---------------- + 1 file changed, 26 insertions(+), 16 deletions(-) + +diff --git a/util/grub-install.c b/util/grub-install.c +index 5babc7af5518..162162bec6e2 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -899,22 +899,6 @@ main (int argc, char *argv[]) + + platform = grub_install_get_target (grub_install_source_directory); + +- switch (platform) +- { +- case GRUB_INSTALL_PLATFORM_ARM_EFI: +- case GRUB_INSTALL_PLATFORM_ARM64_EFI: +- case GRUB_INSTALL_PLATFORM_I386_EFI: +- case GRUB_INSTALL_PLATFORM_IA64_EFI: +- case GRUB_INSTALL_PLATFORM_X86_64_EFI: +- is_efi = 1; +- grub_util_error (_("this utility cannot be used for EFI platforms" +- " because it does not support UEFI Secure Boot")); +- break; +- default: +- is_efi = 0; +- break; +- } +- + { + char *platname = grub_install_get_platform_name (platform); + fprintf (stderr, _("Installing for %s platform.\n"), platname); +@@ -1027,6 +1011,32 @@ main (int argc, char *argv[]) + grub_hostfs_init (); + grub_host_init (); + ++ switch (platform) ++ { ++ case GRUB_INSTALL_PLATFORM_I386_EFI: ++ case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ case GRUB_INSTALL_PLATFORM_ARM_EFI: ++ case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ case GRUB_INSTALL_PLATFORM_RISCV32_EFI: ++ case GRUB_INSTALL_PLATFORM_RISCV64_EFI: ++ case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ is_efi = 1; ++ if (!force) ++ grub_util_error (_("This utility should not be used for EFI platforms" ++ " because it does not support UEFI Secure Boot." ++ " If you really wish to proceed, invoke the --force" ++ " option.\nMake sure Secure Boot is disabled before" ++ " proceeding")); ++ break; ++ default: ++ is_efi = 0; ++ break; ++ ++ /* pacify warning. */ ++ case GRUB_INSTALL_PLATFORM_MAX: ++ break; ++ } ++ + /* Find the EFI System Partition. */ + if (is_efi) + { diff --git a/SOURCES/0340-Remove-Install-section-from-aux-systemd-units.patch b/SOURCES/0340-Remove-Install-section-from-aux-systemd-units.patch new file mode 100644 index 0000000..1a62cdd --- /dev/null +++ b/SOURCES/0340-Remove-Install-section-from-aux-systemd-units.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christian Glombek +Date: Tue, 14 Nov 2023 07:54:59 +0100 +Subject: [PATCH] Remove [Install] section from aux systemd units + +See https://bugzilla.redhat.com/show_bug.cgi?id=2247635#c7 +--- + docs/grub-boot-indeterminate.service | 3 --- + util/systemd/grub-systemd-integration.service.in | 3 --- + 2 files changed, 6 deletions(-) + +diff --git a/docs/grub-boot-indeterminate.service b/docs/grub-boot-indeterminate.service +index 5bcb474a3d31..6c8dcb186b63 100644 +--- a/docs/grub-boot-indeterminate.service ++++ b/docs/grub-boot-indeterminate.service +@@ -9,6 +9,3 @@ Before=system-update-pre.target + [Service] + Type=oneshot + ExecStart=/usr/bin/grub2-editenv - incr boot_indeterminate +- +-[Install] +-WantedBy=system-update.target +diff --git a/util/systemd/grub-systemd-integration.service.in b/util/systemd/grub-systemd-integration.service.in +index 22ca1ca4885e..c81fb594ce17 100644 +--- a/util/systemd/grub-systemd-integration.service.in ++++ b/util/systemd/grub-systemd-integration.service.in +@@ -6,6 +6,3 @@ ConditionPathExists=/run/systemd/reboot-to-boot-loader-menu + + [Service] + ExecStart=@libexecdir@/@grubdirname@/systemd-integration.sh +- +-[Install] +-WantedBy=reboot.target diff --git a/SOURCES/0341-fs-Remove-trailing-whitespaces.patch b/SOURCES/0341-fs-Remove-trailing-whitespaces.patch new file mode 100644 index 0000000..a876f6b --- /dev/null +++ b/SOURCES/0341-fs-Remove-trailing-whitespaces.patch @@ -0,0 +1,1681 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Elyes Haouas +Date: Fri, 4 Mar 2022 07:41:59 +0100 +Subject: [PATCH] fs: Remove trailing whitespaces + +Signed-off-by: Elyes Haouas +Reviewed-by: Daniel Kiper +--- + grub-core/fs/affs.c | 4 +- + grub-core/fs/archelp.c | 4 +- + grub-core/fs/bfs.c | 10 +- + grub-core/fs/cpio_common.c | 2 +- + grub-core/fs/fat.c | 6 +- + grub-core/fs/fshelp.c | 6 +- + grub-core/fs/hfs.c | 14 +-- + grub-core/fs/hfsplus.c | 8 +- + grub-core/fs/hfspluscomp.c | 6 +- + grub-core/fs/iso9660.c | 12 +-- + grub-core/fs/minix.c | 6 +- + grub-core/fs/nilfs2.c | 8 +- + grub-core/fs/ntfs.c | 8 +- + grub-core/fs/reiserfs.c | 2 +- + grub-core/fs/romfs.c | 8 +- + grub-core/fs/squash4.c | 26 ++--- + grub-core/fs/udf.c | 2 +- + grub-core/fs/ufs.c | 4 +- + grub-core/fs/xfs.c | 2 +- + grub-core/fs/zfs/zfs.c | 224 ++++++++++++++++++++-------------------- + grub-core/fs/zfs/zfs_fletcher.c | 12 +-- + grub-core/fs/zfs/zfs_sha256.c | 14 +-- + grub-core/fs/zfs/zfscrypt.c | 14 +-- + 23 files changed, 201 insertions(+), 201 deletions(-) + +diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c +index cafcd0fba916..0d90e9d1a895 100644 +--- a/grub-core/fs/affs.c ++++ b/grub-core/fs/affs.c +@@ -345,7 +345,7 @@ grub_affs_create_node (grub_fshelp_node_t dir, + if (len > sizeof (fil->name)) + len = sizeof (fil->name); + *grub_latin1_to_utf8 (name_u8, fil->name, len) = '\0'; +- ++ + (*node)->di = *fil; + for (nest = 0; nest < 8; nest++) + { +@@ -408,7 +408,7 @@ grub_affs_iterate_dir (grub_fshelp_node_t dir, + node = orig_node = grub_zalloc (sizeof (*node)); + if (!node) + return 1; +- ++ + *node = *dir; + if (hook (".", GRUB_FSHELP_DIR, node, hook_data)) + return 1; +diff --git a/grub-core/fs/archelp.c b/grub-core/fs/archelp.c +index 0cf544f6fdfe..998de88b865c 100644 +--- a/grub-core/fs/archelp.c ++++ b/grub-core/fs/archelp.c +@@ -75,7 +75,7 @@ handle_symlink (struct grub_archelp_data *data, + || !arcops->get_link_target) + return GRUB_ERR_NONE; + flen = grub_strlen (fn); +- if (grub_memcmp (*name, fn, flen) != 0 ++ if (grub_memcmp (*name, fn, flen) != 0 + || ((*name)[flen] != 0 && (*name)[flen] != '/')) + return GRUB_ERR_NONE; + rest = *name + flen; +@@ -251,7 +251,7 @@ grub_archelp_open (struct grub_archelp_data *data, + grub_uint32_t mode; + grub_int32_t mtime; + int restart; +- ++ + if (arcops->find_file (data, &fn, &mtime, &mode)) + goto fail; + +diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c +index 47dbe2011a14..a75876010d30 100644 +--- a/grub-core/fs/bfs.c ++++ b/grub-core/fs/bfs.c +@@ -530,13 +530,13 @@ iterate_in_b_tree (grub_disk_t disk, + err = read_b_node (disk, sb, ino, + node_off, + &node, +- &key_data, ++ &key_data, + &keylen_idx, + &key_values); + + if (err) + return 0; +- ++ + for (i = 0; i < grub_bfs_to_cpu_treehead (node->count_keys); i++) + { + char c; +@@ -682,7 +682,7 @@ find_in_b_tree (grub_disk_t disk, + level--; + grub_free (node); + continue; +- } ++ } + } + else if (level != 0 + && i + 1 < grub_bfs_to_cpu_treehead (node->count_keys)) +@@ -827,7 +827,7 @@ mount (grub_disk_t disk, struct grub_bfs_superblock *sb) + grub_err_t err; + err = grub_disk_read (disk, SUPERBLOCK, 0, sizeof (*sb), sb); + if (err == GRUB_ERR_OUT_OF_RANGE) +- return grub_error (GRUB_ERR_BAD_FS, ++ return grub_error (GRUB_ERR_BAD_FS, + #ifdef MODE_AFS + "not an AFS filesystem" + #else +@@ -843,7 +843,7 @@ mount (grub_disk_t disk, struct grub_bfs_superblock *sb) + || (grub_bfs_to_cpu32 (sb->bsize) + != (1U << grub_bfs_to_cpu32 (sb->log2_bsize))) + || grub_bfs_to_cpu32 (sb->log2_bsize) < GRUB_DISK_SECTOR_BITS) +- return grub_error (GRUB_ERR_BAD_FS, ++ return grub_error (GRUB_ERR_BAD_FS, + #ifdef MODE_AFS + "not an AFS filesystem" + #else +diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c +index 4e885d62313e..5d41b6fdbe1c 100644 +--- a/grub-core/fs/cpio_common.c ++++ b/grub-core/fs/cpio_common.c +@@ -117,7 +117,7 @@ grub_cpio_get_link_target (struct grub_archelp_data *data) + if (!ret) + return NULL; + +- err = grub_disk_read (data->disk, 0, data->dofs, data->size, ++ err = grub_disk_read (data->disk, 0, data->dofs, data->size, + ret); + if (err) + { +diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c +index ff6200c5be5d..c5efed724124 100644 +--- a/grub-core/fs/fat.c ++++ b/grub-core/fs/fat.c +@@ -246,7 +246,7 @@ grub_fat_mount (grub_disk_t disk) + #ifdef MODE_EXFAT + if (grub_memcmp ((const char *) bpb.oem_name, "EXFAT ", + sizeof (bpb.oem_name)) != 0) +- goto fail; ++ goto fail; + #endif + + /* Get the sizes of logical sectors and clusters. */ +@@ -321,7 +321,7 @@ grub_fat_mount (grub_disk_t disk) + #endif + + #ifdef MODE_EXFAT +- data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset) ++ data->cluster_sector = (grub_le_to_cpu32 (bpb.cluster_offset) + << data->logical_sector_bits); + data->num_clusters = (grub_le_to_cpu32 (bpb.cluster_count) + << data->logical_sector_bits); +@@ -694,7 +694,7 @@ grub_fat_iterate_dir_next (grub_fshelp_node_t node, + { + int j; + for (j = 0; j < 15; j++) +- ctxt->unibuf[slots * 15 + j] ++ ctxt->unibuf[slots * 15 + j] + = grub_le_to_cpu16 (sec.type_specific.file_name.str[j]); + slots++; + } +diff --git a/grub-core/fs/fshelp.c b/grub-core/fs/fshelp.c +index a2d0d297a520..cb41934b4fec 100644 +--- a/grub-core/fs/fshelp.c ++++ b/grub-core/fs/fshelp.c +@@ -215,7 +215,7 @@ find_file (char *currpath, + break; + + push_node (ctx, foundnode, foundtype); +- ++ + /* Read in the symlink and follow it. */ + if (ctx->currnode->type == GRUB_FSHELP_SYMLINK) + { +@@ -326,7 +326,7 @@ grub_fshelp_find_file (const char *path, grub_fshelp_node_t rootnode, + enum grub_fshelp_filetype expecttype) + { + return grub_fshelp_find_file_real (path, rootnode, foundnode, +- iterate_dir, NULL, ++ iterate_dir, NULL, + read_symlink, expecttype); + + } +@@ -339,7 +339,7 @@ grub_fshelp_find_file_lookup (const char *path, grub_fshelp_node_t rootnode, + enum grub_fshelp_filetype expecttype) + { + return grub_fshelp_find_file_real (path, rootnode, foundnode, +- NULL, lookup_file, ++ NULL, lookup_file, + read_symlink, expecttype); + + } +diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c +index f419965d154f..91dc0e69c3de 100644 +--- a/grub-core/fs/hfs.c ++++ b/grub-core/fs/hfs.c +@@ -883,7 +883,7 @@ grub_hfs_iterate_dir_it_dir (struct grub_hfs_node *hnd __attribute ((unused)), + { + struct grub_hfs_catalog_key *ckey = rec->key; + struct grub_hfs_iterate_dir_node_found_ctx *ctx = hook_arg; +- ++ + /* Stop when the entries do not match anymore. */ + if (ckey->parent_dir != ctx->dir_be) + return 1; +@@ -1077,7 +1077,7 @@ macroman_to_utf8 (char *to, const grub_uint8_t *from, grub_size_t len, + { + *optr++ = ':'; + continue; +- } ++ } + if (!(*iptr & 0x80)) + { + *optr++ = *iptr; +@@ -1094,7 +1094,7 @@ utf8_to_macroman (grub_uint8_t *to, const char *from) + grub_uint8_t *end = to + 31; + grub_uint8_t *optr = to; + const char *iptr = from; +- ++ + while (*iptr && optr < end) + { + int i, clen; +@@ -1104,7 +1104,7 @@ utf8_to_macroman (grub_uint8_t *to, const char *from) + *optr++ = '/'; + iptr++; + continue; +- } ++ } + if (!(*iptr & 0x80)) + { + *optr++ = *iptr++; +@@ -1165,7 +1165,7 @@ lookup_file (grub_fshelp_node_t dir, + *foundnode = grub_malloc (sizeof (struct grub_fshelp_node)); + if (!*foundnode) + return grub_errno; +- ++ + (*foundnode)->inode = grub_be_to_cpu32 (fdrec.dir.dirid); + (*foundnode)->fdrec = fdrec; + (*foundnode)->data = dir->data; +@@ -1266,7 +1266,7 @@ grub_hfs_dir (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, + .hook_data = hook_data + }; + grub_fshelp_node_t found = NULL; +- ++ + grub_dl_ref (my_mod); + + data = grub_hfs_mount (device->disk); +@@ -1295,7 +1295,7 @@ grub_hfs_open (struct grub_file *file, const char *name) + { + struct grub_hfs_data *data; + grub_fshelp_node_t found = NULL; +- ++ + grub_dl_ref (my_mod); + + data = grub_hfs_mount (file->device->disk); +diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c +index 19c7b3367987..6337cbfcbec6 100644 +--- a/grub-core/fs/hfsplus.c ++++ b/grub-core/fs/hfsplus.c +@@ -19,7 +19,7 @@ + + /* HFS+ is documented at http://developer.apple.com/technotes/tn/tn1150.html */ + +-#define grub_fshelp_node grub_hfsplus_file ++#define grub_fshelp_node grub_hfsplus_file + #include + #include + #include +@@ -146,7 +146,7 @@ grub_hfsplus_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + { + struct grub_hfsplus_btnode *nnode = 0; + grub_disk_addr_t blksleft = fileblock; +- struct grub_hfsplus_extent *extents = node->compressed ++ struct grub_hfsplus_extent *extents = node->compressed + ? &node->resource_extents[0] : &node->extents[0]; + + while (1) +@@ -477,7 +477,7 @@ grub_hfsplus_cmp_extkey (struct grub_hfsplus_key *keya, + + if (extkey_a->type < extkey_b->type) + return -1; +- ++ + akey = grub_be_to_cpu32 (extkey_a->start); + if (akey > extkey_b->start) + return 1; +@@ -568,7 +568,7 @@ grub_hfsplus_btree_search (struct grub_hfsplus_btree *btree, + struct grub_hfsplus_key_internal *key, + int (*compare_keys) (struct grub_hfsplus_key *keya, + struct grub_hfsplus_key_internal *keyb), +- struct grub_hfsplus_btnode **matchnode, ++ struct grub_hfsplus_btnode **matchnode, + grub_off_t *keyoffset) + { + grub_uint64_t currnode; +diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c +index d76f3f137a92..095ea48c9a62 100644 +--- a/grub-core/fs/hfspluscomp.c ++++ b/grub-core/fs/hfspluscomp.c +@@ -179,7 +179,7 @@ hfsplus_read_compressed_real (struct grub_hfsplus_file *node, + return len0; + } + +-static grub_err_t ++static grub_err_t + hfsplus_open_compressed_real (struct grub_hfsplus_file *node) + { + grub_err_t err; +@@ -306,8 +306,8 @@ hfsplus_open_compressed_real (struct grub_hfsplus_file *node) + + GRUB_MOD_INIT(hfspluscomp) + { +- grub_hfsplus_open_compressed = hfsplus_open_compressed_real; +- grub_hfsplus_read_compressed = hfsplus_read_compressed_real; ++ grub_hfsplus_open_compressed = hfsplus_open_compressed_real; ++ grub_hfsplus_read_compressed = hfsplus_read_compressed_real; + } + + GRUB_MOD_FINI(hfspluscomp) +diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c +index ac011950a64f..91817ec1f5ad 100644 +--- a/grub-core/fs/iso9660.c ++++ b/grub-core/fs/iso9660.c +@@ -181,7 +181,7 @@ static grub_err_t + iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int64_t *nix) + { + struct grub_datetime datetime; +- ++ + if (! i->year[0] && ! i->year[1] + && ! i->year[2] && ! i->year[3] + && ! i->month[0] && ! i->month[1] +@@ -198,7 +198,7 @@ iso9660_to_unixtime (const struct grub_iso9660_date *i, grub_int64_t *nix) + datetime.hour = (i->hour[0] - '0') * 10 + (i->hour[1] - '0'); + datetime.minute = (i->minute[0] - '0') * 10 + (i->minute[1] - '0'); + datetime.second = (i->second[0] - '0') * 10 + (i->second[1] - '0'); +- ++ + if (!grub_datetime2unixtime (&datetime, nix)) + return grub_error (GRUB_ERR_BAD_NUMBER, "incorrect date"); + *nix -= i->offset * 60 * 15; +@@ -216,7 +216,7 @@ iso9660_to_unixtime2 (const struct grub_iso9660_date2 *i, grub_int64_t *nix) + datetime.hour = i->hour; + datetime.minute = i->minute; + datetime.second = i->second; +- ++ + if (!grub_datetime2unixtime (&datetime, nix)) + return 0; + *nix -= i->offset * 60 * 15; +@@ -499,7 +499,7 @@ grub_iso9660_mount (grub_disk_t disk) + static char * + grub_iso9660_read_symlink (grub_fshelp_node_t node) + { +- return node->have_symlink ++ return node->have_symlink + ? grub_strdup (node->symlink + + (node->have_dirents) * sizeof (node->dirents[0]) + - sizeof (node->dirents)) : grub_strdup (""); +@@ -549,7 +549,7 @@ add_part (struct iterate_dir_ctx *ctx, + ctx->symlink = new; + + grub_memcpy (ctx->symlink + size, part, len2); +- ctx->symlink[size + len2] = 0; ++ ctx->symlink[size + len2] = 0; + } + + static grub_err_t +@@ -1106,7 +1106,7 @@ grub_iso9660_uuid (grub_device_t device, char **uuid) + } + + /* Get writing time of filesystem. */ +-static grub_err_t ++static grub_err_t + grub_iso9660_mtime (grub_device_t device, grub_int64_t *timebuf) + { + struct grub_iso9660_data *data; +diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c +index 3cd18c85b302..953df11916b8 100644 +--- a/grub-core/fs/minix.c ++++ b/grub-core/fs/minix.c +@@ -98,10 +98,10 @@ struct grub_minix_sblock + grub_uint32_t max_file_size; + grub_uint32_t zones; + grub_uint16_t magic; +- ++ + grub_uint16_t pad2; + grub_uint16_t block_size; +- grub_uint8_t disk_version; ++ grub_uint8_t disk_version; + }; + #else + struct grub_minix_sblock +@@ -351,7 +351,7 @@ grub_minix_read_inode (struct grub_minix_data *data, grub_minix_ino_t ino) + int offs = (ino % (GRUB_DISK_SECTOR_SIZE + / sizeof (struct grub_minix_inode)) + * sizeof (struct grub_minix_inode)); +- ++ + grub_disk_read (data->disk, block, offs, + sizeof (struct grub_minix_inode), &data->inode); + +diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c +index 3c248a910b42..fc7374ead490 100644 +--- a/grub-core/fs/nilfs2.c ++++ b/grub-core/fs/nilfs2.c +@@ -1,5 +1,5 @@ +-/* +- * nilfs2.c - New Implementation of Log filesystem ++/* ++ * nilfs2.c - New Implementation of Log filesystem + * + * Written by Jiro SEKIBA + * +@@ -680,12 +680,12 @@ grub_nilfs2_read_checkpoint (struct grub_nilfs2_data *data, + grub_disk_t disk = data->disk; + unsigned int nilfs2_block_count = (1 << LOG2_NILFS2_BLOCK_SIZE (data)); + +- /* Assume sizeof(struct grub_nilfs2_cpfile_header) < ++ /* Assume sizeof(struct grub_nilfs2_cpfile_header) < + sizeof(struct grub_nilfs2_checkpoint). + */ + blockno = grub_divmod64 (cpno, NILFS2_BLOCK_SIZE (data) / + sizeof (struct grub_nilfs2_checkpoint), &offset); +- ++ + pptr = grub_nilfs2_bmap_lookup (data, &data->sroot.sr_cpfile, blockno, 1); + if (pptr == (grub_uint64_t) - 1) + { +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 2f34f76da88c..3511e4e2cb6f 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -17,7 +17,7 @@ + * along with this program. If not, see . + */ + +-#define grub_fshelp_node grub_ntfs_file ++#define grub_fshelp_node grub_ntfs_file + + #include + #include +@@ -32,7 +32,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-#define grub_fshelp_node grub_ntfs_file ++#define grub_fshelp_node grub_ntfs_file + + static inline grub_uint16_t + u16at (void *ptr, grub_size_t ofs) +@@ -725,7 +725,7 @@ grub_ntfs_read_symlink (grub_fshelp_node_t node) + && grub_isalpha (buf[4])) + { + grub_memmove (buf, buf + 6, end - buf + 1 - 6); +- end -= 6; ++ end -= 6; + } + return buf; + } +@@ -992,7 +992,7 @@ grub_ntfs_dir_iter (const char *filename, enum grub_fshelp_filetype filetype, + grub_memset (&info, 0, sizeof (info)); + info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR); + info.mtimeset = 1; +- info.mtime = grub_divmod64 (node->mtime, 10000000, 0) ++ info.mtime = grub_divmod64 (node->mtime, 10000000, 0) + - 86400ULL * 365 * (1970 - 1601) + - 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100); + grub_free (node); +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index b8253da7fed2..42818c376229 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -775,7 +775,7 @@ grub_reiserfs_iterate_dir (grub_fshelp_node_t item, + char *entry_name; + char *entry_name_end = 0; + char c; +- ++ + if (!(entry_state & GRUB_REISERFS_VISIBLE_MASK)) + continue; + +diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c +index d97b8fbb8c36..1f7dcfca1d3a 100644 +--- a/grub-core/fs/romfs.c ++++ b/grub-core/fs/romfs.c +@@ -112,7 +112,7 @@ grub_romfs_mount (grub_device_t dev) + { + grub_error (GRUB_ERR_BAD_FS, "not romfs"); + return NULL; +- } ++ } + err = do_checksum (&sb, sizeof (sb) < grub_be_to_cpu32 (sb.sb.total_size) ? + sizeof (sb) : grub_be_to_cpu32 (sb.sb.total_size)); + if (err) +@@ -271,7 +271,7 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, + while (1) + { + char buf[16]; +- err = grub_disk_read (dir->data->disk, ++ err = grub_disk_read (dir->data->disk, + laddr >> GRUB_DISK_SECTOR_BITS, + laddr & (GRUB_DISK_SECTOR_SIZE - 1), + 16, buf); +@@ -298,7 +298,7 @@ grub_romfs_iterate_dir (grub_fshelp_node_t dir, + node->data_addr = grub_be_to_cpu32 (node->file.spec); + filetype = GRUB_FSHELP_DIR; + } +- ++ + break; + } + } +@@ -402,7 +402,7 @@ grub_romfs_read (grub_file_t file, char *buf, grub_size_t len) + data->data->disk->read_hook_data = file->read_hook_data; + grub_disk_read (data->data->disk, + (data->data_addr + file->offset) >> GRUB_DISK_SECTOR_BITS, +- (data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1), ++ (data->data_addr + file->offset) & (GRUB_DISK_SECTOR_SIZE - 1), + len, buf); + data->data->disk->read_hook = NULL; + +diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c +index 6dd731e231ee..02b1f9b6d101 100644 +--- a/grub-core/fs/squash4.c ++++ b/grub-core/fs/squash4.c +@@ -210,7 +210,7 @@ struct grub_fshelp_node + struct grub_squash_data *data; + struct grub_squash_inode ino; + grub_size_t stsize; +- struct ++ struct + { + grub_disk_addr_t ino_chunk; + grub_uint16_t ino_offset; +@@ -243,7 +243,7 @@ read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + csize = SQUASH_CHUNK_SIZE - offset; + if (csize > len) + csize = len; +- ++ + if (grub_le_to_cpu16 (d) & SQUASH_CHUNK_UNCOMPRESSED) + { + grub_disk_addr_t a = chunk_start + 2 + offset; +@@ -256,7 +256,7 @@ read_chunk (struct grub_squash_data *data, void *buf, grub_size_t len, + else + { + char *tmp; +- grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS; ++ grub_size_t bsize = grub_le_to_cpu16 (d) & ~SQUASH_CHUNK_FLAGS; + grub_disk_addr_t a = chunk_start + 2; + tmp = grub_malloc (bsize); + if (!tmp) +@@ -339,7 +339,7 @@ xz_decompress (char *inbuf, grub_size_t insize, grub_off_t off, + while (len) + { + enum xz_ret xzret; +- ++ + buf.out_pos = 0; + + xzret = xz_dec_run (data->xzdec, &buf); +@@ -399,9 +399,9 @@ squash_mount (grub_disk_t disk) + return NULL; + } + +- err = grub_disk_read (disk, ++ err = grub_disk_read (disk, + grub_le_to_cpu64 (sb.unk1offset) +- >> GRUB_DISK_SECTOR_BITS, ++ >> GRUB_DISK_SECTOR_BITS, + grub_le_to_cpu64 (sb.unk1offset) + & (GRUB_DISK_SECTOR_SIZE - 1), sizeof (frag), &frag); + if (grub_errno == GRUB_ERR_OUT_OF_RANGE) +@@ -448,7 +448,7 @@ squash_mount (grub_disk_t disk) + } + + data->blksz = grub_le_to_cpu32 (data->sb.block_size); +- for (data->log2_blksz = 0; ++ for (data->log2_blksz = 0; + (1U << data->log2_blksz) < data->blksz; + data->log2_blksz++); + +@@ -643,7 +643,7 @@ make_root_node (struct grub_squash_data *data, struct grub_fshelp_node *root) + root->stack[0].ino_chunk = grub_le_to_cpu32 (data->sb.root_ino_chunk); + root->stack[0].ino_offset = grub_cpu_to_le16 (data->sb.root_ino_offset); + return read_chunk (data, &root->ino, sizeof (root->ino), +- grub_le_to_cpu64 (data->sb.inodeoffset) ++ grub_le_to_cpu64 (data->sb.inodeoffset) + + root->stack[0].ino_chunk, + root->stack[0].ino_offset); + } +@@ -765,7 +765,7 @@ grub_squash_open (struct grub_file *file, const char *name) + } + + static grub_ssize_t +-direct_read (struct grub_squash_data *data, ++direct_read (struct grub_squash_data *data, + struct grub_squash_cache_inode *ino, + grub_off_t off, char *buf, grub_size_t len) + { +@@ -882,7 +882,7 @@ direct_read (struct grub_squash_data *data, + grub_free (block); + } + else +- err = grub_disk_read (data->disk, ++ err = grub_disk_read (data->disk, + (ino->cumulated_block_sizes[i] + a + boff) + >> GRUB_DISK_SECTOR_BITS, + (ino->cumulated_block_sizes[i] + a + boff) +@@ -946,7 +946,7 @@ grub_squash_read (grub_file_t file, char *buf, grub_size_t len) + } + else + off -= direct_len; +- ++ + err = read_chunk (data, &frag, sizeof (frag), + data->fragments, sizeof (frag) * fragment); + if (err) +@@ -957,7 +957,7 @@ grub_squash_read (grub_file_t file, char *buf, grub_size_t len) + b = grub_le_to_cpu32 (ino->ino.long_file.offset) + off; + else + b = grub_le_to_cpu32 (ino->ino.file.offset) + off; +- ++ + /* FIXME: cache uncompressed chunks. */ + if (compressed) + { +@@ -1013,7 +1013,7 @@ grub_squash_mtime (grub_device_t dev, grub_int64_t *tm) + *tm = grub_le_to_cpu32 (data->sb.creation_time); + squash_unmount (data); + return GRUB_ERR_NONE; +-} ++} + + static struct grub_fs grub_squash_fs = + { +diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c +index 2ac5c1d0048f..5a665093ed77 100644 +--- a/grub-core/fs/udf.c ++++ b/grub-core/fs/udf.c +@@ -567,7 +567,7 @@ grub_udf_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + (buf + sizeof (struct grub_udf_aed)); + continue; + } +- ++ + if (filebytes < adlen) + { + grub_uint32_t ad_block_num = ad->block.block_num; +diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c +index 34a698b71b8d..a354c92d936a 100644 +--- a/grub-core/fs/ufs.c ++++ b/grub-core/fs/ufs.c +@@ -568,7 +568,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path) + { + dirino = data->ino; + grub_ufs_read_inode (data, grub_ufs_to_cpu32 (dirent.ino), 0); +- ++ + if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) + == GRUB_UFS_ATTR_LNK) + { +@@ -613,7 +613,7 @@ grub_ufs_mount (grub_disk_t disk) + && ((data->sblock.bsize & (data->sblock.bsize - 1)) == 0) + && data->sblock.ino_per_group != 0) + { +- for (data->log2_blksz = 0; ++ for (data->log2_blksz = 0; + (1U << data->log2_blksz) < grub_ufs_to_cpu32 (data->sblock.bsize); + data->log2_blksz++); + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index e3816d1ec4a9..d6de7f1a2dd2 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -894,7 +894,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + tag, which is not used by GRUB. So it can be overwritten. */ + filename[direntry->len] = '\0'; + +- if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), ++ if (iterate_dir_call_hook (grub_be_to_cpu64(direntry->inode), + filename, &ctx)) + { + grub_free (dirblock); +diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c +index cf4d2ab189a5..5961818abc9a 100644 +--- a/grub-core/fs/zfs/zfs.c ++++ b/grub-core/fs/zfs/zfs.c +@@ -176,7 +176,7 @@ typedef struct decomp_entry + /* + * Signature for checksum functions. + */ +-typedef void zio_checksum_t(const void *data, grub_uint64_t size, ++typedef void zio_checksum_t(const void *data, grub_uint64_t size, + grub_zfs_endian_t endian, zio_cksum_t *zcp); + + /* +@@ -297,7 +297,7 @@ check_feature(const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) + static grub_err_t + check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ); + +-static grub_err_t ++static grub_err_t + zlib_decompress (void *s, void *d, + grub_size_t slen, grub_size_t dlen) + { +@@ -310,7 +310,7 @@ zlib_decompress (void *s, void *d, + return grub_errno; + } + +-static grub_err_t ++static grub_err_t + zle_decompress (void *s, void *d, + grub_size_t slen, grub_size_t dlen) + { +@@ -415,7 +415,7 @@ static zio_checksum_info_t zio_checksum_table[ZIO_CHECKSUM_FUNCTIONS] = { + */ + static grub_err_t + zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, +- grub_zfs_endian_t endian, ++ grub_zfs_endian_t endian, + char *buf, grub_size_t size) + { + zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1; +@@ -425,14 +425,14 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, + if (checksum >= ZIO_CHECKSUM_FUNCTIONS || ci->ci_func == NULL) + { + grub_dprintf ("zfs", "unknown checksum function %d\n", checksum); +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unknown checksum function %d", checksum); + } + + if (ci->ci_eck) + { +- expected_cksum = zec->zec_cksum; +- zec->zec_cksum = zc; ++ expected_cksum = zec->zec_cksum; ++ zec->zec_cksum = zc; + ci->ci_func (buf, size, endian, &actual_cksum); + zec->zec_cksum = expected_cksum; + zc = expected_cksum; +@@ -445,14 +445,14 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum, + { + grub_dprintf ("zfs", "checksum %s verification failed\n", ci->ci_name); + grub_dprintf ("zfs", "actual checksum %016llx %016llx %016llx %016llx\n", +- (unsigned long long) actual_cksum.zc_word[0], ++ (unsigned long long) actual_cksum.zc_word[0], + (unsigned long long) actual_cksum.zc_word[1], +- (unsigned long long) actual_cksum.zc_word[2], ++ (unsigned long long) actual_cksum.zc_word[2], + (unsigned long long) actual_cksum.zc_word[3]); + grub_dprintf ("zfs", "expected checksum %016llx %016llx %016llx %016llx\n", +- (unsigned long long) zc.zc_word[0], ++ (unsigned long long) zc.zc_word[0], + (unsigned long long) zc.zc_word[1], +- (unsigned long long) zc.zc_word[2], ++ (unsigned long long) zc.zc_word[2], + (unsigned long long) zc.zc_word[3]); + return grub_error (GRUB_ERR_BAD_FS, N_("checksum verification failed")); + } +@@ -485,17 +485,17 @@ vdev_uberblock_compare (uberblock_t * ub1, uberblock_t * ub2) + else + ub2_endian = GRUB_ZFS_BIG_ENDIAN; + +- if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) + < grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) + return -1; +- if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_txg, ub1_endian) + > grub_zfs_to_cpu64 (ub2->ub_txg, ub2_endian)) + return 1; + +- if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) + < grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) + return -1; +- if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) ++ if (grub_zfs_to_cpu64 (ub1->ub_timestamp, ub1_endian) + > grub_zfs_to_cpu64 (ub2->ub_timestamp, ub2_endian)) + return 1; + +@@ -573,7 +573,7 @@ find_bestub (uberblock_phys_t * ub_array, + grub_errno = GRUB_ERR_NONE; + continue; + } +- if (ubbest == NULL ++ if (ubbest == NULL + || vdev_uberblock_compare (&(ubptr->ubp_uberblock), + &(ubbest->ubp_uberblock)) > 0) + ubbest = ubptr; +@@ -594,10 +594,10 @@ get_psize (blkptr_t * bp, grub_zfs_endian_t endian) + static grub_uint64_t + dva_get_offset (const dva_t *dva, grub_zfs_endian_t endian) + { +- grub_dprintf ("zfs", "dva=%llx, %llx\n", +- (unsigned long long) dva->dva_word[0], ++ grub_dprintf ("zfs", "dva=%llx, %llx\n", ++ (unsigned long long) dva->dva_word[0], + (unsigned long long) dva->dva_word[1]); +- return grub_zfs_to_cpu64 ((dva)->dva_word[1], ++ return grub_zfs_to_cpu64 ((dva)->dva_word[1], + endian) << SPA_MINBLOCKSHIFT; + } + +@@ -720,7 +720,7 @@ fill_vdev_info_real (struct grub_zfs_data *data, + if (!fill->children) + { + fill->n_children = nelm; +- ++ + fill->children = grub_zalloc (fill->n_children + * sizeof (fill->children[0])); + } +@@ -839,7 +839,7 @@ nvlist_next_nvpair (const char *nvl, const char *nvpair) + { + /* skip over header, nvl_version and nvl_nvflag */ + nvpair = nvl + 4 * 3; +- } ++ } + else + { + /* skip to the next nvpair */ +@@ -873,10 +873,10 @@ nvlist_next_nvpair (const char *nvl, const char *nvpair) + name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); + nvp += 4; + +- nvp = nvp + ((name_len + 3) & ~3); // align +- if (nvp + 4 >= nvl + VDEV_PHYS_SIZE ++ nvp = nvp + ((name_len + 3) & ~3); // align ++ if (nvp + 4 >= nvl + VDEV_PHYS_SIZE + || encode_size < 0 +- || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) ++ || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE) + { + grub_dprintf ("zfs", "nvlist overflow\n"); + grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist"); +@@ -896,7 +896,7 @@ nvpair_name (const char *nvp, char **buf, grub_size_t *buflen) + { + /* skip over encode/decode size */ + nvp += 4 * 2; +- ++ + *buf = (char *) (nvp + 4); + *buflen = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); + +@@ -943,7 +943,7 @@ nvpair_value (const char *nvp,char **val, + + /* skip over name */ + nvp = nvp + ((name_len + 3) & ~3); /* align */ +- ++ + /* skip over type */ + nvp += 4; + nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvp)); +@@ -957,7 +957,7 @@ nvpair_value (const char *nvp,char **val, + *size_out = encode_size; + if (nelm_out) + *nelm_out = nelm; +- ++ + return 1; + } + +@@ -1183,7 +1183,7 @@ scan_disk (grub_device_t dev, struct grub_zfs_data *data, + desc.vdev_phys_sector + = label * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT) + + ((VDEV_SKIP_SIZE + VDEV_BOOT_HEADER_SIZE) >> SPA_MINBLOCKSHIFT) +- + (label < VDEV_LABELS / 2 ? 0 : ++ + (label < VDEV_LABELS / 2 ? 0 : + ALIGN_DOWN (grub_disk_native_sectors (dev->disk), sizeof (vdev_label_t)) + - VDEV_LABELS * (sizeof (vdev_label_t) >> SPA_MINBLOCKSHIFT)); + +@@ -1229,7 +1229,7 @@ scan_disk (grub_device_t dev, struct grub_zfs_data *data, + grub_free (bh); + return GRUB_ERR_NONE; + } +- ++ + grub_free (ub_array); + grub_free (bh); + +@@ -1269,7 +1269,7 @@ scan_devices_iter (const char *name, void *hook_data) + + if (!inserted) + grub_device_close (dev); +- ++ + return 0; + } + +@@ -1386,7 +1386,7 @@ recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, + for (i = 0; i < nbufs; i++) + { + grub_uint8_t mul; +- for (j = i; j < nbufs; j++) ++ for (j = i; j < nbufs; j++) + if (matrix1[i][j]) + break; + if (j == nbufs) +@@ -1453,7 +1453,7 @@ recovery (grub_uint8_t *bufs[4], grub_size_t s, const int nbufs, + } + default: + return grub_error (GRUB_ERR_BUG, "too big matrix"); +- } ++ } + } + + static grub_err_t +@@ -1510,7 +1510,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + int idx, orig_idx; + + if (desc->nparity < 1 || desc->nparity > 3) +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "raidz%d is not supported", desc->nparity); + + if (desc->n_children <= desc->nparity || desc->n_children < 1) +@@ -1659,7 +1659,7 @@ read_device (grub_uint64_t offset, struct grub_zfs_device_desc *desc, + len -= csize; + idx--; + } +- for (i = 0; i < failed_devices ++ for (i = 0; i < failed_devices + && recovery_len[i] == recovery_len[0]; + i++); + /* Since the chunks have variable length handle the last block +@@ -1782,7 +1782,7 @@ zio_read_gang (blkptr_t * bp, grub_zfs_endian_t endian, dva_t * dva, void *buf, + * Read in a block of raw data to buf. + */ + static grub_err_t +-zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, ++zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian, void *buf, + struct grub_zfs_data *data) + { + int i, psize; +@@ -1850,7 +1850,7 @@ decode_embedded_bp_compressed(const blkptr_t *bp, void *buf) + * and put the uncompressed data in buf. + */ + static grub_err_t +-zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, ++zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + grub_size_t *size, struct grub_zfs_data *data) + { + grub_size_t lsize, psize; +@@ -1936,7 +1936,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + if (encrypted) + { + if (!grub_zfs_decrypt) +- err = grub_error (GRUB_ERR_BAD_FS, ++ err = grub_error (GRUB_ERR_BAD_FS, + N_("module `%s' isn't loaded"), + "zfscrypt"); + else +@@ -1960,7 +1960,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + endian)); + return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain"); + } +- grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T ++ grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T + ", %p) for txg %" PRIxGRUB_UINT64_T "\n", + besti, data->subvol.keyring[besti].txg, + data->subvol.keyring[besti].cipher, +@@ -2008,7 +2008,7 @@ zio_read (blkptr_t *bp, grub_zfs_endian_t endian, void **buf, + * + */ + static grub_err_t +-dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, ++dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, + grub_zfs_endian_t *endian_out, struct grub_zfs_data *data) + { + int level; +@@ -2038,8 +2038,8 @@ dmu_read (dnode_end_t * dn, grub_uint64_t blkid, void **buf, + + if (BP_IS_HOLE (bp)) + { +- grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, +- dn->endian) ++ grub_size_t size = grub_zfs_to_cpu16 (dn->dn.dn_datablkszsec, ++ dn->endian) + << SPA_MINBLOCKSHIFT; + *buf = grub_malloc (size); + if (!*buf) +@@ -2103,7 +2103,7 @@ mzap_lookup (mzap_phys_t * zapobj, grub_zfs_endian_t endian, + } + + static int +-mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, ++mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, + int (*hook) (const char *name, grub_uint64_t val, + struct grub_zfs_dir_ctx *ctx), + struct grub_zfs_dir_ctx *ctx) +@@ -2117,7 +2117,7 @@ mzap_iterate (mzap_phys_t * zapobj, grub_zfs_endian_t endian, int objsize, + grub_dprintf ("zfs", "zap: name = %s, value = %llx, cd = %x\n", + mzap_ent[i].mze_name, (long long)mzap_ent[i].mze_value, + (int)mzap_ent[i].mze_cd); +- if (hook (mzap_ent[i].mze_name, ++ if (hook (mzap_ent[i].mze_name, + grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian), ctx)) + return 1; + } +@@ -2178,12 +2178,12 @@ name_cmp (const char *s1, const char *s2, grub_size_t n, + + if (!case_insensitive) + return grub_memcmp (t1, t2, n); +- ++ + while (n--) + { + if (grub_toupper (*t1) != grub_toupper (*t2)) + return (int) grub_toupper (*t1) - (int) grub_toupper (*t2); +- ++ + t1++; + t2++; + } +@@ -2221,7 +2221,7 @@ zap_leaf_array_equal (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + + /* XXX */ + static grub_err_t +-zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, ++zap_leaf_array_get (zap_leaf_phys_t * l, grub_zfs_endian_t endian, int blksft, + int chunk, grub_size_t array_len, char *buf) + { + grub_size_t bseen = 0; +@@ -2285,7 +2285,7 @@ zap_leaf_lookup (zap_leaf_phys_t * l, grub_zfs_endian_t endian, + + grub_dprintf ("zfs", "fzap: length %d\n", (int) le->le_name_length); + +- if (zap_leaf_array_equal (l, endian, blksft, ++ if (zap_leaf_array_equal (l, endian, blksft, + grub_zfs_to_cpu16 (le->le_name_chunk,endian), + grub_zfs_to_cpu16 (le->le_name_length, endian), + name, case_insensitive)) +@@ -2334,7 +2334,7 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, + { + void *l; + grub_uint64_t hash, idx, blkid; +- int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, ++ int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t leafendian; +@@ -2347,7 +2347,7 @@ fzap_lookup (dnode_end_t * zap_dnode, zap_phys_t * zap, + + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) +- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + idx = ZAP_HASH_IDX (hash, zap->zap_ptrtbl.zt_shift); + blkid = grub_zfs_to_cpu64 (((grub_uint64_t *) zap)[idx + (1 << (blksft - 3 - 1))], zap_dnode->endian); +@@ -2379,7 +2379,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + void *l_in; + grub_uint64_t idx, idx2, blkid; + grub_uint16_t chunk; +- int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, ++ int blksft = zfs_log2 (grub_zfs_to_cpu16 (zap_dnode->dn.dn_datablkszsec, + zap_dnode->endian) << DNODE_SHIFT); + grub_err_t err; + grub_zfs_endian_t endian; +@@ -2390,7 +2390,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, + /* get block id from index */ + if (zap->zap_ptrtbl.zt_numblks != 0) + { +- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "external pointer tables not supported"); + return 0; + } +@@ -2517,7 +2517,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val, + grub_dprintf ("zfs", "micro zap\n"); + err = mzap_lookup (zapbuf, endian, size, name, val, + case_insensitive); +- grub_dprintf ("zfs", "returned %d\n", err); ++ grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; + } +@@ -2527,7 +2527,7 @@ zap_lookup (dnode_end_t * zap_dnode, const char *name, grub_uint64_t *val, + /* this is a fat zap */ + err = fzap_lookup (zap_dnode, zapbuf, name, val, data, + case_insensitive); +- grub_dprintf ("zfs", "returned %d\n", err); ++ grub_dprintf ("zfs", "returned %d\n", err); + grub_free (zapbuf); + return err; + } +@@ -2560,7 +2560,7 @@ zap_iterate_u64_transform (const void *name, + } + + static int +-zap_iterate_u64 (dnode_end_t * zap_dnode, ++zap_iterate_u64 (dnode_end_t * zap_dnode, + int (*hook) (const char *name, grub_uint64_t val, + struct grub_zfs_dir_ctx *ctx), + struct grub_zfs_data *data, struct grub_zfs_dir_ctx *ctx) +@@ -2607,7 +2607,7 @@ zap_iterate_u64 (dnode_end_t * zap_dnode, + } + + static int +-zap_iterate (dnode_end_t * zap_dnode, ++zap_iterate (dnode_end_t * zap_dnode, + grub_size_t nameelemlen, + int (*hook) (const void *name, grub_size_t namelen, + const void *val_in, +@@ -2667,7 +2667,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + grub_err_t err; + grub_zfs_endian_t endian; + +- blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, ++ blksz = grub_zfs_to_cpu16 (mdn->dn.dn_datablkszsec, + mdn->endian) << SPA_MINBLOCKSHIFT; + epbs = zfs_log2 (blksz) - DNODE_SHIFT; + +@@ -2678,18 +2678,18 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + blkid = objnum >> epbs; + idx = objnum & ((1 << epbs) - 1); + +- if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn, +- sizeof (*mdn)) == 0 ++ if (data->dnode_buf != NULL && grub_memcmp (data->dnode_mdn, mdn, ++ sizeof (*mdn)) == 0 + && objnum >= data->dnode_start && objnum < data->dnode_end) + { + grub_memmove (&(buf->dn), &(data->dnode_buf)[idx], DNODE_SIZE); + buf->endian = data->dnode_endian; +- if (type && buf->dn.dn_type != type) +- return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); ++ if (type && buf->dn.dn_type != type) ++ return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); + return GRUB_ERR_NONE; + } + +- grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian, ++ grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian, + (unsigned long long) blkid); + err = dmu_read (mdn, blkid, &dnbuf, &endian, data); + if (err) +@@ -2715,8 +2715,8 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type, + + grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE); + buf->endian = endian; +- if (type && buf->dn.dn_type != type) +- return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); ++ if (type && buf->dn.dn_type != type) ++ return grub_error(GRUB_ERR_BAD_FS, "incorrect dnode type"); + + return GRUB_ERR_NONE; + } +@@ -2740,7 +2740,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + struct dnode_chain + { + struct dnode_chain *next; +- dnode_end_t dn; ++ dnode_end_t dn; + }; + struct dnode_chain *dnode_path = 0, *dn_new, *root; + +@@ -2750,7 +2750,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + dn_new->next = 0; + dnode_path = root = dn_new; + +- err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, ++ err = dnode_get (&subvol->mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + &(dnode_path->dn), data); + if (err) + { +@@ -2801,7 +2801,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + grub_free (dn_new); + return grub_errno; + } +- ++ + while (1) + { + /* skip leading slashes */ +@@ -2827,7 +2827,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + } + else + { +- err = grub_error (GRUB_ERR_FILE_NOT_FOUND, ++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, + "can't resolve .."); + break; + } +@@ -2877,7 +2877,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + { + grub_size_t block; + grub_size_t blksz; +- blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, ++ blksz = (grub_zfs_to_cpu16 (dnode_path->dn.dn.dn_datablkszsec, + dnode_path->dn.endian) + << SPA_MINBLOCKSHIFT); + +@@ -2916,7 +2916,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + if (err) + break; + free_symval = 1; +- } ++ } + path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); + if (!path_buf) + { +@@ -2930,9 +2930,9 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + if (free_symval) + grub_free (sym_value); + path [sym_sz] = 0; +- grub_memcpy (path + grub_strlen (path), oldpath, ++ grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); +- ++ + grub_free (oldpathbuf); + if (path[0] != '/') + { +@@ -2951,7 +2951,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + { + void *sahdrp; + int hdrsize; +- ++ + if (dnode_path->dn.dn.dn_bonuslen != 0) + { + sahdrp = DN_BONUS (&dnode_path->dn.dn); +@@ -2959,7 +2959,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + else if (dnode_path->dn.dn.dn_flags & DNODE_FLAG_SPILL_BLKPTR) + { + blkptr_t *bp = &dnode_path->dn.dn.dn_spill; +- ++ + err = zio_read (bp, dnode_path->dn.endian, &sahdrp, NULL, data); + if (err) + break; +@@ -2978,7 +2978,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + dnode_path->dn.endian) >> 12) & 0xf) == 0xa) + { + char *sym_value = (char *) sahdrp + hdrsize + SA_SYMLINK_OFFSET; +- grub_size_t sym_sz = ++ grub_size_t sym_sz = + grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + + hdrsize + + SA_SIZE_OFFSET), +@@ -2993,9 +2993,9 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + } + grub_memcpy (path, sym_value, sym_sz); + path [sym_sz] = 0; +- grub_memcpy (path + grub_strlen (path), oldpath, ++ grub_memcpy (path + grub_strlen (path), oldpath, + grub_strlen (oldpath) + 1); +- ++ + grub_free (oldpathbuf); + if (path[0] != '/') + { +@@ -3096,7 +3096,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, + + grub_dprintf ("zfs", "endian = %d\n", mosmdn->endian); + +- err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, ++ err = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT, + DMU_OT_OBJECT_DIRECTORY, mdn, data); + if (err) + return err; +@@ -3119,7 +3119,7 @@ get_filesystem_dnode (dnode_end_t * mosmdn, char *fsname, + { + grub_uint64_t childobj; + char *cname, ch; +- ++ + while (*fsname == '/') + fsname++; + +@@ -3279,7 +3279,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + filename = ptr_slash; + else + filename = "/"; +- grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n", ++ grub_dprintf ("zfs", "fsname = '%s' snapname='%s' filename = '%s'\n", + fsname, snapname, filename); + } + grub_dprintf ("zfs", "alive\n"); +@@ -3365,7 +3365,7 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + + snapobj = grub_zfs_to_cpu64 (((dsl_dataset_phys_t *) DN_BONUS (&subvol->mdn.dn))->ds_snapnames_zapobj, subvol->mdn.endian); + +- err = dnode_get (&(data->mos), snapobj, ++ err = dnode_get (&(data->mos), snapobj, + DMU_OT_DSL_DS_SNAP_MAP, &subvol->mdn, data); + if (!err) + err = zap_lookup (&subvol->mdn, snapname, &headobj, data, 0); +@@ -3383,13 +3383,13 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, + subvol->obj = headobj; + + make_mdn (&subvol->mdn, data); +- ++ + grub_dprintf ("zfs", "endian = %d\n", subvol->mdn.endian); + + if (*isfs) + { + grub_free (fsname); +- grub_free (snapname); ++ grub_free (snapname); + return GRUB_ERR_NONE; + } + err = dnode_get_path (subvol, filename, dn, data); +@@ -3409,9 +3409,9 @@ nvlist_find_value (const char *nvlist_in, const char *name, + char *nvp_name; + + /* Verify if the 1st and 2nd byte in the nvlist are valid. */ +- /* NOTE: independently of what endianness header announces all ++ /* NOTE: independently of what endianness header announces all + subsequent values are big-endian. */ +- if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN ++ if (nvlist[0] != NV_ENCODE_XDR || (nvlist[1] != NV_LITTLE_ENDIAN + && nvlist[1] != NV_BIG_ENDIAN)) + { + grub_dprintf ("zfs", "incorrect nvlist header\n"); +@@ -3532,13 +3532,13 @@ get_nvlist_size (const char *beg, const char *limit) + { + const char *ptr; + grub_uint32_t encode_size; +- ++ + ptr = beg + 8; + + while (ptr < limit + && (encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (ptr)))) + ptr += encode_size; /* goto the next nvpair */ +- ptr += 8; ++ ptr += 8; + return (ptr > limit) ? -1 : (ptr - beg); + } + +@@ -3674,8 +3674,8 @@ zfs_mount (grub_device_t dev) + } + + ub = &(data->current_uberblock); +- ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, +- GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC ++ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, ++ GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); + + err = zio_read (&ub->ub_rootbp, ub_endian, +@@ -3728,7 +3728,7 @@ grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist) + return err; + } + +-static grub_err_t ++static grub_err_t + zfs_label (grub_device_t device, char **label) + { + char *nvlist; +@@ -3740,7 +3740,7 @@ zfs_label (grub_device_t device, char **label) + return grub_errno; + + err = zfs_fetch_nvlist (data->device_original, &nvlist); +- if (err) ++ if (err) + { + zfs_unmount (data); + return err; +@@ -3752,7 +3752,7 @@ zfs_label (grub_device_t device, char **label) + return grub_errno; + } + +-static grub_err_t ++static grub_err_t + zfs_uuid (grub_device_t device, char **uuid) + { + struct grub_zfs_data *data; +@@ -3770,7 +3770,7 @@ zfs_uuid (grub_device_t device, char **uuid) + return GRUB_ERR_NONE; + } + +-static grub_err_t ++static grub_err_t + zfs_mtime (grub_device_t device, grub_int64_t *mt) + { + struct grub_zfs_data *data; +@@ -3784,8 +3784,8 @@ zfs_mtime (grub_device_t device, grub_int64_t *mt) + return grub_errno; + + ub = &(data->current_uberblock); +- ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, +- GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC ++ ub_endian = (grub_zfs_to_cpu64 (ub->ub_magic, ++ GRUB_ZFS_LITTLE_ENDIAN) == UBERBLOCK_MAGIC + ? GRUB_ZFS_LITTLE_ENDIAN : GRUB_ZFS_BIG_ENDIAN); + + *mt = grub_zfs_to_cpu64 (ub->ub_timestamp, ub_endian); +@@ -3823,7 +3823,7 @@ grub_zfs_open (struct grub_file *file, const char *fsfilename) + } + + /* We found the dnode for this file. Verify if it is a plain file. */ +- if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS) ++ if (data->dnode.dn.dn_type != DMU_OT_PLAIN_FILE_CONTENTS) + { + zfs_unmount (data); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("not a regular file")); +@@ -3898,7 +3898,7 @@ grub_zfs_read (grub_file_t file, char *buf, grub_size_t len) + return len; + } + +- blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec, ++ blksz = grub_zfs_to_cpu16 (data->dnode.dn.dn_datablkszsec, + data->dnode.endian) << SPA_MINBLOCKSHIFT; + + if (blksz == 0) +@@ -3991,11 +3991,11 @@ fill_fs_info (struct grub_dirhook_info *info, + dnode_end_t dn; + grub_uint64_t objnum; + grub_uint64_t headobj; +- ++ + grub_memset (info, 0, sizeof (*info)); +- ++ + info->dir = 1; +- ++ + if (mdn.dn.dn_type == DMU_OT_DSL_DIR) + { + headobj = grub_zfs_to_cpu64 (((dsl_dir_phys_t *) DN_BONUS (&mdn.dn))->dd_head_dataset_obj, mdn.endian); +@@ -4010,28 +4010,28 @@ fill_fs_info (struct grub_dirhook_info *info, + err = make_mdn (&mdn, data); + if (err) + return err; +- err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, ++ err = dnode_get (&mdn, MASTER_NODE_OBJ, DMU_OT_MASTER_NODE, + &dn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } +- ++ + err = zap_lookup (&dn, ZFS_ROOT_OBJ, &objnum, data, 0); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } +- ++ + err = dnode_get (&mdn, objnum, 0, &dn, data); + if (err) + { + grub_dprintf ("zfs", "failed here\n"); + return err; + } +- ++ + if (dn.dn.dn_bonustype == DMU_OT_SA) + { + void *sahdrp; +@@ -4117,15 +4117,15 @@ iterate_zap (const char *name, grub_uint64_t val, struct grub_zfs_dir_ctx *ctx) + info.mtime = grub_zfs_to_cpu64 (grub_get_unaligned64 ((char *) sahdrp + hdrsize + SA_MTIME_OFFSET), dn.endian); + info.case_insensitive = ctx->data->subvol.case_insensitive; + } +- ++ + if (dn.dn.dn_bonustype == DMU_OT_ZNODE) +- { ++ { + info.mtimeset = 1; + info.mtime = grub_zfs_to_cpu64 (((znode_phys_t *) DN_BONUS (&dn.dn))->zp_mtime[0], + dn.endian); + } + info.dir = (dn.dn.dn_type == DMU_OT_DIRECTORY_CONTENTS); +- grub_dprintf ("zfs", "type=%d, name=%s\n", ++ grub_dprintf ("zfs", "type=%d, name=%s\n", + (int)dn.dn.dn_type, (char *)name); + return ctx->hook (name, &info, ctx->hook_data); + } +@@ -4219,7 +4219,7 @@ grub_zfs_dir (grub_device_t device, const char *path, + + if (isfs) + { +- grub_uint64_t childobj, headobj; ++ grub_uint64_t childobj, headobj; + grub_uint64_t snapobj; + dnode_end_t dn; + struct grub_dirhook_info info; +@@ -4247,7 +4247,7 @@ grub_zfs_dir (grub_device_t device, const char *path, + } + + zap_iterate_u64 (&dn, iterate_zap_fs, data, &ctx); +- ++ + err = dnode_get (&(data->mos), headobj, DMU_OT_DSL_DATASET, &dn, data); + if (err) + { +@@ -4289,8 +4289,8 @@ check_feature (const char *name, grub_uint64_t val, + return 0; + if (name[0] == 0) + return 0; +- for (i = 0; spa_feature_names[i] != NULL; i++) +- if (grub_strcmp (name, spa_feature_names[i]) == 0) ++ for (i = 0; spa_feature_names[i] != NULL; i++) ++ if (grub_strcmp (name, spa_feature_names[i]) == 0) + return 0; + return 1; + } +@@ -4303,7 +4303,7 @@ check_feature (const char *name, grub_uint64_t val, + * 0: Success. + * errnum: Failure. + */ +- ++ + static grub_err_t + check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data ) + { +@@ -4328,7 +4328,7 @@ check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct gru + errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0); + if (errnum != 0) + return errnum; +- ++ + errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data); + if (errnum != 0) + return errnum; +diff --git a/grub-core/fs/zfs/zfs_fletcher.c b/grub-core/fs/zfs/zfs_fletcher.c +index 7d27b053dc7a..ad3be6705479 100644 +--- a/grub-core/fs/zfs/zfs_fletcher.c ++++ b/grub-core/fs/zfs/zfs_fletcher.c +@@ -39,14 +39,14 @@ + #include + + void +-fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, ++fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + zio_cksum_t *zcp) + { + const grub_uint64_t *ip = buf; + const grub_uint64_t *ipend = ip + (size / sizeof (grub_uint64_t)); + grub_uint64_t a0, b0, a1, b1; +- +- for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) ++ ++ for (a0 = b0 = a1 = b1 = 0; ip < ipend; ip += 2) + { + a0 += grub_zfs_to_cpu64 (ip[0], endian); + a1 += grub_zfs_to_cpu64 (ip[1], endian); +@@ -61,14 +61,14 @@ fletcher_2(const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + } + + void +-fletcher_4 (const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, ++fletcher_4 (const void *buf, grub_uint64_t size, grub_zfs_endian_t endian, + zio_cksum_t *zcp) + { + const grub_uint32_t *ip = buf; + const grub_uint32_t *ipend = ip + (size / sizeof (grub_uint32_t)); + grub_uint64_t a, b, c, d; +- +- for (a = b = c = d = 0; ip < ipend; ip++) ++ ++ for (a = b = c = d = 0; ip < ipend; ip++) + { + a += grub_zfs_to_cpu32 (ip[0], endian);; + b += a; +diff --git a/grub-core/fs/zfs/zfs_sha256.c b/grub-core/fs/zfs/zfs_sha256.c +index a181f076c54c..f042fa61ab89 100644 +--- a/grub-core/fs/zfs/zfs_sha256.c ++++ b/grub-core/fs/zfs/zfs_sha256.c +@@ -116,23 +116,23 @@ zio_checksum_SHA256(const void *buf, grub_uint64_t size, + grub_uint8_t pad[128]; + unsigned padsize = size & 63; + unsigned i; +- ++ + for (i = 0; i < size - padsize; i += 64) + SHA256Transform(H, (grub_uint8_t *)buf + i); +- ++ + for (i = 0; i < padsize; i++) + pad[i] = ((grub_uint8_t *)buf)[i]; +- ++ + for (pad[padsize++] = 0x80; (padsize & 63) != 56; padsize++) + pad[padsize] = 0; +- ++ + for (i = 0; i < 8; i++) + pad[padsize++] = (size << 3) >> (56 - 8 * i); +- ++ + for (i = 0; i < padsize && i <= 64; i += 64) + SHA256Transform(H, pad + i); +- +- zcp->zc_word[0] = grub_cpu_to_zfs64 ((grub_uint64_t)H[0] << 32 | H[1], ++ ++ zcp->zc_word[0] = grub_cpu_to_zfs64 ((grub_uint64_t)H[0] << 32 | H[1], + endian); + zcp->zc_word[1] = grub_cpu_to_zfs64 ((grub_uint64_t)H[2] << 32 | H[3], + endian); +diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c +index de3b015f5827..da30e9ab33dd 100644 +--- a/grub-core/fs/zfs/zfscrypt.c ++++ b/grub-core/fs/zfs/zfscrypt.c +@@ -46,7 +46,7 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + /* +- Mostly based on following article: ++ Mostly based on following article: + https://blogs.oracle.com/darren/entry/zfs_encryption_what_is_on + */ + +@@ -179,7 +179,7 @@ grub_gcm_mul (grub_uint8_t *a, const grub_uint8_t *b) + grub_crypto_xor (res, res, bs, 16); + grub_gcm_mul_x (bs); + } +- ++ + grub_memcpy (a, res, 16); + } + +@@ -275,7 +275,7 @@ algo_decrypt (grub_crypto_cipher_handle_t cipher, grub_uint64_t algo, + } + + static grub_err_t +-grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, ++grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + grub_uint64_t algo, + void *nonce, + char *buf, grub_size_t size, +@@ -286,7 +286,7 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + unsigned i; + grub_uint32_t sw[4]; + gcry_err_code_t err; +- ++ + grub_memcpy (sw, nonce, 16); + if (endian != GRUB_ZFS_BIG_ENDIAN) + for (i = 0; i < 4; i++) +@@ -302,7 +302,7 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher, + sw + 1, 3, 12); + if (err) + return grub_crypto_gcry_error (err); +- ++ + for (i = 0; i < 3; i++) + if (grub_zfs_to_cpu32 (expected_mac[i], endian) + != grub_be_to_cpu32 (mac[i])) +@@ -362,7 +362,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key, + grub_crypto_cipher_close (cipher); + continue; + } +- ++ + err = grub_crypto_cipher_set_key (cipher, wrap_key_real, + keylen); + if (err) +@@ -371,7 +371,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key, + grub_crypto_cipher_close (cipher); + continue; + } +- ++ + err = algo_decrypt (cipher, algo, decrypted, key->unknown_purpose_key, 32, + mac, key->unknown_purpose_nonce, 2, 16); + if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16) diff --git a/SOURCES/0342-fs-xfs-Fix-memory-leaks-in-XFS-module.patch b/SOURCES/0342-fs-xfs-Fix-memory-leaks-in-XFS-module.patch new file mode 100644 index 0000000..f5421ce --- /dev/null +++ b/SOURCES/0342-fs-xfs-Fix-memory-leaks-in-XFS-module.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "t.feng" +Date: Tue, 29 Nov 2022 17:14:15 +0800 +Subject: [PATCH] fs/xfs: Fix memory leaks in XFS module + +Signed-off-by: t.feng +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index d6de7f1a2dd2..b67407690c1a 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -585,7 +585,10 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + if (grub_disk_read (node->data->disk, + GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb (keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS), + 0, node->data->bsize, leaf)) +- return 0; ++ { ++ grub_free (leaf); ++ return 0; ++ } + + if ((!node->data->hascrc && + grub_strncmp ((char *) leaf->magic, "BMAP", 4)) || +@@ -751,6 +754,7 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename, + if (err) + { + grub_print_error (); ++ grub_free (fdiro); + return 0; + } + +@@ -861,7 +865,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + blk << dirblk_log2, + dirblk_size, dirblock, 0); + if (numread != dirblk_size) +- return 0; ++ { ++ grub_free (dirblock); ++ return 0; ++ } + + entries = (grub_be_to_cpu32 (tail->leaf_count) + - grub_be_to_cpu32 (tail->leaf_stale)); diff --git a/SOURCES/0343-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch b/SOURCES/0343-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch new file mode 100644 index 0000000..7083a57 --- /dev/null +++ b/SOURCES/0343-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Fri, 2 Jun 2023 18:08:44 +0000 +Subject: [PATCH] fs/xfs: Fix issues found while fuzzing the XFS filesystem + +While performing fuzz testing with XFS filesystem images with ASAN +enabled, several issues were found where the memory accesses are made +beyond the data that is allocated into the struct grub_xfs_data +structure's data field. + +The existing structure didn't store the size of the memory allocated into +the buffer in the data field and had no way to check it. To resolve these +issues, the data size is stored to enable checks into the data buffer. + +With these checks in place, the fuzzing corpus no longer cause any crashes. + +Signed-off-by: Darren Kenny +Signed-off-by: Robbie Harwood +Signed-off-by: Marta Lewandowska +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +--- + grub-core/fs/xfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index b67407690c1a..b91cd32b49ab 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -239,6 +239,7 @@ struct grub_fshelp_node + + struct grub_xfs_data + { ++ grub_size_t data_size; + struct grub_xfs_sblock sblock; + grub_disk_t disk; + int pos; +@@ -611,8 +612,20 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + } + else if (node->inode.format == XFS_INODE_FORMAT_EXT) + { ++ grub_addr_t exts_end = 0; ++ grub_addr_t data_end = 0; ++ + nrec = grub_be_to_cpu32 (node->inode.nextents); + exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode); ++ ++ if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) || ++ grub_add ((grub_addr_t) node->data, exts_end, &exts_end) || ++ grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) || ++ exts_end > data_end) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS extents"); ++ return 0; ++ } + } + else + { +@@ -803,6 +816,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de); + grub_uint8_t c; + ++ if ((inopos + (smallino ? 4 : 8)) > (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) ++ return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode"); ++ + /* inopos might be unaligned. */ + if (smallino) + ino = (((grub_uint32_t) inopos[0]) << 24) +@@ -829,6 +845,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + de->name[de->len] = c; + + de = grub_xfs_inline_next_de(dir->data, head, de); ++ ++ if ((grub_uint8_t *) de >= (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) ++ return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); ++ + } + break; + } +@@ -897,6 +917,9 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + } + + filename = (char *)(direntry + 1); ++ if (filename + direntry->len - 1 > (char *) tail) ++ return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); ++ + /* The byte after the filename is for the filetype, padding, or + tag, which is not used by GRUB. So it can be overwritten. */ + filename[direntry->len] = '\0'; +@@ -941,6 +964,8 @@ grub_xfs_mount (grub_disk_t disk) + if (!data) + return 0; + ++ data->data_size = sizeof (struct grub_xfs_data); ++ + grub_dprintf("xfs", "Reading sb\n"); + /* Read the superblock. */ + if (grub_disk_read (disk, 0, 0, +@@ -962,6 +987,7 @@ grub_xfs_mount (grub_disk_t disk) + if (! data) + goto fail; + ++ data->data_size = sz; + data->diropen.data = data; + data->diropen.ino = grub_be_to_cpu64(data->sblock.rootino); + data->diropen.inode_read = 1; diff --git a/SOURCES/0344-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch b/SOURCES/0344-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch new file mode 100644 index 0000000..d70ec5a --- /dev/null +++ b/SOURCES/0344-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lidong Chen +Date: Thu, 28 Sep 2023 22:33:44 +0000 +Subject: [PATCH] fs/xfs: Incorrect short form directory data boundary check + +After parsing of the current entry, the entry pointer is advanced +to the next entry at the end of the "for" loop. In case where the +last entry is at the end of the data boundary, the advanced entry +pointer can point off the data boundary. The subsequent boundary +check for the advanced entry pointer can cause a failure. + +The fix is to include the boundary check into the "for" loop +condition. + +Signed-off-by: Lidong Chen +Reviewed-by: Daniel Kiper +Tested-by: Sebastian Andrzej Siewior +Tested-by: Marta Lewandowska +--- + grub-core/fs/xfs.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index b91cd32b49ab..ebf962793fa7 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -810,7 +810,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + if (iterate_dir_call_hook (parent, "..", &ctx)) + return 1; + +- for (i = 0; i < head->count; i++) ++ for (i = 0; i < head->count && ++ (grub_uint8_t *) de < ((grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)); i++) + { + grub_uint64_t ino; + grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de); +@@ -845,10 +846,6 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + de->name[de->len] = c; + + de = grub_xfs_inline_next_de(dir->data, head, de); +- +- if ((grub_uint8_t *) de >= (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)) +- return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); +- + } + break; + } diff --git a/SOURCES/0345-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch b/SOURCES/0345-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch new file mode 100644 index 0000000..8c414a8 --- /dev/null +++ b/SOURCES/0345-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Anthony Iliopoulos +Date: Thu, 26 Oct 2023 11:53:39 +0200 +Subject: [PATCH] fs/xfs: Add large extent counters incompat feature support + +XFS introduced 64-bit extent counters for inodes via a series of +upstream commits and the feature was marked as stable in v6.5 via +commit 61d7e8274cd8 (xfs: drop EXPERIMENTAL tag for large extent +counts). + +Further, xfsprogs release v6.5.0 switched this feature on by default +in mkfs.xfs via commit e5b18d7d1d96 (mkfs: enable large extent counts +by default). + +Filesystems formatted with large extent count support, nrext64=1, are +thus currently not recognizable by GRUB, since this is an incompat +feature. Add the required support so that those filesystems and inodes +with large extent counters can be read by GRUB. + +Signed-off-by: Anthony Iliopoulos +Reviewed-by: Andrey Albershteyn +Reviewed-by: Daniel Kiper +Tested-by: Marta Lewandowska +Tested-by: Sebastian Andrzej Siewior +--- + grub-core/fs/xfs.c | 30 +++++++++++++++++++++++++----- + 1 file changed, 25 insertions(+), 5 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index 18edfcff486c..bc2224dbb463 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -79,6 +79,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + /* Inode flags2 flags */ + #define XFS_DIFLAG2_BIGTIME_BIT 3 + #define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT) ++#define XFS_DIFLAG2_NREXT64_BIT 4 ++#define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT) + + /* incompat feature flags */ + #define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ +@@ -86,6 +88,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ + #define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */ + #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */ ++#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ + + /* + * Directory entries with ftype are explicitly handled by GRUB code. +@@ -101,7 +104,8 @@ GRUB_MOD_LICENSE ("GPLv3+"); + XFS_SB_FEAT_INCOMPAT_SPINODES | \ + XFS_SB_FEAT_INCOMPAT_META_UUID | \ + XFS_SB_FEAT_INCOMPAT_BIGTIME | \ +- XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR) ++ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \ ++ XFS_SB_FEAT_INCOMPAT_NREXT64) + + struct grub_xfs_sblock + { +@@ -203,7 +207,8 @@ struct grub_xfs_inode + grub_uint16_t mode; + grub_uint8_t version; + grub_uint8_t format; +- grub_uint8_t unused2[26]; ++ grub_uint8_t unused2[18]; ++ grub_uint64_t nextents_big; + grub_uint64_t atime; + grub_uint64_t mtime; + grub_uint64_t ctime; +@@ -545,11 +550,26 @@ get_fsb (const void *keys, int idx) + return grub_be_to_cpu64 (grub_get_unaligned64 (p)); + } + ++static int ++grub_xfs_inode_has_large_extent_counts (const struct grub_xfs_inode *inode) ++{ ++ return inode->version >= 3 && ++ (inode->flags2 & grub_cpu_to_be64_compile_time (XFS_DIFLAG2_NREXT64)); ++} ++ ++static grub_uint64_t ++grub_xfs_get_inode_nextents (struct grub_xfs_inode *inode) ++{ ++ return (grub_xfs_inode_has_large_extent_counts (inode)) ? ++ grub_be_to_cpu64 (inode->nextents_big) : ++ grub_be_to_cpu32 (inode->nextents); ++} ++ + static grub_disk_addr_t + grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + { + struct grub_xfs_btree_node *leaf = 0; +- int ex, nrec; ++ grub_uint64_t ex, nrec; + struct grub_xfs_extent *exts; + grub_uint64_t ret = 0; + +@@ -574,7 +594,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + / (2 * sizeof (grub_uint64_t)); + do + { +- int i; ++ grub_uint64_t i; + + for (i = 0; i < nrec; i++) + { +@@ -621,7 +641,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) + grub_addr_t exts_end = 0; + grub_addr_t data_end = 0; + +- nrec = grub_be_to_cpu32 (node->inode.nextents); ++ nrec = grub_xfs_get_inode_nextents (&node->inode); + exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode); + + if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) || diff --git a/SOURCES/0346-chainloader-remove-device-path-debug-message.patch b/SOURCES/0346-chainloader-remove-device-path-debug-message.patch new file mode 100644 index 0000000..ef7720f --- /dev/null +++ b/SOURCES/0346-chainloader-remove-device-path-debug-message.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: raravind +Date: Tue, 9 May 2023 11:29:35 +0200 +Subject: [PATCH] chainloader: remove device path debug message + +Remove the debug message "/EndEntire" while using GRUB chainloader command. + +Signed-off-by: raravind +(cherry picked from commit f75f5386b7a6a7cb2e10d30f817a3564c0a28dd7) +--- + grub-core/loader/efi/chainloader.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index dd31ac9bb..b1c86dab2 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -210,7 +210,6 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + /* Fill the file path for the directory. */ + d = (grub_efi_device_path_t *) ((char *) file_path + + ((char *) d - (char *) dp)); +- grub_efi_print_device_path (d); + if (copy_file_path ((grub_efi_file_path_device_path_t *) d, + dir_start, dir_end - dir_start) != GRUB_ERR_NONE) + { +-- +2.43.0 + diff --git a/SOURCES/0347-normal-Remove-grub_env_set-prefix-in-grub_try_normal.patch b/SOURCES/0347-normal-Remove-grub_env_set-prefix-in-grub_try_normal.patch new file mode 100644 index 0000000..900c59a --- /dev/null +++ b/SOURCES/0347-normal-Remove-grub_env_set-prefix-in-grub_try_normal.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Tue, 19 Dec 2023 16:52:05 +0100 +Subject: [PATCH] normal: Remove grub_env_set prefix in grub_try_normal_prefix + +Commit de735a453aa35 added a grub_env_set where the prefix contains +the arch name in the pathname. This create issues when trying to +load modules using this prefix as the pathname contains a "doubled" +arch name in it (ie .../powerpc-ieee1275/powerpc-ieee1275/). + +Signed-off-by: Nicolas Frayer +--- + grub-core/normal/main.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index d59145f861d5..bac7b8a0e1d8 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -372,7 +372,6 @@ grub_try_normal_prefix (const char *prefix) + file = grub_file_open (config, GRUB_FILE_TYPE_CONFIG); + if (file) + { +- grub_env_set ("prefix", prefix); + grub_file_close (file); + err = GRUB_ERR_NONE; + } diff --git a/SOURCES/0348-add-flag-to-only-search-root-dev.patch b/SOURCES/0348-add-flag-to-only-search-root-dev.patch new file mode 100644 index 0000000..8ae8875 --- /dev/null +++ b/SOURCES/0348-add-flag-to-only-search-root-dev.patch @@ -0,0 +1,160 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marta Lewandowska +Date: Mon, 9 Oct 2023 08:53:18 +0200 +Subject: [PATCH] add flag to only search root dev + +fixes bz#2223437 + +Signed-off-by: Marta Lewandowska +--- + grub-core/commands/search.c | 36 ++++++++++++++++++++++++++++++++++++ + grub-core/commands/search_wrap.c | 5 +++++ + grub-core/kern/misc.c | 30 ++++++++++++++++++++++++++++++ + include/grub/misc.h | 1 + + include/grub/search.h | 3 ++- + 5 files changed, 74 insertions(+), 1 deletion(-) + +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index 57d26ced8a8e..819231751c38 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -85,6 +85,42 @@ iterate_device (const char *name, void *data) + grub_device_close (dev); + } + ++ /* Skip it if it's not the root device when requested. */ ++ if (ctx->flags & SEARCH_FLAGS_ROOTDEV_ONLY) ++ { ++ const char *root_dev; ++ root_dev = grub_env_get ("root"); ++ if (root_dev != NULL && *root_dev != '\0') ++ { ++ char *root_disk = grub_malloc (grub_strlen(root_dev) + 1); ++ char *name_disk = grub_malloc (grub_strlen(name) + 1); ++ char *rem_1 = grub_malloc(grub_strlen(root_dev) + 1); ++ char *rem_2 = grub_malloc(grub_strlen(name) + 1); ++ ++ if (root_disk != NULL && name_disk != NULL && ++ rem_1 != NULL && rem_2 != NULL) ++ { ++ /* get just the disk name; partitions will be different. */ ++ grub_str_sep (root_dev, root_disk, ',', rem_1); ++ grub_str_sep (name, name_disk, ',', rem_2); ++ if (root_disk != NULL && *root_disk != '\0' && ++ name_disk != NULL && *name_disk != '\0') ++ if (grub_strcmp(root_disk, name_disk) != 0) ++ { ++ grub_free (root_disk); ++ grub_free (name_disk); ++ grub_free (rem_1); ++ grub_free (rem_2); ++ return 0; ++ } ++ } ++ grub_free (root_disk); ++ grub_free (name_disk); ++ grub_free (rem_1); ++ grub_free (rem_2); ++ } ++ } ++ + #ifdef DO_SEARCH_FS_UUID + #define compare_fn grub_strcasecmp + #else +diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c +index 0b62acf85359..06b5f51eefb5 100644 +--- a/grub-core/commands/search_wrap.c ++++ b/grub-core/commands/search_wrap.c +@@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = + ARG_TYPE_STRING}, + {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, + {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, ++ {"root-dev-only", 'r', 0, N_("Only probe root device."), 0, 0}, + {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, + N_("First try the device HINT. If HINT ends in comma, " + "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, +@@ -75,6 +76,7 @@ enum options + SEARCH_SET, + SEARCH_NO_FLOPPY, + SEARCH_EFIDISK_ONLY, ++ SEARCH_ROOTDEV_ONLY, + SEARCH_HINT, + SEARCH_HINT_IEEE1275, + SEARCH_HINT_BIOS, +@@ -189,6 +191,9 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + if (state[SEARCH_EFIDISK_ONLY].set) + flags |= SEARCH_FLAGS_EFIDISK_ONLY; + ++ if (state[SEARCH_ROOTDEV_ONLY].set) ++ flags |= SEARCH_FLAGS_ROOTDEV_ONLY; ++ + if (state[SEARCH_LABEL].set) + grub_search_label (id, var, flags, hints, nhints); + else if (state[SEARCH_FS_UUID].set) +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index cb454614022f..c0ac7fee6cc2 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -619,6 +619,36 @@ grub_reverse (char *str) + } + } + ++/* Separate string into two parts, broken up by delimiter delim. */ ++void ++grub_str_sep (const char *s, char *p, char delim, char *r) ++{ ++ char* t = grub_strndup(s, grub_strlen(s)); ++ ++ if (t != NULL && *t != '\0') ++ { ++ char* tmp = t; ++ ++ while (((*p = *t) != '\0') && ((*p = *t) != delim)) ++ { ++ p++; ++ t++; ++ } ++ *p = '\0'; ++ ++ if (*t != '\0') ++ { ++ t++; ++ while ((*r++ = *t++) != '\0') ++ ; ++ *r = '\0'; ++ } ++ grub_free (tmp); ++ } ++ else ++ grub_free (t); ++} ++ + /* Divide N by D, return the quotient, and store the remainder in *R. */ + grub_uint64_t + grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r) +diff --git a/include/grub/misc.h b/include/grub/misc.h +index faae0ae8606c..981526644d29 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -314,6 +314,7 @@ void *EXPORT_FUNC(grub_memset) (void *s, int c, grub_size_t n); + grub_size_t EXPORT_FUNC(grub_strlen) (const char *s) WARN_UNUSED_RESULT; + int EXPORT_FUNC(grub_printf) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); + int EXPORT_FUNC(grub_printf_) (const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 1, 2))); ++void EXPORT_FUNC(grub_str_sep) (const char *s, char *p, char delim, char *r); + + /* Replace all `ch' characters of `input' with `with' and copy the + result into `output'; return EOS address of `output'. */ +diff --git a/include/grub/search.h b/include/grub/search.h +index 4190aeb2cbf5..321d1400e451 100644 +--- a/include/grub/search.h ++++ b/include/grub/search.h +@@ -22,7 +22,8 @@ + enum search_flags + { + SEARCH_FLAGS_NO_FLOPPY = 1, +- SEARCH_FLAGS_EFIDISK_ONLY = 2 ++ SEARCH_FLAGS_EFIDISK_ONLY = 2, ++ SEARCH_FLAGS_ROOTDEV_ONLY = 4 + }; + + void grub_search_fs_file (const char *key, const char *var, diff --git a/SOURCES/0349-Ignore-warnings-for-incompatible-types.patch b/SOURCES/0349-Ignore-warnings-for-incompatible-types.patch new file mode 100644 index 0000000..73e9910 --- /dev/null +++ b/SOURCES/0349-Ignore-warnings-for-incompatible-types.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Wed, 17 Jan 2024 21:15:14 +0100 +Subject: [PATCH] Ignore warnings for incompatible types + +Add -Wno-incompatible-pointer-types to ignore warnings for incompatible +types + +Signed-off-by: Nicolas Frayer +--- + configure.ac | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 79f45ef1e14c..b66e07c67851 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2009,8 +2009,8 @@ if test x"$enable_wextra" != xno ; then + HOST_CFLAGS="$HOST_CFLAGS -Wextra" + fi + +-TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines" +-HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines" ++TARGET_CFLAGS="$TARGET_CFLAGS -Werror=trampolines -fno-trampolines -Wno-incompatible-pointer-types" ++HOST_CFLAGS="$HOST_CFLAGS -Werror=trampolines -fno-trampolines -Wno-incompatible-pointer-types" + + TARGET_CPP="$TARGET_CC -E" + TARGET_CCAS=$TARGET_CC diff --git a/SOURCES/0350-fs-xfs-Fix-XFS-directory-extent-parsing.patch b/SOURCES/0350-fs-xfs-Fix-XFS-directory-extent-parsing.patch new file mode 100644 index 0000000..c005731 --- /dev/null +++ b/SOURCES/0350-fs-xfs-Fix-XFS-directory-extent-parsing.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jon DeVree +Date: Tue, 17 Oct 2023 23:03:47 -0400 +Subject: [PATCH] fs/xfs: Fix XFS directory extent parsing + +The XFS directory entry parsing code has never been completely correct +for extent based directories. The parser correctly handles the case +where the directory is contained in a single extent, but then mistakenly +assumes the data blocks for the multiple extent case are each identical +to the single extent case. The difference in the format of the data +blocks between the two cases is tiny enough that its gone unnoticed for +a very long time. + +A recent change introduced some additional bounds checking into the XFS +parser. Like GRUB's existing parser, it is correct for the single extent +case but incorrect for the multiple extent case. When parsing a directory +with multiple extents, this new bounds checking is sometimes (but not +always) tripped and triggers an "invalid XFS directory entry" error. This +probably would have continued to go unnoticed but the /boot/grub/ +directory is large enough that it often has multiple extents. + +The difference between the two cases is that when there are multiple +extents, the data blocks do not contain a trailer nor do they contain +any leaf information. That information is stored in a separate set of +extents dedicated to just the leaf information. These extents come after +the directory entry extents and are not included in the inode size. So +the existing parser already ignores the leaf extents. + +The only reason to read the trailer/leaf information at all is so that +the parser can avoid misinterpreting that data as directory entries. So +this updates the parser as follows: + +For the single extent case the parser doesn't change much: +1. Read the size of the leaf information from the trailer +2. Set the end pointer for the parser to the start of the leaf + information. (The previous bounds checking set the end pointer to the + start of the trailer, so this is actually a small improvement.) +3. Set the entries variable to the expected number of directory entries. + +For the multiple extent case: +1. Set the end pointer to the end of the block. +2. Do not set up the entries variable. Figuring out how many entries are + in each individual block is complex and does not seem worth it when + it appears to be safe to just iterate over the entire block. + +The bounds check itself was also dependent upon the faulty XFS parser +because it accidentally used "filename + length - 1". Presumably this +was able to pass the fuzzer because in the old parser there was always +8 bytes of slack space between the tail pointer and the actual end of +the block. Since this is no longer the case the bounds check needs to be +updated to "filename + length + 1" in order to prevent a regression in +the handling of corrupt fliesystems. + +Notes: +* When there is only one extent there will only ever be one block. If + more than one block is required then XFS will always switch to holding + leaf information in a separate extent. +* B-tree based directories seems to be parsed properly by the same code + that handles multiple extents. This is unlikely to ever occur within + /boot though because its only used when there are an extremely large + number of directory entries. + +Fixes: ef7850c75 (fs/xfs: Fix issues found while fuzzing the XFS filesystem) +Fixes: b2499b29c (Adds support for the XFS filesystem.) +Fixes: https://savannah.gnu.org/bugs/?64376 + +Signed-off-by: Jon DeVree +Reviewed-by: Daniel Kiper +Tested-by: Sebastian Andrzej Siewior +Tested-by: Marta Lewandowska +--- + grub-core/fs/xfs.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 38 insertions(+), 14 deletions(-) + +diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c +index ebf962793fa7..18edfcff486c 100644 +--- a/grub-core/fs/xfs.c ++++ b/grub-core/fs/xfs.c +@@ -223,6 +223,12 @@ struct grub_xfs_inode + /* Size of struct grub_xfs_inode v2, up to unused4 member included. */ + #define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76) + ++struct grub_xfs_dir_leaf_entry ++{ ++ grub_uint32_t hashval; ++ grub_uint32_t address; ++} GRUB_PACKED; ++ + struct grub_xfs_dirblock_tail + { + grub_uint32_t leaf_count; +@@ -874,9 +880,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + { + struct grub_xfs_dir2_entry *direntry = + grub_xfs_first_de(dir->data, dirblock); +- int entries; +- struct grub_xfs_dirblock_tail *tail = +- grub_xfs_dir_tail(dir->data, dirblock); ++ int entries = -1; ++ char *end = dirblock + dirblk_size; + + numread = grub_xfs_read_file (dir, 0, 0, + blk << dirblk_log2, +@@ -887,14 +892,27 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 0; + } + +- entries = (grub_be_to_cpu32 (tail->leaf_count) +- - grub_be_to_cpu32 (tail->leaf_stale)); ++ /* ++ * Leaf and tail information are only in the data block if the number ++ * of extents is 1. ++ */ ++ if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ { ++ struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); + +- if (!entries) +- continue; ++ end = (char *) tail; ++ ++ /* Subtract the space used by leaf nodes. */ ++ end -= grub_be_to_cpu32 (tail->leaf_count) * sizeof (struct grub_xfs_dir_leaf_entry); ++ ++ entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale); ++ ++ if (!entries) ++ continue; ++ } + + /* Iterate over all entries within this block. */ +- while ((char *)direntry < (char *)tail) ++ while ((char *) direntry < (char *) end) + { + grub_uint8_t *freetag; + char *filename; +@@ -914,7 +932,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + } + + filename = (char *)(direntry + 1); +- if (filename + direntry->len - 1 > (char *) tail) ++ if (filename + direntry->len + 1 > (char *) end) + return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry"); + + /* The byte after the filename is for the filetype, padding, or +@@ -928,11 +946,17 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, + return 1; + } + +- /* Check if last direntry in this block is +- reached. */ +- entries--; +- if (!entries) +- break; ++ /* ++ * The expected number of directory entries is only tracked for the ++ * single extent case. ++ */ ++ if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1)) ++ { ++ /* Check if last direntry in this block is reached. */ ++ entries--; ++ if (!entries) ++ break; ++ } + + /* Select the next directory entry. */ + direntry = grub_xfs_next_de(dir->data, direntry); diff --git a/SOURCES/0351-grub2-mkconfig-Ensure-grub-cfg-stub-is-not-overwritt.patch b/SOURCES/0351-grub2-mkconfig-Ensure-grub-cfg-stub-is-not-overwritt.patch new file mode 100644 index 0000000..fc76a5e --- /dev/null +++ b/SOURCES/0351-grub2-mkconfig-Ensure-grub-cfg-stub-is-not-overwritt.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Tue, 16 Jul 2024 11:11:43 +0200 +Subject: [PATCH] grub2-mkconfig: Ensure grub cfg stub is not overwritten + +/boot/efi/EFI/$os_name/grub.cfg contains a grub cfg stub +that should not be overwritten by grub2-mkconfig. +Ensure that we prevent this from happening. + +Signed-off-by: Marta Lewandowska +Signed-off-by: Nicolas Frayer +--- + util/grub-mkconfig.in | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 34f7c13fc521..34d0120d0ba2 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -114,6 +114,20 @@ do + esac + done + ++os_name=$(grep '^ID=' /etc/os-release | sed 's/ID=//') ++if test "$os_name" = '"rhel"'; then ++ os_name=redhat ++elif test "$os_name" = '"centos"'; then ++ os_name=centos ++fi ++if test "x${grub_cfg}" = "x/boot/efi/EFI/$os_name/grub.cfg" &&\ ++ mountpoint -q /boot/efi; then ++ gettext_printf "Running \`grub2-mkconfig -o %s' will overwrite the GRUB wrapper.\n" "$grub_cfg" 1>&2 ++ gettext_printf "Please run \`grub2-mkconfig -o /boot/grub2/grub.cfg' instead to update grub.cfg.\n" 1>&2 ++ gettext_printf "GRUB configuration file was not updated.\n" 1>&2 ++ exit 1 ++fi ++ + if [ "x$EUID" = "x" ] ; then + EUID=`id -u` + fi diff --git a/SOURCES/0352-grub2-mkconfig-Simplify-os_name-detection.patch b/SOURCES/0352-grub2-mkconfig-Simplify-os_name-detection.patch new file mode 100644 index 0000000..3d2f9a6 --- /dev/null +++ b/SOURCES/0352-grub2-mkconfig-Simplify-os_name-detection.patch @@ -0,0 +1,30 @@ +From ac5b2bc87a6c361fd504898a368f0867ef3e2679 Mon Sep 17 00:00:00 2001 +From: Andrew Lukoshko +Date: Wed, 31 Jul 2024 16:06:10 +0000 +Subject: [PATCH] grub2-mkconfig: Simplify os_name detection + +--- + util/grub-mkconfig.in | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 7a0738b..ebf5150 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -114,12 +114,7 @@ do + esac + done + +-os_name=$(grep '^ID=' /etc/os-release | sed 's/ID=//') +-if test "$os_name" = '"rhel"'; then +- os_name=redhat +-elif test "$os_name" = '"centos"'; then +- os_name=centos +-fi ++os_name=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') + if test "x${grub_cfg}" = "x/boot/efi/EFI/$os_name/grub.cfg" &&\ + mountpoint -q /boot/efi; then + gettext_printf "Running \`grub2-mkconfig -o %s' will overwrite the GRUB wrapper.\n" "$grub_cfg" 1>&2 +-- +2.43.5 + diff --git a/SOURCES/0353-grub-mkconfig-Remove-check-for-mount-point-for-grub-.patch b/SOURCES/0353-grub-mkconfig-Remove-check-for-mount-point-for-grub-.patch new file mode 100644 index 0000000..e503cef --- /dev/null +++ b/SOURCES/0353-grub-mkconfig-Remove-check-for-mount-point-for-grub-.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Thu, 1 Aug 2024 11:13:20 +0200 +Subject: [PATCH] grub/mkconfig: Remove check for mount point for grub cfg stub + +Remove mountpoint when checking whether or not the grub cfg stub +exists and add -s to the test. This should cover scenarios where +the ESP doesn't have a seperate partition but still uses a grub +cfg stub + +Signed-off-by: Nicolas Frayer +--- + util/grub-mkconfig.in | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index a4972039b751..3f131eea2b12 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -115,8 +115,7 @@ do + done + + os_name=$(grep ^ID= /etc/os-release | sed -e 's/^ID=//' -e 's/rhel/redhat/' -e 's/\"//g') +-if test "x${grub_cfg}" = "x/boot/efi/EFI/$os_name/grub.cfg" &&\ +- mountpoint -q /boot/efi; then ++if test -s "${grub_cfg}" && test "x${grub_cfg}" = "x/boot/efi/EFI/$os_name/grub.cfg"; then + gettext_printf "Running \`grub2-mkconfig -o %s' will overwrite the GRUB wrapper.\n" "$grub_cfg" 1>&2 + gettext_printf "Please run \`grub2-mkconfig -o /boot/grub2/grub.cfg' instead to update grub.cfg.\n" 1>&2 + gettext_printf "GRUB configuration file was not updated.\n" 1>&2 diff --git a/SOURCES/0354-grub-mkconfig-dont-overwrite-BLS-cmdline-if-BLSCFG.patch b/SOURCES/0354-grub-mkconfig-dont-overwrite-BLS-cmdline-if-BLSCFG.patch new file mode 100644 index 0000000..080374f --- /dev/null +++ b/SOURCES/0354-grub-mkconfig-dont-overwrite-BLS-cmdline-if-BLSCFG.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marta Lewandowska +Date: Mon, 17 Jul 2023 16:03:39 -0400 +Subject: [PATCH] grub-mkconfig dont overwrite BLS cmdline if BLSCFG + +If GRUB_ENABLE_BLSCFG is true, running grub2-mkconfig will not +overwrite kernel cmdline in BLS snippets with what is in +GRUB_CMDLINE_LINUX in /etc/default/grub. Update can be forced by +sending new arg --update-bls-cmdline, thus decoupling cmdline +updates from updates of other parameters. GRUB_GRUBENV_UPDATE +remains 'yes' by default. + +Signed-off-by: mkl +--- + util/grub-mkconfig.in | 9 +++++++++ + util/grub.d/10_linux.in | 2 +- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 520a672cd2c8..34f7c13fc521 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -51,6 +51,7 @@ export TEXTDOMAIN=@PACKAGE@ + export TEXTDOMAINDIR="@localedir@" + + export GRUB_GRUBENV_UPDATE="yes" ++export GRUB_UPDATE_BLS_CMDLINE="yes" + + . "${pkgdatadir}/grub-mkconfig_lib" + +@@ -62,6 +63,7 @@ usage () { + echo + print_option_help "-o, --output=$(gettext FILE)" "$(gettext "output generated config to FILE [default=stdout]")" + print_option_help "--no-grubenv-update" "$(gettext "do not update variables in the grubenv file")" ++ print_option_help "--update-bls-cmdline" "$(gettext "overwrite BLS cmdline args with default args")" + print_option_help "-h, --help" "$(gettext "print this message and exit")" + print_option_help "-V, --version" "$(gettext "print the version information and exit")" + echo +@@ -100,6 +102,9 @@ do + --no-grubenv-update) + GRUB_GRUBENV_UPDATE="no" + ;; ++ --update-bls-cmdline) ++ bls_cmdline_update=true ++ ;; + -*) + gettext_printf "Unrecognized option \`%s'\n" "$option" 1>&2 + usage +@@ -167,6 +172,10 @@ fi + + eval "$("${grub_get_kernel_settings}")" || true + ++if [ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ] && [ "x${bls_cmdline_update}" != "xtrue" ]; then ++ GRUB_UPDATE_BLS_CMDLINE="no" ++fi ++ + if [ "x${GRUB_DISABLE_UUID}" = "xtrue" ]; then + if [ -z "${GRUB_DISABLE_LINUX_UUID}" ]; then + GRUB_DISABLE_LINUX_UUID="true" +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 4795a63b4ce6..72b75effe448 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -265,7 +265,7 @@ if [ -z "\${kernelopts}" ]; then + fi + EOF + +- if [ "x${GRUB_GRUBENV_UPDATE}" = "xyes" ]; then ++ if [ "x${GRUB_UPDATE_BLS_CMDLINE}" = "xyes" ]; then + update_bls_cmdline + fi + diff --git a/SOURCES/0355-grub2-mkconfig-Pass-all-boot-params-when-used-by-ana.patch b/SOURCES/0355-grub2-mkconfig-Pass-all-boot-params-when-used-by-ana.patch new file mode 100644 index 0000000..916affd --- /dev/null +++ b/SOURCES/0355-grub2-mkconfig-Pass-all-boot-params-when-used-by-ana.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marta Lewandowska +Date: Mon, 27 May 2024 13:03:32 -0600 +Subject: [PATCH] grub2-mkconfig: Pass all boot params when used by anaconda + +Previous patch makes it so that the machine can boot, but not all +boot params are passed from /etc/default/grub to BLS snippets +because /etc/default/grub gets written by anaconda during boot +loader installation, long after grub rpms first got installed. + +Signed-off-by: Marta Lewandowska +--- + util/grub.d/10_linux.in | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in +index 72b75effe448..041a11529588 100644 +--- a/util/grub.d/10_linux.in ++++ b/util/grub.d/10_linux.in +@@ -265,7 +265,11 @@ if [ -z "\${kernelopts}" ]; then + fi + EOF + +- if [ "x${GRUB_UPDATE_BLS_CMDLINE}" = "xyes" ]; then ++ if [ "x${GRUB_UPDATE_BLS_CMDLINE}" = "xyes" ] || [[ -d /run/install ]]; then ++ # only update the bls cmdline if the user specifically requests it or _anytime_ ++ # in the installer environment: /run/install directory only exists during the ++ # installation and not in cloud images, so this should get all the boot params ++ # from /etc/default/grub into BLS snippets + update_bls_cmdline + fi + diff --git a/SOURCES/0356-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch b/SOURCES/0356-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch new file mode 100644 index 0000000..d20f909 --- /dev/null +++ b/SOURCES/0356-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch @@ -0,0 +1,146 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Solar Designer +Date: Tue, 6 Feb 2024 21:39:41 +0100 +Subject: [PATCH] grub-set-bootflag: Conservative partial fix for CVE-2024-1048 + +Following up on CVE-2019-14865 and taking a fresh look at +grub2-set-bootflag now (through my work at CIQ on Rocky Linux), I saw some +other ways in which users could still abuse this little program: + +1. After CVE-2019-14865 fix, grub2-set-bootflag no longer rewrites the +grubenv file in-place, but writes into a temporary file and renames it +over the original, checking for error returns from each call first. +This prevents the original file truncation vulnerability, but it can +leave the temporary file around if the program is killed before it can +rename or remove the file. There are still many ways to get the program +killed, such as through RLIMIT_FSIZE triggering SIGXFSZ (tested, +reliable) or by careful timing (tricky) of signals sent by process group +leader, pty, pre-scheduled timers, SIGXCPU (probably not an exhaustive +list). Invoking the program multiple times fills up /boot (or if /boot +is not separate, then it can fill up the root filesystem). Since the +files are tiny, the filesystem is likely to run out of free inodes +before it'd run out of blocks, but the effect is similar - can't create +new files after this point (but still can add data to existing files, +such as logs). + +2. After CVE-2019-14865 fix, grub2-set-bootflag naively tries to protect +itself from signals by becoming full root. (This does protect it from +signals sent by the user directly to the PID, but e.g. "kill -9 -1" by +the user still works.) A side effect of such "protection" is that it's +possible to invoke more concurrent instances of grub2-set-bootflag than +the user's RLIMIT_NPROC would normally permit (as specified e.g. in +/etc/security/limits.conf, or say in Apache httpd's RLimitNPROC if +grub2-set-bootflag would be abused by a website script), thereby +exhausting system resources (e.g., bypassing RAM usage limit if +RLIMIT_AS was also set). + +3. umask is inherited. Again, due to how the CVE-2019-14865 fix creates +a new file, and due to how mkstemp() works, this affects grubenv's new +file permissions. Luckily, mkstemp() forces them to be no more relaxed +than 0600, but the user ends up being able to set them e.g. to 0. +Luckily, at least in my testing GRUB still works fine even when the file +has such (lack of) permissions. + +This commit deals with the abuses above as follows: + +1. RLIMIT_FSIZE is pre-checked, so this specific way to get the process +killed should no longer work. However, this isn't a complete fix +because there are other ways to get the process killed after it has +created the temporary file. + +The commit also fixes bug 1975892 ("RFE: grub2-set-bootflag should not +write the grubenv when the flag being written is already set") and +similar for "menu_show_once", which further reduces the abuse potential. + +2. RLIMIT_NPROC bypass should be avoided by not becoming full root (aka +dropping the partial "kill protection"). + +3. A safe umask is set. + +This is a partial fix (temporary files can still accumulate, but this is +harder to trigger). + +While at it, this commit also fixes potential 1- or 2-byte over-read of +env[] if its content is malformed - this was not a security issue since the +grubenv file is trusted input, and the fix is just for robustness. + +Signed-off-by: Solar Designer +--- + util/grub-set-bootflag.c | 29 ++++++++++++++++------------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 3b4c25ca2ac6..5bbbef804391 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -33,6 +33,8 @@ + #include + #include + #include ++#include ++#include + + #include "progname.h" + +@@ -57,12 +59,17 @@ static void usage(FILE *out) + int main(int argc, char *argv[]) + { + /* NOTE buf must be at least the longest bootflag length + 4 bytes */ +- char env[GRUBENV_SIZE + 1], buf[64], *s; ++ char env[GRUBENV_SIZE + 1 + 2], buf[64], *s; + /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ + char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; + const char *bootflag; + int i, fd, len, ret; + FILE *f; ++ struct rlimit rlim; ++ ++ if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) ++ return 1; ++ umask(077); + + if (argc != 2) + { +@@ -94,20 +101,11 @@ int main(int argc, char *argv[]) + len = strlen (bootflag); + + /* +- * Really become root. setuid avoids an user killing us, possibly leaking +- * the tmpfile. setgid avoids the new grubenv's gid being that of the user. ++ * setegid avoids the new grubenv's gid being that of the user. + */ +- ret = setuid(0); +- if (ret) ++ if (setegid(0)) + { +- perror ("Error setuid(0) failed"); +- return 1; +- } +- +- ret = setgid(0); +- if (ret) +- { +- perror ("Error setgid(0) failed"); ++ perror ("Error setegid(0) failed"); + return 1; + } + +@@ -136,6 +134,9 @@ int main(int argc, char *argv[]) + + /* 0 terminate env */ + env[GRUBENV_SIZE] = 0; ++ /* not a valid flag value */ ++ env[GRUBENV_SIZE + 1] = 0; ++ env[GRUBENV_SIZE + 2] = 0; + + if (strncmp (env, GRUB_ENVBLK_SIGNATURE, strlen (GRUB_ENVBLK_SIGNATURE))) + { +@@ -171,6 +172,8 @@ int main(int argc, char *argv[]) + + /* The grubenv is not 0 terminated, so memcpy the name + '=' , '1', '\n' */ + snprintf(buf, sizeof(buf), "%s=1\n", bootflag); ++ if (!memcmp(s, buf, len + 3)) ++ return 0; /* nothing to do */ + memcpy(s, buf, len + 3); + + diff --git a/SOURCES/0357-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch b/SOURCES/0357-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch new file mode 100644 index 0000000..b47b311 --- /dev/null +++ b/SOURCES/0357-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch @@ -0,0 +1,187 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Solar Designer +Date: Tue, 6 Feb 2024 21:56:21 +0100 +Subject: [PATCH] grub-set-bootflag: More complete fix for CVE-2024-1048 + +Switch to per-user fixed temporary filenames along with a weird locking +mechanism, which is explained in source code comments. This is a more +complete fix than the previous commit (temporary files can't accumulate). +Unfortunately, it introduces new risks (by working on a temporary file +shared between the user's invocations), which are _hopefully_ avoided by +the patch's elaborate logic. I actually got it wrong at first, which +suggests that this logic is hard to reason about, and more errors or +omissions are possible. It also relies on the kernel's primitives' exact +semantics to a greater extent (nothing out of the ordinary, though). + +Remaining issues that I think cannot reasonably be fixed without a +redesign (e.g., having per-flag files with nothing else in them) and +without introducing new issues: + +A. A user can still revert a concurrent user's attempt of setting the +other flag - or of making other changes to grubenv by means other than +this program. + +B. One leftover temporary file per user is still possible. + +Signed-off-by: Solar Designer +--- + util/grub-set-bootflag.c | 95 ++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 79 insertions(+), 16 deletions(-) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 5bbbef804391..514c4f9091ac 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -60,15 +61,12 @@ int main(int argc, char *argv[]) + { + /* NOTE buf must be at least the longest bootflag length + 4 bytes */ + char env[GRUBENV_SIZE + 1 + 2], buf[64], *s; +- /* +1 for 0 termination, +6 for "XXXXXX" in tmp filename */ +- char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 6 + 1]; ++ /* +1 for 0 termination, +11 for ".%u" in tmp filename */ ++ char env_filename[PATH_MAX + 1], tmp_filename[PATH_MAX + 11 + 1]; + const char *bootflag; + int i, fd, len, ret; + FILE *f; +- struct rlimit rlim; + +- if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) +- return 1; + umask(077); + + if (argc != 2) +@@ -105,7 +103,7 @@ int main(int argc, char *argv[]) + */ + if (setegid(0)) + { +- perror ("Error setegid(0) failed"); ++ perror ("setegid(0) failed"); + return 1; + } + +@@ -176,19 +174,82 @@ int main(int argc, char *argv[]) + return 0; /* nothing to do */ + memcpy(s, buf, len + 3); + ++ struct rlimit rlim; ++ if (getrlimit(RLIMIT_FSIZE, &rlim) || rlim.rlim_cur < GRUBENV_SIZE || rlim.rlim_max < GRUBENV_SIZE) ++ { ++ fprintf (stderr, "Resource limits undetermined or too low\n"); ++ return 1; ++ } ++ ++ /* ++ * Here we work under the premise that we shouldn't write into the target ++ * file directly because we might not be able to have all of our changes ++ * written completely and atomically. That was CVE-2019-14865, known to ++ * have been triggerable via RLIMIT_FSIZE. While we've dealt with that ++ * specific attack via the check above, there may be other possibilities. ++ */ + + /* + * Create a tempfile for writing the new env. Use the canonicalized filename + * for the template so that the tmpfile is in the same dir / on same fs. ++ * ++ * We now use per-user fixed temporary filenames, so that a user cannot cause ++ * multiple files to accumulate. ++ * ++ * We don't use O_EXCL so that a stale temporary file doesn't prevent further ++ * usage of the program by the user. + */ +- snprintf(tmp_filename, sizeof(tmp_filename), "%sXXXXXX", env_filename); +- fd = mkstemp(tmp_filename); ++ snprintf(tmp_filename, sizeof(tmp_filename), "%s.%u", env_filename, getuid()); ++ fd = open(tmp_filename, O_CREAT | O_WRONLY, 0600); + if (fd == -1) + { + perror ("Creating tmpfile failed"); + return 1; + } + ++ /* ++ * The lock prevents the same user from reaching further steps ending in ++ * rename() concurrently, in which case the temporary file only partially ++ * written by one invocation could be renamed to the target file by another. ++ * ++ * The lock also guards the slow fsync() from concurrent calls. After the ++ * first time that and the rename() complete, further invocations for the ++ * same flag become no-ops. ++ * ++ * We lock the temporary file rather than the target file because locking the ++ * latter would allow any user having SIGSTOP'ed their process to make all ++ * other users' invocations fail (or lock up if we'd use blocking mode). ++ * ++ * We use non-blocking mode (LOCK_NB) because the lock having been taken by ++ * another process implies that the other process would normally have already ++ * renamed the file to target by the time it releases the lock (and we could ++ * acquire it), so we'd be working directly on the target if we proceeded, ++ * which is undesirable, and we'd kind of fail on the already-done rename. ++ */ ++ if (flock(fd, LOCK_EX | LOCK_NB)) ++ { ++ perror ("Locking tmpfile failed"); ++ return 1; ++ } ++ ++ /* ++ * Deal with the potential that another invocation proceeded all the way to ++ * rename() and process exit while we were between open() and flock(). ++ */ ++ { ++ struct stat st1, st2; ++ if (fstat(fd, &st1) || stat(tmp_filename, &st2)) ++ { ++ perror ("stat of tmpfile failed"); ++ return 1; ++ } ++ if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) ++ { ++ fprintf (stderr, "Another invocation won race\n"); ++ return 1; ++ } ++ } ++ + f = fdopen (fd, "w"); + if (!f) + { +@@ -213,6 +274,14 @@ int main(int argc, char *argv[]) + return 1; + } + ++ ret = ftruncate (fileno (f), GRUBENV_SIZE); ++ if (ret) ++ { ++ perror ("Error truncating tmpfile"); ++ unlink(tmp_filename); ++ return 1; ++ } ++ + ret = fsync (fileno (f)); + if (ret) + { +@@ -221,15 +290,9 @@ int main(int argc, char *argv[]) + return 1; + } + +- ret = fclose (f); +- if (ret) +- { +- perror ("Error closing tmpfile"); +- unlink(tmp_filename); +- return 1; +- } +- + /* ++ * We must not close the file before rename() as that would remove the lock. ++ * + * And finally rename the tmpfile with the new env over the old env, the + * linux kernel guarantees that this is atomic (from a syscall pov). + */ diff --git a/SOURCES/0358-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch b/SOURCES/0358-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch new file mode 100644 index 0000000..dba46d4 --- /dev/null +++ b/SOURCES/0358-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Solar Designer +Date: Tue, 6 Feb 2024 22:05:45 +0100 +Subject: [PATCH] grub-set-bootflag: Exit calmly when not running as root + +Exit calmly when not installed SUID root and invoked by non-root. This +allows installing user/grub-boot-success.service unconditionally while +supporting non-SUID installation of the program for some limited usage. + +Signed-off-by: Solar Designer +--- + util/grub-set-bootflag.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/util/grub-set-bootflag.c b/util/grub-set-bootflag.c +index 514c4f9091ac..31a868aeca8a 100644 +--- a/util/grub-set-bootflag.c ++++ b/util/grub-set-bootflag.c +@@ -98,6 +98,17 @@ int main(int argc, char *argv[]) + bootflag = bootflags[i]; + len = strlen (bootflag); + ++ /* ++ * Exit calmly when not installed SUID root and invoked by non-root. This ++ * allows installing user/grub-boot-success.service unconditionally while ++ * supporting non-SUID installation of the program for some limited usage. ++ */ ++ if (geteuid()) ++ { ++ printf ("grub-set-bootflag not running as root, no action taken\n"); ++ return 0; ++ } ++ + /* + * setegid avoids the new grubenv's gid being that of the user. + */ diff --git a/SOURCES/0359-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch b/SOURCES/0359-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch new file mode 100644 index 0000000..ea38989 --- /dev/null +++ b/SOURCES/0359-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:31:57 +0300 +Subject: [PATCH] fs/ntfs: Fix an OOB write when parsing the $ATTRIBUTE_LIST + attribute for the $MFT file + +When parsing an extremely fragmented $MFT file, i.e., the file described +using the $ATTRIBUTE_LIST attribute, current NTFS code will reuse a buffer +containing bytes read from the underlying drive to store sector numbers, +which are consumed later to read data from these sectors into another buffer. + +These sectors numbers, two 32-bit integers, are always stored at predefined +offsets, 0x10 and 0x14, relative to first byte of the selected entry within +the $ATTRIBUTE_LIST attribute. Usually, this won't cause any problem. + +However, when parsing a specially-crafted file system image, this may cause +the NTFS code to write these integers beyond the buffer boundary, likely +causing the GRUB memory allocator to misbehave or fail. These integers contain +values which are controlled by on-disk structures of the NTFS file system. + +Such modification and resulting misbehavior may touch a memory range not +assigned to the GRUB and owned by firmware or another EFI application/driver. + +This fix introduces checks to ensure that these sector numbers are never +written beyond the boundary. + +Fixes: CVE-2023-4692 + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 3511e4e2cb6f..4681c7ac32a8 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -184,7 +184,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + if (at->attr_end) + { +- grub_uint8_t *pa; ++ grub_uint8_t *pa, *pa_end; + + at->emft_buf = grub_malloc (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + if (at->emft_buf == NULL) +@@ -209,11 +209,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + at->attr_nxt = at->edat_buf; + at->attr_end = at->edat_buf + u32at (pa, 0x30); ++ pa_end = at->edat_buf + n; + } + else + { + at->attr_nxt = at->attr_end + u16at (pa, 0x14); + at->attr_end = at->attr_end + u32at (pa, 4); ++ pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } + at->flags |= GRUB_NTFS_AF_ALST; + while (at->attr_nxt < at->attr_end) +@@ -230,6 +232,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + at->flags |= GRUB_NTFS_AF_GPOS; + at->attr_cur = at->attr_nxt; + pa = at->attr_cur; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + grub_set_unaligned32 ((char *) pa + 0x10, + grub_cpu_to_le32 (at->mft->data->mft_start)); + grub_set_unaligned32 ((char *) pa + 0x14, +@@ -240,6 +249,13 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + { + if (*pa != attr) + break; ++ ++ if ((pa >= pa_end) || (pa_end - pa < 0x18)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse attribute list"); ++ return NULL; ++ } ++ + if (read_attr + (at, pa + 0x10, + u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), diff --git a/SOURCES/0360-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch b/SOURCES/0360-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch new file mode 100644 index 0000000..a7da68c --- /dev/null +++ b/SOURCES/0360-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:32:33 +0300 +Subject: [PATCH] fs/ntfs: Fix an OOB read when reading data from the resident + $DATA attribute + +When reading a file containing resident data, i.e., the file data is stored in +the $DATA attribute within the NTFS file record, not in external clusters, +there are no checks that this resident data actually fits the corresponding +file record segment. + +When parsing a specially-crafted file system image, the current NTFS code will +read the file data from an arbitrary, attacker-chosen memory offset and of +arbitrary, attacker-chosen length. + +This allows an attacker to display arbitrary chunks of memory, which could +contain sensitive information like password hashes or even plain-text, +obfuscated passwords from BS EFI variables. + +This fix implements a check to ensure that resident data is read from the +corresponding file record segment only. + +Fixes: CVE-2023-4693 + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 4681c7ac32a8..1949d48a494f 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -401,7 +401,18 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + { + if (ofs + len > u32at (pa, 0x10)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); +- grub_memcpy (dest, pa + u32at (pa, 0x14) + ofs, len); ++ ++ if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); ++ ++ if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) ++ return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); ++ ++ grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); + return 0; + } + diff --git a/SOURCES/0361-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch b/SOURCES/0361-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch new file mode 100644 index 0000000..8f478f7 --- /dev/null +++ b/SOURCES/0361-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:33:17 +0300 +Subject: [PATCH] fs/ntfs: Fix an OOB read when parsing directory entries from + resident and non-resident index attributes + +This fix introduces checks to ensure that index entries are never read +beyond the corresponding directory index. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 1949d48a494f..72302033281a 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -599,7 +599,7 @@ get_utf8 (grub_uint8_t *in, grub_size_t len) + } + + static int +-list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, ++list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, grub_uint8_t *end_pos, + grub_fshelp_iterate_dir_hook_t hook, void *hook_data) + { + grub_uint8_t *np; +@@ -610,6 +610,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + grub_uint8_t namespace; + char *ustr; + ++ if ((pos >= end_pos) || (end_pos - pos < 0x52)) ++ break; ++ + if (pos[0xC] & 2) /* end signature */ + break; + +@@ -617,6 +620,9 @@ list_file (struct grub_ntfs_file *diro, grub_uint8_t *pos, + ns = *(np++); + namespace = *(np++); + ++ if (2 * ns > end_pos - pos - 0x52) ++ break; ++ + /* + * Ignore files in DOS namespace, as they will reappear as Win32 + * names. +@@ -802,7 +808,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + } + + cur_pos += 0x10; /* Skip index root */ +- ret = list_file (mft, cur_pos + u16at (cur_pos, 0), hook, hook_data); ++ ret = list_file (mft, cur_pos + u16at (cur_pos, 0), ++ at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), ++ hook, hook_data); + if (ret) + goto done; + +@@ -889,6 +897,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (const grub_uint8_t *) "INDX"))) + goto done; + ret = list_file (mft, &indx[0x18 + u16at (indx, 0x18)], ++ indx + (mft->data->idx_size << GRUB_NTFS_BLK_SHR), + hook, hook_data); + if (ret) + goto done; diff --git a/SOURCES/0362-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch b/SOURCES/0362-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch new file mode 100644 index 0000000..9d636c6 --- /dev/null +++ b/SOURCES/0362-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:33:44 +0300 +Subject: [PATCH] fs/ntfs: Fix an OOB read when parsing bitmaps for index + attributes + +This fix introduces checks to ensure that bitmaps for directory indices +are never read beyond their actual sizes. + +The lack of this check is a minor issue, likely not exploitable in any way. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 72302033281a..74515114287f 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -839,6 +839,25 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + + if (is_resident) + { ++ if (bitmap_len > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap too large"); ++ goto done; ++ } ++ ++ if (cur_pos >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ ++ if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); ++ goto done; ++ } ++ + grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), + bitmap_len); + } diff --git a/SOURCES/0363-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch b/SOURCES/0363-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch new file mode 100644 index 0000000..60b36f5 --- /dev/null +++ b/SOURCES/0363-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:38:19 +0300 +Subject: [PATCH] fs/ntfs: Fix an OOB read when parsing a volume label + +This fix introduces checks to ensure that an NTFS volume label is always +read from the corresponding file record segment. + +The current NTFS code allows the volume label string to be read from an +arbitrary, attacker-chosen memory location. However, the bytes read are +always treated as UTF-16LE. So, the final string displayed is mostly +unreadable and it can't be easily converted back to raw bytes. + +The lack of this check is a minor issue, likely not causing a significant +data leak. + +Reported-by: Maxim Suhanov +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 74515114287f..32ba8276dd8d 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -1209,13 +1209,29 @@ grub_ntfs_label (grub_device_t device, char **label) + + init_attr (&mft->attr, mft); + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); ++ ++ if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa < 0x16) ++ { ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); ++ goto fail; ++ } ++ + if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) + { + int len; + + len = u32at (pa, 0x10) / 2; + pa += u16at (pa, 0x14); +- *label = get_utf8 (pa, len); ++ if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) ++ *label = get_utf8 (pa, len); ++ else ++ grub_error (GRUB_ERR_BAD_FS, "can\'t parse volume label"); + } + + fail: diff --git a/SOURCES/0364-fs-ntfs-Make-code-more-readable.patch b/SOURCES/0364-fs-ntfs-Make-code-more-readable.patch new file mode 100644 index 0000000..81dc8ef --- /dev/null +++ b/SOURCES/0364-fs-ntfs-Make-code-more-readable.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maxim Suhanov +Date: Mon, 28 Aug 2023 16:40:07 +0300 +Subject: [PATCH] fs/ntfs: Make code more readable + +Move some calls used to access NTFS attribute header fields into +functions with human-readable names. + +Suggested-by: Daniel Kiper +Signed-off-by: Maxim Suhanov +Reviewed-by: Daniel Kiper +--- + grub-core/fs/ntfs.c | 48 +++++++++++++++++++++++++++++++++--------------- + 1 file changed, 33 insertions(+), 15 deletions(-) + +diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c +index 32ba8276dd8d..991b1c2094f5 100644 +--- a/grub-core/fs/ntfs.c ++++ b/grub-core/fs/ntfs.c +@@ -52,6 +52,24 @@ u64at (void *ptr, grub_size_t ofs) + return grub_le_to_cpu64 (grub_get_unaligned64 ((char *) ptr + ofs)); + } + ++static grub_uint16_t ++first_attr_off (void *mft_buf_ptr) ++{ ++ return u16at (mft_buf_ptr, 0x14); ++} ++ ++static grub_uint16_t ++res_attr_data_off (void *res_attr_ptr) ++{ ++ return u16at (res_attr_ptr, 0x14); ++} ++ ++static grub_uint32_t ++res_attr_data_len (void *res_attr_ptr) ++{ ++ return u32at (res_attr_ptr, 0x10); ++} ++ + grub_ntfscomp_func_t grub_ntfscomp_func; + + static grub_err_t +@@ -106,7 +124,7 @@ init_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft) + { + at->mft = mft; + at->flags = (mft == &mft->data->mmft) ? GRUB_NTFS_AF_MMFT : 0; +- at->attr_nxt = mft->buf + u16at (mft->buf, 0x14); ++ at->attr_nxt = mft->buf + first_attr_off (mft->buf); + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; + } + +@@ -154,7 +172,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + return NULL; + } + +- new_pos = &at->emft_buf[u16at (at->emft_buf, 0x14)]; ++ new_pos = &at->emft_buf[first_attr_off (at->emft_buf)]; + while (*new_pos != 0xFF) + { + if ((*new_pos == *at->attr_cur) +@@ -213,7 +231,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) + } + else + { +- at->attr_nxt = at->attr_end + u16at (pa, 0x14); ++ at->attr_nxt = at->attr_end + res_attr_data_off (pa); + at->attr_end = at->attr_end + u32at (pa, 4); + pa_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + } +@@ -399,20 +417,20 @@ read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_uint8_t *dest, + + if (pa[8] == 0) + { +- if (ofs + len > u32at (pa, 0x10)) ++ if (ofs + len > res_attr_data_len (pa)) + return grub_error (GRUB_ERR_BAD_FS, "read out of range"); + +- if (u32at (pa, 0x10) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) ++ if (res_attr_data_len (pa) > (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute too large"); + + if (pa >= at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR)) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- if (u16at (pa, 0x14) + u32at (pa, 0x10) > ++ if (res_attr_data_off (pa) + res_attr_data_len (pa) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) pa) + return grub_error (GRUB_ERR_BAD_FS, "resident attribute out of range"); + +- grub_memcpy (dest, pa + u16at (pa, 0x14) + ofs, len); ++ grub_memcpy (dest, pa + res_attr_data_off (pa) + ofs, len); + return 0; + } + +@@ -556,7 +574,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) + (unsigned long long) mftno); + + if (!pa[8]) +- mft->size = u32at (pa, 0x10); ++ mft->size = res_attr_data_len (pa); + else + mft->size = u64at (pa, 0x30); + +@@ -801,7 +819,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + (u32at (cur_pos, 0x18) != 0x490024) || + (u32at (cur_pos, 0x1C) != 0x300033)) + continue; +- cur_pos += u16at (cur_pos, 0x14); ++ cur_pos += res_attr_data_off (cur_pos); + if (*cur_pos != 0x30) /* Not filename index */ + continue; + break; +@@ -830,7 +848,7 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + { + int is_resident = (cur_pos[8] == 0); + +- bitmap_len = ((is_resident) ? u32at (cur_pos, 0x10) : ++ bitmap_len = ((is_resident) ? res_attr_data_len (cur_pos) : + u32at (cur_pos, 0x28)); + + bmp = grub_malloc (bitmap_len); +@@ -851,14 +869,14 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, + goto done; + } + +- if (u16at (cur_pos, 0x14) + u32at (cur_pos, 0x10) > ++ if (res_attr_data_off (cur_pos) + res_attr_data_len (cur_pos) > + (grub_addr_t) at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR) - (grub_addr_t) cur_pos) + { + grub_error (GRUB_ERR_BAD_FS, "resident bitmap out of range"); + goto done; + } + +- grub_memcpy (bmp, cur_pos + u16at (cur_pos, 0x14), ++ grub_memcpy (bmp, cur_pos + res_attr_data_off (cur_pos), + bitmap_len); + } + else +@@ -1222,12 +1240,12 @@ grub_ntfs_label (grub_device_t device, char **label) + goto fail; + } + +- if ((pa) && (pa[8] == 0) && (u32at (pa, 0x10))) ++ if ((pa) && (pa[8] == 0) && (res_attr_data_len (pa))) + { + int len; + +- len = u32at (pa, 0x10) / 2; +- pa += u16at (pa, 0x14); ++ len = res_attr_data_len (pa) / 2; ++ pa += res_attr_data_off (pa); + if (mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR) - pa >= 2 * len) + *label = get_utf8 (pa, len); + else diff --git a/SOURCES/0365-cmd-search-Rework-of-CVE-2023-4001-fix.patch b/SOURCES/0365-cmd-search-Rework-of-CVE-2023-4001-fix.patch new file mode 100644 index 0000000..5e794a9 --- /dev/null +++ b/SOURCES/0365-cmd-search-Rework-of-CVE-2023-4001-fix.patch @@ -0,0 +1,182 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Nicolas Frayer +Date: Thu, 16 May 2024 10:58:32 +0200 +Subject: [PATCH] cmd/search: Rework of CVE-2023-4001 fix + +The initial fix implemented a new flag that forces the grub cfg +stub to be located on the same disk as grub. This created several +issues such as RAID machines not being able to boot as their +partition names under grub were different from the partition where +grub is located. It also simply means that any machines with the +/boot partition located on a disk other than the one containing grub +won't boot. +This commit denies booting if the grub cfg stub is located on a USB +drive with a duplicated UUID (UUID being the same as the partition +containing the actual grub cfg stub) + +Signed-off-by: Nicolas Frayer +--- + grub-core/commands/search.c | 136 +++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 127 insertions(+), 9 deletions(-) + +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index 819231751c38..1e61a5cf940f 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -54,6 +56,100 @@ struct search_ctx + int is_cache; + }; + ++static int ++is_device_usb (const char *name) ++{ ++ int ret = 0; ++ ++ grub_device_t dev = grub_device_open(name); ++ ++ if (dev) ++ { ++ struct grub_efidisk_data ++ { ++ grub_efi_handle_t handle; ++ grub_efi_device_path_t *device_path; ++ grub_efi_device_path_t *last_device_path; ++ grub_efi_block_io_t *block_io; ++ struct grub_efidisk_data *next; ++ }; ++ ++ if (dev->disk && dev->disk->data) ++ { ++ struct grub_efidisk_data *dp = dev->disk->data; ++ ++ if ( GRUB_EFI_DEVICE_PATH_TYPE (dp->last_device_path) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && ++ GRUB_EFI_DEVICE_PATH_SUBTYPE (dp->last_device_path) == GRUB_EFI_USB_DEVICE_PATH_SUBTYPE) ++ { ++ ret = 1; ++ } ++ } ++ grub_device_close(dev); ++ } ++ ++ return ret; ++} ++ ++static int ++get_device_uuid(const char *name, char** quid) ++{ ++ int ret = 0; ++ ++ grub_device_t dev_part = grub_device_open(name); ++ ++ if (dev_part) ++ { ++ grub_fs_t fs; ++ ++ fs = grub_fs_probe (dev_part); ++ ++#ifdef DO_SEARCH_FS_UUID ++#define read_fn fs_uuid ++#else ++#define read_fn fs_label ++#endif ++ if (fs && fs->read_fn) ++ { ++ fs->read_fn (dev_part, quid); ++ ++ if (grub_errno == GRUB_ERR_NONE && *quid) ++ { ++ ret = 1; ++ } ++ ++ } ++ grub_device_close (dev_part); ++ } ++ ++ return ret; ++} ++struct uuid_context { ++ char* name; ++ char* uuid; ++}; ++ ++static int ++check_for_duplicate (const char *name, void *data) ++{ ++ int ret = 0; ++ struct uuid_context * uuid_ctx = (struct uuid_context *)data; ++ char *quid = 0; ++ ++ get_device_uuid(name, &quid); ++ ++ if (quid == NULL) ++ return 0; ++ ++ if (!grub_strcasecmp(quid, uuid_ctx->uuid) && grub_strcasecmp(name, uuid_ctx->name)) ++ { ++ ret = 1; ++ } ++ ++ grub_free(quid); ++ ++ return ret; ++} ++ + /* Helper for FUNC_NAME. */ + static int + iterate_device (const char *name, void *data) +@@ -104,15 +200,37 @@ iterate_device (const char *name, void *data) + grub_str_sep (root_dev, root_disk, ',', rem_1); + grub_str_sep (name, name_disk, ',', rem_2); + if (root_disk != NULL && *root_disk != '\0' && +- name_disk != NULL && *name_disk != '\0') +- if (grub_strcmp(root_disk, name_disk) != 0) +- { +- grub_free (root_disk); +- grub_free (name_disk); +- grub_free (rem_1); +- grub_free (rem_2); +- return 0; +- } ++ name_disk != NULL && *name_disk != '\0') ++ { ++ grub_device_t dev, dev_part; ++ ++ if (is_device_usb(name) && !is_device_usb(root_dev)) ++ { ++ char *quid_name = NULL; ++ int longlist = 0; ++ struct uuid_context uuid_ctx; ++ int ret = 0; ++ ++ get_device_uuid(name, &quid_name); ++ if (!grub_strcmp(quid_name, ctx->key)) ++ { ++ uuid_ctx.name = name; ++ uuid_ctx.uuid = quid_name; ++ ++ ret = grub_device_iterate (check_for_duplicate, &uuid_ctx); ++ ++ if (ret) ++ { ++ grub_printf("Duplicated media UUID found, rebooting ...\n"); ++ grub_sleep(10); ++ grub_reboot(); ++ } ++ } ++ ++ if (quid_name) grub_free (quid_name); ++ ++ } ++ } + } + grub_free (root_disk); + grub_free (name_disk); diff --git a/SOURCES/0366-grub-mkconfig.in-turn-off-executable-owner-bit.patch b/SOURCES/0366-grub-mkconfig.in-turn-off-executable-owner-bit.patch new file mode 100644 index 0000000..fc3c0f9 --- /dev/null +++ b/SOURCES/0366-grub-mkconfig.in-turn-off-executable-owner-bit.patch @@ -0,0 +1,29 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Leo Sandoval +Date: Mon, 1 Jul 2024 12:52:13 -0600 +Subject: [PATCH] grub-mkconfig.in: turn off executable owner bit + +Stricker permissions are required on the grub.cfg file, resulting in +at most 0600 owner's file permissions. This resolves conflicting +requirement permissions on grub2-pc package's grub2.cfg file. + +Resolves: RHEL-45870 + +Signed-off-by: Leo Sandoval +--- + util/grub-mkconfig.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in +index 3f131eea2b12..8c2bb8259de1 100644 +--- a/util/grub-mkconfig.in ++++ b/util/grub-mkconfig.in +@@ -328,7 +328,7 @@ and /etc/grub.d/* files or please file a bug report with + exit 1 + else + # none of the children aborted with error, install the new grub.cfg +- oldumask=$(umask); umask 077 ++ oldumask=$(umask); umask 177 + cat ${grub_cfg}.new > ${grub_cfg} + umask $oldumask + rm -f ${grub_cfg}.new diff --git a/SOURCES/20-grub.install b/SOURCES/20-grub.install new file mode 100755 index 0000000..afc706d --- /dev/null +++ b/SOURCES/20-grub.install @@ -0,0 +1,211 @@ +#!/bin/bash + +if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then + exit 0 +fi + +[[ -f /etc/default/grub ]] && . /etc/default/grub +[[ -f /etc/os-release ]] && . /etc/os-release + +COMMAND="$1" +KERNEL_VERSION="$2" +BOOT_DIR_ABS="$3" +KERNEL_IMAGE="$4" + +KERNEL_DIR="${KERNEL_IMAGE%/*}" + +MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID + +# If ${BOOT_DIR_ABS} exists, some other boot loader is active. +[[ -d "${BOOT_DIR_ABS}" ]] && exit 0 + +# UKIs are BLS type 2 entries, 90-uki-copy.install takes care of them +[ "x$KERNEL_INSTALL_LAYOUT" != "xuki" ] || exit 0 + +BLS_DIR="/boot/loader/entries" + +mkbls() { + local kernelver=$1 && shift + local datetime=$1 && shift + local kernelopts=$1 && shift + + local debugname="" + local debugid="" + local flavor="" + + if [[ "$kernelver" == *\+* ]] ; then + local flavor=-"${kernelver##*+}" + if [[ "${flavor}" == "-debug" ]]; then + local debugname=" with debugging" + local debugid="-debug" + fi + fi + + cat </dev/null && \ + restorecon -R "/boot/vmlinuz-${KERNEL_VERSION}" + + for i in \ + "$KERNEL_DIR"/System.map \ + "$KERNEL_DIR"/config \ + "$KERNEL_DIR"/zImage.stub \ + "$KERNEL_DIR"/dtb + do + [[ -e "$i" ]] || continue + cp --remove-destination --preserve=timestamps -rT "$i" "/boot/${i##*/}-${KERNEL_VERSION}" + command -v restorecon &>/dev/null && \ + restorecon -R "/boot/${i##*/}-${KERNEL_VERSION}" + done + # hmac is .vmlinuz-.hmac so needs a special treatment + i="$KERNEL_DIR/.${KERNEL_IMAGE##*/}.hmac" + if [[ -e "$i" ]]; then + cp --remove-destination --preserve=timestamps "$i" "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + command -v restorecon &>/dev/null && \ + restorecon "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + fi + # OLD method using gzip'd file (will be deprecated and removed in the future) + # symvers is symvers-.gz symlink, needs a special treatment + i="$KERNEL_DIR/symvers.gz" + if [[ -e "$i" ]]; then + ln -fs "$i" "/boot/symvers-${KERNEL_VERSION}.gz" + command -v restorecon &>/dev/null && \ + restorecon "/boot/symvers-${KERNEL_VERSION}.gz" + fi + # symvers is symvers-.bz symlink, needs a special treatment + i="$KERNEL_DIR/symvers.bz" + if [[ -e "$i" ]]; then + ln -fs "$i" "/boot/symvers-${KERNEL_VERSION}.bz" + command -v restorecon &>/dev/null && \ + restorecon "/boot/symvers-${KERNEL_VERSION}.bz" + fi + fi + + if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then + if [[ -f /etc/kernel/cmdline ]]; then + if [[ /etc/kernel/cmdline -ot /etc/default/grub ]]; then + # user modified /etc/default/grub manually; sync + grub2-mkconfig -o /etc/grub2.cfg + fi + read -r -d '' -a BOOT_OPTIONS < /etc/kernel/cmdline + elif [[ -f /usr/lib/kernel/cmdline ]]; then + read -r -d '' -a BOOT_OPTIONS < /usr/lib/kernel/cmdline + else + declare -a BOOT_OPTIONS + + read -r -d '' -a line < /proc/cmdline + for i in "${line[@]}"; do + [[ "${i#initrd=*}" != "$i" ]] && continue + [[ "${i#BOOT_IMAGE=*}" != "$i" ]] && continue + BOOT_OPTIONS+=("$i") + done + fi + + eval "$(grub2-get-kernel-settings)" || true + [[ -d "$BLS_DIR" ]] || mkdir -m 0700 -p "$BLS_DIR" + BLS_ID="${MACHINE_ID}-${KERNEL_VERSION}" + BLS_TARGET="${BLS_DIR}/${BLS_ID}.conf" + mkbls "${KERNEL_VERSION}" \ + "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${KERNEL_DIR}")")" \ + "${BOOT_OPTIONS[*]}" >"${BLS_TARGET}" + command -v restorecon &>/dev/null && restorecon -R "${BLS_TARGET}" + + LINUX="$(grep '^linux[ \t]' "${BLS_TARGET}" | sed -e 's,^linux[ \t]*,,')" + INITRD="$(grep '^initrd[ \t]' "${BLS_TARGET}" | sed -e 's,^initrd[ \t]*,,')" + if [[ "$(grub2-probe --device $(grub2-probe --target=device /) --target=fs)" == "btrfs" && + "${SUSE_BTRFS_SNAPSHOT_BOOTING}" == "true" ]]; then + LINUX_RELPATH="$(grub2-mkrelpath -r /boot${LINUX})" + else + LINUX_RELPATH="$(grub2-mkrelpath /boot${LINUX})" + fi + BOOTPREFIX="$(dirname ${LINUX_RELPATH})" + ROOTPREFIX="$(dirname "/boot${LINUX}")" + + if [[ $LINUX != $LINUX_RELPATH ]]; then + sed -i -e "s,^linux.*,linux ${BOOTPREFIX}${LINUX},g" "${BLS_TARGET}" + sed -i -e "s,^initrd.*,initrd ${BOOTPREFIX}${INITRD},g" "${BLS_TARGET}" + fi + + if ( [[ "$KERNEL_VERSION" != *${GRUB_DEFAULT_KERNEL_TYPE}* ]] && \ + [ "x$GRUB_NON_STANDARD_KERNEL" == "xtrue" ] ) || \ + ( echo "$KERNEL_VERSION" | grep -E -q "64k|auto|rt|uki" && \ + [ "x$GRUB_NON_STANDARD_KERNEL" != "xtrue" ] ) || \ + ( [[ "$KERNEL_VERSION" == *debug* ]] && [ "x$GRUB_DEFAULT_TO_DEBUG" != "xtrue" ] ); then + GRUB_UPDATE_DEFAULT_KERNEL=false + fi + + if [ "x$GRUB_UPDATE_DEFAULT_KERNEL" = "xtrue" ]; then + NEWDEFAULT="${BLS_ID}" + fi + + if [ "x$GRUB_LINUX_MAKE_DEBUG" = "xtrue" ]; then + BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + cp --preserve=timestamps -T "${BLS_TARGET}" "${BLS_DEBUG}" + TITLE="$(grep '^title[ \t]' "${BLS_DEBUG}" | sed -e 's/^title[ \t]*//')" + OPTIONS="$(echo "${BOOT_OPTIONS[*]} ${GRUB_CMDLINE_LINUX_DEBUG}" | sed -e 's/\//\\\//g')" + sed -i -e "s/^title.*/title ${TITLE}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${BLS_DEBUG}" + sed -i -e "s/^options.*/options ${OPTIONS}/" "${BLS_DEBUG}" + if [ -n "$NEWDEFAULT" -a "x$GRUB_DEFAULT_TO_DEBUG" = "xtrue" ]; then + NEWDEFAULT="${BLS_DEBUG_ID}" + fi + fi + if [ -n "$NEWDEFAULT" ]; then + grub2-editenv - set "saved_entry=${NEWDEFAULT}" + fi + + # this probably isn't the best place to do this, but it will do for now. + if [ -e "${ROOTPREFIX}${INITRD}" -a -e "${ROOTPREFIX}${LINUX}" -a \ + "${ROOTPREFIX}${INITRD}" -ot "${ROOTPREFIX}${LINUX}" -a \ + -x /usr/lib/kernel/install.d/50-dracut.install ]; then + rm -f "${ROOTPREFIX}${INITRD}" + fi + exit 0 + fi + + /sbin/new-kernel-pkg --package "kernel${flavor}" --install "$KERNEL_VERSION" || exit $? + /sbin/new-kernel-pkg --package "kernel${flavor}" --mkinitrd --dracut --depmod --update "$KERNEL_VERSION" || exit $? + /sbin/new-kernel-pkg --package "kernel${flavor}" --rpmposttrans "$KERNEL_VERSION" || exit $? + # If grubby is used there's no need to run other installation plugins + exit 77 + ;; + remove) + + if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then + BLS_TARGET="${BLS_DIR}/${MACHINE_ID}-${KERNEL_VERSION}.conf" + BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + rm -f "${BLS_TARGET}" "${BLS_DEBUG}" + + for i in vmlinuz System.map config zImage.stub dtb; do + rm -rf "/boot/${i}-${KERNEL_VERSION}" + done + # hmac is .vmlinuz-.hmac so needs a special treatment + rm -f "/boot/.vmlinuz-${KERNEL_VERSION}.hmac" + # symvers is symvers-.gz symlink, needs a special treatment + rm -f "/boot/symvers-${KERNEL_VERSION}.gz" + + exit 0 + fi + + /sbin/new-kernel-pkg --package "kernel${flavor+-$flavor}" --rminitrd --rmmoddep --remove "$KERNEL_VERSION" || exit $? + # If grubby is used there's no need to run other installation plugins + exit 77 + ;; + *) + ;; +esac diff --git a/SOURCES/99-grub-mkconfig.install b/SOURCES/99-grub-mkconfig.install new file mode 100755 index 0000000..d9686b5 --- /dev/null +++ b/SOURCES/99-grub-mkconfig.install @@ -0,0 +1,59 @@ +#!/bin/bash + +if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then + exit 0 +fi + +# PV and PVH Xen DomU guests boot with pygrub that doesn't have BLS support, +# also Xen Dom0 use the menuentries from 20_linux_xen and not the ones from +# 10_linux. So BLS support needs to be disabled for both Xen Dom0 and DomU. +if [[ -e /sys/hypervisor/type ]] && grep -q "^xen$" /sys/hypervisor/type; then + RUN_MKCONFIG=true + DISABLE_BLS=true +fi + +ARCH=$(uname -m) +# Older ppc64le OPAL firmware (petitboot version < 1.8.0) don't have BLS support +# so grub2-mkconfig has to be run to generate a config with menuentry commands. +if [[ $ARCH = "ppc64le" ]] && [ -d /sys/firmware/opal ]; then + + petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot" + + if test -e ${petitboot_path}; then + read -r -d '' petitboot_version < ${petitboot_path} + petitboot_version="$(echo ${petitboot_version//v})" + major_version="$(echo ${petitboot_version} | cut -d . -f1)" + minor_version="$(echo ${petitboot_version} | cut -d . -f2)" + + if test -z ${petitboot_version} || test ${major_version} -lt 1 || \ + test ${major_version} -eq 1 -a ${minor_version} -lt 8; then + RUN_MKCONFIG=true + fi + else + RUN_MKCONFIG=true + fi +fi + +if [[ $DISABLE_BLS = "true" ]]; then + if grep -q '^GRUB_ENABLE_BLSCFG="*true"*\s*$' /etc/default/grub; then + sed -i 's/^GRUB_ENABLE_BLSCFG=.*/GRUB_ENABLE_BLSCFG=false/' /etc/default/grub + fi +fi + +# A traditional grub configuration file needs to be generated only in the case when +# the bootloaders are not capable of populating a menu entry from the BLS fragments. +if [[ $RUN_MKCONFIG != "true" ]]; then + exit 0 +fi + +[[ -f /etc/default/grub ]] && . /etc/default/grub + +COMMAND="$1" + +case "$COMMAND" in + add|remove) + grub2-mkconfig --no-grubenv-update -o /boot/grub2/grub.cfg >& /dev/null + ;; + *) + ;; +esac diff --git a/SOURCES/bootstrap b/SOURCES/bootstrap new file mode 100755 index 0000000..5b08e7e --- /dev/null +++ b/SOURCES/bootstrap @@ -0,0 +1,1073 @@ +#! /bin/sh +# Print a version string. +scriptversion=2019-01-04.17; # UTC + +# Bootstrap this package from checked-out sources. + +# Copyright (C) 2003-2019 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Originally written by Paul Eggert. The canonical version of this +# script is maintained as build-aux/bootstrap in gnulib, however, to +# be useful to your project, you should place a copy of it under +# version control in the top-level directory of your project. The +# intent is that all customization can be done with a bootstrap.conf +# file also maintained in your version control; gnulib comes with a +# template build-aux/bootstrap.conf to get you started. + +# Please report bugs or propose patches to bug-gnulib@gnu.org. + +nl=' +' + +# Ensure file names are sorted consistently across platforms. +LC_ALL=C +export LC_ALL + +# Ensure that CDPATH is not set. Otherwise, the output from cd +# would cause trouble in at least one use below. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +local_gl_dir=gl + +# Honor $PERL, but work even if there is none. +PERL="${PERL-perl}" + +me=$0 + +default_gnulib_url=git://git.sv.gnu.org/gnulib + +usage() { + cat <&2 +} + +# warn_ WORD1... +warn_ () +{ + # If IFS does not start with ' ', set it and emit the warning in a subshell. + case $IFS in + ' '*) warnf_ '%s\n' "$*";; + *) (IFS=' '; warn_ "$@");; + esac +} + +# die WORD1... +die() { warn_ "$@"; exit 1; } + +# Configuration. + +# Name of the Makefile.am +gnulib_mk=gnulib.mk + +# List of gnulib modules needed. +gnulib_modules= + +# Any gnulib files needed that are not in modules. +gnulib_files= + +: ${AUTOPOINT=autopoint} +: ${AUTORECONF=autoreconf} + +# A function to be called right after gnulib-tool is run. +# Override it via your own definition in bootstrap.conf. +bootstrap_post_import_hook() { :; } + +# A function to be called after everything else in this script. +# Override it via your own definition in bootstrap.conf. +bootstrap_epilogue() { :; } + +# The command to download all .po files for a specified domain into a +# specified directory. Fill in the first %s with the destination +# directory and the second with the domain name. +po_download_command_format=\ +"wget --mirror --level=1 -nd -q -A.po -P '%s' \ + https://translationproject.org/latest/%s/" + +# Prefer a non-empty tarname (4th argument of AC_INIT if given), else +# fall back to the package name (1st argument with munging) +extract_package_name=' + /^AC_INIT(\[*/{ + s/// + /^[^,]*,[^,]*,[^,]*,[ []*\([^][ ,)]\)/{ + s//\1/ + s/[],)].*// + p + q + } + s/[],)].*// + s/^GNU // + y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + s/[^abcdefghijklmnopqrstuvwxyz0123456789_]/-/g + p + } +' +package=$(sed -n "$extract_package_name" configure.ac) \ + || die 'cannot find package name in configure.ac' +gnulib_name=lib$package + +build_aux=build-aux +source_base=lib +m4_base=m4 +doc_base=doc +tests_base=tests +gnulib_extra_files=" + build-aux/install-sh + build-aux/mdate-sh + build-aux/texinfo.tex + build-aux/depcomp + build-aux/config.guess + build-aux/config.sub + doc/INSTALL +" + +# Additional gnulib-tool options to use. Use "\newline" to break lines. +gnulib_tool_option_extras= + +# Other locale categories that need message catalogs. +EXTRA_LOCALE_CATEGORIES= + +# Additional xgettext options to use. Use "\\\newline" to break lines. +XGETTEXT_OPTIONS='\\\ + --flag=_:1:pass-c-format\\\ + --flag=N_:1:pass-c-format\\\ + --flag=error:3:c-format --flag=error_at_line:5:c-format\\\ +' + +# Package bug report address and copyright holder for gettext files +COPYRIGHT_HOLDER='Free Software Foundation, Inc.' +MSGID_BUGS_ADDRESS=bug-$package@gnu.org + +# Files we don't want to import. +excluded_files= + +# File that should exist in the top directory of a checked out hierarchy, +# but not in a distribution tarball. +checkout_only_file=README-hacking + +# Whether to use copies instead of symlinks. +copy=false + +# Set this to '.cvsignore .gitignore' in bootstrap.conf if you want +# those files to be generated in directories like lib/, m4/, and po/. +# Or set it to 'auto' to make this script select which to use based +# on which version control system (if any) is used in the source directory. +vc_ignore=auto + +# Set this to true in bootstrap.conf to enable --bootstrap-sync by +# default. +bootstrap_sync=false + +# Use git to update gnulib sources +use_git=true + +check_exists() { + if test "$1" = "--verbose"; then + ($2 --version /dev/null 2>&1 + if test $? -ge 126; then + # If not found, run with diagnostics as one may be + # presented with env variables to set to find the right version + ($2 --version /dev/null 2>&1 + fi + + test $? -lt 126 +} + +# find_tool ENVVAR NAMES... +# ------------------------- +# Search for a required program. Use the value of ENVVAR, if set, +# otherwise find the first of the NAMES that can be run. +# If found, set ENVVAR to the program name, die otherwise. +# +# FIXME: code duplication, see also gnu-web-doc-update. +find_tool () +{ + find_tool_envvar=$1 + shift + find_tool_names=$@ + eval "find_tool_res=\$$find_tool_envvar" + if test x"$find_tool_res" = x; then + for i; do + if check_exists $i; then + find_tool_res=$i + break + fi + done + fi + if test x"$find_tool_res" = x; then + warn_ "one of these is required: $find_tool_names;" + die "alternatively set $find_tool_envvar to a compatible tool" + fi + eval "$find_tool_envvar=\$find_tool_res" + eval "export $find_tool_envvar" +} + +# Override the default configuration, if necessary. +# Make sure that bootstrap.conf is sourced from the current directory +# if we were invoked as "sh bootstrap". +case "$0" in + */*) test -r "$0.conf" && . "$0.conf" ;; + *) test -r "$0.conf" && . ./"$0.conf" ;; +esac + +if test "$vc_ignore" = auto; then + vc_ignore= + test -d .git && vc_ignore=.gitignore + test -d CVS && vc_ignore="$vc_ignore .cvsignore" +fi + +if test x"$gnulib_modules$gnulib_files$gnulib_extra_files" = x; then + use_gnulib=false +else + use_gnulib=true +fi + +# Translate configuration into internal form. + +# Parse options. + +for option +do + case $option in + --help) + usage + exit;; + --gnulib-srcdir=*) + GNULIB_SRCDIR=${option#--gnulib-srcdir=};; + --skip-po) + SKIP_PO=t;; + --force) + checkout_only_file=;; + --copy) + copy=true;; + --bootstrap-sync) + bootstrap_sync=true;; + --no-bootstrap-sync) + bootstrap_sync=false;; + --no-git) + use_git=false;; + *) + die "$option: unknown option";; + esac +done + +$use_git || test -d "$GNULIB_SRCDIR" \ + || die "Error: --no-git requires --gnulib-srcdir" + +if test -n "$checkout_only_file" && test ! -r "$checkout_only_file"; then + die "Bootstrapping from a non-checked-out distribution is risky." +fi + +# Strip blank and comment lines to leave significant entries. +gitignore_entries() { + sed '/^#/d; /^$/d' "$@" +} + +# If $STR is not already on a line by itself in $FILE, insert it at the start. +# Entries are inserted at the start of the ignore list to ensure existing +# entries starting with ! are not overridden. Such entries support +# whitelisting exceptions after a more generic blacklist pattern. +insert_if_absent() { + file=$1 + str=$2 + test -f $file || touch $file + test -r $file || die "Error: failed to read ignore file: $file" + duplicate_entries=$(gitignore_entries $file | sort | uniq -d) + if [ "$duplicate_entries" ] ; then + die "Error: Duplicate entries in $file: " $duplicate_entries + fi + linesold=$(gitignore_entries $file | wc -l) + linesnew=$( { echo "$str"; cat $file; } | gitignore_entries | sort -u | wc -l) + if [ $linesold != $linesnew ] ; then + { echo "$str" | cat - $file > $file.bak && mv $file.bak $file; } \ + || die "insert_if_absent $file $str: failed" + fi +} + +# Adjust $PATTERN for $VC_IGNORE_FILE and insert it with +# insert_if_absent. +insert_vc_ignore() { + vc_ignore_file="$1" + pattern="$2" + case $vc_ignore_file in + *.gitignore) + # A .gitignore entry that does not start with '/' applies + # recursively to subdirectories, so prepend '/' to every + # .gitignore entry. + pattern=$(echo "$pattern" | sed s,^,/,);; + esac + insert_if_absent "$vc_ignore_file" "$pattern" +} + +# Die if there is no AC_CONFIG_AUX_DIR($build_aux) line in configure.ac. +found_aux_dir=no +grep '^[ ]*AC_CONFIG_AUX_DIR(\['"$build_aux"'\])' configure.ac \ + >/dev/null && found_aux_dir=yes +grep '^[ ]*AC_CONFIG_AUX_DIR('"$build_aux"')' configure.ac \ + >/dev/null && found_aux_dir=yes +test $found_aux_dir = yes \ + || die "configure.ac lacks 'AC_CONFIG_AUX_DIR([$build_aux])'; add it" + +# If $build_aux doesn't exist, create it now, otherwise some bits +# below will malfunction. If creating it, also mark it as ignored. +if test ! -d $build_aux; then + mkdir $build_aux + for dot_ig in x $vc_ignore; do + test $dot_ig = x && continue + insert_vc_ignore $dot_ig $build_aux + done +fi + +# Note this deviates from the version comparison in automake +# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a +# but this should suffice as we won't be specifying old +# version formats or redundant trailing .0 in bootstrap.conf. +# If we did want full compatibility then we should probably +# use m4_version_compare from autoconf. +sort_ver() { # sort -V is not generally available + ver1="$1" + ver2="$2" + + # split on '.' and compare each component + i=1 + while : ; do + p1=$(echo "$ver1" | cut -d. -f$i) + p2=$(echo "$ver2" | cut -d. -f$i) + if [ ! "$p1" ]; then + echo "$1 $2" + break + elif [ ! "$p2" ]; then + echo "$2 $1" + break + elif [ ! "$p1" = "$p2" ]; then + if [ "$p1" -gt "$p2" ] 2>/dev/null; then # numeric comparison + echo "$2 $1" + elif [ "$p2" -gt "$p1" ] 2>/dev/null; then # numeric comparison + echo "$1 $2" + else # numeric, then lexicographic comparison + lp=$(printf "$p1\n$p2\n" | LANG=C sort -n | tail -n1) + if [ "$lp" = "$p2" ]; then + echo "$1 $2" + else + echo "$2 $1" + fi + fi + break + fi + i=$(($i+1)) + done +} + +get_version_sed=' +# Move version to start of line. +s/.*[v ]\([0-9]\)/\1/ + +# Skip lines that do not start with version. +/^[0-9]/!d + +# Remove characters after the version. +s/[^.a-z0-9-].*// + +# The first component must be digits only. +s/^\([0-9]*\)[a-z-].*/\1/ + +#the following essentially does s/5.005/5.5/ +s/\.0*\([1-9]\)/.\1/g +p +q' + +get_version() { + app=$1 + + $app --version >/dev/null 2>&1 || { $app --version; return 1; } + + $app --version 2>&1 | sed -n "$get_version_sed" +} + +check_versions() { + ret=0 + + while read app req_ver; do + # We only need libtoolize from the libtool package. + if test "$app" = libtool; then + app=libtoolize + fi + # Exempt git if --no-git is in effect. + if test "$app" = git; then + $use_git || continue + fi + # Honor $APP variables ($TAR, $AUTOCONF, etc.) + appvar=$(echo $app | LC_ALL=C tr '[a-z]-' '[A-Z]_') + test "$appvar" = TAR && appvar=AMTAR + case $appvar in + GZIP) ;; # Do not use $GZIP: it contains gzip options. + PERL::*) ;; # Keep perl modules as-is + *) eval "app=\${$appvar-$app}" ;; + esac + + # Handle the still-experimental Automake-NG programs specially. + # They remain named as the mainstream Automake programs ("automake", + # and "aclocal") to avoid gratuitous incompatibilities with + # pre-existing usages (by, say, autoreconf, or custom autogen.sh + # scripts), but correctly identify themselves (as being part of + # "GNU automake-ng") when asked their version. + case $app in + automake-ng|aclocal-ng) + app=${app%-ng} + ($app --version | grep '(GNU automake-ng)') >/dev/null 2>&1 || { + warn_ "Error: '$app' not found or not from Automake-NG" + ret=1 + continue + } ;; + # Another check is for perl modules. These can be written as + # e.g. perl::XML::XPath in case of XML::XPath module, etc. + perl::*) + # Extract module name + app="${app#perl::}" + if ! $PERL -m"$app" -e 'exit 0' >/dev/null 2>&1; then + warn_ "Error: perl module '$app' not found" + ret=1 + fi + continue + ;; + esac + if [ "$req_ver" = "-" ]; then + # Merely require app to exist; not all prereq apps are well-behaved + # so we have to rely on $? rather than get_version. + if ! check_exists --verbose $app; then + warn_ "Error: '$app' not found" + ret=1 + fi + else + # Require app to produce a new enough version string. + inst_ver=$(get_version $app) + if [ ! "$inst_ver" ]; then + warn_ "Error: '$app' not found" + ret=1 + else + latest_ver=$(sort_ver $req_ver $inst_ver | cut -d' ' -f2) + if [ ! "$latest_ver" = "$inst_ver" ]; then + warnf_ '%s\n' \ + "Error: '$app' version == $inst_ver is too old" \ + " '$app' version >= $req_ver is required" + ret=1 + fi + fi + fi + done + + return $ret +} + +print_versions() { + echo "Program Min_version" + echo "----------------------" + printf %s "$buildreq" + echo "----------------------" + # can't depend on column -t +} + +# Find sha1sum, named gsha1sum on MacPorts, shasum on Mac OS X 10.6. +# Also find the compatible sha1 utility on the BSDs +if test x"$SKIP_PO" = x; then + find_tool SHA1SUM sha1sum gsha1sum shasum sha1 +fi + +use_libtool=0 +# We'd like to use grep -E, to see if any of LT_INIT, +# AC_PROG_LIBTOOL, AM_PROG_LIBTOOL is used in configure.ac, +# but that's not portable enough (e.g., for Solaris). +grep '^[ ]*A[CM]_PROG_LIBTOOL' configure.ac >/dev/null \ + && use_libtool=1 +grep '^[ ]*LT_INIT' configure.ac >/dev/null \ + && use_libtool=1 +if test $use_libtool = 1; then + find_tool LIBTOOLIZE glibtoolize libtoolize +fi + +# gnulib-tool requires at least automake and autoconf. +# If either is not listed, add it (with minimum version) as a prerequisite. +case $buildreq in + *automake*) ;; + *) buildreq="automake 1.9 +$buildreq" ;; +esac +case $buildreq in + *autoconf*) ;; + *) buildreq="autoconf 2.59 +$buildreq" ;; +esac + +# When we can deduce that gnulib-tool will require patch, +# and when patch is not already listed as a prerequisite, add it, too. +if test -d "$local_gl_dir" \ + && ! find "$local_gl_dir" -name '*.diff' -exec false {} +; then + case $buildreq in + *patch*) ;; + *) buildreq="patch - +$buildreq" ;; + esac +fi + +if ! printf "$buildreq" | check_versions; then + echo >&2 + if test -f README-prereq; then + die "See README-prereq for how to get the prerequisite programs" + else + die "Please install the prerequisite programs" + fi +fi + +# Warn the user if autom4te appears to be broken; this causes known +# issues with at least gettext 0.18.3. +probe=$(echo 'm4_quote([hi])' | autom4te -l M4sugar -t 'm4_quote:$%' -) +if test "x$probe" != xhi; then + warn_ "WARNING: your autom4te wrapper eats stdin;" + warn_ "if bootstrap fails, consider upgrading your autotools" +fi + +echo "$0: Bootstrapping from checked-out $package sources..." + +# See if we can use gnulib's git-merge-changelog merge driver. +if $use_git && test -d .git && check_exists git; then + if git config merge.merge-changelog.driver >/dev/null ; then + : + elif check_exists git-merge-changelog; then + echo "$0: initializing git-merge-changelog driver" + git config merge.merge-changelog.name 'GNU-style ChangeLog merge driver' + git config merge.merge-changelog.driver 'git-merge-changelog %O %A %B' + else + echo "$0: consider installing git-merge-changelog from gnulib" + fi +fi + + +cleanup_gnulib() { + status=$? + rm -fr "$gnulib_path" + exit $status +} + +git_modules_config () { + test -f .gitmodules && git config --file .gitmodules "$@" +} + +if $use_gnulib; then + if $use_git; then + gnulib_path=$(git_modules_config submodule.gnulib.path) + test -z "$gnulib_path" && gnulib_path=gnulib + fi + + # Get gnulib files. Populate $GNULIB_SRCDIR, possibly updating a + # submodule, for use in the rest of the script. + + case ${GNULIB_SRCDIR--} in + -) + # Note that $use_git is necessarily true in this case. + if git_modules_config submodule.gnulib.url >/dev/null; then + echo "$0: getting gnulib files..." + git submodule init -- "$gnulib_path" || exit $? + git submodule update -- "$gnulib_path" || exit $? + + elif [ ! -d "$gnulib_path" ]; then + echo "$0: getting gnulib files..." + + trap cleanup_gnulib 1 2 13 15 + + shallow= + if test -z "$GNULIB_REVISION"; then + git clone -h 2>&1 | grep -- --depth > /dev/null && shallow='--depth 2' + fi + git clone $shallow ${GNULIB_URL:-$default_gnulib_url} "$gnulib_path" \ + || cleanup_gnulib + + trap - 1 2 13 15 + fi + GNULIB_SRCDIR=$gnulib_path + ;; + *) + # Use GNULIB_SRCDIR directly or as a reference. + if $use_git && test -d "$GNULIB_SRCDIR"/.git && \ + git_modules_config submodule.gnulib.url >/dev/null; then + echo "$0: getting gnulib files..." + if git submodule -h|grep -- --reference > /dev/null; then + # Prefer the one-liner available in git 1.6.4 or newer. + git submodule update --init --reference "$GNULIB_SRCDIR" \ + "$gnulib_path" || exit $? + else + # This fallback allows at least git 1.5.5. + if test -f "$gnulib_path"/gnulib-tool; then + # Since file already exists, assume submodule init already complete. + git submodule update -- "$gnulib_path" || exit $? + else + # Older git can't clone into an empty directory. + rmdir "$gnulib_path" 2>/dev/null + git clone --reference "$GNULIB_SRCDIR" \ + "$(git_modules_config submodule.gnulib.url)" "$gnulib_path" \ + && git submodule init -- "$gnulib_path" \ + && git submodule update -- "$gnulib_path" \ + || exit $? + fi + fi + GNULIB_SRCDIR=$gnulib_path + fi + ;; + esac + + if test -d "$GNULIB_SRCDIR"/.git && test -n "$GNULIB_REVISION" \ + && ! git_modules_config submodule.gnulib.url >/dev/null; then + (cd "$GNULIB_SRCDIR" && git checkout "$GNULIB_REVISION") || cleanup_gnulib + fi + + # $GNULIB_SRCDIR now points to the version of gnulib to use, and + # we no longer need to use git or $gnulib_path below here. + + if $bootstrap_sync; then + cmp -s "$0" "$GNULIB_SRCDIR/build-aux/bootstrap" || { + echo "$0: updating bootstrap and restarting..." + case $(sh -c 'echo "$1"' -- a) in + a) ignored=--;; + *) ignored=ignored;; + esac + exec sh -c \ + 'cp "$1" "$2" && shift && exec "${CONFIG_SHELL-/bin/sh}" "$@"' \ + $ignored "$GNULIB_SRCDIR/build-aux/bootstrap" \ + "$0" "$@" --no-bootstrap-sync + } + fi + + gnulib_tool=$GNULIB_SRCDIR/gnulib-tool + <$gnulib_tool || exit $? +fi + +# Get translations. + +download_po_files() { + subdir=$1 + domain=$2 + echo "$me: getting translations into $subdir for $domain..." + cmd=$(printf "$po_download_command_format" "$subdir" "$domain") + eval "$cmd" +} + +# Mirror .po files to $po_dir/.reference and copy only the new +# or modified ones into $po_dir. Also update $po_dir/LINGUAS. +# Note po files that exist locally only are left in $po_dir but will +# not be included in LINGUAS and hence will not be distributed. +update_po_files() { + # Directory containing primary .po files. + # Overwrite them only when we're sure a .po file is new. + po_dir=$1 + domain=$2 + + # Mirror *.po files into this dir. + # Usually contains *.s1 checksum files. + ref_po_dir="$po_dir/.reference" + + test -d $ref_po_dir || mkdir $ref_po_dir || return + download_po_files $ref_po_dir $domain \ + && ls "$ref_po_dir"/*.po 2>/dev/null | + sed 's|.*/||; s|\.po$||' > "$po_dir/LINGUAS" || return + + langs=$(cd $ref_po_dir && echo *.po | sed 's/\.po//g') + test "$langs" = '*' && langs=x + for po in $langs; do + case $po in x) continue;; esac + new_po="$ref_po_dir/$po.po" + cksum_file="$ref_po_dir/$po.s1" + if ! test -f "$cksum_file" || + ! test -f "$po_dir/$po.po" || + ! $SHA1SUM -c "$cksum_file" < "$new_po" > /dev/null 2>&1; then + echo "$me: updated $po_dir/$po.po..." + cp "$new_po" "$po_dir/$po.po" \ + && $SHA1SUM < "$new_po" > "$cksum_file" || return + fi + done +} + +case $SKIP_PO in +'') + if test -d po; then + update_po_files po $package || exit + fi + + if test -d runtime-po; then + update_po_files runtime-po $package-runtime || exit + fi;; +esac + +symlink_to_dir() +{ + src=$1/$2 + dst=${3-$2} + + test -f "$src" && { + + # If the destination directory doesn't exist, create it. + # This is required at least for "lib/uniwidth/cjk.h". + dst_dir=$(dirname "$dst") + if ! test -d "$dst_dir"; then + mkdir -p "$dst_dir" + + # If we've just created a directory like lib/uniwidth, + # tell version control system(s) it's ignorable. + # FIXME: for now, this does only one level + parent=$(dirname "$dst_dir") + for dot_ig in x $vc_ignore; do + test $dot_ig = x && continue + ig=$parent/$dot_ig + insert_vc_ignore $ig "${dst_dir##*/}" + done + fi + + if $copy; then + { + test ! -h "$dst" || { + echo "$me: rm -f $dst" && + rm -f "$dst" + } + } && + test -f "$dst" && + cmp -s "$src" "$dst" || { + echo "$me: cp -fp $src $dst" && + cp -fp "$src" "$dst" + } + else + # Leave any existing symlink alone, if it already points to the source, + # so that broken build tools that care about symlink times + # aren't confused into doing unnecessary builds. Conversely, if the + # existing symlink's timestamp is older than the source, make it afresh, + # so that broken tools aren't confused into skipping needed builds. See + # . + test -h "$dst" && + src_ls=$(ls -diL "$src" 2>/dev/null) && set $src_ls && src_i=$1 && + dst_ls=$(ls -diL "$dst" 2>/dev/null) && set $dst_ls && dst_i=$1 && + test "$src_i" = "$dst_i" && + both_ls=$(ls -dt "$src" "$dst") && + test "X$both_ls" = "X$dst$nl$src" || { + dot_dots= + case $src in + /*) ;; + *) + case /$dst/ in + *//* | */../* | */./* | /*/*/*/*/*/) + die "invalid symlink calculation: $src -> $dst";; + /*/*/*/*/) dot_dots=../../../;; + /*/*/*/) dot_dots=../../;; + /*/*/) dot_dots=../;; + esac;; + esac + + echo "$me: ln -fs $dot_dots$src $dst" && + ln -fs "$dot_dots$src" "$dst" + } + fi + } +} + +version_controlled_file() { + parent=$1 + file=$2 + if test -d .git; then + git rm -n "$file" > /dev/null 2>&1 + elif test -d .svn; then + svn log -r HEAD "$file" > /dev/null 2>&1 + elif test -d CVS; then + grep -F "/${file##*/}/" "$parent/CVS/Entries" 2>/dev/null | + grep '^/[^/]*/[0-9]' > /dev/null + else + warn_ "no version control for $file?" + false + fi +} + +# NOTE: we have to be careful to run both autopoint and libtoolize +# before gnulib-tool, since gnulib-tool is likely to provide newer +# versions of files "installed" by these two programs. +# Then, *after* gnulib-tool (see below), we have to be careful to +# run autoreconf in such a way that it does not run either of these +# two just-pre-run programs. + +# Import from gettext. +with_gettext=yes +grep '^[ ]*AM_GNU_GETTEXT_VERSION(' configure.ac >/dev/null || \ + with_gettext=no + +if test $with_gettext = yes || test $use_libtool = 1; then + + tempbase=.bootstrap$$ + trap "rm -f $tempbase.0 $tempbase.1" 1 2 13 15 + + > $tempbase.0 > $tempbase.1 && + find . ! -type d -print | sort > $tempbase.0 || exit + + if test $with_gettext = yes; then + # Released autopoint has the tendency to install macros that have been + # obsoleted in current gnulib, so run this before gnulib-tool. + echo "$0: $AUTOPOINT --force" + $AUTOPOINT --force || exit + fi + + # Autoreconf runs aclocal before libtoolize, which causes spurious + # warnings if the initial aclocal is confused by the libtoolized + # (or worse out-of-date) macro directory. + # libtoolize 1.9b added the --install option; but we support back + # to libtoolize 1.5.22, where the install action was default. + if test $use_libtool = 1; then + install= + case $($LIBTOOLIZE --help) in + *--install*) install=--install ;; + esac + echo "running: $LIBTOOLIZE $install --copy" + $LIBTOOLIZE $install --copy + fi + + find . ! -type d -print | sort >$tempbase.1 + old_IFS=$IFS + IFS=$nl + for file in $(comm -13 $tempbase.0 $tempbase.1); do + IFS=$old_IFS + parent=${file%/*} + version_controlled_file "$parent" "$file" || { + for dot_ig in x $vc_ignore; do + test $dot_ig = x && continue + ig=$parent/$dot_ig + insert_vc_ignore "$ig" "${file##*/}" + done + } + done + IFS=$old_IFS + + rm -f $tempbase.0 $tempbase.1 + trap - 1 2 13 15 +fi + +# Import from gnulib. + +if $use_gnulib; then + gnulib_tool_options="\ + --no-changelog\ + --aux-dir=$build_aux\ + --doc-base=$doc_base\ + --lib=$gnulib_name\ + --m4-base=$m4_base/\ + --source-base=$source_base/\ + --tests-base=$tests_base\ + --local-dir=$local_gl_dir\ + $gnulib_tool_option_extras\ + " + if test $use_libtool = 1; then + case "$gnulib_tool_options " in + *' --libtool '*) ;; + *) gnulib_tool_options="$gnulib_tool_options --libtool" ;; + esac + fi + echo "$0: $gnulib_tool $gnulib_tool_options --import ..." + $gnulib_tool $gnulib_tool_options --import $gnulib_modules \ + || die "gnulib-tool failed" + + for file in $gnulib_files; do + symlink_to_dir "$GNULIB_SRCDIR" $file \ + || die "failed to symlink $file" + done +fi + +bootstrap_post_import_hook \ + || die "bootstrap_post_import_hook failed" + +# Don't proceed if there are uninitialized submodules. In particular, +# the next step will remove dangling links, which might be links into +# uninitialized submodules. +# +# Uninitialized submodules are listed with an initial dash. +if $use_git && git submodule | grep '^-' >/dev/null; then + die "some git submodules are not initialized. " \ + "Run 'git submodule init' and bootstrap again." +fi + +# Remove any dangling symlink matching "*.m4" or "*.[ch]" in some +# gnulib-populated directories. Such .m4 files would cause aclocal to fail. +# The following requires GNU find 4.2.3 or newer. Considering the usual +# portability constraints of this script, that may seem a very demanding +# requirement, but it should be ok. Ignore any failure, which is fine, +# since this is only a convenience to help developers avoid the relatively +# unusual case in which a symlinked-to .m4 file is git-removed from gnulib +# between successive runs of this script. +find "$m4_base" "$source_base" \ + -depth \( -name '*.m4' -o -name '*.[ch]' \) \ + -type l -xtype l -delete > /dev/null 2>&1 + +# Invoke autoreconf with --force --install to ensure upgrades of tools +# such as ylwrap. +AUTORECONFFLAGS="--verbose --install --force -I $m4_base $ACLOCAL_FLAGS" + +# Some systems (RHEL 5) are using ancient autotools, for which the +# --no-recursive option had not been invented. Detect that lack and +# omit the option when it's not supported. FIXME in 2017: remove this +# hack when RHEL 5 autotools are updated, or when they become irrelevant. +case $($AUTORECONF --help) in + *--no-recursive*) AUTORECONFFLAGS="$AUTORECONFFLAGS --no-recursive";; +esac + +# Tell autoreconf not to invoke autopoint or libtoolize; they were run above. +echo "running: AUTOPOINT=true LIBTOOLIZE=true $AUTORECONF $AUTORECONFFLAGS" +AUTOPOINT=true LIBTOOLIZE=true $AUTORECONF $AUTORECONFFLAGS \ + || die "autoreconf failed" + +# Get some extra files from gnulib, overriding existing files. +for file in $gnulib_extra_files; do + case $file in + */INSTALL) dst=INSTALL;; + build-aux/*) dst=$build_aux/${file#build-aux/};; + *) dst=$file;; + esac + symlink_to_dir "$GNULIB_SRCDIR" $file $dst \ + || die "failed to symlink $file" +done + +if test $with_gettext = yes; then + # Create gettext configuration. + echo "$0: Creating po/Makevars from po/Makevars.template ..." + rm -f po/Makevars + sed ' + /^EXTRA_LOCALE_CATEGORIES *=/s/=.*/= '"$EXTRA_LOCALE_CATEGORIES"'/ + /^COPYRIGHT_HOLDER *=/s/=.*/= '"$COPYRIGHT_HOLDER"'/ + /^MSGID_BUGS_ADDRESS *=/s|=.*|= '"$MSGID_BUGS_ADDRESS"'| + /^XGETTEXT_OPTIONS *=/{ + s/$/ \\/ + a\ + '"$XGETTEXT_OPTIONS"' $${end_of_xgettext_options+} + } + ' po/Makevars.template >po/Makevars \ + || die 'cannot generate po/Makevars' + + # If the 'gettext' module is in use, grab the latest Makefile.in.in. + # If only the 'gettext-h' module is in use, assume autopoint already + # put the correct version of this file into place. + case $gnulib_modules in + *gettext-h*) ;; + *gettext*) + cp $GNULIB_SRCDIR/build-aux/po/Makefile.in.in po/Makefile.in.in \ + || die "cannot create po/Makefile.in.in" + ;; + esac + + if test -d runtime-po; then + # Similarly for runtime-po/Makevars, but not quite the same. + rm -f runtime-po/Makevars + sed ' + /^DOMAIN *=.*/s/=.*/= '"$package"'-runtime/ + /^subdir *=.*/s/=.*/= runtime-po/ + /^MSGID_BUGS_ADDRESS *=/s/=.*/= bug-'"$package"'@gnu.org/ + /^XGETTEXT_OPTIONS *=/{ + s/$/ \\/ + a\ + '"$XGETTEXT_OPTIONS_RUNTIME"' $${end_of_xgettext_options+} + } + ' po/Makevars.template >runtime-po/Makevars \ + || die 'cannot generate runtime-po/Makevars' + + # Copy identical files from po to runtime-po. + (cd po && cp -p Makefile.in.in *-quot *.header *.sed *.sin ../runtime-po) + fi +fi + +bootstrap_epilogue + +echo "$0: done. Now you can run './configure'." + +# Local variables: +# eval: (add-hook 'before-save-hook 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" +# End: diff --git a/SOURCES/bootstrap.conf b/SOURCES/bootstrap.conf new file mode 100644 index 0000000..6b043fc --- /dev/null +++ b/SOURCES/bootstrap.conf @@ -0,0 +1,101 @@ +# Bootstrap configuration. + +# Copyright (C) 2006-2019 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263 + +# gnulib modules used by this package. +# mbswidth is used by gnulib-fix-width.diff's changes to argp rather than +# directly. +gnulib_modules=" + argp + base64 + error + fnmatch + getdelim + getline + gettext-h + gitlog-to-changelog + mbswidth + progname + realloc-gnu + regex + save-cwd +" + +gnulib_tool_option_extras="\ + --no-conditional-dependencies \ + --no-vc-files \ +" + +gnulib_name=libgnu +source_base=grub-core/lib/gnulib +gnulib_extra_files=" + build-aux/install-sh + build-aux/mdate-sh + build-aux/texinfo.tex + build-aux/depcomp + build-aux/config.guess + build-aux/config.sub +" + +# Additional xgettext options to use. Use "\\\newline" to break lines. +XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\ + --from-code=UTF-8\\\ +' + +checkout_only_file= +copy=true +vc_ignore= + +SKIP_PO=t + +# Build prerequisites +buildreq="\ +autoconf 2.63 +automake 1.11 +gettext 0.18.3 +git 1.5.5 +tar - +" + +# bootstrap doesn't give us a reasonable way to stop Automake from +# overwriting this, so we just copy our version aside and put it back later. +cp -a INSTALL INSTALL.grub + +bootstrap_post_import_hook () { + set -e + for patchname in fix-base64 fix-null-deref fix-null-state-deref fix-regcomp-uninit-token \ + fix-regexec-null-deref fix-uninit-structure fix-unused-value fix-width no-abort; do + patch -d grub-core/lib/gnulib -p2 \ + < "grub-core/lib/gnulib-patches/$patchname.patch" + done + for patchname in \ + 0001-Support-POTFILES-shell \ + 0002-Handle-gettext_printf-shell-function \ + 0003-Make-msgfmt-output-in-little-endian \ + 0004-Use-SHELL-rather-than-bin-sh; do + patch -d po -p3 \ + < "po/gettext-patches/$patchname.patch" + done + FROM_BOOTSTRAP=1 ./autogen.sh + set +e # bootstrap expects this +} + +bootstrap_epilogue () { + mv INSTALL.grub INSTALL +} diff --git a/SOURCES/gitignore b/SOURCES/gitignore new file mode 100644 index 0000000..f6a1bd0 --- /dev/null +++ b/SOURCES/gitignore @@ -0,0 +1,277 @@ +# +# Ignore patterns in this directory and all subdirectories. +# +*.1 +*.8 +*.a +*.exec +*.exec.exe +*.image +*.image.exe +*.img +*.log +*.lst +*.marker +*.mod +*.o +*.pf2 +*.pp +*.trs +*~ +.deps-core/ +.deps-util/ +.deps/ +.dirstamp +DISTLIST +GPATH +GRTAGS +GSYMS +GTAGS +Makefile +Makefile.in +ascii.bitmaps +genkernsyms.sh +gensymlist.sh +grub-bin2h +grub-emu +grub-emu-lite +grub-emu-lite.exe +grub-emu.exe +grub-macho2img +grub_emu_init.c +grub_emu_init.h +grub_probe_init.c +grub_probe_init.h +grub_script.tab.c +grub_script.tab.h +grub_script.yy.c +grub_script.yy.h +grub_script_check_init.c +grub_script_check_init.h +grub_setup_init.c +grub_setup_init.h +mdate-sh +mod-*.c +update-grub_lib +widthspec.bin + +# +# Ignore patterns relative to this .gitignore file's directory. +# +/00_header +/10_* +/20_linux_xen +/30_os-prober +/30_uefi-firmware +/40_custom +/41_custom +/ABOUT-NLS +/ChangeLog +/INSTALL.grub +/Makefile.util.am +/Makefile.utilgcry.def +/aclocal.m4 +/ahci_test +/ascii.h +/autom4te.cache/ +/btrfs_test +/build-aux/ +/build-grub-gen-asciih +/build-grub-gen-widthspec +/build-grub-mkfont +/cdboot_test +/cmp_test +/compile +/config-util.h +/config-util.h.in +/config.cache +/config.guess +/config.h +/config.log +/config.status +/config.sub +/configure +/contrib +/core_compress_test +/cpio_test +/date_test +/depcomp +/docs/*.info +/docs/*.info-[0-9]* +/docs/stamp-1 +/docs/stamp-vti +/docs/version-dev.texi +/docs/version.texi +/ehci_test +/example_grub_script_test +/example_scripted_test +/example_unit_test +/exfat_test +/ext234_test +/f2fs_test +/fat_test +/fddboot_test +/file_filter_test +/garbage-gen +/garbage-gen.exe +/gettext_strings_test +/gnulib/ +/grub-2.[0-9]*/ +/grub-2.[0-9]*.tar.gz +/grub-bios-setup +/grub-bios-setup.exe +/grub-core/*.module +/grub-core/*.module.exe +/grub-core/*.pp +/grub-core/Makefile.core.am +/grub-core/Makefile.gcry.def +/grub-core/bootinfo.txt +/grub-core/build-grub-module-verifier +/grub-core/build-grub-pe2elf.exe +/grub-core/contrib +/grub-core/gdb_grub +/grub-core/genmod.sh +/grub-core/gensyminfo.sh +/grub-core/gentrigtables +/grub-core/gentrigtables.exe +/grub-core/gmodule.pl +/grub-core/grub.chrp +/grub-core/kernel.img.bin +/grub-core/lib/gnulib +/grub-core/lib/libgcrypt-grub +/grub-core/modinfo.sh +/grub-core/rs_decoder.h +/grub-core/symlist.c +/grub-core/symlist.h +/grub-core/trigtables.c +/grub-core/unidata.c +/grub-editenv +/grub-editenv.exe +/grub-file +/grub-file.exe +/grub-fs-tester +/grub-fstest +/grub-fstest.exe +/grub-glue-efi +/grub-glue-efi.exe +/grub-install +/grub-install.exe +/grub-kbdcomp +/grub-macbless +/grub-macbless.exe +/grub-menulst2cfg +/grub-menulst2cfg.exe +/grub-mk* +/grub-mount +/grub-ofpathname +/grub-ofpathname.exe +/grub-probe +/grub-probe.exe +/grub-reboot +/grub-render-label +/grub-render-label.exe +/grub-script-check +/grub-script-check.exe +/grub-set-default +/grub-shell +/grub-shell-tester +/grub-sparc64-setup +/grub-sparc64-setup.exe +/grub-syslinux2cfg +/grub-syslinux2cfg.exe +/grub_cmd_date +/grub_cmd_echo +/grub_cmd_regexp +/grub_cmd_set_date +/grub_cmd_sleep +/grub_cmd_test +/grub_cmd_tr +/grub_fstest_init.c +/grub_fstest_init.h +/grub_func_test +/grub_script_blanklines +/grub_script_blockarg +/grub_script_break +/grub_script_comments +/grub_script_continue +/grub_script_dollar +/grub_script_echo1 +/grub_script_echo_keywords +/grub_script_escape_comma +/grub_script_eval +/grub_script_expansion +/grub_script_final_semicolon +/grub_script_for1 +/grub_script_functions +/grub_script_gettext +/grub_script_if +/grub_script_leading_whitespace +/grub_script_no_commands +/grub_script_not +/grub_script_return +/grub_script_setparams +/grub_script_shift +/grub_script_strcmp +/grub_script_test +/grub_script_vars1 +/grub_script_while1 +/gzcompress_test +/hddboot_test +/help_test +/hfs_test +/hfsplus_test +/include/grub/cpu +/include/grub/gcrypt/g10lib.h +/include/grub/gcrypt/gcrypt.h +/include/grub/machine +/install-sh +/iso9660_test +/jfs_test +/lib/libgcrypt-grub +/libgrub_a_init.c +/lzocompress_test +/m4/ +/minixfs_test +/missing +/netboot_test +/nilfs2_test +/ntfs_test +/ohci_test +/partmap_test +/pata_test +/po/*.gmo +/po/*.mo +/po/*.po +/po/LINGUAS +/po/Makefile.in.in +/po/Makevars +/po/Makevars.template +/po/POTFILES +/po/POTFILES-shell.in +/po/POTFILES.in +/po/Rules-quot +/po/grub.pot +/po/remove-potcdate.sed +/po/stamp-po +/printf_test +/priority_queue_unit_test +/pseries_test +/reiserfs_test +/romfs_test +/squashfs_test +/stamp-h +/stamp-h.in +/stamp-h1 +/syslinux_test +/tar_test +/test_sha512sum +/test_unset +/tests/syslinux/ubuntu10.04_grub.cfg +/texinfo.tex +/udf_test +/uhci_test +/util/bash-completion.d/grub +/widthspec.h +/xfs_test +/xzcompress_test +/zfs_test diff --git a/SOURCES/grub.macros b/SOURCES/grub.macros new file mode 100644 index 0000000..1f708b2 --- /dev/null +++ b/SOURCES/grub.macros @@ -0,0 +1,739 @@ +# vim:filetype=spec +# Modules always contain just 32-bit code +%global _libdir %{_exec_prefix}/lib +%global _binaries_in_noarch_packages_terminate_build 0 +#%%undefine _missing_build_ids_terminate_build +%{expand:%%{!?buildsubdir:%%global buildsubdir grub-%{tarversion}}} +%{expand:%%{!?_licensedir:%%global license %%%%doc}} + +%global _configure ../configure + +%if %{?_with_ccache: 1}%{?!_with_ccache: 0} +%global ccpath /usr/%{_lib}/ccache/gcc +%else +%global ccpath %{__cc} +%endif + +# gnulib actively ignores CFLAGS because it's terrible +%global cc_equals "CC=%{ccpath} -fPIE -Wl,-z,noexecstack -Wl,--no-warn-rwx-segments" + +%global cflags_sed \\\ + sed \\\ + -e 's/-O. //g' \\\ + -e 's/-fplugin=annobin//g' \\\ + -e 's,-specs=[[:alnum:]/_-]*annobin[[:alnum:]_-]*,,g' \\\ + -e 's/-fstack-protector[[:alpha:]-]\\+//g' \\\ + -e 's/-[^ ]*D_FORTIFY_SOURCE=[[:digit:]][^ ]*\\+//g' \\\ + -e 's/--param=ssp-buffer-size=4//g' \\\ + -e 's/-mregparm=3/-mregparm=4/g' \\\ + -e 's/-fexceptions//g' \\\ + -e 's/-fcf-protection//g' \\\ + -e 's/-fasynchronous-unwind-tables//g' \\\ + -e 's/^/ -fno-strict-aliasing /' \\\ + %{nil} + +%global host_cflags_ %{expand:%%(echo %{build_cflags} %{?_hardening_cflags} | %{cflags_sed})} -fstack-protector-strong +%ifarch x86_64 +%global host_cflags %{host_cflags_} -fcf-protection +%else +%global host_cflags %{host_cflags_} +%endif +%global legacy_host_cflags \\\ + %{expand:%%(echo %{host_cflags} | \\\ + sed \\\ + -e 's/-m64//g' \\\ + -e 's/-mcpu=power[[:alnum:]]\\+/-mcpu=power6/g' \\\ + )} +%global efi_host_cflags %{expand:%%(echo %{host_cflags})} + +%global target_cflags %{expand:%%(echo %{build_cflags} | %{cflags_sed})} +%global legacy_target_cflags \\\ + %{expand:%%(echo %{target_cflags} | \\\ + %{cflags_sed} \\\ + -e 's/-m64//g' \\\ + -e 's/-mcpu=power[[:alnum:]]\\+/-mcpu=power6/g' \\\ + )} +%global efi_target_cflags %{expand:%%(echo %{target_cflags})} + +%global ldflags_sed \\\ + sed \\\ + -e 's,-specs=[[:alnum:]/_-]*annobin[[:alnum:]_-]*,,g' \\\ + -e 's/^$//' \\\ + %{nil} + +%global host_ldflags %{expand:%%(echo %{build_ldflags} %{?_hardening_ldflags} | %{ldflags_sed})} +%global legacy_host_ldflags \\\ + %{expand:%%(echo %{host_ldflags} | \\\ + %{ldflags_sed} \\\ + )} +%global efi_host_ldflags %{expand:%%(echo %{host_ldflags})} + +%global target_ldflags %{expand:%%(echo %{build_ldflags} -Wl,--no-warn-rwx-segments -static | %{ldflags_sed})} +%global legacy_target_ldflags \\\ + %{expand:%%(echo %{target_ldflags} | \\\ + %{ldflags_sed} \\\ + )} +%global efi_target_ldflags %{expand:%%(echo %{target_ldflags})} + +%global with_efi_arch 0 +%global with_alt_efi_arch 0 +%global with_legacy_arch 0 +%global with_emu_arch 1 +%global emuarch %{_arch} +%global grubefiarch %{nil} +%global grublegacyarch %{nil} +%global grubelfname %{nil} + +# sparc is always compiled 64 bit +%ifarch %{sparc} +%global target_cpu_name sparc64 +%global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} +%global legacy_target_cpu_name %{_arch} +%global legacy_package_arch ieee1275 +%global platform ieee1275 +%endif +# ppc is always compiled 64 bit +%ifarch ppc ppc64 ppc64le +# GRUB emu fails to build on ppc64le +%global with_emu_arch 0 +%global target_cpu_name %{_arch} +%global legacy_target_cpu_name powerpc +%global legacy_package_arch %{_arch} +%global legacy_grub_dir powerpc-ieee1275 +%global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} +%global platform ieee1275 +%endif + + +%global efi_only aarch64 %{arm} riscv64 +%global efi_arch x86_64 ia64 %{efi_only} +%ifarch %{efi_arch} +%global with_efi_arch 1 +%else +%global with_efi_arch 0 +%endif +%ifarch %{efi_only} +%global with_efi_only 1 +%else +%global with_efi_only 0 +%endif +%{!?with_efi_arch:%global without_efi_arch 0} +%{?with_efi_arch:%global without_efi_arch 1} +%{!?with_efi_only:%global without_efi_only 0} +%{?with_efi_only:%global without_efi_only 1} + +%ifarch %{efi_arch} +%global efi_modules " efi_netfs efifwsetup efinet lsefi lsefimmap connectefi " +%endif + +%ifarch x86_64 %{ix86} +%global platform_modules " backtrace chain tpm usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug keylayouts at_keyboard " +%endif + +%ifarch ppc64le +%global platform_modules " appendedsig tpm ofnet " +%endif + +%ifarch aarch64 %{arm} riscv64 +%global platform_modules " " +%endif + +%ifarch aarch64 %{arm} riscv64 +%global legacy_provides -l +%endif + +%ifarch %{ix86} +%global efiarch ia32 +%global target_cpu_name i386 +%global grub_target_name i386-efi +%global package_arch efi-ia32 + +%global legacy_target_cpu_name i386 +%global legacy_package_arch pc +%global platform pc +%endif + +%ifarch x86_64 +%global efiarch x64 +%global target_cpu_name %{_arch} +%global grub_target_name %{_arch}-efi +%global package_arch efi-x64 + +%global legacy_target_cpu_name i386 +%global legacy_package_arch pc +%global platform pc + +%global alt_efi_arch ia32 +%global alt_target_cpu_name i386 +%global alt_grub_target_name i386-efi +%global alt_platform efi +%global alt_package_arch efi-ia32 + +%global alt_efi_host_cflags %{expand:%%(echo %{efi_host_cflags})} +%global alt_efi_target_cflags \\\ + %{expand:%%(echo %{target_cflags} | \\\ + %{cflags_sed} \\\ + -e 's/-m64//g' \\\ + )} +%endif + +%ifarch aarch64 +%global emuarch arm64 +%global efiarch aa64 +%global target_cpu_name aarch64 +%global grub_target_name arm64-efi +%global package_arch efi-aa64 +%endif + +%ifarch riscv64 +%global emuarch riscv64 +%global efiarch riscv64 +%global target_cpu_name riscv64 +%global grub_target_name riscv64-efi +%global package_arch efi-riscv64 +%endif + +%ifarch %{arm} +%global efiarch arm +%global target_cpu_name arm +%global grub_target_name arm-efi +%global package_arch efi-arm +%global efi_target_cflags \\\ + %{expand:%%(echo %{optflags} | \\\ + %{cflags_sed} \\\ + -e 's/-march=armv7-a[[:alnum:]+-]*/&+nofp/g' \\\ + -e 's/-mfpu=[[:alnum:]-]\\+//g' \\\ + -e 's/-mfloat-abi=[[:alpha:]]\\+/-mfloat-abi=soft/g' \\\ + )} +%endif + +%global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} +%global _alt_target_platform %{alt_target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} + +%ifarch %{efi_arch} +%global with_efi_arch 1 +%global grubefiname grub%{efiarch}.efi +%global grubeficdname gcd%{efiarch}.efi +%global grubefiarch %{target_cpu_name}-efi +%ifarch %{ix86} +%global with_efi_modules 0 +%global without_efi_modules 1 +%else +%global with_efi_modules 1 +%global without_efi_modules 0 +%endif +%endif + +%if 0%{?alt_efi_arch:1} +%global with_alt_efi_arch 1 +%global grubaltefiname grub%{alt_efi_arch}.efi +%global grubalteficdname gcd%{alt_efi_arch}.efi +%global grubaltefiarch %{alt_target_cpu_name}-efi +%endif + +%ifnarch %{efi_only} +%global with_legacy_arch 1 +%global grublegacyarch %{legacy_target_cpu_name}-%{platform} +%global moduledir %{legacy_target_cpu_name}-%{platform} +%global grubelfname core.elf +%endif + +%global evr %{epoch}:%{version}-%{release} + +%ifarch x86_64 +%global with_efi_common 1 +%global with_legacy_modules 1 +%global with_legacy_common 1 +%else +%global with_efi_common 0 +%global with_legacy_common 1 +%global with_legacy_modules 1 +%endif + +%define define_legacy_variant() \ +%{expand:%%package %%{1}} \ +Summary: Bootloader with support for Linux, Multiboot, and more \ +Provides: grub2 = %{evr} \ +Obsoletes: grub2 < %{evr} \ +Requires: grub2-common = %{evr} \ +Requires: grub2-tools-minimal = %{evr} \ +Requires: grub2-%{1}-modules = %{evr} \ +Requires: gettext-runtime which file \ +Requires: grub2-tools = %{evr} \ +Requires(pre): dracut \ +Requires(post): dracut \ +%{expand:%%description %%{1}} \ +%{desc} \ +This subpackage provides support for %{1} systems. \ + \ +%{expand:%%{?!buildsubdir:%%define buildsubdir grub-%%{1}-%{tarversion}}}\ +%{expand:%%if 0%%{with_legacy_modules} \ +%%package %%{1}-modules \ +Summary: Modules used to build custom grub images \ +BuildArch: noarch \ +Requires: grub2-common = %%{evr} \ +%%description %%{1}-modules \ +%%{desc} \ +This subpackage provides support for rebuilding your own grub.efi. \ +%%endif \ +} \ + \ +%{expand:%%{?!buildsubdir:%%define buildsubdir grub-%%{1}-%{tarversion}}}\ +%{expand:%%package %%{1}-tools} \ +Summary: Support tools for GRUB. \ +Requires: gettext-runtime os-prober which file system-logos \ +Requires: grub2-common = %{evr} \ +Requires: grub2-tools-minimal = %{evr} \ +Requires: os-prober >= 1.58-11 \ + \ +%{expand:%%description %%{1}-tools} \ +%{desc} \ +This subpackage provides tools for support of %%{1} platforms. \ +%{nil} + +%define define_efi_variant(o) \ +%{expand:%%package %{1}} \ +Summary: GRUB for EFI systems. \ +Requires: efi-filesystem \ +Requires: grub2-common = %{evr} \ +Requires: grub2-tools-minimal >= %{evr} \ +Requires: grub2-tools = %{evr} \ +Provides: grub2-efi = %{evr} \ +%{?legacy_provides:Provides: grub2 = %{evr}} \ +%{-o:Obsoletes: grub2-efi < %{evr}} \ + \ +%{expand:%%description %{1}} \ +%{desc} \ +This subpackage provides support for %{1} systems. \ + \ +%{expand:%%{?!buildsubdir:%%define buildsubdir grub-%{1}-%{tarversion}}}\ +%{expand:%if 0%{?with_efi_modules} \ +%{expand:%%package %{1}-modules} \ +Summary: Modules used to build custom grub.efi images \ +BuildArch: noarch \ +Requires: grub2-common = %{evr} \ +Provides: grub2-efi-modules = %{evr} \ +Obsoletes: grub2-efi-modules < %{evr} \ +%{expand:%%description %{1}-modules} \ +%{desc} \ +This subpackage provides support for rebuilding your own grub.efi. \ +%endif} \ + \ +%{expand:%%package %{1}-cdboot} \ +Summary: Files used to boot removeable media with EFI \ +Requires: grub2-common = %{evr} \ +Provides: grub2-efi-cdboot = %{evr} \ +%{expand:%%description %{1}-cdboot} \ +%{desc} \ +This subpackage provides optional components of grub used with removeable media on %{1} systems.\ +%{nil} + +%global do_common_setup() \ +%setup -q -n grub-%{tarversion} \ +rm -fv docs/*.info \ +cp %{SOURCE6} .gitignore \ +cp %{SOURCE7} bootstrap \ +cp %{SOURCE8} bootstrap.conf \ +cp %{SOURCE9} ./grub-core/tests/strtoull_test.c \ +cp %{SOURCE2} gnulib-%{gnulibversion}.tar.gz \ +tar -zxf gnulib-%{gnulibversion}.tar.gz \ +mv gnulib-%{gnulibversion} gnulib \ +git init \ +echo '![[:digit:]][[:digit:]]_*.in' > util/grub.d/.gitignore \ +echo '!*.[[:digit:]]' > util/.gitignore \ +echo '!config.h' > include/grub/emu/.gitignore \ +git config user.email "grub2-owner@fedoraproject.org" \ +git config user.name "Fedora Ninjas" \ +git config gc.auto 0 \ +rm -f configure \ +git add . \ +git commit -a -q -m "%{tarversion} baseline." \ +git am --whitespace=nowarn %%{patches} %{1}.conf \ +install -d -m 755 ${RPM_BUILD_ROOT}/etc/dnf/protected.d/ \ +install -m 644 %{1}.conf ${RPM_BUILD_ROOT}/etc/dnf/protected.d/ \ +rm -f %{1}.conf \ +%{nil} + +%global grub_modules " all_video boot blscfg \\\ + cat configfile cryptodisk \\\ + echo ext2 f2fs fat font \\\ + gcry_rijndael gcry_rsa gcry_serpent \\\ + gcry_sha256 gcry_twofish gcry_whirlpool \\\ + gfxmenu gfxterm gzio \\\ + halt hfsplus http increment iso9660 \\\ + jpeg loadenv loopback linux lvm luks \\\ + luks2 \\\ + memdisk \\\ + mdraid09 mdraid1x minicmd net \\\ + normal part_apple part_msdos part_gpt \\\ + password_pbkdf2 pgp png reboot regexp \\\ + search search_fs_uuid search_fs_file \\\ + search_label serial sleep \\\ + squash4 \\\ + syslinuxcfg \\\ + test tftp version video xfs zstd " \ + +%ifarch %{efi_arch} +%define efi_mkimage() \ +mkdir -p memdisk/fonts \ +cp %{4}/unicode.pf2 memdisk/fonts \ +mksquashfs memdisk memdisk.squashfs -comp lzo \ +%{4}./grub-mkimage -O %{1} -o %{2}.orig \\\ + -d grub-core \\\ + --sbat %{4}./sbat.csv \\\ + -m memdisk.squashfs \\\ + -p /EFI/%{efi_vendor} \\\ + ${GRUB_MODULES} \ +%{4}./grub-mkimage -O %{1} -o %{3}.orig \\\ + -d grub-core \\\ + --sbat %{4}./sbat.csv \\\ + -m memdisk.squashfs \\\ + -p /EFI/BOOT \\\ + ${GRUB_MODULES} \ +%{expand:%%define ___pesign_client_cert %{?___pesign_client_cert}%{!?___pesign_client_cert:%{__pesign_client_cert}}} \ +%{?__pesign_client_cert:%{expand:%%define __pesign_client_cert %{___pesign_client_cert}}} \ +%{expand:%%{pesign -s -i %%{2}.orig -o %%{2} -a %%{5} -c %%{6} -n %%{7}}} \ +%{expand:%%{pesign -s -i %%{3}.orig -o %%{3} -a %%{5} -c %%{6} -n %%{7}}} \ +%{nil} +%endif + +%ifarch ppc64le +# RHEL signs, Fedora + ELN don't (but ELN defines rhel) +%if 0%{?fedora} || 0%{?eln} +%define ieee1275_mkimage() \ +mkdir -p memdisk/fonts \ +cp %{5}/unicode.pf2 memdisk/fonts \ +mksquashfs memdisk memdisk.squashfs -comp lzo \ +./grub-mkimage -O %{1} -o %{2} -p '/grub2' -d grub-core ${GRUB_MODULES} \ +%{nil} +%else +%define ieee1275_mkimage() \ +mkdir -p memdisk/fonts \ +cp %{5}/unicode.pf2 memdisk/fonts \ +mksquashfs memdisk memdisk.squashfs -comp lzo \ +APPENDED_SIG_SIZE=0 \ +if [ -x /usr/bin/rpm-sign ]; then \ + touch empty.unsigned \ + rpm-sign --key %{4} \\\ + --lkmsign empty.unsigned \\\ + --output empty.signed \ + APPENDED_SIG_SIZE="$(stat -c '%s' empty.signed)" \ + rm empty.{un,}signed \ +fi \ +# FIXME: using this prefix is fragile, must be done properly \ +./grub-mkimage -O %{1} -o %{2}.orig \\\ + -d grub-core \\\ + -m memdisk.squashfs \\\ + -p '/grub2' \\\ + -x %{3} \\\ + --appended-signature-size ${APPENDED_SIG_SIZE} \\\ + ${GRUB_MODULES} \ +if [ -x /usr/bin/rpm-sign ]; then \ + truncate -s -${APPENDED_SIG_SIZE} %{2}.orig \ + rpm-sign --key %{4} \\\ + --lkmsign %{2}.orig \\\ + --output %{2} \ +else \ + mv %{2}.orig %{2} \ +fi \ +%{nil} +%endif +%endif + +%define do_efi_build_images() \ +GRUB_MODULES+=%{grub_modules} \ +GRUB_MODULES+=%{efi_modules} \ +GRUB_MODULES+=%{platform_modules} \ +%{expand:%efi_mkimage %%{1} %%{2} %%{3} %%{4} %%{5} %%{6} %%{7}} \ +%{nil} + +%define do_ieee1275_build_images() \ +GRUB_MODULES+=%{grub_modules} \ +GRUB_MODULES+=%{platform_modules} \ +cd grub-%{1}-%{tarversion} \ +%{expand:%%ieee1275_mkimage %%{1} %%{2} %%{3} %%{4} ./ }\ +cd .. \ +%{nil} + +%define do_primary_efi_build() \ +cd grub-%{1}-%{tarversion} \ +%{expand:%%do_efi_configure %%{4} %%{5} %%{6}} \ +%do_efi_build_all \ +%{expand:%%do_efi_build_images %{grub_target_name} %%{2} %%{3} ./ %%{7} %%{8} %%{9}} \ +cd .. \ +%{nil} + +%define do_alt_efi_build() \ +cd grub-%{1}-%{tarversion} \ +%{expand:%%do_efi_configure %%{4} %%{5} %%{6}} \ +%do_efi_build_modules \ +%{expand:%%do_efi_link_utils %{grubefiarch}} \ +%{expand:%%do_efi_build_images %{alt_grub_target_name} %%{2} %%{3} ../grub-%{grubefiarch}-%{tarversion}/ %%{7} %%{8} %%{9}} \ +cd .. \ +%{nil} + +%define do_legacy_build() \ +cd grub-%{1}-%{tarversion} \ +%configure \\\ + %{cc_equals} \\\ + HOST_CFLAGS="%{legacy_host_cflags}" \\\ + HOST_CPPFLAGS="-I$(pwd)" \\\ + HOST_LDFLAGS="%{legacy_host_ldflags}" \\\ + TARGET_CFLAGS="%{legacy_target_cflags}" \\\ + TARGET_CPPFLAGS="-I$(pwd)" \\\ + TARGET_LDFLAGS="%{legacy_target_ldflags}" \\\ + --with-platform=%{platform} \\\ + --with-utils=host \\\ + --target=%{_target_platform} \\\ + --with-grubdir=grub2 \\\ + --program-transform-name=s,grub,grub2, \\\ + --disable-werror || ( cat config.log ; exit 1 ) \ +git add . \ +git commit -m "After legacy configure" \ +make %{?_smp_mflags} \ +cd .. \ +%{nil} + +%define do_emu_build() \ +cd grub-emu-%{tarversion} \ +%configure \\\ + %{cc_equals} \\\ + HOST_CFLAGS="%{legacy_host_cflags}" \\\ + HOST_CPPFLAGS="-I$(pwd)" \\\ + HOST_LDFLAGS="%{legacy_host_ldflags}" \\\ + --with-platform=emu \\\ + --with-grubdir=grub2 \\\ + --program-transform-name=s,grub,grub2, \\\ + --disable-werror || ( cat config.log ; exit 1 ) \ +git add . \ +git commit -m "After emu configure" \ +make %{?_smp_mflags} ascii.h widthspec.h \ +make %{?_smp_mflags} -C grub-core/lib/gnulib \ +make %{?_smp_mflags} -C grub-core \ +cd .. \ +%{nil} + +%define do_alt_efi_install() \ +cd grub-%{1}-%{tarversion} \ +install -d -m 755 $RPM_BUILD_ROOT/usr/lib/grub/%{grubaltefiarch}/ \ +find . '(' -iname gdb_grub \\\ + -o -iname kernel.exec \\\ + -o -iname kernel.img \\\ + -o -iname config.h \\\ + -o -iname gmodule.pl \\\ + -o -iname modinfo.sh \\\ + -o -iname '*.lst' \\\ + -o -iname '*.mod' \\\ + ')' \\\ + -exec cp {} $RPM_BUILD_ROOT/usr/lib/grub/%{grubaltefiarch}/ \\\; \ +find $RPM_BUILD_ROOT -type f -iname "*.mod*" -exec chmod a-x {} '\;' \ +install -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_dir}/%{2} \ +install -m 700 %{3} $RPM_BUILD_ROOT%{efi_esp_dir}/%{3} \ +%{expand:%%do_install_protected_file grub2-%{alt_package_arch}} \ +cd .. \ +%{nil} + +%define do_efi_install() \ +cd grub-%{1}-%{tarversion} \ +make DESTDIR=$RPM_BUILD_ROOT install \ +if [ -f $RPM_BUILD_ROOT%{_infodir}/grub.info ]; then \ + rm -f $RPM_BUILD_ROOT%{_infodir}/grub.info \ +fi \ +if [ -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info ]; then \ + rm -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info \ +fi \ +find $RPM_BUILD_ROOT -iname "*.module" -exec chmod a-x {} '\;' \ +ln -s ../boot/grub2/grub.cfg \\\ + $RPM_BUILD_ROOT%{_sysconfdir}/grub2-efi.cfg \ +install -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_dir}/%{2} \ +install -m 700 %{3} $RPM_BUILD_ROOT%{efi_esp_dir}/%{3} \ +%ifarch %{arm} \ +install -D -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_boot}/BOOTARM.EFI \ +%endif \ +install -D -m 700 unicode.pf2 \\\ + ${RPM_BUILD_ROOT}/boot/grub2/fonts/unicode.pf2 \ +${RPM_BUILD_ROOT}/%{_bindir}/grub2-editenv \\\ + ${RPM_BUILD_ROOT}/boot/grub2/grubenv create \ +%{expand:%%do_install_protected_file grub2-%{package_arch}} \ +cd .. \ +%{nil} + +%define do_legacy_install() \ +cd grub-%{1}-%{tarversion} \ +make DESTDIR=$RPM_BUILD_ROOT install \ +if [ -f $RPM_BUILD_ROOT%{_infodir}/grub.info ]; then \ + rm -f $RPM_BUILD_ROOT%{_infodir}/grub.info \ +fi \ +if [ -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info ]; then \ + rm -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info \ +fi \ +%{expand:%ifarch ppc64le \ + install -m 700 %{grubelfname} $RPM_BUILD_ROOT/%{_libdir}/grub/%{1} \ +%endif} \ +if [ -f $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub2.chrp ]; then \ + mv $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub2.chrp \\\ + $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub.chrp \ +fi \ +if [ %{3} -eq 0 ]; then \ + ${RPM_BUILD_ROOT}/%{_bindir}/grub2-editenv \\\ + ${RPM_BUILD_ROOT}/boot/grub2/grubenv create \ +fi \ +%{expand:%ifnarch ppc64le \ +mkdir pxe \ +./grub-mknetdir \\\ + --directory ./grub-core \\\ + --fonts="" \\\ + --locales="" \\\ + --themes="" \\\ + --modules="configfile gzio linux reboot test" \\\ + --net-directory=pxe \\\ + --subdir . \ +mv pxe/*/core.0 $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/ \ +%endif} \ +%{expand:%%do_install_protected_file grub2-%{legacy_package_arch}} \ +cd .. \ +%{nil} + +%define do_emu_install() \ +cd grub-emu-%{tarversion} \ +make DESTDIR=$RPM_BUILD_ROOT install -C grub-core \ +if [ -f $RPM_BUILD_ROOT%{_infodir}/grub.info ]; then \ + rm -f $RPM_BUILD_ROOT%{_infodir}/grub.info \ +fi \ +if [ -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info ]; then \ + rm -f $RPM_BUILD_ROOT%{_infodir}/grub-dev.info \ +fi \ +if [ -f $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub2.chrp ]; then \ + mv $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub2.chrp \\\ + $RPM_BUILD_ROOT/%{_libdir}/grub/%{1}/grub.chrp \ +fi \ +cd .. \ +%{nil} + +%define do_common_install() \ +install -d -m 0755 \\\ + $RPM_BUILD_ROOT%{_datarootdir}/locale/en\@quot \\\ + $RPM_BUILD_ROOT%{_datarootdir}/locale/en \\\ + $RPM_BUILD_ROOT%{_infodir}/ \ +cp -a $RPM_BUILD_ROOT%{_datarootdir}/locale/en\@quot \\\ + $RPM_BUILD_ROOT%{_datarootdir}/locale/en \ +cp docs/grub.info $RPM_BUILD_ROOT%{_infodir}/grub2.info \ +cp docs/grub-dev.info \\\ + $RPM_BUILD_ROOT%{_infodir}/grub2-dev.info \ +install -d -m 0700 ${RPM_BUILD_ROOT}%{efi_esp_dir}/ \ +install -d -m 0700 ${RPM_BUILD_ROOT}/boot/grub2/ \ +install -d -m 0700 ${RPM_BUILD_ROOT}/boot/loader/entries \ +install -d -m 0700 ${RPM_BUILD_ROOT}/boot/grub2/themes/system \ +install -d -m 0700 ${RPM_BUILD_ROOT}%{_sysconfdir}/default \ +install -d -m 0700 ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig \ +touch ${RPM_BUILD_ROOT}%{_sysconfdir}/default/grub \ +ln -sf ../default/grub \\\ + ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/grub \ +touch ${RPM_BUILD_ROOT}/boot/grub2/grub.cfg \ +ln -s ../boot/grub2/grub.cfg \\\ + ${RPM_BUILD_ROOT}%{_sysconfdir}/grub2.cfg \ +%{nil} + +%define define_legacy_variant_files() \ +%{expand:%%files %{1}} \ +%defattr(-,root,root,-) \ +%config(noreplace) %{_sysconfdir}/grub2.cfg \ +%ghost %config(noreplace) %attr(0700,root,root)/boot/grub2/grub.cfg \ +%dir %attr(0700,root,root)/boot/loader/entries \ +%attr(0644,root,root) %config(noreplace) /etc/dnf/protected.d/grub2-%{1}.conf \ +%ifarch ppc64le \ +%dir %{_libdir}/grub/%{2}/ \ +%{_libdir}/grub/%{2}/%{grubelfname} \ +%endif \ + \ +%{expand:%if 0%{?with_legacy_modules} \ +%{expand:%%files %{1}-modules} \ +%defattr(-,root,root) \ +%dir %{_libdir}/grub/%{2}/ \ +%{_libdir}/grub/%{2}/* \ +%ifarch ppc64le \ +%exclude %{_libdir}/grub/%{2}/%{grubelfname} \ +%endif \ +%exclude %{_libdir}/grub/%{2}/*.module \ +%exclude %{_libdir}/grub/%{2}/{boot,boot_hybrid,cdboot,diskboot,lzma_decompress,pxeboot}.image \ +%exclude %{_libdir}/grub/%{2}/*.o \ +%else \ +%%exclude %%{_libdir}/grub/%%{grublegacyarch}/* \ +%endif} \ +%{nil} + +%define define_efi_variant_files() \ +%{expand:%%files %{1}} \ +%defattr(-,root,root,-) \ +%config(noreplace) %{_sysconfdir}/grub2.cfg \ +%config(noreplace) %{_sysconfdir}/grub2-efi.cfg \ +%attr(0700,root,root) %verify(not mtime) %{efi_esp_dir}/%{2} \ +%ifarch %{arm} \ +%attr(0700,root,root) %verify(not mtime) %{efi_esp_boot}/BOOTARM.EFI \ +%endif \ +%attr(0700,root,root)/boot/grub2/fonts \ +%dir %attr(0700,root,root)/boot/loader/entries \ +%ghost %config(noreplace) %attr(0700,root,root)/boot/grub2/grub.cfg \ +%ghost %config(noreplace) %verify(not mtime) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg \ +%config(noreplace) %verify(not size mode md5 mtime) /boot/grub2/grubenv \ +%attr(0644,root,root) %config(noreplace) /etc/dnf/protected.d/grub2-%{1}.conf \ +%{expand:%if 0%{?without_efi_modules} \ +%exclude %{_libdir}/grub/%{6} \ +%exclude %{_libdir}/grub/%{6}/* \ +%endif} \ + \ +%{expand:%if 0%{?with_efi_modules} \ +%{expand:%%files %{1}-modules} \ +%defattr(-,root,root,-) \ +%dir %{_libdir}/grub/%{6}/ \ +%{_libdir}/grub/%{6}/* \ +%exclude %{_libdir}/grub/%{6}/*.module \ +%endif} \ + \ +%{expand:%%files %{1}-cdboot} \ +%defattr(-,root,root,-) \ +%attr(0700,root,root) %verify(not mtime) %{efi_esp_dir}/%{3} \ +%attr(0700,root,root)/boot/grub2/fonts \ +%{nil} diff --git a/SOURCES/grub.patches b/SOURCES/grub.patches new file mode 100644 index 0000000..0da3904 --- /dev/null +++ b/SOURCES/grub.patches @@ -0,0 +1,366 @@ +Patch0001: 0001-Revert-templates-Fix-user-facing-typo-with-an-incorr.patch +Patch0002: 0002-Revert-templates-Properly-disable-the-os-prober-by-d.patch +Patch0003: 0003-Revert-templates-Disable-the-os-prober-by-default.patch +Patch0004: 0004-Add-support-for-Linux-EFI-stub-loading.patch +Patch0005: 0005-Rework-linux-command.patch +Patch0006: 0006-Rework-linux16-command.patch +Patch0007: 0007-Add-secureboot-support-on-efi-chainloader.patch +Patch0008: 0008-Make-any-of-the-loaders-that-link-in-efi-mode-honor-.patch +Patch0009: 0009-Handle-multi-arch-64-on-32-boot-in-linuxefi-loader.patch +Patch0010: 0010-re-write-.gitignore.patch +Patch0011: 0011-IBM-client-architecture-CAS-reboot-support.patch +Patch0012: 0012-for-ppc-reset-console-display-attr-when-clear-screen.patch +Patch0013: 0013-Disable-GRUB-video-support-for-IBM-power-machines.patch +Patch0014: 0014-Move-bash-completion-script-922997.patch +Patch0015: 0015-Allow-fallback-to-include-entries-by-title-not-just-.patch +Patch0016: 0016-Make-exit-take-a-return-code.patch +Patch0017: 0017-Make-efi-machines-load-an-env-block-from-a-variable.patch +Patch0018: 0018-Migrate-PPC-from-Yaboot-to-Grub2.patch +Patch0019: 0019-Add-fw_path-variable-revised.patch +Patch0020: 0020-Pass-x-hex-hex-straight-through-unmolested.patch +Patch0021: 0021-blscfg-add-blscfg-module-to-parse-Boot-Loader-Specif.patch +Patch0022: 0022-Add-devicetree-loading.patch +Patch0023: 0023-Enable-pager-by-default.-985860.patch +Patch0024: 0024-Don-t-say-GNU-Linux-in-generated-menus.patch +Patch0025: 0025-Add-.eh_frame-to-list-of-relocations-stripped.patch +Patch0026: 0026-Don-t-require-a-password-to-boot-entries-generated-b.patch +Patch0027: 0027-use-fw_path-prefix-when-fallback-searching-for-grub-.patch +Patch0028: 0028-Try-mac-guid-etc-before-grub.cfg-on-tftp-config-file.patch +Patch0029: 0029-Generate-OS-and-CLASS-in-10_linux-from-etc-os-releas.patch +Patch0030: 0030-Minimize-the-sort-ordering-for-.debug-and-rescue-ker.patch +Patch0031: 0031-Try-prefix-if-fw_path-doesn-t-work.patch +Patch0032: 0032-Make-grub2-mkconfig-construct-titles-that-look-like-.patch +Patch0033: 0033-Add-friendly-grub2-password-config-tool-985962.patch +Patch0034: 0034-tcp-add-window-scaling-support.patch +Patch0035: 0035-efinet-and-bootp-add-support-for-dhcpv6.patch +Patch0036: 0036-Add-grub-get-kernel-settings-and-use-it-in-10_linux.patch +Patch0037: 0037-bz1374141-fix-incorrect-mask-for-ppc64.patch +Patch0038: 0038-Make-grub_fatal-also-backtrace.patch +Patch0039: 0039-Make-our-info-pages-say-grub2-where-appropriate.patch +Patch0040: 0040-macos-just-build-chainloader-entries-don-t-try-any-x.patch +Patch0041: 0041-grub2-btrfs-Add-ability-to-boot-from-subvolumes.patch +Patch0042: 0042-export-btrfs_subvol-and-btrfs_subvolid.patch +Patch0043: 0043-grub2-btrfs-03-follow_default.patch +Patch0044: 0044-grub2-btrfs-04-grub2-install.patch +Patch0045: 0045-grub2-btrfs-05-grub2-mkconfig.patch +Patch0046: 0046-grub2-btrfs-06-subvol-mount.patch +Patch0047: 0047-Fallback-to-old-subvol-name-scheme-to-support-old-sn.patch +Patch0048: 0048-Grub-not-working-correctly-with-btrfs-snapshots-bsc-.patch +Patch0049: 0049-Add-grub_efi_allocate_pool-and-grub_efi_free_pool-wr.patch +Patch0050: 0050-Use-grub_efi_.-memory-helpers-where-reasonable.patch +Patch0051: 0051-Add-PRIxGRUB_EFI_STATUS-and-use-it.patch +Patch0052: 0052-don-t-use-int-for-efi-status.patch +Patch0053: 0053-make-GRUB_MOD_INIT-declare-its-function-prototypes.patch +Patch0054: 0054-Don-t-guess-boot-efi-as-HFS-on-ppc-machines-in-grub-.patch +Patch0055: 0055-20_linux_xen-load-xen-or-multiboot-2-modules-as-need.patch +Patch0056: 0056-Make-pmtimer-tsc-calibration-not-take-51-seconds-to-.patch +Patch0057: 0057-align-struct-efi_variable-better.patch +Patch0058: 0058-Add-BLS-support-to-grub-mkconfig.patch +Patch0059: 0059-Don-t-attempt-to-backtrace-on-grub_abort-for-grub-em.patch +Patch0060: 0060-Add-grub2-switch-to-blscfg.patch +Patch0061: 0061-make-better-backtraces.patch +Patch0062: 0062-normal-don-t-draw-our-startup-message-if-debug-is-se.patch +Patch0063: 0063-Work-around-some-minor-include-path-weirdnesses.patch +Patch0064: 0064-Make-it-possible-to-enabled-build-id-sha1.patch +Patch0065: 0065-Add-grub_qdprintf-grub_dprintf-without-the-file-line.patch +Patch0066: 0066-Make-a-gdb-dprintf-that-tells-us-load-addresses.patch +Patch0067: 0067-Fixup-for-newer-compiler.patch +Patch0068: 0068-Don-t-attempt-to-export-the-start-and-_start-symbols.patch +Patch0069: 0069-Fixup-for-newer-compiler.patch +Patch0070: 0070-Add-support-for-non-Ethernet-network-cards.patch +Patch0071: 0071-net-read-bracketed-ipv6-addrs-and-port-numbers.patch +Patch0072: 0072-bootp-New-net_bootp6-command.patch +Patch0073: 0073-efinet-UEFI-IPv6-PXE-support.patch +Patch0074: 0074-grub.texi-Add-net_bootp6-doument.patch +Patch0075: 0075-bootp-Add-processing-DHCPACK-packet-from-HTTP-Boot.patch +Patch0076: 0076-efinet-Setting-network-from-UEFI-device-path.patch +Patch0077: 0077-efinet-Setting-DNS-server-from-UEFI-protocol.patch +Patch0078: 0078-Support-UEFI-networking-protocols.patch +Patch0079: 0079-AUDIT-0-http-boot-tracker-bug.patch +Patch0080: 0080-grub-editenv-Add-incr-command-to-increment-integer-v.patch +Patch0081: 0081-Add-auto-hide-menu-support.patch +Patch0082: 0082-Add-grub-set-bootflag-utility.patch +Patch0083: 0083-docs-Add-grub-boot-indeterminate.service-example.patch +Patch0084: 0084-gentpl-add-disable-support.patch +Patch0085: 0085-gentpl-add-pc-firmware-type.patch +Patch0086: 0086-efinet-also-use-the-firmware-acceleration-for-http.patch +Patch0087: 0087-efi-http-Make-root_url-reflect-the-protocol-hostname.patch +Patch0088: 0088-Make-it-so-we-can-tell-configure-which-cflags-utils-.patch +Patch0089: 0089-module-verifier-make-it-possible-to-run-checkers-on-.patch +Patch0090: 0090-Rework-how-the-fdt-command-builds.patch +Patch0091: 0091-Disable-non-wordsize-allocations-on-arm.patch +Patch0092: 0092-Prepend-prefix-when-HTTP-path-is-relative.patch +Patch0093: 0093-Make-grub_error-more-verbose.patch +Patch0094: 0094-Make-reset-an-alias-for-the-reboot-command.patch +Patch0095: 0095-Add-a-version-command.patch +Patch0096: 0096-Add-more-dprintf-and-nerf-dprintf-in-script.c.patch +Patch0097: 0097-arm-arm64-loader-Better-memory-allocation-and-error-.patch +Patch0098: 0098-Try-to-pick-better-locations-for-kernel-and-initrd.patch +Patch0099: 0099-Attempt-to-fix-up-all-the-places-Wsign-compare-error.patch +Patch0100: 0100-Don-t-use-Wno-sign-compare-Wno-conversion-Wno-error-.patch +Patch0101: 0101-x86-efi-Use-bounce-buffers-for-reading-to-addresses-.patch +Patch0102: 0102-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch +Patch0103: 0103-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch +Patch0104: 0104-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch +Patch0105: 0105-Fix-getroot.c-s-trampolines.patch +Patch0106: 0106-Do-not-allow-stack-trampolines-anywhere.patch +Patch0107: 0107-Reimplement-boot_counter.patch +Patch0108: 0108-Fix-menu-entry-selection-based-on-ID-and-title.patch +Patch0109: 0109-Make-the-menu-entry-users-option-argument-to-be-opti.patch +Patch0110: 0110-Add-efi-export-env-and-efi-load-env-commands.patch +Patch0111: 0111-Make-it-possible-to-subtract-conditions-from-debug.patch +Patch0112: 0112-Export-all-variables-from-the-initial-context-when-c.patch +Patch0113: 0113-grub.d-Split-out-boot-success-reset-from-menu-auto-h.patch +Patch0114: 0114-Don-t-assume-that-boot-commands-will-only-return-on-.patch +Patch0115: 0115-grub-set-bootflag-Update-comment-about-running-as-ro.patch +Patch0116: 0116-grub-set-bootflag-Write-new-env-to-tmpfile-and-then-.patch +Patch0117: 0117-grub.d-Fix-boot_indeterminate-getting-set-on-boot_su.patch +Patch0118: 0118-Add-start-symbol-for-RISC-V.patch +Patch0119: 0119-bootstrap.conf-Force-autogen.sh-to-use-python3.patch +Patch0120: 0120-efi-http-Export-fw-http-_path-variables-to-make-them.patch +Patch0121: 0121-efi-http-Enclose-literal-IPv6-addresses-in-square-br.patch +Patch0122: 0122-efi-net-Allow-to-specify-a-port-number-in-addresses.patch +Patch0123: 0123-efi-ip4_config-Improve-check-to-detect-literal-IPv6-.patch +Patch0124: 0124-efi-net-Print-a-debug-message-if-parsing-the-address.patch +Patch0125: 0125-kern-term-Also-accept-F8-as-a-user-interrupt-key.patch +Patch0126: 0126-efi-Set-image-base-address-before-jumping-to-the-PE-.patch +Patch0127: 0127-tpm-Don-t-propagate-TPM-measurement-errors-to-the-ve.patch +Patch0128: 0128-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch +Patch0129: 0129-http-Prepend-prefix-when-the-HTTP-path-is-relative-a.patch +Patch0130: 0130-Fix-a-missing-return-in-efi-export-env-and-efi-load-.patch +Patch0131: 0131-efi-dhcp-fix-some-allocation-error-checking.patch +Patch0132: 0132-efi-http-fix-some-allocation-error-checking.patch +Patch0133: 0133-efi-ip-46-_config.c-fix-some-potential-allocation-ov.patch +Patch0134: 0134-efilinux-Fix-integer-overflows-in-grub_cmd_initrd.patch +Patch0135: 0135-linuxefi-fail-kernel-validation-without-shim-protoco.patch +Patch0136: 0136-Fix-const-char-pointers-in-grub-core-net-bootp.c.patch +Patch0137: 0137-Fix-const-char-pointers-in-grub-core-net-efi-ip4_con.patch +Patch0138: 0138-Fix-const-char-pointers-in-grub-core-net-efi-ip6_con.patch +Patch0139: 0139-Fix-const-char-pointers-in-grub-core-net-efi-net.c.patch +Patch0140: 0140-Fix-const-char-pointers-in-grub-core-net-efi-pxe.c.patch +Patch0141: 0141-Add-systemd-integration-scripts-to-make-systemctl-re.patch +Patch0142: 0142-systemd-integration.sh-Also-set-old-menu_show_once-g.patch +Patch0143: 0143-at_keyboard-use-set-1-when-keyboard-is-in-Translate-.patch +Patch0144: 0144-grub-install-disable-support-for-EFI-platforms.patch +Patch0145: 0145-New-with-debug-timestamps-configure-flag-to-prepend-.patch +Patch0146: 0146-Added-debug-statements-to-grub_disk_open-and-grub_di.patch +Patch0147: 0147-Introduce-function-grub_debug_is_enabled-void-return.patch +Patch0148: 0148-Don-t-clear-screen-when-debugging-is-enabled.patch +Patch0149: 0149-kern-file-Fix-error-handling-in-grub_file_open.patch +Patch0150: 0150-grub_file_-instrumentation-new-file-debug-tag.patch +Patch0151: 0151-ieee1275-Avoiding-many-unecessary-open-close.patch +Patch0152: 0152-ieee1275-powerpc-implements-fibre-channel-discovery-.patch +Patch0153: 0153-ieee1275-powerpc-enables-device-mapper-discovery.patch +Patch0154: 0154-Add-at_keyboard_fallback_set-var-to-force-the-set-ma.patch +Patch0155: 0155-Add-suport-for-signing-grub-with-an-appended-signatu.patch +Patch0156: 0156-docs-grub-Document-signing-grub-under-UEFI.patch +Patch0157: 0157-docs-grub-Document-signing-grub-with-an-appended-sig.patch +Patch0158: 0158-dl-provide-a-fake-grub_dl_set_persistent-for-the-emu.patch +Patch0159: 0159-pgp-factor-out-rsa_pad.patch +Patch0160: 0160-crypto-move-storage-for-grub_crypto_pk_-to-crypto.c.patch +Patch0161: 0161-posix_wrap-tweaks-in-preparation-for-libtasn1.patch +Patch0162: 0162-libtasn1-import-libtasn1-4.16.0.patch +Patch0163: 0163-libtasn1-disable-code-not-needed-in-grub.patch +Patch0164: 0164-libtasn1-changes-for-grub-compatibility.patch +Patch0165: 0165-libtasn1-compile-into-asn1-module.patch +Patch0166: 0166-test_asn1-test-module-for-libtasn1.patch +Patch0167: 0167-grub-install-support-embedding-x509-certificates.patch +Patch0168: 0168-appended-signatures-import-GNUTLS-s-ASN.1-descriptio.patch +Patch0169: 0169-appended-signatures-parse-PKCS-7-signedData-and-X.50.patch +Patch0170: 0170-appended-signatures-support-verifying-appended-signa.patch +Patch0171: 0171-appended-signatures-verification-tests.patch +Patch0172: 0172-appended-signatures-documentation.patch +Patch0173: 0173-ieee1275-enter-lockdown-based-on-ibm-secure-boot.patch +Patch0174: 0174-ieee1275-drop-HEAP_MAX_ADDR-HEAP_MIN_SIZE.patch +Patch0175: 0175-appendedsig-x509-Also-handle-the-Extended-Key-Usage-.patch +Patch0176: 0176-ieee1275-ofdisk-retry-on-open-failure.patch +Patch0177: 0177-Allow-chainloading-EFI-apps-from-loop-mounts.patch +Patch0178: 0178-efinet-Add-DHCP-proxy-support.patch +Patch0179: 0179-fs-ext2-Ignore-checksum-seed-incompat-feature.patch +Patch0180: 0180-Don-t-update-the-cmdline-when-generating-legacy-menu.patch +Patch0181: 0181-Suppress-gettext-error-message.patch +Patch0182: 0182-grub-set-password-Always-use-boot-grub2-user.cfg-as-.patch +Patch0183: 0183-templates-Check-for-EFI-at-runtime-instead-of-config.patch +Patch0184: 0184-efi-Print-an-error-if-boot-to-firmware-setup-is-not-.patch +Patch0185: 0185-arm64-Fix-EFI-loader-kernel-image-allocation.patch +Patch0186: 0186-normal-main-Discover-the-device-to-read-the-config-f.patch +Patch0187: 0187-powerpc-adjust-setting-of-prefix-for-signed-binary-c.patch +Patch0188: 0188-fs-xfs-Fix-unreadable-filesystem-with-v4-superblock.patch +Patch0189: 0189-Print-module-name-on-license-check-failure.patch +Patch0190: 0190-powerpc-ieee1275-load-grub-at-4MB-not-2MB.patch +Patch0191: 0191-grub-mkconfig-restore-umask-for-grub.cfg.patch +Patch0192: 0192-fs-btrfs-Use-full-btrfs-bootloader-area.patch +Patch0193: 0193-Add-Fedora-location-of-DejaVu-SANS-font.patch +Patch0194: 0194-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch +Patch0195: 0195-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch +Patch0196: 0196-EFI-console-Do-not-set-colorstate-until-the-first-te.patch +Patch0197: 0197-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch +Patch0198: 0198-Use-visual-indentation-in-config.h.in.patch +Patch0199: 0199-Where-present-ensure-config-util.h-precedes-config.h.patch +Patch0200: 0200-Drop-gnulib-fix-base64.patch.patch +Patch0201: 0201-Drop-gnulib-no-abort.patch.patch +Patch0202: 0202-Update-gnulib-version-and-drop-most-gnulib-patches.patch +Patch0203: 0203-commands-search-Fix-bug-stopping-iteration-when-no-f.patch +Patch0204: 0204-search-new-efidisk-only-option-on-EFI-systems.patch +Patch0205: 0205-efi-new-connectefi-command.patch +Patch0206: 0206-grub-core-loader-i386-efi-linux.c-do-not-validate-ke.patch +Patch0207: 0207-grub-core-loader-arm64-linux.c-do-not-validate-kerne.patch +Patch0208: 0208-grub-core-loader-efi-chainloader.c-do-not-validate-c.patch +Patch0209: 0209-grub-core-loader-efi-linux.c-drop-now-unused-grub_li.patch +Patch0210: 0210-powerpc-prefix-detection-support-device-names-with-c.patch +Patch0211: 0211-make-ofdisk_retries-optional.patch +Patch0212: 0212-loader-efi-chainloader-grub_load_and_start_image-doe.patch +Patch0213: 0213-loader-efi-chainloader-simplify-the-loader-state.patch +Patch0214: 0214-commands-boot-Add-API-to-pass-context-to-loader.patch +Patch0215: 0215-loader-efi-chainloader-Use-grub_loader_set_ex.patch +Patch0216: 0216-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch +Patch0217: 0217-loader-i386-efi-linux-Use-grub_loader_set_ex.patch +Patch0218: 0218-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch +Patch0219: 0219-kern-efi-sb-Reject-non-kernel-files-in-the-shim_lock.patch +Patch0220: 0220-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch +Patch0221: 0221-video-readers-png-Abort-sooner-if-a-read-operation-f.patch +Patch0222: 0222-video-readers-png-Refuse-to-handle-multiple-image-he.patch +Patch0223: 0223-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +Patch0224: 0224-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch +Patch0225: 0225-video-readers-png-Sanity-check-some-huffman-codes.patch +Patch0226: 0226-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch +Patch0227: 0227-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch +Patch0228: 0228-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +Patch0229: 0229-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch +Patch0230: 0230-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +Patch0231: 0231-net-netbuff-Block-overly-large-netbuff-allocs.patch +Patch0232: 0232-net-ip-Do-IP-fragment-maths-safely.patch +Patch0233: 0233-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch +Patch0234: 0234-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch +Patch0235: 0235-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch +Patch0236: 0236-net-tftp-Avoid-a-trivial-UAF.patch +Patch0237: 0237-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +Patch0238: 0238-net-http-Fix-OOB-write-for-split-http-headers.patch +Patch0239: 0239-net-http-Error-out-on-headers-with-LF-without-CR.patch +Patch0240: 0240-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch +Patch0241: 0241-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch +Patch0242: 0242-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch +Patch0243: 0243-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch +Patch0244: 0244-fs-btrfs-Fix-more-ASAN-and-SEGV-issues-found-with-fu.patch +Patch0245: 0245-fs-btrfs-Fix-more-fuzz-issues-related-to-chunks.patch +Patch0246: 0246-misc-Make-grub_min-and-grub_max-more-resilient.patch +Patch0247: 0247-ReiserFS-switch-to-using-grub_min-grub_max.patch +Patch0248: 0248-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch +Patch0249: 0249-modules-make-.module_license-read-only.patch +Patch0250: 0250-modules-strip-.llvm_addrsig-sections-and-similar.patch +Patch0251: 0251-modules-Don-t-allocate-space-for-non-allocable-secti.patch +Patch0252: 0252-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch +Patch0253: 0253-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch +Patch0254: 0254-modules-load-module-sections-at-page-aligned-address.patch +Patch0255: 0255-nx-add-memory-attribute-get-set-API.patch +Patch0256: 0256-nx-set-page-permissions-for-loaded-modules.patch +Patch0257: 0257-nx-set-attrs-in-our-kernel-loaders.patch +Patch0258: 0258-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch +Patch0259: 0259-grub-probe-document-the-behavior-of-multiple-v.patch +Patch0260: 0260-grub_fs_probe-dprint-errors-from-filesystems.patch +Patch0261: 0261-fs-fat-don-t-error-when-mtime-is-0.patch +Patch0262: 0262-Make-debug-file-show-which-file-filters-get-run.patch +Patch0263: 0263-efi-use-enumerated-array-positions-for-our-allocatio.patch +Patch0264: 0264-efi-split-allocation-policy-for-kernel-vs-initrd-mem.patch +Patch0265: 0265-efi-allocate-the-initrd-within-the-bounds-expressed-.patch +Patch0266: 0266-efi-use-EFI_LOADER_-CODE-DATA-for-kernel-and-initrd-.patch +Patch0267: 0267-BLS-create-etc-kernel-cmdline-during-mkconfig.patch +Patch0268: 0268-squish-don-t-dup-rhgb-quiet-check-mtimes.patch +Patch0269: 0269-squish-give-up-on-rhgb-quiet.patch +Patch0270: 0270-squish-BLS-only-write-etc-kernel-cmdline-if-writable.patch +Patch0271: 0271-blscfg-Don-t-root-device-in-emu-builds.patch +Patch0272: 0272-loader-arm64-linux-Remove-magic-number-header-field-.patch +Patch0273: 0273-Correct-BSS-zeroing-on-aarch64.patch +Patch0274: 0274-linuxefi-Invalidate-i-cache-before-starting-the-kern.patch +Patch0275: 0275-x86-efi-Fix-an-incorrect-array-size-in-kernel-alloca.patch +Patch0276: 0276-commands-efi-tpm-Refine-the-status-of-log-event.patch +Patch0277: 0277-commands-efi-tpm-Use-grub_strcpy-instead-of-grub_mem.patch +Patch0278: 0278-efi-tpm-Add-EFI_CC_MEASUREMENT_PROTOCOL-support.patch +Patch0279: 0279-font-Reject-glyphs-exceeds-font-max_glyph_width-or-f.patch +Patch0280: 0280-font-Fix-size-overflow-in-grub_font_get_glyph_intern.patch +Patch0281: 0281-font-Fix-several-integer-overflows-in-grub_font_cons.patch +Patch0282: 0282-font-Remove-grub_font_dup_glyph.patch +Patch0283: 0283-font-Fix-integer-overflow-in-ensure_comb_space.patch +Patch0284: 0284-font-Fix-integer-overflow-in-BMP-index.patch +Patch0285: 0285-font-Fix-integer-underflow-in-binary-search-of-char-.patch +Patch0286: 0286-kern-efi-sb-Enforce-verification-of-font-files.patch +Patch0287: 0287-fbutil-Fix-integer-overflow.patch +Patch0288: 0288-font-Fix-an-integer-underflow-in-blit_comb.patch +Patch0289: 0289-font-Harden-grub_font_blit_glyph-and-grub_font_blit_.patch +Patch0290: 0290-font-Assign-null_font-to-glyphs-in-ascii_font_glyph.patch +Patch0291: 0291-normal-charset-Fix-an-integer-overflow-in-grub_unico.patch +Patch0292: 0292-font-Try-opening-fonts-from-the-bundled-memdisk.patch +Patch0293: 0293-mm-Clarify-grub_real_malloc.patch +Patch0294: 0294-mm-grub_real_malloc-Make-small-allocs-comment-match-.patch +Patch0295: 0295-mm-Document-grub_free.patch +Patch0296: 0296-mm-Document-grub_mm_init_region.patch +Patch0297: 0297-mm-Document-GRUB-internal-memory-management-structur.patch +Patch0298: 0298-mm-Assert-that-we-preserve-header-vs-region-alignmen.patch +Patch0299: 0299-mm-When-adding-a-region-merge-with-region-after-as-w.patch +Patch0300: 0300-mm-Debug-support-for-region-operations.patch +Patch0301: 0301-mm-Drop-unused-unloading-of-modules-on-OOM.patch +Patch0302: 0302-mm-Allow-dynamically-requesting-additional-memory-re.patch +Patch0303: 0303-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch +Patch0304: 0304-kern-efi-mm-Extract-function-to-add-memory-regions.patch +Patch0305: 0305-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch +Patch0306: 0306-kern-efi-mm-Implement-runtime-addition-of-pages.patch +Patch0307: 0307-efi-Increase-default-memory-allocation-to-32-MiB.patch +Patch0308: 0308-mm-Try-invalidate-disk-caches-last-when-out-of-memor.patch +Patch0309: 0309-ppc64le-signed-boot-media-changes.patch +Patch0310: 0310-core-Fix-several-implicit-function-declarations.patch +Patch0311: 0311-loader-Add-support-for-grub-emu-to-kexec-Linux-menu-.patch +Patch0312: 0312-powerpc-Drop-Open-Hack-Ware-remove-GRUB_IEEE1275_FLA.patch +Patch0313: 0313-ieee1275-request-memory-with-ibm-client-architecture.patch +Patch0314: 0314-ieee1275-drop-len-1-quirk-in-heap_init.patch +Patch0315: 0315-ieee1275-support-runtime-memory-claiming.patch +Patch0316: 0316-ieee1275-implement-vec5-for-cas-negotiation.patch +Patch0317: 0317-ibmvtpm-Add-support-for-trusted-boot-using-a-vTPM-2..patch +Patch0318: 0318-powerpc-Drop-Open-Hack-Ware.patch +Patch0319: 0319-osdep-linux-hostdisk-Modify-sector-by-sysfs-as-disk-.patch +Patch0320: 0320-mm-Adjust-new-region-size-to-take-management-overhea.patch +Patch0321: 0321-mm-Preallocate-some-space-when-adding-new-regions.patch +Patch0322: 0322-mm-Avoid-complex-heap-growth-math-in-hot-path.patch +Patch0323: 0323-hostdisk-work-around-proc-not-reporting-size.patch +Patch0324: 0324-blscfg-check-for-mounted-boot-in-emu.patch +Patch0325: 0325-emu-linux-work-around-systemctl-kexec-returning.patch +Patch0326: 0326-kern-ieee1275-init-Convert-plain-numbers-to-constant.patch +Patch0327: 0327-kern-ieee1275-init-Extended-support-in-Vec5.patch +Patch0328: 0328-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch +Patch0329: 0329-grub_dl_set_mem_attrs-fix-format-string.patch +Patch0330: 0330-grub_dl_set_mem_attrs-add-self-check-for-the-tramp-G.patch +Patch0331: 0331-grub_dl_load_segments-page-align-the-tramp-GOT-areas.patch +Patch0332: 0332-emu-Add-switch-root-to-grub-emu.patch +Patch0333: 0333-util-Enable-default-kernel-for-updates.patch +Patch0334: 0334-efi-http-change-uint32_t-to-uintn_t.patch +Patch0335: 0335-Add-Install-section-to-aux-systemd-units.patch +Patch0336: 0336-arm64-Use-proper-memory-type-for-kernel-allocation.patch +Patch0337: 0337-Fix-missing-include-in-ofdisk.c.patch +Patch0338: 0338-kern-ieee1275-init-ppc64-Restrict-high-memory-in-pre.patch +Patch0339: 0339-grub-install-on-EFI-if-forced.patch +Patch0340: 0340-Remove-Install-section-from-aux-systemd-units.patch +Patch0341: 0341-fs-Remove-trailing-whitespaces.patch +Patch0342: 0342-fs-xfs-Fix-memory-leaks-in-XFS-module.patch +Patch0343: 0343-fs-xfs-Fix-issues-found-while-fuzzing-the-XFS-filesy.patch +Patch0344: 0344-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch +Patch0345: 0345-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch +Patch0346: 0346-chainloader-remove-device-path-debug-message.patch +Patch0347: 0347-normal-Remove-grub_env_set-prefix-in-grub_try_normal.patch +Patch0348: 0348-add-flag-to-only-search-root-dev.patch +Patch0349: 0349-Ignore-warnings-for-incompatible-types.patch +Patch0350: 0350-fs-xfs-Fix-XFS-directory-extent-parsing.patch +Patch0351: 0351-grub2-mkconfig-Ensure-grub-cfg-stub-is-not-overwritt.patch +Patch0352: 0352-grub2-mkconfig-Simplify-os_name-detection.patch +Patch0353: 0353-grub-mkconfig-Remove-check-for-mount-point-for-grub-.patch +Patch0354: 0354-grub-mkconfig-dont-overwrite-BLS-cmdline-if-BLSCFG.patch +Patch0355: 0355-grub2-mkconfig-Pass-all-boot-params-when-used-by-ana.patch +Patch0356: 0356-grub-set-bootflag-Conservative-partial-fix-for-CVE-2.patch +Patch0357: 0357-grub-set-bootflag-More-complete-fix-for-CVE-2024-104.patch +Patch0358: 0358-grub-set-bootflag-Exit-calmly-when-not-running-as-ro.patch +Patch0359: 0359-fs-ntfs-Fix-an-OOB-write-when-parsing-the-ATTRIBUTE_.patch +Patch0360: 0360-fs-ntfs-Fix-an-OOB-read-when-reading-data-from-the-r.patch +Patch0361: 0361-fs-ntfs-Fix-an-OOB-read-when-parsing-directory-entri.patch +Patch0362: 0362-fs-ntfs-Fix-an-OOB-read-when-parsing-bitmaps-for-ind.patch +Patch0363: 0363-fs-ntfs-Fix-an-OOB-read-when-parsing-a-volume-label.patch +Patch0364: 0364-fs-ntfs-Make-code-more-readable.patch +Patch0365: 0365-cmd-search-Rework-of-CVE-2023-4001-fix.patch +Patch0366: 0366-grub-mkconfig.in-turn-off-executable-owner-bit.patch diff --git a/SOURCES/sbat.csv.in b/SOURCES/sbat.csv.in new file mode 100755 index 0000000..b338b5f --- /dev/null +++ b/SOURCES/sbat.csv.in @@ -0,0 +1,3 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +grub,3,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/ +grub.rh,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com diff --git a/SOURCES/strtoull_test.c b/SOURCES/strtoull_test.c new file mode 100644 index 0000000..7da615f --- /dev/null +++ b/SOURCES/strtoull_test.c @@ -0,0 +1,63 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2016 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static void +strtoull_testcase (const char *input, int base, unsigned long long expected, + int num_digits, grub_err_t error) +{ + char *output; + unsigned long long value; + grub_errno = 0; + value = grub_strtoull(input, &output, base); + grub_test_assert (grub_errno == error, + "unexpected error. Expected %d, got %d. Input \"%s\"", + error, grub_errno, input); + if (grub_errno) + { + grub_errno = 0; + return; + } + grub_test_assert (input + num_digits == output, + "unexpected number of digits. Expected %d, got %d, input \"%s\"", + num_digits, (int) (output - input), input); + grub_test_assert (value == expected, + "unexpected return value. Expected %llu, got %llu, input \"\%s\"", + expected, value, input); +} + +static void +strtoull_test (void) +{ + strtoull_testcase ("9", 0, 9, 1, GRUB_ERR_NONE); + strtoull_testcase ("0xaa", 0, 0xaa, 4, GRUB_ERR_NONE); + strtoull_testcase ("0xff", 0, 0xff, 4, GRUB_ERR_NONE); + strtoull_testcase ("0", 10, 0, 1, GRUB_ERR_NONE); + strtoull_testcase ("8", 8, 0, 0, GRUB_ERR_BAD_NUMBER); + strtoull_testcase ("38", 8, 3, 1, GRUB_ERR_NONE); + strtoull_testcase ("7", 8, 7, 1, GRUB_ERR_NONE); + strtoull_testcase ("1]", 16, 1, 1, GRUB_ERR_NONE); + strtoull_testcase ("18446744073709551616", 10, 0, 0, GRUB_ERR_OUT_OF_RANGE); +} + + +GRUB_FUNCTIONAL_TEST (strtoull_test, strtoull_test); diff --git a/SPECS/grub2.spec b/SPECS/grub2.spec new file mode 100644 index 0000000..1614035 --- /dev/null +++ b/SPECS/grub2.spec @@ -0,0 +1,2195 @@ +# This package calls binutils components directly and would need to pass +# in flags to enable the LTO plugins +# Disable LTO +%global _lto_cflags %{nil} + +%undefine _hardened_build +%undefine _package_note_file + +%global tarversion 2.06 +%undefine _missing_build_ids_terminate_build +%global _configure_gnuconfig_hack 0 + +# It's a commit from their gnulib's development tree. They don't do releases, +# and it is *awful* to update this. +%global gnulibversion 9f48fb992a3d7e96610c4ce8be969cff2d61a01b + +Name: grub2 +Epoch: 1 +Version: 2.06 +Release: 127%{?dist} +Summary: Bootloader with support for Linux, Multiboot and more +License: GPL-3.0-or-later +URL: http://www.gnu.org/software/grub/ +Obsoletes: grub < 1:0.98 +Source0: https://ftp.gnu.org/gnu/grub/grub-%{tarversion}.tar.xz +Source1: grub.macros +Source2: gnulib-%{gnulibversion}.tar.gz +Source3: 99-grub-mkconfig.install +Source4: http://unifoundry.com/pub/unifont/unifont-13.0.06/font-builds/unifont-13.0.06.pcf.gz +Source5: theme.tar.bz2 +Source6: gitignore +Source7: bootstrap +Source8: bootstrap.conf +Source9: strtoull_test.c +Source10: 20-grub.install +Source11: grub.patches +Source12: sbat.csv.in + +%include %{SOURCE1} + +%ifarch x86_64 aarch64 ppc64le +%define sb_ca %{_datadir}/pki/sb-certs/secureboot-ca-%{_arch}.cer +%define sb_cer %{_datadir}/pki/sb-certs/secureboot-grub2-%{_arch}.cer +%endif + +%if 0%{?centos} + +%ifarch x86_64 aarch64 ppc64le +%define sb_key centossecureboot202 +%endif +%else +%ifarch x86_64 aarch64 +%define sb_key redhatsecureboot502 +%endif +%ifarch ppc64le +%define sb_key redhatsecureboot702 +%endif + +%endif +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: binutils +BuildRequires: bison +BuildRequires: bzip2-devel +BuildRequires: dejavu-sans-fonts +BuildRequires: device-mapper-devel +BuildRequires: efi-srpm-macros +BuildRequires: flex +BuildRequires: freetype-devel +BuildRequires: freetype-devel +BuildRequires: fuse-devel +BuildRequires: gcc +BuildRequires: gettext-devel +BuildRequires: git +BuildRequires: help2man +BuildRequires: ncurses-devel +BuildRequires: python3 +BuildRequires: rpm-devel +BuildRequires: rpm-libs +BuildRequires: squashfs-tools +BuildRequires: texinfo +BuildRequires: xz-devel + +# For %%_userunitdir and %%systemd_* macros +BuildRequires: systemd-rpm-macros + +%ifarch %{efi_arch} +BuildRequires: pesign >= 0.99-8 +%endif +BuildRequires: system-sb-certs +%if %{?_with_ccache: 1}%{?!_with_ccache: 0} +BuildRequires: ccache +%endif + +ExcludeArch: s390 s390x %{ix86} +Obsoletes: grub2 <= %{evr} + +%if 0%{with_legacy_arch} +Requires: grub2-%{legacy_package_arch} = %{evr} +%else +Requires: grub2-%{package_arch} = %{evr} +%endif + +%global desc \ +The GRand Unified Bootloader (GRUB) is a highly configurable and \ +customizable bootloader with modular architecture. It supports a rich \ +variety of kernel formats, file systems, computer architectures and \ +hardware devices.\ +%{nil} + +# generate with do-rebase +%include %{SOURCE11} + +%description +%{desc} + +%package common +Summary: grub2 common layout +BuildArch: noarch +Conflicts: grubby < 8.40-18 +Requires(posttrans): util-linux-core +Requires(posttrans): coreutils +Requires(posttrans): grep + +%description common +This package provides some directories which are required by various grub2 +subpackages. + +%package tools +Summary: Support tools for GRUB. +Requires: grub2-common = %{epoch}:%{version}-%{release} +Requires: gettext-runtime os-prober file +Requires(pre): dracut +Requires(pre): grep +Requires(pre): sed +%{?systemd_requires} + +%description tools +%{desc} +This subpackage provides tools for support of all platforms. + +%ifarch x86_64 +%package tools-efi +Summary: Support tools for GRUB. +Requires: gettext-runtime os-prober file +Requires: grub2-common = %{epoch}:%{version}-%{release} + +%description tools-efi +%{desc} +This subpackage provides tools for support of EFI platforms. +%endif + +%package tools-minimal +Summary: Support tools for GRUB. +Requires: gettext-runtime +Requires: grub2-common = %{epoch}:%{version}-%{release} + +%description tools-minimal +%{desc} +This subpackage provides tools for support of all platforms. + +%package tools-extra +Summary: Support tools for GRUB. +Requires: gettext-runtime os-prober file +Requires: grub2-tools-minimal = %{epoch}:%{version}-%{release} +Requires: grub2-common = %{epoch}:%{version}-%{release} +Requires: mtools + +%description tools-extra +%{desc} +This subpackage provides tools for support of all platforms. + +%if 0%{with_efi_arch} +%{expand:%define_efi_variant %%{package_arch} -o} +%endif +%if 0%{with_alt_efi_arch} +%{expand:%define_efi_variant %%{alt_package_arch}} +%endif +%if 0%{with_legacy_arch} +%{expand:%define_legacy_variant %%{legacy_package_arch}} +%endif + +%if 0%{with_emu_arch} +%package emu +Summary: GRUB user-space emulation. +Requires: grub2-tools-minimal = %{epoch}:%{version}-%{release} + +%description emu +%{desc} +This subpackage provides the GRUB user-space emulation support of all platforms. + +%package emu-modules +Summary: GRUB user-space emulation modules. +Requires: grub2-tools-minimal = %{epoch}:%{version}-%{release} + +%description emu-modules +%{desc} +This subpackage provides the GRUB user-space emulation modules. +%endif + +%prep +%do_common_setup +%if 0%{with_efi_arch} +mkdir grub-%{grubefiarch}-%{tarversion} +grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubefiarch}-%{tarversion}/.gitignore +cp %{SOURCE4} grub-%{grubefiarch}-%{tarversion}/unifont.pcf.gz +sed -e "s,@@VERSION@@,%{version},g" -e "s,@@VERSION_RELEASE@@,%{version}-%{release},g" \ + %{SOURCE12} > grub-%{grubefiarch}-%{tarversion}/sbat.csv +git add grub-%{grubefiarch}-%{tarversion} +%endif +%if 0%{with_alt_efi_arch} +mkdir grub-%{grubaltefiarch}-%{tarversion} +grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubaltefiarch}-%{tarversion}/.gitignore +cp %{SOURCE4} grub-%{grubaltefiarch}-%{tarversion}/unifont.pcf.gz +git add grub-%{grubaltefiarch}-%{tarversion} +%endif +%if 0%{with_legacy_arch} +mkdir grub-%{grublegacyarch}-%{tarversion} +grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grublegacyarch}-%{tarversion}/.gitignore +cp %{SOURCE4} grub-%{grublegacyarch}-%{tarversion}/unifont.pcf.gz +git add grub-%{grublegacyarch}-%{tarversion} +%endif +%if 0%{with_emu_arch} +mkdir grub-emu-%{tarversion} +grep -A100000 '# stuff "make" creates' .gitignore > grub-emu-%{tarversion}/.gitignore +cp %{SOURCE4} grub-emu-%{tarversion}/unifont.pcf.gz +git add grub-emu-%{tarversion} +%endif +git commit -m "After making subdirs" + +%build +%if 0%{with_efi_arch} +%{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{sb_ca} %{sb_cer} %{sb_key}} +%endif +%if 0%{with_alt_efi_arch} +%{expand:%do_alt_efi_build %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname} %%{_alt_target_platform} %%{alt_efi_target_cflags} %%{alt_efi_host_cflags} %{sb_ca} %{sb_cer} %{sb_key}} +%endif +%if 0%{with_legacy_arch} +%{expand:%do_legacy_build %%{grublegacyarch}} +%endif +%if 0%{with_emu_arch} +%{expand:%do_emu_build} +%endif +%ifarch ppc64le +%{expand:%do_ieee1275_build_images %%{grublegacyarch} %{grubelfname} %{sb_cer} %{sb_key}} +%endif +makeinfo --info --no-split -I docs -o docs/grub-dev.info \ + docs/grub-dev.texi +makeinfo --info --no-split -I docs -o docs/grub.info \ + docs/grub.texi +makeinfo --html --no-split -I docs -o docs/grub-dev.html \ + docs/grub-dev.texi +makeinfo --html --no-split -I docs -o docs/grub.html \ + docs/grub.texi + +%install +set -e +rm -fr $RPM_BUILD_ROOT + +%do_common_install +%if 0%{with_efi_arch} +%{expand:%do_efi_install %%{grubefiarch} %%{grubefiname} %%{grubeficdname}} +%endif +%if 0%{with_alt_efi_arch} +%{expand:%do_alt_efi_install %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname}} +%endif +%if 0%{with_legacy_arch} +%{expand:%do_legacy_install %%{grublegacyarch} %%{alt_grub_target_name} 0%{with_efi_arch}} +%endif +%if 0%{with_emu_arch} +%{expand:%do_emu_install %%{package_arch}} +%endif +rm -f $RPM_BUILD_ROOT%{_infodir}/dir +ln -s grub2-set-password ${RPM_BUILD_ROOT}/%{_sbindir}/grub2-setpassword +echo '.so man8/grub2-set-password.8' > ${RPM_BUILD_ROOT}/%{_datadir}/man/man8/grub2-setpassword.8 +%ifnarch x86_64 +rm -vf ${RPM_BUILD_ROOT}/%{_bindir}/grub2-render-label +rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/grub2-bios-setup +rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/grub2-macbless +%endif +%{expand:%%do_install_protected_file grub2-tools-minimal} + +%find_lang grub + +# Install kernel-install scripts +install -d -m 0755 %{buildroot}%{_prefix}/lib/kernel/install.d/ +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE10} +install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE3} +install -d -m 0755 %{buildroot}%{_sysconfdir}/kernel/install.d/ +# Install systemd user service to set the boot_success flag +install -D -m 0755 -t %{buildroot}%{_userunitdir} \ + docs/grub-boot-success.{timer,service} +# Install systemd system-update unit to set boot_indeterminate for offline-upd +install -D -m 0755 -t %{buildroot}%{_unitdir} docs/grub-boot-indeterminate.service +install -d -m 0755 %{buildroot}%{_unitdir}/system-update.target.wants +install -d -m 0755 %{buildroot}%{_unitdir}/reboot.target.wants +ln -s ../grub-boot-indeterminate.service \ + %{buildroot}%{_unitdir}/system-update.target.wants +ln -s ../grub2-systemd-integration.service \ + %{buildroot}%{_unitdir}/reboot.target.wants + +# Don't run debuginfo on all the grub modules and whatnot; it just +# rejects them, complains, and slows down extraction. +%global finddebugroot "%{_builddir}/%{?buildsubdir}/debug" + +%global dip RPM_BUILD_ROOT=%{finddebugroot} %{__debug_install_post} +%define __debug_install_post ( \ + mkdir -p %{finddebugroot}/usr \ + mv ${RPM_BUILD_ROOT}/usr/bin %{finddebugroot}/usr/bin \ + mv ${RPM_BUILD_ROOT}/usr/sbin %{finddebugroot}/usr/sbin \ + %{dip} \ + install -m 0755 -d %{buildroot}/usr/lib/ %{buildroot}/usr/src/ \ + cp -al %{finddebugroot}/usr/lib/debug/ \\\ + %{buildroot}/usr/lib/debug/ \ + cp -al %{finddebugroot}/usr/src/debug/ \\\ + %{buildroot}/usr/src/debug/ ) \ + mv %{finddebugroot}/usr/bin %{buildroot}/usr/bin \ + mv %{finddebugroot}/usr/sbin %{buildroot}/usr/sbin \ + %{nil} + +%undefine buildsubdir + +%pre tools +if [ -f /boot/grub2/user.cfg ]; then + if grep -q '^GRUB_PASSWORD=' /boot/grub2/user.cfg ; then + sed -i 's/^GRUB_PASSWORD=/GRUB2_PASSWORD=/' /boot/grub2/user.cfg + fi +elif [ -f %{efi_esp_dir}/user.cfg ]; then + if grep -q '^GRUB_PASSWORD=' %{efi_esp_dir}/user.cfg ; then + sed -i 's/^GRUB_PASSWORD=/GRUB2_PASSWORD=/' \ + %{efi_esp_dir}/user.cfg + fi +elif [ -f /etc/grub.d/01_users ] && \ + grep -q '^password_pbkdf2 root' /etc/grub.d/01_users ; then + if [ -f %{efi_esp_dir}/grub.cfg ]; then + # on EFI we don't get permissions on the file, but + # the directory is protected. + grep '^password_pbkdf2 root' /etc/grub.d/01_users | \ + sed 's/^password_pbkdf2 root \(.*\)$/GRUB2_PASSWORD=\1/' \ + > %{efi_esp_dir}/user.cfg + fi + if [ -f /boot/grub2/grub.cfg ]; then + install -m 0600 /dev/null /boot/grub2/user.cfg + chmod 0600 /boot/grub2/user.cfg + grep '^password_pbkdf2 root' /etc/grub.d/01_users | \ + sed 's/^password_pbkdf2 root \(.*\)$/GRUB2_PASSWORD=\1/' \ + > /boot/grub2/user.cfg + fi +fi + +%post tools +%systemd_user_post grub-boot-success.timer + +%preun tools +%systemd_user_preun grub-boot-success.timer + +%postun tools +%systemd_user_postun_with_restart grub-boot-success.timer + +%triggerpostun tools -- grub2-tools < 1:2.06-107 +# grub-boot-success.timer was moved from a hard symlink under /lib/systemd +# to a preset, apply the preset when upgrading from pre-preset versions +/usr/lib/systemd/systemd-update-helper install-user-units grub-boot-success.timer + +%posttrans common +set -eu + +EFI_HOME=%{efi_esp_dir} +GRUB_HOME=/boot/grub2 +ESP_PATH=/boot/efi + +if ! mountpoint -q ${ESP_PATH}; then + exit 0 # no ESP mounted, nothing to do +fi + +if test ! -f ${EFI_HOME}/grub.cfg; then + # there's no config in ESP, create one + grub2-mkconfig -o ${EFI_HOME}/grub.cfg +fi + +if ((grep -q "configfile" ${EFI_HOME}/grub.cfg || grep -q "source" ${EFI_HOME}/grub.cfg) && ! grep -q "# It is automatically generated by grub2-mkconfig using templates" ${EFI_HOME}/grub.cfg); then + exit 0 #Already unified +fi + +# create a stub grub2 config in EFI +BOOT_UUID=$(grub2-probe --target=fs_uuid ${GRUB_HOME}) +GRUB_DIR=$(grub2-mkrelpath ${GRUB_HOME}) + +cat << EOF > ${EFI_HOME}/grub.cfg.stb +search --no-floppy --root-dev-only --fs-uuid --set=dev ${BOOT_UUID} +set prefix=(\$dev)${GRUB_DIR} +export \$prefix +configfile \$prefix/grub.cfg +EOF + +if test -f ${EFI_HOME}/grubenv; then + cp -a ${EFI_HOME}/grubenv ${EFI_HOME}/grubenv.rpmsave + mv --force ${EFI_HOME}/grubenv ${GRUB_HOME}/grubenv +fi + +cp -a ${EFI_HOME}/grub.cfg ${EFI_HOME}/grub.cfg.rpmsave +cp -a ${EFI_HOME}/grub.cfg ${GRUB_HOME}/ +mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg + +%files common -f grub.lang +%dir %{_libdir}/grub/ +%dir %{_datarootdir}/grub/ +%attr(0700,root,root) %dir %{_sysconfdir}/grub.d +%{_prefix}/lib/kernel/install.d/20-grub.install +%{_prefix}/lib/kernel/install.d/99-grub-mkconfig.install +%dir %{_datarootdir}/grub +%exclude %{_datarootdir}/grub/* +%dir /boot/grub2 +%dir /boot/grub2/themes/ +%dir /boot/grub2/themes/system +%attr(0700,root,root) %dir /boot/grub2 +%exclude /boot/grub2/* +%dir %attr(0700,root,root) %{efi_esp_dir} +%exclude %{efi_esp_dir}/* +%ghost %config(noreplace) %verify(not size mode md5 mtime) /boot/grub2/grubenv +%license COPYING +%doc THANKS +%doc docs/grub.html +%doc docs/grub-dev.html +%doc docs/font_char_metrics.png + +%files tools-minimal +%{_sbindir}/grub2-get-kernel-settings +%{_sbindir}/grub2-probe +%attr(4755, root, root) %{_sbindir}/grub2-set-bootflag +%{_sbindir}/grub2-set-default +%{_sbindir}/grub2-set*password +%{_bindir}/grub2-editenv +%{_bindir}/grub2-mkpasswd-pbkdf2 +%{_bindir}/grub2-mount +%attr(0644,root,root) %config(noreplace) /etc/dnf/protected.d/grub2-tools-minimal.conf + +%{_datadir}/man/man3/grub2-get-kernel-settings* +%{_datadir}/man/man8/grub2-set-default* +%{_datadir}/man/man8/grub2-set*password* +%{_datadir}/man/man1/grub2-editenv* +%{_datadir}/man/man1/grub2-mkpasswd-* + +%ifarch x86_64 +%files tools-efi +%{_bindir}/grub2-glue-efi +%{_bindir}/grub2-render-label +%{_sbindir}/grub2-macbless +%{_datadir}/man/man1/grub2-glue-efi* +%{_datadir}/man/man1/grub2-render-label* +%{_datadir}/man/man8/grub2-macbless* +%endif + +%files tools +%attr(0644,root,root) %ghost %config(noreplace) %{_sysconfdir}/default/grub +%config %{_sysconfdir}/grub.d/??_* +%{_sysconfdir}/grub.d/README +%{_userunitdir}/grub-boot-success.timer +%{_userunitdir}/grub-boot-success.service +%{_unitdir}/grub-boot-indeterminate.service +%{_unitdir}/system-update.target.wants +%{_unitdir}/grub2-systemd-integration.service +%{_unitdir}/reboot.target.wants +%{_unitdir}/systemd-logind.service.d +%{_infodir}/grub2* +%{_datarootdir}/grub/* +%{_sbindir}/grub2-install +%exclude %{_datarootdir}/grub/themes +%exclude %{_datarootdir}/grub/*.h +%{_datarootdir}/bash-completion/completions/grub +%{_sbindir}/grub2-mkconfig +%{_sbindir}/grub2-switch-to-blscfg +%{_sbindir}/grub2-reboot +%{_bindir}/grub2-file +%{_bindir}/grub2-menulst2cfg +%{_bindir}/grub2-mkimage +%{_bindir}/grub2-mkrelpath +%{_bindir}/grub2-script-check +%{_libexecdir}/grub2 +%{_datadir}/man/man?/* + +# exclude man pages from tools-extra +%exclude %{_datadir}/man/man8/grub2-sparc64-setup* +%exclude %{_datadir}/man/man1/grub2-fstest* +%exclude %{_datadir}/man/man1/grub2-glue-efi* +%exclude %{_datadir}/man/man1/grub2-kbdcomp* +%exclude %{_datadir}/man/man1/grub2-mkfont* +%exclude %{_datadir}/man/man1/grub2-mklayout* +%exclude %{_datadir}/man/man1/grub2-mknetdir* +%exclude %{_datadir}/man/man1/grub2-mkrescue* +%exclude %{_datadir}/man/man1/grub2-mkstandalone* +%exclude %{_datadir}/man/man1/grub2-syslinux2cfg* + +# exclude man pages from tools-minimal +%exclude %{_datadir}/man/man3/grub2-get-kernel-settings* +%exclude %{_datadir}/man/man8/grub2-set-default* +%exclude %{_datadir}/man/man8/grub2-set*password* +%exclude %{_datadir}/man/man1/grub2-editenv* +%exclude %{_datadir}/man/man1/grub2-mkpasswd-* +%exclude %{_datadir}/man/man8/grub2-macbless* +%exclude %{_datadir}/man/man1/grub2-render-label* + +%if %{with_legacy_arch} +%{_sbindir}/grub2-install +%ifarch x86_64 +%{_sbindir}/grub2-bios-setup +%else +%exclude %{_sbindir}/grub2-bios-setup +%exclude %{_datadir}/man/man8/grub2-bios-setup* +%endif +%ifarch %{sparc} +%{_sbindir}/grub2-sparc64-setup +%else +%exclude %{_sbindir}/grub2-sparc64-setup +%exclude %{_datadir}/man/man8/grub2-sparc64-setup* +%endif +%ifarch %{sparc} ppc ppc64 ppc64le +%{_sbindir}/grub2-ofpathname +%else +%exclude %{_sbindir}/grub2-ofpathname +%exclude %{_datadir}/man/man8/grub2-ofpathname* +%endif +%endif + +%files tools-extra +%{_bindir}/grub2-fstest +%{_bindir}/grub2-kbdcomp +%{_bindir}/grub2-mkfont +%{_bindir}/grub2-mklayout +%{_bindir}/grub2-mknetdir +%ifnarch %{sparc} +%{_bindir}/grub2-mkrescue +%{_datadir}/man/man1/grub2-mkrescue* +%else +%exclude %{_datadir}/man/man1/grub2-mkrescue* +%endif +%{_bindir}/grub2-mkstandalone +%{_bindir}/grub2-syslinux2cfg +%{_sysconfdir}/sysconfig/grub +%{_datadir}/man/man1/grub2-fstest* +%{_datadir}/man/man1/grub2-kbdcomp* +%{_datadir}/man/man1/grub2-mkfont* +%{_datadir}/man/man1/grub2-mklayout* +%{_datadir}/man/man1/grub2-mknetdir* +%{_datadir}/man/man1/grub2-mkstandalone* +%{_datadir}/man/man1/grub2-syslinux2cfg* +%exclude %{_bindir}/grub2-glue-efi +%exclude %{_sbindir}/grub2-sparc64-setup +%exclude %{_sbindir}/grub2-ofpathname +%exclude %{_datadir}/man/man1/grub2-glue-efi* +%exclude %{_datadir}/man/man8/grub2-ofpathname* +%exclude %{_datadir}/man/man8/grub2-sparc64-setup* +%exclude %{_datarootdir}/grub/themes/starfield + +%if 0%{with_efi_arch} +%{expand:%define_efi_variant_files %%{package_arch} %%{grubefiname} %%{grubeficdname} %%{grubefiarch} %%{target_cpu_name} %%{grub_target_name}} +%endif +%if 0%{with_alt_efi_arch} +%{expand:%define_efi_variant_files %%{alt_package_arch} %%{grubaltefiname} %%{grubalteficdname} %%{grubaltefiarch} %%{alt_target_cpu_name} %%{alt_grub_target_name}} +%endif +%if 0%{with_legacy_arch} +%{expand:%define_legacy_variant_files %%{legacy_package_arch} %%{grublegacyarch}} +%endif + +%if 0%{with_emu_arch} +%files emu +%{_bindir}/grub2-emu* +%{_datadir}/man/man1/grub2-emu* + +%files emu-modules +%{_libdir}/grub/%{emuarch}-emu/* +%exclude %{_libdir}/grub/%{emuarch}-emu/*.module +%endif + +%changelog +* Tue Nov 26 2024 MSVSphere Packaging Team - 2.06-127 +- Rebuilt for MSVSphere 10 + +* Fri Aug 30 2024 Nicolas Frayer - 2.06-127 +- Sync with rhel9 for critical patches +- Resolves: #RHEL-56733 + +* Wed Aug 28 2024 Nicolas Frayer - 2.06-126 +- grub-mkconfig dont overwrite BLS cmdline if BLSCFG +- Resolves: #RHEL-53848 + +* Mon Aug 5 2024 Peter Jones - 2.06-125 +- spec/macros: Modified spec and macros files for RHEL10 signing +- Related: #RHEL-51867 + +* Thu Aug 1 2024 Nicolas Frayer - 2.06-124 +- grub2-mkconfig: Remove mountpoint check +- Related: #RHEL-32099 + +* Wed Jul 31 2024 Nicolas Frayer - 2.06-123 +- Use the set of macros provided by system-sb-certs for signing +- Resolves: #RHEL-51867 +- Resolves: #RHELBLD-15314 + +* Wed Jul 31 2024 Andrew Lukoshko - 2.06-122 +- grub2-mkconfig: Simplify os_name detection +- Resolves: #RHEL-32099 + +* Tue Jul 16 2024 Nicolas Frayer - 2.06-121 +- grub2-mkconfig: Prevent mkconfig from overwriting grub cfg stub +- Resolves: #RHEL-32099 + +* Mon Jun 24 2024 Troy Dawson +- Bump release for June 2024 mass rebuild + +* Wed Jun 19 2024 Nicolas Frayer - 2.06-119 +- Bump to use the right keys to sign + +* Tue Jan 23 2024 Leo Sandoval - 2.06-118 +- xfs: include the 'directory extent parsing patch', otherwise +XFS-formatted partitions do not boot. This change effectively +reverts 2.06-115 +- Resolves: #2259266 + +* Wed Jan 17 2024 Nicolas Frayer - 2.06-117 +- Compiler flags: ignore incompatible types for now as it prevents +CI builds + +* Wed Jan 17 2024 Nicolas Frayer - 2.06-116 +- grub-core/commands: add flag to only search root dev +- Resolves: #2223437 +- Resolves: #2224951 +- Resolves: #2258096 +- Resolves: CVE-2023-4001 + +* Wed Jan 17 2024 Nicolas Frayer - 2.06-115 +- xfs: some bios systems can't boot with one of the xfs upstream patches +- Resolves: #2254370 + +* Sat Jan 13 2024 Hector Martin - 2.06-114 +- Switch memdisk compression to lzop + +* Thu Jan 11 2024 Daan De Meyer - 2.06-113 +- Don't obsolete the tools package with minimal + +* Tue Dec 19 2023 Nicolas Frayer - 2.06-112 +- normal: fix prefix when loading modules +- Resolves: #2209435 +- Resolves: #2173015 + +* Tue Dec 12 2023 leo sandoval - 2.06-111 +- chainloader: remove device path debug message + +* Fri Dec 1 2023 Nicolas Frayer - 2.06-110 +- fs/xfs: Add several fixes/improvements to xfs fs from upstream +- Resolves: #2247926 + +* Wed Nov 15 2023 Nicolas Frayer - 2.06-109 +- Linker: added --no-warn-rwx-segments as build will fail after +ld.bfd default options have been changed. +https://fedoraproject.org/wiki/Changes/Linker_Error_On_Security_Issues + +* Tue Nov 14 2023 Nicolas Frayer - 2.06-108 +- Remove [Install] section from aux systemd units +- Related: #2247635 + +* Tue Nov 14 2023 Hans de Goede - 2.06-107 +- spec: Switch back to static enablement for grub services in tools package +- spec: Add %%triggerpostun to apply grub-boot-success.timer preset + when upgrading from older versions where this was not a preset +- Resolves: #2247635 + +* Mon Nov 6 2023 Nicolas Frayer - 2.06-106 +- util: grub-install on EFI if forced +- Resolves: #1917213 +- Resolves: #2240994 + +* Fri Oct 20 2023 Nicolas Frayer - 2.06-105 +- kern/ieee1275/init: ppc64: Restrict high memory in presence + of fadump + +* Wed Oct 11 2023 Janne Grunau - 2.06-104 +- 20-grub.install: Copy device-tree directory recursively +- Resolves: #2243060 + +* Fri Sep 29 2023 Zbigniew Jedrzejewski-Szmek - 1:2.06-103 +- Rename installed kernel to match name used in boot entry +- Resolves: #2239008 + +* Fri Sep 29 2023 Nicolas Frayer - 2.06-102 +- ofdisk: Fix missing #include in ofdisk.c + +* Thu Sep 28 2023 Christian Glombek - 2.06-101 +- spec: Fix grub2-systemd-integration.service name + +* Wed Sep 13 2023 Nicolas Frayer - 2.06-100 +- arm64: Use proper memory type for kernel allocation +- Resolves: #2149020 + +* Fri Sep 01 2023 Christian Glombek - 2.06-99 +- spec: Use systemd presets and macros for units in tools package +- Resolves: #2230575 + +* Thu Aug 31 2023 Nicolas Frayer - 2.06-98 +- spec: Modified posttrans to harden grub config detection +- Resolves: #2235692 + +* Tue Aug 22 2023 Nicolas Frayer - 2.06-97 +- efi/http: change uint32_t to uintn_t + +* Tue Aug 22 2023 Nicolas Frayer - 2.06-96 +- util: Enable default kernel for updates + +* Wed Apr 12 2023 Robbie Harwood - 2.06-95 +- Add switch-root support to grub-emu + +* Mon Apr 10 2023 Robbie Harwood - 2.06-94 +- Fix aa64 page fault with EFI_MEMORY_ATTRIBUTE_PROTOCOL + +* Fri Mar 31 2023 Robbie Harwood - 2.06-93 +- Add legacy pxe core.0 (cmadams) + +* Thu Mar 30 2023 Robbie Harwood - 2.06-92 +- Disable the tpm verifier if the TPM device is not present + +* Thu Mar 30 2023 Robbie Harwood - 2.06-91 +- ppc64le: more cas vec5 shenanigans + +* Wed Mar 22 2023 Robbie Harwood - 2.06-90 +- emu: work around systemctl bad behavior + +* Thu Mar 09 2023 Robbie Harwood - 2.06-89 +- emu: handle BLS /boot weirdness + +* Mon Feb 20 2023 Robbie Harwood - 2.06-88 +- Update mm fixes from upstream + +* Thu Feb 16 2023 Robbie Harwood - 2.06-87 +- Fix disk sector size computation + +* Fri Feb 10 2023 Robbie Harwood - 2.06-86 +- Override the linker and force nonexecutable stacks + +* Wed Feb 08 2023 Robbie Harwood - 2.06-85 +- ppc64le: sync cas/tpm patchset with upstream + +* Mon Feb 06 2023 Robbie Harwood - 2.06-84 +- emu: support newer kexec syscall + +* Mon Feb 06 2023 Robbie Harwood - 2.06-83 +- ppc64le: cas5, take 3 + +* Mon Feb 06 2023 Robbie Harwood - 2.06-82 +- Fix implicit function declaration warnings + +* Wed Feb 01 2023 Javier Martinez Canillas - 2.06-81 +- 20-grub-install: Explicitly check '+debug' suffix for debug kernels +- Resolves: #2148351 + +* Wed Feb 01 2023 Robbie Harwood - 2.06-80 +- Bump to re-run signing + +* Tue Jan 31 2023 Robbie Harwood - 2.06-79 +- Disable mdraid < 1.1 on ppc64le + +* Fri Jan 27 2023 Robbie Harwood - 2.06-78 +- Fix grub2-probe issue with previous commit +- Resolves: #2165136 + +* Fri Jan 27 2023 Robbie Harwood - 2.06-77 +- ppc64le: update signed media fixes + +* Fri Jan 13 2023 Robbie Harwood - 2.06-76 +- ppc64le: fix issues using core.elf on boot media + +* Wed Jan 11 2023 Robbie Harwood - 2.06-75 +- Pull allocator improvements from upstream + +* Wed Jan 11 2023 Robbie Harwood - 2.06-74 +- Apply more hardening to host binaries + +* Tue Jan 10 2023 Robbie Harwood - 2.06-73 +- Allow internal grub allocations over 4GB + +* Wed Dec 21 2022 Robbie Harwood - 2.06-72 +- Fix prefix setting with memdisk creation for network boot + +* Mon Dec 19 2022 Robbie Harwood - 2.06-71 +- Attempt to fix eln build + +* Wed Dec 14 2022 Robbie Harwood - 2.06-70 +- ppc64le: fix lpar cas5 +- Resolves: #2152547 + +* Tue Dec 06 2022 Robbie Harwood - 2.06-69 +- Fix error handling in grub_file_open() + +* Mon Dec 05 2022 Robbie Harwood - 2.06-68 +- Allow for xz'd symvers file (prarit) + +* Wed Nov 23 2022 Tomas Hrcka - 1:2.06-67 +- install unicode.pf2 into place so lorax works + +* Tue Nov 22 2022 Robbie Harwood - 2.06-66 +- Bundle unicode.pf2 with images +- Resolves: #2143725 +- Resolves: #2144113 + +* Tue Nov 22 2022 Robbie Harwood - 1:2.06-65 +- Don't obsolete the tools package with extra/efi (pbrobinson) + +* Mon Nov 21 2022 Robbie Harwood - 1:2.06-64 +- Forward-port ppc64le image creation (with nerfed signing) + +* Tue Nov 08 2022 Robbie Harwood - 1:2.06-63 +- Font fixes (CVE-2022-2601 batch) + +* Tue Nov 01 2022 Robbie Harwood - 1:2.06-62 +- Try dropping custom sort again +- See-also: https://github.com/rpm-software-management/rpm/pull/2249 + +* Fri Oct 28 2022 Robbie Harwood - 2.06-61 +- TDX measurements to RTMR + +* Wed Oct 12 2022 Robbie Harwood - 2.06-60 +- x86-efi: Fix an incorrect array size in kernel allocation + +* Tue Oct 04 2022 Robbie Harwood - 2.06-59 +- Flush instruction cache before starting aa64 kernel + +* Fri Sep 09 2022 Robbie Harwood - 2.06-58 +- Bump spec for grub.macros gettext changes from Jens + +* Thu Sep 08 2022 Robbie Harwood - 2.06-57 +- aa64: support pe/coff decompressor + +* Wed Sep 07 2022 Robbie Harwood - 2.06-56 +- Revert patches to claim more memory for the arena + +* Thu Aug 25 2022 Robbie Harwood - 2.06-55 +- Fix root definition for blscfg in emu + +* Thu Aug 25 2022 Robbie Harwood - 2.06-54 +- gettext to gettext-runtime migration from Jens + +* Thu Aug 25 2022 Robbie Harwood - 2.06-53 +- ieee1275: implement vec5 for cas negotiation + +* Wed Aug 17 2022 Robbie Harwood - 2.06-52 +- Handle ostree's non-writable /etc/kernel + +* Wed Aug 17 2022 Robbie Harwood - 2.06-51 +- Give up on rhgb quiet + +* Wed Aug 17 2022 Robbie Harwood - 2.06-50 +- Fix duplicated args and cope with /etc/default/grub modification + +* Mon Aug 15 2022 Robbie Harwood - 2.06-49 +- Skip rpm mtime verification on likely-vfat filesystems + +* Mon Aug 15 2022 Robbie Harwood - 2.06-48 +- Use --with-rpm-version +- Resolves: #2118390 + +* Mon Aug 08 2022 Robbie Harwood - 2.06-47 +- Try reserving less RAM to fix windows booting +- Related: #2115202 + +* Tue Aug 02 2022 Robbie Harwood - 2.06-46 +- Populate /etc/kernel/cmdline during mkconfig + +* Tue Aug 02 2022 Robbie Harwood - 2.06-45 +- Rest of allocator fixes + +* Mon Aug 01 2022 Robbie Harwood - 2.06-44 +- Some allocator fixes for kernel + +* Tue Jul 19 2022 Robbie Harwood - 2.06-43 +- Handle FAT mtime of 0 +- Resolves: #2096192 + +* Mon May 16 2022 Robbie Harwood - 1:2.06-42 +- CVE fixes for 2022-05-24 +- Resolves: CVE-2022-28736 CVE-2022-28735 CVE-2022-28734 CVE-2022-28733 +- Resolves: CVE-2021-3697 CVE-2021-3696 CVE-2021-3695 + +* Mon May 16 2022 Robbie Harwood - 1:2.06-41 +- ppc64le: make ofdisk retries optional + +* Thu May 05 2022 Robbie Harwood - 1:2.06-40 +- Fix missing declaration of strchrnul in rpm-sort + +* Wed May 04 2022 Robbie Harwood - 1:2.06-39 +- ppc64le: CAS improvements, prefix detection, and vTPM support + +* Tue Apr 19 2022 Dominik Mierzejewski - 1:2.06-38 +- fix "grub2-mkrescue: error: `mformat` invocation failed" + +* Mon Apr 18 2022 Robbie Harwood - 1:2.06-37 +- Attempt to fix version display + +* Mon Apr 18 2022 Robbie Harwood - 2.06-36 +- Fix permission change report from rpm verification on grub.cfg + +* Wed Apr 13 2022 Robbie Harwood - 2.06-35 +- Enable "read" module +- Resolves: #2071644 + +* Tue Apr 12 2022 Robbie Harwood - 2.06-34 +- Bump for requirements updates; no code changes + +* Thu Mar 31 2022 Robbie Harwood - 1:2.06-33 +- Drop i32 build for real this time + +* Thu Mar 31 2022 Robbie Harwood - 1:2.06-32 +- Switch to upstream man pages + +* Wed Mar 30 2022 Robbie Harwood - 2.06-31 +- Revert previous change (grub2-pc-modules is built on i32) + +* Tue Mar 29 2022 Robbie Harwood - 2.06-30 +- Drop i32 support + +* Wed Mar 23 2022 Adam Williamson - 2.06-29 +- Fix a syntax error in the ostree BLS fix attempt + +* Wed Mar 23 2022 Peter Robinson 2.06-28 +- Rebuild for secure-boot signing + +* Tue Mar 22 2022 Adam Williamson - 2.06-27 +- Revert "Use my sort patch instead", it broke Rawhide +- Tweak BLS skipping on ostree to work in chroots (I hope) +- Resolves: #2066969 +- Resolves: #2059776 + +* Tue Mar 22 2022 Robbie Harwood - 2.06-26 +- Fix rebase on x509 embedding patch + +* Mon Mar 21 2022 Robbie Harwood - 2.06-25 +- Use my sort patch instead + +* Mon Mar 21 2022 Robbie Harwood - 2.06-24 +- Fix missing format specifier in appended signature commit + +* Fri Mar 18 2022 Robbie Harwood - 2.06-23 +- Don't verify kernels twice + +* Thu Mar 10 2022 Robbie Harwood - 2.06-22 +- Skip updating BLS on ostree installations +- Resolves: #2059776 + +* Wed Mar 09 2022 Robbie Harwood - 2.06-21 +- Fix initialization in efidisk patch + +* Mon Feb 28 2022 Robbie Harwood - 2.06-20 +- Disable the .package_note awfulness +- Resolves: #2058712 +- Resolves: #2058527 + +* Fri Feb 25 2022 Robbie Harwood - 2.06-19 +- Fix stripping of annobin -spec + +* Thu Feb 24 2022 Robbie Harwood - 2.06-18 +- Add efidisk/connectefi patches + +* Thu Feb 24 2022 Robbie Harwood - 2.06-17 +- Fix appended signature support commit (thanks: pjones) + +* Thu Feb 24 2022 Robbie Harwood - 2.06-16 +- Suffer through updating gnulib + +* Thu Jan 20 2022 Robbie Harwood - 2.06-15 +- Skip machine ID check when updating BLS + +* Tue Jan 18 2022 Robbie Harwood - 2.06-14 +- Add location of DejaVu Sans font + +* Mon Jan 17 2022 Robbie Harwood - 2.06-13 +- Update patches; minor changes at most, if correct + +* Thu Jan 06 2022 Robbie Harwood - 2.06-12 +- btrfs: use full bootloader area + +* Fri Dec 10 2021 Robbie Harwood - 2.06-11 +- Bump to rerun signing (no code changes) + +* Thu Dec 09 2021 Robbie Harwood - 2.06-10 +- restore umask for grub.cfg (CVE-2021-3981) + +* Thu Nov 04 2021 Robbie Harwood - 2.06-9 +- Drop UI patches and update provenance information + +* Thu Oct 07 2021 Peter Jones - 2.06-8 +- Fix "grub2-mkimage --appended-signature-size" parsing. + +* Wed Sep 29 2021 Robbie Harwood - 2.06-7 +- Rebuild; no code changes + +* Wed Sep 29 2021 Robbie Harwood - 2.06-6 +- fs/xfs: Fix unreadable filesystem with v4 superblock +- Arm: check for the PE magic for the compiled arch +- Resolves: rhbz#2008819 + +* Mon Aug 30 2021 Javier Martinez Canillas - 2.06-5 +- A few fixes for ppc64le LPAR Secure Boot support + +* Tue Aug 24 2021 Peter Jones - 2.06-4 +- Fix aarch64 kernel alignment. +- Fix annobin regexp on ppc64le + +* Tue Jul 06 2021 Javier Martinez Canillas - 2.06-3 +- Add luks2 to GRUB_MODULES +- 20-grub-install: Create a symvers.gz symbolic link +- 20-grub-install: Always use fedora as the boot entry --class + Resolves: rhbz#1957014 +- grub.macros: Install font in /boot/grub2 instead of the ESP + Resolves: rhbz#1739762 +- grub.macros: Use consistent file mode for legacy and EFI + Resolves: rhbz#1965794 +- Drop grub2 prelink configuration + Resolves: rhbz#1659675 +- Remove triggers needed to upgrade from legacy GRUB +- Don't harcode grub2 in the spec file +- Update to unifont-13.0.06 + Resolves: rhbz#1939125 +- 20-grub-install: Use relative paths for btrfs in BLS snippets + Resolves: rhbz#1906191 +- Don't update the cmdline when generating legacy menuentry commands +- Suppress gettext error message + Resolves: rhbz#1592124 +- grub-boot-success.timer: Only run if not in a container + Resolves: rhbz#1914571 +- grub-set-password: Always use /boot/grub2/user.cfg as password default + Resolves: rhbz#1955294 +- Remove outdated URL for BLS document + Resolves: rhbz#1926453 +- templates: Check for EFI at runtime instead of config generation time + Resolves: rhbz#1823864 +- efi: Print an error if boot to firmware setup is not supported + Resolves: rhbz#1823864 + +* Tue Jun 15 2021 Javier Martinez Canillas - 2.06-2 +- Only try to generate a config if the ESP is mounted + +* Mon Jun 14 2021 Javier Martinez Canillas - 2.06-1 +- Update to 2.06 final release and ton of fixes + +* Mon May 03 2021 Javier Martinez Canillas - 2.06~rc1-7 +- Add XFS needsrepair support + +* Fri Apr 23 2021 Javier Martinez Canillas - 2.06~rc1-6 +- Find and claim more memory for ieee1275 (dja) + +* Wed Apr 14 2021 Javier Martinez Canillas - 2.06~rc1-5 +- Add XFS bigtime support (cmaiolino) + +* Mon Apr 12 2021 Javier Martinez Canillas - 2.06~rc1-4 +- Add again 20_linux_xen script fix that got dropped by mistake + Resolves: rhbz#1858364 + +* Thu Mar 25 2021 Javier Martinez Canillas - 2.06~rc1-3 +- Prevent %%posttrans scriptlet to fail if grubenv isn't present in the ESP + +* Wed Mar 24 2021 Javier Martinez Canillas - 2.06~rc1-2 +- Fix a couple of merge mistakes made when rebasing to 2.06~rc1 + Resolves: rhbz#1940524 + +* Fri Mar 12 2021 Javier Martinez Canillas - 2.06~rc1-1 +- Update to 2.06~rc1 to fix a bunch of CVEs + Resolves: CVE-2020-14372 + Resolves: CVE-2020-25632 + Resolves: CVE-2020-25647 + Resolves: CVE-2020-27749 + Resolves: CVE-2020-27779 + Resolves: CVE-2021-20225 + Resolves: CVE-2021-20233 + +* Thu Mar 11 2021 Javier Martinez Canillas - 2.04-39 +- Fix config file generation failing due invalid petitboot version value + Resolves: rhbz#1921479 + +* Fri Mar 05 2021 Javier Martinez Canillas - 2.04-38 +- Fix keyboards that report IBM PC AT scan codes (rmetrich) + +* Thu Feb 25 2021 Javier Martinez Canillas - 2.04-37 +- Don't attempt to unify if there is no grub.cfg on EFI (gicmo) + Resolves: rhbz#1933085 + +* Mon Feb 22 2021 Javier Martinez Canillas - 2.04-36 +- Switch EFI users to new unified config + Resolves: rhbz#1918817 +- Fix ESC key no longer showing the menu + Resolves: rhbz#1928595 + +* Mon Feb 08 2021 Javier Martinez Canillas - 2.04-35 +- Remove -fcf-protection compiler flag to allow i386 builds (law) + Related: rhbz#1915452 +- Unify GRUB configuration file location across all platforms + Related: rhbz#1918817 +- Add 'at_keyboard_fallback_set' var to force the set manually (rmetrich) +- Add appended signatures support for ppc64le LPAR Secure Boot (daxtens) + +* Tue Jan 12 2021 Javier Martinez Canillas - 2.04-34 +- at_keyboard: use set 1 when keyboard is in Translate mode (rmetrich) + +* Thu Dec 31 2020 Javier Martinez Canillas - 2.04-33 +- Add DNF protected.d fragments for GRUB packages + Resolves: rhbz#1874541 + - Include keylayouts and at_keyboard modules in EFI builds + - Add GRUB enhanced debugging features + - ieee1275: Avoiding many unecessary open/close + - ieee1275: device mapper and fibre channel discovery support + - Fix tps-rpmtest failing due /boot/grub2/grubenv attributes mismatch + +* Thu Nov 12 2020 Peter Hazenberg - 2.04-32 +- Fixed some typos in grub-install.8 man page + +* Mon Aug 31 2020 Javier Martinez Canillas - 2.04-31 +- Roll over TFTP block counter to prevent timeouts with data packets + Resolves: rhbz#1869335 + +* Fri Aug 21 2020 Javier Martinez Canillas - 2.04-30 +- Set TFTP blocksize to 1428 instead of 2048 to avoid IP fragmentation + Resolves: rhbz#1869335 + +* Fri Aug 21 2020 Javier Martinez Canillas - 2.04-29 +- Fix TFTP timeouts when trying to fetch files larger than 65535 KiB + Resolves: rhbz#1869335 + +* Wed Aug 12 2020 Javier Martinez Canillas - 2.04-28 +- Add support for "systemctl reboot --boot-loader-menu=xx" (hdegoede) + Related: rhbz#1857389 + +* Mon Aug 10 2020 Peter Jones - 2.04-27 +- Attempt to enable dual-signing in f33 +- "Minor" bug fixes. For f33: + Resolves: CVE-2020-10713 + Resolves: CVE-2020-14308 + Resolves: CVE-2020-14309 + Resolves: CVE-2020-14310 + Resolves: CVE-2020-14311 + Resolves: CVE-2020-15705 + Resolves: CVE-2020-15706 + Resolves: CVE-2020-15707 + +* Tue Jun 30 2020 Jeff Law - 2.04-26 +- Disable LTO + +* Thu Jun 18 2020 Javier Martinez Canillas - 2.04-25 +- Only mark GRUB as BLS supported in OSTree systems with a boot partition + +* Mon Jun 08 2020 Javier Martinez Canillas - 2.04-24 +- http: Prepend prefix when the HTTP path is relative as done in efi/http +- Fix build with rpm-4.16 (thierry.vignaud) + +* Fri Jun 05 2020 Javier Martinez Canillas - 2.04-23 +- Install GRUB as \EFI\BOOT\BOOTARM.EFI in armv7hl + +* Tue May 26 2020 Javier Martinez Canillas - 2.04-22 +- Fix an out of memory error when loading large initrd images + Resolves: rhbz#1838633 + +* Wed May 20 2020 Javier Martinez Canillas - 2.04-21 +- Don't update BLS files that aren't managed by GRUB scripts + Resolves: rhbz#1837783 + +* Mon May 18 2020 Javier Martinez Canillas - 2.04-20 +- Only enable the tpm module for EFI platforms + +* Sat May 16 2020 Javier Martinez Canillas - 2.04-19 +- Enable tpm module and make system to boot even if TPM measurements fail + Resolves: rhbz#1836433 + +* Thu May 14 2020 Adam Williamson - 2.04-18 +- 10_linux.in: restore existence check in `get_sorted_bls` + Resolves: rhbz#1836020 + +* Wed May 13 2020 Javier Martinez Canillas - 2.04-17 +- Store cmdline in BLS snippets instead of using a grubenv variable + +* Tue May 12 2020 Javier Martinez Canillas - 2.04-16 +- Fix a segfault in grub2-editenv when attempting to shrink a variable + +* Thu Apr 30 2020 Javier Martinez Canillas - 2.04-15 +- blscfg: Lookup default_kernelopts variable as fallback for options + Related: rhbz#1765297 +- 10_linux.in: fix early exit due error when reading petitboot version + Resolves: rhbz#1827397 + +* Thu Apr 23 2020 Javier Martinez Canillas - 2.04-14 +- efi: Set image base address before jumping to the PE/COFF entry point + Resolves: rhbz#1825411 + +* Thu Apr 16 2020 Javier Martinez Canillas - 2.04-13 +- Make the grub-switch-to-blscfg and 10_linux scripts more robust + +* Thu Apr 02 2020 Javier Martinez Canillas - 2.04-12 +- Merge 10_linux_bls logic into 10_linux and avoid issues if blsdir is set + +* Thu Mar 26 2020 Javier Martinez Canillas - 2.04-11 +- grub-switch-to-blscfg: Update grub2 binary in ESP for OSTree systems + Related: rhbz#1751272 + +* Tue Mar 17 2020 Javier Martinez Canillas - 2.04-10 +- Fix for entries having an empty initrd command and HTTP boot issues + Resolves: rhbz#1806022 + +* Thu Jan 16 2020 Javier Martinez Canillas - 2.04-9 +- Add riscv64 support to grub.macros and RISC-V build fixes (davidlt) +- blscfg: Always use the root variable to search for BLS snippets +- bootstrap.conf: Force autogen.sh to use python3 + +* Mon Jan 13 2020 Javier Martinez Canillas - 2.04-8 +- Make the blscfg module honour the GRUB_SAVEDEFAULT option (fritz) + Resolves: rhbz#1704926 + +* Mon Jan 06 2020 Peter Jones - 2.04-7 +- Add zstd to the EFI module list. + Related: rhbz#1418336 + +* Thu Dec 05 2019 Javier Martinez Canillas - 2.04-6 +- Various grub2 cleanups (pbrobinson) +- Another fix for blscfg variable expansion support +- blscfg: Add support for sorting the plus ('+') higher than base version + Resolves: rhbz#1767395 + +* Wed Nov 27 2019 Javier Martinez Canillas - 2.04-5 +- blscfg: add a space char when appending fields for variable expansion +- grub.d: Fix boot_indeterminate getting set on boot_success=0 boot + +* Tue Nov 26 2019 Javier Martinez Canillas - 2.04-4 +- grub-set-bootflag: Write new env to tmpfile and then rename (hdegoede) + Resolves: CVE-2019-14865 + Resolves: rhbz#1776580 + +* Thu Oct 17 2019 Javier Martinez Canillas - 2.04-3 +- 20-grub-install: Don't add an id field to generated BLS snippets +- 99-grub-mkconfig: Disable BLS usage for Xen machines + Resolves: rhbz#1703700 +- Don't add a class option to menu entries generated for ppc64le + Resolves: rhbz#1758225 +- 10_linux.in: Also use GRUB_CMDLINE_LINUX_DEFAULT to set kernelopts +- blscfg: Don't hardcode an env var as fallback for the BLS options field + Resolves: rhbz#1710483 + +* Wed Sep 18 2019 Javier Martinez Canillas - 2.04-2 +- A couple of RISC-V fixes +- Remove grub2-tools %%posttrans scriptlet that migrates to a BLS config +- Add blscfg device tree support + Resolves: rhbz#1751307 + +* Thu Aug 15 2019 Javier Martinez Canillas - 2.04-1 +- Update to 2.04 + Resolves: rhbz#1727279 + +* Wed Aug 07 2019 Javier Martinez Canillas - 2.02-97 +- Include regexp module in EFI builds + +* Thu Aug 01 2019 Javier Martinez Canillas - 2.02-96 +- Manual build for the Fedora 31 mass rebuild to succeed + +* Thu Jul 25 2019 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Thu Jul 18 2019 Javier Martinez Canillas - 2.02-94 +- 20-grub-install: Restore default SELinux security contexts for BLS files + Resolves: rhbz#1726020 + +* Wed Jul 17 2019 Javier Martinez Canillas - 2.02-93 +- Add btrfs snapshot submenu when BLS configuration is used +- Move grub2-probe to the grub2-tools-minimal subpackage + Resolves: rhbz#1715994 + +* Tue Jul 16 2019 Javier Martinez Canillas - 2.02-92 +- Cleanup our patchset to reduce the number of patches + +* Sat Jul 13 2019 Javier Martinez Canillas - 2.02-91 +- Includes security modules in Grub2 EFI builds (benjamin.doron) + Resolves: rhbz#1722938 +- Enable again multiboot and multiboot2 modules on EFI builds + Resolves: rhbz#1703872 + +* Fri Jul 05 2019 Javier Martinez Canillas - 2.02-90 +- Fix failure to request grub.cfg over HTTP +- Some ARM fixes (pbrobinson) +- Preserve multi-device workflows (Yclept Nemo) + +* Thu Jun 27 2019 Javier Martinez Canillas - 2.02-89 +- Fix --bls-directory option comment in grub2-switch-to-blscfg man page + Resolves: rhbz#1714835 +- 10_linux_bls: use '=' to separate --id argument due a Petitboot bug +- grub-set-bootflag: Print an error if failing to read from grubenv + Resolves: rhbz#1702354 +- 10_linux: generate BLS section even if no kernels are found in /boot +- 10_linux: don't search for OSTree kernels + +* Tue Jun 18 2019 Sergio Durigan Junior - 2.02-88 +- Use '-g' instead of '-g3' when compiling grub2. + Resolves: rhbz#1708780 + +* Tue Jun 11 2019 Javier Martinez Canillas - 2.02-87 +- Rebuild for RPM 4.15 + +* Mon Jun 10 22:13:19 CET 2019 Igor Gnatenko +- Rebuild for RPM 4.15 + +* Mon Jun 10 15:42:01 CET 2019 Igor Gnatenko +- Rebuild for RPM 4.15 + +* Mon May 20 2019 Javier Martinez Canillas - 2.02-84 +- Don't try to switch to a BLS config if GRUB_ENABLE_BLSCFG is already set + +* Wed May 15 2019 Javier Martinez Canillas - 2.02-83 +- Fix error messages wrongly being printed when executing blscfg command + Resolves: rhbz#1699761 +- Remove bogus load_env after blscfg command in 10_linux + +* Tue May 07 2019 Javier Martinez Canillas - 2.02-82 +- Make blscfg module compatible at least up to the Fedora 19 GRUB core + Related: rhbz#1652806 + +* Fri May 03 2019 Neal Gompa - 2.02-81 +- Add grub2-mount to grub2-tools-minimal subpackage + Resolves: rhbz#1471267 + +* Fri May 03 2019 Javier Martinez Canillas - 2.02-80 +- Add grub2-emu subpackage + +* Fri May 03 2019 Tim Landscheidt - 2.02-79 +- Fix description of grub2-pc + Resolves: rhbz#1484298 + +* Thu Apr 18 2019 Javier Martinez Canillas - 2.02-78 +- Add 10_reset_boot_success to Makefile + Related: rhbz#17010 + +* Thu Apr 18 2019 Javier Martinez Canillas - 2.02-77 +- Never remove boot loader configuration for other boot loaders from the ESP. + This would render machines with sd-boot unbootable (zbyszek) +- Execute grub2-switch-to-blscfg script in %%posttrans instead of %%post +- grub.d: Split out boot success reset from menu auto hide script (lorbus) +- HTTP boot: strncmp returns 0 on equal (stephen) +- Some grub2-emu fixes and make it to not print unnecessary messages +- Don't assume that boot commands will only return on fail + +* Thu Mar 28 2019 Javier Martinez Canillas - 2.02-76 +- 10_linux_bls: don't add --users option to generated menu entries + Resolves: rhbz#1693515 + +* Tue Mar 26 2019 Javier Martinez Canillas - 2.02-75 +- A set of EFI fixes to support arm64 QCom UEFI firmwares (pbrobinson) + +* Fri Mar 22 2019 Javier Martinez Canillas - 2.02-74 +- Fix some BLS snippets not being displayed in the GRUB menu + Resolves: rhbz#1691232 +- Fix possible undefined behaviour due wrong grub_efi_status_t type (pjones) + +* Wed Mar 20 2019 Javier Martinez Canillas - 2.02-73 +- Only set blsdir if /boot/loader/entries is in a btrfs or zfs partition + Related: rhbz#1688453 + +* Mon Mar 11 2019 Javier Martinez Canillas - 2.02-72 +- Avoid grub2-efi package to overwrite existing /boot/grub2/grubenv file + Resolves: rhbz#1687323 +- Switch to BLS in tools package %%post scriptlet + Resolves: rhbz#1652806 + +* Wed Feb 27 2019 Javier Martinez Canillas - 2.02-71 +- 20-grub-install: Replace, rather than overwrite, the existing kernel (pjones) + Resolves: rhbz#1642402 +- 99-grub-mkconfig: Don't update grubenv generating entries on ppc64le + Related: rhbz#1637875 +- blscfg: fallback to default_kernelopts if BLS option field isn't set + Related: rhbz#1625124 +- grub-switch-to-blscfg: copy increment.mod for legacy BIOS and ppc64 + Resolves: rhbz#1652806 + +* Fri Feb 15 2019 Javier Martinez Canillas - 2.02-70 +- Check if blsdir exists before attempting to get it's real path + Resolves: rhbz#1677415 + +* Wed Feb 13 2019 Javier Martinez Canillas - 2.02-69 +- Don't make grub_strtoull() print an error if no conversion is performed + Resolves: rhbz#1674512 +- Set blsdir if the BLS directory path isn't one of the looked up by default + Resolves: rhbz#1657240 + +* Mon Feb 04 2019 Javier Martinez Canillas - 2.02-68 +- Don't build the grub2-efi-ia32-* packages on i686 (pjones) +- Add efi-export-env and efi-load-env commands (pjones) +- Make it possible to subtract conditions from debug= (pjones) +- Try to set -fPIE and friends on libgnu.a (pjones) +- Add more options to blscfg command to make it more flexible +- Add support for prepend early initrds to the BLS entries +- Fix grub.cfg-XXX look up when booting over TFTP + +* Fri Feb 01 2019 Fedora Release Engineering +- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild + +* Mon Dec 17 2018 Javier Martinez Canillas - 2.02-66 +- Don't exclude /etc/grub.d/01_fallback_counting anymore + +* Tue Dec 11 2018 Javier Martinez Canillas - 2.02-65 +- BLS files should only be copied by grub-switch-to-blscfg if BLS isn't set + Related: rhbz#1638117 +- Fix get_entry_number() wrongly dereferencing the tail pointer + Resolves: rhbz#1654936 +- Make grub2-mkconfig to honour GRUB_CMDLINE_LINUX in /etc/default/grub + Resolves: rhbz#1637875 + +* Fri Nov 30 2018 Javier Martinez Canillas - 2.02-64 +- Add comments and revert logic changes in 01_fallback_counting +- Remove quotes when reading ID value from /etc/os-release + Related: rhbz#1650706 +- blscfg: expand grub_users before passing to grub_normal_add_menu_entry() + Resolves: rhbz#1650706 +- Drop buggy downstream patch "efinet: retransmit if our device is busy" + Resolves: rhbz#1649048 +- Make the menu entry users option argument to be optional + Related: rhbz#1652434 +- 10_linux_bls: add missing menu entries options + Resolves: rhbz#1652434 +- Drop "Be more aggro about actually using the *configured* network device." + Resolves: rhbz#1654388 +- Fix menu entry selection based on title + Resolves: rhbz#1654936 + +* Wed Nov 21 2018 Javier Martinez Canillas - 2.02-63 +- add 10_linux_bls grub.d snippet to generate menu entries from BLS files + Resolves: rhbz#1636013 +- Only set kernelopts in grubenv if it wasn't set before + Resolves: rhbz#1636466 +- kernel-install: Remove existing initramfs if it's older than the kernel (pjones) + Resolves: rhbz#1638405 +- Update the saved entry correctly after a kernel install (pjones) + Resolves: rhbz#1638117 +- blscfg: sort everything with rpm *package* comparison (pjones) + Related: rhbz#1638103 +- blscfg: Make 10_linux_bls sort the same way as well + Related: rhbz#1638103 +- don't set saved_entry on grub2-mkconfig + Resolves: rhbz#1636466 +- Fix menu entry selection based on ID and title (pjones) + Resolves: rhbz#1640979 +- Don't unconditionally set default entry when installing debug kernels + Resolves: rhbz#1636346 +- Remove installkernel-bls script + Related: rhbz#1647721 + +* Thu Oct 04 2018 Peter Jones - 2.02-62 +- Exclude /etc/grub.d/01_fallback_counting until we work through some design + questions. + Resolves: rhbz#1614637 + +* Wed Oct 03 2018 Peter Jones - 2.02-61 +- Fix the fallback counting script even harder. Apparently, this wasn't + tested well enough. + Resolves: rhbz#1614637 + +* Tue Oct 02 2018 Peter Jones - 2.02-60 +- Fix grub.cfg boot counting snippet generation (lorbus) + Resolves: rhbz#1614637 +- Fix spurrious allocation error reporting on EFI boot + Resolves: rhbz#1635319 +- Stop doing TPM on BIOS *again*. It just doesn't work. + Related: rhbz#1579835 +- Make blscfg module loadable on older grub2 i386-pc and powerpc-ieee1275 + builds +- Fix execstack cropping up in grub2-tools +- Ban stack trampolines with compiler flags. + +* Tue Sep 25 2018 Hans de Goede - 2.02-59 +- Stop using pkexec for grub2-set-bootflag, it does not work under gdm + instead make it suid root (it was written with this in mind) + +* Tue Sep 25 2018 Peter Jones +- Use bounce buffers for addresses above 4GB +- Allow initramfs, cmdline, and params >4GB, but not kernel + +* Wed Sep 12 2018 Peter Jones - 2.02-58 +- Add 2 conditions to boot-success timer and service: + - Don't run it for system users + Resolves: rhbz#1592201 + - Don't run it when pkexec isn't available + Resolves: rhbz#1619445 +- Use -Wsign-compare -Wconversion -Wextra in the build. + +* Tue Sep 11 2018 Peter Jones - 2.02-57 +- Limit grub_malloc() on x86_64 to < 31bit addresses, as some devices seem to + have a colossally broken storage controller (or UEFI driver) that can't do + DMA to higher memory addresses, but fails silently. + Resolves: rhbz#1626844 (possibly really resolving it this time.) +- Also integrate Hans's attempt to fix the related error from -54, but do it + the other way around: try the low addresses first and *then* the high one if + the allocation fails. This way we'll get low regions by default, and if + kernel/initramfs don't fit anywhere, it'll try the higher addresses. + Related: rhbz#1624532 +- Coalesce all the intermediate debugging junk from -54/-55/-56. + +* Tue Sep 11 2018 Peter Jones - 2.02-56 +- Don't mangle fw_path even harder. + Resolves: rhbz#1626844 +- Fix reboot being missing on some platforms, and make it alias to + "reset" as well. +- More dprintf(). + +* Mon Sep 10 2018 Peter Jones - 2.02-55 +- Fix UEFI memory problem in a different way. + Related: rhbz#1624532 +- Don't mangle fw_path with a / unless we're on http + Resolves: rhbz#1626844 + +* Fri Sep 07 2018 Kevin Fenzi - 2.02-54 +- Add patch from https://github.com/rhboot/grub2/pull/30 to fix uefi booting + Resolves: rhbz#1624532 + +* Thu Aug 30 2018 Peter Jones - 2.02-53 +- Fix AArch64 machines with no RAM latched lower than 1GB + Resolves: rhbz#1615969 +- Set http_path and http_url when HTTP booting +- Hopefully slightly better error reporting in some cases +- Better allocation of kernel+initramfs on x86_64 and aarch64 + Resolves: rhbz#1572126 + +* Mon Aug 20 2018 Peter Jones - 2.02-52 +- Update conflicts on grubby not to care about %%{?dist} + +* Sun Aug 19 2018 Peter Jones - 2.02-51 +- Make it quieter. + +* Thu Aug 16 2018 Peter Jones - 2.02-50 +- Fix arm32 off-by-one error on reading the PE header. + +* Tue Aug 14 2018 Peter Jones - 2.02-50 +- Fix typo in /etc/grub.d/01_fallback_counting + Resolves: rhbz#1614637 + +* Fri Aug 10 2018 Javier Martinez Canillas - 2.02-50 +- Add an installkernel script for BLS configurations + +* Tue Aug 07 2018 Peter Jones - 2.02-49 +- Temporarily make -cdboot perms 0700 again. + +* Fri Aug 03 2018 Peter Jones - 2.02-48 +- Kill .note.gnu.property with fire. + Resolves: rhbz#1612339 + +* Thu Aug 02 2018 Peter Jones - 2.02-47 +- Enable armv7 EFI builds. This was way harder than I expected. + +* Tue Jul 17 2018 Peter Jones - 2.02-46 +- Fix some minor BLS issues +- Rework the FDT module linking to make aarch64 build and boot right + +* Mon Jul 16 2018 pjones - 2.02-45 +- Rework SB patches and 10_linux.in changes even harder. + Resolves: rhbz#1601578 + +* Mon Jul 16 2018 Hans de Goede - 2.02-44 +- Make the user session automatically set the boot_success grubenv flag +- Make offline-updates increment the boot_indeterminate grubenv variable + +* Mon Jul 16 2018 pjones - 2.02-43 +- Rework SB patches and 10_linux.in changes + +* Fri Jul 13 2018 Peter Jones - 2.02-42 +- Revert broken moduledir fix *again*. + +* Thu Jul 12 2018 Peter Jones - 2.02-41 +- Fix our linuxefi/linux command reunion. + +* Wed Jul 11 2018 Peter Jones - 2.02-40 +- Port several fixes from the F28 tree and a WIP tree. + +* Mon Jul 09 2018 pjones - 2.02-39 +- Fix my fix of grub2-switch-to-blscfg (javierm and pjones) + +* Mon Jul 02 2018 Javier Martinez Canillas - 2.02-38 +- Use BLS fragment filename as menu entry id and for sort criterion + +* Tue Jun 26 2018 Javier Martinez Canillas +- Cleanups and fixes for grub2-switch-to-blscfg (pjones) +- Use /boot/loader/entries as BLS dir also on EFI (javierm) + +* Tue Jun 19 2018 Peter Jones - 2.02-37 +- Fix some TPM errors on 32-bit (hdegoede) +- More fixups to avoid compiler changes (pjones) +- Put lsmmap into the EFI builds (pjones) + Related: rhbz#1572126 +- Make 20-grub.install to exit if there is no machine ID set (javierm) + Resolves: rhbz#1576573 +- More fixes for BLS (javierm) + Resolves: rhbz#1588184 + +* Wed May 16 2018 Peter Jones - 2.02-37.fc29 +- Fixups to work with gcc 8 +- Experimental https boot support on UEFI +- XFS fixes for sparse inode support + Resolves: rhbz#1575797 + +* Thu May 10 2018 Javier Martinez Canillas - 2.02-36 +- Use version field to sort BLS entries if id field isn't defined +- Add version field to BLS fragments generated by 20-grub.install + +* Tue Apr 24 2018 Peter Jones - 2.02-35 +- A couple of fixes needed by Fedora Atomic - javierm + +* Mon Apr 23 2018 Peter Jones - 2.02-34 +- Put the os-prober dep back in - we need to change test plans and criteria + before it can go. + Resolves: rhbz#1569411 + +* Wed Apr 11 2018 Peter Jones - 2.02-33 +- Work around some issues with older automake found in CentOS. +- Make multiple initramfs images work in BLS. + +* Wed Apr 11 2018 Javier Martinez Canillas - 2.02-32 +- Make 20-grub.install to generate debug BLS when MAKEDEBUG is set. + +* Fri Apr 06 2018 Peter Jones - 2.02-31 +- Pull in some TPM fixes I missed. + +* Fri Apr 06 2018 Peter Jones - 2.02-30 +- Enable TPM measurements +- Set the default boot entry to the first entry when we're using BLS. + +* Tue Apr 03 2018 Peter Jones - 2.02-29 +- Fix for BLS paths on BIOS / non-UEFI (javierm) + +* Fri Mar 16 2018 Peter Jones - 2.02-28 +- Install kernel-install scripts. (javierm) +- Add grub2-switch-to-blscfg + +* Tue Mar 06 2018 Peter Jones - 2.02-27 +- Build the blscfg module in on EFI builds. + +* Wed Feb 28 2018 Peter Jones - 2.02-26 +- Try to fix things for new compiler madness. + I really don't know why gcc decided __attribute__((packed)) on a "typedef + struct" should imply __attribute__((align (1))) and that it should have a + warning that it does so. The obvious behavior would be to keep the alignment + of the first element unless it's used in another object or type that /also/ + hask the packed attribute. Why should it change the default alignment at + all? +- Merge in the BLS patches Javier and I wrote. +- Attempt to fix pmtimer initialization failures to not be super duper slow. + +* Fri Feb 09 2018 Igor Gnatenko +- Escape macros in %%changelog + +* Tue Jan 23 2018 Peter Jones - 2.02-24 +- Fix a merge error from 2.02-21 that affected kernel loading on Aarch64. + Related: rhbz#1519311 + Related: rhbz#1506704 + Related: rhbz#1502312 + +* Fri Jan 19 2018 Peter Jones - 2.02-23 +- Only nerf annobin, not -fstack-crash-protection. +- Fix a conflict on /boot/efi directory permissions between -cdboot and the + normal bootloader. + +* Thu Jan 18 2018 Peter Jones - 2.02-22 +- Nerf some gcc 7.2.1-6 'features' that cause grub to crash on start. + +* Thu Jan 18 2018 Peter Jones - 2.02-21 +- Fix grub2-efi-modules provides/obsoletes generation + Resolves: rhbz#1506704 +- *Also* build grub-efi-ia32{,-*,!-modules} packages for i686 builds + Resolves: rhbz#1502312 +- Make everything under /boot/efi be mode 0700, since that's what FAT will + show anyway. + +* Wed Jan 17 2018 Peter Jones - 2.02-20 +- Update to newer upstream for F28 +- Pull in patches for Apollo Lake hardware + Resolves: rhbz#1519311 + +* Tue Oct 24 2017 Peter Jones - 2.02-19 +- Handle xen module loading (somewhat) better + Resolves: rhbz#1486002 + +* Wed Sep 20 2017 Peter Jones - 2.02-18 +- Make grub2-efi-aa64 provide grub2 + Resolves: rhbz#1491045 + +* Mon Sep 11 2017 Dennis Gilmore - 2.02-17 +- bump for Obsoletes again + +* Wed Sep 06 2017 Peter Jones - 2.02-16 +- Fix Obsoletes on grub2-pc + +* Wed Aug 30 2017 Petr Šabata - 2.02-15 +- Limit the pattern matching in do_alt_efi_install to files to + unbreak module builds + +* Fri Aug 25 2017 Peter Jones - 2.02-14 +- Revert the /usr/lib/.build-id/ change: + https://fedoraproject.org/wiki/Changes/ParallelInstallableDebuginfo + says (without any particularly convincing reasoning): + The main build-id file should not be in the debuginfo file, but in the + main package (this was always a problem since the package and debuginfo + package installed might not match). If we want to make usr/lib/debug/ a + network resource then we will need to move the symlink to another + location (maybe /usr/lib/.build-id). + So do it that way. Of course it doesn't matter, because exclude gets + ignored due to implementation details. + +* Fri Aug 25 2017 Peter Jones - 2.02-13 +- Add some unconditional Provides: + grub2-efi on grub2-efi-${arch} + grub2-efi-cdboot on grub2-efi-${arch}-cdboot + grub2 on all grub2-${arch} pacakges +- Something is somehow adding /usr/lib/.build-id/... to all the -tools + subpackages, so exclude all that. + +* Thu Aug 24 2017 Peter Jones - 2.02-12 +- Fix arm kernel command line allocation + Resolves: rhbz#1484609 +- Get rid of the temporary extra efi packages hack. + +* Wed Aug 23 2017 Peter Jones - 2.02-11 +- Put grub2-mkimage in -tools, not -tools-extra. +- Fix i686 building +- Fix ppc HFS+ usage due to /boot/efi's presence. + +* Fri Aug 18 2017 Peter Jones - 2.02-10 +- Add the .img files into grub2-pc-modules (and all legacy variants) + +* Wed Aug 16 2017 Peter Jones - 2.02-9 +- Re-work for ia32-efi. + +* Wed Aug 16 2017 pjones - 2.02-8 +- Rebased to newer upstream for fedora-27 + +* Tue Aug 15 2017 Peter Jones - 2.02-7 +- Rebuild again with new fixed rpm. (bug #1480407) + +* Fri Aug 11 2017 Kevin Fenzi - 2.02-6 +- Rebuild again with new fixed rpm. (bug #1480407) + +* Thu Aug 10 2017 Kevin Fenzi - 2.02-5 +- Rebuild for rpm soname bump again. + +* Thu Aug 10 2017 Igor Gnatenko - 2.02-4 +- Rebuilt for RPM soname bump + +* Thu Aug 03 2017 Peter Jones - 2.02-3 +- Rebuild so it gets SB signed correctly. + Related: rhbz#1335533 +- Enable lsefi + +* Mon Jul 24 2017 Michael Cronenworth - 2.02-2 +- Fix symlink to work on both EFI and BIOS machines + Resolves: rhbz#1335533 + +* Mon Jul 10 2017 Peter Jones - 2.02-1 +- Rebased to newer upstream for fedora-27 + +* Wed Feb 01 2017 Stephen Gallagher - 2.02-0.39 +- Add missing %%license macro +- Fix deps that should have moved to -tools but didn't. + +* Thu Dec 08 2016 Peter Jones - 2.02-0.38 +- Fix regexp in power compile flags, and synchronize release number with + other branches. + +* Fri Dec 02 2016 pjones - 1:2.02-0.37 +- Rebased to newer upstream for fedora-26 + +* Thu Dec 01 2016 Peter Jones - 2.02-0.36 +- Update version to .36 because I already built an f25 one named 0.35 + +* Thu Dec 01 2016 pjones - 1:2.02-0.35 +- Rebased to newer upstream for fedora-26 + +* Thu Dec 01 2016 Peter Jones - 2.02-0.34 +- Fix power6 makefile bits for newer autoconf defaults. +- efi/chainloader: fix wrong sanity check in relocate_coff() (Laszlo Ersek) + Resolves: rhbz#1347291 + +* Thu Aug 25 2016 Peter Jones - 2.02-0.34 +- Update to be newer than f24's branch. +- Add grub2-get-kernel-settings + Related: rhbz#1226325 + +* Thu Apr 07 2016 pjones - 1:2.02-0.30 +- Revert 27e66193, which was replaced by upstream's 49426e9fd + Resolves: rhbz#1251600 + +* Thu Apr 07 2016 Peter Jones - 2.02-0.29 +- Fix ppc64 build failure and rebase to newer f24 code. + +* Tue Apr 05 2016 pjones - 1:2.02-0.27 +- Pull TPM updates from mjg59. + Resolves: rhbz#1318067 + +* Tue Mar 08 2016 pjones - 1:2.02-0.27 +- Fix aarch64 build problem. + +* Fri Mar 04 2016 Peter Jones - 2.02-0.26 +- Rebased to newer upstream (grub-2.02-beta3) for fedora-24 + +* Thu Dec 10 2015 Peter Jones - 2.02-0.25 +- Fix security issue when reading username and password + Related: CVE-2015-8370 +- Do a better job of handling GRUB2_PASSWORD + Related: rhbz#1284370 + +* Fri Nov 20 2015 Peter Jones - 2.02-0.24 +- Rebuild without multiboot* modules in the EFI image. + Related: rhbz#1264103 + +* Sat Sep 05 2015 Kalev Lember - 2.02-0.23 +- Rebuilt for librpm soname bump + +* Wed Aug 05 2015 Peter Jones - 2.02-0.21 +- Back out one of the debuginfo generation patches; it doesn't work right on + aarch64 yet. + Resolves: rhbz#1250197 + +* Mon Aug 03 2015 Peter Jones - 2.02-0.20 +- The previous fix was completely not right, so fix it a different way. + Resolves: rhbz#1249668 + +* Fri Jul 31 2015 Peter Jones - 2.02-0.19 +- Fix grub2-mkconfig's sort to put kernels in the right order. + Related: rhbz#1124074 + +* Thu Jul 30 2015 Peter Jones - 2.02-0.18 +- Fix a build failure on aarch64 + +* Wed Jul 22 2015 Peter Jones - 2.02-0.17 +- Don't build hardened (fixes FTBFS) (pbrobinson) +- Reconcile with the current upstream +- Fixes for gcc 5 + +* Tue Apr 28 2015 Peter Jones - 2.02-0.16 +- Make grub2-mkconfig produce the kernel titles we actually want. + Resolves: rhbz#1215839 + +* Sat Feb 21 2015 Till Maas +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Mon Jan 05 2015 Peter Jones - 2.02-0.15 +- Bump release to rebuild with Ralf Corsépius's fixes. + +* Sun Jan 04 2015 Ralf Corsépius - 2.02-0.14 +- Move grub2.info/grub2-dev.info install-info scriptlets into *-tools package. +- Use sub-shell in %%__debug_install_post (RHBZ#1168732). +- Cleanup grub2-starfield-theme packaging. + +* Thu Dec 04 2014 Peter Jones - 2.02-0.13 +- Update minilzo to 2.08 for CVE-2014-4607 + Resolves: rhbz#1131793 + +* Thu Nov 13 2014 Peter Jones - 2.02-0.12 +- Make backtrace and usb conditional on !arm +- Make sure gcdaa64.efi is packaged. + Resolves: rhbz#1163481 + +* Fri Nov 07 2014 Peter Jones - 2.02-0.11 +- fix a copy-paste error in patch 0154. + Resolves: rhbz#964828 + +* Mon Oct 27 2014 Peter Jones - 2.02-0.10 +- Try to emit linux16/initrd16 and linuxefi/initrdefi when appropriate + in 30_os-prober. + Resolves: rhbz#1108296 +- If $fw_path doesn't work to find the config file, try $prefix as well + Resolves: rhbz#1148652 + +* Mon Sep 29 2014 Peter Jones - 2.02-0.9 +- Clean up the build a bit to make it faster +- Make grubenv work right on UEFI machines + Related: rhbz#1119943 +- Sort debug and rescue kernels later than normal ones + Related: rhbz#1065360 +- Allow "fallback" to include entries by title as well as number. + Related: rhbz#1026084 +- Fix a segfault on aarch64. +- Load arm with SB enabled if available. +- Add some serial port options to GRUB_MODULES. + +* Tue Aug 19 2014 Peter Jones - 2.02-0.8 +- Add ppc64le support. + Resolves: rhbz#1125540 + +* Thu Jul 24 2014 Peter Jones - 2.02-0.7 +- Enabled syslinuxcfg module. + +* Wed Jul 02 2014 Peter Jones - 2.02-0.6 +- Re-merge RHEL 7 changes and ARM works in progress. + +* Mon Jun 30 2014 Peter Jones - 2.02-0.5 +- Avoid munging raw spaces when we're escaping command line arguments. + Resolves: rhbz#923374 + +* Tue Jun 24 2014 Peter Jones - 2.02-0.4 +- Update to latest upstream. + +* Thu Mar 13 2014 Peter Jones - 2.02-0.3 +- Merge in RHEL 7 changes and ARM works in progress. + +* Mon Jan 06 2014 Peter Jones - 2.02-0.2 +- Update to grub-2.02~beta2 + +* Sat Aug 10 2013 Peter Jones - 2.00-25 +- Last build failed because of a hardware error on the builder. + +* Mon Aug 05 2013 Peter Jones - 2.00-24 +- Fix compiler flags to deal with -fstack-protector-strong + +* Sat Aug 03 2013 Fedora Release Engineering - 1:2.00-24 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Tue Jul 02 2013 Dennis Gilmore - 2.00-23 +- add epoch to obsoletes + +* Fri Jun 21 2013 Peter Jones - 2.00-22 +- Fix linewrapping in edit menu. + Resolves: rhbz #976643 + +* Thu Jun 20 2013 Peter Jones - 2.00-21 +- Fix obsoletes to pull in -starfield-theme subpackage when it should. + +* Fri Jun 14 2013 Peter Jones - 2.00-20 +- Put the theme entirely ento the subpackage where it belongs (#974667) + +* Wed Jun 12 2013 Peter Jones - 2.00-19 +- Rebase to upstream snapshot. +- Fix PPC build error (#967862) +- Fix crash on net_bootp command (#960624) +- Reset colors on ppc when appropriate (#908519) +- Left align "Loading..." messages (#908492) +- Fix probing of SAS disks on PPC (#953954) +- Add support for UEFI OSes returned by os-prober +- Disable "video" mode on PPC for now (#973205) +- Make grub fit better into the boot sequence, visually (#966719) + +* Fri May 10 2013 Matthias Clasen - 2.00-18 +- Move the starfield theme to a subpackage (#962004) +- Don't allow SSE or MMX on UEFI builds (#949761) + +* Wed Apr 24 2013 Peter Jones - 2.00-17.pj0 +- Rebase to upstream snapshot. + +* Thu Apr 04 2013 Peter Jones - 2.00-17 +- Fix booting from drives with 4k sectors on UEFI. +- Move bash completion to new location (#922997) +- Include lvm support for /boot (#906203) + +* Thu Feb 14 2013 Peter Jones - 2.00-16 +- Allow the user to disable submenu generation +- (partially) support BLS-style configuration stanzas. + +* Tue Feb 12 2013 Peter Jones - 2.00-15.pj0 +- Add various config file related changes. + +* Thu Dec 20 2012 Dennis Gilmore - 2.00-15 +- bump nvr + +* Mon Dec 17 2012 Karsten Hopp 2.00-14 +- add bootpath device to the device list (pfsmorigo, #886685) + +* Tue Nov 27 2012 Peter Jones - 2.00-13 +- Add vlan tag support (pfsmorigo, #871563) +- Follow symlinks during PReP installation in grub2-install (pfsmorigo, #874234) +- Improve search paths for config files on network boot (pfsmorigo, #873406) + +* Tue Oct 23 2012 Peter Jones - 2.00-12 +- Don't load modules when grub transitions to "normal" mode on UEFI. + +* Mon Oct 22 2012 Peter Jones - 2.00-11 +- Rebuild with newer pesign so we'll get signed with the final signing keys. + +* Thu Oct 18 2012 Peter Jones - 2.00-10 +- Various PPC fixes. +- Fix crash fetching from http (gustavold, #860834) +- Issue separate dns queries for ipv4 and ipv6 (gustavold, #860829) +- Support IBM CAS reboot (pfsmorigo, #859223) +- Include all modules in the core image on ppc (pfsmorigo, #866559) + +* Mon Oct 01 2012 Peter Jones - 1:2.00-9 +- Work around bug with using "\x20" in linux command line. + Related: rhbz#855849 + +* Thu Sep 20 2012 Peter Jones - 2.00-8 +- Don't error on insmod on UEFI/SB, but also don't do any insmodding. +- Increase device path size for ieee1275 + Resolves: rhbz#857936 +- Make network booting work on ieee1275 machines. + Resolves: rhbz#857936 + +* Wed Sep 05 2012 Matthew Garrett - 2.00-7 +- Add Apple partition map support for EFI + +* Thu Aug 23 2012 David Cantrell - 2.00-6 +- Only require pesign on EFI architectures (#851215) + +* Tue Aug 14 2012 Peter Jones - 2.00-5 +- Work around AHCI firmware bug in efidisk driver. +- Move to newer pesign macros +- Don't allow insmod if we're in secure-boot mode. + +* Wed Aug 08 2012 Peter Jones +- Split module lists for UEFI boot vs UEFI cd images. +- Add raid modules for UEFI image (related: #750794) +- Include a prelink whitelist for binaries that need execstack (#839813) +- Include fix efi memory map fix from upstream (#839363) + +* Wed Aug 08 2012 Peter Jones - 2.00-4 +- Correct grub-mkimage invocation to use efidir RPM macro (jwb) +- Sign with test keys on UEFI systems. +- PPC - Handle device paths with commas correctly. + Related: rhbz#828740 + +* Wed Jul 25 2012 Peter Jones - 2.00-3 +- Add some more code to support Secure Boot, and temporarily disable + some other bits that don't work well enough yet. + Resolves: rhbz#836695 + +* Wed Jul 11 2012 Matthew Garrett - 2.00-2 +- Set a prefix for the image - needed for installer work +- Provide the font in the EFI directory for the same reason + +* Thu Jun 28 2012 Peter Jones - 2.00-1 +- Rebase to grub-2.00 release. + +* Mon Jun 18 2012 Peter Jones - 2.0-0.37.beta6 +- Fix double-free in grub-probe. + +* Wed Jun 06 2012 Peter Jones - 2.0-0.36.beta6 +- Build with patch19 applied. + +* Wed Jun 06 2012 Peter Jones - 2.0-0.35.beta6 +- More ppc fixes. + +* Wed Jun 06 2012 Peter Jones - 2.0-0.34.beta6 +- Add IBM PPC fixes. + +* Mon Jun 04 2012 Peter Jones - 2.0-0.33.beta6 +- Update to beta6. +- Various fixes from mads. + +* Fri May 25 2012 Peter Jones - 2.0-0.32.beta5 +- Revert builddep change for crt1.o; it breaks ppc build. + +* Fri May 25 2012 Peter Jones - 2.0-0.31.beta5 +- Add fwsetup command (pjones) +- More ppc fixes (IBM) + +* Tue May 22 2012 Peter Jones - 2.0-0.30.beta5 +- Fix the /other/ grub2-tools require to include epoch. + +* Mon May 21 2012 Peter Jones - 2.0-0.29.beta5 +- Get rid of efi_uga and efi_gop, favoring all_video instead. + +* Mon May 21 2012 Peter Jones - 2.0-0.28.beta5 +- Name grub.efi something that's arch-appropriate (kiilerix, pjones) +- use EFI/$SOMETHING_DISTRO_BASED/ not always EFI/redhat/grub2-efi/ . +- move common stuff to -tools (kiilerix) +- spec file cleanups (kiilerix) + +* Mon May 14 2012 Peter Jones - 2.0-0.27.beta5 +- Fix module trampolining on ppc (benh) + +* Thu May 10 2012 Peter Jones - 2.0-0.27.beta5 +- Fix license of theme (mizmo) + Resolves: rhbz#820713 +- Fix some PPC bootloader detection IBM problem + Resolves: rhbz#820722 + +* Thu May 10 2012 Peter Jones - 2.0-0.26.beta5 +- Update to beta5. +- Update how efi building works (kiilerix) +- Fix theme support to bring in fonts correctly (kiilerix, pjones) + +* Wed May 09 2012 Peter Jones - 2.0-0.25.beta4 +- Include theme support (mizmo) +- Include locale support (kiilerix) +- Include html docs (kiilerix) + +* Thu Apr 26 2012 Peter Jones - 2.0-0.24 +- Various fixes from Mads Kiilerich + +* Thu Apr 19 2012 Peter Jones - 2.0-0.23 +- Update to 2.00~beta4 +- Make fonts work so we can do graphics reasonably + +* Thu Mar 29 2012 David Aquilina - 2.0-0.22 +- Fix ieee1275 platform define for ppc + +* Thu Mar 29 2012 Peter Jones - 2.0-0.21 +- Remove ppc excludearch lines (dwa) +- Update ppc terminfo patch (hamzy) + +* Wed Mar 28 2012 Peter Jones - 2.0-0.20 +- Fix ppc64 vs ppc exclude according to what dwa tells me they need +- Fix version number to better match policy. + +* Tue Mar 27 2012 Dan Horák - 1.99-19.2 +- Add support for serial terminal consoles on PPC by Mark Hamzy + +* Sun Mar 25 2012 Dan Horák - 1.99-19.1 +- Use Fix-tests-of-zeroed-partition patch by Mark Hamzy + +* Thu Mar 15 2012 Peter Jones - 1.99-19 +- Use --with-grubdir= on configure to make it behave like -17 did. + +* Wed Mar 14 2012 Peter Jones - 1.99-18 +- Rebase from 1.99 to 2.00~beta2 + +* Wed Mar 07 2012 Peter Jones - 1.99-17 +- Update for newer autotools and gcc 4.7.0 + Related: rhbz#782144 +- Add /etc/sysconfig/grub link to /etc/default/grub + Resolves: rhbz#800152 +- ExcludeArch s390*, which is not supported by this package. + Resolves: rhbz#758333 + +* Fri Feb 17 2012 Orion Poplawski - 1:1.99-16 +- Build with -Os (bug 782144) + +* Fri Jan 13 2012 Fedora Release Engineering - 1:1.99-15 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Dec 14 2011 Matthew Garrett - 1.99-14 +- fix up various grub2-efi issues + +* Thu Dec 08 2011 Adam Williamson - 1.99-13 +- fix hardwired call to grub-probe in 30_os-prober (rhbz#737203) + +* Mon Nov 07 2011 Peter Jones - 1.99-12 +- Lots of .spec fixes from Mads Kiilerich: + Remove comment about update-grub - it isn't run in any scriptlets + patch info pages so they can be installed and removed correctly when renamed + fix references to grub/grub2 renames in info pages (#743964) + update README.Fedora (#734090) + fix comments for the hack for upgrading from grub2 < 1.99-4 + fix sed syntax error preventing use of $RPM_OPT_FLAGS (#704820) + make /etc/grub2*.cfg %%config(noreplace) + make grub.cfg %%ghost - an empty file is of no use anyway + create /etc/default/grub more like anaconda would create it (#678453) + don't create rescue entries by default - grubby will not maintain them anyway + set GRUB_SAVEDEFAULT=true so saved defaults works (rbhz#732058) + grub2-efi should have its own bash completion + don't set gfxpayload in efi mode - backport upstream r3402 +- Handle dmraid better. Resolves: rhbz#742226 + +* Wed Oct 26 2011 Fedora Release Engineering - 1:1.99-11 +- Rebuilt for glibc bug#747377 + +* Wed Oct 19 2011 Adam Williamson - 1.99-10 +- /etc/default/grub is explicitly intended for user customization, so + mark it as config(noreplace) + +* Tue Oct 11 2011 Peter Jones - 1.99-9 +- grub has an epoch, so we need that expressed in the obsolete as well. + Today isn't my day. + +* Tue Oct 11 2011 Peter Jones - 1.99-8 +- Fix my bad obsoletes syntax. + +* Thu Oct 06 2011 Peter Jones - 1.99-7 +- Obsolete grub + Resolves: rhbz#743381 + +* Wed Sep 14 2011 Peter Jones - 1.99-6 +- Use mv not cp to try to avoid moving disk blocks around for -5 fix + Related: rhbz#735259 +- handle initramfs on xen better (patch from Marko Ristola) + Resolves: rhbz#728775 + +* Sat Sep 03 2011 Kalev Lember - 1.99-5 +- Fix upgrades from grub2 < 1.99-4 (#735259) + +* Fri Sep 02 2011 Peter Jones - 1.99-4 +- Don't do sysadminny things in %%preun or %%post ever. (#735259) +- Actually include the changelog in this build (sorry about -3) + +* Thu Sep 01 2011 Peter Jones - 1.99-2 +- Require os-prober (#678456) (patch from Elad Alfassa) +- Require which (#734959) (patch from Elad Alfassa) + +* Thu Sep 01 2011 Peter Jones - 1.99-1 +- Update to grub-1.99 final. +- Fix crt1.o require on x86-64 (fix from Mads Kiilerich) +- Various CFLAGS fixes (from Mads Kiilerich) + - -fexceptions and -m64 +- Temporarily ignore translations (from Mads Kiilerich) + +* Thu Jul 21 2011 Peter Jones - 1.99-0.3 +- Use /sbin not /usr/sbin . + +* Thu Jun 23 2011 Peter Lemenkov - 1:1.99-0.2 +- Fixes for ppc and ppc64 + +* Wed Feb 09 2011 Fedora Release Engineering - 1:1.98-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild