diff --git a/.gitignore b/.gitignore index 4d0dfb700e..a18787dcfe 100644 --- a/.gitignore +++ b/.gitignore @@ -279,3 +279,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/20-grub.install b/20-grub.install new file mode 100755 index 0000000000..f2de7760c4 --- /dev/null +++ b/20-grub.install @@ -0,0 +1,167 @@ +#!/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 + +BLS_DIR="/boot/loader/entries" + +mkbls() { + local kernelver=$1 && shift + local datetime=$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/${i##*/}-${KERNEL_VERSION}" + done + # hmac is .vmlinuz-.hmac so needs a special treatment + i="$KERNEL_DIR/.${KERNEL_IMAGE##*/}.hmac" + if [[ -e "$i" ]]; then + rm -f "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + cp -a "$i" "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + command -v restorecon &>/dev/null && \ + restorecon "/boot/.${KERNEL_IMAGE##*/}-${KERNEL_VERSION}.hmac" + fi + fi + + if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then + 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" + if [[ -f "${KERNEL_DIR}/bls.conf" ]]; then + cp -aT "${KERNEL_DIR}/bls.conf" "${BLS_TARGET}" || exit $? + else + mkbls "${KERNEL_VERSION}" \ + "$(date -u +%Y%m%d%H%M%S -d "$(stat -c '%y' "${KERNEL_DIR}")")" \ + >"${BLS_TARGET}" + fi + + LINUX="$(grep '^linux[ \t]' "${BLS_TARGET}" | sed -e 's,^linux[ \t]*,,')" + INITRD="$(grep '^initrd[ \t]' "${BLS_TARGET}" | sed -e 's,^initrd[ \t]*,,')" + LINUX_RELPATH="$(grub2-mkrelpath /boot${LINUX})" + 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" == *\+* ]] && [ "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 + ARCH="$(uname -m)" + BLS_DEBUG_ID="$(echo ${BLS_ID} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")" + cp -aT "${BLS_TARGET}" "${BLS_DEBUG}" + TITLE="$(grep '^title[ \t]' "${BLS_DEBUG}" | sed -e 's/^title[ \t]*//')" + sed -i -e "s/^title.*/title ${TITLE}${GRUB_LINUX_DEBUG_TITLE_POSTFIX}/" "${BLS_DEBUG}" + sed -i -e "s/^id.*/id ${BLS_DEBUG_ID}/" "${BLS_DEBUG}" + sed -i -e "s/^options.*/options \$kernelopts ${GRUB_CMDLINE_LINUX_DEBUG}/" "${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 + ARCH="$(uname -m)" + 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" + + 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/99-grub-mkconfig.install b/99-grub-mkconfig.install new file mode 100755 index 0000000000..e37089936a --- /dev/null +++ b/99-grub-mkconfig.install @@ -0,0 +1,24 @@ +#!/bin/bash + +if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then + exit 0 +fi + +ARCH=$(uname -m) + +# Is only needed for ppc64* since we can't assume a BLS capable bootloader there +if [[ $ARCH != "ppc64" && $ARCH != "ppc64le" ]]; 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/Makefile.builder b/Makefile.builder new file mode 100644 index 0000000000..35c9f90f6e --- /dev/null +++ b/Makefile.builder @@ -0,0 +1,4 @@ +RPM_SPEC_FILES.dom0 := grub2.spec +RPM_SPEC_FILES := $(RPM_SPEC_FILES.$(PACKAGE_SET)) + +NO_ARCHIVE := 1 diff --git a/Makefile.util.def b/Makefile.util.def index 9432365a9d..10f2c3669a 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -455,6 +455,30 @@ script = { installdir = grubconf; }; +script = { + name = '08_fallback_counting'; + common = util/grub.d/08_fallback_counting.in; + installdir = grubconf; +}; + +script = { + name = '12_menu_auto_hide'; + common = util/grub.d/12_menu_auto_hide.in; + 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; + installdir = grubconf; +}; + script = { name = '10_windows'; common = util/grub.d/10_windows.in; @@ -497,6 +521,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; @@ -541,6 +571,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; @@ -712,6 +763,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; @@ -726,6 +784,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; @@ -1422,3 +1487,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/acinclude.m4 b/acinclude.m4 index fa7840f09a..0231e64e33 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/bootstrap b/bootstrap index dc2238f4ad..5b08e7e2d4 100755 --- a/bootstrap +++ b/bootstrap @@ -1,10 +1,10 @@ #! /bin/sh # Print a version string. -scriptversion=2022-01-26.05; # UTC +scriptversion=2019-01-04.17; # UTC # Bootstrap this package from checked-out sources. -# Copyright (C) 2003-2022 Free Software Foundation, Inc. +# 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 @@ -47,7 +47,7 @@ PERL="${PERL-perl}" me=$0 -default_gnulib_url=https://git.savannah.gnu.org/git/gnulib.git +default_gnulib_url=git://git.sv.gnu.org/gnulib 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 +package=$(sed -n "$extract_package_name" configure.ac) \ + || die 'cannot find package name in configure.ac' gnulib_name=lib$package build_aux=build-aux @@ -313,116 +290,6 @@ 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". @@ -453,12 +320,6 @@ do --help) usage exit;; - --version) - set -e - echo "bootstrap $scriptversion" - echo "$copyright" - exit 0 - ;; --gnulib-srcdir=*) GNULIB_SRCDIR=${option#--gnulib-srcdir=};; --skip-po) @@ -474,7 +335,7 @@ do --no-git) use_git=false;; *) - bootstrap_option_hook $option || die "$option: unknown option";; + die "$option: unknown option";; esac done @@ -485,6 +346,47 @@ 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 \ @@ -763,25 +665,9 @@ 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 @@ -898,6 +784,75 @@ 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 @@ -1015,7 +970,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 update --init' and bootstrap again." + "Run 'git submodule init' and bootstrap again." fi # Remove any dangling symlink matching "*.m4" or "*.[ch]" in some @@ -1109,7 +1064,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 7a7813d282..6b043fc354 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -1,6 +1,6 @@ # Bootstrap configuration. -# Copyright (C) 2006-2022 Free Software Foundation, Inc. +# 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 @@ -16,10 +16,11 @@ # along with this program. If not, see . -GNULIB_REVISION=9f48fb992a3d7e96610c4ce8be969cff2d61a01b +GNULIB_REVISION=d271f868a8df9bbec29049d01e056481b7a1a263 # gnulib modules used by this package. -# mbswidth is used by fix-width.diff's changes to argp rather than directly. +# mbswidth is used by gnulib-fix-width.diff's changes to argp rather than +# directly. gnulib_modules=" argp base64 @@ -34,7 +35,6 @@ gnulib_modules=" realloc-gnu regex save-cwd - stdbool " gnulib_tool_option_extras="\ @@ -66,11 +66,10 @@ SKIP_PO=t # Build prerequisites buildreq="\ -autoconf 2.64 -automake 1.14 -gettext - +autoconf 2.63 +automake 1.11 +gettext 0.18.3 git 1.5.5 -patch - tar - " @@ -80,12 +79,11 @@ cp -a INSTALL INSTALL.grub bootstrap_post_import_hook () { set -e - - # 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 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 \ diff --git a/conf/Makefile.common b/conf/Makefile.common index b8f216f6cd..a6e84ea623 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -41,7 +41,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 -R .note.gnu.property -R .gnu.build.attributes if !COND_emu if COND_HAVE_ASM_USCORE LDFLAGS_KERNEL += -Wl,--defsym=_malloc=_grub_malloc -Wl,--defsym=_free=_grub_free @@ -50,32 +50,36 @@ else endif endif -CFLAGS_MODULE = $(CFLAGS_PLATFORM) -ffreestanding -LDFLAGS_MODULE = $(LDFLAGS_PLATFORM) -nostdlib $(TARGET_LDFLAGS_OLDMAGIC) -Wl,-r -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 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-sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-conversion -Wno-error=attributes +CFLAGS_GNULIB = -Wno-undef -Wno-error=sign-compare -Wno-unused -Wno-unused-parameter -Wno-redundant-decls -Wno-unreachable-code -Wno-error=attributes -Werror=trampolines -fno-trampolines CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-core/lib/gnulib CFLAGS_POSIX = -fno-builtin @@ -111,6 +115,7 @@ MOD_FILES = MODULE_FILES = MARKER_FILES = KERNEL_HEADER_FILES = +EXTRA_DEPS = bin_SCRIPTS = bin_PROGRAMS = @@ -132,6 +137,9 @@ platform_SCRIPTS = platform_PROGRAMS = sbin_SCRIPTS = sbin_PROGRAMS = +grublibexec_SCRIPTS = +systemdunit_SCRIPTS = +systemd_logind_service_d_SCRIPTS = EXTRA_DIST = CLEANFILES = diff --git a/conf/Makefile.extra-dist b/conf/Makefile.extra-dist index 5e7126f987..f35f69d68b 100644 --- a/conf/Makefile.extra-dist +++ b/conf/Makefile.extra-dist @@ -15,12 +15,16 @@ 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 EXTRA_DIST += grub-core/Makefile.core.def EXTRA_DIST += grub-core/Makefile.gcry.def +EXTRA_DIST += grub-core/extra_deps.lst EXTRA_DIST += grub-core/genmoddep.awk EXTRA_DIST += grub-core/genmod.sh.in EXTRA_DIST += grub-core/gensyminfo.sh.in diff --git a/configure.ac b/configure.ac index cd667a2eb7..8381b18a5d 100644 --- a/configure.ac +++ b/configure.ac @@ -34,7 +34,7 @@ dnl "TARGET_" (such as TARGET_CC, TARGET_CFLAGS, etc.) are used for dnl the target type. See INSTALL for full list of variables and dnl description of the relationships between them. -AC_INIT([GRUB],[2.12],[bug-grub@gnu.org]) +AC_INIT([GRUB],[2.13],[bug-grub@gnu.org]) AS_CASE(["$ERROR_PLATFORM_NOT_SUPPORT_SSP"], [n | no | nO | N | No | NO], [ERROR_PLATFORM_NOT_SUPPORT_SSP=no], @@ -70,6 +70,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]) @@ -77,6 +78,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]) @@ -319,6 +321,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. # @@ -534,6 +544,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" @@ -901,11 +914,23 @@ if test "x$target_cpu" = xloongarch64; then TARGET_CCASFLAGS="$TARGET_CCASFLAGS -Wa,-mla-global-with-abs" 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 @@ -1527,7 +1552,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 @@ -2081,6 +2114,17 @@ if test x"$enable_werror" != xno ; then fi 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_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 @@ -2090,6 +2134,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/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/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/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/grub-dev.texi b/docs/grub-dev.texi index 1276c59302..8ad5494f5c 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 @@ -996,9 +996,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 latter following this template: diff --git a/docs/grub.texi b/docs/grub.texi index a225f9a88d..da34a924fc 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 @@ -223,7 +223,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 @@ -237,7 +237,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 @@ -542,7 +542,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: @@ -565,7 +565,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 @@ -592,7 +592,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 @@ -602,7 +602,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 @@ -615,7 +615,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 @@ -626,22 +626,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 @@ -650,13 +650,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 @@ -670,7 +670,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 @@ -682,30 +682,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 @@ -725,10 +732,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 @@ -751,7 +758,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 @@ -767,7 +774,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: @@ -1269,23 +1276,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: @@ -1323,7 +1330,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}). @@ -1334,7 +1341,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}). @@ -1481,15 +1488,15 @@ 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 disable the use of UUIDs, set this option to @samp{true}. @item GRUB_DISABLE_LINUX_PARTUUID -If @command{grub-mkconfig} cannot identify the root filesystem via its -universally-unique indentifier (UUID), @command{grub-mkconfig} can use the UUID +If @command{grub2-mkconfig} cannot identify the root filesystem via its +universally-unique indentifier (UUID), @command{grub2-mkconfig} can use the UUID of the partition containing the filesystem to identify the root filesystem to the Linux kernel via a @samp{root=PARTUUID=...} kernel parameter. This is not as reliable as using the filesystem UUID, but is more reliable than using the @@ -1503,7 +1510,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 @@ -1514,12 +1521,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 @@ -1552,20 +1559,20 @@ 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 +The @command{grub2-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. +@command{grub2-mkconfig} command. @item GRUB_OS_PROBER_SKIP_LIST 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 @@ -1573,11 +1580,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. @@ -1636,7 +1643,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 @@ -1644,14 +1651,14 @@ that file, making sure to leave at least the first two lines intact. @node Root Identifcation Heuristics @section Root Identifcation Heuristics -If the target operating system uses the Linux kernel, @command{grub-mkconfig} +If the target operating system uses the Linux kernel, @command{grub2-mkconfig} attempts to identify the root file system via a heuristic algoirthm. This algorithm selects the identification method of the root file system by considering three factors. The first is if an initrd for the target operating system is also present. The second is @samp{GRUB_DISABLE_LINUX_UUID} and if set -to @samp{true}, prevents @command{grub-mkconfig} from identifying the root file +to @samp{true}, prevents @command{grub2-mkconfig} from identifying the root file system by its UUID. The third is @samp{GRUB_DISABLE_LINUX_PARTUUID} and if set -to @samp{true}, prevents @command{grub-mkconfig} from identifying the root file +to @samp{true}, prevents @command{grub2-mkconfig} from identifying the root file system via the UUID of its enclosing partition. If the variables are assigned any other value, that value is considered equivalent to @samp{false}. The variables are also considered to be set to @samp{false} if they are not set. @@ -1661,18 +1668,18 @@ filesystem to the initrd. Most initrd images determine the root file system by checking the Linux kernel's command-line for the @samp{root} key and use its value as the identification method of the root file system. To improve the reliability of booting, most initrd images also allow the root file system to be -identified by its UUID. Because of this behavior, the @command{grub-mkconfig} +identified by its UUID. Because of this behavior, the @command{grub2-mkconfig} command will set @samp{root} to @samp{root=UUID=...} to provide the initrd with the filesystem UUID of the root file system. If no initrd is detected or @samp{GRUB_DISABLE_LINUX_UUID} is set to @samp{true} -then @command{grub-command} will identify the root filesystem by setting the +then @command{grub2-command} will identify the root filesystem by setting the kernel command-line variable @samp{root} to @samp{root=PARTUUID=...} unless @samp{GRUB_DISABLE_LINUX_PARTUUID} is also set to @samp{true}. If @samp{GRUB_DISABLE_LINUX_PARTUUID} is also set to @samp{true}, -@command{grub-command} will identify by its Linux device name. +@command{grub2-command} will identify by its Linux device name. -The following table summarizes the behavior of the @command{grub-mkconfig} +The following table summarizes the behavior of the @command{grub2-mkconfig} command. @multitable {detected} {GRUB_DISABLE_LINUX_PARTUUID} {GRUB_DISABLE_LINUX_UUID} {Linux Root} @@ -1900,7 +1907,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 @@ -1910,20 +1917,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" @{ @@ -1986,15 +1993,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 @@ -2029,13 +2036,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 @@ -2559,7 +2566,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 @@ -2762,7 +2769,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? @@ -2823,7 +2830,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 @@ -2853,7 +2860,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 @@ -2905,7 +2912,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 @@ -3073,8 +3080,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}), @@ -3082,8 +3089,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. @@ -3502,7 +3509,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 @@ -3592,7 +3599,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. @@ -3600,10 +3607,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. @@ -3740,7 +3747,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. @@ -3852,17 +3859,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}). @node Modules @@ -4924,7 +4931,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 @@ -5276,7 +5283,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 @@ -5950,6 +5957,7 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}). * 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 @@ -6075,6 +6083,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 @@ -6402,8 +6426,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, @@ -6448,7 +6472,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} @@ -6474,8 +6498,18 @@ validation fails, then file @file{foo} cannot be opened. This failure 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}). +using the @code{--pubkey} option to @command{grub2-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 @@ -6495,8 +6529,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 @@ -6518,7 +6552,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. @@ -6566,7 +6600,7 @@ UTF-8 strings as comma-separated values (CSV). See @uref{https://github.com/rhboot/shim/blob/main/SBAT.md} for more details. To add a data section containing the SBAT information into the binary, the -@option{--sbat} option of @command{grub-mkimage} command should be used. The content +@option{--sbat} option of @command{grub2-mkimage} command should be used. The content of a CSV file, encoded with UTF-8, is copied as is to the .sbat data section into the generated EFI binary. The CSV file can be stored anywhere on the file system. @@ -6977,10 +7011,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 @@ -7006,8 +7040,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 @@ -7019,7 +7053,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. @@ -7054,33 +7088,40 @@ bootability on other machines. @chapter User-space utilities @menu -* 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 @end menu -@node Invoking grub-install -@section Invoking grub-install +@node Invoking grub2-install +@section 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: +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 @item --help @@ -7096,13 +7137,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 @@ -7110,16 +7151,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 @@ -7132,17 +7173,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 -@section Invoking grub-mkconfig +@node Invoking grub2-mkconfig +@section 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 +grub2-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 @@ -7158,17 +7199,17 @@ it to standard output. @end table -@node Invoking grub-mkpasswd-pbkdf2 -@section Invoking grub-mkpasswd-pbkdf2 +@node Invoking grub2-mkpasswd-pbkdf2 +@section 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 +grub2-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} @@ -7186,23 +7227,23 @@ Length of the salt. Defaults to 64. @end table -@node Invoking grub-mkrelpath -@section Invoking grub-mkrelpath +@node Invoking grub2-mkrelpath +@section 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 @@ -7213,17 +7254,17 @@ Print the version number of GRUB and exit. @end table -@node Invoking grub-mkrescue -@section Invoking grub-mkrescue +@node Invoking grub2-mkrescue +@section 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 +grub2-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 @@ -7235,10 +7276,10 @@ commonly used to add extra files to the image: @example mkdir -p disk/boot/grub @r{(add extra files to @file{disk/boot/grub})} -grub-mkrescue -o grub.iso disk +grub2-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 @@ -7266,15 +7307,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 -@section Invoking grub-mount +@node Invoking grub2-mount +@section 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: @@ -7306,13 +7347,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 +grub2-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: @@ -7334,13 +7375,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 @@ -7349,7 +7390,7 @@ an entire disk in @file{disk.img}, then you can use this command to mount its second partition: @example -grub-mount -r 2 disk.img mount-point +grub2-mount -r 2 disk.img mount-point @end example @item -v @@ -7358,18 +7399,18 @@ Print verbose messages. @end table -@node Invoking grub-probe -@section Invoking grub-probe +@node Invoking grub2-probe +@section 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 -grub-probe --target=fs /boot/grub -grub-probe --target=drive --device /dev/sda1 +grub2-probe --target=fs /boot/grub +grub2-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 @@ -7382,16 +7423,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} @@ -7444,19 +7485,19 @@ Print verbose messages. @end table -@node Invoking grub-script-check -@section Invoking grub-script-check +@node Invoking grub2-script-check +@section 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 +grub2-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/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/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/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/gentpl.py b/gentpl.py index bfab2113a1..0f8d009ef2 100644 --- a/gentpl.py +++ b/gentpl.py @@ -52,6 +52,7 @@ 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", "loongarch64_efi", "riscv32_efi", "riscv64_efi" ] GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] @@ -594,11 +595,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) @@ -631,6 +642,9 @@ def platform_values(defn, platform, suffix): def extra_dist(defn): return foreach_value(defn, "extra_dist", lambda value: value + " ") +def extra_dep(defn): + return foreach_value(defn, "depends", lambda value: value + " ") + def platform_sources(defn, p): return platform_values(defn, p, "") def platform_nodist_sources(defn, p): return platform_values(defn, p, "_nodist") @@ -657,6 +671,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:]: @@ -686,10 +702,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)) @@ -699,6 +715,10 @@ def module(defn, platform): gvar_add("MOD_FILES", name + ".mod") gvar_add("MARKER_FILES", name + ".marker") gvar_add("CLEANFILES", name + ".marker") + + for dep in defn.find_all("depends"): + gvar_add("EXTRA_DEPS", "depends " + name + " " + dep + ":") + output(""" """ + name + """.marker: $(""" + cname(defn) + """_SOURCES) $(nodist_""" + cname(defn) + """_SOURCES) $(TARGET_CPP) -DGRUB_LST_GENERATOR $(CPPFLAGS_MARKER) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(""" + cname(defn) + """_CPPFLAGS) $(CPPFLAGS) $^ > $@.new || (rm -f $@; exit 1) diff --git a/gitignore b/gitignore new file mode 100644 index 0000000000..f6a1bd0517 --- /dev/null +++ b/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/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz b/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz new file mode 100644 index 0000000000..1a0cf7dbaf Binary files /dev/null and b/gnulib-9f48fb992a3d7e96610c4ce8be969cff2d61a01b.tar.gz differ 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/Makefile.am b/grub-core/Makefile.am index f18550c1c9..12786f43ee 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -454,8 +454,15 @@ crypto.lst: $(srcdir)/lib/libgcrypt-grub/cipher/crypto.lst platform_DATA += crypto.lst CLEANFILES += crypto.lst -syminfo.lst: gensyminfo.sh kernel_syms.lst $(top_srcdir)/grub-core/extra_deps.lst $(MODULE_FILES) - cat kernel_syms.lst $(top_srcdir)/grub-core/extra_deps.lst > $@.new +extra_deps.lst: + @echo $(EXTRA_DEPS) | sed "s/\s*:\s*/\n/g" > $@ + +syminfo.lst: gensyminfo.sh kernel_syms.lst extra_deps.lst $(MODULE_FILES) + if ! [ -f extra_deps.lst ] ; then \ + echo Missing extra_deps.lst ; \ + echo $(EXTRA_DEPS) | sed "s/\s*:\s*/\n/g" > extra_deps.lst ; \ + fi + cat kernel_syms.lst extra_deps.lst > $@.new for m in $(MODULE_FILES); do \ sh $< $$m >> $@.new || exit 1; \ done @@ -465,7 +472,7 @@ syminfo.lst: gensyminfo.sh kernel_syms.lst $(top_srcdir)/grub-core/extra_deps.ls moddep.lst: syminfo.lst genmoddep.awk video.lst cat $< | sort | $(AWK) -f $(srcdir)/genmoddep.awk > $@ || (rm -f $@; exit 1) platform_DATA += moddep.lst -CLEANFILES += config.log syminfo.lst moddep.lst +CLEANFILES += config.log syminfo.lst moddep.lst extra_deps.lst $(MOD_FILES): %.mod : genmod.sh moddep.lst %.module$(EXEEXT) build-grub-module-verifier$(BUILD_EXEEXT) TARGET_OBJ2ELF=@TARGET_OBJ2ELF@ sh $^ $@ diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 1571421d7e..f4936b3feb 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -199,6 +199,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; @@ -219,6 +222,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; @@ -409,6 +413,11 @@ kernel = { extra_dist = kern/mips/cache_flush.S; }; +module = { + name = increment; + common = commands/increment.c; +}; + program = { name = grub-emu; mansection = 1; @@ -824,6 +833,12 @@ module = { enable = efi; }; +module = { + name = efienv; + common = commands/efi/env.c; + enable = efi; +}; + module = { name = efifwsetup; efi = commands/efi/efifwsetup.c; @@ -2338,6 +2353,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; @@ -2351,6 +2372,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 = { @@ -2594,4 +2621,5 @@ module = { name = bli; efi = commands/bli.c; enable = efi; + depends = part_gpt; }; diff --git a/grub-core/bus/usb/ehci.c b/grub-core/bus/usb/ehci.c index 9abebc6bda..2db07c7c0c 100644 --- a/grub-core/bus/usb/ehci.c +++ b/grub-core/bus/usb/ehci.c @@ -218,7 +218,7 @@ enum #define GRUB_EHCI_TERMINATE (1<<0) -#define GRUB_EHCI_TOGGLE (1<<31) +#define GRUB_EHCI_TOGGLE ((grub_uint32_t) 1<<31) enum { diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c index e0d8a54f7b..298c5f70a8 100644 --- a/grub-core/commands/bli.c +++ b/grub-core/commands/bli.c @@ -48,6 +48,22 @@ get_part_uuid (const char *device_name, char **part_uuid) if (device == NULL) return grub_error (grub_errno, N_("cannot open device: %s"), device_name); + if (device->disk == NULL) + { + grub_dprintf ("bli", "%s is not a disk device, partuuid skipped\n", device_name); + *part_uuid = NULL; + grub_device_close (device); + return GRUB_ERR_NONE; + } + + if (device->disk->partition == NULL) + { + grub_dprintf ("bli", "%s has no partition, partuuid skipped\n", device_name); + *part_uuid = NULL; + grub_device_close (device); + return GRUB_ERR_NONE; + } + disk = grub_disk_open (device->disk->name); if (disk == NULL) { @@ -99,7 +115,7 @@ set_loader_device_part_uuid (void) status = get_part_uuid (device_name, &part_uuid); - if (status == GRUB_ERR_NONE) + if (status == GRUB_ERR_NONE && part_uuid) status = grub_efi_set_variable_to_string ("LoaderDevicePartUUID", &bli_vendor_guid, part_uuid, GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS); @@ -117,4 +133,6 @@ GRUB_MOD_INIT (bli) GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS); set_loader_device_part_uuid (); + /* No error here is critical, other than being logged */ + grub_print_error (); } diff --git a/grub-core/commands/efi/env.c b/grub-core/commands/efi/env.c new file mode 100644 index 0000000000..4080f24fdb --- /dev/null +++ b/grub-core/commands/efi/env.c @@ -0,0 +1,170 @@ +/* + * 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_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); + + return GRUB_ERR_NONE; +} + +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/commands/extcmd.c b/grub-core/commands/extcmd.c index 90a5ca24a6..c236be13af 100644 --- a/grub-core/commands/extcmd.c +++ b/grub-core/commands/extcmd.c @@ -49,6 +49,9 @@ grub_extcmd_dispatcher (struct grub_command *cmd, int argc, char **args, } state = grub_arg_list_alloc (ext, argc, args); + if (state == NULL) + return grub_errno; + if (grub_arg_parse (ext, argc, args, state, &new_args, &new_argc)) { context.state = state; diff --git a/grub-core/commands/hexdump.c b/grub-core/commands/hexdump.c index eaa12465bb..d6f61d98a1 100644 --- a/grub-core/commands/hexdump.c +++ b/grub-core/commands/hexdump.c @@ -24,6 +24,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -51,7 +52,11 @@ grub_cmd_hexdump (grub_extcmd_context_t ctxt, int argc, char **args) length = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 256; if (!grub_strcmp (args[0], "(mem)")) - hexdump (skip, (char *) (grub_addr_t) skip, length); + { + if (grub_is_lockdown() == GRUB_LOCKDOWN_ENABLED) + return grub_error (GRUB_ERR_ACCESS_DENIED, N_("memory reading is disabled in lockdown mode")); + hexdump (skip, (char *) (grub_addr_t) skip, length); + } else if ((args[0][0] == '(') && (args[0][namelen - 1] == ')')) { grub_disk_t disk; 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/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/legacycfg.c b/grub-core/commands/legacycfg.c index e9e9d94eff..3bf9fe2e4d 100644 --- a/grub-core/commands/legacycfg.c +++ b/grub-core/commands/legacycfg.c @@ -198,7 +198,6 @@ legacy_file (const char *filename) const char **args = grub_malloc (sizeof (args[0])); if (!args) { - grub_file_close (file); grub_free (suffix); grub_free (entrysrc); return grub_errno; diff --git a/grub-core/commands/ls.c b/grub-core/commands/ls.c index 6a1c7f5d36..f660946a24 100644 --- a/grub-core/commands/ls.c +++ b/grub-core/commands/ls.c @@ -241,7 +241,11 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human) grub_file_close (file); - p = grub_strrchr (dirname, '/') + 1; + p = grub_strrchr (dirname, '/'); + if (p == NULL) + goto fail; + ++p; + ctx.dirname = grub_strndup (dirname, p - dirname); if (ctx.dirname == NULL) goto fail; diff --git a/grub-core/commands/memrw.c b/grub-core/commands/memrw.c index d401a6db0e..9d8a54a4b3 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,18 +122,24 @@ 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."), - options); + grub_register_extcmd_lockdown ("read_byte", grub_cmd_read, 0, + N_("ADDR"), + N_("Read 8-bit value from ADDR."), + options); cmd_read_word = - grub_register_extcmd ("read_word", grub_cmd_read, 0, - N_("ADDR"), N_("Read 16-bit value from ADDR."), - options); + grub_register_extcmd_lockdown ("read_word", grub_cmd_read, 0, + N_("ADDR"), + N_("Read 16-bit value from ADDR."), + options); cmd_read_dword = - grub_register_extcmd ("read_dword", grub_cmd_read, 0, - N_("ADDR"), N_("Read 32-bit value from ADDR."), - options); + grub_register_extcmd_lockdown ("read_dword", grub_cmd_read, 0, + N_("ADDR"), + N_("Read 32-bit value from ADDR."), + options); cmd_write_byte = grub_register_command_lockdown ("write_byte", grub_cmd_write, N_("ADDR VALUE [MASK]"), @@ -149,6 +156,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/menuentry.c b/grub-core/commands/menuentry.c index 720e6d8ea3..d7b04522a6 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, @@ -271,7 +271,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/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c index fa498931ed..8c5ee3e604 100644 --- a/grub-core/commands/minicmd.c +++ b/grub-core/commands/minicmd.c @@ -167,7 +167,7 @@ grub_mini_cmd_lsmod (struct grub_command *cmd __attribute__ ((unused)), { grub_dl_dep_t dep; - grub_printf ("%s\t%d\t\t", mod->name, mod->ref_count); + grub_printf ("%s\t%" PRIuGRUB_UINT64_T "\t\t", mod->name, mod->ref_count); for (dep = mod->dep; dep; dep = dep->next) { if (dep != mod->dep) @@ -203,8 +203,8 @@ GRUB_MOD_INIT(minicmd) grub_register_command ("help", grub_mini_cmd_help, 0, N_("Show this message.")); cmd_dump = - grub_register_command ("dump", grub_mini_cmd_dump, - N_("ADDR [SIZE]"), N_("Show memory contents.")); + grub_register_command_lockdown ("dump", grub_mini_cmd_dump, + N_("ADDR [SIZE]"), N_("Show memory contents.")); cmd_rmmod = grub_register_command ("rmmod", grub_mini_cmd_rmmod, N_("MODULE"), N_("Remove a module.")); diff --git a/grub-core/commands/pgp.c b/grub-core/commands/pgp.c index c6766f044a..5fadc33c41 100644 --- a/grub-core/commands/pgp.c +++ b/grub-core/commands/pgp.c @@ -1010,6 +1010,8 @@ GRUB_MOD_INIT(pgp) GRUB_MOD_FINI(pgp) { + grub_register_variable_hook ("check_signatures", NULL, NULL); + grub_env_unset ("check_signatures"); grub_verifier_unregister (&grub_pubkey_verifier); grub_unregister_extcmd (cmd); grub_unregister_extcmd (cmd_trust); diff --git a/grub-core/commands/read.c b/grub-core/commands/read.c index 597c907065..8d72e45c93 100644 --- a/grub-core/commands/read.c +++ b/grub-core/commands/read.c @@ -25,6 +25,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -37,13 +38,14 @@ static const struct grub_arg_option options[] = static char * grub_getline (int silent) { - int i; + grub_size_t i; char *line; char *tmp; int c; + grub_size_t alloc_size; i = 0; - line = grub_malloc (1 + i + sizeof('\0')); + line = grub_malloc (1 + sizeof('\0')); if (! line) return NULL; @@ -59,8 +61,17 @@ grub_getline (int silent) line[i] = (char) c; if (!silent) grub_printf ("%c", c); - i++; - tmp = grub_realloc (line, 1 + i + sizeof('\0')); + if (grub_add (i, 1, &i)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); + return NULL; + } + if (grub_add (i, 1 + sizeof('\0'), &alloc_size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); + return NULL; + } + tmp = grub_realloc (line, alloc_size); if (! tmp) { grub_free (line); diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 263f1501cd..d538b36219 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) @@ -86,6 +182,66 @@ 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') + { + 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; + + if (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); + 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 318581f3b1..4fe6440c65 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/commands/test.c b/grub-core/commands/test.c index 62d3fb3988..b585c3d703 100644 --- a/grub-core/commands/test.c +++ b/grub-core/commands/test.c @@ -29,6 +29,9 @@ GRUB_MOD_LICENSE ("GPLv3+"); +/* Set a limit on recursion to avoid stack overflow. */ +#define MAX_TEST_RECURSION_DEPTH 100 + /* A simple implementation for signed numbers. */ static int grub_strtosl (char *arg, const char ** const end, int base) @@ -150,7 +153,7 @@ get_fileinfo (char *path, struct test_parse_ctx *ctx) /* Parse a test expression starting from *argn. */ static int -test_parse (char **args, int *argn, int argc) +test_parse (char **args, int *argn, int argc, int *depth) { struct test_parse_ctx ctx = { .and = 1, @@ -387,13 +390,24 @@ test_parse (char **args, int *argn, int argc) if (grub_strcmp (args[*argn], ")") == 0) { (*argn)++; + if (*depth > 0) + (*depth)--; + return ctx.or || ctx.and; } /* Recursively invoke if parenthesis. */ if (grub_strcmp (args[*argn], "(") == 0) { (*argn)++; - update_val (test_parse (args, argn, argc), &ctx); + + if (++(*depth) > MAX_TEST_RECURSION_DEPTH) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded")); + depth--; + return ctx.or || ctx.and; + } + + update_val (test_parse (args, argn, argc, depth), &ctx); continue; } @@ -428,11 +442,12 @@ grub_cmd_test (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { int argn = 0; + int depth = 0; if (argc >= 1 && grub_strcmp (args[argc - 1], "]") == 0) argc--; - return test_parse (args, &argn, argc) ? GRUB_ERR_NONE + return test_parse (args, &argn, argc, &depth) ? GRUB_ERR_NONE : grub_error (GRUB_ERR_TEST_FAILURE, N_("false")); } diff --git a/grub-core/disk/ahci.c b/grub-core/disk/ahci.c index e7b5dc5f20..b247161b90 100644 --- a/grub-core/disk/ahci.c +++ b/grub-core/disk/ahci.c @@ -1038,7 +1038,7 @@ grub_ahci_readwrite_real (struct grub_ahci_device *dev, grub_dprintf ("ahci", "AHCI tfd = %x\n", dev->hba->ports[dev->port].task_file_data); - endtime = grub_get_time_ms () + (spinup ? 20000 : 20000); + endtime = grub_get_time_ms () + 20000; while ((dev->hba->ports[dev->port].command_issue & 1)) if (grub_get_time_ms () > endtime || (dev->hba->ports[dev->port].intstatus & GRUB_AHCI_HBA_PORT_IS_FATAL_MASK)) diff --git a/grub-core/disk/ata.c b/grub-core/disk/ata.c index 7b6ac7bfc7..a2433e29e2 100644 --- a/grub-core/disk/ata.c +++ b/grub-core/disk/ata.c @@ -112,10 +112,10 @@ grub_ata_identify (struct grub_ata *dev) return grub_atapi_identify (dev); info64 = grub_malloc (GRUB_DISK_SECTOR_SIZE); + if (info64 == NULL) + return grub_errno; info32 = (grub_uint32_t *) info64; info16 = (grub_uint16_t *) info64; - if (! info16) - return grub_errno; grub_memset (&parms, 0, sizeof (parms)); parms.buffer = info16; diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 2246af51b6..acf7968f03 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include @@ -721,7 +722,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk) #ifdef GRUB_UTIL if (dev->cheat) { - grub_uint64_t cheat_dev_size; + grub_int64_t cheat_dev_size; unsigned int cheat_log_sector_size; if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd)) @@ -1473,7 +1474,7 @@ static char * luks_script_get (grub_size_t *sz) { grub_cryptodisk_t i; - grub_size_t size = 0; + grub_size_t size = 0, mul; char *ptr, *ret; *sz = 0; @@ -1482,10 +1483,6 @@ luks_script_get (grub_size_t *sz) if (grub_strcmp (i->modname, "luks") == 0 || grub_strcmp (i->modname, "luks2") == 0) { - size += grub_strlen (i->modname); - size += sizeof ("_mount"); - size += grub_strlen (i->uuid); - size += grub_strlen (i->cipher->cipher->name); /* * Add space in the line for (in order) spaces, cipher mode, cipher IV * mode, sector offset, sector size and the trailing newline. This is @@ -1493,14 +1490,35 @@ luks_script_get (grub_size_t *sz) * in an earlier version of this code that are unaccounted for. It is * left in the calculations in case it is needed. At worst, its short- * lived wasted space. + * + * 60 = 5 + 5 + 8 + 20 + 6 + 1 + 15 */ - size += 5 + 5 + 8 + 20 + 6 + 1 + 15; + if (grub_add (size, grub_strlen (i->modname), &size) || + grub_add (size, sizeof ("_mount") + 60, &size) || + grub_add (size, grub_strlen (i->uuid), &size) || + grub_add (size, grub_strlen (i->cipher->cipher->name), &size) || + grub_mul (i->keysize, 2, &mul) || + grub_add (size, mul, &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); + return 0; + } if (i->essiv_hash) - size += grub_strlen (i->essiv_hash->name); - size += i->keysize * 2; + { + if (grub_add (size, grub_strlen (i->essiv_hash->name), &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); + return 0; + } + } } + if (grub_add (size, 1, &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining size of luks script"); + return 0; + } - ret = grub_malloc (size + 1); + ret = grub_malloc (size); if (!ret) return 0; diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index 21e2395111..de5a564d4b 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef GRUB_UTIL #include #include @@ -1039,7 +1040,7 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, { struct grub_diskfilter_vg *array; int i; - grub_size_t j; + grub_size_t j, sz; grub_uint64_t totsize; struct grub_diskfilter_pv *pv; grub_err_t err; @@ -1140,7 +1141,11 @@ grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb, } array->lvs->vg = array; - array->lvs->idname = grub_malloc (sizeof ("mduuid/") + 2 * uuidlen); + if (grub_mul (uuidlen, 2, &sz) || + grub_add (sz, sizeof ("mduuid/"), &sz)) + goto fail; + + array->lvs->idname = grub_malloc (sz); if (!array->lvs->idname) goto fail; diff --git a/grub-core/disk/ieee1275/obdisk.c b/grub-core/disk/ieee1275/obdisk.c index cd923b90fb..fcc39e0a23 100644 --- a/grub-core/disk/ieee1275/obdisk.c +++ b/grub-core/disk/ieee1275/obdisk.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -128,9 +129,17 @@ count_commas (const char *src) static char * decode_grub_devname (const char *name) { - char *devpath = grub_malloc (grub_strlen (name) + 1); + char *devpath; char *p, c; + grub_size_t sz; + if (grub_add (grub_strlen (name), 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device name")); + return NULL; + } + + devpath = grub_malloc (sz); if (devpath == NULL) return NULL; @@ -156,12 +165,20 @@ static char * encode_grub_devname (const char *path) { char *encoding, *optr; + grub_size_t sz; if (path == NULL) return NULL; - encoding = grub_malloc (sizeof (IEEE1275_DEV) + count_commas (path) + - grub_strlen (path) + 1); + if (grub_add (sizeof (IEEE1275_DEV) + 1, count_commas (path), &sz) || + grub_add (sz, grub_strlen (path), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining encoding size")); + grub_print_error (); + return NULL; + } + + encoding = grub_malloc (sz); if (encoding == NULL) { @@ -396,8 +413,22 @@ canonicalise_disk (const char *devname) real_unit_str_len = grub_strlen (op->name) + sizeof (IEEE1275_DISK_ALIAS) + grub_strlen (real_unit_address); + if (grub_add (grub_strlen (op->name), sizeof (IEEE1275_DISK_ALIAS), &real_unit_str_len) || + grub_add (real_unit_str_len, grub_strlen (real_unit_address), &real_unit_str_len)) + { + grub_free (parent); + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of canonical name")); + grub_print_error (); + return NULL; + } real_canon = grub_malloc (real_unit_str_len); + if (real_canon == NULL) + { + grub_free (parent); + grub_print_error (); + return NULL; + } grub_snprintf (real_canon, real_unit_str_len, "%s/disk@%s", op->name, real_unit_address); @@ -413,6 +444,7 @@ canonicalise_disk (const char *devname) static struct disk_dev * add_canon_disk (const char *cname) { + grub_size_t sz; struct disk_dev *dev; dev = grub_zalloc (sizeof (struct disk_dev)); @@ -428,13 +460,18 @@ add_canon_disk (const char *cname) * arguments and allows a client program to open * the entire (raw) disk. Any disk label is ignored. */ - dev->raw_name = grub_malloc (grub_strlen (cname) + sizeof (":nolabel")); + if (grub_add (grub_strlen (cname), sizeof (":nolabel"), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while appending :nolabel to end of canonical name"); + goto failed; + } + + dev->raw_name = grub_malloc (sz); if (dev->raw_name == NULL) goto failed; - grub_snprintf (dev->raw_name, grub_strlen (cname) + sizeof (":nolabel"), - "%s:nolabel", cname); + grub_snprintf (dev->raw_name, sz, "%s:nolabel", cname); } /* diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c index c6cba0c8aa..71237b2560 100644 --- a/grub-core/disk/ieee1275/ofdisk.c +++ b/grub-core/disk/ieee1275/ofdisk.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include static char *last_devpath; static grub_ieee1275_ihandle_t last_ihandle; @@ -44,7 +46,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 @@ -80,6 +82,7 @@ ofdisk_hash_add_real (char *devpath) struct ofdisk_hash_ent **head = &ofdisk_hash[ofdisk_hash_fn(devpath)]; const char *iptr; char *optr; + grub_size_t sz; p = grub_zalloc (sizeof (*p)); if (!p) @@ -87,8 +90,14 @@ ofdisk_hash_add_real (char *devpath) p->devpath = devpath; - p->grub_devpath = grub_malloc (sizeof ("ieee1275/") - + 2 * grub_strlen (p->devpath)); + if (grub_mul (grub_strlen (p->devpath), 2, &sz) || + grub_add (sz, sizeof ("ieee1275/"), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); + return NULL; + } + + p->grub_devpath = grub_malloc (sz); if (!p->grub_devpath) { @@ -98,7 +107,13 @@ ofdisk_hash_add_real (char *devpath) if (! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PARTITION_0)) { - p->open_path = grub_malloc (grub_strlen (p->devpath) + 3); + if (grub_add (grub_strlen (p->devpath), 3, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path")); + return NULL; + } + + p->open_path = grub_malloc (sz); if (!p->open_path) { grub_free (p->grub_devpath); @@ -224,8 +239,10 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) args; char *buf, *bufptr; unsigned i; + grub_size_t sz; - 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 @@ -243,9 +260,19 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) return; } - buf = grub_malloc (grub_strlen (alias->path) + 32); + if (grub_add (grub_strlen (alias->path), 32, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for vscsi"); + grub_ieee1275_close (ihandle); + return; + } + + buf = grub_malloc (sz); if (!buf) - return; + { + grub_ieee1275_close (ihandle); + return; + } bufptr = grub_stpcpy (buf, alias->path); for (i = 0; i < args.nentries; i++) @@ -287,9 +314,15 @@ dev_iterate (const struct grub_ieee1275_devalias *alias) grub_uint64_t *table; grub_uint16_t table_size; grub_ieee1275_ihandle_t ihandle; + grub_size_t sz; + + if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa"); + return; + } - buf = grub_malloc (grub_strlen (alias->path) + - sizeof ("/disk@7766554433221100")); + buf = grub_malloc (sz); if (!buf) return; bufptr = grub_stpcpy (buf, alias->path); @@ -305,7 +338,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); @@ -427,9 +462,17 @@ grub_ofdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data, static char * compute_dev_path (const char *name) { - char *devpath = grub_malloc (grub_strlen (name) + 3); + char *devpath; char *p, c; + grub_size_t sz; + + if (grub_add (grub_strlen (name), 3, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path")); + return NULL; + } + devpath = grub_malloc (sz); if (!devpath) return NULL; @@ -461,6 +504,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 +515,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; + + 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; + } + if (grub_ieee1275_finddevice (devpath, &dev)) { grub_free (devpath); @@ -491,25 +564,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); @@ -528,13 +594,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; } @@ -551,7 +610,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; @@ -578,12 +637,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; } @@ -625,6 +695,7 @@ insert_bootpath (void) char *bootpath; grub_ssize_t bootpath_size; char *type; + grub_size_t sz; if (grub_ieee1275_get_property_length (grub_ieee1275_chosen, "bootpath", &bootpath_size) @@ -635,7 +706,13 @@ insert_bootpath (void) return; } - bootpath = (char *) grub_malloc ((grub_size_t) bootpath_size + 64); + if (grub_add (bootpath_size, 64, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining bootpath size")); + return; + } + + bootpath = (char *) grub_malloc (sz); if (! bootpath) { grub_print_error (); @@ -681,7 +758,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 @@ -694,16 +771,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/grub-core/disk/ldm.c b/grub-core/disk/ldm.c index 34bfe6bd13..048e29cd09 100644 --- a/grub-core/disk/ldm.c +++ b/grub-core/disk/ldm.c @@ -220,6 +220,7 @@ make_vg (grub_disk_t disk, struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_ldm_vblk)]; unsigned i; + grub_size_t sz; err = grub_disk_read (disk, cursec, 0, sizeof(vblk), &vblk); if (err) @@ -251,7 +252,13 @@ make_vg (grub_disk_t disk, grub_free (pv); goto fail2; } - pv->internal_id = grub_malloc (ptr[0] + 2); + if (grub_add (ptr[0], 2, &sz)) + { + grub_free (pv); + goto fail2; + } + + pv->internal_id = grub_malloc (sz); if (!pv->internal_id) { grub_free (pv); @@ -276,7 +283,21 @@ make_vg (grub_disk_t disk, goto fail2; } pv->id.uuidlen = *ptr; - pv->id.uuid = grub_malloc (pv->id.uuidlen + 1); + + if (grub_add (pv->id.uuidlen, 1, &sz)) + { + grub_free (pv->internal_id); + grub_free (pv); + goto fail2; + } + + pv->id.uuid = grub_malloc (sz); + if (pv->id.uuid == NULL) + { + grub_free (pv->internal_id); + grub_free (pv); + goto fail2; + } grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen); pv->id.uuid[pv->id.uuidlen] = 0; @@ -343,7 +364,13 @@ make_vg (grub_disk_t disk, grub_free (lv); goto fail2; } - lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); + if (grub_add (ptr[0], 2, &sz)) + { + grub_free (lv->segments); + grub_free (lv); + goto fail2; + } + lv->internal_id = grub_malloc (sz); if (!lv->internal_id) { grub_free (lv); @@ -455,6 +482,7 @@ make_vg (grub_disk_t disk, struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE / sizeof (struct grub_ldm_vblk)]; unsigned i; + grub_size_t sz; err = grub_disk_read (disk, cursec, 0, sizeof(vblk), &vblk); if (err) @@ -490,7 +518,12 @@ make_vg (grub_disk_t disk, grub_free (comp); goto fail2; } - comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2); + if (grub_add (ptr[0], 2, &sz)) + { + grub_free (comp); + goto fail2; + } + comp->internal_id = grub_malloc (sz); if (!comp->internal_id) { grub_free (comp); @@ -640,7 +673,6 @@ make_vg (grub_disk_t disk, if (lv->segments->node_alloc == lv->segments->node_count) { void *t; - grub_size_t sz; if (grub_mul (lv->segments->node_alloc, 2, &lv->segments->node_alloc) || grub_mul (lv->segments->node_alloc, sizeof (*lv->segments->nodes), &sz)) diff --git a/grub-core/disk/loopback.c b/grub-core/disk/loopback.c index 4635dcfdee..2bea4e922a 100644 --- a/grub-core/disk/loopback.c +++ b/grub-core/disk/loopback.c @@ -24,6 +24,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -33,6 +34,7 @@ struct grub_loopback grub_file_t file; struct grub_loopback *next; unsigned long id; + grub_uint64_t refcnt; }; static struct grub_loopback *loopback_list; @@ -64,6 +66,8 @@ delete_loopback (const char *name) if (! dev) return grub_error (GRUB_ERR_BAD_DEVICE, "device not found"); + if (dev->refcnt > 0) + return grub_error (GRUB_ERR_STILL_REFERENCED, "device still referenced"); /* Remove the device from the list. */ *prev = dev->next; @@ -120,6 +124,7 @@ grub_cmd_loopback (grub_extcmd_context_t ctxt, int argc, char **args) newdev->file = file; newdev->id = last_id++; + newdev->refcnt = 0; /* Add the new entry to the list. */ newdev->next = loopback_list; @@ -161,6 +166,9 @@ grub_loopback_open (const char *name, grub_disk_t disk) if (! dev) return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "can't open device"); + if (grub_add (dev->refcnt, 1, &dev->refcnt)) + grub_fatal ("Reference count overflow"); + /* Use the filesize for the disk size, round up to a complete sector. */ if (dev->file->size != GRUB_FILE_SIZE_UNKNOWN) disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1) @@ -178,6 +186,15 @@ grub_loopback_open (const char *name, grub_disk_t disk) return 0; } +static void +grub_loopback_close (grub_disk_t disk) +{ + struct grub_loopback *dev = disk->data; + + if (grub_sub (dev->refcnt, 1, &dev->refcnt)) + grub_fatal ("Reference count underflow"); +} + static grub_err_t grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector, grub_size_t size, char *buf) @@ -220,6 +237,7 @@ static struct grub_disk_dev grub_loopback_dev = .id = GRUB_DISK_DEVICE_LOOPBACK_ID, .disk_iterate = grub_loopback_iterate, .disk_open = grub_loopback_open, + .disk_close = grub_loopback_close, .disk_read = grub_loopback_read, .disk_write = grub_loopback_write, .next = 0 diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c index d5106402fb..8036d76ff1 100644 --- a/grub-core/disk/luks2.c +++ b/grub-core/disk/luks2.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -569,6 +570,7 @@ luks2_recover_key (grub_disk_t source, gcry_err_code_t gcry_ret; grub_json_t *json = NULL, keyslots; grub_err_t ret; + grub_size_t sz; if (cargs->key_data == NULL || cargs->key_len == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, "no key data"); @@ -577,7 +579,10 @@ luks2_recover_key (grub_disk_t source, if (ret) return ret; - json_header = grub_zalloc (grub_be_to_cpu64 (header.hdr_size) - sizeof (header)); + if (grub_sub (grub_be_to_cpu64 (header.hdr_size), sizeof (header), &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while calculating json header size"); + + json_header = grub_zalloc (sz); if (!json_header) return GRUB_ERR_OUT_OF_MEMORY; diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c index 794248540c..b2dff76d17 100644 --- a/grub-core/disk/lvm.c +++ b/grub-core/disk/lvm.c @@ -370,6 +370,8 @@ grub_lvm_detect (grub_disk_t disk, break; pv = grub_zalloc (sizeof (*pv)); + if (pv == NULL) + goto fail4; q = p; while (*q != ' ' && q < mda_end) q++; @@ -379,6 +381,8 @@ grub_lvm_detect (grub_disk_t disk, s = q - p; pv->name = grub_malloc (s + 1); + if (pv->name == NULL) + goto pvs_fail_noname; grub_memcpy (pv->name, p, s); pv->name[s] = '\0'; @@ -451,6 +455,8 @@ grub_lvm_detect (grub_disk_t disk, break; lv = grub_zalloc (sizeof (*lv)); + if (lv == NULL) + goto fail4; q = p; while (*q != ' ' && q < mda_end) @@ -545,6 +551,8 @@ grub_lvm_detect (grub_disk_t disk, goto lvs_fail; } lv->segments = grub_calloc (lv->segment_count, sizeof (*seg)); + if (lv->segments == NULL) + goto lvs_fail; seg = lv->segments; for (i = 0; i < lv->segment_count; i++) @@ -612,6 +620,8 @@ grub_lvm_detect (grub_disk_t disk, seg->nodes = grub_calloc (seg->node_count, sizeof (*stripe)); + if (seg->nodes == NULL) + goto lvs_segment_fail; stripe = seg->nodes; p = grub_strstr (p, "stripes = ["); @@ -671,8 +681,9 @@ grub_lvm_detect (grub_disk_t disk, goto lvs_segment_fail; } - seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) - * seg->node_count); + seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0])); + if (seg->nodes == NULL) + goto lvs_segment_fail; p = grub_strstr (p, "mirrors = ["); if (p == NULL) @@ -760,8 +771,9 @@ grub_lvm_detect (grub_disk_t disk, } } - seg->nodes = grub_zalloc (sizeof (seg->nodes[0]) - * seg->node_count); + seg->nodes = grub_calloc (seg->node_count, sizeof (seg->nodes[0])); + if (seg->nodes == NULL) + goto lvs_segment_fail; p = grub_strstr (p, "raids = ["); if (p == NULL) diff --git a/grub-core/disk/memdisk.c b/grub-core/disk/memdisk.c index 613779cf32..2d7afaea3f 100644 --- a/grub-core/disk/memdisk.c +++ b/grub-core/disk/memdisk.c @@ -23,6 +23,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -96,8 +97,14 @@ GRUB_MOD_INIT(memdisk) grub_dprintf ("memdisk", "Found memdisk image at %p\n", memdisk_orig_addr); - memdisk_size = header->size - sizeof (struct grub_module_header); + if (grub_sub (header->size, sizeof (struct grub_module_header), &memdisk_size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while obtaining memdisk size"); + return; + } memdisk_addr = grub_malloc (memdisk_size); + if (memdisk_addr == NULL) + return; grub_dprintf ("memdisk", "Copying memdisk image to dynamic memory\n"); grub_memmove (memdisk_addr, memdisk_orig_addr, memdisk_size); diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c index 47e64805fb..21ec4072c6 100644 --- a/grub-core/disk/plainmount.c +++ b/grub-core/disk/plainmount.c @@ -24,6 +24,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -126,7 +127,7 @@ plainmount_configure_password (grub_cryptodisk_t dev, const char *hash, grub_uint8_t *derived_hash, *dh; char *p; unsigned int round, i, len, size; - grub_size_t alloc_size; + grub_size_t alloc_size, sz; grub_err_t err = GRUB_ERR_NONE; /* Support none (plain) hash */ @@ -145,7 +146,11 @@ plainmount_configure_password (grub_cryptodisk_t dev, const char *hash, * Allocate buffer for the password and for an added prefix character * for each hash round ('alloc_size' may not be a multiple of 'len'). */ - p = grub_zalloc (alloc_size + (alloc_size / len) + 1); + if (grub_add (alloc_size, (alloc_size / len), &sz) || + grub_add (sz, 1, &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while allocating size of password buffer")); + + p = grub_zalloc (sz); derived_hash = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN * 2); if (p == NULL || derived_hash == NULL) { diff --git a/grub-core/fs/affs.c b/grub-core/fs/affs.c index ed606b3f15..520a001c75 100644 --- a/grub-core/fs/affs.c +++ b/grub-core/fs/affs.c @@ -26,6 +26,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -703,11 +704,16 @@ static struct grub_fs grub_affs_fs = GRUB_MOD_INIT(affs) { - grub_fs_register (&grub_affs_fs); + if (!grub_is_lockdown ()) + { + grub_affs_fs.mod = mod; + grub_fs_register (&grub_affs_fs); + } my_mod = mod; } GRUB_MOD_FINI(affs) { - grub_fs_unregister (&grub_affs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_affs_fs); } diff --git a/grub-core/fs/archelp.c b/grub-core/fs/archelp.c index c1dcc62858..0816b28dee 100644 --- a/grub-core/fs/archelp.c +++ b/grub-core/fs/archelp.c @@ -21,6 +21,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -68,6 +69,7 @@ handle_symlink (struct grub_archelp_data *data, char *rest; char *linktarget; grub_size_t linktarget_len; + grub_size_t sz; *restart = 0; @@ -98,7 +100,12 @@ handle_symlink (struct grub_archelp_data *data, if (linktarget[0] == '\0') return GRUB_ERR_NONE; linktarget_len = grub_strlen (linktarget); - target = grub_malloc (linktarget_len + grub_strlen (*name) + 2); + + if (grub_add (linktarget_len, grub_strlen (*name), &sz) || + grub_add (sz, 2, &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("link target length overflow")); + + target = grub_malloc (sz); if (!target) return grub_errno; diff --git a/grub-core/fs/bfs.c b/grub-core/fs/bfs.c index 07cb3e3acf..c92fd79168 100644 --- a/grub-core/fs/bfs.c +++ b/grub-core/fs/bfs.c @@ -30,6 +30,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -1106,7 +1107,11 @@ GRUB_MOD_INIT (bfs) { COMPILE_TIME_ASSERT (1 << LOG_EXTENT_SIZE == sizeof (struct grub_bfs_extent)); - grub_fs_register (&grub_bfs_fs); + if (!grub_is_lockdown ()) + { + grub_bfs_fs.mod = mod; + grub_fs_register (&grub_bfs_fs); + } } #ifdef MODE_AFS @@ -1115,5 +1120,6 @@ GRUB_MOD_FINI (afs) GRUB_MOD_FINI (bfs) #endif { - grub_fs_unregister (&grub_bfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_bfs_fs); } diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c index ba0c583526..3228e17886 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -38,6 +38,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -79,9 +83,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 +127,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 +198,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; @@ -203,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 { @@ -236,6 +251,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 }; @@ -244,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) @@ -1252,11 +1281,115 @@ 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; + 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); + + 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 +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) + { + 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); + + data->fs_tree = 0; + + return GRUB_ERR_NONE; +} + + static struct grub_btrfs_data * 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) { @@ -1276,8 +1409,8 @@ grub_btrfs_mount (grub_device_t dev) } data->n_devices_allocated = 16; - data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) - * data->n_devices_allocated); + data->devices_attached = grub_calloc (data->n_devices_allocated, + sizeof (data->devices_attached[0])); if (!data->devices_attached) { grub_free (data); @@ -1287,6 +1420,16 @@ grub_btrfs_mount (grub_device_t dev) data->devices_attached[0].dev = dev; data->devices_attached[0].id = data->sblock.this_device.device_id; + if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { + err = btrfs_handle_subvol (data); + if (err) + { + grub_free (data); + return NULL; + } + } + return data; } @@ -1784,6 +1927,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, @@ -1796,31 +2024,67 @@ 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"); + grub_size_t sz; - err = get_root (data, key, tree, type); - if (err) - return err; - + follow_default = 0; origpath = grub_strdup (path); if (!origpath) return grub_errno; + if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) + { + 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 + { + err = get_root (data, key, tree, type); + if (err) + return err; + } + 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) { @@ -1831,7 +2095,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] == '.') @@ -1862,8 +2128,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; } @@ -1891,9 +2158,15 @@ find_path (struct grub_btrfs_data *data, struct grub_btrfs_dir_item *cdirel; if (elemsize > allocated) { - allocated = 2 * elemsize; + if (grub_mul (2, elemsize, &allocated) || + grub_add (allocated, 1, &sz)) + { + grub_free (path_alloc); + grub_free (origpath); + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory item size overflow")); + } grub_free (direl); - direl = grub_malloc (allocated + 1); + direl = grub_malloc (sz); if (!direl) { grub_free (path_alloc); @@ -1932,7 +2205,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; @@ -1955,8 +2230,16 @@ find_path (struct grub_btrfs_data *data, grub_free (origpath); return err; } - tmp = grub_malloc (grub_le_to_cpu64 (inode.size) - + grub_strlen (path) + 1); + + if (grub_add (grub_le_to_cpu64 (inode.size), grub_strlen (path), &sz) || + grub_add (sz, 1, &sz)) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow")); + } + tmp = grub_malloc (sz); if (!tmp) { grub_free (direl); @@ -1982,13 +2265,37 @@ find_path (struct grub_btrfs_data *data, path = path_alloc = tmp; if (path[0] == '/') { - err = get_root (data, key, tree, type); - if (err) + if (relpath && (relpath[0] == '1' || relpath[0] == 'y')) { - grub_free (direl); - grub_free (path_alloc); - grub_free (origpath); - 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 + { + *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 + { + err = get_root (data, key, tree, type); + if (err) + { + grub_free (direl); + grub_free (path_alloc); + grub_free (origpath); + return err; + } } } continue; @@ -2078,11 +2385,21 @@ grub_btrfs_dir (grub_device_t device, const char *path, grub_uint64_t tree; grub_uint8_t type; grub_size_t est_size = 0; + char *new_path = NULL; + grub_size_t sz; 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); @@ -2119,9 +2436,15 @@ grub_btrfs_dir (grub_device_t device, const char *path, } if (elemsize > allocated) { - allocated = 2 * elemsize; + if (grub_mul (2, elemsize, &allocated) || + grub_add (allocated, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory element size overflow")); + r = -grub_errno; + break; + } grub_free (direl); - direl = grub_malloc (allocated + 1); + direl = grub_malloc (sz); if (!direl) { r = -grub_errno; @@ -2209,11 +2532,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); @@ -2256,6 +2589,20 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) data->tree, file->offset, buf, len); } +static char * +btrfs_unparse_uuid(struct grub_btrfs_data *data) +{ + 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]), + grub_be_to_cpu16 (data->sblock.uuid[3]), + grub_be_to_cpu16 (data->sblock.uuid[4]), + 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) { @@ -2267,15 +2614,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) if (!data) return grub_errno; - *uuid = 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]), - grub_be_to_cpu16 (data->sblock.uuid[3]), - grub_be_to_cpu16 (data->sblock.uuid[4]), - grub_be_to_cpu16 (data->sblock.uuid[5]), - grub_be_to_cpu16 (data->sblock.uuid[6]), - grub_be_to_cpu16 (data->sblock.uuid[7])); + *uuid = btrfs_unparse_uuid(data); grub_btrfs_unmount (data); @@ -2396,6 +2735,618 @@ 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[0]) + 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; +} + +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, + 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 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, @@ -2411,12 +3362,102 @@ static struct grub_fs grub_btrfs_fs = { #endif }; +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)), + 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_btrfs_fs.mod = mod; grub_fs_register (&grub_btrfs_fs); + 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", + "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, + subvolid_set_env); + grub_env_export ("btrfs_subvol"); + grub_env_export ("btrfs_subvolid"); + grub_env_export ("btrfs_relative_path"); } 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/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c index 8ab7106afb..b62c8777cf 100644 --- a/grub-core/fs/cbfs.c +++ b/grub-core/fs/cbfs.c @@ -26,6 +26,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -390,12 +391,17 @@ GRUB_MOD_INIT (cbfs) #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN) init_cbfsdisk (); #endif - grub_fs_register (&grub_cbfs_fs); + if (!grub_is_lockdown ()) + { + grub_cbfs_fs.mod = mod; + grub_fs_register (&grub_cbfs_fs); + } } GRUB_MOD_FINI (cbfs) { - grub_fs_unregister (&grub_cbfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_cbfs_fs); #if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) && !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN) fini_cbfsdisk (); #endif diff --git a/grub-core/fs/cpio.c b/grub-core/fs/cpio.c index dab5f98988..1799f7ff5a 100644 --- a/grub-core/fs/cpio.c +++ b/grub-core/fs/cpio.c @@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size) GRUB_MOD_INIT (cpio) { + grub_cpio_fs.mod = mod; grub_fs_register (&grub_cpio_fs); } diff --git a/grub-core/fs/cpio_be.c b/grub-core/fs/cpio_be.c index 8465488921..7bed1b848c 100644 --- a/grub-core/fs/cpio_be.c +++ b/grub-core/fs/cpio_be.c @@ -52,6 +52,7 @@ read_number (const grub_uint16_t *arr, grub_size_t size) GRUB_MOD_INIT (cpio_be) { + grub_cpio_fs.mod = mod; grub_fs_register (&grub_cpio_fs); } diff --git a/grub-core/fs/cpio_common.c b/grub-core/fs/cpio_common.c index 5d41b6fdbe..45ac119a8f 100644 --- a/grub-core/fs/cpio_common.c +++ b/grub-core/fs/cpio_common.c @@ -24,6 +24,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -48,6 +49,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, struct head hd; grub_size_t namesize; grub_uint32_t modeval; + grub_size_t sz; data->hofs = data->next_hofs; @@ -60,11 +62,21 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, #endif ) return grub_error (GRUB_ERR_BAD_FS, "invalid cpio archive"); - data->size = read_number (hd.filesize, ARRAY_SIZE (hd.filesize)); + + if (grub_cast (read_number (hd.filesize, ARRAY_SIZE (hd.filesize)), &data->size)) + return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow")); + if (mtime) - *mtime = read_number (hd.mtime, ARRAY_SIZE (hd.mtime)); - modeval = read_number (hd.mode, ARRAY_SIZE (hd.mode)); - namesize = read_number (hd.namesize, ARRAY_SIZE (hd.namesize)); + { + if (grub_cast (read_number (hd.mtime, ARRAY_SIZE (hd.mtime)), mtime)) + return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow")); + } + + if (grub_cast (read_number (hd.mode, ARRAY_SIZE (hd.mode)), &modeval)) + return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow")); + + if (grub_cast (read_number (hd.namesize, ARRAY_SIZE (hd.namesize)), &namesize)) + return grub_error (GRUB_ERR_BAD_FS, N_("namesize overflow")); /* Don't allow negative numbers. */ if (namesize >= 0x80000000) @@ -76,7 +88,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, *mode = modeval; - *name = grub_malloc (namesize + 1); + if (grub_add (namesize, 1, &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("file name size overflow")); + + *name = grub_malloc (sz); if (*name == NULL) return grub_errno; @@ -110,10 +125,17 @@ grub_cpio_get_link_target (struct grub_archelp_data *data) { char *ret; grub_err_t err; + grub_size_t sz; if (data->size == 0) return grub_strdup (""); - ret = grub_malloc (data->size + 1); + + if (grub_add (data->size, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("target data size overflow")); + return NULL; + } + ret = grub_malloc (sz); if (!ret) return NULL; diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c index e1cc5e62aa..a5650c34cf 100644 --- a/grub-core/fs/ext2.c +++ b/grub-core/fs/ext2.c @@ -495,6 +495,11 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) struct grub_ext4_extent *ext; int i; grub_disk_addr_t ret; + grub_uint16_t nent; + /* maximum number of extent entries in the inode's inline extent area */ + const grub_uint16_t max_inline_ext = sizeof (inode->blocks) / sizeof (*ext) - 1; /* Minus 1 extent header. */ + /* maximum number of extent entries in the external extent block */ + const grub_uint16_t max_external_ext = EXT2_BLOCK_SIZE(data) / sizeof (*ext) - 1; /* Minus 1 extent header. */ if (grub_ext4_find_leaf (data, (struct grub_ext4_extent_header *) inode->blocks.dir_blocks, fileblock, &leaf) != GRUB_ERR_NONE) @@ -508,7 +513,23 @@ grub_ext2_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) return 0; ext = (struct grub_ext4_extent *) (leaf + 1); - for (i = 0; i < grub_le_to_cpu16 (leaf->entries); i++) + + nent = grub_le_to_cpu16 (leaf->entries); + + /* + * Determine the effective number of extent entries (nent) to process: + * If the extent header (leaf) is stored inline in the inode’s block + * area (i.e. at inode->blocks.dir_blocks), then only max_inline_ext + * entries can fit. + * Otherwise, if the header was read from an external extent block, use + * the larger limit, max_external_ext, based on the full block size. + */ + if (leaf == (struct grub_ext4_extent_header *) inode->blocks.dir_blocks) + nent = grub_min (nent, max_inline_ext); + else + nent = grub_min (nent, max_external_ext); + + for (i = 0; i < nent; i++) { if (fileblock < grub_le_to_cpu32 (ext[i].block)) break; @@ -1123,6 +1144,7 @@ static struct grub_fs grub_ext2_fs = GRUB_MOD_INIT(ext2) { + grub_ext2_fs.mod = mod; grub_fs_register (&grub_ext2_fs); my_mod = mod; } diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c index 855e24618c..72b4aa1e65 100644 --- a/grub-core/fs/f2fs.c +++ b/grub-core/fs/f2fs.c @@ -28,6 +28,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -872,6 +873,9 @@ grub_f2fs_mount (grub_disk_t disk) return data; fail: + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_FS, "not a F2FS filesystem"); + grub_free (data); return NULL; @@ -955,6 +959,7 @@ grub_f2fs_read_symlink (grub_fshelp_node_t node) char *symlink; struct grub_fshelp_node *diro = node; grub_uint64_t filesize; + grub_size_t sz; if (!diro->inode_read) { @@ -965,7 +970,12 @@ grub_f2fs_read_symlink (grub_fshelp_node_t node) filesize = grub_f2fs_file_size(&diro->inode.i); - symlink = grub_malloc (filesize + 1); + if (grub_add (filesize, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow")); + return 0; + } + symlink = grub_malloc (sz); if (!symlink) return 0; @@ -994,6 +1004,7 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) enum FILE_TYPE ftype; int name_len; int ret; + int sz; if (grub_f2fs_test_bit_le (i, ctx->bitmap) == 0) { @@ -1007,7 +1018,12 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) if (name_len >= F2FS_NAME_LEN) return 0; - filename = grub_malloc (name_len + 1); + if (grub_add (name_len, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory entry name length overflow")); + return 0; + } + filename = grub_malloc (sz); if (!filename) return 0; @@ -1350,6 +1366,7 @@ static struct grub_fs grub_f2fs_fs = { GRUB_MOD_INIT (f2fs) { + grub_f2fs_fs.mod = mod; grub_fs_register (&grub_f2fs_fs); my_mod = mod; } diff --git a/grub-core/fs/fat.c b/grub-core/fs/fat.c index c5efed7241..6e62b915dd 100644 --- a/grub-core/fs/fat.c +++ b/grub-core/fs/fat.c @@ -1312,6 +1312,7 @@ GRUB_MOD_INIT(fat) #endif { COMPILE_TIME_ASSERT (sizeof (struct grub_fat_dir_entry) == 32); + grub_fat_fs.mod = mod; grub_fs_register (&grub_fat_fs); my_mod = mod; } diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c index 91dc0e69c3..ce7581dd5f 100644 --- a/grub-core/fs/hfs.c +++ b/grub-core/fs/hfs.c @@ -379,7 +379,7 @@ grub_hfs_mount (grub_disk_t disk) volume name. */ key.parent_dir = grub_cpu_to_be32_compile_time (1); key.strlen = data->sblock.volname[0]; - grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1)); + grub_strlcpy ((char *) key.str, (char *) (data->sblock.volname + 1), sizeof (key.str)); if (grub_hfs_find_node (data, (char *) &key, data->cat_root, 0, (char *) &dir, sizeof (dir)) == 0) @@ -1434,6 +1434,7 @@ static struct grub_fs grub_hfs_fs = GRUB_MOD_INIT(hfs) { + grub_hfs_fs.mod = mod; if (!grub_is_lockdown ()) grub_fs_register (&grub_hfs_fs); my_mod = mod; diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c index 295822f694..3f203abccd 100644 --- a/grub-core/fs/hfsplus.c +++ b/grub-core/fs/hfsplus.c @@ -405,7 +405,7 @@ grub_hfsplus_mount (grub_disk_t disk) fail: - if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE) grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem"); grub_free (data); @@ -1176,6 +1176,7 @@ static struct grub_fs grub_hfsplus_fs = GRUB_MOD_INIT(hfsplus) { + grub_hfsplus_fs.mod = mod; grub_fs_register (&grub_hfsplus_fs); my_mod = mod; } diff --git a/grub-core/fs/hfspluscomp.c b/grub-core/fs/hfspluscomp.c index 48ae438d85..a80954ee61 100644 --- a/grub-core/fs/hfspluscomp.c +++ b/grub-core/fs/hfspluscomp.c @@ -244,14 +244,19 @@ hfsplus_open_compressed_real (struct grub_hfsplus_file *node) return 0; } node->compress_index_size = grub_le_to_cpu32 (index_size); - node->compress_index = grub_malloc (node->compress_index_size - * sizeof (node->compress_index[0])); + node->compress_index = grub_calloc (node->compress_index_size, + sizeof (node->compress_index[0])); if (!node->compress_index) { node->compressed = 0; grub_free (attr_node); return grub_errno; } + + /* + * The node->compress_index_size * sizeof (node->compress_index[0]) is safe here + * due to relevant checks done in grub_calloc() above. + */ if (grub_hfsplus_read_file (node, 0, 0, 0x104 + sizeof (index_size), node->compress_index_size diff --git a/grub-core/fs/iso9660.c b/grub-core/fs/iso9660.c index 8c348b59a5..c73cb9ce05 100644 --- a/grub-core/fs/iso9660.c +++ b/grub-core/fs/iso9660.c @@ -551,6 +551,9 @@ grub_iso9660_mount (grub_disk_t disk) return data; fail: + if (grub_errno == GRUB_ERR_NONE) + grub_error (GRUB_ERR_BAD_FS, "not a ISO9660 filesystem"); + grub_free (data); return 0; } @@ -625,9 +628,19 @@ susp_iterate_dir (struct grub_iso9660_susp_entry *entry, filename type is stored. */ /* FIXME: Fix this slightly improper cast. */ if (entry->data[0] & GRUB_ISO9660_RR_DOT) - ctx->filename = (char *) "."; + { + if (ctx->filename_alloc) + grub_free (ctx->filename); + ctx->filename_alloc = 0; + ctx->filename = (char *) "."; + } else if (entry->data[0] & GRUB_ISO9660_RR_DOTDOT) - ctx->filename = (char *) ".."; + { + if (ctx->filename_alloc) + grub_free (ctx->filename); + ctx->filename_alloc = 0; + ctx->filename = (char *) ".."; + } else if (entry->len >= 5) { grub_size_t off = 0, csize = 1; @@ -1247,6 +1260,7 @@ static struct grub_fs grub_iso9660_fs = GRUB_MOD_INIT(iso9660) { + grub_iso9660_fs.mod = mod; grub_fs_register (&grub_iso9660_fs); my_mod = mod; } diff --git a/grub-core/fs/jfs.c b/grub-core/fs/jfs.c index 6f7c439049..03be9ef4cf 100644 --- a/grub-core/fs/jfs.c +++ b/grub-core/fs/jfs.c @@ -26,6 +26,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -41,6 +42,13 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define GRUB_JFS_TREE_LEAF 2 +/* + * Define max entries stored in-line in an inode. + * https://jfs.sourceforge.net/project/pub/jfslayout.pdf + */ +#define GRUB_JFS_INODE_INLINE_ENTRIES 8 +#define GRUB_JFS_DIR_MAX_SLOTS 128 + struct grub_jfs_sblock { /* The magic for JFS. It should contain the string "JFS1". */ @@ -203,9 +211,9 @@ struct grub_jfs_inode grub_uint8_t freecnt; grub_uint8_t freelist; grub_uint32_t idotdot; - grub_uint8_t sorted[8]; + grub_uint8_t sorted[GRUB_JFS_INODE_INLINE_ENTRIES]; } header; - struct grub_jfs_leaf_dirent dirents[8]; + struct grub_jfs_leaf_dirent dirents[GRUB_JFS_INODE_INLINE_ENTRIES]; } GRUB_PACKED dir; /* Fast symlink. */ struct @@ -258,7 +266,21 @@ static grub_dl_t my_mod; static grub_err_t grub_jfs_lookup_symlink (struct grub_jfs_data *data, grub_uint32_t ino); -static grub_int64_t +/* + * An extent's offset, physical and logical, is represented as a 40-bit value. + * This 40-bit value is split into two parts: + * - offset1: the most signficant 8 bits of the offset, + * - offset2: the least significant 32 bits of the offset. + * + * This function calculates and returns the 64-bit offset of an extent. + */ +static grub_uint64_t +get_ext_offset (grub_uint8_t offset1, grub_uint32_t offset2) +{ + return (((grub_uint64_t) offset1 << 32) | grub_le_to_cpu32 (offset2)); +} + +static grub_uint64_t getblk (struct grub_jfs_treehead *treehead, struct grub_jfs_tree_extent *extents, int max_extents, @@ -267,28 +289,33 @@ getblk (struct grub_jfs_treehead *treehead, { int found = -1; int i; + grub_uint64_t ext_offset, ext_blk; + + grub_errno = GRUB_ERR_NONE; for (i = 0; i < grub_le_to_cpu16 (treehead->count) - 2 && i < max_extents; i++) { + ext_offset = get_ext_offset (extents[i].offset1, extents[i].offset2); + ext_blk = get_ext_offset (extents[i].extent.blk1, extents[i].extent.blk2); + if (treehead->flags & GRUB_JFS_TREE_LEAF) { /* Read the leafnode. */ - if (grub_le_to_cpu32 (extents[i].offset2) <= blk + if (ext_offset <= blk && ((grub_le_to_cpu16 (extents[i].extent.length)) + (extents[i].extent.length2 << 16) - + grub_le_to_cpu32 (extents[i].offset2)) > blk) - return (blk - grub_le_to_cpu32 (extents[i].offset2) - + grub_le_to_cpu32 (extents[i].extent.blk2)); + + ext_offset) > blk) + return (blk - ext_offset + ext_blk); } else - if (blk >= grub_le_to_cpu32 (extents[i].offset2)) + if (blk >= ext_offset) found = i; } if (found != -1) { - grub_int64_t ret = -1; + grub_uint64_t ret = 0; struct { struct grub_jfs_treehead treehead; @@ -297,13 +324,12 @@ getblk (struct grub_jfs_treehead *treehead, tree = grub_zalloc (sizeof (*tree)); if (!tree) - return -1; + return 0; if (!grub_disk_read (data->disk, - ((grub_disk_addr_t) grub_le_to_cpu32 (extents[found].extent.blk2)) - << (grub_le_to_cpu16 (data->sblock.log2_blksz) - - GRUB_DISK_SECTOR_BITS), 0, - sizeof (*tree), (char *) tree)) + (grub_disk_addr_t) ext_blk + << (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS), + 0, sizeof (*tree), (char *) tree)) { if (grub_memcmp (&tree->treehead, treehead, sizeof (struct grub_jfs_treehead)) || grub_memcmp (&tree->extents, extents, 254 * sizeof (struct grub_jfs_tree_extent))) @@ -311,19 +337,20 @@ getblk (struct grub_jfs_treehead *treehead, else { grub_error (GRUB_ERR_BAD_FS, "jfs: infinite recursion detected"); - ret = -1; + ret = 0; } } grub_free (tree); return ret; } - return -1; + grub_error (GRUB_ERR_READ_ERROR, "jfs: block %" PRIuGRUB_UINT64_T " not found", blk); + return 0; } /* Get the block number for the block BLK in the node INODE in the mounted filesystem DATA. */ -static grub_int64_t +static grub_uint64_t grub_jfs_blkno (struct grub_jfs_data *data, struct grub_jfs_inode *inode, grub_uint64_t blk) { @@ -354,7 +381,7 @@ grub_jfs_read_inode (struct grub_jfs_data *data, grub_uint32_t ino, sizeof (iag_inodes), &iag_inodes)) return grub_errno; - inoblk = grub_le_to_cpu32 (iag_inodes[inoext].blk2); + inoblk = get_ext_offset (iag_inodes[inoext].blk1, iag_inodes[inoext].blk2); inoblk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS); inoblk += inonum; @@ -453,6 +480,13 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) /* Check if the entire tree is contained within the inode. */ if (inode->file.tree.flags & GRUB_JFS_TREE_LEAF) { + if (inode->dir.header.count > GRUB_JFS_INODE_INLINE_ENTRIES) + { + grub_free (diro); + grub_error (GRUB_ERR_BAD_FS, N_("invalid JFS inode")); + return 0; + } + diro->leaf = inode->dir.dirents; diro->next_leaf = (struct grub_jfs_leaf_next_dirent *) de; diro->sorted = inode->dir.header.sorted; @@ -468,7 +502,16 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) return 0; } - blk = grub_le_to_cpu32 (de[inode->dir.header.sorted[0]].ex.blk2); + if (inode->dir.header.sorted[0] >= GRUB_JFS_DIR_MAX_SLOTS) + { + grub_error (GRUB_ERR_BAD_FS, N_("invalid directory slot index")); + grub_free (diro->dirpage); + grub_free (diro); + return 0; + } + + blk = get_ext_offset (de[inode->dir.header.sorted[0]].ex.blk1, + de[inode->dir.header.sorted[0]].ex.blk2); blk <<= (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS); /* Read in the nodes until we are on the leaf node level. */ @@ -486,7 +529,7 @@ grub_jfs_opendir (struct grub_jfs_data *data, struct grub_jfs_inode *inode) de = (struct grub_jfs_internal_dirent *) diro->dirpage->dirent; index = diro->dirpage->sorted[diro->dirpage->header.sindex * 32]; - blk = (grub_le_to_cpu32 (de[index].ex.blk2) + blk = (get_ext_offset (de[index].ex.blk1, de[index].ex.blk2) << (grub_le_to_cpu16 (data->sblock.log2_blksz) - GRUB_DISK_SECTOR_BITS)); } while (!(diro->dirpage->header.flags & GRUB_JFS_TREE_LEAF)); @@ -716,7 +759,6 @@ grub_jfs_find_file (struct grub_jfs_data *data, const char *path, grub_uint32_t dirino = grub_le_to_cpu32 (data->currinode.inode); grub_jfs_closedir (diro); - diro = 0; if (grub_jfs_read_inode (data, ino, &data->currinode)) break; @@ -963,11 +1005,16 @@ static struct grub_fs grub_jfs_fs = GRUB_MOD_INIT(jfs) { - grub_fs_register (&grub_jfs_fs); + if (!grub_is_lockdown ()) + { + grub_jfs_fs.mod = mod; + grub_fs_register (&grub_jfs_fs); + } my_mod = mod; } GRUB_MOD_FINI(jfs) { - grub_fs_unregister (&grub_jfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_jfs_fs); } diff --git a/grub-core/fs/minix.c b/grub-core/fs/minix.c index 5354951d10..4440fcca83 100644 --- a/grub-core/fs/minix.c +++ b/grub-core/fs/minix.c @@ -25,6 +25,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -734,7 +735,11 @@ GRUB_MOD_INIT(minix) #endif #endif { - grub_fs_register (&grub_minix_fs); + if (!grub_is_lockdown ()) + { + grub_minix_fs.mod = mod; + grub_fs_register (&grub_minix_fs); + } my_mod = mod; } @@ -756,5 +761,6 @@ GRUB_MOD_FINI(minix) #endif #endif { - grub_fs_unregister (&grub_minix_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_minix_fs); } diff --git a/grub-core/fs/newc.c b/grub-core/fs/newc.c index 4fb8b2e3d2..43b7f8b642 100644 --- a/grub-core/fs/newc.c +++ b/grub-core/fs/newc.c @@ -64,6 +64,7 @@ read_number (const char *str, grub_size_t size) GRUB_MOD_INIT (newc) { + grub_cpio_fs.mod = mod; grub_fs_register (&grub_cpio_fs); } diff --git a/grub-core/fs/nilfs2.c b/grub-core/fs/nilfs2.c index fc7374ead4..26e6077ff2 100644 --- a/grub-core/fs/nilfs2.c +++ b/grub-core/fs/nilfs2.c @@ -34,6 +34,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -1231,11 +1232,16 @@ GRUB_MOD_INIT (nilfs2) grub_nilfs2_dat_entry)); COMPILE_TIME_ASSERT (1 << LOG_INODE_SIZE == sizeof (struct grub_nilfs2_inode)); - grub_fs_register (&grub_nilfs2_fs); + if (!grub_is_lockdown ()) + { + grub_nilfs2_fs.mod = mod; + grub_fs_register (&grub_nilfs2_fs); + } my_mod = mod; } GRUB_MOD_FINI (nilfs2) { - grub_fs_unregister (&grub_nilfs2_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_nilfs2_fs); } diff --git a/grub-core/fs/ntfs.c b/grub-core/fs/ntfs.c index de435aa14d..1a5f3b6374 100644 --- a/grub-core/fs/ntfs.c +++ b/grub-core/fs/ntfs.c @@ -27,6 +27,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -70,6 +71,25 @@ res_attr_data_len (void *res_attr_ptr) return u32at (res_attr_ptr, 0x10); } +/* Return the next attribute if it exists, otherwise return NULL. */ +static grub_uint8_t * +next_attribute (grub_uint8_t *curr_attribute, void *end) +{ + grub_uint8_t *next = curr_attribute; + + /* + * Need to verify we aren't exceeding the end of the buffer by reading the + * header for the current attribute + */ + if (curr_attribute + GRUB_NTFS_ATTRIBUTE_HEADER_SIZE >= (grub_uint8_t *) end) + return NULL; + + next += u16at (curr_attribute, 4); + + return next; +} + + grub_ntfscomp_func_t grub_ntfscomp_func; static grub_err_t @@ -119,13 +139,20 @@ static grub_err_t read_data (struct grub_ntfs_attr *at, grub_uint8_t *pa, grub_disk_read_hook_t read_hook, void *read_hook_data); -static void +static grub_err_t 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 + first_attr_off (mft->buf); + at->end = mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR); + + if (at->attr_nxt > at->end) + return grub_error (GRUB_ERR_BAD_FS, "attributes start outside the MFT"); + at->attr_end = at->emft_buf = at->edat_buf = at->sbuf = NULL; + + return GRUB_ERR_NONE; } static void @@ -139,16 +166,18 @@ free_attr (struct grub_ntfs_attr *at) static grub_uint8_t * find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) { + grub_uint8_t *mft_end; + if (at->flags & GRUB_NTFS_AF_ALST) { retry: - while (at->attr_nxt < at->attr_end) + while (at->attr_nxt) { at->attr_cur = at->attr_nxt; - at->attr_nxt += u16at (at->attr_cur, 4); + at->attr_nxt = next_attribute (at->attr_cur, at->attr_end); if ((*at->attr_cur == attr) || (attr == 0)) { - grub_uint8_t *new_pos; + grub_uint8_t *new_pos, *end; if (at->flags & GRUB_NTFS_AF_MMFT) { @@ -172,15 +201,36 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) return NULL; } + /* + * Only time emft_bufs is defined is in this function, with this + * size. + */ + grub_size_t emft_buf_size = + at->mft->data->mft_size << GRUB_NTFS_BLK_SHR; + + /* + * Needs to be enough space for the successful case to even + * bother. + */ + if (first_attr_off (at->emft_buf) >= (emft_buf_size - 0x18 - 2)) + { + grub_error (GRUB_ERR_BAD_FS, + "can\'t find 0x%X in attribute list", + (unsigned char) *at->attr_cur); + return NULL; + } + new_pos = &at->emft_buf[first_attr_off (at->emft_buf)]; - while (*new_pos != 0xFF) + end = &at->emft_buf[emft_buf_size]; + + while (new_pos && *new_pos != 0xFF) { if ((*new_pos == *at->attr_cur) && (u16at (new_pos, 0xE) == u16at (at->attr_cur, 0x18))) { return new_pos; } - new_pos += u16at (new_pos, 4); + new_pos = next_attribute (new_pos, end); } grub_error (GRUB_ERR_BAD_FS, "can\'t find 0x%X in attribute list", @@ -191,9 +241,10 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) return NULL; } at->attr_cur = at->attr_nxt; - while (*at->attr_cur != 0xFF) + mft_end = at->mft->buf + (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR); + while (at->attr_cur < mft_end && *at->attr_cur != 0xFF) { - at->attr_nxt += u16at (at->attr_cur, 4); + at->attr_nxt = next_attribute (at->attr_cur, at->end); if (*at->attr_cur == GRUB_NTFS_AT_ATTRIBUTE_LIST) at->attr_end = at->attr_cur; if ((*at->attr_cur == attr) || (attr == 0)) @@ -236,13 +287,18 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) 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) + + /* From this point on pa_end is the end of the buffer */ + at->end = pa_end; + + while (at->attr_nxt) { if ((*at->attr_nxt == attr) || (attr == 0)) break; - at->attr_nxt += u16at (at->attr_nxt, 4); + at->attr_nxt = next_attribute (at->attr_nxt, pa_end); } - if (at->attr_nxt >= at->attr_end) + + if (at->attr_nxt >= at->attr_end || at->attr_nxt == NULL) return NULL; if ((at->flags & GRUB_NTFS_AF_MMFT) && (attr == GRUB_NTFS_AT_DATA)) @@ -263,7 +319,8 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) grub_cpu_to_le32 (at->mft->data->mft_start + 1)); pa = at->attr_nxt + u16at (pa, 4); - while (pa < at->attr_end) + + while (pa) { if (*pa != attr) break; @@ -279,7 +336,7 @@ find_attr (struct grub_ntfs_attr *at, grub_uint8_t attr) u32at (pa, 0x10) * (at->mft->data->mft_size << GRUB_NTFS_BLK_SHR), at->mft->data->mft_size << GRUB_NTFS_BLK_SHR, 0, 0, 0)) return NULL; - pa += u16at (pa, 4); + pa = next_attribute (pa, pa_end); } at->attr_nxt = at->attr_cur; at->flags &= ~GRUB_NTFS_AF_GPOS; @@ -295,7 +352,9 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft, { grub_uint8_t *pa; - init_attr (at, mft); + if (init_attr (at, mft) != GRUB_ERR_NONE) + return NULL; + pa = find_attr (at, attr); if (pa == NULL) return NULL; @@ -311,7 +370,8 @@ locate_attr (struct grub_ntfs_attr *at, struct grub_ntfs_file *mft, } grub_errno = GRUB_ERR_NONE; free_attr (at); - init_attr (at, mft); + if (init_attr (at, mft) != GRUB_ERR_NONE) + return NULL; pa = find_attr (at, attr); } return pa; @@ -363,7 +423,7 @@ grub_ntfs_read_run_list (struct grub_ntfs_rlst * ctx) goto retry; } } - return grub_error (GRUB_ERR_BAD_FS, "run list overflown"); + return grub_error (GRUB_ERR_BAD_FS, "run list overflow"); } ctx->curr_vcn = ctx->next_vcn; ctx->next_vcn += read_run_data (run, c1, 0); /* length of current VCN */ @@ -513,14 +573,15 @@ read_attr (struct grub_ntfs_attr *at, grub_uint8_t *dest, grub_disk_addr_t ofs, else vcn = ofs >> (at->mft->data->log_spc + GRUB_NTFS_BLK_SHR); pa = at->attr_nxt + u16at (at->attr_nxt, 4); - while (pa < at->attr_end) + + while (pa) { if (*pa != attr) break; if (u32at (pa, 8) > vcn) break; at->attr_nxt = pa; - pa += u16at (pa, 4); + pa = next_attribute (pa, at->attr_end); } } pp = find_attr (at, attr); @@ -582,7 +643,7 @@ init_file (struct grub_ntfs_file *mft, grub_uint64_t mftno) mft->attr.attr_end = 0; /* Don't jump to attribute list */ } else - init_attr (&mft->attr, mft); + return init_attr (&mft->attr, mft); return 0; } @@ -808,7 +869,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, bmp = NULL; at = &attr; - init_attr (at, mft); + if (init_attr (at, mft) != GRUB_ERR_NONE) + return 0; + while (1) { cur_pos = find_attr (at, GRUB_NTFS_AT_INDEX_ROOT); @@ -839,7 +902,9 @@ grub_ntfs_iterate_dir (grub_fshelp_node_t dir, bitmap = NULL; bitmap_len = 0; free_attr (at); + /* No need to check errors here, as it will already be fine */ init_attr (at, mft); + while ((cur_pos = find_attr (at, GRUB_NTFS_AT_BITMAP)) != NULL) { int ofs; @@ -1204,6 +1269,7 @@ grub_ntfs_label (grub_device_t device, char **label) struct grub_ntfs_data *data = 0; struct grub_fshelp_node *mft = 0; grub_uint8_t *pa; + grub_err_t err; grub_dl_ref (my_mod); @@ -1229,7 +1295,10 @@ grub_ntfs_label (grub_device_t device, char **label) goto fail; } - init_attr (&mft->attr, mft); + err = init_attr (&mft->attr, mft); + if (err != GRUB_ERR_NONE) + return err; + pa = find_attr (&mft->attr, GRUB_NTFS_AT_VOLUME_NAME); if (pa >= mft->buf + (mft->data->mft_size << GRUB_NTFS_BLK_SHR)) @@ -1320,11 +1389,16 @@ static struct grub_fs grub_ntfs_fs = GRUB_MOD_INIT (ntfs) { - grub_fs_register (&grub_ntfs_fs); + if (!grub_is_lockdown ()) + { + grub_ntfs_fs.mod = mod; + grub_fs_register (&grub_ntfs_fs); + } my_mod = mod; } GRUB_MOD_FINI (ntfs) { - grub_fs_unregister (&grub_ntfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_ntfs_fs); } diff --git a/grub-core/fs/ntfscomp.c b/grub-core/fs/ntfscomp.c index a009f2c2dd..b68bf5e40a 100644 --- a/grub-core/fs/ntfscomp.c +++ b/grub-core/fs/ntfscomp.c @@ -22,6 +22,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -29,7 +30,7 @@ static grub_err_t decomp_nextvcn (struct grub_ntfs_comp *cc) { if (cc->comp_head >= cc->comp_tail) - return grub_error (GRUB_ERR_BAD_FS, "compression block overflown"); + return grub_error (GRUB_ERR_BAD_FS, "compression block overflow"); if (grub_disk_read (cc->disk, (cc->comp_table[cc->comp_head].next_lcn - @@ -310,6 +311,7 @@ ntfscomp (grub_uint8_t *dest, grub_disk_addr_t ofs, { grub_err_t ret; grub_disk_addr_t vcn; + int log_sz; if (ctx->attr->sbuf) { @@ -349,7 +351,12 @@ ntfscomp (grub_uint8_t *dest, grub_disk_addr_t ofs, } ctx->comp.comp_head = ctx->comp.comp_tail = 0; - ctx->comp.cbuf = grub_malloc (1 << (ctx->comp.log_spc + GRUB_NTFS_BLK_SHR)); + if (grub_add (ctx->comp.log_spc, GRUB_NTFS_BLK_SHR, &log_sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("compression buffer size overflow")); + return 0; + } + ctx->comp.cbuf = grub_malloc (1 << log_sz); if (!ctx->comp.cbuf) return 0; diff --git a/grub-core/fs/odc.c b/grub-core/fs/odc.c index 790000622d..8e4e8aeac8 100644 --- a/grub-core/fs/odc.c +++ b/grub-core/fs/odc.c @@ -52,6 +52,7 @@ read_number (const char *str, grub_size_t size) GRUB_MOD_INIT (odc) { + grub_cpio_fs.mod = mod; grub_fs_register (&grub_cpio_fs); } diff --git a/grub-core/fs/proc.c b/grub-core/fs/proc.c index 5f516502d4..bcde433495 100644 --- a/grub-core/fs/proc.c +++ b/grub-core/fs/proc.c @@ -192,6 +192,7 @@ static struct grub_fs grub_procfs_fs = GRUB_MOD_INIT (procfs) { + grub_procfs_fs.mod = mod; grub_disk_dev_register (&grub_procfs_dev); grub_fs_register (&grub_procfs_fs); } diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c index 36b26ac98a..ca47e0a43f 100644 --- a/grub-core/fs/reiserfs.c +++ b/grub-core/fs/reiserfs.c @@ -39,19 +39,10 @@ #include #include #include +#include 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 +1067,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 +1106,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 +1152,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 +1196,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 +1215,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, @@ -1417,11 +1408,16 @@ static struct grub_fs grub_reiserfs_fs = GRUB_MOD_INIT(reiserfs) { - grub_fs_register (&grub_reiserfs_fs); + if (!grub_is_lockdown ()) + { + grub_reiserfs_fs.mod = mod; + grub_fs_register (&grub_reiserfs_fs); + } my_mod = mod; } GRUB_MOD_FINI(reiserfs) { - grub_fs_unregister (&grub_reiserfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_reiserfs_fs); } diff --git a/grub-core/fs/romfs.c b/grub-core/fs/romfs.c index 1f7dcfca1d..eafab03b25 100644 --- a/grub-core/fs/romfs.c +++ b/grub-core/fs/romfs.c @@ -23,6 +23,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -475,10 +476,15 @@ static struct grub_fs grub_romfs_fs = GRUB_MOD_INIT(romfs) { - grub_fs_register (&grub_romfs_fs); + if (!grub_is_lockdown ()) + { + grub_romfs_fs.mod = mod; + grub_fs_register (&grub_romfs_fs); + } } GRUB_MOD_FINI(romfs) { - grub_fs_unregister (&grub_romfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_romfs_fs); } diff --git a/grub-core/fs/sfs.c b/grub-core/fs/sfs.c index 983e880088..bad4ae8d10 100644 --- a/grub-core/fs/sfs.c +++ b/grub-core/fs/sfs.c @@ -26,6 +26,7 @@ #include #include #include +#include #include GRUB_MOD_LICENSE ("GPLv3+"); @@ -428,6 +429,9 @@ grub_sfs_mount (grub_disk_t disk) - 24 /* offsetof (struct grub_sfs_objc, objects) */ - 25); /* offsetof (struct grub_sfs_obj, filename) */ data->label = grub_zalloc (max_len + 1); + if (data->label == NULL) + goto fail; + grub_strncpy (data->label, (char *) rootobjc->objects[0].filename, max_len); grub_free (rootobjc_data); @@ -779,11 +783,16 @@ static struct grub_fs grub_sfs_fs = GRUB_MOD_INIT(sfs) { - grub_fs_register (&grub_sfs_fs); + if (!grub_is_lockdown ()) + { + grub_sfs_fs.mod = mod; + grub_fs_register (&grub_sfs_fs); + } my_mod = mod; } GRUB_MOD_FINI(sfs) { - grub_fs_unregister (&grub_sfs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_sfs_fs); } diff --git a/grub-core/fs/squash4.c b/grub-core/fs/squash4.c index a30e6ebe14..cf2bca8221 100644 --- a/grub-core/fs/squash4.c +++ b/grub-core/fs/squash4.c @@ -460,11 +460,11 @@ grub_squash_read_symlink (grub_fshelp_node_t node) { char *ret; grub_err_t err; - grub_size_t sz; + grub_uint32_t sz; if (grub_add (grub_le_to_cpu32 (node->ino.symlink.namelen), 1, &sz)) { - grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected")); + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink name length overflow")); return NULL; } @@ -580,6 +580,7 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, struct grub_squash_dirent di; struct grub_squash_inode ino; grub_size_t sz; + grub_uint16_t nlen; err = read_chunk (dir->data, &di, sizeof (di), grub_le_to_cpu64 (dir->data->sb.diroffset) @@ -595,7 +596,12 @@ grub_squash_iterate_dir (grub_fshelp_node_t dir, if (err) return 0; - buf = grub_malloc (grub_le_to_cpu16 (di.namelen) + 2); + if (grub_add (grub_le_to_cpu16 (di.namelen), 2, &nlen)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); + return 0; + } + buf = grub_malloc (nlen); if (!buf) return 0; err = read_chunk (dir->data, buf, @@ -816,10 +822,10 @@ direct_read (struct grub_squash_data *data, break; } total_blocks = ((total_size + data->blksz - 1) >> data->log2_blksz); - ino->block_sizes = grub_malloc (total_blocks - * sizeof (ino->block_sizes[0])); - ino->cumulated_block_sizes = grub_malloc (total_blocks - * sizeof (ino->cumulated_block_sizes[0])); + ino->block_sizes = grub_calloc (total_blocks, + sizeof (ino->block_sizes[0])); + ino->cumulated_block_sizes = grub_calloc (total_blocks, + sizeof (ino->cumulated_block_sizes[0])); if (!ino->block_sizes || !ino->cumulated_block_sizes) { grub_free (ino->block_sizes); @@ -1044,6 +1050,7 @@ static struct grub_fs grub_squash_fs = GRUB_MOD_INIT(squash4) { + grub_squash_fs.mod = mod; grub_fs_register (&grub_squash_fs); } diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c index c551ed6b52..1eaa5349f3 100644 --- a/grub-core/fs/tar.c +++ b/grub-core/fs/tar.c @@ -25,6 +25,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -76,8 +77,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, { struct head hd; int reread = 0, have_longname = 0, have_longlink = 0; + grub_size_t sz; data->hofs = data->next_hofs; + *name = NULL; for (reread = 0; reread < 3; reread++) { @@ -96,8 +99,13 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, if (hd.typeflag == 'L') { grub_err_t err; - grub_size_t namesize = read_number (hd.size, sizeof (hd.size)); - *name = grub_malloc (namesize + 1); + grub_size_t namesize; + + if (grub_cast (read_number (hd.size, sizeof (hd.size)), &namesize) || + grub_add (namesize, 1, &sz)) + return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow")); + + *name = grub_malloc (sz); if (*name == NULL) return grub_errno; err = grub_disk_read (data->disk, 0, @@ -116,16 +124,21 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, if (hd.typeflag == 'K') { grub_err_t err; - grub_size_t linksize = read_number (hd.size, sizeof (hd.size)); - if (data->linkname_alloc < linksize + 1) + grub_size_t linksize; + + if (grub_cast (read_number (hd.size, sizeof (hd.size)), &linksize) || + grub_add (linksize, 1, &sz)) + return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow")); + + if (data->linkname_alloc < sz) { char *n; - n = grub_calloc (2, linksize + 1); + n = grub_calloc (2, sz); if (!n) return grub_errno; grub_free (data->linkname); data->linkname = n; - data->linkname_alloc = 2 * (linksize + 1); + data->linkname_alloc = 2 * (sz); } err = grub_disk_read (data->disk, 0, @@ -148,7 +161,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, while (extra_size < sizeof (hd.prefix) && hd.prefix[extra_size]) extra_size++; - *name = grub_malloc (sizeof (hd.name) + extra_size + 2); + + if (grub_add (sizeof (hd.name) + 2, extra_size, &sz)) + return grub_error (GRUB_ERR_BAD_FS, N_("long name size overflow")); + *name = grub_malloc (sz); if (*name == NULL) return grub_errno; if (hd.prefix[0]) @@ -160,15 +176,22 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, (*name)[extra_size + sizeof (hd.name)] = 0; } - data->size = read_number (hd.size, sizeof (hd.size)); + if (grub_cast (read_number (hd.size, sizeof (hd.size)), &data->size)) + return grub_error (GRUB_ERR_BAD_FS, N_("data size overflow")); + data->dofs = data->hofs + GRUB_DISK_SECTOR_SIZE; data->next_hofs = data->dofs + ((data->size + GRUB_DISK_SECTOR_SIZE - 1) & ~(GRUB_DISK_SECTOR_SIZE - 1)); if (mtime) - *mtime = read_number (hd.mtime, sizeof (hd.mtime)); + { + if (grub_cast (read_number (hd.mtime, sizeof (hd.mtime)), mtime)) + return grub_error (GRUB_ERR_BAD_FS, N_("mtime overflow")); + } if (mode) { - *mode = read_number (hd.mode, sizeof (hd.mode)); + if (grub_cast (read_number (hd.mode, sizeof (hd.mode)), mode)) + return grub_error (GRUB_ERR_BAD_FS, N_("mode overflow")); + switch (hd.typeflag) { /* Hardlink. */ @@ -202,6 +225,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name, } return GRUB_ERR_NONE; } + + if (*name == NULL) + return grub_error (GRUB_ERR_BAD_FS, "invalid tar archive"); + return GRUB_ERR_NONE; } @@ -336,6 +363,7 @@ static struct grub_fs grub_cpio_fs = { GRUB_MOD_INIT (tar) { + grub_cpio_fs.mod = mod; grub_fs_register (&grub_cpio_fs); } diff --git a/grub-core/fs/udf.c b/grub-core/fs/udf.c index b836e61075..3d5ee5af50 100644 --- a/grub-core/fs/udf.c +++ b/grub-core/fs/udf.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -1455,11 +1456,16 @@ static struct grub_fs grub_udf_fs = { GRUB_MOD_INIT (udf) { - grub_fs_register (&grub_udf_fs); + if (!grub_is_lockdown ()) + { + grub_udf_fs.mod = mod; + grub_fs_register (&grub_udf_fs); + } my_mod = mod; } GRUB_MOD_FINI (udf) { - grub_fs_unregister (&grub_udf_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_udf_fs); } diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c index a354c92d93..8b5adbd48d 100644 --- a/grub-core/fs/ufs.c +++ b/grub-core/fs/ufs.c @@ -25,6 +25,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -463,7 +464,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino) /* Check against zero is paylindromic, no need to swap. */ if (data->inode.nblocks == 0 && INODE_SIZE (data) <= sizeof (data->inode.symlink)) - grub_strcpy (symlink, (char *) data->inode.symlink); + grub_strlcpy (symlink, (char *) data->inode.symlink, sz); else { if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0) @@ -899,7 +900,11 @@ GRUB_MOD_INIT(ufs1) #endif #endif { - grub_fs_register (&grub_ufs_fs); + if (!grub_is_lockdown ()) + { + grub_ufs_fs.mod = mod; + grub_fs_register (&grub_ufs_fs); + } my_mod = mod; } @@ -913,6 +918,7 @@ GRUB_MOD_FINI(ufs1) #endif #endif { - grub_fs_unregister (&grub_ufs_fs); + if (!grub_is_lockdown ()) + grub_fs_unregister (&grub_ufs_fs); } diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c index bc2224dbb4..0519105aaf 100644 --- a/grub-core/fs/xfs.c +++ b/grub-core/fs/xfs.c @@ -88,7 +88,10 @@ 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 */ +#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */ +#define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6) /* exchangerange supported */ +#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 7) /* parent pointers */ +#define XFS_SB_FEAT_INCOMPAT_METADIR (1 << 8) /* metadata dir tree */ /* * Directory entries with ftype are explicitly handled by GRUB code. @@ -98,6 +101,15 @@ GRUB_MOD_LICENSE ("GPLv3+"); * * We do not currently verify metadata UUID, so it is safe to read filesystems * with the XFS_SB_FEAT_INCOMPAT_META_UUID feature. + * + * We do not currently replay the log, so it is safe to read filesystems + * with the XFS_SB_FEAT_INCOMPAT_EXCHRANGE feature. + * + * We do not currently read directory parent pointers, so it is safe to read + * filesystems with the XFS_SB_FEAT_INCOMPAT_PARENT feature. + * + * We do not currently look at realtime or quota metadata, so it is safe to + * read filesystems with the XFS_SB_FEAT_INCOMPAT_METADIR feature. */ #define XFS_SB_FEAT_INCOMPAT_SUPPORTED \ (XFS_SB_FEAT_INCOMPAT_FTYPE | \ @@ -105,7 +117,10 @@ GRUB_MOD_LICENSE ("GPLv3+"); XFS_SB_FEAT_INCOMPAT_META_UUID | \ XFS_SB_FEAT_INCOMPAT_BIGTIME | \ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \ - XFS_SB_FEAT_INCOMPAT_NREXT64) + XFS_SB_FEAT_INCOMPAT_NREXT64 | \ + XFS_SB_FEAT_INCOMPAT_EXCHRANGE | \ + XFS_SB_FEAT_INCOMPAT_PARENT | \ + XFS_SB_FEAT_INCOMPAT_METADIR) struct grub_xfs_sblock { @@ -327,6 +342,8 @@ static int grub_xfs_sb_valid(struct grub_xfs_data *data) } return 1; } + + grub_error (GRUB_ERR_BAD_FS, "unsupported XFS filesystem version"); return 0; } @@ -595,6 +612,17 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock) do { grub_uint64_t i; + grub_addr_t keys_end, data_end; + + if (grub_mul (sizeof (grub_uint64_t), nrec, &keys_end) || + grub_add ((grub_addr_t) keys, keys_end, &keys_end) || + grub_add ((grub_addr_t) node->data, node->data->data_size, &data_end) || + keys_end > data_end) + { + grub_error (GRUB_ERR_BAD_FS, "invalid number of XFS root keys"); + grub_free (leaf); + return 0; + } for (i = 0; i < nrec; i++) { @@ -705,6 +733,7 @@ static char * grub_xfs_read_symlink (grub_fshelp_node_t node) { grub_ssize_t size = grub_be_to_cpu64 (node->inode.size); + grub_size_t sz; if (size < 0) { @@ -726,7 +755,12 @@ grub_xfs_read_symlink (grub_fshelp_node_t node) if (node->data->hascrc) off = 56; - symlink = grub_malloc (size + 1); + if (grub_add (size, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("symlink size overflow")); + return 0; + } + symlink = grub_malloc (sz); if (!symlink) return 0; @@ -776,8 +810,15 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename, { struct grub_fshelp_node *fdiro; grub_err_t err; + grub_size_t sz; - fdiro = grub_malloc (grub_xfs_fshelp_size(ctx->diro->data) + 1); + if (grub_add (grub_xfs_fshelp_size(ctx->diro->data), 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("directory data size overflow")); + grub_print_error (); + return 0; + } + fdiro = grub_malloc (sz); if (!fdiro) { grub_print_error (); @@ -902,6 +943,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, grub_xfs_first_de(dir->data, dirblock); int entries = -1; char *end = dirblock + dirblk_size; + grub_uint32_t magic; numread = grub_xfs_read_file (dir, 0, 0, blk << dirblk_log2, @@ -912,11 +954,20 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, return 0; } + /* + * If this data block isn't actually part of the extent list then + * grub_xfs_read_file() returns a block of zeros. So, if the magic + * number field is all zeros then this block should be skipped. + */ + magic = *(grub_uint32_t *)(void *) dirblock; + if (!magic) + continue; + /* * 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)) + if (grub_xfs_get_inode_nextents(&dir->inode) == 1) { struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock); @@ -970,7 +1021,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir, * 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)) + if (grub_xfs_get_inode_nextents(&dir->inode) == 1) { /* Check if last direntry in this block is reached. */ entries--; @@ -1047,7 +1098,7 @@ grub_xfs_mount (grub_disk_t disk) return data; fail: - if (grub_errno == GRUB_ERR_OUT_OF_RANGE) + if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE) grub_error (GRUB_ERR_BAD_FS, "not an XFS filesystem"); grub_free (data); @@ -1281,6 +1332,7 @@ static struct grub_fs grub_xfs_fs = GRUB_MOD_INIT(xfs) { + grub_xfs_fs.mod = mod; grub_fs_register (&grub_xfs_fs); my_mod = mod; } diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c index b5453e0062..5ff647ffbb 100644 --- a/grub-core/fs/zfs/zfs.c +++ b/grub-core/fs/zfs/zfs.c @@ -614,6 +614,8 @@ zfs_fetch_nvlist (struct grub_zfs_device_desc *diskdesc, char **nvlist) return grub_error (GRUB_ERR_BUG, "member drive unknown"); *nvlist = grub_malloc (VDEV_PHYS_SIZE); + if (!*nvlist) + return grub_errno; /* Read in the vdev name-value pair list (112K). */ err = grub_disk_read (diskdesc->dev->disk, diskdesc->vdev_phys_sector, 0, @@ -723,8 +725,13 @@ fill_vdev_info_real (struct grub_zfs_data *data, { fill->n_children = nelm; - fill->children = grub_zalloc (fill->n_children - * sizeof (fill->children[0])); + fill->children = grub_calloc (fill->n_children, + sizeof (fill->children[0])); + if (!fill->children) + { + grub_free (type); + return grub_errno; + } } for (i = 0; i < nelm; i++) @@ -2387,6 +2394,7 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, zap_dnode->endian) << DNODE_SHIFT); grub_err_t err; grub_zfs_endian_t endian; + grub_size_t sz; if (zap_verify (zap, zap_dnode->endian)) return 0; @@ -2448,8 +2456,19 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, if (le->le_type != ZAP_CHUNK_ENTRY) continue; - buf = grub_malloc (grub_zfs_to_cpu16 (le->le_name_length, endian) - * name_elem_length + 1); + if (grub_mul (grub_zfs_to_cpu16 (le->le_name_length, endian), name_elem_length, &sz) || + grub_add (sz, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("buffer size overflow")); + grub_free (l); + return grub_errno; + } + buf = grub_malloc (sz); + if (!buf) + { + grub_free (l); + return grub_errno; + } if (zap_leaf_array_get (l, endian, blksft, grub_zfs_to_cpu16 (le->le_name_chunk, endian), @@ -2465,6 +2484,12 @@ fzap_iterate (dnode_end_t * zap_dnode, zap_phys_t * zap, val_length = ((int) le->le_value_length * (int) le->le_int_size); val = grub_malloc (grub_zfs_to_cpu16 (val_length, endian)); + if (!val) + { + grub_free (l); + grub_free (buf); + return grub_errno; + } if (zap_leaf_array_get (l, endian, blksft, grub_zfs_to_cpu16 (le->le_value_chunk, endian), @@ -2872,6 +2897,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, && ((grub_zfs_to_cpu64(((znode_phys_t *) DN_BONUS (&dnode_path->dn.dn))->zp_mode, dnode_path->dn.endian) >> 12) & 0xf) == 0xa) { char *sym_value; + grub_size_t sz; grub_size_t sym_sz; int free_symval = 0; char *oldpath = path, *oldpathbuf = path_buf; @@ -2923,7 +2949,18 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, break; free_symval = 1; } - path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); + + if (grub_add (sym_sz, grub_strlen (oldpath), &sz) || + grub_add (sz, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow")); + grub_free (oldpathbuf); + if (free_symval) + grub_free (sym_value); + err = grub_errno; + break; + } + path = path_buf = grub_malloc (sz); if (!path_buf) { grub_free (oldpathbuf); @@ -2960,6 +2997,7 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, { void *sahdrp; int hdrsize; + grub_size_t sz; if (dnode_path->dn.dn.dn_bonuslen != 0) { @@ -2993,7 +3031,15 @@ dnode_get_path (struct subvolume *subvol, const char *path_in, dnode_end_t *dn, + SA_SIZE_OFFSET), dnode_path->dn.endian); char *oldpath = path, *oldpathbuf = path_buf; - path = path_buf = grub_malloc (sym_sz + grub_strlen (oldpath) + 1); + if (grub_add (sym_sz, grub_strlen (oldpath), &sz) || + grub_add (sz, 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("path buffer size overflow")); + grub_free (oldpathbuf); + err = grub_errno; + break; + } + path = path_buf = grub_malloc (sz); if (!path_buf) { grub_free (oldpathbuf); @@ -3263,6 +3309,8 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol, filename = 0; snapname = 0; fsname = grub_strdup (fullpath); + if (!fsname) + return grub_errno; } else { @@ -3568,6 +3616,7 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, unsigned i; grub_size_t nelm; int elemsize = 0; + int sz; found = nvlist_find_value (nvlist, name, DATA_TYPE_NVLIST_ARRAY, &nvpair, &size, &nelm); @@ -3602,7 +3651,12 @@ grub_zfs_nvlist_lookup_nvlist_array (const char *nvlist, const char *name, return 0; } - ret = grub_zalloc (elemsize + sizeof (grub_uint32_t)); + if (grub_add (elemsize, sizeof (grub_uint32_t), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("elemsize overflow")); + return 0; + } + ret = grub_zalloc (sz); if (!ret) return 0; grub_memcpy (ret, nvlist, sizeof (grub_uint32_t)); @@ -3678,8 +3732,13 @@ zfs_mount (grub_device_t dev) #endif data->n_devices_allocated = 16; - data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) - * data->n_devices_allocated); + data->devices_attached = grub_calloc (data->n_devices_allocated, + sizeof (data->devices_attached[0])); + if (!data->devices_attached) + { + grub_free (data); + return NULL; + } data->n_devices_attached = 0; err = scan_disk (dev, data, 1, &inserted); if (err) @@ -4193,6 +4252,7 @@ iterate_zap_snap (const char *name, grub_uint64_t val, struct grub_dirhook_info info; char *name2; int ret; + grub_size_t sz; dnode_end_t mdn; @@ -4213,7 +4273,13 @@ iterate_zap_snap (const char *name, grub_uint64_t val, return 0; } - name2 = grub_malloc (grub_strlen (name) + 2); + if (grub_add (grub_strlen (name), 2, &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); + + name2 = grub_malloc (sz); + if (!name2) + return grub_errno; + name2[0] = '@'; grub_memcpy (name2 + 1, name, grub_strlen (name) + 1); ret = ctx->hook (name2, &info, ctx->hook_data); @@ -4424,6 +4490,7 @@ static struct grub_fs grub_zfs_fs = { GRUB_MOD_INIT (zfs) { COMPILE_TIME_ASSERT (sizeof (zap_leaf_chunk_t) == ZAP_LEAF_CHUNKSIZE); + grub_zfs_fs.mod = mod; grub_fs_register (&grub_zfs_fs); #ifndef GRUB_UTIL my_mod = mod; diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in index e57c4d9205..337753c574 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/grub-core/genmoddep.awk b/grub-core/genmoddep.awk index cc987a53aa..ab457cb2b5 100644 --- a/grub-core/genmoddep.awk +++ b/grub-core/genmoddep.awk @@ -35,7 +35,7 @@ BEGIN { for (i = 3; i <= NF; i++) { modtab[$2] = modtab[$2] " " $i; } - } + } else if ($1 == "") {} #Skip empty lines else { printf "error: %u: unrecognized input format\n", NR >"/dev/stderr"; error++; diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c index 7a1c14e4f3..fffe3a0548 100644 --- a/grub-core/gettext/gettext.c +++ b/grub-core/gettext/gettext.c @@ -26,6 +26,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -99,6 +100,7 @@ grub_gettext_getstr_from_position (struct grub_gettext_context *ctx, char *translation; struct string_descriptor desc; grub_err_t err; + grub_size_t alloc_sz; internal_position = (off + position * sizeof (desc)); @@ -109,7 +111,10 @@ grub_gettext_getstr_from_position (struct grub_gettext_context *ctx, length = grub_cpu_to_le32 (desc.length); offset = grub_cpu_to_le32 (desc.offset); - translation = grub_malloc (length + 1); + if (grub_add (length, 1, &alloc_sz)) + return NULL; + + translation = grub_malloc (alloc_sz); if (!translation) return NULL; @@ -323,8 +328,8 @@ grub_mofile_open (struct grub_gettext_context *ctx, for (ctx->grub_gettext_max_log = 0; ctx->grub_gettext_max >> ctx->grub_gettext_max_log; ctx->grub_gettext_max_log++); - ctx->grub_gettext_msg_list = grub_zalloc (ctx->grub_gettext_max - * sizeof (ctx->grub_gettext_msg_list[0])); + ctx->grub_gettext_msg_list = grub_calloc (ctx->grub_gettext_max, + sizeof (ctx->grub_gettext_msg_list[0])); if (!ctx->grub_gettext_msg_list) { grub_file_close (fd); @@ -424,6 +429,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; @@ -535,6 +547,10 @@ GRUB_MOD_INIT (gettext) GRUB_MOD_FINI (gettext) { + grub_register_variable_hook ("locale_dir", NULL, NULL); + grub_register_variable_hook ("secondary_locale_dir", NULL, NULL); + grub_register_variable_hook ("lang", NULL, NULL); + grub_gettext_delete_list (&main_context); grub_gettext_delete_list (&secondary_context); 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/acpi.c b/grub-core/kern/acpi.c index 48ded4e2ea..8ff0835d50 100644 --- a/grub-core/kern/acpi.c +++ b/grub-core/kern/acpi.c @@ -75,7 +75,7 @@ grub_acpi_xsdt_find_table (struct grub_acpi_table_header *xsdt, const char *sig) return 0; ptr = (grub_unaligned_uint64_t *) (xsdt + 1); - s = (xsdt->length - sizeof (*xsdt)) / sizeof (grub_uint32_t); + s = (xsdt->length - sizeof (*xsdt)) / sizeof (grub_uint64_t); for (; s; s--, ptr++) { struct grub_acpi_table_header *tbl; 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 a2b5789a9d..95c6d5bf4e 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/disk.c b/grub-core/kern/disk.c index 1eda58fe9a..82e04fd00a 100644 --- a/grub-core/kern/disk.c +++ b/grub-core/kern/disk.c @@ -28,6 +28,10 @@ #define GRUB_CACHE_TIMEOUT 2 +/* Disk reads may trigger other disk reads. So, limit recursion depth. */ +#define MAX_READ_RECURSION_DEPTH 16 +static unsigned int read_recursion_depth = 0; + /* The last time the disk was used. */ static grub_uint64_t grub_last_time = 0; @@ -417,6 +421,8 @@ grub_err_t grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, grub_off_t offset, grub_size_t size, void *buf) { + grub_err_t err = GRUB_ERR_NONE; + /* First of all, check if the region is within the disk. */ if (grub_disk_adjust_range (disk, §or, &offset, size) != GRUB_ERR_NONE) { @@ -427,12 +433,17 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, return grub_errno; } + if (++read_recursion_depth >= MAX_READ_RECURSION_DEPTH) + { + grub_error (GRUB_ERR_RECURSION_DEPTH, "grub_disk_read(): Maximum recursion depth exceeded"); + goto error; + } + /* First read until first cache boundary. */ if (offset || (sector & (GRUB_DISK_CACHE_SIZE - 1))) { grub_disk_addr_t start_sector; grub_size_t pos; - grub_err_t err; grub_size_t len; start_sector = sector & ~((grub_disk_addr_t) GRUB_DISK_CACHE_SIZE - 1); @@ -444,7 +455,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, err = grub_disk_read_small (disk, start_sector, offset + pos, len, buf); if (err) - return err; + goto error; buf = (char *) buf + len; size -= len; offset += len; @@ -457,7 +468,6 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, { char *data = NULL; grub_disk_addr_t agglomerate; - grub_err_t err; /* agglomerate read until we find a first cached entry. */ for (agglomerate = 0; agglomerate @@ -493,7 +503,7 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, - disk->log_sector_size), buf); if (err) - return err; + goto error; for (i = 0; i < agglomerate; i ++) grub_disk_cache_store (disk->dev->id, disk->id, @@ -527,13 +537,16 @@ grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector, /* And now read the last part. */ if (size) { - grub_err_t err; err = grub_disk_read_small (disk, sector, 0, size, buf); if (err) - return err; + goto error; } - return grub_errno; + err = grub_errno; + + error: + read_recursion_depth--; + return err; } grub_uint64_t diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 0bf40caa61..76116e0169 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) @@ -224,22 +225,37 @@ 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) && \ !defined (__loongarch__) 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; + 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); i < e->e_shnum; i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) { - tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; - if (talign < s->sh_addralign) - talign = s->sh_addralign; + grub_size_t sh_addralign; + grub_size_t sh_size; + + if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) + continue; + + 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) && \ @@ -247,12 +263,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 @@ -269,6 +291,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; @@ -281,17 +306,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; } @@ -300,7 +327,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; @@ -308,16 +335,17 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) } #if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) && \ !defined (__loongarch__) - 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; #endif + grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); return GRUB_ERR_NONE; } @@ -532,7 +560,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) return GRUB_ERR_NONE; } -int +grub_uint64_t grub_dl_ref (grub_dl_t mod) { grub_dl_dep_t dep; @@ -543,10 +571,13 @@ grub_dl_ref (grub_dl_t mod) for (dep = mod->dep; dep; dep = dep->next) grub_dl_ref (dep->mod); - return ++mod->ref_count; + if (grub_add (mod->ref_count, 1, &mod->ref_count)) + grub_fatal ("Module reference count overflow"); + + return mod->ref_count; } -int +grub_uint64_t grub_dl_unref (grub_dl_t mod) { grub_dl_dep_t dep; @@ -557,10 +588,13 @@ grub_dl_unref (grub_dl_t mod) for (dep = mod->dep; dep; dep = dep->next) grub_dl_unref (dep->mod); - return --mod->ref_count; + if (grub_sub (mod->ref_count, 1, &mod->ref_count)) + grub_fatal ("Module reference count underflow"); + + return mod->ref_count; } -int +grub_uint64_t grub_dl_ref_count (grub_dl_t mod) { if (mod == NULL) @@ -584,6 +618,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)) @@ -592,22 +627,105 @@ 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; + if (!(s->sh_flags & SHF_INFO_LINK)) + continue; - if (seg) - { - if (!mod->symtab) - return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); + seg = grub_dl_find_segment(mod, s->sh_info); + if (!seg) + continue; - err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); - if (err) - return err; - } + 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; } + 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_size_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 (\"%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); + } +#endif + + grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n", + mod->name); + return GRUB_ERR_NONE; } @@ -644,6 +762,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 @@ -657,7 +776,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/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index b93ae3aba1..e6dfb4b3b3 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -222,6 +222,9 @@ grub_efi_set_variable_with_attributes (const char *var, const grub_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); } @@ -770,7 +773,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], @@ -783,33 +786,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: @@ -856,6 +886,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; @@ -1049,3 +1112,39 @@ grub_efi_find_configuration_table (const grub_guid_t *target_guid) 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/init.c b/grub-core/kern/efi/init.c index 6c54af6e79..dee3918fd3 100644 --- a/grub-core/kern/efi/init.c +++ b/grub-core/kern/efi/init.c @@ -28,8 +28,11 @@ #include #include #include + #include +#include + #ifdef GRUB_STACK_PROTECTOR static grub_efi_char16_t stack_chk_fail_msg[] = @@ -103,6 +106,31 @@ stack_protector_init (void) grub_addr_t grub_modbase; +/* 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_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); +} + __attribute__ ((__optimize__ ("-fno-stack-protector"))) void grub_efi_init (void) { @@ -128,6 +156,7 @@ grub_efi_init (void) grub_efi_system_table->boot_services->set_watchdog_timer (0, 0, 0, NULL); + grub_efi_env_init (); grub_efidisk_init (); grub_efi_register_debug_commands (); diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c index 6a6fba8918..df443f434d 100644 --- a/grub-core/kern/efi/mm.c +++ b/grub-core/kern/efi/mm.c @@ -687,3 +687,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_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 = 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_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 = proto->set_memory_attributes( + proto, physaddr, size, uefi_set_attrs); + if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) + efi_status = 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/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/emu/misc.c b/grub-core/kern/emu/misc.c index 521220b49d..1a50be8de3 100644 --- a/grub-core/kern/emu/misc.c +++ b/grub-core/kern/emu/misc.c @@ -188,7 +188,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/kern/file.c b/grub-core/kern/file.c index 750177248f..6df05583de 100644 --- a/grub-core/kern/file.c +++ b/grub-core/kern/file.c @@ -25,6 +25,7 @@ #include #include #include +#include void (*EXPORT_VAR (grub_grubnet_fini)) (void); @@ -114,6 +115,12 @@ grub_file_open (const char *name, enum grub_file_type type) if ((file->fs->fs_open) (file, file_name) != GRUB_ERR_NONE) goto fail; + if (file->data == NULL) + goto fail; + + if (file->fs->mod) + grub_dl_ref (file->fs->mod); + file->name = grub_strdup (name); grub_errno = GRUB_ERR_NONE; @@ -194,6 +201,9 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len) grub_err_t grub_file_close (grub_file_t file) { + if (file->fs->mod) + grub_dl_unref (file->fs->mod); + if (file->fs->fs_close) (file->fs->fs_close) (file); 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/i386/efi/startup.S b/grub-core/kern/i386/efi/startup.S index fc5ea3dac8..36d1b1a689 100644 --- a/grub-core/kern/i386/efi/startup.S +++ b/grub-core/kern/i386/efi/startup.S @@ -34,3 +34,8 @@ _start: movl %eax, EXT_C(grub_efi_system_table) call EXT_C(grub_main) ret + +/* An executable stack is not required for these functions. */ +#if defined (__linux__) && defined (__ELF__) +.section .note.GNU-stack,"",%progbits +#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/ieee1275/init.c b/grub-core/kern/ieee1275/init.c index fb7d1a3bac..dab8d97f7a 100644 --- a/grub-core/kern/ieee1275/init.c +++ b/grub-core/kern/ieee1275/init.c @@ -170,23 +170,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/kern/main.c b/grub-core/kern/main.c index 731c07c290..353a62ef1e 100644 --- a/grub-core/kern/main.c +++ b/grub-core/kern/main.c @@ -128,16 +128,24 @@ grub_set_prefix_and_root (void) grub_machine_get_bootlocation (&fwdevice, &fwpath); - if (fwdevice) + if (fwdevice && fwpath) { - char *cmdpath; + char *fw_path; + char separator[3] = ")"; - cmdpath = grub_xasprintf ("(%s)%s", fwdevice, fwpath ? : ""); - if (cmdpath) + 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 ("cmdpath", cmdpath); - grub_env_export ("cmdpath"); - grub_free (cmdpath); + 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/kern/mips/dl.c b/grub-core/kern/mips/dl.c index 5b02f97fca..db411899db 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/misc.c b/grub-core/kern/misc.c index 7cee5d75c3..4528bed68c 100644 --- a/grub-core/kern/misc.c +++ b/grub-core/kern/misc.c @@ -26,6 +26,7 @@ #include #include #include +#include union printf_arg { @@ -182,6 +183,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) { @@ -611,6 +625,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) @@ -830,7 +874,7 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, while ((c = *fmt++) != 0) { int longfmt = 0; - grub_size_t curn; + unsigned long curn; const char *p; if (c != '%') @@ -848,7 +892,10 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args, if (*fmt == '$') { - curn = grub_strtoull (p, 0, 10) - 1; + curn = grub_strtoul (p, 0, 10); + if (curn == 0) + continue; + curn--; fmt++; } @@ -1034,6 +1081,8 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0, if (*fmt == '$') { + if (format1 == 0) + continue; curn = format1 - 1; fmt++; format1 = 0; @@ -1301,6 +1350,11 @@ grub_printf_fmt_check (const char *fmt, const char *fmt_expected) 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 diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c index 027a25cd1f..dea41b6f95 100644 --- a/grub-core/kern/mm.c +++ b/grub-core/kern/mm.c @@ -505,7 +505,7 @@ grub_memalign (grub_size_t align, grub_size_t size) goto fail; /* Preallocate some extra space if heap growth is small. */ - grow = grub_max (grow, GRUB_MM_HEAP_GROW_EXTRA); + grow = grub_max (grow, (grub_size_t)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)) diff --git a/grub-core/kern/partition.c b/grub-core/kern/partition.c index edad9f9e47..c6a578cf4a 100644 --- a/grub-core/kern/partition.c +++ b/grub-core/kern/partition.c @@ -28,6 +28,9 @@ grub_partition_map_t grub_partition_map_list; +#define MAX_RECURSION_DEPTH 32 +static unsigned int recursion_depth = 0; + /* * Checks that disk->partition contains part. This function assumes that the * start of part is relative to the start of disk->partition. Returns 1 if @@ -122,14 +125,22 @@ grub_partition_probe (struct grub_disk *disk, const char *str) for (ptr = str; *ptr;) { grub_partition_map_t partmap; - int num; + unsigned long num; const char *partname, *partname_end; partname = ptr; while (*ptr && grub_isalpha (*ptr)) ptr++; partname_end = ptr; - num = grub_strtoul (ptr, &ptr, 0) - 1; + + num = grub_strtoul (ptr, &ptr, 0); + if (*ptr != '\0' || num == 0 || num > GRUB_INT_MAX) + { + grub_error (GRUB_ERR_BAD_NUMBER, N_("invalid partition number")); + return 0; + } + + num -= 1; curpart = 0; /* Use the first partition map type found. */ @@ -208,7 +219,12 @@ part_iterate (grub_disk_t dsk, const grub_partition_t partition, void *data) FOR_PARTITION_MAPS(partmap) { grub_err_t err; - err = partmap->iterate (dsk, part_iterate, ctx); + recursion_depth++; + if (recursion_depth <= MAX_RECURSION_DEPTH) + err = partmap->iterate (dsk, part_iterate, ctx); + else + err = grub_error (GRUB_ERR_RECURSION_DEPTH, "maximum recursion depth exceeded"); + recursion_depth--; if (err) grub_errno = GRUB_ERR_NONE; if (ctx->ret) diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c index 7b6418eabd..0eb8bc5bd3 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 896653bb41..1fa085b4ac 100644 --- a/grub-core/kern/riscv/dl.c +++ b/grub-core/kern/riscv/dl.c @@ -344,3 +344,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/grub-core/kern/x86_64/efi/startup.S b/grub-core/kern/x86_64/efi/startup.S index 9357e5c5dd..f5c6bc3d8e 100644 --- a/grub-core/kern/x86_64/efi/startup.S +++ b/grub-core/kern/x86_64/efi/startup.S @@ -33,3 +33,8 @@ _start: andq $~0xf, %rsp call EXT_C(grub_main) /* Doesn't return. */ + +/* An executable stack is not required for these functions. */ +#if defined (__linux__) && defined (__ELF__) +.section .note.GNU-stack,"",%progbits +#endif 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/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/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/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/grub-core/lib/reed_solomon.c b/grub-core/lib/reed_solomon.c index 562bd2e3e3..5fee7f2a1a 100644 --- a/grub-core/lib/reed_solomon.c +++ b/grub-core/lib/reed_solomon.c @@ -162,7 +162,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)); @@ -333,7 +333,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/loader/efi/appleloader.c b/grub-core/loader/efi/appleloader.c index a0b61a240b..35d53c5f85 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/linux.c b/grub-core/loader/efi/linux.c index bfbd95aeef..32faf2fffa 100644 --- a/grub-core/loader/efi/linux.c +++ b/grub-core/loader/efi/linux.c @@ -211,6 +211,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) status = b->load_image (0, grub_efi_image_handle, (grub_efi_device_path_t *) mempath, (void *) addr, size, &image_handle); + grub_free (mempath); if (status != GRUB_EFI_SUCCESS) return grub_error (GRUB_ERR_BAD_OS, "cannot load image"); @@ -228,7 +229,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args) 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; + goto unload; loaded_image->load_options_size = 2 * grub_utf8_to_utf16 (loaded_image->load_options, len, diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c index 1f9128f6f2..50f96ea7a0 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+"); @@ -1340,6 +1341,7 @@ static grub_err_t grub_bsd_load_elf (grub_elf_t elf, const char *filename) { grub_err_t err; + grub_size_t sz; kern_end = 0; kern_start = ~0; @@ -1370,8 +1372,11 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename) if (grub_errno) return grub_errno; - err = grub_relocator_alloc_chunk_addr (relocator, &ch, - kern_start, kern_end - kern_start); + + if (grub_sub (kern_end, kern_start, &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator"); + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz); if (err) return err; @@ -1431,8 +1436,10 @@ grub_bsd_load_elf (grub_elf_t elf, const char *filename) { grub_relocator_chunk_t ch; - err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, - kern_end - kern_start); + if (grub_sub (kern_end, kern_start, &sz)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while determining size of kernel for relocator"); + + err = grub_relocator_alloc_chunk_addr (relocator, &ch, kern_start, sz); if (err) return err; kern_chunk_src = get_virtual_current_address (ch); @@ -2137,6 +2144,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 +2186,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 977757f2cc..e417667462 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+"); @@ -806,7 +807,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), } linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; - linux_params.kernel_alignment = (1 << align); + linux_params.kernel_alignment = ((grub_uint32_t)1 << align); linux_params.ps_mouse = linux_params.padding11 = 0; linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE; @@ -1153,6 +1154,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, @@ -1162,6 +1166,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/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c index 11a6e224ff..fae5d6fb8c 100644 --- a/grub-core/loader/i386/multiboot_mbi.c +++ b/grub-core/loader/i386/multiboot_mbi.c @@ -86,7 +86,7 @@ load_kernel (grub_file_t file, const char *filename, return GRUB_ERR_NONE; } if (err == GRUB_ERR_UNKNOWN_OS && (header->flags & MULTIBOOT_AOUT_KLUDGE)) - grub_errno = err = GRUB_ERR_NONE; + grub_errno = GRUB_ERR_NONE; } if (header->flags & MULTIBOOT_AOUT_KLUDGE) { diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c index 4adeee9ae0..53428bb2f6 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+"); @@ -478,6 +479,9 @@ static grub_command_t cmd_linux, cmd_initrd; GRUB_MOD_INIT(linux16) { + if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED) + return; + cmd_linux = grub_register_command ("linux16", grub_cmd_linux, 0, N_("Load Linux.")); @@ -489,6 +493,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_initrd); } diff --git a/grub-core/loader/i386/pc/truecrypt.c b/grub-core/loader/i386/pc/truecrypt.c index bae1ad031b..7bf801603f 100644 --- a/grub-core/loader/i386/pc/truecrypt.c +++ b/grub-core/loader/i386/pc/truecrypt.c @@ -176,7 +176,7 @@ grub_cmd_truecrypt (grub_command_t cmd __attribute__ ((unused)), edx = (dh << 8) | grub_get_root_biosnumber (); - destaddr = ALIGN_DOWN (grub_min (0x90000, grub_mmap_get_lower ()) + destaddr = ALIGN_DOWN (grub_min (0x90000ull, grub_mmap_get_lower ()) - truecryptmemsize, 64 * 1024); { diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 94be512c4d..94c112a29d 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/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c index 1edad05948..24480df505 100644 --- a/grub-core/loader/multiboot_elfxx.c +++ b/grub-core/loader/multiboot_elfxx.c @@ -45,9 +45,7 @@ #endif #include - -#define CONCAT(a,b) CONCAT_(a, b) -#define CONCAT_(a,b) a ## b +#include #pragma GCC diagnostic ignored "-Wcast-align" @@ -101,7 +99,7 @@ CONCAT(grub_multiboot_load_elf, XX) (mbi_load_data_t *mld) return err; /* FIXME: Should we support program headers at strange locations? */ - phlimit = grub_min (MULTIBOOT_SEARCH, grub_file_size (mld->file)); + phlimit = grub_min ((grub_off_t)MULTIBOOT_SEARCH, grub_file_size (mld->file)); if ((grub_off_t) ehdr->e_phoff + phnum * ehdr->e_phentsize > phlimit) return grub_error (GRUB_ERR_BAD_OS, "program header at a too high offset"); diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c index 4cca55df92..f76f511ac2 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/grub-core/net/bootp.c b/grub-core/net/bootp.c index abe45ef7bf..739b1cb732 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -20,10 +20,104 @@ #include #include #include +#include #include #include #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 { @@ -237,7 +331,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; @@ -414,6 +508,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 ((char *)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); @@ -610,6 +758,584 @@ send_dhcp_packet (struct grub_net_network_level_interface *iface) 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_int64_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 @@ -678,6 +1404,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) @@ -686,6 +1483,7 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), unsigned num; const grub_uint8_t *ptr; grub_uint8_t taglength; + grub_uint8_t len; if (argc < 4) return grub_error (GRUB_ERR_BAD_ARGUMENT, @@ -727,7 +1525,12 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), if (grub_strcmp (args[3], "string") == 0) { grub_err_t err = GRUB_ERR_NONE; - char *val = grub_malloc (taglength + 1); + char *val; + + if (grub_add (taglength, 1, &len)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("tag length overflow")); + + val = grub_malloc (len); if (!val) return grub_errno; grub_memcpy (val, ptr, taglength); @@ -760,7 +1563,12 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)), if (grub_strcmp (args[3], "hex") == 0) { grub_err_t err = GRUB_ERR_NONE; - char *val = grub_malloc (2 * taglength + 1); + char *val; + + if (grub_mul (taglength, 2, &len) || grub_add (len, 1, &len)) + return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("tag length overflow")); + + val = grub_malloc (len); int i; if (!val) return grub_errno; @@ -903,7 +1711,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), return err; } -static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp; +static grub_err_t +grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_net_card *card; + grub_uint32_t iaid = 0; + int interval; + grub_err_t err; + grub_dhcp6_session_t se; + + err = GRUB_ERR_NONE; + + FOR_NET_CARDS (card) + { + struct grub_net_network_level_interface *iface; + + if (argc > 0 && grub_strcmp (card->name, args[0]) != 0) + continue; + + iface = grub_net_ipv6_get_link_local (card, &card->default_address); + if (!iface) + { + grub_dhcp6_session_remove_all (); + return grub_errno; + } + + grub_dhcp6_session_add (iface, iaid++); + } + + for (interval = 200; interval < 10000; interval *= 2) + { + 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); + } + + FOR_DHCP6_SESSIONS (se) + { + grub_error_push (); + err = grub_error (GRUB_ERR_FILE_NOT_FOUND, + N_("couldn't autoconfigure %s"), + se->iface->card->name); + } + + grub_dhcp6_session_remove_all (); + + return err; +} + +static grub_command_t cmd_getdhcp, cmd_bootp, cmd_dhcp, cmd_bootp6; void grub_bootp_init (void) @@ -917,11 +1892,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/dns.c b/grub-core/net/dns.c index fcc09aa65d..f20cd6f835 100644 --- a/grub-core/net/dns.c +++ b/grub-core/net/dns.c @@ -224,10 +224,17 @@ get_name (const grub_uint8_t *name_at, const grub_uint8_t *head, { int length; char *ret; + int len; if (!check_name_real (name_at, head, tail, NULL, &length, NULL)) return NULL; - ret = grub_malloc (length + 1); + + if (grub_add (length, 1, &len)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("name length overflow")); + return NULL; + } + ret = grub_malloc (len); if (!ret) return NULL; if (!check_name_real (name_at, head, tail, NULL, NULL, ret)) @@ -463,8 +470,8 @@ grub_net_dns_lookup (const char *name, && grub_get_time_ms () < dns_cache[h].limit_time) { grub_dprintf ("dns", "retrieved from cache\n"); - *addresses = grub_malloc (dns_cache[h].naddresses - * sizeof ((*addresses)[0])); + *addresses = grub_calloc (dns_cache[h].naddresses, + sizeof ((*addresses)[0])); if (!*addresses) return grub_errno; *naddresses = dns_cache[h].naddresses; diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c index 3ea25cf989..b2ce3a0e65 100644 --- a/grub-core/net/drivers/efi/efinet.c +++ b/grub-core/net/drivers/efi/efinet.c @@ -18,17 +18,24 @@ #include #include +#include #include #include #include #include #include +#include +#include +#include +#include GRUB_MOD_LICENSE ("GPLv3+"); /* GUID. */ static grub_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID; static grub_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; +static grub_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; +static grub_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; static grub_err_t send_card_buffer (struct grub_net_card *dev, @@ -165,6 +172,22 @@ open_card (struct grub_net_card *dev) */ net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid, GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE); + + if (net == NULL) + { + /* + * In some PXE + chainload scenarios the SNP handle is already opened + * and firmware refuses an exclusive reopen (often manifests as + * "%s: can't open protocol"). Fall back to a non-exclusive open so we + * can reuse the existing PXE-provided SNP instance. + * + * Note: We still prefer BY_EXCLUSIVE when it works, since it can + * implicitly tear down competing MNP instances. + */ + net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid, + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); + } + if (net != NULL) { if (net->mode->state == GRUB_EFI_NETWORK_STOPPED @@ -341,12 +364,405 @@ grub_efinet_findcards (void) grub_free (handles); } +static grub_efi_handle_t +grub_efi_locate_device_path (grub_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 = 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 = 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 = 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 = 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 = 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) +{ + 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); + + /* 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)) + { + 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; + 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); + 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); + + 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) + { + 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; + 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)); + 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); + + 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; + } + + grub_free (ddp); + return nb; +} + static void 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; struct grub_net_network_level_interface *inter; grub_efi_device_path_t *vlan_dp; grub_efi_uint16_t vlan_dp_len; @@ -360,15 +776,24 @@ 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; + 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 @@ -377,14 +802,33 @@ 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)) + && 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); 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); + 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; @@ -394,46 +838,114 @@ 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; - - inter = 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 (inter != NULL) + if (!pxe) { - /* - * Search the device path for any VLAN subtype and use it - * to configure the interface. - */ - vlan_dp = dp; + 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; + } - while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (vlan_dp)) + if (ipv6) + { + grub_dprintf ("efinet", "using ipv6 and dhcpv6\n"); + 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"); + + inter = grub_net_configure_by_dhcpv6_reply (card->name, card, 0, + (struct grub_net_dhcp6_packet *) + packet_buf, + packet_bufsz, + 1, device, path); + if (grub_errno) + grub_print_error (); + if (inter && device && path) + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + if (grub_errno) + grub_print_error (); + } + else + { + grub_dprintf ("efinet", "using ipv4 and dhcp\n"); + + struct grub_net_bootp_packet *dhcp_ack = (struct grub_net_bootp_packet *) &pxe_mode->dhcp_ack; + + if (pxe_mode->proxy_offer_received) + { + grub_dprintf ("efinet", "proxy offer receive"); + struct grub_net_bootp_packet *proxy_offer = (struct grub_net_bootp_packet *) &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; + } + } + + inter = grub_net_configure_by_dhcp_ack (card->name, card, 0, + (struct grub_net_bootp_packet *) + packet_buf, + packet_bufsz, + 1, device, path); + grub_dprintf ("efinet", "device: `%s' path: `%s'\n", *device, *path); + if (inter != NULL) { - if (GRUB_EFI_DEVICE_PATH_TYPE (vlan_dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && - GRUB_EFI_DEVICE_PATH_SUBTYPE (vlan_dp) == GRUB_EFI_VLAN_DEVICE_PATH_SUBTYPE) + /* + * Search the device path for any VLAN subtype and use it + * to configure the interface. + */ + vlan_dp = dp; + + while (!GRUB_EFI_END_ENTIRE_DEVICE_PATH (vlan_dp)) { - vlan = (grub_efi_vlan_device_path_t *) vlan_dp; - inter->vlantag = vlan->vlan_id; - break; + if (GRUB_EFI_DEVICE_PATH_TYPE (vlan_dp) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE && + GRUB_EFI_DEVICE_PATH_SUBTYPE (vlan_dp) == GRUB_EFI_VLAN_DEVICE_PATH_SUBTYPE) + { + vlan = (grub_efi_vlan_device_path_t *) vlan_dp; + inter->vlantag = vlan->vlan_id; + break; + } + + vlan_dp_len = GRUB_EFI_DEVICE_PATH_LENGTH (vlan_dp); + vlan_dp = (grub_efi_device_path_t *) ((grub_efi_uint8_t *) vlan_dp + vlan_dp_len); } - - vlan_dp_len = GRUB_EFI_DEVICE_PATH_LENGTH (vlan_dp); - vlan_dp = (grub_efi_device_path_t *) ((grub_efi_uint8_t *) vlan_dp + vlan_dp_len); } } + + if (nb) + grub_netbuff_free (nb); + return; } } GRUB_MOD_INIT(efinet) { + if (grub_efi_net_config) + return; + grub_efinet_findcards (); grub_efi_net_config = grub_efi_net_config_real; } @@ -445,5 +957,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/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c index 78f03df8e2..c35b107ad4 100644 --- a/grub-core/net/drivers/ieee1275/ofnet.c +++ b/grub-core/net/drivers/ieee1275/ofnet.c @@ -22,6 +22,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -391,6 +392,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) grub_uint8_t *pprop; char *shortname; char need_suffix = 1; + grub_size_t sz; if (grub_strcmp (alias->type, "network") != 0) return 0; @@ -448,9 +450,23 @@ search_net_devices (struct grub_ieee1275_devalias *alias) } if (need_suffix) - ofdata->path = grub_malloc (grub_strlen (alias->path) + sizeof (SUFFIX)); + { + if (grub_add (grub_strlen (alias->path), sizeof (SUFFIX), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path")); + grub_print_error (); + return 0; + } + } else - ofdata->path = grub_malloc (grub_strlen (alias->path) + 1); + { + if (grub_add (grub_strlen (alias->path), 1, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obatining size of ofdata path")); + grub_print_error (); + return 0; + } + } if (!ofdata->path) { grub_print_error (); diff --git a/grub-core/net/efi/dhcp.c b/grub-core/net/efi/dhcp.c new file mode 100644 index 0000000000..6cc0dad85a --- /dev/null +++ b/grub-core/net/efi/dhcp.c @@ -0,0 +1,400 @@ +#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 = dhcp4->parse(dhcp4, reply_packet, &option_count, NULL); + + if (status != GRUB_EFI_BUFFER_TOO_SMALL) + return NULL; + + option_list = grub_calloc (option_count, sizeof(*option_list)); + if (!option_list) + return NULL; + + status = 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 = pxe->start(pxe, 0); + + if (status != GRUB_EFI_SUCCESS) + grub_printf ("Couldn't start PXE\n"); + } + + status = 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 = 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 = netdev->dhcp4->start(netdev->dhcp4, NULL); + if (status != GRUB_EFI_SUCCESS) + { + grub_printf ("dhcp4 start failed, %d\n", (int)status); + continue; + } + + status = 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 = 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 = dev->dhcp6->start(dev->dhcp6); + if (status != GRUB_EFI_SUCCESS) + { + grub_printf ("dhcp6 start failed, %d\n", (int)status); + continue; + } + + status = 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 = dev->dhcp6->parse(dev->dhcp6, mode.ia->reply_packet, &count, NULL); + + if (status == GRUB_EFI_BUFFER_TOO_SMALL && count) + { + options = grub_calloc (count, sizeof(*options)); + if (options) + status = dev->dhcp6->parse(dev->dhcp6, mode.ia->reply_packet, &count, options); + else + status = GRUB_EFI_OUT_OF_RESOURCES; + } + + 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); + } + + b->free_pool(mode.client_id); + 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..5bdb47548f --- /dev/null +++ b/grub-core/net/efi/http.c @@ -0,0 +1,494 @@ + +#include +#include +#include +#include +#include +#include + +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); + grub_env_export ("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; + + 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 = 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 = http->configure(http, &http_config); + + if (status == GRUB_EFI_ALREADY_STARTED) + { + /* XXX: This hangs HTTPS boot */ +#if 0 + if (http->configure(http, NULL) != GRUB_EFI_SUCCESS) + { + grub_error (GRUB_ERR_IO, N_("couldn't reset http instance")); + grub_print_error (); + return; + } + status = 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_api grub_efi_http_request_callback (grub_efi_event_t event __attribute__ ((unused)), + void *context __attribute__ ((unused))) +{ + request_callback_done = 1; +} + +static void +__grub_efi_api 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; + char *hostname = NULL; + + { + 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) + { + 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); + } + + 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_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; + 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 = 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", (unsigned) status); + } + + status = http->request(http, &request_token); + + if (hostname) + grub_free (hostname); + + if (status != GRUB_EFI_SUCCESS) + { + 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", (unsigned) status); + } + /* TODO: Add Timeout */ + while (!request_callback_done) + 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 = 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) + { + 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", (unsigned) status); + } + + response_token.status = GRUB_EFI_SUCCESS; + response_token.message = &response_message; + + /* wait for HTTP response */ + response_callback_done = 0; + status = http->response(http, &response_token); + + if (status != GRUB_EFI_SUCCESS) + { + b->close_event(response_token.event); + 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) + 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) + b->free_pool(response_message.headers); + b->close_event(response_token.event); + 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) + b->free_pool(response_message.headers); + b->close_event(response_token.event); + 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; + } + + 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 = http->response(http, &response_token); + if (status != GRUB_EFI_SUCCESS) + { + b->close_event(response_token.event); + grub_error (GRUB_ERR_IO, "Error! status=%d\n", (int)status); + return -1; + } + + while (!response_callback_done) + http->poll(http); + + sum += response_message.body_length; + buf += response_message.body_length; + len -= response_message.body_length; + } + + 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 = 0; + char *buf = NULL; + char *file_name = NULL; + const char *http_path; + + /* 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_name ? file_name : file->device->net->name, type, 1, 0); + if (err != GRUB_ERR_NONE) + { + grub_free (file_name); + return err; + } + + 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; + } + + if (size) + { + 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..85a090ec42 --- /dev/null +++ b/grub-core/net/efi/ip4_config.c @@ -0,0 +1,421 @@ + +#include +#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; + grub_size_t sz, s, i; + + 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) + return NULL; + + p = hw_addr; + s = sz; + for (i = 0; i < 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; + grub_size_t i; + int 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; + t = grub_strtoul (ptr, &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 = 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 = 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 = 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 id; + grub_size_t i, nmemb; + + interface_info = efi_ip4_config_interface_info (dev->ip4_config); + if (!interface_info) + return NULL; + + 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); + return NULL; + } + + id = 0; + for (i = 0; i < 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 = 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 = 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 = 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..952bda9fa7 --- /dev/null +++ b/grub-core/net/efi/ip6_config.c @@ -0,0 +1,429 @@ +#include +#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, &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 = 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 = 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 = 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 id; + grub_size_t i, nmemb; + + interface_info = efi_ip6_config_interface_info (dev->ip6_config); + if (!interface_info) + return NULL; + + 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); + return NULL; + } + + id = 0; + for (i = 0; i < 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 = 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 = 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 = 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..1b13603a63 --- /dev/null +++ b/grub-core/net/efi/net.c @@ -0,0 +1,1436 @@ +#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_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID; +static grub_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID; +static grub_guid_t http_service_binding_guid = GRUB_EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; +static grub_guid_t http_guid = GRUB_EFI_HTTP_PROTOCOL_GUID; +static grub_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID; +static grub_guid_t dhcp4_service_binding_guid = GRUB_EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; +static grub_guid_t dhcp4_guid = GRUB_EFI_DHCP4_PROTOCOL_GUID; +static grub_guid_t dhcp6_service_binding_guid = GRUB_EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; +static grub_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_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 = 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) { + grub_free (chunk); + 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_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 = 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"), (unsigned) 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, &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 || *rest == ':') + { + 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, &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 || *rest == ':') + { + ip6->prefix_length = 128; + ip6->is_anycast = 0; + if (has_cidr) + *has_cidr = 0; + return GRUB_ERR_NONE; + } + } + + grub_dprintf ("efinet", "unrecognised network address '%s'\n", address); + + return GRUB_ERR_NET_BAD_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) + 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 (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 (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); + + 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) + { + 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; + 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)) + 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..e828fb23e9 --- /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 = 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 = 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 = 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 = 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 = 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, &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; + const 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 = 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; + 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; + 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 = 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 = 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/http.c b/grub-core/net/http.c index f389bf03d9..40df19426c 100644 --- a/grub-core/net/http.c +++ b/grub-core/net/http.c @@ -26,10 +26,15 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); -#define HTTP_PORT ((grub_uint16_t) 80) +enum + { + HTTP_PORT = 80, + HTTP_MAX_CHUNK_SIZE = 0x80000000 + }; typedef struct http_data { @@ -82,6 +87,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) { @@ -496,13 +503,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/grub-core/net/ip.c b/grub-core/net/ip.c index 3c3d0be0e5..f967618e53 100644 --- a/grub-core/net/ip.c +++ b/grub-core/net/ip.c @@ -240,6 +240,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/grub-core/net/net.c b/grub-core/net/net.c index 8cad4fb6d4..0d0de05ae3 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -32,6 +32,10 @@ #include #include #include +#include +#ifdef GRUB_MACHINE_EFI +#include +#endif GRUB_MOD_LICENSE ("GPLv3+"); @@ -87,8 +91,8 @@ grub_net_link_layer_add_address (struct grub_net_card *card, /* Add sender to cache table. */ if (card->link_layer_table == NULL) { - card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE - * sizeof (card->link_layer_table[0])); + card->link_layer_table = grub_calloc (LINK_LAYER_CACHE_SIZE, + sizeof (card->link_layer_table[0])); if (card->link_layer_table == NULL) return; } @@ -206,6 +210,7 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card, { struct grub_net_slaac_mac_list *slaac; char *ptr; + grub_size_t sz; for (slaac = card->slaac_list; slaac; slaac = slaac->next) if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0) @@ -215,9 +220,21 @@ grub_net_ipv6_get_slaac (struct grub_net_card *card, if (!slaac) return NULL; - slaac->name = grub_malloc (grub_strlen (card->name) - + GRUB_NET_MAX_STR_HWADDR_LEN - + sizeof (":slaac")); + if (grub_add (grub_strlen (card->name), + (GRUB_NET_MAX_STR_HWADDR_LEN + sizeof (":slaac")), &sz)) + { + grub_free (slaac); + grub_error (GRUB_ERR_OUT_OF_RANGE, + "overflow detected while obtaining size of slaac name"); + return NULL; + } + + slaac->name = grub_malloc (sz); + if (slaac->name == NULL) + { + grub_free (slaac); + return NULL; + } ptr = grub_stpcpy (slaac->name, card->name); if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0) { @@ -288,6 +305,7 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card, char *name; char *ptr; grub_net_network_level_address_t addr; + grub_size_t sz; addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6; addr.ipv6[0] = grub_cpu_to_be64_compile_time (0xfe80ULL << 48); @@ -302,9 +320,14 @@ grub_net_ipv6_get_link_local (struct grub_net_card *card, return inf; } - name = grub_malloc (grub_strlen (card->name) - + GRUB_NET_MAX_STR_HWADDR_LEN - + sizeof (":link")); + if (grub_add (grub_strlen (card->name), + (GRUB_NET_MAX_STR_HWADDR_LEN + sizeof (":link")), &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, + "overflow detected while obtaining size of link name"); + return NULL; + } + name = grub_malloc (sz); if (!name) return NULL; @@ -984,6 +1007,111 @@ 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) +{ + 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; +} + +void +grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter) +{ + char *name; + + { + char buf[GRUB_NET_MAX_STR_HWADDR_LEN]; + + grub_net_hwaddr_to_str (&inter->hwaddress, buf); + name = grub_xasprintf ("net_%s_mac", inter->name); + if (name != NULL) + grub_register_variable_hook (name, NULL, NULL); + grub_free (name); + } + + { + char buf[GRUB_NET_MAX_STR_ADDR_LEN]; + + grub_net_addr_to_str (&inter->address, buf); + name = grub_xasprintf ("net_%s_ip", inter->name); + if (name != NULL) + grub_register_variable_hook (name, NULL, NULL); + grub_free (name); + } + + inter->card->num_ifaces--; + *inter->prev = inter->next; + if (inter->next) + inter->next->prev = inter->prev; + inter->next = 0; + inter->prev = 0; +} grub_err_t grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, @@ -1402,9 +1530,15 @@ grub_net_open_real (const char *name) if (grub_strchr (port_start + 1, ':')) { int iplen = grub_strlen (server); + grub_size_t sz; /* Bracket bare IPv6 addr. */ - host = grub_malloc (iplen + 3); + if (grub_add (iplen, 3, &sz)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining length of host")); + return NULL; + } + host = grub_malloc (sz); if (!host) return NULL; @@ -1659,6 +1793,7 @@ grub_env_set_net_property (const char *intername, const char *suffix, { char *varname, *varvalue; char *ptr; + grub_size_t sz; varname = grub_xasprintf ("net_%s_%s", intername, suffix); if (!varname) @@ -1666,7 +1801,12 @@ grub_env_set_net_property (const char *intername, const char *suffix, for (ptr = varname; *ptr; ptr++) if (*ptr == ':') *ptr = '_'; - varvalue = grub_malloc (len + 1); + if (grub_add (len, 1, &sz)) + { + grub_free (varname); + return grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while obtaining the size of an env variable"); + } + varvalue = grub_malloc (sz); if (!varvalue) { grub_free (varname); @@ -1909,14 +2049,15 @@ grub_config_search_through (char *config, char *suffix, } grub_err_t -grub_net_search_config_file (char *config) +grub_net_search_config_file (char *config, grub_size_t config_buf_len) { - grub_size_t config_len; + grub_size_t config_len, suffix_len; char *suffix; config_len = grub_strlen (config); config[config_len] = '-'; suffix = config + config_len + 1; + suffix_len = config_buf_len - (config_len + 1); struct grub_net_network_level_interface *inf; FOR_NET_NETWORK_LEVEL_INTERFACES (inf) @@ -1942,7 +2083,7 @@ grub_net_search_config_file (char *config) if (client_uuid) { - grub_strcpy (suffix, client_uuid); + grub_strlcpy (suffix, client_uuid, suffix_len); if (grub_config_search_through (config, suffix, 1, 0) == 0) return GRUB_ERR_NONE; } @@ -2005,7 +2146,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; @@ -2014,8 +2155,49 @@ static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute; static grub_command_t cmd_setvlan, 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"); @@ -2066,12 +2248,41 @@ 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); + grub_register_variable_hook ("net_default_ip", 0, 0); + grub_register_variable_hook ("net_default_mac", 0, 0); grub_bootp_fini (); grub_dns_fini (); @@ -2088,4 +2299,7 @@ GRUB_MOD_FINI(net) grub_net_fini_hw (0); grub_loader_unregister_preboot_hook (fini_hnd); grub_net_poll_cards_idle = NULL; +#ifdef GRUB_MACHINE_EFI + init_mode = INIT_MODE_NONE; +#endif } diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c index 93dee0caa1..902ab7e8ae 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; @@ -571,7 +583,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; @@ -640,20 +652,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/grub-core/net/tftp.c b/grub-core/net/tftp.c index 409b1d09bc..3d96e50f4b 100644 --- a/grub-core/net/tftp.c +++ b/grub-core/net/tftp.c @@ -266,17 +266,19 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), * forward slashes to a single forward slash. */ static void -grub_normalize_filename (char *normalized, const char *filename) +grub_normalize_filename (char *normalized, const char *filename, int c) { char *dest = normalized; const char *src = filename; - while (*src != '\0') + while (*src != '\0' && c > 0) { if (src[0] == '/' && src[1] == '/') src++; - else + else { + c--; *dest++ = *src++; + } } *dest = '\0'; } @@ -287,7 +289,7 @@ tftp_open (struct grub_file *file, const char *filename) struct tftphdr *tftph; char *rrq; int i; - int rrqlen; + int rrqlen, rrqsize; int hdrlen; grub_uint8_t open_data[1500]; struct grub_net_buff nb; @@ -315,37 +317,45 @@ tftp_open (struct grub_file *file, const char *filename) tftph = (struct tftphdr *) nb.data; - rrq = (char *) tftph->u.rrq; - rrqlen = 0; - tftph->opcode = grub_cpu_to_be16_compile_time (TFTP_RRQ); + rrq = (char *) tftph->u.rrq; + rrqsize = sizeof (tftph->u.rrq); + /* * Copy and normalize the filename to work-around issues on some TFTP * servers when file names are being matched for remapping. */ - grub_normalize_filename (rrq, filename); - rrqlen += grub_strlen (rrq) + 1; + grub_normalize_filename (rrq, filename, rrqsize); + + rrqlen = grub_strlen (rrq) + 1; rrq += grub_strlen (rrq) + 1; - grub_strcpy (rrq, "octet"); + /* Verify there is enough space for the remaining components. */ rrqlen += grub_strlen ("octet") + 1; + rrqlen += grub_strlen ("blksize") + 1; + rrqlen += grub_strlen ("1024") + 1; + rrqlen += grub_strlen ("tsize") + 1; + rrqlen += grub_strlen ("0") + 1; + + if (rrqlen >= rrqsize) { + grub_free (data); + return grub_error (GRUB_ERR_BAD_FILENAME, N_("filename too long")); + } + + grub_strcpy (rrq, "octet"); rrq += grub_strlen ("octet") + 1; grub_strcpy (rrq, "blksize"); - rrqlen += grub_strlen ("blksize") + 1; rrq += grub_strlen ("blksize") + 1; grub_strcpy (rrq, "1024"); - rrqlen += grub_strlen ("1024") + 1; rrq += grub_strlen ("1024") + 1; grub_strcpy (rrq, "tsize"); - rrqlen += grub_strlen ("tsize") + 1; rrq += grub_strlen ("tsize") + 1; grub_strcpy (rrq, "0"); - rrqlen += grub_strlen ("0") + 1; rrq += grub_strlen ("0") + 1; hdrlen = sizeof (tftph->opcode) + rrqlen; @@ -359,6 +369,7 @@ 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) { @@ -369,11 +380,13 @@ tftp_open (struct grub_file *file, const char *filename) return err; } + grub_dprintf("tftp", "opening connection\n"); data->sock = grub_net_udp_open (addr, port ? port : TFTP_SERVER_PORT, tftp_receive, file); if (!data->sock) { + grub_dprintf("tftp", "connection failed\n"); grub_free (data); return grub_errno; } diff --git a/grub-core/normal/context.c b/grub-core/normal/context.c index ba185e9159..b4baa4392c 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/main.c b/grub-core/normal/main.c index bd44310005..2c07568895 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -207,9 +207,10 @@ grub_normal_init_page (struct grub_term_output *term, 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 (_("GNU GRUB version %s"), PACKAGE_VERSION); + msg_formatted = grub_xasprintf (_("GRUB version %s"), PACKAGE_VERSION); if (!msg_formatted) return; @@ -310,52 +311,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, config_len); + } + + 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) + if (argc) + grub_enter_normal_mode (argv[0]); + else { - /* 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; - - prefix = grub_env_get ("prefix"); - 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_enter_normal_mode (config); - grub_free (config); - } - else - grub_enter_normal_mode (0); + /* 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); } - else - grub_enter_normal_mode (argv[0]); -quit: return 0; } @@ -582,7 +610,9 @@ GRUB_MOD_FINI(normal) grub_xputs = grub_xputs_saved; grub_set_history (0); - grub_register_variable_hook ("pager", 0, 0); + grub_register_variable_hook ("pager", NULL, NULL); + grub_register_variable_hook ("color_normal", NULL, NULL); + grub_register_variable_hook ("color_highlight", NULL, NULL); grub_fs_autoload_hook = 0; grub_unregister_command (cmd_clear); } diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index 6a90e091f2..97687013c9 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -32,6 +32,7 @@ #include #include #include +#include /* Time to delay after displaying an error message about a default/fallback entry failing to boot. */ @@ -163,12 +164,92 @@ grub_menu_set_timeout (int timeout) } } +static int +menuentry_eq (const char *id, const char *spec, int limit) +{ + const char *ptr1, *ptr2; + ptr1 = id; + ptr2 = spec; + while (limit == -1 || ptr1 - id <= limit) + { + if (*ptr2 == '>' && ptr2[1] != '>' && *ptr1 == 0) + return ptr2 - spec; + if (*ptr2 == '>' && ptr2[1] != '>') + return 0; + if (*ptr2 == '>') + ptr2++; + if (*ptr1 != *ptr2) + { + if (limit > -1 && ptr1 - id == limit && !*ptr1 && grub_isspace(*ptr2)) + return ptr1 -id -1; + return 0; + } + if (*ptr1 == 0) + return ptr1 - id; + ptr1++; + ptr2++; + } + 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 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; @@ -179,20 +260,24 @@ get_and_remove_first_entry_number (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_NONE) + if (entry >= 0) { - /* Skip whitespace to find the next digit. */ + /* 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 (); @@ -201,7 +286,7 @@ get_and_remove_first_entry_number (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; @@ -218,7 +303,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; @@ -231,7 +316,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"); @@ -291,8 +376,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); @@ -303,7 +386,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 (); @@ -326,6 +409,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 @@ -340,13 +425,16 @@ 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 ("fallback")) + while ((fallback_entry = get_and_remove_first_entry_number (menu, "fallback")) >= 0) { grub_print_error (); @@ -354,11 +442,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) @@ -464,35 +550,12 @@ 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) { const char *val; + const char *tail; int entry; val = grub_env_get (name); @@ -500,38 +563,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; @@ -751,9 +785,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) case GRUB_TERM_CTRL | 'c': case GRUB_TERM_KEY_NPAGE: - if (current_entry + GRUB_MENU_PAGE_SIZE < menu->size) - current_entry += GRUB_MENU_PAGE_SIZE; - else + if (grub_add (current_entry, GRUB_MENU_PAGE_SIZE, ¤t_entry) || current_entry >= menu->size) current_entry = menu->size - 1; menu_set_chosen_entry (current_entry); break; diff --git a/grub-core/osdep/hurd/getroot.c b/grub-core/osdep/hurd/getroot.c index 0efefdab4a..b849700e64 100644 --- a/grub-core/osdep/hurd/getroot.c +++ b/grub-core/osdep/hurd/getroot.c @@ -58,7 +58,7 @@ grub_util_find_hurd_root_device (const char *path) file_t file; error_t err; char *argz = NULL, *name = NULL, *ret; - size_t argz_len = 0; + mach_msg_type_number_t argz_len = 0; int i; file = file_name_lookup (path, 0, 0); diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c index 2efee2c2ae..902cfee53a 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 7dd775d2ad..4bf386b590 100644 --- a/grub-core/osdep/linux/getroot.c +++ b/grub-core/osdep/linux/getroot.c @@ -103,6 +103,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)) @@ -119,7 +127,7 @@ struct btrfs_ioctl_search_args { struct btrfs_ioctl_fs_info_args) static int -grub_util_is_imsm (const char *os_dev); +grub_util_is_imsm_or_ddf (const char *os_dev); #define ESCAPED_PATH_MAX (4 * PATH_MAX) @@ -225,7 +233,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); @@ -373,6 +381,110 @@ get_btrfs_fs_prefix (const char *mount_path) return NULL; } +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) @@ -484,6 +596,9 @@ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) } } + if (!entry_len) + goto out; + /* Now scan visible mounts for the ones we're interested in. */ for (i = entry_len - 1; i >= 0; i--) { @@ -515,7 +630,16 @@ grub_find_root_devices_from_mountinfo (const char *dir, char **relroot) 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) + { + 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) { @@ -635,10 +759,10 @@ get_mdadm_uuid (const char *os_dev) } static int -grub_util_is_imsm (const char *os_dev) +grub_util_is_imsm_or_ddf (const char *os_dev) { int retry; - int is_imsm = 0; + int is_imsm_or_ddf = 0; int container_seen = 0; const char *dev = os_dev; @@ -699,10 +823,17 @@ grub_util_is_imsm (const char *os_dev) if (strncmp (buf, "MD_METADATA=imsm", sizeof ("MD_METADATA=imsm") - 1) == 0) { - is_imsm = 1; + is_imsm_or_ddf = 1; grub_util_info ("%s is imsm", dev); break; } + if (strncmp (buf, "MD_METADATA=ddf", + sizeof ("MD_METADATA=ddf") - 1) == 0) + { + is_imsm_or_ddf = 1; + grub_util_info ("%s is ddf", dev); + break; + } } free (buf); @@ -713,7 +844,7 @@ grub_util_is_imsm (const char *os_dev) if (dev != os_dev) free ((void *) dev); - return is_imsm; + return is_imsm_or_ddf; } char * @@ -1078,7 +1209,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev) /* Check for RAID. */ if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev) - && !grub_util_is_imsm (os_dev)) + && !grub_util_is_imsm_or_ddf (os_dev)) return GRUB_DEV_ABSTRACTION_RAID; return GRUB_DEV_ABSTRACTION_NONE; } @@ -1140,6 +1271,32 @@ 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) +{ + if (mount_path) + *mount_path = NULL; + + 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; + + 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/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c index 0b1f7618d2..0ce0e309ac 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/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c index ee11b02fb6..c7aa202abe 100644 --- a/grub-core/osdep/unix/getroot.c +++ b/grub-core/osdep/unix/getroot.c @@ -540,7 +540,6 @@ grub_guess_root_devices (const char *dir_in) for (cur = os_dev; *cur; cur++) free (*cur); free (os_dev); - os_dev = 0; } if (stat (dir, &st) < 0) diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c index 14ff09094f..8cedfd0294 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -33,10 +33,18 @@ is sizeof (int) * 3, and one extra for a possible -ve sign. */ #define ERRNO_DIGITS_MAX (sizeof (int) * 3 + 1) +/* + * A limit on recursion, to avoid colliding with the heap. UEFI defines a baseline + * stack size of 128 KiB. So, assuming at most 1-2 KiB per iteration this should + * keep us safe. + */ +#define MAX_RECURSION_DEPTH 64 + static unsigned long is_continue; static unsigned long active_loops; static unsigned long active_breaks; static unsigned long function_return; +static unsigned long recursion_depth; #define GRUB_SCRIPT_SCOPE_MALLOCED 1 #define GRUB_SCRIPT_SCOPE_ARGS_MALLOCED 2 @@ -752,6 +760,9 @@ grub_script_arglist_to_argv (struct grub_script_arglist *arglist, } } + if (result.args == NULL || result.argc == 0) + goto fail; + if (! result.args[result.argc - 1]) result.argc--; @@ -816,7 +827,13 @@ grub_script_execute_cmd (struct grub_script_cmd *cmd) if (cmd == 0) return 0; + recursion_depth++; + + if (recursion_depth >= MAX_RECURSION_DEPTH) + return grub_error (GRUB_ERR_RECURSION_DEPTH, N_("maximum recursion depth exceeded")); + ret = cmd->exec (cmd); + recursion_depth--; grub_snprintf (errnobuf, sizeof (errnobuf), "%d", ret); grub_env_set ("?", errnobuf); @@ -897,7 +914,10 @@ grub_script_execute_sourcecode (const char *source) break; } - ret = grub_script_execute (parsed_script); + /* Don't let trailing blank lines determine the return code. */ + if (parsed_script->cmd) + ret = grub_script_execute (parsed_script); + grub_script_free (parsed_script); grub_free (line); } diff --git a/grub-core/term/at_keyboard.c b/grub-core/term/at_keyboard.c index f8a129eb7f..d2b716b5b4 100644 --- a/grub-core/term/at_keyboard.c +++ b/grub-core/term/at_keyboard.c @@ -25,12 +25,14 @@ #include #include #include +#include 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; @@ -86,10 +88,12 @@ 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); } -static void +static void __attribute__((__unused__)) grub_keyboard_controller_write (grub_uint8_t c) { at_command (KEYBOARD_COMMAND_WRITE); @@ -115,6 +119,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) { @@ -123,11 +142,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) @@ -135,6 +157,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); } @@ -142,23 +167,66 @@ static int query_mode (void) { grub_uint8_t ret; + grub_uint64_t endtime; + unsigned i; int e; + const char *envvar; - e = write_mode (0); - if (!e) - 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) - return 1; - if (ret == 0x41 || ret == 2) - return 2; - if (ret == 0x3f || ret == 3) - return 3; + 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); + } + + /* + * 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; } @@ -167,15 +235,32 @@ 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 - ps2_state.current_set = 1; + 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; + } else { + grub_dprintf ("atkeyb", "using queried set %d\n", grub_keyboard_orig_set); + ps2_state.current_set = grub_keyboard_orig_set; + } return; #else @@ -257,6 +342,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) @@ -276,7 +362,9 @@ 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 (); + grub_dprintf ("atkeyb", "grub_keyboard_orig_set = %d\n", grub_keyboard_orig_set); #endif set_scancodes (); keyboard_controller_led (ps2_state.led_status); @@ -285,11 +373,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; } @@ -320,7 +412,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/grub-core/term/ns8250-spcr.c b/grub-core/term/ns8250-spcr.c index d52b52c265..86f1aa078c 100644 --- a/grub-core/term/ns8250-spcr.c +++ b/grub-core/term/ns8250-spcr.c @@ -75,6 +75,11 @@ grub_ns8250_spcr_init (void) config.speed = 115200; break; }; + + /* if base address is 0, it means redirection is disable, so return it */ + if (spcr->base_addr.addr == 0) + return NULL; + switch (spcr->base_addr.space_id) { case GRUB_ACPI_GENADDR_MEM_SPACE: diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c index ae634fd419..631a893564 100644 --- a/grub-core/video/readers/jpeg.c +++ b/grub-core/video/readers/jpeg.c @@ -339,6 +339,10 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) if (grub_errno != GRUB_ERR_NONE) return grub_errno; + if (data->image_height != 0 || data->image_width != 0) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: cannot have duplicate SOF0 markers"); + if (grub_jpeg_get_byte (data) != 8) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c index 3163e97bfe..aa7524b7dc 100644 --- a/grub-core/video/readers/png.c +++ b/grub-core/video/readers/png.c @@ -626,7 +626,7 @@ static grub_err_t grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n) { if (--data->raw_bytes < 0) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflown"); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflow"); if (data->cur_column == 0) { diff --git a/grub2-key.asc b/grub2-key.asc new file mode 100644 index 0000000000..7db30fdfe6 --- /dev/null +++ b/grub2-key.asc @@ -0,0 +1,144 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFiWn2QBEADXm20A5f/kQt3zImaTdtSVG3xnyaE9KhhfHfbS5XxoTzH63c04 +AU3OGKQFJCn9fND7BrWDu8g/+D4n16VCvaRX6VYQ4zmaQmQgQQzJPqZ07O67t6/O +9DO/IJzDyjzkqWIq9u/IlhzzRmQokUQQ2hNVY355eBQHlZ4W5XTKS6r2eI6WaF+8 +/Bqs9vj5R83MmipkwOFvhc39BUeEMY2XVkootIcrQH5cNTKvNHe6QWVUOY4IdxwZ +mHG0UXm0LbStxMVUln1524NcZi5s2DqQXg4t2Arwo/xv3+UBtbLOi25gyM31GgAR +NUr4XlTsNQoJpmM53lRNjdyyOor8zF2QdJj9O7NYaO4WsDNEX26ahAzrNTxhPwem +aqdOvtPMHQKVyKIWTxC0U97ht3FHjSBOJpqk0MXKuNWRI3XoBarjYBgXJGDWhYH7 +292vbo+khSApe2wct2P3h91cmWspsGfRGLPSy6h6o9VLiIbnwPoeiZbgha4C2ofL +tUnEqkQBJZ27Dqy0wLHil1RuXftiG0OtrSQBuBWWfZHOWH25ozOGblJ5QPqmkd4M +dWRoYcOVxKxRky0zv8erZnng7IiacXFqSFOcG1IILXpZcPcr/QlXqzl2/ruHgAFR +Ls7TEMfAgfpEKzgxX9f6vQ3VrvlpuvttWDjZC27MOFjFZxftDseP1F1/zQARAQAB +tCZEYW5pZWwgS2lwZXIgPGRhbmllbC5raXBlckBvcmFjbGUuY29tPokCrAQTAQoA +lgIbAwIeAQIXgAQLCQgHBRUKCQgLBRYCAwEAWBhodHRwczovL2tleXMub3BlbnBn +cC5vcmcvdmtzL3YxL2J5LWZpbmdlcnByaW50L0JFNUMyMzIwOUFDRERBQ0VCMjBE +QjBBMjhDODE4OUYxOTg4QzIxNjYWIQS+XCMgms3azrINsKKMgYnxmIwhZgUCZiq8 +owUJFvoevwAKCRCMgYnxmIwhZsTlD/4pZtQhngLdCpttoqScVuoA2M3RZYL6UmSa +jqZiNfdpeNoMIXzWT4WF9iAc6dJVsT59+LuplVQV4aPDsoDMNmmcNpnE4J69D2eO ++36QufcRO1jNII2SrjYU6FTvQYUF9yQDXOK77IDTClGD27IA0rZ6o9yKsIPt7PBY +1zZiQku+jfbj1n9RtXnHscl7dMEm5OM5gGveCf2hk5BpB0GiB/gcP5tpIxuApV05 +7gCB2rr6/vu36mn643OVBfRtmtBo2gGJ1003fofMIZ5Awcm1GqFjXhrHGt/ZfoZD +A5cJBzGRnU1HHZ+NjMIWUnthunH1XwEEPile1B8v+sMwDC4MU697xqRWdPza3bor +vX1CACFB9g5c8bN5Dj6lk+Dq9f6nUYzSsmdQmVZ2/2jVCpxH5ZKi8sq1miWZwZca +rq8yxzw1l4KL9X20UMenh7JBZSV1IR5y8xGhBrJk01NQnevHYjKaBpscyrqtfhLQ +VNwmu8aj74+6ZhRZqjD5K+5kWw6SpK5bUbtcxd8I2oGRkKTZfalYIXEINyo3vE3Y +hW+Wl9WZnWvsF/ZH2YTgdDJY8Wv6a03gdfaBrVCtx1fD3udfPat+IEGAF9zM2dLz +nyE5oYqZRoCbvIAY6zaBBwZbHDYyjzz8VGNDJV28Vxe3NkYd+5nFGW+zJsoeCLFs +QiGM3nmtGYkCVAQTAQgAPgIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgBYhBL5c +IyCazdrOsg2wooyBifGYjCFmBQJj7CHdBQkUu4P5AAoJEIyBifGYjCFmkx8P/1kj +ihb4yW17JB3vLfBKaDl1z1Qsq62QUP2FF2WTxrQ0OA+AMdA+Fw47vatUcJZ6fEtB +q7kbVIg4qwCgYhPCI+8qpumoSzNg+bXt/eAbp9zQ0ZzHSPHWddHCv1PGABss2JYS +0xunRilaID6Rg6/IQ1IOdMDPS2lbQshbHa/nLywEmjxLYrv3gpuLNF4T5r6dlOax +Tqh6tDfW4UynHi/NXBEiYL+wihZVDGCm03gPdDVbyzvUiRkA1M+XPejCnXVtJbgX +qqJidgPXVFrCn0pjkwOJGHNZfOaI3+eBYYCW08r2JqwCLsIQmGjtEEmvRUimLphA +w7MFD94ZMDGmQ4dgZdgomxix8NIzeHYqI5vPMrDVHfbSse8UuBbpYKI8/WH6m6xT +XgmTSOijowYdDAxlNOb9jHiCXxoThduaJXwPBxVwNkl9P5JmXyuWvm8wHDy0EndI +OiQQdMOH6ejdwbUjVHZPDe16ljtWuuh6XOms26l4FXbq9HEo0VD3WuumC1RjlSws +X00sCg9zVLGqcjcdjUeIFxk5Jvydx6PnSXz8KmyCPnhSSaDzz//G5+hfYtFDJM8M +r1qTpZ54131cRAv4l/gejSuNEv6wWVXayIefSKSSxTsFNzxwGVE6EeDVSMMElxE6 +Yx7DHNHZfdd+DFP3GcFxYt5pX6xiK6YxnJGAoP9viQJUBBMBCAA+FiEEvlwjIJrN +2s6yDbCijIGJ8ZiMIWYFAl7kvUQCGwMFCQtl/7cFCwkIBwIGFQgJCgsCBBYCAwEC +HgECF4AACgkQjIGJ8ZiMIWayYg/+Nfky1iSaoIInsb4nVc/rxePsosVpACZgs2jS +X6OTcTIoVoZOvd9JiqJE2Da+sLmypD786TXXyRAyIxBTZKKyLDvly54J3Mjl+ZaO +nWq9IpUsYY5oBJTEBaZATV0WXJtTJGHEdxgrvJj8DiEjvTkfWAWZ6GWHw7/o1bFR +2jPra85p9Fi3MMplUHskWN5LIOtU7Eqn27ncGwEnpK4nzskYepgNoDOYNsXJEEzt +Q31PhLGzxbkWVF++3QomsTkRJwl1oF7zF9AFIC/uktmaInGYmg6f2FVmY4IsQSEt +htoHy8ssA5vG++MeqU/baRudVQT5zHCNYAic03FOOU0ixDSLIjlipWOnaknshQmG +SWyeEteEcbNoj9s9T8gJqCCG36KGkVlNBOtgZP4hMi3Vit6zBTb1iAUns2dQ2JTW +CaaxPkpUEFfnqQsYj+FxTsmPUw8rM47o+rTsE+aYM0YNW/Y6U4uCJMb2ShWpz2DB +tCmuBLZJCIZo/8Q37nWOmIw508i3+5aCqRmcvlNtRGbh+S1DNSOlfoYqZ53M2C5V +RvK7oT9Ey+FMTfhJUSlS+IWgt3pLW1OsHZOTx6YFoi47CumqOWdrMa01PNsqmVH9 +IMRM3Ln+dQm7n8Mff2og8ojRxRKNQoatF1/LBX8LSswlRLZ2ZG9jUFx1pxXvtEQs +ablsplO0IkRhbmllbCBLaXBlciA8ZGtpcGVyQG5ldC1zcGFjZS5wbD6JAq8EEwEK +AJkCGwMCHgECF4ACGQEECwkIBwUVCgkICwUWAgMBAFgYaHR0cHM6Ly9rZXlzLm9w +ZW5wZ3Aub3JnL3Zrcy92MS9ieS1maW5nZXJwcmludC9CRTVDMjMyMDlBQ0REQUNF +QjIwREIwQTI4QzgxODlGMTk4OEMyMTY2FiEEvlwjIJrN2s6yDbCijIGJ8ZiMIWYF +AmYqvKMFCRb6Hr8ACgkQjIGJ8ZiMIWadMRAAlkioldBUy4CJmdisbyEccjanKFdH +ZYyECW5/Cr4g6GJoc+alnKD1BqRrrZokpvOmU8pZV3GliMZbfsCWP4xafGcFceq/ +0enpwS8SXMGWuBzgVUp4wJiSjX3s0mSlUKxBEdgyoQD0qDg6QWflos0d8YS4ZhbJ +nGQH8AqSWVZ8x7SyVBxOuXnT4nMDeda5UarApCDUrRnzi1aXRsr7URQyQVbHSbZp +8GSUcEimRiOJmDucn9Qtj/RHIdB13bWwjpCGrtUneGgHNCJS6rfoDTETirYwfc+h +c1DO/u/3Tzo223UnVe8/Q9z0bbx+BvfeJ4cdFa0NqzgG8ikYW0VSwhFr/AoY83Vw +TYuEFXhmLgkBnY2GgaEMxYSQi8E57dBTdbviR6TS5xTPM1Fgy7/pP+Ocl6xwmfbg +2Y+taVz+PcMV8lMm3oPTc9BbJhf7VDQ9+J+vEyWFrAyon0rRPS+pW+SoVXxnkLcH +sGAIuJQoE39W8fnQ5SUwsN7uxFHtSVRJYfJ01/cAIE3AfDzMgMWJ8F2jTOP2oh7t +4DAvyU1YL38PWlkKZ6Dj4pCk/ZnSdpRpdsdtc7cphIAFt1qShUvr2tDM8iCgIpUb +6I/UlHWuQENEws/j3yG2EdCHI+OxoKcW/bJRY+hKqR1tFdE3W7oWh1r/Ektp2lsw +bRs3gbUDN/ROLiGJAlgEEwECAEICGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheA +AhkBFiEEvlwjIJrN2s6yDbCijIGJ8ZiMIWYFAmPsId0FCRS7g/kACgkQjIGJ8ZiM +IWZyiBAAg7unDNEg0hYMVoLUQDSVC/73OBaxaLTkGERDsueQZnKjcqsg7nJtCVqU +GOknqnNRT890cEajv0CJw5nNUA3bPi0DkTi7dU4CgdeXinHKZ2/qwDSVT6daKz/I +GgD82kpT5Xn7z7N50FGxLzDmfiyPLC0IaioJsNb3EOi+9qII/7dqLZtwyn8DjO+w +zp4pH8JrD/px3wIMrUC61ol1Lga0SIXhD94UJiA4zrkV1sxRywPDqgk9gH5iSZm6 +eSgUHJnB2Jz76vKXjEXxEngx5MzA8KJf6tZkVb4QOxNjj8UA0+7LXCV0G3WptBL4 +6JT7UbzGCT4WjH1CE7nQAHbXZMmR62wmRIWKZu6crtl+i34IZxuLlgHk6fWI5af9 +U+Fl/ohMs/wgBV1uZKZbZ4rldiUu4sBBFBIFhrn1p6N567GVRb2hgpTiTVflVoAD +YRWfMSyMpw3gQ05fYOmogaALQiN4xk+ywxYGlf9BLqrAEts5meZiZckQACOQgMuP ++6kPxM4A0nqL2kL9AM45eNeyYeYRWB/D97j2mNEIK1rJrNkuFQZm+x9ljnbkPEUq +eueDV9cxLQBYEZ/gc+xh03e0DTf/fDYHI14r9R7weB6zOnA64FpAZH+4Al6OywZW +Ls1edR0mk+/QrujWqc8Aw20Rj7hXWEJyCQmlKzykAFxZ2FsjnzCJAlgEEwECAEIC +GwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQkLZf+3FiEEvlwjIJrN2s6yDbCi +jIGJ8ZiMIWYFAl7kv70CGQEACgkQjIGJ8ZiMIWaDpw//ZssWq2wlXK5qMkrOZomf +mrUGpwFoa7JlgnPC2v949UwboqJ3cOPwZJdupGomuzbT4/T8+c5Jfw6jjOqwvC/x +mS4IeCCtgDKw2qg7xpAQuFrT/+MXmHVFnke5THtTZ41kDM6Q34iOrYvRr30hySNB +jY94SsJQN9T/6CfKf/kq/4OmdnnSinbRcsK/OurJcP1oP3yxiVeD4SaqbknnO2a5 +JH8Cdx9BrlHMwRu8r3juSDdzIYiG5v5uUATy0ql060hfTglLgzebzgw030uZp02u +9GvYehuMKnbFLyuKhhPMqEtvKG42BF8Zflw+aRqnQrQW3W4WnEK6UG/XEo5RYg3v +5EvwZGOsNj6BUzrLDeSK+lghKud3D8RNeGHt1a6W1+m7n6sXwXqTOXMoR9RbpAlg +kJqq/9jnNqg3ROWcTi0lRYJrFgAhpsDDemqflfHnyHuodre6rxJ0ODdO2vsc10SS +fv+JQ57l293ij5Riz83RNpDBuLoEaHipm13Tts4S6+T1gbXv74FTBlNpah/kfkDk +GJw4iUzjp3AfXRAg0RqmDIEvzQmlGIEl/IXxqgbKd3tMCBfArN4nWS+X1Z68RGNw +ujn3Hi4KcMDR3Y0vgeHjp6MpPe+f/X0rs/sXr8b9S0oLY5E2xTjF4aDGVbuyE20G +6gtoWTAEfkE9URjYZbyWzd+JAlUEEwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMB +Ah4BAheABQJalp2jBQkLZf+3ACEJEIyBifGYjCFmFiEEvlwjIJrN2s6yDbCijIGJ +8ZiMIWb1YhAAgvhwtDzHMqOgjy+h3XPYcjcPvcUhD/I+PrX+yQ3z2kYaq9ZvEtDM +gbRwrcuRbuvw4P5KTAY5Ikdxe6wJ8/N5o7bD2HP11rcTX1kYEcd/4Lq+wdWT60hf +fExTne6Q79X9mQHfXzISb8JJiZ9TKsDgYHx8ALXPHjLkUhPkubQ2m4+/iFLePtYA +sl4CkpRUi/bXFR4KntBcLY6ZQjfuayU8Ls0CPi2+6ERFVWgL5cWlCG8P2hzB2hED +tTY2SxEkvzNCUh7e8y5d+VuUqHdxAdkRw9gfLVlWMVEjmPuQshJz/gh6FERWMQDF +tMgFQHANVPJbJIT+fYbs8uPR6KP1SlstE9YHMSsUT+imkJYnxmTHvZElG8DQDUtr +fn8zzBTYR2Us8zorgjUET8R8GhKxwgqWO09sna9QC9sCTnd4h8ALLXnfnEXSbvhA +tJbir840vB1CfX2TuzSt0frIRRjbO8vK1JBupz8SYkHsNeCq06XWcSggZtF+G5C0 +FPunLdX2Wb8HmueNDUbhQYasVQVYU/K0XffoYeKv2ti7P2TonB3/tM9b7Nw2p+4/ +8XUuw+TCjH2dtfgTRHAQT2E0K2AYROlves/HP2Raa5UGGWCgoWwNpsWGDIbngEee +G8pjMYJ2ebNNgAwGe6C79LsCEyR2YQ8zCJwojhbCSaVX6k0JbbidDz2JAlUEEwEC +ACgFAliWn2QCGwMFCQPCZwAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAACEJEIyB +ifGYjCFmFiEEvlwjIJrN2s6yDbCijIGJ8ZiMIWbmFA//ZgPV18L21cgl8nkGrljN +ZCApkUTX4qbzwUE33pfE/ZUlf7k/Jy9mBOq6pYHdnsBVoMovDh6etR2o2fnRRWG6 +rVb6bRvUEmUH5f6GuU9p7z5yjHRA7Eh5iMp+Q6AzPQFertuLWmU/UAWT19VsRsTa +3matf0C1wQDyyZfNnFtIa7IwSdDuSJMlJk4IbcQFUG6qIvw9e680T6FepUxahNjK +e7yNyKlyXnMBzjtA69Tip7ElKpOww/1CuhKDIbNWqu9Zwy/1kuKSAJvSToahsqD+ +TxWWeqdi6NQPCPUUAmVDXxXblWkAjM8ET3WU1XTAJO7Ftz2atz+m9CoDvpT5vRTJ +mgXm+nV2MxUgRycjpNEB5TSeaH9enoHqBqmZRbCaAyVnXM1kmySlfXgkjlzKWo7W +SNXNeDN75n+Ox9I2oazoNiJhnMFfnAP8M9Y10qZiydtz9Yo6Idk+Uwy4eKzA54QC +Shyf3EIAsMA229WABCVYxU/D3swFyKyA5TftgkrT+YW1Mep4PVqU7Kllq5jdD0rF +NpwL2mn1q/qFqZJiN3RWKxSBso7sPxIfZ9DBV8MnakwcCodzfKJeQIZFaf6b9fba +H/so45F265F+CHt7Wn9k8u4KlpmgfaWKuYgd2kdyZBgDIaanHVrXyqaWPwOuQYpD +k96tfg23ctiUzrQAGN/I7qS5Ag0EWJafZAEQAKlDAz4CW/6GG6ZS2xL9kP5ovB3c +Q47p0jUeFYY63rnmr7R1MC8Y7o+X3S0JBVKDImOg9xmk9xLZ4oUAiOdduCvG3y4Q +7ucXCgRlU/Y2ijcu8IJbCKfcEh1hqmU90R6hScB7QAzORmtTiu0Lg99+25dkw3mv +tJlw9dEhcHhRCQ8UsOLlWMwC4sDIFyX8MzhdUITLlBnxjEACBumD+7d2UDB8mrVj +Jw1sLDr2cFJ1lWKdpShl/cqVqx88AZ7sI7cT7xE1oZvywsh9/yOI9EtbNCE300lM +/d1gm73XFAN63L1wFo5194vQ96YjxZUHrY41Xi2O+N4bE91gsdAr6m4XVkC5VDEX +owudbTKDaA7WeT3Zrv26Drvy/+VoE+iThdtdf4TeQfsogAjpZRwYCAjHuyfYeSnd +tpPAcsTKiQkHqSEqO39I3XPWd6ktsNTeyClyu9GXCTHR6lAewZy1RRKn/r/A3qNp +Evy717kwMVOQ3FPHatWwUE4uXuKQf4OPEWd87F6MhbwN/KXKaZP7BGynInPue7Dx +Esi685pK8GJImpArYmJuSsyUKe9GUMBwY4XHAMuZm3ucalDloDlkfLtccFNCWBc8 +jVHuGSKNhpTeBd44ge1SD4dgT0VIFXXvNRQrKvtKfqy0heqrc4Y/5Ow0BUDr5hvc +5VrH01jFH5gsF3lNABEBAAGJAjwEGAEKACYCGwwWIQS+XCMgms3azrINsKKMgYnx +mIwhZgUCZiq8kgUJFvoergAKCRCMgYnxmIwhZsgoEACrDcxdnE3bSARLw7QBzjpR +xEuX+kovVRpFiaGEVMpzxeESrj8vKtf95u5Evww0VSIiI6VJ64OkL8Vv2qBTunyV +rHNZiIIMyYJPiRi0zXaDxQjp8WESCYThyG2cpiTwZuMprDF44/CTaht88UayWnUn +68vcX2Jo6lZsTgvpexhspZM7qlGa7HRImD/k9RzaW13n/3rKy7GWajSb7ALw0rbA +1QW705DEF1Rhh4x2I6Sd8qrLx0C+DY8UeohZevtLLMhH4dEQL77iiEkJMw8jIQqJ +9ls9Y6QbFP3lfmiHj9LSudW2lblp61k9SVoC+o0o/JFcwj40ka1kUn7za1zG7GnE +LoP4xll2AGtqoKd4SYSQ/wLaFGw6SiOY6lR/WCxo1BXMglfe5tFlb+Hqcxauy5y3 +vQ8cM1m9B9ikFMJIrh2dakO9hB7FFluQa++rkq3tmzRhgNqg1BEiZNGWgkA9hPv+ +3E6GawkZtb4iH3qo/oiuCXJ4KMyRFdPXd1LvlLtkyyuC4YeIaXDg9cBDixlnf0Ct +RbhWQpmfPFvZpNhzOEdlZ9x0J499HU6TZsBhP8m7SqZrgO1d1SgIUfD0RrrEnGE7 +XtIVs2SlbUsb3MNRz/xTypI60CmIv9h9KGeCpvEevIKzo1Jl3n9MwiKEa6SCgYOX +sRJfWXMYdn8mwLcBy339Xw== +=oLn/ +-----END PGP PUBLIC KEY BLOCK----- diff --git a/grub2.spec.in b/grub2.spec.in new file mode 100644 index 0000000000..56357e571d --- /dev/null +++ b/grub2.spec.in @@ -0,0 +1,1257 @@ +# 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 @VERSION@ +%undefine _missing_build_ids_terminate_build +%global _configure_gnuconfig_hack 0 + +%global efi_vendor qubes +%global efi_esp_dir /boot/efi/EFI/%{efi_vendor} +%global gnulibversion 9f48fb992a3d7e96610c4ce8be969cff2d61a01b +Name: grub2 +Epoch: 1000 +Version: @VERSION@ +Release: @REL@%{?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: https://ftp.gnu.org/gnu/grub/grub-%{tarversion}.tar.xz.sig +Source2: gnulib-%{gnulibversion}.tar.gz +Source3: 99-grub-mkconfig.install +Source4: http://unifoundry.com/unifont-5.1.20080820.pcf.gz +Source5: theme.tar.bz2 +Source6: gitignore +Source7: bootstrap +Source8: bootstrap.conf +Source9: strtoull_test.c +Source10: 20-grub.install +Source12: sbat.csv.in +Source13: 99-grub-mkconfig.install + + +### begin grub.macros +# 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 0 +%global emuarch %{_arch} +%global grubefiarch %{nil} +%global grublegacyarch %{nil} + +# 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} +%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} + +### fixme +%ifarch aarch64 %{arm} +%global efi_modules " " +%else +%global efi_modules " backtrace chain usb usbserial_common usbserial_pl2303 usbserial_ftdi usbserial_usbdebug keylayouts at_keyboard " +%endif + +%ifarch aarch64 %{arm} +%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 %{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} +%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 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 which file system-logos \ +Requires: grub2-common = %{evr} \ +Requires: grub2-tools-minimal = %{evr} \ +Requires: gettext which file \ + \ +%{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 apply --index --whitespace=nowarn %{SOURCE3} \ +#git commit -a -q -m "%{tarversion} master." \ +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} + +%ifarch x86_64 aarch64 %{arm} +%define mkimage() \ +%{4}./grub-mkimage -O %{1} -o %{2}.orig \\\ + -p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES} \\\ + --sbat %{4}./sbat.csv \ +%{4}./grub-mkimage -O %{1} -o %{3}.orig \\\ + -p /EFI/BOOT -d grub-core ${GRUB_MODULES} \\\ + --sbat %{4}./sbat.csv \ +%{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}.onesig -a %%{5} -c %%{6} -n %%{7}}} \ +%{expand:%%{pesign -s -i %%{3}.orig -o %%{3}.onesig -a %%{5} -c %%{6} -n %%{7}}} \ +%{expand:%%define __pesign_client_cert grub2-signer} \ +%{expand:%%{pesign -s -i %%{2}.onesig -o %%{2} -a %%{5} -c %%{6} -n %%{7}}} \ +%{expand:%%{pesign -s -i %%{3}.onesig -o %%{3} -a %%{5} -c %%{6} -n %%{7}}} \ +%{nil} +%else +%define mkimage() \ +%{4}./grub-mkimage -O %{1} -o %{2} \\\ + -p /EFI/%{efi_vendor} -d grub-core ${GRUB_MODULES} \ +%{4}./grub-mkimage -O %{1} -o %{3} \\\ + -p /EFI/BOOT -d grub-core ${GRUB_MODULES} \ +%{nil} +%endif + +### QUBES OS: -blscfg -efi_netns -version +multiboot +multiboot2 + +%define do_efi_build_images() \ +GRUB_MODULES=" all_video boot btrfs \\\ + cat configfile cryptodisk \\\ + echo efifwsetup efinet 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 lsefi lsefimmap luks \\\ + luks2 mdraid09 mdraid1x minicmd net \\\ + multiboot multiboot2 \\\ + normal part_apple part_msdos part_gpt \\\ + password_pbkdf2 pgp png reboot \\\ + regexp search search_fs_uuid search_fs_file \\\ + search_label serial sleep syslinuxcfg test tftp \\\ + video xfs zstd " \ +GRUB_MODULES+=%{efi_modules} \ +%{expand:%%{mkimage %{1} %{2} %{3} %{4}}} \ +%{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} ./ } \ +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}/ } \ +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} + +# TODO: switch to %upper macro with rpm 4.19+ +%define upper_() %{lua:print(string.upper(rpm.expand("%{1}")))} + +# This is supposed to be case-insensitive anyway. But all-uppercase (even for +# the x in BOOTx64.EFI) is what both 'grub2-install --removable' and systemd's +# 'bootctl install' do, and it might be safer: +# https://github.com/systemd/systemd/commit/00f69504a2c1861d98a027afdebc22c873f09083 +%define efi_default_image() /boot/efi/EFI/BOOT/BOOT%{upper_ %{1}}.EFI + +%global efi_startup_script /boot/efi/startup.nsh + +%define do_fallback_efi_install() \ +cd grub-%{1}-%{tarversion} \ +install -D -m 700 %{2} \\\ + $RPM_BUILD_ROOT%{expand:%%efi_default_image %{3}} \ +%if "%{3}" != "%{alt_efi_arch}" \ +printf '%s\\n' '\\EFI\\%{efi_vendor}\\%{2}' > \\\ + $RPM_BUILD_ROOT%{efi_startup_script} \ +%endif \ +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 \ +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:%%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) /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 \ + \ +%{expand:%if 0%{?with_legacy_modules} \ +%{expand:%%files %{1}-modules} \ +%defattr(-,root,root) \ +%dir %{_libdir}/grub/%{2}/ \ +%{_libdir}/grub/%{2}/* \ +%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(0700,root,root,-) \ +%config(noreplace) %{_sysconfdir}/grub2.cfg \ +%config(noreplace) %{_sysconfdir}/grub2-efi.cfg \ +%attr(0700,root,root)%{efi_esp_dir}/%{2} \ +%ifarch %{arm} \ +%attr(0700,root,root)%{efi_esp_boot}/BOOTARM.EFI \ +%endif \ +%attr(0700,root,root)/boot/grub2/fonts \ +%dir %attr(0700,root,root)/boot/loader/entries \ +%ghost %config(noreplace) /boot/grub2/grub.cfg \ +%ghost %config(noreplace) %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} \ +%attr(0700,root,root) %config(noreplace) %{expand:%%efi_default_image %{7}} \ +%if "%{1}" != "%{alt_package_arch}" \ +%attr(0700,root,root) %config(noreplace) %{efi_startup_script} \ +%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(0700,root,root,-) \ +%attr(0700,root,root)%{efi_esp_dir}/%{3} \ +%attr(0700,root,root)/boot/grub2/fonts \ +%{nil} +### end grub.macros + +### begin grub.patches +### end grub.patches + +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 + +%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} + +%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. +Obsoletes: grub2-tools < %{evr} +Requires: grub2-common = %{epoch}:%{version}-%{release} +Requires: gettext-runtime file +Requires(pre): dracut +Requires(post): dracut +Requires(pre): grep +Requires(pre): sed + +%description tools +%{desc} +This subpackage provides tools for support of all platforms. + +%ifarch x86_64 +%package tools-efi +Summary: Support tools for GRUB. +%if 0%{?fedora} >= 37 +Requires: gettext-runtime file +%else +Requires: gettext file +%endif +Requires: grub2-common = %{epoch}:%{version}-%{release} +Obsoletes: grub2-tools < %{evr} + +%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} +Obsoletes: grub2-tools < %{evr} + +%description tools-minimal +%{desc} +This subpackage provides tools for support of all platforms. + +%package tools-extra +Summary: Support tools for GRUB. +Requires: gettext-runtime file +Requires: grub2-tools-minimal = %{epoch}:%{version}-%{release} +Requires: grub2-common = %{epoch}:%{version}-%{release} +Obsoletes: grub2-tools < %{evr} + +%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}} +%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}} +%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}} +%{expand:%do_fallback_efi_install %%{grubefiarch} %%{grubefiname} %%{efiarch}} +%endif +%if 0%{with_alt_efi_arch} +%{expand:%do_alt_efi_install %%{grubaltefiarch} %%{grubaltefiname} %%{grubalteficdname}} +%{expand:%do_fallback_efi_install %%{grubaltefiarch} %%{grubaltefiname} %%{alt_efi_arch}} +%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 + +# Make selinux happy with exec stack binaries. +mkdir ${RPM_BUILD_ROOT}%{_sysconfdir}/prelink.conf.d/ +cat << EOF > ${RPM_BUILD_ROOT}%{_sysconfdir}/prelink.conf.d/grub2.conf +# these have execstack, and break under selinux +-b /usr/bin/grub2-script-check +-b /usr/bin/grub2-mkrelpath +-b /usr/bin/grub2-mount +-b /usr/bin/grub2-fstest +-b /usr/sbin/grub2-bios-setup +-b /usr/sbin/grub2-probe +-b /usr/sbin/grub2-sparc64-setup +EOF + +# 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 -d -m 0755 %{buildroot}%{_userunitdir}/timers.target.wants +ln -s ../grub-boot-success.timer \ + %{buildroot}%{_userunitdir}/timers.target.wants +# 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 + +%triggerun -- grub2 < 1:1.99-4 +# grub2 < 1.99-4 removed a number of essential files in postun. To fix upgrades +# from the affected grub2 packages, we first back up the files in triggerun and +# later restore them in triggerpostun. +# https://bugzilla.redhat.com/show_bug.cgi?id=735259 + +# Back up the files before uninstalling old grub2 +mkdir -p /boot/grub2.tmp && +mv -f /boot/grub2/*.mod \ + /boot/grub2/*.img \ + /boot/grub2/*.lst \ + /boot/grub2/device.map \ + /boot/grub2.tmp/ || : + +%triggerpostun -- grub2 < 1:1.99-4 +# ... and restore the files. +test ! -f /boot/grub2/device.map && +test -d /boot/grub2.tmp && +mv -f /boot/grub2.tmp/*.mod \ + /boot/grub2.tmp/*.img \ + /boot/grub2.tmp/*.lst \ + /boot/grub2.tmp/device.map \ + /boot/grub2/ && +rm -r /boot/grub2.tmp/ || : + +%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 + cp -a ${EFI_HOME}/grub.cfg ${EFI_HOME}/grub.cfg.rpmsave + cp -a ${EFI_HOME}/grub.cfg ${GRUB_HOME}/ +fi + +if (((grep -q "configfile" ${EFI_HOME}/grub.cfg && grep -q "root-dev-only" ${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 +if test ! -f ${GRUB_HOME}/grub.cfg; then + cp -a ${EFI_HOME}/grub.cfg ${GRUB_HOME}/ +fi +mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg + +%files + +%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 +%{_sysconfdir}/prelink.conf.d/grub2.conf +%{_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 +%{_userunitdir}/timers.target.wants +%{_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-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 +%exclude %{_sbindir}/grub2-sparc64-setup +%exclude %{_datadir}/man/man8/grub2-sparc64-setup* +%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 +%{_bindir}/grub2-mkrescue +%{_datadir}/man/man1/grub2-mkrescue* +%{_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} %%{efiarch}} +%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} %%{alt_efi_arch}} +%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 +@CHANGELOG@ 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/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/include/grub/compiler.h b/include/grub/compiler.h index 0c5519387b..441a9eca07 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/dl.h b/include/grub/dl.h index cd1f46c8ba..02870b996c 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -27,6 +27,7 @@ #include #include #include +#include #endif /* @@ -119,7 +120,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 @@ -174,7 +175,7 @@ typedef struct grub_dl_dep *grub_dl_dep_t; struct grub_dl { char *name; - int ref_count; + grub_uint64_t ref_count; int persistent; grub_dl_dep_t dep; grub_dl_segment_t segment; @@ -203,9 +204,9 @@ 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 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); +extern grub_uint64_t EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); +extern grub_uint64_t EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); +extern grub_uint64_t EXPORT_FUNC(grub_dl_ref_count) (grub_dl_t mod); extern grub_dl_t EXPORT_VAR(grub_dl_head); @@ -254,6 +255,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 grub_err_t grub_dl_register_symbol (const char *name, void *addr, @@ -264,6 +308,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/include/grub/efi/api.h b/include/grub/efi/api.h index d44d00ad7d..c7b66604b5 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -369,6 +369,16 @@ { 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 } \ + } + #define LINUX_EFI_INITRD_MEDIA_GUID \ { 0x5568e427, 0x68fc, 0x4f3d, \ { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ @@ -379,6 +389,11 @@ {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \ } +#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; @@ -637,12 +652,35 @@ 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; +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; /* XXX although the spec does not specify the padding, this actually must have the padding! */ @@ -876,6 +914,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; @@ -890,6 +930,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; @@ -939,6 +981,24 @@ struct grub_efi_vlan_device_path } GRUB_PACKED; typedef struct grub_efi_vlan_device_path grub_efi_vlan_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_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. */ @@ -1021,6 +1081,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_api *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_api *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; @@ -1521,33 +1598,178 @@ 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; + +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 grub_efi_uint16_t grub_efi_pxe_base_code_udp_port_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_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 +{ + 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_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_BASE_CODE_MAX_ARP_ENTRIES]; + grub_efi_uint32_t route_table_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; typedef struct grub_efi_pxe { grub_uint64_t rev; - void *start; - void *stop; - void *dhcp; - void *discover; - void *mftp; - void *udpwrite; - void *udpread; - void *setipfilter; - void *arp; - void *setparams; - void *setstationip; - void *setpackets; + grub_efi_status_t (__grub_efi_api *start) (struct grub_efi_pxe *this, grub_efi_boolean_t use_ipv6); + void (*stop) (void); + grub_efi_status_t (__grub_efi_api *dhcp) (struct grub_efi_pxe *this, + grub_efi_boolean_t sort_offers); + void (*discover) (void); + grub_efi_status_t (__grub_efi_api *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); + grub_efi_status_t (__grub_efi_api *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 (*setpackets) (void); struct grub_efi_pxe_mode *mode; } grub_efi_pxe_t; @@ -1809,6 +2031,173 @@ struct grub_efi_load_file2 }; typedef struct grub_efi_load_file2 grub_efi_load_file2_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 (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *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; + +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, + 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 (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *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; + +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; + +struct grub_efi_memory_attribute_protocol +{ + grub_efi_status_t (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *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; + struct initrd_media_device_path { grub_efi_vendor_media_device_path_t vendor; grub_efi_device_path_t end; diff --git a/include/grub/efi/dhcp.h b/include/grub/efi/dhcp.h new file mode 100644 index 0000000000..d996716e40 --- /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 (__grub_efi_api *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 (__grub_efi_api *get_mode_data) (grub_efi_dhcp4_protocol_t *this, + grub_efi_dhcp4_mode_data_t *dhcp4_mode_data); + grub_efi_status_t (__grub_efi_api *configure) (grub_efi_dhcp4_protocol_t *this, + grub_efi_dhcp4_config_data_t *dhcp4_cfg_data); + grub_efi_status_t (__grub_efi_api *start) (grub_efi_dhcp4_protocol_t *this, + grub_efi_event_t completion_event); + grub_efi_status_t (__grub_efi_api *renew_rebind) (grub_efi_dhcp4_protocol_t *this, + grub_efi_boolean_t rebind_request, + grub_efi_event_t completion_event); + grub_efi_status_t (__grub_efi_api *release) (grub_efi_dhcp4_protocol_t *this); + grub_efi_status_t (__grub_efi_api *stop) (grub_efi_dhcp4_protocol_t *this); + grub_efi_status_t (__grub_efi_api *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 (__grub_efi_api *transmit_receive) (grub_efi_dhcp4_protocol_t *this, + grub_efi_dhcp4_transmit_receive_token_t *token); + grub_efi_status_t (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *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 (__grub_efi_api *configure) (grub_efi_dhcp6_protocol_t *this, + grub_efi_dhcp6_config_data_t *dhcp6_cfg_data); + grub_efi_status_t (__grub_efi_api *start) (grub_efi_dhcp6_protocol_t *this); + grub_efi_status_t (__grub_efi_api *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 (__grub_efi_api *reply_callback) (grub_efi_dhcp6_protocol_t *this, + void *context, + grub_efi_dhcp6_packet_t *packet), + void *callback_context); + grub_efi_status_t (__grub_efi_api *renew_rebind) (grub_efi_dhcp6_protocol_t *this, + grub_efi_boolean_t rebind_request); + grub_efi_status_t (__grub_efi_api *decline) (grub_efi_dhcp6_protocol_t *this, + grub_efi_uint32_t address_count, + grub_efi_ipv6_address_t *addresses); + grub_efi_status_t (__grub_efi_api *release) (grub_efi_dhcp6_protocol_t *this, + grub_efi_uint32_t address_count, + grub_efi_ipv6_address_t *addresses); + grub_efi_status_t (__grub_efi_api *stop) (grub_efi_dhcp6_protocol_t *this); + grub_efi_status_t (__grub_efi_api *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/edid.h b/include/grub/efi/edid.h index 43c0c4372f..ac1b8e2fda 100644 --- a/include/grub/efi/edid.h +++ b/include/grub/efi/edid.h @@ -33,7 +33,7 @@ struct grub_efi_edid_override; typedef grub_efi_status_t -(*grub_efi_edid_override_get_edid) (struct grub_efi_edid_override *this, +(__grub_efi_api *grub_efi_edid_override_get_edid) (struct grub_efi_edid_override *this, grub_efi_handle_t *childhandle, grub_efi_uint32_t *attributes, grub_efi_uintn_t *edidsize, diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index a5cd99e5af..a63c5367a2 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -36,6 +36,11 @@ struct linux_arch_kernel_header { struct grub_pe_image_header pe_image_header; }; +#define GRUB_EFI_GRUB_VARIABLE_GUID \ + { 0x91376aff, 0xcba6, 0x42be, \ + { 0x94, 0x9d, 0x06, 0xfd, 0xe8, 0x11, 0x28, 0xe8 } \ + } + /* Functions. */ void *EXPORT_FUNC(grub_efi_locate_protocol) (grub_guid_t *protocol, void *registration); @@ -151,4 +156,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/efi/http.h b/include/grub/efi/http.h new file mode 100644 index 0000000000..242d001b62 --- /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_uintn_t header_count; + grub_efi_http_header_t *headers; + grub_efi_uintn_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 + (__grub_efi_api *get_mode_data) (struct grub_efi_http *this, + grub_efi_http_config_data_t *http_config_data); + + grub_efi_status_t + (__grub_efi_api *configure) (struct grub_efi_http *this, + grub_efi_http_config_data_t *http_config_data); + + grub_efi_status_t + (__grub_efi_api *request) (struct grub_efi_http *this, + grub_efi_http_token_t *token); + + grub_efi_status_t + (__grub_efi_api *cancel) (struct grub_efi_http *this, + grub_efi_http_token_t *token); + + grub_efi_status_t + (__grub_efi_api *response) (struct grub_efi_http *this, + grub_efi_http_token_t *token); + + grub_efi_status_t + (__grub_efi_api *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/efi/pci.h b/include/grub/efi/pci.h index b17245549f..a90f610422 100644 --- a/include/grub/efi/pci.h +++ b/include/grub/efi/pci.h @@ -48,7 +48,7 @@ typedef enum struct grub_efi_pci_io; typedef grub_efi_status_t -(*grub_efi_pci_io_mem_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_mem_t) (struct grub_efi_pci_io *this, grub_efi_pci_io_width_t width, grub_efi_uint8_t bar_index, grub_efi_uint64_t offset, @@ -56,7 +56,7 @@ typedef grub_efi_status_t void *buffer); typedef grub_efi_status_t -(*grub_efi_pci_io_config_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_config_t) (struct grub_efi_pci_io *this, grub_efi_pci_io_width_t width, grub_efi_uint32_t offset, grub_efi_uintn_t count, @@ -113,7 +113,7 @@ typedef enum grub_efi_pci_io_attribute_operation_t; typedef grub_efi_status_t -(*grub_efi_pci_io_poll_io_mem_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_poll_io_mem_t) (struct grub_efi_pci_io *this, grub_efi_pci_io_width_t width, grub_efi_uint8_t bar_ndex, grub_efi_uint64_t offset, @@ -123,7 +123,7 @@ typedef grub_efi_status_t grub_efi_uint64_t *result); typedef grub_efi_status_t -(*grub_efi_pci_io_copy_mem_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_copy_mem_t) (struct grub_efi_pci_io *this, grub_efi_pci_io_width_t width, grub_efi_uint8_t dest_bar_index, grub_efi_uint64_t dest_offset, @@ -132,7 +132,7 @@ typedef grub_efi_status_t grub_efi_uintn_t count); typedef grub_efi_status_t -(*grub_efi_pci_io_map_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_map_t) (struct grub_efi_pci_io *this, grub_efi_pci_io_operation_t operation, void *host_address, grub_efi_uintn_t *number_of_bytes, @@ -140,11 +140,11 @@ typedef grub_efi_status_t void **mapping); typedef grub_efi_status_t -(*grub_efi_pci_io_unmap_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_unmap_t) (struct grub_efi_pci_io *this, void *mapping); typedef grub_efi_status_t -(*grub_efi_pci_io_allocate_buffer_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_allocate_buffer_t) (struct grub_efi_pci_io *this, grub_efi_allocate_type_t type, grub_efi_memory_type_t memory_type, grub_efi_uintn_t pages, @@ -152,7 +152,7 @@ typedef grub_efi_status_t grub_efi_uint64_t attributes); typedef grub_efi_status_t -(*grub_efi_pci_io_free_buffer_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_free_buffer_t) (struct grub_efi_pci_io *this, grub_efi_allocate_type_t type, grub_efi_memory_type_t memory_type, grub_efi_uintn_t pages, @@ -160,29 +160,29 @@ typedef grub_efi_status_t grub_efi_uint64_t attributes); typedef grub_efi_status_t -(*grub_efi_pci_io_flush_t) (struct grub_efi_pci_io *this); +(__grub_efi_api *grub_efi_pci_io_flush_t) (struct grub_efi_pci_io *this); typedef grub_efi_status_t -(*grub_efi_pci_io_get_location_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_get_location_t) (struct grub_efi_pci_io *this, grub_efi_uintn_t *segment_number, grub_efi_uintn_t *bus_number, grub_efi_uintn_t *device_number, grub_efi_uintn_t *function_number); typedef grub_efi_status_t -(*grub_efi_pci_io_attributes_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_attributes_t) (struct grub_efi_pci_io *this, grub_efi_pci_io_attribute_operation_t operation, grub_efi_uint64_t attributes, grub_efi_uint64_t *result); typedef grub_efi_status_t -(*grub_efi_pci_io_get_bar_attributes_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_get_bar_attributes_t) (struct grub_efi_pci_io *this, grub_efi_uint8_t bar_index, grub_efi_uint64_t *supports, void **resources); typedef grub_efi_status_t -(*grub_efi_pci_io_set_bar_attributes_t) (struct grub_efi_pci_io *this, +(__grub_efi_api *grub_efi_pci_io_set_bar_attributes_t) (struct grub_efi_pci_io *this, grub_efi_uint64_t attributes, grub_efi_uint8_t bar_index, grub_efi_uint64_t *offset, @@ -212,12 +212,12 @@ struct grub_efi_pci_root_io; typedef struct { - grub_efi_status_t(*read) (struct grub_efi_pci_root_io *this, + grub_efi_status_t(__grub_efi_api *read) (struct grub_efi_pci_root_io *this, grub_efi_pci_io_width_t width, grub_efi_uint64_t address, grub_efi_uintn_t count, void *buffer); - grub_efi_status_t(*write) (struct grub_efi_pci_root_io *this, + grub_efi_status_t(__grub_efi_api *write) (struct grub_efi_pci_root_io *this, grub_efi_pci_io_width_t width, grub_efi_uint64_t address, grub_efi_uintn_t count, @@ -237,7 +237,7 @@ typedef enum grub_efi_pci_root_io_operation_t; typedef grub_efi_status_t -(*grub_efi_pci_root_io_poll_io_mem_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_poll_io_mem_t) (struct grub_efi_pci_root_io *this, grub_efi_pci_io_width_t width, grub_efi_uint64_t address, grub_efi_uint64_t mask, @@ -246,7 +246,7 @@ typedef grub_efi_status_t grub_efi_uint64_t *result); typedef grub_efi_status_t -(*grub_efi_pci_root_io_copy_mem_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_copy_mem_t) (struct grub_efi_pci_root_io *this, grub_efi_pci_io_width_t width, grub_efi_uint64_t dest_offset, grub_efi_uint64_t src_offset, @@ -254,7 +254,7 @@ typedef grub_efi_status_t typedef grub_efi_status_t -(*grub_efi_pci_root_io_map_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_map_t) (struct grub_efi_pci_root_io *this, grub_efi_pci_root_io_operation_t operation, void *host_address, grub_efi_uintn_t *number_of_bytes, @@ -262,11 +262,11 @@ typedef grub_efi_status_t void **mapping); typedef grub_efi_status_t -(*grub_efi_pci_root_io_unmap_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_unmap_t) (struct grub_efi_pci_root_io *this, void *mapping); typedef grub_efi_status_t -(*grub_efi_pci_root_io_allocate_buffer_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_allocate_buffer_t) (struct grub_efi_pci_root_io *this, grub_efi_allocate_type_t type, grub_efi_memory_type_t memory_type, grub_efi_uintn_t pages, @@ -274,26 +274,26 @@ typedef grub_efi_status_t grub_efi_uint64_t attributes); typedef grub_efi_status_t -(*grub_efi_pci_root_io_free_buffer_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_free_buffer_t) (struct grub_efi_pci_root_io *this, grub_efi_uintn_t pages, void **host_address); typedef grub_efi_status_t -(*grub_efi_pci_root_io_flush_t) (struct grub_efi_pci_root_io *this); +(__grub_efi_api *grub_efi_pci_root_io_flush_t) (struct grub_efi_pci_root_io *this); typedef grub_efi_status_t -(*grub_efi_pci_root_io_get_attributes_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_get_attributes_t) (struct grub_efi_pci_root_io *this, grub_efi_uint64_t *supports, void **resources); typedef grub_efi_status_t -(*grub_efi_pci_root_io_set_attributes_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_set_attributes_t) (struct grub_efi_pci_root_io *this, grub_efi_uint64_t attributes, grub_efi_uint64_t *offset, grub_efi_uint64_t *length); typedef grub_efi_status_t -(*grub_efi_pci_root_io_configuration_t) (struct grub_efi_pci_root_io *this, +(__grub_efi_api *grub_efi_pci_root_io_configuration_t) (struct grub_efi_pci_root_io *this, void **resources); struct grub_efi_pci_root_io { diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index 4e6e9d254b..9887e14b27 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -231,6 +231,8 @@ struct grub_pe64_optional_header #define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION 10 +#define GRUB_PE32_NX_COMPAT 0x0100 + #define GRUB_PE32_NUM_DATA_DIRECTORIES 16 struct grub_pe32_section_table 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/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/include/grub/err.h b/include/grub/err.h index 1c07034cd6..202fa8a7ae 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -73,7 +73,9 @@ typedef enum GRUB_ERR_NET_NO_DOMAIN, GRUB_ERR_EOF, GRUB_ERR_BAD_SIGNATURE, - GRUB_ERR_BAD_FIRMWARE + GRUB_ERR_BAD_FIRMWARE, + GRUB_ERR_STILL_REFERENCED, + GRUB_ERR_RECURSION_DEPTH } grub_err_t; diff --git a/include/grub/fs.h b/include/grub/fs.h index 026bc3bb86..df4c93b16f 100644 --- a/include/grub/fs.h +++ b/include/grub/fs.h @@ -23,6 +23,7 @@ #include #include #include +#include #include /* For embedding types. */ @@ -57,6 +58,9 @@ struct grub_fs /* My name. */ const char *name; + /* My module */ + grub_dl_t mod; + /* Call HOOK with each file under DIR. */ grub_err_t (*fs_dir) (grub_device_t device, const char *path, grub_fs_dir_hook_t hook, void *hook_data); 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/include/grub/ia64/linux.h b/include/grub/ia64/linux.h new file mode 100644 index 0000000000..e69de29bb2 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/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/include/grub/mips/linux.h b/include/grub/mips/linux.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/include/grub/misc.h b/include/grub/misc.h index 1b35a167fd..0407ac8d8b 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); @@ -64,6 +72,45 @@ grub_stpcpy (char *dest, const char *src) return d - 1; } +static inline grub_size_t +grub_strlcpy (char *dest, const char *src, grub_size_t size) +{ + char *d = dest; + grub_size_t res = 0; + /* + * We do not subtract one from size here to avoid dealing with underflowing + * the value, which is why to_copy is always checked to be greater than one + * throughout this function. + */ + grub_size_t to_copy = size; + + /* Copy size - 1 bytes to dest. */ + if (to_copy > 1) + while ((*d++ = *src++) != '\0' && ++res && --to_copy > 1) + ; + + /* + * NUL terminate if size != 0. The previous step may have copied a NUL byte + * if it reached the end of the string, but we know dest[size - 1] must always + * be a NUL byte. + */ + if (size != 0) + dest[size - 1] = '\0'; + + /* If there is still space in dest, but are here, we reached the end of src. */ + if (to_copy > 1) + return res; + + /* + * If we haven't reached the end of the string, iterate through to determine + * the strings total length. + */ + while (*src++ != '\0' && ++res) + ; + + return res; +} + /* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */ static inline void * grub_memcpy (void *dest, const void *src, grub_size_t n) @@ -335,6 +382,7 @@ char *EXPORT_FUNC(grub_strdup) (const char *s) WARN_UNUSED_RESULT; char *EXPORT_FUNC(grub_strndup) (const char *s, grub_size_t n) WARN_UNUSED_RESULT; 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; +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'. */ @@ -369,6 +417,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, @@ -524,8 +573,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/include/grub/mm.h b/include/grub/mm.h index f3bf87fa0f..8ee1fc7171 100644 --- a/include/grub/mm.h +++ b/include/grub/mm.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #ifndef NULL @@ -56,6 +57,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/include/grub/mm_private.h b/include/grub/mm_private.h index 96c2d816be..2481ee1fa2 100644 --- a/include/grub/mm_private.h +++ b/include/grub/mm_private.h @@ -20,7 +20,6 @@ #define GRUB_MM_PRIVATE_H 1 #include -#include /* For context, see kern/mm.c */ @@ -99,17 +98,4 @@ 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/include/grub/net.h b/include/grub/net.h index 844e501c12..ce3000f3b4 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -450,6 +450,66 @@ struct grub_net_bootp_packet grub_uint8_t vendor[0]; } GRUB_PACKED; +struct grub_net_dhcp6_packet +{ + grub_uint32_t message_type:8; + grub_uint32_t transaction_id:24; + grub_uint8_t dhcp_options[0]; +} GRUB_PACKED; + +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 data[0]; +} GRUB_PACKED; + +struct grub_net_dhcp6_option_iaaddr { + grub_uint8_t addr[16]; + grub_uint32_t preferred_lifetime; + grub_uint32_t valid_lifetime; + grub_uint8_t data[0]; +} GRUB_PACKED; + +struct grub_net_dhcp6_option_duid_ll +{ + grub_uint16_t type; + grub_uint16_t hw_type; + grub_uint8_t hwaddr[6]; +} GRUB_PACKED; + +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 #define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53 @@ -470,6 +530,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, @@ -485,6 +546,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_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); + +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); @@ -493,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); @@ -540,16 +620,7 @@ void grub_bootp_fini (void); void grub_dns_init (void); void grub_dns_fini (void); -static inline void -grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter) -{ - inter->card->num_ifaces--; - *inter->prev = inter->next; - if (inter->next) - inter->next->prev = inter->prev; - inter->next = 0; - inter->prev = 0; -} +void grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter); void grub_net_tcp_retransmit (void); @@ -579,7 +650,7 @@ void grub_net_remove_dns_server (const struct grub_net_network_level_address *s); grub_err_t -grub_net_search_config_file (char *config); +grub_net_search_config_file (char *config, grub_size_t config_buf_len); extern char *grub_net_default_server; 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/include/grub/ntfs.h b/include/grub/ntfs.h index d1a6af6967..2c80784039 100644 --- a/include/grub/ntfs.h +++ b/include/grub/ntfs.h @@ -89,6 +89,8 @@ enum #define GRUB_NTFS_COM_SEC (GRUB_NTFS_COM_LEN >> GRUB_NTFS_BLK_SHR) #define GRUB_NTFS_LOG_COM_SEC (GRUB_NTFS_COM_LOG_LEN - GRUB_NTFS_BLK_SHR) +#define GRUB_NTFS_ATTRIBUTE_HEADER_SIZE 16 + enum { GRUB_NTFS_AF_ALST = 1, @@ -134,6 +136,7 @@ struct grub_ntfs_attr grub_uint8_t *attr_cur, *attr_nxt, *attr_end; grub_uint32_t save_pos; grub_uint8_t *sbuf; + grub_uint8_t *end; struct grub_ntfs_file *mft; }; 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/search.h b/include/grub/search.h index ffd2411ca1..9343c66b13 100644 --- a/include/grub/search.h +++ b/include/grub/search.h @@ -23,7 +23,8 @@ enum search_flags { SEARCH_FLAGS_NONE = 0, 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/include/grub/sparc64/linux.h b/include/grub/sparc64/linux.h new file mode 100644 index 0000000000..e69de29bb2 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/rel b/rel new file mode 100644 index 0000000000..d00491fd7e --- /dev/null +++ b/rel @@ -0,0 +1 @@ +1 diff --git a/sbat.csv.in b/sbat.csv.in new file mode 100755 index 0000000000..ea697f51ab --- /dev/null +++ b/sbat.csv.in @@ -0,0 +1,3 @@ +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +grub,1,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/ +grub.fedora,1,The Fedora Project,grub2,@@VERSION_RELEASE@@,https://src.fedoraproject.org/rpms/grub2 diff --git a/strtoull_test.c b/strtoull_test.c new file mode 100644 index 0000000000..5488ab26b4 --- /dev/null +++ b/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) +{ + const 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/tests/grub_cmd_cryptomount.in b/tests/grub_cmd_cryptomount.in index 4578ab7093..f4d8f35473 100644 --- a/tests/grub_cmd_cryptomount.in +++ b/tests/grub_cmd_cryptomount.in @@ -173,7 +173,7 @@ eval testcase_fail "'LUKS2 test with argon2 pbkdf:'" \ # Add good password to second slot and change first slot to unchecked password csscript=`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"` || exit 99 cat >$csscript <<'EOF' - CSOPTS="--pbkdf-force-iterations 1000 --pbkdf=pbkdf2" + CSOPTS="--pbkdf-force-iterations 1000 --pbkdf=pbkdf2 --force-password" cryptsetup $CSOPTS --key-file $lukskeyfile luksAddKey $luksdiskfile $lukskeyfile echo "newpass" | cryptsetup $CSOPTS --key-file $lukskeyfile --key-slot 0 luksChangeKey $luksdiskfile EOF diff --git a/tests/grub_script_eval.in b/tests/grub_script_eval.in index c97b78d77f..9c62110424 100644 --- a/tests/grub_script_eval.in +++ b/tests/grub_script_eval.in @@ -3,4 +3,12 @@ eval echo "Hello world" valname=tst eval $valname=hi -echo $tst \ No newline at end of file +echo $tst + +if eval " +false +"; then + echo should have failed +else + echo failed as expected +fi 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 496e1bab33..e0570c88e1 100644 --- a/tests/util/grub-shell.in +++ b/tests/util/grub-shell.in @@ -243,7 +243,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/theme.tar.bz2 b/theme.tar.bz2 new file mode 100644 index 0000000000..c1035b08fe Binary files /dev/null and b/theme.tar.bz2 differ diff --git a/unifont-5.1.20080820.pcf.gz b/unifont-5.1.20080820.pcf.gz new file mode 100644 index 0000000000..2b1ce37cff Binary files /dev/null and b/unifont-5.1.20080820.pcf.gz differ 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/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/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in index 213ce1e57c..da7fca5efa 100644 --- a/util/bash-completion.d/grub-completion.bash.in +++ b/util/bash-completion.d/grub-completion.bash.in @@ -275,6 +275,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/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-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/util/grub-fstest.c b/util/grub-fstest.c index 25ae52ab6f..982ce9ed7d 100644 --- a/util/grub-fstest.c +++ b/util/grub-fstest.c @@ -329,7 +329,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-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-install-common.c b/util/grub-install-common.c index ce854d86f8..847e888f32 100644 --- a/util/grub-install-common.c +++ b/util/grub-install-common.c @@ -368,7 +368,7 @@ char *grub_install_themes_directory = NULL; int grub_install_is_short_mbrgap_supported (void) { - int i, j; + unsigned int i, j; static const char *whitelist[] = { "part_msdos", "biosdisk", "affs", "afs", "bfs", "archelp", diff --git a/util/grub-install.c b/util/grub-install.c index 7dc5657bb6..fea4cafd95 100644 --- a/util/grub-install.c +++ b/util/grub-install.c @@ -843,6 +843,8 @@ try_open (const char *path) } #endif +extern int use_relative_path_on_btrfs; + int main (int argc, char *argv[]) { @@ -876,6 +878,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; @@ -1026,27 +1031,22 @@ main (int argc, char *argv[]) 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_I386_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: case GRUB_INSTALL_PLATFORM_RISCV32_EFI: case GRUB_INSTALL_PLATFORM_RISCV64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_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; - } - - switch (platform) - { case GRUB_INSTALL_PLATFORM_I386_IEEE1275: case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: #ifdef __linux__ @@ -1055,12 +1055,14 @@ main (int argc, char *argv[]) try_open ("/dev/nvram"); #endif break; + /* pacify warning. */ + case GRUB_INSTALL_PLATFORM_MAX: + break; default: break; } /* Find the EFI System Partition. */ - if (is_efi) { grub_fs_t fs; @@ -1366,6 +1368,15 @@ main (int argc, char *argv[]) relative_grubdir = xstrdup ("/"); } + 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; @@ -1601,6 +1612,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/util/grub-menulst2cfg.c b/util/grub-menulst2cfg.c index b80e15cc36..1ea2a86e12 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-mkconfig.in b/util/grub-mkconfig.in index 32c480daeb..592d99338c 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@" @@ -161,6 +162,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" @@ -255,7 +258,8 @@ export GRUB_DEFAULT \ GRUB_ENABLE_CRYPTODISK \ GRUB_BADRAM \ GRUB_OS_PROBER_SKIP_LIST \ - GRUB_DISABLE_SUBMENU + GRUB_DISABLE_SUBMENU \ + SUSE_BTRFS_SNAPSHOT_BOOTING if test "x${grub_cfg}" != "x"; then rm -f "${grub_cfg}.new" @@ -282,6 +286,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-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 33e1750aeb..0ba0e0e1c6 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-mkfont.c b/util/grub-mkfont.c index 7624d7808b..e8a914021b 100644 --- a/util/grub-mkfont.c +++ b/util/grub-mkfont.c @@ -143,7 +143,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; @@ -188,7 +189,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] @@ -208,10 +209,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] @@ -230,7 +231,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; } @@ -267,7 +268,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-mknetdir.c b/util/grub-mknetdir.c index 46f304c2b4..11c9db1177 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; @@ -157,6 +162,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); @@ -196,7 +202,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/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/util/grub-mount.c b/util/grub-mount.c index bf4c8b891b..d369e21666 100644 --- a/util/grub-mount.c +++ b/util/grub-mount.c @@ -269,11 +269,17 @@ fuse_read (const char *path, char *buf, size_t sz, off_t off, { grub_file_t file = files[fi->fh]; grub_ssize_t size; + grub_off_t offset; - if (off > file->size) + if (off < 0) return -EINVAL; - file->offset = off; + if ((grub_off_t)off > file->size) + return -EINVAL; + + offset = (grub_off_t)off; + + file->offset = offset; size = grub_file_read (file, buf, sz); if (size < 0) diff --git a/util/grub-probe.c b/util/grub-probe.c index 65c1ca3f8b..08ae915e8d 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -799,7 +799,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/grub-set-bootflag.c b/util/grub-set-bootflag.c new file mode 100644 index 0000000000..31a868aeca --- /dev/null +++ b/util/grub-set-bootflag.c @@ -0,0 +1,319 @@ +/* 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 (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. + */ + +#include /* For *_DIR_NAME defines */ +#include +#include +#include /* For GRUB_ENVBLK_DEFCFG define */ +#include +#include +#include +#include +#include +#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 + 2], buf[64], *s; + /* +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; + + umask(077); + + 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); + + /* + * 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. + */ + if (setegid(0)) + { + perror ("setegid(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"); + 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; + /* 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))) + { + 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); + if (!memcmp(s, buf, len + 3)) + 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), "%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) + { + 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 tmpfile"); + unlink(tmp_filename); + return 1; + } + + ret = fflush (f); + if (ret) + { + perror ("Error flushing tmpfile"); + unlink(tmp_filename); + 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) + { + perror ("Error syncing 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). + */ + 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/util/grub-set-password.in b/util/grub-set-password.in new file mode 100644 index 0000000000..d8005e5a14 --- /dev/null +++ b/util/grub-set-password.in @@ -0,0 +1,121 @@ +#!/bin/sh -e + +grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'` + +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 + +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/00_header.in b/util/grub.d/00_header.in index 6a316a5ba7..3e1b77265d 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 <&2 echo >&2 exit 1 @@ -210,7 +217,7 @@ EOF $host_ports \\ --exec-server-task='\${exec-task}' -T typed '\${root}' \\ '\$(fs-task=task-create)' $resume_task - module /lib/ld.so.1 exec /hurd/exec '\$(exec-task=task-create)' + module $LD_SO exec /hurd/exec '\$(exec-task=task-create)' } EOF diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index cc393be7ed..dd5addd3c1 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -26,12 +26,13 @@ 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=GNU/Linux + 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} 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 @@ -67,10 +68,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` @@ -79,6 +84,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 () @@ -86,23 +117,21 @@ 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}")" 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 + 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 @@ -284,11 +313,15 @@ for linux in ${reverse_sorted_list}; 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 @@ -297,10 +330,15 @@ for linux in ${reverse_sorted_list}; 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 \ "${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}" fi done 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..e73f4137b3 --- /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 +# 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 +if [ "\${boot_success}" = "1" ] ; then + set boot_indeterminate=0 +# 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 +save_env boot_success boot_indeterminate +EOF diff --git a/util/grub.d/12_menu_auto_hide.in b/util/grub.d/12_menu_auto_hide.in new file mode 100644 index 0000000000..6a7c0fa0d4 --- /dev/null +++ b/util/grub.d/12_menu_auto_hide.in @@ -0,0 +1,35 @@ +#! /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 + serial*) + exit 0 + ;; + esac +done + +cat << EOF +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 "\${menu_hide_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/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/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in index 94dd8be134..4ecf5deea1 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 @@ -75,10 +75,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` @@ -152,6 +156,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} @@ -164,6 +169,7 @@ EOF initrd_path="${rel_dirname}/${i}" sed "s/^/$submenu_indentation/" << EOF echo '$(echo "$message" | grub_quote)' + insmod ${xen_module} ${module_loader} --nounzip $(echo $initrd_path) EOF done @@ -265,13 +271,16 @@ for current_xen in ${reverse_sorted_xen_list}; 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/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 656301eaf2..13db23dd23 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -27,7 +27,6 @@ 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.")" exit 0 fi @@ -45,68 +44,26 @@ 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 + found_other_os=1 # 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 } @@ -152,6 +109,7 @@ for OS in ${OSPROBED} ; do case ${BOOT} in chain) + found_other_os=1 onstr="$(gettext_printf "(on %s)" "${DEVICE}")" cat << EOF @@ -182,6 +140,7 @@ EOF EOF ;; efi) + found_other_os=1 EFIPATH=${DEVICE#*@} DEVICE=${DEVICE%@*} @@ -226,6 +185,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 @@ -299,13 +259,15 @@ 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) + 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}")' { @@ -332,6 +294,7 @@ EOF EOF ;; minix) + found_other_os=1 cat << EOF menuentry "${LONGNAME} (on ${DEVICE}, Multiboot)" { EOF @@ -348,3 +311,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/util/misc.c b/util/misc.c index d545212d90..0f928e5b49 100644 --- a/util/misc.c +++ b/util/misc.c @@ -190,14 +190,14 @@ grub_xputs_real (const char *str) void (*grub_xputs) (const char *str) = grub_xputs_real; -int +grub_uint64_t grub_dl_ref (grub_dl_t mod) { (void) mod; return 0; } -int +grub_uint64_t grub_dl_unref (grub_dl_t mod) { (void) mod; diff --git a/util/mkimage.c b/util/mkimage.c index 4237383aca..9b4720e21b 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -1403,6 +1403,7 @@ grub_install_generate_image (const char *dir, const char *prefix, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdangling-pointer" #endif + 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/util/setup.c b/util/setup.c index 87a889ff7e..7aab468b0e 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/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..a4c071c5b0 --- /dev/null +++ b/util/systemd/systemd-integration.sh.in @@ -0,0 +1,11 @@ +#!/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 + +# 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/version b/version new file mode 100644 index 0000000000..3e162f02ea --- /dev/null +++ b/version @@ -0,0 +1 @@ +2.12