From f6e2734f7d8d91b901a819351bc34f840c80606f Mon Sep 17 00:00:00 2001 From: "zhangyongde.zyd" Date: Mon, 22 Jan 2024 11:05:29 +0800 Subject: [PATCH] change the repo patch deploy ways update README.md. Signed-off-by: ydjohn --- 0001-kpatch-don-t-need-vmlinux.patch | 79 + ...-some-subfunction-.cold-change-error.patch | 23 + ...tch-get-gcc-version-from-config-file.patch | 52 + ...get-kernel-version-from-kpatch-build.patch | 39 + 0005-kpatch-build-use-new-klp-arch.patch | 54 + ...k-klp_register_patch-function-symbol.patch | 40 + 0007-kpatch-build-set-EXTRAVERSION.patch | 26 + ...options-for-kpatch-module-build-mode.patch | 48 + 0009-kpatch-build-add-DISTRO-anolis.patch | 39 + COPYING | 339 -- Makefile | 95 - Makefile.inc | 21 - README.md | 2 +- contrib/Makefile | 17 - contrib/kpatch.conf | 29 - contrib/kpatch.service | 13 - contrib/kpatch.spec | 320 -- examples/proc-version.patch | 29 - ...-better-follow-cubic-curve-converted.patch | 105 - ...c-better-follow-cubic-curve-original.patch | 58 - kmod/Makefile | 28 - kmod/core/Makefile | 24 - kmod/core/core.c | 1334 ----- kmod/core/kpatch.h | 102 - kmod/core/shadow.c | 175 - kmod/patch/Makefile | 26 - kmod/patch/kpatch-macros.h | 144 - kmod/patch/kpatch-patch-hook.c | 424 -- kmod/patch/kpatch-patch.h | 63 - kmod/patch/kpatch-syscall.h | 207 - kmod/patch/kpatch.h | 1 - kmod/patch/kpatch.lds.S | 50 - kmod/patch/livepatch-patch-hook.c | 607 --- kmod/patch/patch-hook.c | 25 - kpatch-build/Makefile | 52 - kpatch-build/create-diff-object.c | 4362 ----------------- kpatch-build/create-klp-module.c | 513 -- kpatch-build/create-kpatch-module.c | 265 - kpatch-build/gcc-plugins/gcc-common.h | 969 ---- .../gcc-plugins/gcc-generate-rtl-pass.h | 176 - kpatch-build/gcc-plugins/ppc64le-plugin.c | 97 - kpatch-build/insn/asm/inat.h | 221 - kpatch-build/insn/asm/inat_types.h | 29 - kpatch-build/insn/asm/insn.h | 199 - kpatch-build/insn/inat-tables.c | 1146 ----- kpatch-build/insn/inat.c | 97 - kpatch-build/insn/insn.c | 582 --- kpatch-build/kpatch-build | 1466 ------ kpatch-build/kpatch-cc | 92 - kpatch-build/kpatch-elf.c | 1069 ---- kpatch-build/kpatch-elf.h | 191 - kpatch-build/kpatch-intermediate.h | 48 - kpatch-build/kpatch.h | 11 - kpatch-build/list.h | 221 - kpatch-build/log.h | 27 - kpatch-build/lookup.c | 561 --- kpatch-build/lookup.h | 23 - kpatch.spec | 121 + kpatch/Makefile | 12 - kpatch/kpatch | 649 --- man/Makefile | 22 - man/kpatch-build.1 | 83 - man/kpatch.1 | 56 - test/difftree.sh | 93 - test/integration/.gitignore | 2 - test/integration/Makefile | 51 - test/integration/centos-7 | 1 - test/integration/centos-8 | 1 - test/integration/common/multiple.template | 80 - test/integration/fedora-27/README | 1 - .../fedora-27/data-new-LOADED.test | 3 - test/integration/fedora-27/data-new.patch | 20 - .../fedora-27/gcc-static-local-var-6.patch | 23 - .../fedora-27/macro-callbacks.patch | 163 - ...-cmdline-rebuild-SLOW-LOADED.test.disabled | 3 - ...eminfo-cmdline-rebuild-SLOW.patch.disabled | 40 - .../fedora-27/module-call-external.patch | 33 - .../fedora-27/module-shadow.patch.disabled | 24 - test/integration/fedora-27/multiple.test | 7 - test/integration/fedora-27/new-function.patch | 25 - test/integration/fedora-27/new-globals.patch | 34 - test/integration/fedora-27/remote-setup | 45 - .../fedora-27/shadow-newpid-LOADED.test | 3 - .../fedora-27/shadow-newpid.patch.disabled | 78 - .../fedora-27/warn-detect-FAIL.patch | 9 - test/integration/kpatch-test | 398 -- test/integration/lib.sh | 316 -- .../linux-5.10.11/data-new-LOADED.test | 3 - test/integration/linux-5.10.11/data-new.patch | 20 - .../gcc-static-local-var-6.patch | 22 - .../linux-5.10.11/macro-callbacks.patch | 163 - .../linux-5.10.11/module-call-external.patch | 36 - test/integration/linux-5.10.11/multiple.test | 7 - .../linux-5.10.11/new-function.patch | 27 - .../linux-5.10.11/new-globals.patch | 34 - .../linux-5.10.11/syscall-LOADED.test | 3 - test/integration/linux-5.10.11/syscall.patch | 21 - .../linux-5.10.11/warn-detect-FAIL.patch | 9 - .../linux-5.18.0/data-new-LOADED.test | 3 - test/integration/linux-5.18.0/data-new.patch | 20 - .../linux-5.18.0/gcc-static-local-var-6.patch | 22 - .../linux-5.18.0/macro-callbacks.patch | 155 - .../linux-5.18.0/module-LOADED.test | 13 - test/integration/linux-5.18.0/module.patch | 79 - test/integration/linux-5.18.0/multiple.test | 7 - .../linux-5.18.0/new-function.patch | 25 - .../linux-5.18.0/new-globals.patch | 34 - .../linux-5.18.0/shadow-newpid-LOADED.test | 3 - .../linux-5.18.0/shadow-newpid.patch | 75 - .../linux-5.18.0/special-static.patch | 22 - .../symvers-disagreement-FAIL.patch | 46 - .../linux-5.18.0/syscall-LOADED.test | 3 - test/integration/linux-5.18.0/syscall.patch | 20 - .../linux-5.18.0/warn-detect-FAIL.patch | 9 - test/integration/rebase-patches | 56 - .../rhel-7.4/bug-table-section.patch | 12 - .../rhel-7.4/cmdline-string-LOADED.test | 3 - .../integration/rhel-7.4/cmdline-string.patch | 12 - .../integration/rhel-7.4/data-new-LOADED.test | 3 - test/integration/rhel-7.4/data-new.patch | 28 - .../rhel-7.4/data-read-mostly.patch.disabled | 11 - test/integration/rhel-7.4/fixup-section.patch | 12 - test/integration/rhel-7.4/gcc-constprop.patch | 13 - test/integration/rhel-7.4/gcc-isra.patch | 11 - test/integration/rhel-7.4/gcc-mangled-3.patch | 13 - .../rhel-7.4/gcc-static-local-var-2.patch | 13 - .../rhel-7.4/gcc-static-local-var-3.patch | 19 - .../rhel-7.4/gcc-static-local-var-4.patch | 20 - .../rhel-7.4/gcc-static-local-var-4.test | 8 - .../rhel-7.4/gcc-static-local-var-5.patch | 45 - .../rhel-7.4/gcc-static-local-var-6.patch | 23 - .../rhel-7.4/gcc-static-local-var.patch | 25 - .../rhel-7.4/macro-callbacks.patch | 160 - test/integration/rhel-7.4/macro-printk.patch | 147 - .../rhel-7.4/meminfo-init-FAIL.patch | 11 - .../rhel-7.4/meminfo-init2-FAIL.patch | 19 - .../rhel-7.4/meminfo-string-LOADED.test | 3 - .../integration/rhel-7.4/meminfo-string.patch | 12 - .../rhel-7.4/module-call-external.patch | 33 - .../rhel-7.4/module-kvm-fixup.patch | 12 - test/integration/rhel-7.4/module-shadow.patch | 24 - test/integration/rhel-7.4/multiple.test | 7 - test/integration/rhel-7.4/new-function.patch | 25 - test/integration/rhel-7.4/new-globals.patch | 34 - .../rhel-7.4/parainstructions-section.patch | 11 - .../rhel-7.4/replace-section-references.patch | 12 - .../rhel-7.4/shadow-newpid-LOADED.test | 3 - test/integration/rhel-7.4/shadow-newpid.patch | 69 - .../rhel-7.4/smp-locks-section.patch | 14 - .../rhel-7.4/special-static-2.patch | 24 - .../integration/rhel-7.4/special-static.patch | 22 - .../rhel-7.4/tracepoints-section.patch | 13 - .../rhel-7.4/warn-detect-FAIL.patch | 8 - .../rhel-7.5/bug-table-section.patch | 12 - .../rhel-7.5/cmdline-string-LOADED.test | 3 - .../integration/rhel-7.5/cmdline-string.patch | 12 - .../integration/rhel-7.5/data-new-LOADED.test | 3 - test/integration/rhel-7.5/data-new.patch | 28 - .../rhel-7.5/data-read-mostly.patch.disabled | 11 - test/integration/rhel-7.5/fixup-section.patch | 12 - test/integration/rhel-7.5/gcc-constprop.patch | 13 - test/integration/rhel-7.5/gcc-isra.patch | 11 - test/integration/rhel-7.5/gcc-mangled-3.patch | 13 - .../rhel-7.5/gcc-static-local-var-2.patch | 13 - .../rhel-7.5/gcc-static-local-var-3.patch | 19 - .../rhel-7.5/gcc-static-local-var-4.patch | 20 - .../rhel-7.5/gcc-static-local-var-4.test | 8 - .../rhel-7.5/gcc-static-local-var-5.patch | 45 - .../rhel-7.5/gcc-static-local-var-6.patch | 23 - .../rhel-7.5/gcc-static-local-var.patch | 25 - .../rhel-7.5/macro-callbacks.patch | 160 - test/integration/rhel-7.5/macro-printk.patch | 147 - .../rhel-7.5/meminfo-init-FAIL.patch | 11 - .../rhel-7.5/meminfo-init2-FAIL.patch | 19 - .../rhel-7.5/meminfo-string-LOADED.test | 3 - .../integration/rhel-7.5/meminfo-string.patch | 12 - .../rhel-7.5/module-call-external.patch | 33 - .../rhel-7.5/module-kvm-fixup.patch | 12 - .../rhel-7.5/module-shadow.patch.disabled | 25 - test/integration/rhel-7.5/multiple.test | 7 - test/integration/rhel-7.5/new-function.patch | 25 - test/integration/rhel-7.5/new-globals.patch | 34 - .../rhel-7.5/parainstructions-section.patch | 11 - .../rhel-7.5/replace-section-references.patch | 12 - .../rhel-7.5/shadow-newpid-LOADED.test | 3 - test/integration/rhel-7.5/shadow-newpid.patch | 72 - .../rhel-7.5/smp-locks-section.patch | 14 - .../rhel-7.5/special-static-2.patch | 24 - .../integration/rhel-7.5/special-static.patch | 22 - .../rhel-7.5/tracepoints-section.patch | 13 - .../rhel-7.5/warn-detect-FAIL.patch | 8 - .../rhel-7.6/bug-table-section.patch | 13 - .../rhel-7.6/cmdline-string-LOADED.test | 3 - .../integration/rhel-7.6/cmdline-string.patch | 12 - .../integration/rhel-7.6/data-new-LOADED.test | 3 - test/integration/rhel-7.6/data-new.patch | 29 - .../rhel-7.6/data-read-mostly.patch.disabled | 12 - test/integration/rhel-7.6/fixup-section.patch | 12 - .../rhel-7.6/gcc-constprop.patch.disabled | 13 - test/integration/rhel-7.6/gcc-isra.patch | 12 - test/integration/rhel-7.6/gcc-mangled-3.patch | 14 - .../rhel-7.6/gcc-static-local-var-2.patch | 14 - .../rhel-7.6/gcc-static-local-var-3.patch | 20 - .../rhel-7.6/gcc-static-local-var-4.patch | 21 - .../rhel-7.6/gcc-static-local-var-4.test | 8 - .../rhel-7.6/gcc-static-local-var-5.patch | 45 - .../rhel-7.6/gcc-static-local-var-6.patch | 23 - .../rhel-7.6/macro-callbacks.patch | 160 - test/integration/rhel-7.6/macro-printk.patch | 151 - .../rhel-7.6/meminfo-init-FAIL.patch | 12 - .../rhel-7.6/meminfo-init2-FAIL.patch | 20 - .../rhel-7.6/meminfo-string-LOADED.test | 3 - .../integration/rhel-7.6/meminfo-string.patch | 12 - .../rhel-7.6/module-call-external.patch | 40 - test/integration/rhel-7.6/multiple.test | 7 - test/integration/rhel-7.6/new-function.patch | 26 - test/integration/rhel-7.6/new-globals.patch | 34 - .../rhel-7.6/parainstructions-section.patch | 11 - .../rhel-7.6/shadow-newpid-LOADED.test | 3 - test/integration/rhel-7.6/shadow-newpid.patch | 72 - .../rhel-7.6/smp-locks-section.patch | 14 - .../integration/rhel-7.6/special-static.patch | 23 - .../rhel-7.6/symvers-disagreement-FAIL.patch | 51 - .../rhel-7.6/tracepoints-section.patch | 14 - .../rhel-7.6/warn-detect-FAIL.patch | 8 - .../rhel-7.7/bug-table-section.patch | 13 - .../rhel-7.7/cmdline-string-LOADED.test | 3 - .../integration/rhel-7.7/cmdline-string.patch | 13 - .../integration/rhel-7.7/data-new-LOADED.test | 3 - test/integration/rhel-7.7/data-new.patch | 29 - .../rhel-7.7/data-read-mostly.patch.disabled | 12 - test/integration/rhel-7.7/fixup-section.patch | 12 - .../rhel-7.7/gcc-constprop.patch.disabled | 13 - test/integration/rhel-7.7/gcc-isra.patch | 12 - test/integration/rhel-7.7/gcc-mangled-3.patch | 14 - .../rhel-7.7/gcc-static-local-var-2.patch | 14 - .../rhel-7.7/gcc-static-local-var-3.patch | 20 - .../rhel-7.7/gcc-static-local-var-4.patch | 21 - .../rhel-7.7/gcc-static-local-var-4.test | 8 - .../rhel-7.7/gcc-static-local-var-5.patch | 46 - .../rhel-7.7/gcc-static-local-var-6.patch | 23 - .../rhel-7.7/macro-callbacks.patch | 166 - test/integration/rhel-7.7/macro-printk.patch | 151 - .../rhel-7.7/meminfo-init-FAIL.patch | 12 - .../rhel-7.7/meminfo-init2-FAIL.patch | 20 - .../rhel-7.7/meminfo-string-LOADED.test | 3 - .../integration/rhel-7.7/meminfo-string.patch | 13 - .../rhel-7.7/module-call-external.patch | 40 - test/integration/rhel-7.7/multiple.test | 7 - test/integration/rhel-7.7/new-function.patch | 26 - test/integration/rhel-7.7/new-globals.patch | 36 - .../rhel-7.7/parainstructions-section.patch | 12 - .../rhel-7.7/shadow-newpid-LOADED.test | 3 - test/integration/rhel-7.7/shadow-newpid.patch | 72 - .../rhel-7.7/smp-locks-section.patch | 15 - .../integration/rhel-7.7/special-static.patch | 23 - .../rhel-7.7/symvers-disagreement-FAIL.patch | 51 - .../rhel-7.7/tracepoints-section.patch | 14 - .../rhel-7.7/warn-detect-FAIL.patch | 9 - .../rhel-7.8/bug-table-section.patch | 12 - .../rhel-7.8/cmdline-string-LOADED.test | 3 - .../integration/rhel-7.8/cmdline-string.patch | 12 - .../integration/rhel-7.8/data-new-LOADED.test | 3 - test/integration/rhel-7.8/data-new.patch | 28 - .../rhel-7.8/data-read-mostly.patch.disabled | 11 - test/integration/rhel-7.8/fixup-section.patch | 11 - .../rhel-7.8/gcc-constprop.patch.disabled | 13 - test/integration/rhel-7.8/gcc-isra.patch | 11 - test/integration/rhel-7.8/gcc-mangled-3.patch | 13 - .../rhel-7.8/gcc-static-local-var-2.patch | 13 - .../rhel-7.8/gcc-static-local-var-3.patch | 19 - .../rhel-7.8/gcc-static-local-var-4.patch | 20 - .../rhel-7.8/gcc-static-local-var-4.test | 8 - .../rhel-7.8/gcc-static-local-var-5.patch | 45 - .../rhel-7.8/gcc-static-local-var-6.patch | 22 - .../rhel-7.8/macro-callbacks.patch | 163 - test/integration/rhel-7.8/macro-printk.patch | 148 - .../rhel-7.8/meminfo-init-FAIL.patch | 11 - .../rhel-7.8/meminfo-init2-FAIL.patch | 19 - .../rhel-7.8/meminfo-string-LOADED.test | 3 - .../integration/rhel-7.8/meminfo-string.patch | 12 - .../rhel-7.8/module-call-external.patch | 38 - test/integration/rhel-7.8/multiple.test | 7 - test/integration/rhel-7.8/new-function.patch | 25 - test/integration/rhel-7.8/new-globals.patch | 34 - .../rhel-7.8/parainstructions-section.patch | 11 - .../rhel-7.8/shadow-newpid-LOADED.test | 3 - test/integration/rhel-7.8/shadow-newpid.patch | 69 - .../rhel-7.8/smp-locks-section.patch | 14 - .../integration/rhel-7.8/special-static.patch | 22 - .../rhel-7.8/symvers-disagreement-FAIL.patch | 49 - .../rhel-7.8/tracepoints-section.patch | 13 - .../rhel-7.8/warn-detect-FAIL.patch | 8 - .../rhel-7.9/bug-table-section.patch | 12 - .../rhel-7.9/cmdline-string-LOADED.test | 3 - .../integration/rhel-7.9/cmdline-string.patch | 12 - .../integration/rhel-7.9/data-new-LOADED.test | 3 - test/integration/rhel-7.9/data-new.patch | 28 - .../rhel-7.9/data-read-mostly.patch.disabled | 11 - test/integration/rhel-7.9/fixup-section.patch | 11 - test/integration/rhel-7.9/gcc-constprop.patch | 13 - test/integration/rhel-7.9/gcc-isra.patch | 11 - test/integration/rhel-7.9/gcc-mangled-3.patch | 13 - .../rhel-7.9/gcc-static-local-var-2.patch | 13 - .../rhel-7.9/gcc-static-local-var-3.patch | 19 - .../rhel-7.9/gcc-static-local-var-4.patch | 20 - .../rhel-7.9/gcc-static-local-var-4.test | 8 - .../rhel-7.9/gcc-static-local-var-5.patch | 45 - .../rhel-7.9/gcc-static-local-var-6.patch | 22 - .../rhel-7.9/macro-callbacks.patch | 163 - test/integration/rhel-7.9/macro-printk.patch | 148 - .../rhel-7.9/meminfo-init-FAIL.patch | 11 - .../rhel-7.9/meminfo-init2-FAIL.patch | 19 - .../rhel-7.9/meminfo-string-LOADED.test | 3 - .../integration/rhel-7.9/meminfo-string.patch | 12 - .../rhel-7.9/module-call-external.patch | 38 - test/integration/rhel-7.9/multiple.test | 7 - test/integration/rhel-7.9/new-function.patch | 25 - test/integration/rhel-7.9/new-globals.patch | 34 - .../rhel-7.9/parainstructions-section.patch | 11 - .../rhel-7.9/shadow-newpid-LOADED.test | 3 - test/integration/rhel-7.9/shadow-newpid.patch | 69 - .../rhel-7.9/smp-locks-section.patch | 14 - .../integration/rhel-7.9/special-static.patch | 22 - .../rhel-7.9/symvers-disagreement-FAIL.patch | 49 - test/integration/rhel-7.9/syscall-LOADED.test | 3 - test/integration/rhel-7.9/syscall.patch | 26 - .../rhel-7.9/tracepoints-section.patch | 13 - .../rhel-7.9/warn-detect-FAIL.patch | 8 - test/integration/rhel-8.0/README | 1 - .../rhel-8.0/bug-table-section.patch | 13 - .../rhel-8.0/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.0/cmdline-string.patch | 14 - .../integration/rhel-8.0/data-new-LOADED.test | 3 - test/integration/rhel-8.0/data-new.patch | 21 - .../rhel-8.0/data-read-mostly.patch.disabled | 14 - test/integration/rhel-8.0/fixup-section.patch | 12 - .../rhel-8.0/gcc-constprop.patch.disabled | 14 - test/integration/rhel-8.0/gcc-isra.patch | 12 - test/integration/rhel-8.0/gcc-mangled-3.patch | 14 - .../rhel-8.0/gcc-static-local-var-2.patch | 14 - .../rhel-8.0/gcc-static-local-var-3.patch | 20 - .../gcc-static-local-var-4.patch.disabled | 25 - .../gcc-static-local-var-4.test.disabled | 8 - .../rhel-8.0/gcc-static-local-var-5.patch | 46 - .../rhel-8.0/gcc-static-local-var-6.patch | 23 - .../rhel-8.0/macro-callbacks.patch | 158 - .../rhel-8.0/macro-printk.patch.disabled | 151 - .../rhel-8.0/meminfo-init-FAIL.patch | 12 - .../rhel-8.0/meminfo-init2-FAIL.patch | 20 - .../rhel-8.0/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.0/meminfo-string.patch | 13 - .../rhel-8.0/module-call-external.patch | 35 - test/integration/rhel-8.0/multiple.test | 7 - test/integration/rhel-8.0/new-function.patch | 26 - test/integration/rhel-8.0/new-globals.patch | 36 - .../rhel-8.0/parainstructions-section.patch | 12 - .../rhel-8.0/shadow-newpid-LOADED.test | 3 - .../rhel-8.0/shadow-newpid.patch.disabled | 80 - .../rhel-8.0/smp-locks-section.patch | 14 - .../integration/rhel-8.0/special-static.patch | 23 - .../rhel-8.0/symvers-disagreement-FAIL.patch | 51 - .../rhel-8.0/tracepoints-section.patch | 14 - .../rhel-8.0/warn-detect-FAIL.patch | 9 - .../rhel-8.1/bug-table-section.patch | 12 - .../rhel-8.1/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.1/cmdline-string.patch | 13 - .../integration/rhel-8.1/data-new-LOADED.test | 3 - test/integration/rhel-8.1/data-new.patch | 20 - .../rhel-8.1/data-read-mostly.patch.disabled | 13 - test/integration/rhel-8.1/fixup-section.patch | 11 - .../rhel-8.1/gcc-constprop.patch.disabled | 13 - test/integration/rhel-8.1/gcc-isra.patch | 11 - test/integration/rhel-8.1/gcc-mangled-3.patch | 13 - .../rhel-8.1/gcc-static-local-var-2.patch | 13 - .../rhel-8.1/gcc-static-local-var-3.patch | 19 - .../gcc-static-local-var-4.patch.disabled | 24 - .../gcc-static-local-var-4.test.disabled | 8 - .../rhel-8.1/gcc-static-local-var-5.patch | 45 - .../rhel-8.1/gcc-static-local-var-6.patch | 22 - .../rhel-8.1/macro-callbacks.patch | 155 - .../rhel-8.1/macro-printk.patch.disabled | 148 - .../rhel-8.1/meminfo-init-FAIL.patch | 11 - .../rhel-8.1/meminfo-init2-FAIL.patch | 19 - .../rhel-8.1/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.1/meminfo-string.patch | 12 - test/integration/rhel-8.1/module-LOADED.test | 13 - test/integration/rhel-8.1/module.patch | 90 - test/integration/rhel-8.1/multiple.test | 7 - test/integration/rhel-8.1/new-function.patch | 25 - test/integration/rhel-8.1/new-globals.patch | 34 - .../rhel-8.1/parainstructions-section.patch | 11 - .../shadow-newpid-LOADED.test.disabled | 3 - .../rhel-8.1/shadow-newpid.patch.disabled | 77 - .../rhel-8.1/smp-locks-section.patch | 13 - .../rhel-8.1/special-static.patch.disabled | 22 - .../rhel-8.1/symvers-disagreement-FAIL.patch | 51 - .../rhel-8.1/tracepoints-section.patch | 13 - .../rhel-8.1/warn-detect-FAIL.patch | 8 - .../rhel-8.2/bug-table-section.patch | 12 - .../rhel-8.2/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.2/cmdline-string.patch | 13 - .../integration/rhel-8.2/data-new-LOADED.test | 3 - test/integration/rhel-8.2/data-new.patch | 20 - .../rhel-8.2/data-read-mostly.patch.disabled | 13 - test/integration/rhel-8.2/fixup-section.patch | 11 - test/integration/rhel-8.2/gcc-constprop.patch | 13 - test/integration/rhel-8.2/gcc-isra.patch | 11 - test/integration/rhel-8.2/gcc-mangled-3.patch | 13 - .../rhel-8.2/gcc-static-local-var-2.patch | 13 - .../rhel-8.2/gcc-static-local-var-3.patch | 19 - .../gcc-static-local-var-4.patch.disabled | 24 - .../gcc-static-local-var-4.test.disabled | 8 - .../rhel-8.2/gcc-static-local-var-5.patch | 45 - .../rhel-8.2/gcc-static-local-var-6.patch | 22 - .../rhel-8.2/macro-callbacks.patch | 155 - test/integration/rhel-8.2/macro-printk.patch | 148 - .../rhel-8.2/meminfo-init-FAIL.patch | 11 - .../rhel-8.2/meminfo-init2-FAIL.patch | 19 - .../rhel-8.2/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.2/meminfo-string.patch | 12 - test/integration/rhel-8.2/module-LOADED.test | 13 - test/integration/rhel-8.2/module.patch | 85 - test/integration/rhel-8.2/multiple.test | 7 - test/integration/rhel-8.2/new-function.patch | 25 - test/integration/rhel-8.2/new-globals.patch | 34 - .../rhel-8.2/parainstructions-section.patch | 11 - .../shadow-newpid-LOADED.test.disabled | 3 - .../rhel-8.2/shadow-newpid.patch.disabled | 77 - .../rhel-8.2/smp-locks-section.patch | 13 - .../rhel-8.2/special-static.patch.disabled | 22 - .../rhel-8.2/symvers-disagreement-FAIL.patch | 51 - .../rhel-8.2/tracepoints-section.patch | 13 - .../rhel-8.2/warn-detect-FAIL.patch | 8 - .../rhel-8.3/bug-table-section.patch | 12 - .../rhel-8.3/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.3/cmdline-string.patch | 13 - .../integration/rhel-8.3/data-new-LOADED.test | 3 - test/integration/rhel-8.3/data-new.patch | 20 - .../rhel-8.3/data-read-mostly.patch.disabled | 13 - test/integration/rhel-8.3/fixup-section.patch | 11 - test/integration/rhel-8.3/gcc-constprop.patch | 13 - test/integration/rhel-8.3/gcc-isra.patch | 11 - test/integration/rhel-8.3/gcc-mangled-3.patch | 13 - .../rhel-8.3/gcc-static-local-var-2.patch | 13 - .../rhel-8.3/gcc-static-local-var-3.patch | 19 - .../gcc-static-local-var-4.patch.disabled | 24 - .../gcc-static-local-var-4.test.disabled | 8 - .../rhel-8.3/gcc-static-local-var-5.patch | 45 - .../rhel-8.3/gcc-static-local-var-6.patch | 22 - .../rhel-8.3/macro-callbacks.patch | 155 - test/integration/rhel-8.3/macro-printk.patch | 148 - .../rhel-8.3/meminfo-init-FAIL.patch | 11 - .../rhel-8.3/meminfo-init2-FAIL.patch | 19 - .../rhel-8.3/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.3/meminfo-string.patch | 12 - test/integration/rhel-8.3/module-LOADED.test | 13 - test/integration/rhel-8.3/module.patch | 85 - test/integration/rhel-8.3/multiple.test | 7 - test/integration/rhel-8.3/new-function.patch | 25 - test/integration/rhel-8.3/new-globals.patch | 34 - .../rhel-8.3/parainstructions-section.patch | 11 - .../shadow-newpid-LOADED.test.disabled | 3 - .../rhel-8.3/shadow-newpid.patch.disabled | 77 - .../rhel-8.3/smp-locks-section.patch | 13 - .../rhel-8.3/special-static.patch.disabled | 22 - .../rhel-8.3/symvers-disagreement-FAIL.patch | 51 - .../rhel-8.3/tracepoints-section.patch | 13 - .../rhel-8.3/warn-detect-FAIL.patch | 8 - .../rhel-8.4/bug-table-section.patch | 12 - .../rhel-8.4/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.4/cmdline-string.patch | 13 - .../integration/rhel-8.4/data-new-LOADED.test | 3 - test/integration/rhel-8.4/data-new.patch | 20 - .../rhel-8.4/data-read-mostly.patch | 11 - test/integration/rhel-8.4/fixup-section.patch | 11 - test/integration/rhel-8.4/gcc-constprop.patch | 13 - test/integration/rhel-8.4/gcc-isra.patch | 11 - test/integration/rhel-8.4/gcc-mangled-3.patch | 13 - .../rhel-8.4/gcc-static-local-var-2.patch | 13 - .../rhel-8.4/gcc-static-local-var-3.patch | 19 - .../rhel-8.4/gcc-static-local-var-4.patch | 23 - .../rhel-8.4/gcc-static-local-var-4.test | 8 - .../rhel-8.4/gcc-static-local-var-5.patch | 45 - .../rhel-8.4/gcc-static-local-var-6.patch | 22 - .../rhel-8.4/macro-callbacks.patch | 155 - test/integration/rhel-8.4/macro-printk.patch | 149 - .../rhel-8.4/meminfo-init-FAIL.patch | 11 - .../rhel-8.4/meminfo-init2-FAIL.patch | 19 - .../rhel-8.4/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.4/meminfo-string.patch | 12 - test/integration/rhel-8.4/module-LOADED.test | 13 - test/integration/rhel-8.4/module.patch | 85 - test/integration/rhel-8.4/multiple.test | 7 - test/integration/rhel-8.4/new-function.patch | 25 - test/integration/rhel-8.4/new-globals.patch | 34 - .../rhel-8.4/parainstructions-section.patch | 11 - .../rhel-8.4/shadow-newpid-LOADED.test | 3 - test/integration/rhel-8.4/shadow-newpid.patch | 75 - .../rhel-8.4/smp-locks-section.patch | 13 - .../integration/rhel-8.4/special-static.patch | 22 - .../rhel-8.4/symvers-disagreement-FAIL.patch | 46 - test/integration/rhel-8.4/syscall-LOADED.test | 3 - test/integration/rhel-8.4/syscall.patch | 26 - .../rhel-8.4/tracepoints-section.patch | 13 - .../rhel-8.4/warn-detect-FAIL.patch | 9 - .../rhel-8.6/bug-table-section.patch | 12 - .../rhel-8.6/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.6/cmdline-string.patch | 13 - .../integration/rhel-8.6/data-new-LOADED.test | 3 - test/integration/rhel-8.6/data-new.patch | 20 - .../rhel-8.6/data-read-mostly.patch | 11 - test/integration/rhel-8.6/fixup-section.patch | 11 - test/integration/rhel-8.6/gcc-constprop.patch | 13 - test/integration/rhel-8.6/gcc-isra.patch | 11 - test/integration/rhel-8.6/gcc-mangled-3.patch | 13 - .../rhel-8.6/gcc-static-local-var-2.patch | 13 - .../rhel-8.6/gcc-static-local-var-3.patch | 19 - .../rhel-8.6/gcc-static-local-var-4.patch | 23 - .../rhel-8.6/gcc-static-local-var-4.test | 8 - .../rhel-8.6/gcc-static-local-var-5.patch | 45 - .../rhel-8.6/gcc-static-local-var-6.patch | 22 - .../rhel-8.6/macro-callbacks.patch | 155 - test/integration/rhel-8.6/macro-printk.patch | 149 - .../rhel-8.6/meminfo-init-FAIL.patch | 11 - .../rhel-8.6/meminfo-init2-FAIL.patch | 19 - .../rhel-8.6/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.6/meminfo-string.patch | 12 - test/integration/rhel-8.6/module-LOADED.test | 13 - test/integration/rhel-8.6/module.patch | 85 - test/integration/rhel-8.6/multiple.test | 7 - test/integration/rhel-8.6/new-function.patch | 25 - test/integration/rhel-8.6/new-globals.patch | 34 - .../rhel-8.6/parainstructions-section.patch | 11 - .../rhel-8.6/shadow-newpid-LOADED.test | 3 - test/integration/rhel-8.6/shadow-newpid.patch | 75 - .../rhel-8.6/smp-locks-section.patch | 13 - .../integration/rhel-8.6/special-static.patch | 22 - .../rhel-8.6/symvers-disagreement-FAIL.patch | 46 - test/integration/rhel-8.6/syscall-LOADED.test | 3 - test/integration/rhel-8.6/syscall.patch | 25 - .../rhel-8.6/tracepoints-section.patch | 13 - .../rhel-8.6/warn-detect-FAIL.patch | 9 - .../rhel-8.7/bug-table-section.patch | 12 - .../rhel-8.7/cmdline-string-LOADED.test | 3 - .../integration/rhel-8.7/cmdline-string.patch | 13 - .../integration/rhel-8.7/data-new-LOADED.test | 3 - test/integration/rhel-8.7/data-new.patch | 20 - .../rhel-8.7/data-read-mostly.patch | 11 - test/integration/rhel-8.7/fixup-section.patch | 11 - test/integration/rhel-8.7/gcc-constprop.patch | 13 - test/integration/rhel-8.7/gcc-isra.patch | 11 - test/integration/rhel-8.7/gcc-mangled-3.patch | 13 - .../rhel-8.7/gcc-static-local-var-2.patch | 13 - .../rhel-8.7/gcc-static-local-var-3.patch | 19 - .../rhel-8.7/gcc-static-local-var-4.patch | 23 - .../rhel-8.7/gcc-static-local-var-4.test | 8 - .../rhel-8.7/gcc-static-local-var-5.patch | 45 - .../rhel-8.7/gcc-static-local-var-6.patch | 22 - .../rhel-8.7/macro-callbacks.patch | 155 - test/integration/rhel-8.7/macro-printk.patch | 149 - .../rhel-8.7/meminfo-init-FAIL.patch | 11 - .../rhel-8.7/meminfo-init2-FAIL.patch | 19 - .../rhel-8.7/meminfo-string-LOADED.test | 3 - .../integration/rhel-8.7/meminfo-string.patch | 12 - test/integration/rhel-8.7/module-LOADED.test | 13 - test/integration/rhel-8.7/module.patch | 85 - test/integration/rhel-8.7/multiple.test | 7 - test/integration/rhel-8.7/new-function.patch | 25 - test/integration/rhel-8.7/new-globals.patch | 34 - .../rhel-8.7/parainstructions-section.patch | 11 - .../rhel-8.7/shadow-newpid-LOADED.test | 3 - test/integration/rhel-8.7/shadow-newpid.patch | 75 - .../rhel-8.7/smp-locks-section.patch | 13 - .../integration/rhel-8.7/special-static.patch | 22 - .../rhel-8.7/symvers-disagreement-FAIL.patch | 46 - test/integration/rhel-8.7/syscall-LOADED.test | 3 - test/integration/rhel-8.7/syscall.patch | 25 - .../rhel-8.7/tracepoints-section.patch | 13 - .../rhel-8.7/warn-detect-FAIL.patch | 9 - .../integration/rhel-9.0/data-new-LOADED.test | 3 - test/integration/rhel-9.0/data-new.patch | 20 - .../rhel-9.0/gcc-static-local-var-6.patch | 22 - .../rhel-9.0/macro-callbacks.patch | 155 - test/integration/rhel-9.0/module-LOADED.test | 13 - test/integration/rhel-9.0/module.patch | 79 - test/integration/rhel-9.0/multiple.test | 7 - test/integration/rhel-9.0/new-function.patch | 25 - test/integration/rhel-9.0/new-globals.patch | 34 - .../rhel-9.0/shadow-newpid-LOADED.test | 3 - test/integration/rhel-9.0/shadow-newpid.patch | 75 - .../integration/rhel-9.0/special-static.patch | 22 - .../rhel-9.0/symvers-disagreement-FAIL.patch | 46 - test/integration/rhel-9.0/syscall-LOADED.test | 3 - test/integration/rhel-9.0/syscall.patch | 20 - .../rhel-9.0/warn-detect-FAIL.patch | 9 - .../integration/rhel-9.1/data-new-LOADED.test | 3 - test/integration/rhel-9.1/data-new.patch | 20 - .../rhel-9.1/gcc-static-local-var-6.patch | 22 - .../rhel-9.1/macro-callbacks.patch | 155 - test/integration/rhel-9.1/module-LOADED.test | 13 - test/integration/rhel-9.1/module.patch | 79 - test/integration/rhel-9.1/multiple.test | 7 - test/integration/rhel-9.1/new-function.patch | 25 - test/integration/rhel-9.1/new-globals.patch | 34 - .../rhel-9.1/shadow-newpid-LOADED.test | 3 - test/integration/rhel-9.1/shadow-newpid.patch | 75 - .../integration/rhel-9.1/special-static.patch | 22 - .../rhel-9.1/symvers-disagreement-FAIL.patch | 46 - test/integration/rhel-9.1/syscall-LOADED.test | 3 - test/integration/rhel-9.1/syscall.patch | 20 - .../rhel-9.1/warn-detect-FAIL.patch | 9 - test/integration/test-vagrant | 42 - test/integration/ubuntu-16.04/README | 1 - .../ubuntu-16.04/bug-table-section.patch | 12 - .../ubuntu-16.04/cmdline-string-LOADED.test | 3 - .../ubuntu-16.04/cmdline-string.patch | 12 - .../ubuntu-16.04/data-new-LOADED.test | 3 - test/integration/ubuntu-16.04/data-new.patch | 28 - .../ubuntu-16.04/data-read-mostly.patch | 11 - .../ubuntu-16.04/fixup-section.patch | 12 - .../ubuntu-16.04/gcc-constprop.patch | 16 - test/integration/ubuntu-16.04/gcc-isra.patch | 11 - .../ubuntu-16.04/gcc-mangled-3.patch.disabled | 19 - .../ubuntu-16.04/gcc-static-local-var-2.patch | 13 - .../ubuntu-16.04/gcc-static-local-var-3.patch | 19 - .../ubuntu-16.04/gcc-static-local-var-4.patch | 20 - .../ubuntu-16.04/gcc-static-local-var-4.test | 8 - .../ubuntu-16.04/gcc-static-local-var-5.patch | 45 - .../ubuntu-16.04/gcc-static-local-var-6.patch | 23 - .../ubuntu-16.04/gcc-static-local-var.patch | 25 - .../ubuntu-16.04/macro-callbacks.patch | 163 - .../ubuntu-16.04/macro-printk.patch | 148 - ...-cmdline-rebuild-SLOW-LOADED.test.disabled | 3 - ...eminfo-cmdline-rebuild-SLOW.patch.disabled | 42 - .../ubuntu-16.04/meminfo-init-FAIL.patch | 11 - .../ubuntu-16.04/meminfo-init2-FAIL.patch | 19 - .../ubuntu-16.04/meminfo-string-LOADED.test | 3 - .../ubuntu-16.04/meminfo-string.patch | 12 - .../module-call-external.patch.disable | 38 - .../ubuntu-16.04/module-kvm-fixup.patch | 12 - test/integration/ubuntu-16.04/multiple.test | 7 - .../ubuntu-16.04/new-function.patch | 25 - .../ubuntu-16.04/new-globals.patch | 34 - .../parainstructions-section.patch | 11 - .../replace-section-references.patch | 12 - .../ubuntu-16.04/smp-locks-section.patch | 12 - .../ubuntu-16.04/special-static-2.patch | 24 - .../ubuntu-16.04/special-static.patch | 22 - .../ubuntu-16.04/tracepoints-section.patch | 13 - .../ubuntu-16.04/warn-detect-FAIL.patch | 8 - test/integration/vm-integration-run | 85 - test/test-functions.sh | 12 - test/unit/Makefile | 17 - test/unit/Makefile.include | 73 - v0.9.9.tar.gz | Bin 0 -> 3282944 bytes 656 files changed, 522 insertions(+), 34306 deletions(-) create mode 100644 0001-kpatch-don-t-need-vmlinux.patch create mode 100644 0002-kpatch-build-fix-some-subfunction-.cold-change-error.patch create mode 100644 0003-kpatch-get-gcc-version-from-config-file.patch create mode 100644 0004-get-kernel-version-from-kpatch-build.patch create mode 100644 0005-kpatch-build-use-new-klp-arch.patch create mode 100644 0006-check-klp_register_patch-function-symbol.patch create mode 100644 0007-kpatch-build-set-EXTRAVERSION.patch create mode 100644 0008-devel-an-options-for-kpatch-module-build-mode.patch create mode 100644 0009-kpatch-build-add-DISTRO-anolis.patch delete mode 100644 COPYING delete mode 100644 Makefile delete mode 100644 Makefile.inc delete mode 100644 contrib/Makefile delete mode 100644 contrib/kpatch.conf delete mode 100644 contrib/kpatch.service delete mode 100644 contrib/kpatch.spec delete mode 100644 examples/proc-version.patch delete mode 100644 examples/tcp_cubic-better-follow-cubic-curve-converted.patch delete mode 100644 examples/tcp_cubic-better-follow-cubic-curve-original.patch delete mode 100644 kmod/Makefile delete mode 100644 kmod/core/Makefile delete mode 100644 kmod/core/core.c delete mode 100644 kmod/core/kpatch.h delete mode 100644 kmod/core/shadow.c delete mode 100644 kmod/patch/Makefile delete mode 100644 kmod/patch/kpatch-macros.h delete mode 100644 kmod/patch/kpatch-patch-hook.c delete mode 100644 kmod/patch/kpatch-patch.h delete mode 100644 kmod/patch/kpatch-syscall.h delete mode 120000 kmod/patch/kpatch.h delete mode 100644 kmod/patch/kpatch.lds.S delete mode 100644 kmod/patch/livepatch-patch-hook.c delete mode 100644 kmod/patch/patch-hook.c delete mode 100644 kpatch-build/Makefile delete mode 100644 kpatch-build/create-diff-object.c delete mode 100644 kpatch-build/create-klp-module.c delete mode 100644 kpatch-build/create-kpatch-module.c delete mode 100644 kpatch-build/gcc-plugins/gcc-common.h delete mode 100644 kpatch-build/gcc-plugins/gcc-generate-rtl-pass.h delete mode 100644 kpatch-build/gcc-plugins/ppc64le-plugin.c delete mode 100644 kpatch-build/insn/asm/inat.h delete mode 100644 kpatch-build/insn/asm/inat_types.h delete mode 100644 kpatch-build/insn/asm/insn.h delete mode 100644 kpatch-build/insn/inat-tables.c delete mode 100644 kpatch-build/insn/inat.c delete mode 100644 kpatch-build/insn/insn.c delete mode 100755 kpatch-build/kpatch-build delete mode 100755 kpatch-build/kpatch-cc delete mode 100755 kpatch-build/kpatch-elf.c delete mode 100644 kpatch-build/kpatch-elf.h delete mode 100644 kpatch-build/kpatch-intermediate.h delete mode 100644 kpatch-build/kpatch.h delete mode 100644 kpatch-build/list.h delete mode 100644 kpatch-build/log.h delete mode 100644 kpatch-build/lookup.c delete mode 100644 kpatch-build/lookup.h create mode 100755 kpatch.spec delete mode 100644 kpatch/Makefile delete mode 100755 kpatch/kpatch delete mode 100644 man/Makefile delete mode 100644 man/kpatch-build.1 delete mode 100644 man/kpatch.1 delete mode 100755 test/difftree.sh delete mode 100644 test/integration/.gitignore delete mode 100644 test/integration/Makefile delete mode 120000 test/integration/centos-7 delete mode 120000 test/integration/centos-8 delete mode 100755 test/integration/common/multiple.template delete mode 100644 test/integration/fedora-27/README delete mode 100755 test/integration/fedora-27/data-new-LOADED.test delete mode 100644 test/integration/fedora-27/data-new.patch delete mode 100644 test/integration/fedora-27/gcc-static-local-var-6.patch delete mode 100644 test/integration/fedora-27/macro-callbacks.patch delete mode 100755 test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled delete mode 100644 test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW.patch.disabled delete mode 100644 test/integration/fedora-27/module-call-external.patch delete mode 100644 test/integration/fedora-27/module-shadow.patch.disabled delete mode 100755 test/integration/fedora-27/multiple.test delete mode 100644 test/integration/fedora-27/new-function.patch delete mode 100644 test/integration/fedora-27/new-globals.patch delete mode 100755 test/integration/fedora-27/remote-setup delete mode 100755 test/integration/fedora-27/shadow-newpid-LOADED.test delete mode 100644 test/integration/fedora-27/shadow-newpid.patch.disabled delete mode 100644 test/integration/fedora-27/warn-detect-FAIL.patch delete mode 100755 test/integration/kpatch-test delete mode 100644 test/integration/lib.sh delete mode 100755 test/integration/linux-5.10.11/data-new-LOADED.test delete mode 100644 test/integration/linux-5.10.11/data-new.patch delete mode 100644 test/integration/linux-5.10.11/gcc-static-local-var-6.patch delete mode 100644 test/integration/linux-5.10.11/macro-callbacks.patch delete mode 100644 test/integration/linux-5.10.11/module-call-external.patch delete mode 100755 test/integration/linux-5.10.11/multiple.test delete mode 100644 test/integration/linux-5.10.11/new-function.patch delete mode 100644 test/integration/linux-5.10.11/new-globals.patch delete mode 100755 test/integration/linux-5.10.11/syscall-LOADED.test delete mode 100644 test/integration/linux-5.10.11/syscall.patch delete mode 100644 test/integration/linux-5.10.11/warn-detect-FAIL.patch delete mode 100755 test/integration/linux-5.18.0/data-new-LOADED.test delete mode 100644 test/integration/linux-5.18.0/data-new.patch delete mode 100644 test/integration/linux-5.18.0/gcc-static-local-var-6.patch delete mode 100644 test/integration/linux-5.18.0/macro-callbacks.patch delete mode 100755 test/integration/linux-5.18.0/module-LOADED.test delete mode 100644 test/integration/linux-5.18.0/module.patch delete mode 100755 test/integration/linux-5.18.0/multiple.test delete mode 100644 test/integration/linux-5.18.0/new-function.patch delete mode 100644 test/integration/linux-5.18.0/new-globals.patch delete mode 100755 test/integration/linux-5.18.0/shadow-newpid-LOADED.test delete mode 100644 test/integration/linux-5.18.0/shadow-newpid.patch delete mode 100644 test/integration/linux-5.18.0/special-static.patch delete mode 100644 test/integration/linux-5.18.0/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/linux-5.18.0/syscall-LOADED.test delete mode 100644 test/integration/linux-5.18.0/syscall.patch delete mode 100644 test/integration/linux-5.18.0/warn-detect-FAIL.patch delete mode 100755 test/integration/rebase-patches delete mode 100644 test/integration/rhel-7.4/bug-table-section.patch delete mode 100755 test/integration/rhel-7.4/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-7.4/cmdline-string.patch delete mode 100755 test/integration/rhel-7.4/data-new-LOADED.test delete mode 100644 test/integration/rhel-7.4/data-new.patch delete mode 100644 test/integration/rhel-7.4/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-7.4/fixup-section.patch delete mode 100644 test/integration/rhel-7.4/gcc-constprop.patch delete mode 100644 test/integration/rhel-7.4/gcc-isra.patch delete mode 100644 test/integration/rhel-7.4/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-7.4/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-7.4/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-7.4/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-7.4/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-7.4/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-7.4/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-7.4/gcc-static-local-var.patch delete mode 100644 test/integration/rhel-7.4/macro-callbacks.patch delete mode 100644 test/integration/rhel-7.4/macro-printk.patch delete mode 100644 test/integration/rhel-7.4/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-7.4/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-7.4/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-7.4/meminfo-string.patch delete mode 100644 test/integration/rhel-7.4/module-call-external.patch delete mode 100644 test/integration/rhel-7.4/module-kvm-fixup.patch delete mode 100644 test/integration/rhel-7.4/module-shadow.patch delete mode 100755 test/integration/rhel-7.4/multiple.test delete mode 100644 test/integration/rhel-7.4/new-function.patch delete mode 100644 test/integration/rhel-7.4/new-globals.patch delete mode 100644 test/integration/rhel-7.4/parainstructions-section.patch delete mode 100644 test/integration/rhel-7.4/replace-section-references.patch delete mode 100755 test/integration/rhel-7.4/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-7.4/shadow-newpid.patch delete mode 100644 test/integration/rhel-7.4/smp-locks-section.patch delete mode 100644 test/integration/rhel-7.4/special-static-2.patch delete mode 100644 test/integration/rhel-7.4/special-static.patch delete mode 100644 test/integration/rhel-7.4/tracepoints-section.patch delete mode 100644 test/integration/rhel-7.4/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-7.5/bug-table-section.patch delete mode 100755 test/integration/rhel-7.5/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-7.5/cmdline-string.patch delete mode 100755 test/integration/rhel-7.5/data-new-LOADED.test delete mode 100644 test/integration/rhel-7.5/data-new.patch delete mode 100644 test/integration/rhel-7.5/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-7.5/fixup-section.patch delete mode 100644 test/integration/rhel-7.5/gcc-constprop.patch delete mode 100644 test/integration/rhel-7.5/gcc-isra.patch delete mode 100644 test/integration/rhel-7.5/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-7.5/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-7.5/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-7.5/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-7.5/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-7.5/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-7.5/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-7.5/gcc-static-local-var.patch delete mode 100644 test/integration/rhel-7.5/macro-callbacks.patch delete mode 100644 test/integration/rhel-7.5/macro-printk.patch delete mode 100644 test/integration/rhel-7.5/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-7.5/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-7.5/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-7.5/meminfo-string.patch delete mode 100644 test/integration/rhel-7.5/module-call-external.patch delete mode 100644 test/integration/rhel-7.5/module-kvm-fixup.patch delete mode 100644 test/integration/rhel-7.5/module-shadow.patch.disabled delete mode 100755 test/integration/rhel-7.5/multiple.test delete mode 100644 test/integration/rhel-7.5/new-function.patch delete mode 100644 test/integration/rhel-7.5/new-globals.patch delete mode 100644 test/integration/rhel-7.5/parainstructions-section.patch delete mode 100644 test/integration/rhel-7.5/replace-section-references.patch delete mode 100755 test/integration/rhel-7.5/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-7.5/shadow-newpid.patch delete mode 100644 test/integration/rhel-7.5/smp-locks-section.patch delete mode 100644 test/integration/rhel-7.5/special-static-2.patch delete mode 100644 test/integration/rhel-7.5/special-static.patch delete mode 100644 test/integration/rhel-7.5/tracepoints-section.patch delete mode 100644 test/integration/rhel-7.5/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-7.6/bug-table-section.patch delete mode 100755 test/integration/rhel-7.6/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-7.6/cmdline-string.patch delete mode 100755 test/integration/rhel-7.6/data-new-LOADED.test delete mode 100644 test/integration/rhel-7.6/data-new.patch delete mode 100644 test/integration/rhel-7.6/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-7.6/fixup-section.patch delete mode 100644 test/integration/rhel-7.6/gcc-constprop.patch.disabled delete mode 100644 test/integration/rhel-7.6/gcc-isra.patch delete mode 100644 test/integration/rhel-7.6/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-7.6/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-7.6/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-7.6/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-7.6/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-7.6/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-7.6/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-7.6/macro-callbacks.patch delete mode 100644 test/integration/rhel-7.6/macro-printk.patch delete mode 100644 test/integration/rhel-7.6/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-7.6/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-7.6/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-7.6/meminfo-string.patch delete mode 100644 test/integration/rhel-7.6/module-call-external.patch delete mode 100755 test/integration/rhel-7.6/multiple.test delete mode 100644 test/integration/rhel-7.6/new-function.patch delete mode 100644 test/integration/rhel-7.6/new-globals.patch delete mode 100644 test/integration/rhel-7.6/parainstructions-section.patch delete mode 100755 test/integration/rhel-7.6/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-7.6/shadow-newpid.patch delete mode 100644 test/integration/rhel-7.6/smp-locks-section.patch delete mode 100644 test/integration/rhel-7.6/special-static.patch delete mode 100644 test/integration/rhel-7.6/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-7.6/tracepoints-section.patch delete mode 100644 test/integration/rhel-7.6/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-7.7/bug-table-section.patch delete mode 100755 test/integration/rhel-7.7/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-7.7/cmdline-string.patch delete mode 100755 test/integration/rhel-7.7/data-new-LOADED.test delete mode 100644 test/integration/rhel-7.7/data-new.patch delete mode 100644 test/integration/rhel-7.7/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-7.7/fixup-section.patch delete mode 100644 test/integration/rhel-7.7/gcc-constprop.patch.disabled delete mode 100644 test/integration/rhel-7.7/gcc-isra.patch delete mode 100644 test/integration/rhel-7.7/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-7.7/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-7.7/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-7.7/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-7.7/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-7.7/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-7.7/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-7.7/macro-callbacks.patch delete mode 100644 test/integration/rhel-7.7/macro-printk.patch delete mode 100644 test/integration/rhel-7.7/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-7.7/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-7.7/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-7.7/meminfo-string.patch delete mode 100644 test/integration/rhel-7.7/module-call-external.patch delete mode 100755 test/integration/rhel-7.7/multiple.test delete mode 100644 test/integration/rhel-7.7/new-function.patch delete mode 100644 test/integration/rhel-7.7/new-globals.patch delete mode 100644 test/integration/rhel-7.7/parainstructions-section.patch delete mode 100755 test/integration/rhel-7.7/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-7.7/shadow-newpid.patch delete mode 100644 test/integration/rhel-7.7/smp-locks-section.patch delete mode 100644 test/integration/rhel-7.7/special-static.patch delete mode 100644 test/integration/rhel-7.7/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-7.7/tracepoints-section.patch delete mode 100644 test/integration/rhel-7.7/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-7.8/bug-table-section.patch delete mode 100755 test/integration/rhel-7.8/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-7.8/cmdline-string.patch delete mode 100755 test/integration/rhel-7.8/data-new-LOADED.test delete mode 100644 test/integration/rhel-7.8/data-new.patch delete mode 100644 test/integration/rhel-7.8/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-7.8/fixup-section.patch delete mode 100644 test/integration/rhel-7.8/gcc-constprop.patch.disabled delete mode 100644 test/integration/rhel-7.8/gcc-isra.patch delete mode 100644 test/integration/rhel-7.8/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-7.8/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-7.8/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-7.8/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-7.8/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-7.8/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-7.8/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-7.8/macro-callbacks.patch delete mode 100644 test/integration/rhel-7.8/macro-printk.patch delete mode 100644 test/integration/rhel-7.8/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-7.8/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-7.8/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-7.8/meminfo-string.patch delete mode 100644 test/integration/rhel-7.8/module-call-external.patch delete mode 100755 test/integration/rhel-7.8/multiple.test delete mode 100644 test/integration/rhel-7.8/new-function.patch delete mode 100644 test/integration/rhel-7.8/new-globals.patch delete mode 100644 test/integration/rhel-7.8/parainstructions-section.patch delete mode 100755 test/integration/rhel-7.8/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-7.8/shadow-newpid.patch delete mode 100644 test/integration/rhel-7.8/smp-locks-section.patch delete mode 100644 test/integration/rhel-7.8/special-static.patch delete mode 100644 test/integration/rhel-7.8/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-7.8/tracepoints-section.patch delete mode 100644 test/integration/rhel-7.8/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-7.9/bug-table-section.patch delete mode 100755 test/integration/rhel-7.9/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-7.9/cmdline-string.patch delete mode 100755 test/integration/rhel-7.9/data-new-LOADED.test delete mode 100644 test/integration/rhel-7.9/data-new.patch delete mode 100644 test/integration/rhel-7.9/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-7.9/fixup-section.patch delete mode 100644 test/integration/rhel-7.9/gcc-constprop.patch delete mode 100644 test/integration/rhel-7.9/gcc-isra.patch delete mode 100644 test/integration/rhel-7.9/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-7.9/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-7.9/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-7.9/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-7.9/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-7.9/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-7.9/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-7.9/macro-callbacks.patch delete mode 100644 test/integration/rhel-7.9/macro-printk.patch delete mode 100644 test/integration/rhel-7.9/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-7.9/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-7.9/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-7.9/meminfo-string.patch delete mode 100644 test/integration/rhel-7.9/module-call-external.patch delete mode 100755 test/integration/rhel-7.9/multiple.test delete mode 100644 test/integration/rhel-7.9/new-function.patch delete mode 100644 test/integration/rhel-7.9/new-globals.patch delete mode 100644 test/integration/rhel-7.9/parainstructions-section.patch delete mode 100755 test/integration/rhel-7.9/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-7.9/shadow-newpid.patch delete mode 100644 test/integration/rhel-7.9/smp-locks-section.patch delete mode 100644 test/integration/rhel-7.9/special-static.patch delete mode 100644 test/integration/rhel-7.9/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/rhel-7.9/syscall-LOADED.test delete mode 100644 test/integration/rhel-7.9/syscall.patch delete mode 100644 test/integration/rhel-7.9/tracepoints-section.patch delete mode 100644 test/integration/rhel-7.9/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.0/README delete mode 100644 test/integration/rhel-8.0/bug-table-section.patch delete mode 100755 test/integration/rhel-8.0/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.0/cmdline-string.patch delete mode 100755 test/integration/rhel-8.0/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.0/data-new.patch delete mode 100644 test/integration/rhel-8.0/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-8.0/fixup-section.patch delete mode 100644 test/integration/rhel-8.0/gcc-constprop.patch.disabled delete mode 100644 test/integration/rhel-8.0/gcc-isra.patch delete mode 100644 test/integration/rhel-8.0/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.0/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.0/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.0/gcc-static-local-var-4.patch.disabled delete mode 100755 test/integration/rhel-8.0/gcc-static-local-var-4.test.disabled delete mode 100644 test/integration/rhel-8.0/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.0/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.0/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.0/macro-printk.patch.disabled delete mode 100644 test/integration/rhel-8.0/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.0/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.0/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.0/meminfo-string.patch delete mode 100644 test/integration/rhel-8.0/module-call-external.patch delete mode 100755 test/integration/rhel-8.0/multiple.test delete mode 100644 test/integration/rhel-8.0/new-function.patch delete mode 100644 test/integration/rhel-8.0/new-globals.patch delete mode 100644 test/integration/rhel-8.0/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.0/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-8.0/shadow-newpid.patch.disabled delete mode 100644 test/integration/rhel-8.0/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.0/special-static.patch delete mode 100644 test/integration/rhel-8.0/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-8.0/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.0/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.1/bug-table-section.patch delete mode 100755 test/integration/rhel-8.1/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.1/cmdline-string.patch delete mode 100755 test/integration/rhel-8.1/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.1/data-new.patch delete mode 100644 test/integration/rhel-8.1/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-8.1/fixup-section.patch delete mode 100644 test/integration/rhel-8.1/gcc-constprop.patch.disabled delete mode 100644 test/integration/rhel-8.1/gcc-isra.patch delete mode 100644 test/integration/rhel-8.1/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.1/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.1/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.1/gcc-static-local-var-4.patch.disabled delete mode 100755 test/integration/rhel-8.1/gcc-static-local-var-4.test.disabled delete mode 100644 test/integration/rhel-8.1/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.1/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.1/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.1/macro-printk.patch.disabled delete mode 100644 test/integration/rhel-8.1/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.1/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.1/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.1/meminfo-string.patch delete mode 100755 test/integration/rhel-8.1/module-LOADED.test delete mode 100644 test/integration/rhel-8.1/module.patch delete mode 100755 test/integration/rhel-8.1/multiple.test delete mode 100644 test/integration/rhel-8.1/new-function.patch delete mode 100644 test/integration/rhel-8.1/new-globals.patch delete mode 100644 test/integration/rhel-8.1/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.1/shadow-newpid-LOADED.test.disabled delete mode 100644 test/integration/rhel-8.1/shadow-newpid.patch.disabled delete mode 100644 test/integration/rhel-8.1/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.1/special-static.patch.disabled delete mode 100644 test/integration/rhel-8.1/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-8.1/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.1/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.2/bug-table-section.patch delete mode 100755 test/integration/rhel-8.2/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.2/cmdline-string.patch delete mode 100755 test/integration/rhel-8.2/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.2/data-new.patch delete mode 100644 test/integration/rhel-8.2/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-8.2/fixup-section.patch delete mode 100644 test/integration/rhel-8.2/gcc-constprop.patch delete mode 100644 test/integration/rhel-8.2/gcc-isra.patch delete mode 100644 test/integration/rhel-8.2/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.2/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.2/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.2/gcc-static-local-var-4.patch.disabled delete mode 100755 test/integration/rhel-8.2/gcc-static-local-var-4.test.disabled delete mode 100644 test/integration/rhel-8.2/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.2/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.2/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.2/macro-printk.patch delete mode 100644 test/integration/rhel-8.2/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.2/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.2/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.2/meminfo-string.patch delete mode 100755 test/integration/rhel-8.2/module-LOADED.test delete mode 100644 test/integration/rhel-8.2/module.patch delete mode 100755 test/integration/rhel-8.2/multiple.test delete mode 100644 test/integration/rhel-8.2/new-function.patch delete mode 100644 test/integration/rhel-8.2/new-globals.patch delete mode 100644 test/integration/rhel-8.2/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.2/shadow-newpid-LOADED.test.disabled delete mode 100644 test/integration/rhel-8.2/shadow-newpid.patch.disabled delete mode 100644 test/integration/rhel-8.2/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.2/special-static.patch.disabled delete mode 100644 test/integration/rhel-8.2/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-8.2/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.2/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.3/bug-table-section.patch delete mode 100755 test/integration/rhel-8.3/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.3/cmdline-string.patch delete mode 100755 test/integration/rhel-8.3/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.3/data-new.patch delete mode 100644 test/integration/rhel-8.3/data-read-mostly.patch.disabled delete mode 100644 test/integration/rhel-8.3/fixup-section.patch delete mode 100644 test/integration/rhel-8.3/gcc-constprop.patch delete mode 100644 test/integration/rhel-8.3/gcc-isra.patch delete mode 100644 test/integration/rhel-8.3/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.3/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.3/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.3/gcc-static-local-var-4.patch.disabled delete mode 100755 test/integration/rhel-8.3/gcc-static-local-var-4.test.disabled delete mode 100644 test/integration/rhel-8.3/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.3/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.3/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.3/macro-printk.patch delete mode 100644 test/integration/rhel-8.3/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.3/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.3/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.3/meminfo-string.patch delete mode 100755 test/integration/rhel-8.3/module-LOADED.test delete mode 100644 test/integration/rhel-8.3/module.patch delete mode 100755 test/integration/rhel-8.3/multiple.test delete mode 100644 test/integration/rhel-8.3/new-function.patch delete mode 100644 test/integration/rhel-8.3/new-globals.patch delete mode 100644 test/integration/rhel-8.3/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.3/shadow-newpid-LOADED.test.disabled delete mode 100644 test/integration/rhel-8.3/shadow-newpid.patch.disabled delete mode 100644 test/integration/rhel-8.3/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.3/special-static.patch.disabled delete mode 100644 test/integration/rhel-8.3/symvers-disagreement-FAIL.patch delete mode 100644 test/integration/rhel-8.3/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.3/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.4/bug-table-section.patch delete mode 100755 test/integration/rhel-8.4/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.4/cmdline-string.patch delete mode 100755 test/integration/rhel-8.4/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.4/data-new.patch delete mode 100644 test/integration/rhel-8.4/data-read-mostly.patch delete mode 100644 test/integration/rhel-8.4/fixup-section.patch delete mode 100644 test/integration/rhel-8.4/gcc-constprop.patch delete mode 100644 test/integration/rhel-8.4/gcc-isra.patch delete mode 100644 test/integration/rhel-8.4/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.4/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.4/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.4/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-8.4/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-8.4/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.4/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.4/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.4/macro-printk.patch delete mode 100644 test/integration/rhel-8.4/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.4/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.4/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.4/meminfo-string.patch delete mode 100755 test/integration/rhel-8.4/module-LOADED.test delete mode 100644 test/integration/rhel-8.4/module.patch delete mode 100755 test/integration/rhel-8.4/multiple.test delete mode 100644 test/integration/rhel-8.4/new-function.patch delete mode 100644 test/integration/rhel-8.4/new-globals.patch delete mode 100644 test/integration/rhel-8.4/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.4/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-8.4/shadow-newpid.patch delete mode 100644 test/integration/rhel-8.4/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.4/special-static.patch delete mode 100644 test/integration/rhel-8.4/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/rhel-8.4/syscall-LOADED.test delete mode 100644 test/integration/rhel-8.4/syscall.patch delete mode 100644 test/integration/rhel-8.4/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.4/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.6/bug-table-section.patch delete mode 100755 test/integration/rhel-8.6/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.6/cmdline-string.patch delete mode 100755 test/integration/rhel-8.6/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.6/data-new.patch delete mode 100644 test/integration/rhel-8.6/data-read-mostly.patch delete mode 100644 test/integration/rhel-8.6/fixup-section.patch delete mode 100644 test/integration/rhel-8.6/gcc-constprop.patch delete mode 100644 test/integration/rhel-8.6/gcc-isra.patch delete mode 100644 test/integration/rhel-8.6/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.6/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.6/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.6/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-8.6/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-8.6/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.6/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.6/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.6/macro-printk.patch delete mode 100644 test/integration/rhel-8.6/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.6/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.6/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.6/meminfo-string.patch delete mode 100755 test/integration/rhel-8.6/module-LOADED.test delete mode 100644 test/integration/rhel-8.6/module.patch delete mode 100755 test/integration/rhel-8.6/multiple.test delete mode 100644 test/integration/rhel-8.6/new-function.patch delete mode 100644 test/integration/rhel-8.6/new-globals.patch delete mode 100644 test/integration/rhel-8.6/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.6/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-8.6/shadow-newpid.patch delete mode 100644 test/integration/rhel-8.6/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.6/special-static.patch delete mode 100644 test/integration/rhel-8.6/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/rhel-8.6/syscall-LOADED.test delete mode 100644 test/integration/rhel-8.6/syscall.patch delete mode 100644 test/integration/rhel-8.6/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.6/warn-detect-FAIL.patch delete mode 100644 test/integration/rhel-8.7/bug-table-section.patch delete mode 100755 test/integration/rhel-8.7/cmdline-string-LOADED.test delete mode 100644 test/integration/rhel-8.7/cmdline-string.patch delete mode 100755 test/integration/rhel-8.7/data-new-LOADED.test delete mode 100644 test/integration/rhel-8.7/data-new.patch delete mode 100644 test/integration/rhel-8.7/data-read-mostly.patch delete mode 100644 test/integration/rhel-8.7/fixup-section.patch delete mode 100644 test/integration/rhel-8.7/gcc-constprop.patch delete mode 100644 test/integration/rhel-8.7/gcc-isra.patch delete mode 100644 test/integration/rhel-8.7/gcc-mangled-3.patch delete mode 100644 test/integration/rhel-8.7/gcc-static-local-var-2.patch delete mode 100644 test/integration/rhel-8.7/gcc-static-local-var-3.patch delete mode 100644 test/integration/rhel-8.7/gcc-static-local-var-4.patch delete mode 100755 test/integration/rhel-8.7/gcc-static-local-var-4.test delete mode 100644 test/integration/rhel-8.7/gcc-static-local-var-5.patch delete mode 100644 test/integration/rhel-8.7/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-8.7/macro-callbacks.patch delete mode 100644 test/integration/rhel-8.7/macro-printk.patch delete mode 100644 test/integration/rhel-8.7/meminfo-init-FAIL.patch delete mode 100644 test/integration/rhel-8.7/meminfo-init2-FAIL.patch delete mode 100755 test/integration/rhel-8.7/meminfo-string-LOADED.test delete mode 100644 test/integration/rhel-8.7/meminfo-string.patch delete mode 100755 test/integration/rhel-8.7/module-LOADED.test delete mode 100644 test/integration/rhel-8.7/module.patch delete mode 100755 test/integration/rhel-8.7/multiple.test delete mode 100644 test/integration/rhel-8.7/new-function.patch delete mode 100644 test/integration/rhel-8.7/new-globals.patch delete mode 100644 test/integration/rhel-8.7/parainstructions-section.patch delete mode 100755 test/integration/rhel-8.7/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-8.7/shadow-newpid.patch delete mode 100644 test/integration/rhel-8.7/smp-locks-section.patch delete mode 100644 test/integration/rhel-8.7/special-static.patch delete mode 100644 test/integration/rhel-8.7/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/rhel-8.7/syscall-LOADED.test delete mode 100644 test/integration/rhel-8.7/syscall.patch delete mode 100644 test/integration/rhel-8.7/tracepoints-section.patch delete mode 100644 test/integration/rhel-8.7/warn-detect-FAIL.patch delete mode 100755 test/integration/rhel-9.0/data-new-LOADED.test delete mode 100644 test/integration/rhel-9.0/data-new.patch delete mode 100644 test/integration/rhel-9.0/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-9.0/macro-callbacks.patch delete mode 100755 test/integration/rhel-9.0/module-LOADED.test delete mode 100644 test/integration/rhel-9.0/module.patch delete mode 100755 test/integration/rhel-9.0/multiple.test delete mode 100644 test/integration/rhel-9.0/new-function.patch delete mode 100644 test/integration/rhel-9.0/new-globals.patch delete mode 100755 test/integration/rhel-9.0/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-9.0/shadow-newpid.patch delete mode 100644 test/integration/rhel-9.0/special-static.patch delete mode 100644 test/integration/rhel-9.0/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/rhel-9.0/syscall-LOADED.test delete mode 100644 test/integration/rhel-9.0/syscall.patch delete mode 100644 test/integration/rhel-9.0/warn-detect-FAIL.patch delete mode 100755 test/integration/rhel-9.1/data-new-LOADED.test delete mode 100644 test/integration/rhel-9.1/data-new.patch delete mode 100644 test/integration/rhel-9.1/gcc-static-local-var-6.patch delete mode 100644 test/integration/rhel-9.1/macro-callbacks.patch delete mode 100755 test/integration/rhel-9.1/module-LOADED.test delete mode 100644 test/integration/rhel-9.1/module.patch delete mode 100755 test/integration/rhel-9.1/multiple.test delete mode 100644 test/integration/rhel-9.1/new-function.patch delete mode 100644 test/integration/rhel-9.1/new-globals.patch delete mode 100755 test/integration/rhel-9.1/shadow-newpid-LOADED.test delete mode 100644 test/integration/rhel-9.1/shadow-newpid.patch delete mode 100644 test/integration/rhel-9.1/special-static.patch delete mode 100644 test/integration/rhel-9.1/symvers-disagreement-FAIL.patch delete mode 100755 test/integration/rhel-9.1/syscall-LOADED.test delete mode 100644 test/integration/rhel-9.1/syscall.patch delete mode 100644 test/integration/rhel-9.1/warn-detect-FAIL.patch delete mode 100755 test/integration/test-vagrant delete mode 100644 test/integration/ubuntu-16.04/README delete mode 100644 test/integration/ubuntu-16.04/bug-table-section.patch delete mode 100755 test/integration/ubuntu-16.04/cmdline-string-LOADED.test delete mode 100644 test/integration/ubuntu-16.04/cmdline-string.patch delete mode 100755 test/integration/ubuntu-16.04/data-new-LOADED.test delete mode 100644 test/integration/ubuntu-16.04/data-new.patch delete mode 100644 test/integration/ubuntu-16.04/data-read-mostly.patch delete mode 100644 test/integration/ubuntu-16.04/fixup-section.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-constprop.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-isra.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-mangled-3.patch.disabled delete mode 100644 test/integration/ubuntu-16.04/gcc-static-local-var-2.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-static-local-var-3.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-static-local-var-4.patch delete mode 100755 test/integration/ubuntu-16.04/gcc-static-local-var-4.test delete mode 100644 test/integration/ubuntu-16.04/gcc-static-local-var-5.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-static-local-var-6.patch delete mode 100644 test/integration/ubuntu-16.04/gcc-static-local-var.patch delete mode 100644 test/integration/ubuntu-16.04/macro-callbacks.patch delete mode 100644 test/integration/ubuntu-16.04/macro-printk.patch delete mode 100755 test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled delete mode 100644 test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW.patch.disabled delete mode 100644 test/integration/ubuntu-16.04/meminfo-init-FAIL.patch delete mode 100644 test/integration/ubuntu-16.04/meminfo-init2-FAIL.patch delete mode 100755 test/integration/ubuntu-16.04/meminfo-string-LOADED.test delete mode 100644 test/integration/ubuntu-16.04/meminfo-string.patch delete mode 100644 test/integration/ubuntu-16.04/module-call-external.patch.disable delete mode 100644 test/integration/ubuntu-16.04/module-kvm-fixup.patch delete mode 100755 test/integration/ubuntu-16.04/multiple.test delete mode 100644 test/integration/ubuntu-16.04/new-function.patch delete mode 100644 test/integration/ubuntu-16.04/new-globals.patch delete mode 100644 test/integration/ubuntu-16.04/parainstructions-section.patch delete mode 100644 test/integration/ubuntu-16.04/replace-section-references.patch delete mode 100644 test/integration/ubuntu-16.04/smp-locks-section.patch delete mode 100644 test/integration/ubuntu-16.04/special-static-2.patch delete mode 100644 test/integration/ubuntu-16.04/special-static.patch delete mode 100644 test/integration/ubuntu-16.04/tracepoints-section.patch delete mode 100644 test/integration/ubuntu-16.04/warn-detect-FAIL.patch delete mode 100755 test/integration/vm-integration-run delete mode 100644 test/test-functions.sh delete mode 100644 test/unit/Makefile delete mode 100644 test/unit/Makefile.include create mode 100644 v0.9.9.tar.gz diff --git a/0001-kpatch-don-t-need-vmlinux.patch b/0001-kpatch-don-t-need-vmlinux.patch new file mode 100644 index 0000000..288db31 --- /dev/null +++ b/0001-kpatch-don-t-need-vmlinux.patch @@ -0,0 +1,79 @@ +From 02ccca667a5d7343ffee7b4c4a01a7dc2db91c8f Mon Sep 17 00:00:00 2001 +From: yinbinbin +Date: Wed, 9 Nov 2022 20:25:28 +0800 +Subject: [PATCH] kpatch:don't need vmlinux + +Signed-off-by: yinbinbin + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 5a60191..f03d4cd 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -271,9 +271,14 @@ find_core_symvers() { + } + + gcc_version_from_file() { +- "$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*' ++ "$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*'| awk '{$1=$2=""; print $0}'|awk '{gsub(/^\s+|\s+$/, "");print}' + } + ++gcc_version_from_config() { ++ if [[ -n "$CONFIGFILE" ]]; then ++ cat "$CONFIGFILE" | grep -w "Compiler: gcc" | awk '{$1=$2=$3=$4=""; print $0}' | awk '{gsub(/^\s+|\s+$/, "");print}' ++ fi ++} + gcc_version_check() { + local target="$1" + local c="$TEMPDIR/test.c" o="$TEMPDIR/test.o" +@@ -284,7 +289,11 @@ gcc_version_check() { + echo 'void main(void) {}' > "$c" + out="$("$GCC" -c -pg -ffunction-sections -o "$o" "$c" 2>&1)" + gccver="$(gcc_version_from_file "$o")" ++ if [[ -f "$target" ]]; then + kgccver="$(gcc_version_from_file "$target")" ++ else ++ kgccver="$(gcc_version_from_config)" ++ fi + + if [[ -n "$out" ]]; then + warn "gcc >= 4.8 required for -pg -ffunction-settings" +@@ -806,8 +815,6 @@ if [[ -n "$USERSRCDIR" ]]; then + KERNEL_SRCDIR="$USERSRCDIR" + + [[ -z "$VMLINUX" ]] && VMLINUX="$KERNEL_SRCDIR"/vmlinux +- [[ ! -e "$VMLINUX" ]] && die "can't find vmlinux" +- + # Extract the target kernel version from vmlinux in this case. + VMLINUX_VER="$(strings "$VMLINUX" | grep -m 1 -e "^Linux version" | awk '{ print($3); }')" + if [[ -n "$ARCHVERSION" ]]; then +@@ -815,7 +822,7 @@ if [[ -n "$USERSRCDIR" ]]; then + die "Kernel version mismatch: $ARCHVERSION was specified but vmlinux was built for $VMLINUX_VER" + fi + else +- if [[ -z "$VMLINUX_VER" ]]; then ++ if [[ -z "$VMLINUX_VER" ]] && [[ -f "$VMLINUX" ]]; then + die "Unable to determine the kernel version from vmlinux" + fi + ARCHVERSION="$VMLINUX_VER" +@@ -1093,8 +1100,6 @@ fi + export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \ + $ARCH_KCFLAGS $DEBUG_KCFLAGS" + +-echo "Reading special section data" +-find_special_section_data + + if [[ $DEBUG -ge 4 ]]; then + export KPATCH_GCC_DEBUG=1 +@@ -1126,6 +1131,9 @@ fi + # shellcheck disable=SC2086 + make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die + ++echo "Reading special section data" ++find_special_section_data ++ + # Save original module symvers + cp -f "$BUILDDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die + +-- +2.37.3 + diff --git a/0002-kpatch-build-fix-some-subfunction-.cold-change-error.patch b/0002-kpatch-build-fix-some-subfunction-.cold-change-error.patch new file mode 100644 index 0000000..1904b69 --- /dev/null +++ b/0002-kpatch-build-fix-some-subfunction-.cold-change-error.patch @@ -0,0 +1,23 @@ +From b8716da7bec0a7edb51c104e2cd54a5a0f818442 Mon Sep 17 00:00:00 2001 +From: yinbinbin +Date: Fri, 11 Nov 2022 14:00:13 +0800 +Subject: [PATCH] kpatch-build: fix some subfunction *.cold change error + +Signed-off-by: yinbinbin + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index f03d4cd..f2b6fab 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -1097,7 +1097,7 @@ if [[ "$ARCH" = "s390x" ]]; then + ARCH_KCFLAGS="-mno-pic-data-is-text-relative -fno-section-anchors" + fi + +-export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \ ++export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections -fno-reorder-functions \ + $ARCH_KCFLAGS $DEBUG_KCFLAGS" + + +-- +2.37.3 + diff --git a/0003-kpatch-get-gcc-version-from-config-file.patch b/0003-kpatch-get-gcc-version-from-config-file.patch new file mode 100644 index 0000000..f238169 --- /dev/null +++ b/0003-kpatch-get-gcc-version-from-config-file.patch @@ -0,0 +1,52 @@ +From 7864b1f138641fef716a4374be6c8c64a415c110 Mon Sep 17 00:00:00 2001 +From: RobinYin +Date: Mon, 14 Nov 2022 21:13:24 +0800 +Subject: [PATCH] kpatch:get gcc version from config file + +Signed-off-by: RobinYin + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index f2b6fab..2f8f55d 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -271,14 +271,23 @@ find_core_symvers() { + } + + gcc_version_from_file() { +- "$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*'| awk '{$1=$2=""; print $0}'|awk '{gsub(/^\s+|\s+$/, "");print}' ++ "$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*'| cut -d ' ' -f 3- + } + + gcc_version_from_config() { +- if [[ -n "$CONFIGFILE" ]]; then +- cat "$CONFIGFILE" | grep -w "Compiler: gcc" | awk '{$1=$2=$3=$4=""; print $0}' | awk '{gsub(/^\s+|\s+$/, "");print}' ++ local gccver ++ if [[ -f "$CONFIGFILE" ]]; then ++ # Compiler: gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) ++ gccver="$(sed -n '/Compiler:/p' "$CONFIGFILE" | cut -d ' ' -f 5-)" ++ if [[ -z "$gccver" ]];then ++ #CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0" ++ gccver="$(sed -n '/CONFIG_CC_VERSION_TEXT/p' "$CONFIGFILE" | cut -d ' ' -f 3-)" ++ gccver=${gccver%\"*} ++ fi + fi ++ return "$gccver" + } ++ + gcc_version_check() { + local target="$1" + local c="$TEMPDIR/test.c" o="$TEMPDIR/test.o" +@@ -816,7 +825,9 @@ if [[ -n "$USERSRCDIR" ]]; then + + [[ -z "$VMLINUX" ]] && VMLINUX="$KERNEL_SRCDIR"/vmlinux + # Extract the target kernel version from vmlinux in this case. +- VMLINUX_VER="$(strings "$VMLINUX" | grep -m 1 -e "^Linux version" | awk '{ print($3); }')" ++ if [[ -f "$VMLINUX" ]]; then ++ VMLINUX_VER="$(strings "$VMLINUX" | grep -m 1 -e "^Linux version" | awk '{ print($3); }')" ++ fi + if [[ -n "$ARCHVERSION" ]]; then + if [[ -n "$VMLINUX_VER" ]] && [[ "$ARCHVERSION" != "$VMLINUX_VER" ]]; then + die "Kernel version mismatch: $ARCHVERSION was specified but vmlinux was built for $VMLINUX_VER" +-- +2.37.3 + diff --git a/0004-get-kernel-version-from-kpatch-build.patch b/0004-get-kernel-version-from-kpatch-build.patch new file mode 100644 index 0000000..58c2660 --- /dev/null +++ b/0004-get-kernel-version-from-kpatch-build.patch @@ -0,0 +1,39 @@ +From 854a17c0114201d216e5ce82e5b91f4890fb753c Mon Sep 17 00:00:00 2001 +From: yinbinbin +Date: Tue, 15 Nov 2022 14:21:59 +0800 +Subject: [PATCH] get kernel version from kpatch-build + +Signed-off-by: yinbinbin + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 2f8f55d..086d28b 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -285,7 +285,13 @@ gcc_version_from_config() { + gccver=${gccver%\"*} + fi + fi +- return "$gccver" ++ echo "$gccver" ++} ++ ++kernel_version_from_config() { ++ if [[ -f "$CONFIGFILE" ]]; then ++ sed -n '/Kernel Configuration/p' "$CONFIGFILE" | cut -d ' ' -f 3 ++ fi + } + + gcc_version_check() { +@@ -837,6 +843,9 @@ if [[ -n "$USERSRCDIR" ]]; then + die "Unable to determine the kernel version from vmlinux" + fi + ARCHVERSION="$VMLINUX_VER" ++ if [[ -z "$ARCHVERSION" ]] && [[ -f "$CONFIGFILE" ]]; then ++ ARCHVERSION="$(kernel_version_from_config)" ++ fi + fi + fi + +-- +2.37.3 + diff --git a/0005-kpatch-build-use-new-klp-arch.patch b/0005-kpatch-build-use-new-klp-arch.patch new file mode 100644 index 0000000..d1ab251 --- /dev/null +++ b/0005-kpatch-build-use-new-klp-arch.patch @@ -0,0 +1,54 @@ +From bfdcd08bd78620eb43fe800ce90bd28f07048b3e Mon Sep 17 00:00:00 2001 +From: yinbinbin +Date: Tue, 6 Dec 2022 16:52:37 +0800 +Subject: [PATCH] kpatch-build: use new klp arch + +Signed-off-by: yinbinbin + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 086d28b..fda9b2f 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -228,6 +228,11 @@ use_klp_arch() + fi + } + ++new_use_klp_arch() ++{ ++ "$READELF" -s --wide "$VMLINUX" | grep -w "arch_klp_init_object_loaded" ++} ++ + support_klp_replace() + { + if kernel_is_rhel; then +@@ -1043,12 +1048,6 @@ if [[ -n "$CONFIG_LIVEPATCH" ]] && (kernel_is_rhel || kernel_version_gte 4.9.0); + + USE_KLP=1 + +- if use_klp_arch; then +- USE_KLP_ARCH=1 +- KPATCH_LDFLAGS="--unique=.parainstructions --unique=.altinstructions" +- CDO_FLAGS="--klp-arch" +- fi +- + if [[ "$KLP_REPLACE" -eq 1 ]] ; then + support_klp_replace || die "The kernel doesn't support klp replace" + else +@@ -1151,6 +1150,14 @@ fi + # shellcheck disable=SC2086 + make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die + ++if [[ -n "$CONFIG_LIVEPATCH" ]]; then ++ if new_use_klp_arch; then ++ USE_KLP_ARCH=1 ++ KPATCH_LDFLAGS="--unique=.parainstructions --unique=.altinstructions" ++ CDO_FLAGS="--klp-arch" ++ fi ++fi ++ + echo "Reading special section data" + find_special_section_data + +-- +2.37.3 + diff --git a/0006-check-klp_register_patch-function-symbol.patch b/0006-check-klp_register_patch-function-symbol.patch new file mode 100644 index 0000000..1322ce7 --- /dev/null +++ b/0006-check-klp_register_patch-function-symbol.patch @@ -0,0 +1,40 @@ +From ab93f70982c7f86a520dcae2a27ce58857df811c Mon Sep 17 00:00:00 2001 +From: "zhangyongde.zyd" +Date: Thu, 18 Jan 2024 15:26:17 +0800 +Subject: [PATCH] kpatch-build: use new klp arch + + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 0831259..ae895c3 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -228,6 +228,11 @@ new_use_klp_arch() + "$READELF" -s --wide "$VMLINUX" | grep -w "arch_klp_init_object_loaded" + } + ++klp_register_patch() ++{ ++ "$READELF" -s --wide "$VMLINUX" | grep -w "klp_register_patch" ++} ++ + support_klp_replace() + { + if kernel_is_rhel; then +@@ -1237,7 +1242,13 @@ if [[ -n "$CONFIG_LIVEPATCH" ]]; then + USE_KLP_ARCH=1 + KPATCH_LDFLAGS="--unique=.parainstructions --unique=.altinstructions" + CDO_FLAGS="--klp-arch" +- fi ++ fi ++ if klp_register_patch; then ++ echo "use klp_register_patch" ++ else ++ echo "don't use klp_register_patch" ++ export CFLAGS_MODULE="$CFLAGS_MODULE -DHAVE_SIMPLE_ENABLE" ++ fi + fi + + echo "Reading special section data" +-- +2.37.3 + diff --git a/0007-kpatch-build-set-EXTRAVERSION.patch b/0007-kpatch-build-set-EXTRAVERSION.patch new file mode 100644 index 0000000..0cb0225 --- /dev/null +++ b/0007-kpatch-build-set-EXTRAVERSION.patch @@ -0,0 +1,26 @@ +From 91ca1a8c7f287a022d5768c1189a6b453910dfb6 Mon Sep 17 00:00:00 2001 +From: Jian Wen +Date: Fri, 3 Feb 2023 15:36:24 +0800 +Subject: [PATCH] kpatch-build: set EXTRAVERSION + +Adding the version string to the kernel Makefile EXTRAVERSION as +rpmbuild would do (minus the perl voodoo). + +Fixes: #1 +Signed-off-by: Jian Wen + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 8632434..2afb3a1 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -856,6 +856,7 @@ if [[ -n "$USERSRCDIR" ]]; then + if [[ -z "$ARCHVERSION" ]] && [[ -f "$CONFIGFILE" ]]; then + ARCHVERSION="$(kernel_version_from_config)" + fi ++ sed -i "s/^EXTRAVERSION.*/EXTRAVERSION = -${ARCHVERSION##*-}/" "$KERNEL_SRCDIR/Makefile" || die + fi + fi + +-- +2.37.3 + diff --git a/0008-devel-an-options-for-kpatch-module-build-mode.patch b/0008-devel-an-options-for-kpatch-module-build-mode.patch new file mode 100644 index 0000000..f7eda73 --- /dev/null +++ b/0008-devel-an-options-for-kpatch-module-build-mode.patch @@ -0,0 +1,48 @@ +From db174af76d67cfece3399528cb67105b467b951c Mon Sep 17 00:00:00 2001 +From: ydzhang +Date: Wed, 22 Feb 2023 18:50:19 +0800 +Subject: [PATCH] devel an options for kpatch module build mode + + +diff --git a/kmod/patch/patch-hook.c b/kmod/patch/patch-hook.c +index ff314d9..2b080a9 100644 +--- a/kmod/patch/patch-hook.c ++++ b/kmod/patch/patch-hook.c +@@ -17,7 +17,7 @@ + * 02110-1301, USA. + */ + +-#if IS_ENABLED(CONFIG_LIVEPATCH) ++#if IS_ENABLED(CONFIG_LIVEPATCH) && (USE_KLP == 1) + #include "livepatch-patch-hook.c" + #else + #include "kpatch-patch-hook.c" +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index 2afb3a1..766af98 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -1366,6 +1366,7 @@ if [[ "$USE_KLP" -eq 1 ]]; then + touch "$TEMPDIR"/patch/.output.o.cmd || die + else + # Add .kpatch.checksum for kpatch script ++ echo "Addind .kpatch.checksum" + md5sum ../patch/tmp_output.o | awk '{printf "%s\0", $1}' > checksum.tmp || die + "$OBJCOPY" --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly ../patch/tmp_output.o || die + rm -f checksum.tmp +@@ -1387,6 +1388,13 @@ KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \ + CROSS_COMPILE="$CROSS_COMPILE" + save_env + ++ ++if [[ $USE_KLP -eq 1 ]]; then ++ export CFLAGS_MODULE=$CFLAGS_MODULE" -DUSE_KLP=1" ++else ++ export CFLAGS_MODULE=$CFLAGS_MODULE" -DUSE_KLP=0" ++fi ++ + make "${MAKEVARS[@]}" 2>&1 | logger || die + + if [[ "$USE_KLP" -eq 1 ]]; then +-- +2.37.3 + diff --git a/0009-kpatch-build-add-DISTRO-anolis.patch b/0009-kpatch-build-add-DISTRO-anolis.patch new file mode 100644 index 0000000..26ca825 --- /dev/null +++ b/0009-kpatch-build-add-DISTRO-anolis.patch @@ -0,0 +1,39 @@ +From e5cd1f36baf92014d586058543a006e70979ca0a Mon Sep 17 00:00:00 2001 +From: "zhangyongde.zyd" +Date: Thu, 18 Jan 2024 15:35:31 +0800 +Subject: [PATCH] kpatch-build: add DISTRO anolis + + +diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build +index efee66c..66a4a96 100755 +--- a/kpatch-build/kpatch-build ++++ b/kpatch-build/kpatch-build +@@ -905,7 +905,7 @@ fi + + if [[ "$DISTRO" = fedora ]] || [[ "$DISTRO" = rhel ]] || [[ "$DISTRO" = ol ]] || + [[ "$DISTRO" = centos ]] || [[ "$DISTRO" = openEuler ]] || +- [[ "$DISTRO" = photon ]]; then ++ [[ "$DISTRO" = photon ]] || [[ "$DISTRO" = anolis ]]; then + + [[ -z "$VMLINUX" ]] && VMLINUX="/usr/lib/debug/lib/modules/$ARCHVERSION/vmlinux" + [[ -e "$VMLINUX" ]] || die "kernel-debuginfo-$ARCHVERSION not installed" +@@ -944,7 +944,7 @@ elif [[ -e "$KERNEL_SRCDIR"/.config ]] && [[ -e "$VERSIONFILE" ]] && [[ "$(cat " + echo "Using cache at $KERNEL_SRCDIR" + + else +- if [[ "$DISTRO" = fedora ]] || [[ "$DISTRO" = rhel ]] || [[ "$DISTRO" = ol ]] || [[ "$DISTRO" = centos ]] || [[ "$DISTRO" = openEuler ]] || [[ "$DISTRO" = photon ]]; then ++ if [[ "$DISTRO" = fedora ]] || [[ "$DISTRO" = rhel ]] || [[ "$DISTRO" = ol ]] || [[ "$DISTRO" = centos ]] || [[ "$DISTRO" = openEuler ]] || [[ "$DISTRO" = photon ]] || [[ "$DISTRO" = anolis ]]; then + + [[ "$DISTRO" = fedora ]] && echo "Fedora distribution detected" + [[ "$DISTRO" = rhel ]] && echo "RHEL distribution detected" +@@ -952,6 +952,7 @@ else + [[ "$DISTRO" = centos ]] && echo "CentOS distribution detected" + [[ "$DISTRO" = openEuler ]] && echo "OpenEuler distribution detected" + [[ "$DISTRO" = photon ]] && echo "Photon OS distribution detected" ++ [[ "$DISTRO" = anolis ]] && echo "Anolis distribution detected" + + clean_cache + +-- +2.37.3 + diff --git a/COPYING b/COPYING deleted file mode 100644 index d159169..0000000 --- a/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/Makefile b/Makefile deleted file mode 100644 index 37ab1e8..0000000 --- a/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -include Makefile.inc - -SUBDIRS = kpatch-build kpatch kmod man contrib -BUILD_DIRS = $(SUBDIRS:%=build-%) -INSTALL_DIRS = $(SUBDIRS:%=install-%) -UNINSTALL_DIRS = $(SUBDIRS:%=uninstall-%) -CLEAN_DIRS = $(SUBDIRS:%=clean-%) - -UNITTEST_DIR = test/unit -INTEGRATION_DIR = test/integration -CLEAN_DIRS += clean-$(UNITTEST_DIR) - -.PHONY: all dependencies install uninstall clean check unit -.PHONY: $(SUBDIRS) $(BUILD_DIRS) $(INSTALL_DIRS) $(CLEAN_DIRS) -.PHONY: integration integration-slow integration-quick -.PHONY: vagrant-integration-slow vagrant-integration-quick vagrant-integration -.PHONY: vagrant-install -.PHONY: help - - -all: $(BUILD_DIRS) -$(BUILD_DIRS): - $(MAKE) -C $(@:build-%=%) - -dependencies: SHELL:=/bin/bash -dependencies: - source test/integration/lib.sh && kpatch_dependencies - -install: $(INSTALL_DIRS) -$(INSTALL_DIRS): - $(MAKE) -C $(@:install-%=%) install - -uninstall: $(UNINSTALL_DIRS) -$(UNINSTALL_DIRS): - $(MAKE) -C $(@:uninstall-%=%) uninstall - -clean: $(CLEAN_DIRS) -$(CLEAN_DIRS): - $(MAKE) -C $(@:clean-%=%) clean - -unit: $(UNITTEST_DIR)/Makefile build-kpatch-build - $(MAKE) -C $(UNITTEST_DIR) - -integration: integration-quick - -integration-slow: $(INTEGRATION_DIR)/Makefile build-kpatch-build build-kpatch build-kmod - $(MAKE) -C $(INTEGRATION_DIR) slow - -integration-quick: $(INTEGRATION_DIR)/Makefile build-kpatch-build build-kpatch build-kmod - $(MAKE) -C $(INTEGRATION_DIR) quick - -vagrant-install: $(INTEGRATION_DIR)/lib.sh -ifneq ($(shell id -u), 0) - @echo "WARNING: This target is intended for use on freshly-installed machines/vms only." && \ - echo "Do not proceed unless you read $(INTEGRATION_DIR)/lib.sh and realise what this target does." && \ - echo "Press ctrl-c to abort, return to proceed." && \ - read -endif - source $(INTEGRATION_DIR)/lib.sh && kpatch_check_install_vagrant - -vagrant-integration: vagrant-integration-quick - -vagrant-integration-slow: - $(MAKE) -C $(INTEGRATION_DIR) vagrant-slow - -vagrant-integration-quick: - $(MAKE) -C $(INTEGRATION_DIR) vagrant-quick - -check: - shellcheck kpatch/kpatch kpatch-build/kpatch-build kpatch-build/kpatch-cc - shellcheck test/difftree.sh test/integration/kpatch-test \ - test/integration/lib.sh test/integration/rebase-patches \ - test/integration/test-vagrant \ - test/integration/vm-integration-run - -help: - @echo "kpatch Makefile" - @echo - @echo "Targets:" - @echo " make dependencies install build dependencies [1]" - @echo " make all build entire project" - @echo " make install install programs to system [1]" - @echo " make uninstall remove programs from system [1]" - @echo " make clean clean build files" - @echo - @echo "Test targets:" - @echo " make check run static code analyzers" - @echo " make integration build and run integration tests [2]" - @echo " make integration-slow build and run integration tests [2]" - @echo " make integration-quick build and run integration tests [2]" - @echo " make unit run unit tests" - @echo - @echo "[1] requires admin privileges" - @echo "[2] installs test kpatch kernel modules, run at your own risk" - @echo diff --git a/Makefile.inc b/Makefile.inc deleted file mode 100644 index 15049f3..0000000 --- a/Makefile.inc +++ /dev/null @@ -1,21 +0,0 @@ -SHELL = /bin/sh -CC = gcc - -INSTALL = /usr/bin/install - -ARCH = $(shell uname -m) - -PREFIX ?= /usr/local -LIBDIR ?= lib -LIBEXEC ?= libexec -BINDIR = $(DESTDIR)$(PREFIX)/bin -SBINDIR = $(DESTDIR)$(PREFIX)/sbin -MODULESDIR = $(DESTDIR)$(PREFIX)/$(LIBDIR)/kpatch -LIBEXECDIR = $(DESTDIR)$(PREFIX)/$(LIBEXEC)/kpatch -DATADIR = $(DESTDIR)$(PREFIX)/share/kpatch -MANDIR = $(DESTDIR)$(PREFIX)/share/man/man1 -SYSTEMDDIR = $(DESTDIR)$(PREFIX)/lib/systemd/system -UPSTARTDIR = $(DESTDIR)/etc/init - -.PHONY: all install clean -.DEFAULT: all diff --git a/README.md b/README.md index 5512b20..a7414e5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ X86,ARM64 #### 软件架构 软件架构说明 -![软件架构说明](image.png) +![输入图片说明](image.png) ## 安装教程 diff --git a/contrib/Makefile b/contrib/Makefile deleted file mode 100644 index 0b0eeeb..0000000 --- a/contrib/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../Makefile.inc - -all: - -install: all - $(INSTALL) -d $(SYSTEMDDIR) - $(INSTALL) -m 0644 kpatch.service $(SYSTEMDDIR) - sed -i 's~PREFIX~$(PREFIX)~' $(SYSTEMDDIR)/kpatch.service - $(INSTALL) -d $(UPSTARTDIR) - $(INSTALL) -m 0644 kpatch.conf $(UPSTARTDIR) - sed -i 's~PREFIX~$(PREFIX)~' $(UPSTARTDIR)/kpatch.conf - -uninstall: - $(RM) $(SYSTEMDDIR)/kpatch.service - $(RM) $(UPSTARTDIR)/kpatch.conf - -clean: diff --git a/contrib/kpatch.conf b/contrib/kpatch.conf deleted file mode 100644 index 560ce3d..0000000 --- a/contrib/kpatch.conf +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -# This upstart version lacks the ability of unloading modules with -# the "stop" directive, as upstart does not support a feature like -# systemd's RemainAfterExit option. - - -description "Apply kpatch kernel patches" - -start on runlevel [2345] # Roughly equivalent to multi-user.target - -# We are not a daemon -task - -# Emulating systemd's ConditionKernelCommandLine option. -pre-start script - if [[ -e /proc/cmdline ]] - then - grep -q "kpatch.enable=0" /proc/cmdline && exit 1 - else - dmesg | grep -q "Command line.*kpatch.enable=0" && exit 1 - fi - - exit 0 -end script - -# Main process (start) -exec PREFIX/sbin/kpatch load --all - diff --git a/contrib/kpatch.service b/contrib/kpatch.service deleted file mode 100644 index 6240256..0000000 --- a/contrib/kpatch.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description="Apply kpatch kernel patches" -ConditionKernelCommandLine=!kpatch.enable=0 -Before=network-pre.target -Wants=network-pre.target - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStart=PREFIX/sbin/kpatch load --all - -[Install] -WantedBy=multi-user.target diff --git a/contrib/kpatch.spec b/contrib/kpatch.spec deleted file mode 100644 index 96a2cac..0000000 --- a/contrib/kpatch.spec +++ /dev/null @@ -1,320 +0,0 @@ -# needed for the kernel specific module -%define KVER %(uname -r) - -# Don't build kpatch kernel module by default -%bcond_with kpatch_mod - -Name: kpatch -Summary: Dynamic kernel patching -Version: 0.9.7 -License: GPLv2 -Group: System Environment/Kernel -URL: http://github.com/dynup/kpatch -Release: 1%{?dist} -Source0: %{name}-%{version}.tar.gz - -Requires: kmod bash -BuildRequires: gcc kernel-devel elfutils elfutils-devel -%if %{with kpatch_mod} -BuildRequires: kernel-devel-uname-r = %{KVER} -BuildRequires: kernel-uname-r = %{KVER} -%endif -BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) - -%description -kpatch is a Linux dynamic kernel patching tool which allows you to patch a -running kernel without rebooting or restarting any processes. It enables -sysadmins to apply critical security patches to the kernel immediately, without -having to wait for long-running tasks to complete, users to log off, or -for scheduled reboot windows. It gives more control over up-time without -sacrificing security or stability. - - -%package runtime -Summary: Dynamic kernel patching -Buildarch: noarch -Provides: %{name} = %{version} -%description runtime -kpatch is a Linux dynamic kernel patching tool which allows you to patch a -running kernel without rebooting or restarting any processes. It enables -sysadmins to apply critical security patches to the kernel immediately, without -having to wait for long-running tasks to complete, users to log off, or -for scheduled reboot windows. It gives more control over up-time without -sacrificing security or stability. - - -%package build -Requires: %{name} -Summary: Dynamic kernel patching -%description build -kpatch is a Linux dynamic kernel patching tool which allows you to patch a -running kernel without rebooting or restarting any processes. It enables -sysadmins to apply critical security patches to the kernel immediately, without -having to wait for long-running tasks to complete, users to log off, or -for scheduled reboot windows. It gives more control over up-time without -sacrificing security or stability. - -%if %{with kpatch_mod} -%package %{KVER} -Requires: %{name} -Summary: Dynamic kernel patching -%description %{KVER} -kpatch is a Linux dynamic kernel patching tool which allows you to patch a -running kernel without rebooting or restarting any processes. It enables -sysadmins to apply critical security patches to the kernel immediately, without -having to wait for long-running tasks to complete, users to log off, or -for scheduled reboot windows. It gives more control over up-time without -sacrificing security or stability. - -%endif - -%prep -%setup -q - -%build -make %{_smp_mflags} %{?with_kpatch_mod: BUILDMOD=yes KPATCH_BUILD=/lib/modules/%{KVER}/build} - -%install -rm -rf %{buildroot} - -make install PREFIX=/%{_usr} DESTDIR=%{buildroot} %{?with_kpatch_mod: BUILDMOD=yes KPATCH_BUILD=/lib/modules/%{KVER}/build} - -%clean -rm -rf %{buildroot} - -%files runtime -%defattr(-,root,root,-) -%doc COPYING README.md -%{_sbindir}/kpatch -%{_mandir}/man1/kpatch.1* -%{_usr}/lib/systemd/system/* -%{_sysconfdir}/init/kpatch.conf - -%if %{with kpatch_mod} -%files %{KVER} -%defattr(-,root,root,-) -%{_usr}/lib/kpatch/%{KVER} -%endif - -%files build -%defattr(-,root,root,-) -%{_bindir}/* -%{_libexecdir}/* -%{_datadir}/%{name} -%{_mandir}/man1/kpatch-build.1* - -%changelog -* Wed Sep 14 Yannick Cote - 0.9.7 -* S390x kpatch support -* Add support for openEuler + documentation (kpatch-build) -* Use err.h instead of error.h for musl support (kpatch-build) -* Add support for .return_sites section (kpatch-build x86) -* Create missing section symbol (kpatch-build) -* Fix symtab parsing lookup (kpatch-build) -* Many fixes and improvements in create-diff-object (kpatch-build) -* Unload already disabled modules (kpatch util) -* Add integration tests for: rhel-{8.6,9.0},5.18.0 (test) -* Add tests for patching a syscall (test) -* Combine and improve Fedora, CentOS with RHEL kpatch-build dependencies (test) -* Major revamp of README.md and documentation -* Add syscall patching macros (kmod) - -* Tue Apr 12 Joe Lawrence - 0.9.6 -* Allow OOT modules to be built with non-distro kernels -* Add cross-arch unit testing support -* Support ELF extended symbol section indexes -* Allow setting kernel version if --sourcedir and --vmlinux are used -* Cleanup and enhance __LINE__ macro detection for all arches -* Fix segfault on .LCx string literal symbols -* Include __dyndbg section when referenced by jump table -* Honor user provided KBUILD_EXTRA_SYMBOLS -* Support .retpoline_sites section -* Add native compiler selection via CROSS_COMPILE - -* Wed Oct 13 Artem Savkov - 0.9.5 -- openEuler support -- kpatch-build: Do not check KLP_REPLACE for kpatch.ko-based patches -- create-diff-object: fix use after free in kpatch-check-relocations() -- kpatch-build: Handle error in create-klp-module -- create-diff-object: support ppc64le relative jump labels -- kmod/patch: clean only rebuildable objs -- kpatch-build: save environment varibles to file - -* Wed Aug 25 Yannick Cote - 0.9.4 -- Support for multiple source files -- Makefile tweaks for handling non-replace kpatch building -- Support CONFIG_PRINTK_INDEX -- kpatch-build: set EXTRAVERSION and not localversion for RH kernels -- Make sure section symbols exist -- create-diff-object: Check that the section has a secsym -- kpatch: rmmod module of the same name before loading a module -- kpatch-build: enable option -R|--replace to build replace klp -- kpatch: use /sys/kernel/kpatch/ to check whether core module is loaded -- kpatch: Sync signal subcmd usage output with manpage -- fixes for the out-of-range relocation check - -* Tue Apr 20 Yannick Cote - 0.9.3 -- Initial support for clang compiler -- Add support for rhel-8.4 -- rhel-8.4: workaround pahole and extended ELF sections -- rhel-8.4: drop klp.arch support -- Kpatch command waits for module to fully unload -- Kpatch command informs user when signal subcommand is unnecessary -- kpatch-build skips ppc64le vdso files - -* Tue Sep 8 2020 Joe Lawrence - 0.9.2 -- Integration test support for rhel-{7.8,7.9,8.1,8.2}, centos-8 -- Better support for gcc child functions -- Batch jump label errors to report all instances -- Dynrela code cleanup -- Remove .klp.arch and add support for jump labels in v5.8+ kernels -- Mark ignored sections earlier to support functions missing ftrace hook -- Minor README.md improvements -- Add ppc64le mcount support to patched functions -- Show additional stalled process information in kpatch script -- Increased shellcheck coverage and fixes -- ppc64le plugin fixes for gcc v10 -- Ignore __UNIQUE_ID_ symbol from tristate config objects -- Don't clear dmesg during integration tests -- Detect and report MODVERSIONS symbol version CRC changes - -* Wed Mar 11 2020 Yannick Cote - 0.9.1 -- Handle ppc64le toc with only constants -- Don't strip callback section symbols -- Integration tests update -- Fix -Wconversion warnings -- Process debug sections last - -* Wed Mar 11 2020 Yannick Cote - 0.9.0 -- Many fixes in integration tests and adding rhel-8.0 -- Updates to documentation -- Many updates and additions to the patch author guide -- Fix to relocations used for ZERO_PAGE(0) -- Simplify static local variables correlation -- Make symvers reading code more flexible -- Free sections in elf teardown -- Fix kpatch-test module unloading -- Disable the build of kpatch.ko module by default -- Simplify mangled function correlation -- Use whole word filename matching in find_parent_obj() -- Simplify relocation processing - -* Wed Aug 21 2019 Artem Savkov - 0.8.0 -- kpatch.ko atomic replace fixes -- Fixes for potential problems found by covscan -- Remove manual signaling logic from kpatch utility -- Don't strip callback symbols -- Allow dynamic debug static keys - -* Wed Jul 24 2019 Josh Poimboeuf - 0.7.1 -- Fix several powerpc-specific bugs, including two which can result in kernel - panics -- Use rpmbuild --nodeps for installing srpm on Fedora/RHEL -- Fix inconsistent unit test failures for FAIL tests - -* Thu Jul 18 2019 Artem Savkov - 0.7.0 -- Multiple memory leak fixes in kpatch-build -- livepatch-patch-hook compatability fixes for kernels 5.1+ -- Making kpatch-build compatible with custom gcc names -- Added rhel-rebased integration tests -- kpatch.service will no longer unload modules on stop -- kpatch load will no longer fail if a module is already loaded and enabled -- kpatch-build will now check for *_fixup section changes on ppc64le and will - fail on such changes -- Add support for R_X86_64_PLT32 -- don't allow jump labels -- ppc64le-specific kpatch-build fixes - -* Fri Apr 12 2019 Joe Lawrence - 0.6.3 -- Lots of integration test work -- Better support for building out-of-tree modules -- Updated manpage options, drop deprecated distro specific mentions -- README.md updates for shadow variables, out-of-tree modules -- Fix core module compilation with CONFIG_HAVE_ARCH_PREL32_RELOCATIONS -- kpatch-build detects and abort on unsupported options - GCC_PLUGIN_LATENT_ENTROPY, GCC_PLUGIN_RANDSTRUCT -- Fix patch linking with 4.20+ -- Other minor shellcheck and kpatch-build fixups - -* Tue Oct 2 2018 Joe Lawrence - 0.6.2 -- ppc64le: relax .text section addralign value check -- gcc8: unit-tests -- gcc8: support parent/child symbol relations -- gcc8: handle functions changing subsection -- gcc8: consider ".text.hot" sections bundleable -- kpatch-build: bugfix for less aggressive clean build-cache -- ubuntu: remove "-signed" substring from the kernel source package name -- ubuntu: explicitly note elfutils dependency -- upstream 4.18: unit-tests -- upstream 4.18: KCFLAGS -mcount-record support support -- RHEL-8: don't care who provides yumdownloader -- RHEL-8: account for quirky SRPM / release name conventions - -* Tue May 29 2018 Joe Lawrence - 0.6.1 -- Increase the transition timeout, helpful for large CPU count systems -- Miscellaneous unit testing, ppc64, etc. fixes - -* Mon Apr 22 2018 Josh Poimboeuf - 0.6.0 -- Support and converted to livepatch-style hooks. -- Lots of misc bugfixes and cleanups -- Manpage, README.md fixups -- More PPC64 work -- "Undefined reference" build failure rework -- Livepatch disable retries -- New unit testing framework - -* Thu Dec 21 2017 Josh Poimboeuf - 0.5.0 -- Basic ppc64le support -- kpatch: load automatically signals stalled processes after a timeout -- kpatch: list shows stalled processes -- kpatch: signal signals stalled processes -- kpatch-build: multiple source patches can be combined into a single binary patch module -- kpatch-build: -n|--name option for giving a custom name to the patch module -- kpatch-build: additional -d options for more verbose debug modes -- The module prefix is now either livepatch- or kpatch- depending on the underlying patching technology - -* Mon Mar 13 2017 Josh Poimboeuf - 0.4.0 -- The tools underlying kpatch-build have been made more modular, in preparation for making create-diff-object more generally useful to other use cases (kernel livepatch, Xen live patching, user space patching). -- Support for all new upstream kernels up to 4.10. -- KASLR support. -- Many other bug fixes and improvements. - -* Thu Oct 11 2016 Jessica Yu - 0.3.4 -- bump version to 0.3.4 - -* Fri Aug 19 2016 Josh Poimboeuf - 0.3.3 -- bump version to 0.3.3 - -* Thu Feb 18 2016 Josh Poimboeuf - 0.3.2 -- bump version to 0.3.2 - -* Thu Nov 19 2015 Josh Poimboeuf - 0.3.1 -- Get kernel version from vmlinux if the kernel source tree is used - -* Wed Nov 18 2015 Josh Poimboeuf - 0.3.0 -- kpatch-build: fix gcc_version_check: both "GNU" and "GCC" are possible - -* Wed Dec 3 2014 Josh Poimboeuf - 0.2.2-1 -- rebased to current version - -* Tue Sep 2 2014 Josh Poimboeuf - 0.2.1-1 -- rebased to current version - -* Mon Jul 28 2014 Josh Poimboeuf - 0.1.9-1 -- moved core module to /usr/lib/kpatch -- rebased to current version - -* Mon Jul 07 2014 Udo Seidel - 0.1.7-1 -- rebased to current version - -* Sat May 24 2014 Udo Seidel - 0.1.1-1 -- rebased to current version - -* Thu Apr 10 2014 Udo Seidel - 0.0.1-3 -- added dracut module - -* Tue Mar 25 2014 Udo Seidel - 0.0.1-2 -- added man pages - -* Sat Mar 22 2014 Udo Seidel - 0.0.1-1 -- initial release diff --git a/examples/proc-version.patch b/examples/proc-version.patch deleted file mode 100644 index cb43236..0000000 --- a/examples/proc-version.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 64aff1ab8f9a9f5df06c998be73d4981b77e480d Mon Sep 17 00:00:00 2001 -From: Joe Lawrence -Date: Mon, 7 Nov 2022 08:21:58 -0500 -Subject: [PATCH] kpatch: modify /proc/version output -Content-type: text/plain - -This is a simple kpatch example that modifies version_proc_show() so -that the output of /proc/version will be prefixed by "kpatch ". - -Signed-off-by: Joe Lawrence ---- - fs/proc/version.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/fs/proc/version.c b/fs/proc/version.c -index 02e3c3cd4a9a..957faeea8f5c 100644 ---- a/fs/proc/version.c -+++ b/fs/proc/version.c -@@ -9,6 +9,7 @@ - - static int version_proc_show(struct seq_file *m, void *v) - { -+ seq_printf(m, "kpatch "); - seq_printf(m, linux_proc_banner, - utsname()->sysname, - utsname()->release, --- -2.26.3 - diff --git a/examples/tcp_cubic-better-follow-cubic-curve-converted.patch b/examples/tcp_cubic-better-follow-cubic-curve-converted.patch deleted file mode 100644 index f16e5ff..0000000 --- a/examples/tcp_cubic-better-follow-cubic-curve-converted.patch +++ /dev/null @@ -1,105 +0,0 @@ -The original patch changes the initialization of 'cubictcp' instance of -struct tcp_congestion_ops ('cubictcp.cwnd_event' field). Kpatch -intentionally rejects to process such changes. - -This modification of the patch uses Kpatch load/unload hooks to set -'cubictcp.cwnd_event' when the binary patch is loaded and reset it to NULL -when the patch is unloaded. - -It is still needed to check if changing that field could be problematic -due to concurrency issues, etc. - -'cwnd_event' callback is used only via tcp_ca_event() function. - -include/net/tcp.h: - -static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->cwnd_event) - icsk->icsk_ca_ops->cwnd_event(sk, event); -} - -In turn, tcp_ca_event() is called in a number of places in -net/ipv4/tcp_output.c and net/ipv4/tcp_input.c. - -One problem with this modification of the patch is that it may not be safe -to unload it. If it is possible for tcp_ca_event() to run concurrently with -the unloading of the patch, it may happen that 'icsk->icsk_ca_ops->cwnd_event' -is the address of bictcp_cwnd_event() when tcp_ca_event() checks it but is -set to NULL right after. So 'icsk->icsk_ca_ops->cwnd_event(sk, event)' would -result in a kernel oops. - -Whether such scenario is possible or not, it should be analyzed. If it is, -then at least, the body of tcp_ca_event() should be made atomic w.r.t. -changing 'cwnd_event' in the patch somehow. Perhaps, RCU could be suitable -for that: a read-side critical section for the body of tcp_ca_event() with -a single read of icsk->icsk_ca_ops->cwnd_event pointer with rcu_dereference(). -The pointer could be set by the patch with rcu_assign_pointer(). - -An alternative suggested by Josh Poimboeuf would be to patch the functions -that call 'cwnd_event' callback (tcp_ca_event() in this case) so that they -call bictcp_cwnd_event() directly when they detect the cubictcp struct [1]. - -Note that tcp_ca_event() is inlined in a number of places, so the binary -patch will provide replacements for all of the corresponding functions -rather than for just one. It is still needed to check if replacing these -functions in runtime is safe. - -References: -[1] https://www.redhat.com/archives/kpatch/2015-September/msg00005.html - -diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c -index 894b7ce..9bff8a0 100644 ---- a/net/ipv4/tcp_cubic.c -+++ b/net/ipv4/tcp_cubic.c -@@ -153,6 +153,27 @@ static void bictcp_init(struct sock *sk) - tcp_sk(sk)->snd_ssthresh = initial_ssthresh; - } - -+static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) -+{ -+ if (event == CA_EVENT_TX_START) { -+ struct bictcp *ca = inet_csk_ca(sk); -+ u32 now = tcp_time_stamp; -+ s32 delta; -+ -+ delta = now - tcp_sk(sk)->lsndtime; -+ -+ /* We were application limited (idle) for a while. -+ * Shift epoch_start to keep cwnd growth to cubic curve. -+ */ -+ if (ca->epoch_start && delta > 0) { -+ ca->epoch_start += delta; -+ if (after(ca->epoch_start, now)) -+ ca->epoch_start = now; -+ } -+ return; -+ } -+} -+ - /* calculate the cubic root of x using a table lookup followed by one - * Newton-Raphson iteration. - * Avg err ~= 0.195% -@@ -444,6 +465,20 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { - .name = "cubic", - }; - -+void kpatch_load_cubictcp_cwnd_event(void) -+{ -+ cubictcp.cwnd_event = bictcp_cwnd_event; -+} -+ -+void kpatch_unload_cubictcp_cwnd_event(void) -+{ -+ cubictcp.cwnd_event = NULL; -+} -+ -+#include "kpatch-macros.h" -+KPATCH_LOAD_HOOK(kpatch_load_cubictcp_cwnd_event); -+KPATCH_UNLOAD_HOOK(kpatch_unload_cubictcp_cwnd_event); -+ - static int __init cubictcp_register(void) - { - BUILD_BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE); diff --git a/examples/tcp_cubic-better-follow-cubic-curve-original.patch b/examples/tcp_cubic-better-follow-cubic-curve-original.patch deleted file mode 100644 index dacc89f..0000000 --- a/examples/tcp_cubic-better-follow-cubic-curve-original.patch +++ /dev/null @@ -1,58 +0,0 @@ -This patch is for 3.10.x. -It combines the following commits from the mainline: - -commit 30927520dbae297182990bb21d08762bcc35ce1d -Author: Eric Dumazet -Date: Wed Sep 9 21:55:07 2015 -0700 - - tcp_cubic: better follow cubic curve after idle period - -commit c2e7204d180f8efc80f27959ca9cf16fa17f67db -Author: Eric Dumazet -Date: Thu Sep 17 08:38:00 2015 -0700 - - tcp_cubic: do not set epoch_start in the future - -References: -http://www.phoronix.com/scan.php?page=news_item&px=Google-Fixes-TCP-Linux - -diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c -index 894b7ce..872b3a0 100644 ---- a/net/ipv4/tcp_cubic.c -+++ b/net/ipv4/tcp_cubic.c -@@ -153,6 +153,27 @@ static void bictcp_init(struct sock *sk) - tcp_sk(sk)->snd_ssthresh = initial_ssthresh; - } - -+static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) -+{ -+ if (event == CA_EVENT_TX_START) { -+ struct bictcp *ca = inet_csk_ca(sk); -+ u32 now = tcp_time_stamp; -+ s32 delta; -+ -+ delta = now - tcp_sk(sk)->lsndtime; -+ -+ /* We were application limited (idle) for a while. -+ * Shift epoch_start to keep cwnd growth to cubic curve. -+ */ -+ if (ca->epoch_start && delta > 0) { -+ ca->epoch_start += delta; -+ if (after(ca->epoch_start, now)) -+ ca->epoch_start = now; -+ } -+ return; -+ } -+} -+ - /* calculate the cubic root of x using a table lookup followed by one - * Newton-Raphson iteration. - * Avg err ~= 0.195% -@@ -439,6 +460,7 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { - .cong_avoid = bictcp_cong_avoid, - .set_state = bictcp_state, - .undo_cwnd = bictcp_undo_cwnd, -+ .cwnd_event = bictcp_cwnd_event, - .pkts_acked = bictcp_acked, - .owner = THIS_MODULE, - .name = "cubic", diff --git a/kmod/Makefile b/kmod/Makefile deleted file mode 100644 index 7b0aeed..0000000 --- a/kmod/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -include ../Makefile.inc -KPATCH_BUILD ?= /lib/modules/$(shell uname -r)/build -KERNELRELEASE := $(lastword $(subst /, , $(dir $(KPATCH_BUILD)))) - -all: clean -ifeq ($(BUILDMOD),yes) - $(MAKE) -C core -endif - -install: -ifeq ($(BUILDMOD),yes) - $(INSTALL) -d $(MODULESDIR)/$(KERNELRELEASE) - $(INSTALL) -m 644 core/kpatch.ko $(MODULESDIR)/$(KERNELRELEASE) - $(INSTALL) -m 644 core/Module.symvers $(MODULESDIR)/$(KERNELRELEASE) -endif - $(INSTALL) -d $(DATADIR)/patch - $(INSTALL) -m 644 patch/* $(DATADIR)/patch - -uninstall: -ifeq ($(BUILDMOD),yes) - $(RM) -R $(MODULESDIR) -endif - $(RM) -R $(DATADIR) - -clean: -ifeq ($(BUILDMOD),yes) - $(MAKE) -C core clean -endif diff --git a/kmod/core/Makefile b/kmod/core/Makefile deleted file mode 100644 index 93e8490..0000000 --- a/kmod/core/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# make rules -KPATCH_BUILD ?= /lib/modules/$(shell uname -r)/build -KERNELRELEASE := $(lastword $(subst /, , $(dir $(patsubst %/,%,$(KPATCH_BUILD))))) -THISDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) - -ifeq ($(wildcard $(KPATCH_BUILD)),) -$(error $(KPATCH_BUILD) doesn\'t exist. Try installing the kernel-devel-$(KERNELRELEASE) RPM or linux-headers-$(KERNELRELEASE) DEB.) -endif - -KPATCH_MAKE = $(MAKE) -C $(KPATCH_BUILD) M=$(THISDIR) - -kpatch.ko: core.c - $(KPATCH_MAKE) kpatch.ko - -all: kpatch.ko - -clean: - $(RM) -Rf .*.o.cmd .*.ko.cmd .tmp_versions *.o *.ko *.mod.c \ - Module.symvers - - -# kbuild rules -obj-m := kpatch.o -kpatch-y := core.o shadow.o diff --git a/kmod/core/core.c b/kmod/core/core.c deleted file mode 100644 index cc97ad0..0000000 --- a/kmod/core/core.c +++ /dev/null @@ -1,1334 +0,0 @@ -/* - * Copyright (C) 2014 Seth Jennings - * Copyright (C) 2013-2014 Josh Poimboeuf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -/* - * kpatch core module - * - * Patch modules register with this module to redirect old functions to new - * functions. - * - * For each function patched by the module we must: - * - Call stop_machine - * - Ensure that no task has the old function in its call stack - * - Add the new function address to kpatch_func_hash - * - * After that, each call to the old function calls into kpatch_ftrace_handler() - * which finds the new function in kpatch_func_hash table and updates the - * return instruction pointer so that ftrace will return to the new function. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "kpatch.h" - -#ifndef UTS_UBUNTU_RELEASE_ABI -#define UTS_UBUNTU_RELEASE_ABI 0 -#endif - -#if !defined(CONFIG_FUNCTION_TRACER) || \ - !defined(CONFIG_HAVE_FENTRY) || \ - !defined(CONFIG_MODULES) || \ - !defined(CONFIG_SYSFS) || \ - !defined(CONFIG_STACKTRACE) || \ - !defined(CONFIG_KALLSYMS_ALL) -#error "CONFIG_FUNCTION_TRACER, CONFIG_HAVE_FENTRY, CONFIG_MODULES, CONFIG_SYSFS, CONFIG_KALLSYMS_ALL kernel config options are required" -#endif - -#define KPATCH_HASH_BITS 8 -static DEFINE_HASHTABLE(kpatch_func_hash, KPATCH_HASH_BITS); - -static DEFINE_SEMAPHORE(kpatch_mutex); - -static LIST_HEAD(kpmod_list); - -static int kpatch_num_patched; - -struct kobject *kpatch_root_kobj; -EXPORT_SYMBOL_GPL(kpatch_root_kobj); - -struct kpatch_kallsyms_args { - const char *objname; - const char *name; - unsigned long addr; - unsigned long count; - unsigned long pos; -}; - -struct kpatch_apply_patch_args { - struct kpatch_module *kpmod; - bool replace; -}; - -/* this is a double loop, use goto instead of break */ -#define do_for_each_linked_func(kpmod, func) { \ - struct kpatch_object *_object; \ - list_for_each_entry(_object, &kpmod->objects, list) { \ - if (!kpatch_object_linked(_object)) \ - continue; \ - list_for_each_entry(func, &_object->funcs, list) { - -#define while_for_each_linked_func() \ - } \ - } \ -} - - -/* - * The kpatch core module has a state machine which allows for proper - * synchronization with kpatch_ftrace_handler() when it runs in NMI context. - * - * +-----------------------------------------------------+ - * | | - * | + - * v +---> KPATCH_STATE_SUCCESS - * KPATCH_STATE_IDLE +---> KPATCH_STATE_UPDATING | - * ^ +---> KPATCH_STATE_FAILURE - * | + - * | | - * +-----------------------------------------------------+ - * - * KPATCH_STATE_IDLE: No updates are pending. The func hash is valid, and the - * reader doesn't need to check func->op. - * - * KPATCH_STATE_UPDATING: An update is in progress. The reader must call - * kpatch_state_finish(KPATCH_STATE_FAILURE) before accessing the func hash. - * - * KPATCH_STATE_FAILURE: An update failed, and the func hash might be - * inconsistent (pending patched funcs might not have been removed yet). If - * func->op is KPATCH_OP_PATCH, then rollback to the previous version of the - * func. - * - * KPATCH_STATE_SUCCESS: An update succeeded, but the func hash might be - * inconsistent (pending unpatched funcs might not have been removed yet). If - * func->op is KPATCH_OP_UNPATCH, then rollback to the previous version of the - * func. - */ -enum { - KPATCH_STATE_IDLE, - KPATCH_STATE_UPDATING, - KPATCH_STATE_SUCCESS, - KPATCH_STATE_FAILURE, -}; -static atomic_t kpatch_state; - -static int (*kpatch_set_memory_rw)(unsigned long addr, int numpages); -static int (*kpatch_set_memory_ro)(unsigned long addr, int numpages); - -#define MAX_STACK_TRACE_DEPTH 64 -static unsigned long stack_entries[MAX_STACK_TRACE_DEPTH]; -static struct stack_trace trace = { - .max_entries = ARRAY_SIZE(stack_entries), - .entries = &stack_entries[0], -}; - -static inline void kpatch_state_idle(void) -{ - int state = atomic_read(&kpatch_state); - - WARN_ON(state != KPATCH_STATE_SUCCESS && state != KPATCH_STATE_FAILURE); - atomic_set(&kpatch_state, KPATCH_STATE_IDLE); -} - -static inline void kpatch_state_updating(void) -{ - WARN_ON(atomic_read(&kpatch_state) != KPATCH_STATE_IDLE); - atomic_set(&kpatch_state, KPATCH_STATE_UPDATING); -} - -/* If state is updating, change it to success or failure and return new state */ -static inline int kpatch_state_finish(int state) -{ - int result; - - WARN_ON(state != KPATCH_STATE_SUCCESS && state != KPATCH_STATE_FAILURE); - result = atomic_cmpxchg(&kpatch_state, KPATCH_STATE_UPDATING, state); - return result == KPATCH_STATE_UPDATING ? state : result; -} - -static struct kpatch_func *kpatch_get_func(unsigned long ip) -{ - struct kpatch_func *f; - - /* Here, we have to use rcu safe hlist because of NMI concurrency */ - hash_for_each_possible_rcu(kpatch_func_hash, f, node, ip) - if (f->old_addr == ip) - return f; - return NULL; -} - -static struct kpatch_func *kpatch_get_prev_func(struct kpatch_func *f, - unsigned long ip) -{ - hlist_for_each_entry_continue_rcu(f, node) - if (f->old_addr == ip) - return f; - return NULL; -} - -static inline bool kpatch_object_linked(struct kpatch_object *object) -{ - return object->mod || !strcmp(object->name, "vmlinux"); -} - -static inline int kpatch_compare_addresses(unsigned long stack_addr, - unsigned long func_addr, - unsigned long func_size, - const char *func_name) -{ - if (stack_addr >= func_addr && stack_addr < func_addr + func_size) { - pr_err("activeness safety check failed for %s\n", func_name); - return -EBUSY; - } - return 0; -} - -static int kpatch_backtrace_address_verify(struct kpatch_module *kpmod, - unsigned long address, - bool replace) -{ - struct kpatch_func *func; - int i; - int ret; - - /* check kpmod funcs */ - do_for_each_linked_func(kpmod, func) { - unsigned long func_addr, func_size; - const char *func_name; - struct kpatch_func *active_func; - - if (func->force) - continue; - - active_func = kpatch_get_func(func->old_addr); - if (!active_func) { - /* patching an unpatched func */ - func_addr = func->old_addr; - func_size = func->old_size; - func_name = func->name; - } else { - /* repatching or unpatching */ - func_addr = active_func->new_addr; - func_size = active_func->new_size; - func_name = active_func->name; - } - - ret = kpatch_compare_addresses(address, func_addr, - func_size, func_name); - if (ret) - return ret; - } while_for_each_linked_func(); - - /* in the replace case, need to check the func hash as well */ - if (replace) { - hash_for_each_rcu(kpatch_func_hash, i, func, node) { - if (func->op != KPATCH_OP_UNPATCH || func->force) - continue; - - ret = kpatch_compare_addresses(address, - func->new_addr, - func->new_size, - func->name); - if (ret) - return ret; - } - } - - return ret; -} - -/* - * Verify activeness safety, i.e. that none of the to-be-patched functions are - * on the stack of any task. - * - * This function is called from stop_machine() context. - */ -static int kpatch_verify_activeness_safety(struct kpatch_module *kpmod, - bool replace) -{ - struct task_struct *g, *t; - int i; - int ret = 0; - - /* Check the stacks of all tasks. */ - do_each_thread(g, t) { - - trace.nr_entries = 0; - save_stack_trace_tsk(t, &trace); - if (trace.nr_entries >= trace.max_entries) { - ret = -EBUSY; - pr_err("more than %u trace entries!\n", - trace.max_entries); - goto out; - } - - for (i = 0; i < trace.nr_entries; i++) { - if (trace.entries[i] == ULONG_MAX) - break; - ret = kpatch_backtrace_address_verify(kpmod, - trace.entries[i], - replace); - if (ret) - goto out; - } - - } while_each_thread(g, t); - -out: - if (ret) { - pr_err("PID: %d Comm: %.20s\n", t->pid, t->comm); - for (i = 0; i < trace.nr_entries; i++) { - if (trace.entries[i] == ULONG_MAX) - break; - pr_err(" [<%pK>] %pB\n", - (void *)trace.entries[i], - (void *)trace.entries[i]); - } - } - - return ret; -} - -static inline int pre_patch_callback(struct kpatch_object *object) -{ - int ret; - - if (kpatch_object_linked(object) && - object->pre_patch_callback) { - ret = (*object->pre_patch_callback)(object); - if (ret) { - object->callbacks_enabled = false; - return ret; - } - } - object->callbacks_enabled = true; - - return 0; -} - -static inline void post_patch_callback(struct kpatch_object *object) -{ - if (kpatch_object_linked(object) && - object->post_patch_callback && - object->callbacks_enabled) - (*object->post_patch_callback)(object); -} - -static inline void pre_unpatch_callback(struct kpatch_object *object) -{ - if (kpatch_object_linked(object) && - object->pre_unpatch_callback && - object->callbacks_enabled) - (*object->pre_unpatch_callback)(object); -} - -static inline void post_unpatch_callback(struct kpatch_object *object) -{ - if (kpatch_object_linked(object) && - object->post_unpatch_callback && - object->callbacks_enabled) - (*object->post_unpatch_callback)(object); -} - -/* Called from stop_machine */ -static int kpatch_apply_patch(void *data) -{ - struct kpatch_apply_patch_args *args = data; - struct kpatch_module *kpmod; - struct kpatch_func *func; - struct hlist_node *tmp; - struct kpatch_object *object; - int ret; - int i; - - kpmod = args->kpmod; - - ret = kpatch_verify_activeness_safety(kpmod, args->replace); - if (ret) { - kpatch_state_finish(KPATCH_STATE_FAILURE); - return ret; - } - - /* tentatively add the new funcs to the global func hash */ - do_for_each_linked_func(kpmod, func) { - hash_add_rcu(kpatch_func_hash, &func->node, func->old_addr); - } while_for_each_linked_func(); - - /* memory barrier between func hash add and state change */ - smp_wmb(); - - /* - * Check if any inconsistent NMI has happened while updating. If not, - * move to success state. - */ - ret = kpatch_state_finish(KPATCH_STATE_SUCCESS); - if (ret == KPATCH_STATE_FAILURE) { - pr_err("NMI activeness safety check failed\n"); - - /* Failed, we have to rollback patching process */ - do_for_each_linked_func(kpmod, func) { - hash_del_rcu(&func->node); - } while_for_each_linked_func(); - - return -EBUSY; - } - - /* - * The new patch has been applied successfully. Remove the functions - * provided by the replaced patches (if any) from hash, to make sure - * they will not be executed anymore. - */ - if (args->replace) { - hash_for_each_safe(kpatch_func_hash, i, tmp, func, node) { - if (func->op != KPATCH_OP_UNPATCH) - continue; - hash_del_rcu(&func->node); - } - } - - /* run any user-defined post-patch callbacks */ - list_for_each_entry(object, &kpmod->objects, list) - post_patch_callback(object); - - return 0; -} - -/* Called from stop_machine */ -static int kpatch_remove_patch(void *data) -{ - struct kpatch_module *kpmod = data; - struct kpatch_func *func; - struct kpatch_object *object; - int ret; - - ret = kpatch_verify_activeness_safety(kpmod, false); - if (ret) { - kpatch_state_finish(KPATCH_STATE_FAILURE); - return ret; - } - - /* run any user-defined pre-unpatch callbacks */ - list_for_each_entry(object, &kpmod->objects, list) - pre_unpatch_callback(object); - - /* Check if any inconsistent NMI has happened while updating */ - ret = kpatch_state_finish(KPATCH_STATE_SUCCESS); - if (ret == KPATCH_STATE_FAILURE) { - ret = -EBUSY; - goto err; - } - - /* Succeeded, remove all updating funcs from hash table */ - do_for_each_linked_func(kpmod, func) { - hash_del_rcu(&func->node); - } while_for_each_linked_func(); - - return 0; - -err: - /* undo pre-unpatch callbacks by calling post-patch counterparts */ - list_for_each_entry(object, &kpmod->objects, list) - post_patch_callback(object); - - return ret; -} - -/* - * This is where the magic happens. Update regs->ip to tell ftrace to return - * to the new function. - * - * If there are multiple patch modules that have registered to patch the same - * function, the last one to register wins, as it'll be first in the hash - * bucket. - */ -static void notrace -kpatch_ftrace_handler(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *fops, struct pt_regs *regs) -{ - struct kpatch_func *func; - int state; - - preempt_disable_notrace(); - - if (likely(!in_nmi())) - func = kpatch_get_func(ip); - else { - /* Checking for NMI inconsistency */ - state = kpatch_state_finish(KPATCH_STATE_FAILURE); - - /* no memory reordering between state and func hash read */ - smp_rmb(); - - func = kpatch_get_func(ip); - - if (likely(state == KPATCH_STATE_IDLE)) - goto done; - - if (state == KPATCH_STATE_SUCCESS) { - /* - * Patching succeeded. If the function was being - * unpatched, roll back to the previous version. - */ - if (func && func->op == KPATCH_OP_UNPATCH) - func = kpatch_get_prev_func(func, ip); - } else { - /* - * Patching failed. If the function was being patched, - * roll back to the previous version. - */ - if (func && func->op == KPATCH_OP_PATCH) - func = kpatch_get_prev_func(func, ip); - } - } -done: - if (func) - regs->ip = func->new_addr + MCOUNT_INSN_SIZE; - - preempt_enable_notrace(); -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0) -#define FTRACE_OPS_FL_IPMODIFY 0 -#endif - -static struct ftrace_ops kpatch_ftrace_ops __read_mostly = { - .func = kpatch_ftrace_handler, - .flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY, -}; - -static int kpatch_ftrace_add_func(unsigned long ip) -{ - int ret; - - /* check if any other patch modules have also patched this func */ - if (kpatch_get_func(ip)) - return 0; - - ret = ftrace_set_filter_ip(&kpatch_ftrace_ops, ip, 0, 0); - if (ret) { - pr_err("can't set ftrace filter at address 0x%lx\n", ip); - return ret; - } - - if (!kpatch_num_patched) { - ret = register_ftrace_function(&kpatch_ftrace_ops); - if (ret) { - pr_err("can't register ftrace handler\n"); - ftrace_set_filter_ip(&kpatch_ftrace_ops, ip, 1, 0); - return ret; - } - } - kpatch_num_patched++; - - return 0; -} - -static int kpatch_ftrace_remove_func(unsigned long ip) -{ - int ret; - - /* check if any other patch modules have also patched this func */ - if (kpatch_get_func(ip)) - return 0; - - if (kpatch_num_patched == 1) { - ret = unregister_ftrace_function(&kpatch_ftrace_ops); - if (ret) { - pr_err("can't unregister ftrace handler\n"); - return ret; - } - } - kpatch_num_patched--; - - ret = ftrace_set_filter_ip(&kpatch_ftrace_ops, ip, 1, 0); - if (ret) { - pr_err("can't remove ftrace filter at address 0x%lx\n", ip); - return ret; - } - - return 0; -} - -static int kpatch_kallsyms_callback(void *data, const char *name, - struct module *mod, - unsigned long addr) -{ - struct kpatch_kallsyms_args *args = data; - bool vmlinux = !strcmp(args->objname, "vmlinux"); - - if ((mod && vmlinux) || (!mod && !vmlinux)) - return 0; - - if (strcmp(args->name, name)) - return 0; - - if (!vmlinux && strcmp(args->objname, mod->name)) - return 0; - - args->addr = addr; - args->count++; - - /* - * Finish the search when the symbol is found for the desired position - * or the position is not defined for a non-unique symbol. - */ - if ((args->pos && (args->count == args->pos)) || - (!args->pos && (args->count > 1))) { - return 1; - } - - return 0; -} - -static int kpatch_find_object_symbol(const char *objname, const char *name, - unsigned long sympos, unsigned long *addr) -{ - struct kpatch_kallsyms_args args = { - .objname = objname, - .name = name, - .addr = 0, - .count = 0, - .pos = sympos, - }; - - mutex_lock(&module_mutex); - kallsyms_on_each_symbol(kpatch_kallsyms_callback, &args); - mutex_unlock(&module_mutex); - - /* - * Ensure an address was found. If sympos is 0, ensure symbol is unique; - * otherwise ensure the symbol position count matches sympos. - */ - if (args.addr == 0) - pr_err("symbol '%s' not found in symbol table\n", name); - else if (args.count > 1 && sympos == 0) { - pr_err("unresolvable ambiguity for symbol '%s' in object '%s'\n", - name, objname); - } else if (sympos != args.count && sympos > 0) { - pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n", - sympos, name, objname); - } else { - *addr = args.addr; - return 0; - } - - *addr = 0; - return -EINVAL; -} - -/* - * External symbols are located outside the parent object (where the parent - * object is either vmlinux or the kmod being patched). - */ -static int kpatch_find_external_symbol(const char *objname, const char *name, - unsigned long sympos, unsigned long *addr) - -{ - const struct kernel_symbol *sym; - - /* first, check if it's an exported symbol */ - preempt_disable(); - sym = find_symbol(name, NULL, NULL, true, true); - preempt_enable(); - if (sym) { -#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS - *addr = (unsigned long)offset_to_ptr(&sym->value_offset); -#else - *addr = sym->value; -#endif - return 0; - } - - /* otherwise check if it's in another .o within the patch module */ - return kpatch_find_object_symbol(objname, name, sympos, addr); -} - -static int kpatch_write_relocations(struct kpatch_module *kpmod, - struct kpatch_object *object) -{ - int ret, size, readonly = 0, numpages; - struct kpatch_dynrela *dynrela; - u64 loc, val; -#if (( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) ) || \ - ( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ - UTS_UBUNTU_RELEASE_ABI >= 7 ) \ - ) - unsigned long core = (unsigned long)kpmod->mod->core_layout.base; - unsigned long core_size = kpmod->mod->core_layout.size; -#else - unsigned long core = (unsigned long)kpmod->mod->module_core; - unsigned long core_size = kpmod->mod->core_size; -#endif - - list_for_each_entry(dynrela, &object->dynrelas, list) { - if (dynrela->external) - ret = kpatch_find_external_symbol(kpmod->mod->name, - dynrela->name, - dynrela->sympos, - &dynrela->src); - else - ret = kpatch_find_object_symbol(object->name, - dynrela->name, - dynrela->sympos, - &dynrela->src); - if (ret) { - pr_err("unable to find symbol '%s'\n", dynrela->name); - return ret; - } - - switch (dynrela->type) { - case R_X86_64_NONE: - continue; - case R_X86_64_PC32: - case R_X86_64_PLT32: - loc = dynrela->dest; - val = (u32)(dynrela->src + dynrela->addend - - dynrela->dest); - size = 4; - break; - case R_X86_64_32S: - loc = dynrela->dest; - val = (s32)dynrela->src + dynrela->addend; - size = 4; - break; - case R_X86_64_64: - loc = dynrela->dest; - val = dynrela->src + dynrela->addend; - size = 8; - break; - default: - pr_err("unsupported rela type %ld for source %s (0x%lx <- 0x%lx)\n", - dynrela->type, dynrela->name, dynrela->dest, - dynrela->src); - return -EINVAL; - } - - if (loc < core || loc >= core + core_size) { - pr_err("bad dynrela location 0x%llx for symbol %s\n", - loc, dynrela->name); - return -EINVAL; - } - - /* - * Skip it if the instruction to be relocated has been - * changed already (paravirt or alternatives may do this). - */ - if (memchr_inv((void *)loc, 0, size)) { - pr_notice("Skipped dynrela for %s (0x%lx <- 0x%lx): the instruction has been changed already.\n", - dynrela->name, dynrela->dest, dynrela->src); - pr_notice_once( -"This is not necessarily a bug but it may indicate in some cases " -"that the binary patch does not handle paravirt operations, alternatives or the like properly.\n"); - continue; - } - -#if defined(CONFIG_DEBUG_SET_MODULE_RONX) || defined(CONFIG_ARCH_HAS_SET_MEMORY) -#if (( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) ) || \ - ( LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ - UTS_UBUNTU_RELEASE_ABI >= 7 ) \ - ) - readonly = (loc < core + kpmod->mod->core_layout.ro_size); -#else - readonly = (loc < core + kpmod->mod->core_ro_size); -#endif -#endif - - numpages = (PAGE_SIZE - (loc & ~PAGE_MASK) >= size) ? 1 : 2; - - if (readonly) - kpatch_set_memory_rw(loc & PAGE_MASK, numpages); - - ret = probe_kernel_write((void *)loc, &val, size); - - if (readonly) - kpatch_set_memory_ro(loc & PAGE_MASK, numpages); - - if (ret) { - pr_err("write to 0x%llx failed for symbol %s\n", - loc, dynrela->name); - return ret; - } - } - - return 0; -} - -static int kpatch_unlink_object(struct kpatch_object *object) -{ - struct kpatch_func *func; - int ret; - - list_for_each_entry(func, &object->funcs, list) { - if (!func->old_addr) - continue; - ret = kpatch_ftrace_remove_func(func->old_addr); - if (ret) { - WARN(1, "can't unregister ftrace for address 0x%lx\n", - func->old_addr); - return ret; - } - } - - if (object->mod) { - module_put(object->mod); - object->mod = NULL; - } - - return 0; -} - -/* - * Link to a to-be-patched object in preparation for patching it. - * - * - Find the object module - * - Write patch module relocations which reference the object - * - Calculate the patched functions' addresses - * - Register them with ftrace - */ -static int kpatch_link_object(struct kpatch_module *kpmod, - struct kpatch_object *object) -{ - struct module *mod = NULL; - struct kpatch_func *func, *func_err = NULL; - int ret; - bool vmlinux = !strcmp(object->name, "vmlinux"); - - if (!vmlinux) { - mutex_lock(&module_mutex); - mod = find_module(object->name); - if (!mod) { - /* - * The module hasn't been loaded yet. We can patch it - * later in kpatch_module_notify(). - */ - mutex_unlock(&module_mutex); - return 0; - } - - /* should never fail because we have the mutex */ - WARN_ON(!try_module_get(mod)); - mutex_unlock(&module_mutex); - object->mod = mod; - } - - ret = kpatch_write_relocations(kpmod, object); - if (ret) - goto err_put; - - list_for_each_entry(func, &object->funcs, list) { - - /* lookup the old location */ - ret = kpatch_find_object_symbol(object->name, - func->name, - func->sympos, - &func->old_addr); - if (ret) { - func_err = func; - goto err_ftrace; - } - - /* add to ftrace filter and register handler if needed */ - ret = kpatch_ftrace_add_func(func->old_addr); - if (ret) { - func_err = func; - goto err_ftrace; - } - } - - return 0; - -err_ftrace: - list_for_each_entry(func, &object->funcs, list) { - if (func == func_err) - break; - WARN_ON(kpatch_ftrace_remove_func(func->old_addr)); - } -err_put: - if (!vmlinux) - module_put(mod); - return ret; -} - -static int kpatch_module_notify_coming(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct module *mod = data; - struct kpatch_module *kpmod; - struct kpatch_object *object; - struct kpatch_func *func; - int ret = 0; - bool found = false; - - if (action != MODULE_STATE_COMING) - return 0; - - down(&kpatch_mutex); - - list_for_each_entry(kpmod, &kpmod_list, list) { - list_for_each_entry(object, &kpmod->objects, list) { - if (kpatch_object_linked(object)) - continue; - if (!strcmp(object->name, mod->name)) { - found = true; - goto done; - } - } - } -done: - if (!found) - goto out; - - ret = kpatch_link_object(kpmod, object); - if (ret) - goto out; - - BUG_ON(!object->mod); - - pr_notice("patching newly loaded module '%s'\n", object->name); - - /* run user-defined pre-patch callback */ - ret = pre_patch_callback(object); - if (ret) { - pr_err("pre-patch callback failed!\n"); - goto out; /* and WARN */ - } - - /* add to the global func hash */ - list_for_each_entry(func, &object->funcs, list) - hash_add_rcu(kpatch_func_hash, &func->node, func->old_addr); - - /* run user-defined post-patch callback */ - post_patch_callback(object); -out: - up(&kpatch_mutex); - - /* no way to stop the module load on error */ - WARN(ret, "error (%d) patching newly loaded module '%s'\n", ret, - object->name); - - return 0; -} - -static int kpatch_module_notify_going(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct module *mod = data; - struct kpatch_module *kpmod; - struct kpatch_object *object; - struct kpatch_func *func; - bool found = false; - - if (action != MODULE_STATE_GOING) - return 0; - - down(&kpatch_mutex); - - list_for_each_entry(kpmod, &kpmod_list, list) { - list_for_each_entry(object, &kpmod->objects, list) { - if (!kpatch_object_linked(object)) - continue; - if (!strcmp(object->name, mod->name)) { - found = true; - goto done; - } - } - } -done: - if (!found) - goto out; - - /* run user-defined pre-unpatch callback */ - pre_unpatch_callback(object); - - /* remove from the global func hash */ - list_for_each_entry(func, &object->funcs, list) - hash_del_rcu(&func->node); - - /* run user-defined pre-unpatch callback */ - post_unpatch_callback(object); - - kpatch_unlink_object(object); - -out: - up(&kpatch_mutex); - - return 0; -} - -/* - * Remove the obsolete functions from the ftrace filter. - * Return 1 if one or more of such functions have 'force' flag set, - * 0 otherwise. - */ -static int kpatch_ftrace_remove_unpatched_funcs(void) -{ - struct kpatch_module *kpmod; - struct kpatch_func *func; - int force = 0; - - list_for_each_entry(kpmod, &kpmod_list, list) { - do_for_each_linked_func(kpmod, func) { - if (func->op != KPATCH_OP_UNPATCH) - continue; - if (func->force) - force = 1; - WARN_ON(kpatch_ftrace_remove_func(func->old_addr)); - } while_for_each_linked_func(); - } - - return force; -} - -int kpatch_register(struct kpatch_module *kpmod, bool replace) -{ - int ret, i; - struct kpatch_object *object, *object_err = NULL; - struct kpatch_func *func; - - struct kpatch_apply_patch_args args = { - .kpmod = kpmod, - .replace = replace, - }; - - if (!kpmod->mod || list_empty(&kpmod->objects)) - return -EINVAL; - - down(&kpatch_mutex); - - if (kpmod->enabled) { - ret = -EINVAL; - goto err_up; - } - - list_add_tail(&kpmod->list, &kpmod_list); - - if (!try_module_get(kpmod->mod)) { - ret = -ENODEV; - goto err_list; - } - - list_for_each_entry(object, &kpmod->objects, list) { - - ret = kpatch_link_object(kpmod, object); - if (ret) { - object_err = object; - goto err_unlink; - } - - if (!kpatch_object_linked(object)) { - pr_notice("delaying patch of unloaded module '%s'\n", - object->name); - continue; - } - - if (strcmp(object->name, "vmlinux")) - pr_notice("patching module '%s'\n", object->name); - - list_for_each_entry(func, &object->funcs, list) - func->op = KPATCH_OP_PATCH; - } - - if (replace) - hash_for_each_rcu(kpatch_func_hash, i, func, node) - func->op = KPATCH_OP_UNPATCH; - - /* memory barrier between func hash and state write */ - smp_wmb(); - - kpatch_state_updating(); - - /* run any user-defined pre-patch callbacks */ - list_for_each_entry(object, &kpmod->objects, list) { - ret = pre_patch_callback(object); - if(ret){ - pr_err("pre-patch callback failed!\n"); - kpatch_state_finish(KPATCH_STATE_FAILURE); - break; - } - } - - /* if pre_patch_callback succeed. */ - if (!ret) { - /* - * Idle the CPUs, verify activeness safety, and atomically make the new - * functions visible to the ftrace handler. - */ - ret = stop_machine(kpatch_apply_patch, &args, NULL); - } - - /* if pre_patch_callback or stop_machine failed */ - if (ret) { - list_for_each_entry(object, &kpmod->objects, list) - post_unpatch_callback(object); - } - - /* - * For the replace case, remove any obsolete funcs from the ftrace - * filter, and disable the owning patch module so that it can be - * removed. - */ - if (!ret && replace) { - struct kpatch_module *kpmod2, *safe; - int force; - - force = kpatch_ftrace_remove_unpatched_funcs(); - - list_for_each_entry_safe(kpmod2, safe, &kpmod_list, list) { - if (kpmod == kpmod2) - continue; - - kpmod2->enabled = false; - pr_notice("unloaded patch module '%s'\n", - kpmod2->mod->name); - - /* - * Don't allow modules with forced functions to be - * removed because they might still be in use. - */ - if (!force) - module_put(kpmod2->mod); - - list_del(&kpmod2->list); - } - } - - - /* memory barrier between func hash and state write */ - smp_wmb(); - - /* NMI handlers can return to normal now */ - kpatch_state_idle(); - - /* - * Wait for all existing NMI handlers to complete so that they don't - * see any changes to funcs or funcs->op that might occur after this - * point. - * - * Any NMI handlers starting after this point will see the IDLE state. - */ - synchronize_rcu(); - - if (ret) - goto err_ops; - - do_for_each_linked_func(kpmod, func) { - func->op = KPATCH_OP_NONE; - } while_for_each_linked_func(); - -/* HAS_MODULE_TAINT - upstream 2992ef29ae01 "livepatch/module: make TAINT_LIVEPATCH module-specific" */ -/* HAS_MODULE_TAINT_LONG - upstream 7fd8329ba502 "taint/module: Clean up global and module taint flags handling" */ -#ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 4) -# define HAS_MODULE_TAINT -# endif -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0) -# define HAS_MODULE_TAINT_LONG -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) -# define HAS_MODULE_TAINT -#endif - -#ifdef TAINT_LIVEPATCH - pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n"); - add_taint(TAINT_LIVEPATCH, LOCKDEP_STILL_OK); -# ifdef HAS_MODULE_TAINT_LONG - set_bit(TAINT_LIVEPATCH, &kpmod->mod->taints); -# elif defined(HAS_MODULE_TAINT) - kpmod->mod->taints |= (1 << TAINT_LIVEPATCH); -# endif -#else - pr_notice_once("tainting kernel with TAINT_USER\n"); - add_taint(TAINT_USER, LOCKDEP_STILL_OK); -#endif - - pr_notice("loaded patch module '%s'\n", kpmod->mod->name); - - kpmod->enabled = true; - - up(&kpatch_mutex); - return 0; - -err_ops: - if (replace) - hash_for_each_rcu(kpatch_func_hash, i, func, node) - func->op = KPATCH_OP_NONE; -err_unlink: - list_for_each_entry(object, &kpmod->objects, list) { - if (object == object_err) - break; - if (!kpatch_object_linked(object)) - continue; - WARN_ON(kpatch_unlink_object(object)); - } - module_put(kpmod->mod); -err_list: - list_del(&kpmod->list); -err_up: - up(&kpatch_mutex); - return ret; -} -EXPORT_SYMBOL(kpatch_register); - -int kpatch_unregister(struct kpatch_module *kpmod) -{ - struct kpatch_object *object; - struct kpatch_func *func; - int ret, force = 0; - - down(&kpatch_mutex); - - if (!kpmod->enabled) { - ret = -EINVAL; - goto out; - } - - do_for_each_linked_func(kpmod, func) { - func->op = KPATCH_OP_UNPATCH; - if (func->force) - force = 1; - } while_for_each_linked_func(); - - /* memory barrier between func hash and state write */ - smp_wmb(); - - kpatch_state_updating(); - - ret = stop_machine(kpatch_remove_patch, kpmod, NULL); - - if (!ret) { - /* run any user-defined post-unpatch callbacks */ - list_for_each_entry(object, &kpmod->objects, list) - post_unpatch_callback(object); - } - /* NMI handlers can return to normal now */ - kpatch_state_idle(); - - /* - * Wait for all existing NMI handlers to complete so that they don't - * see any changes to funcs or funcs->op that might occur after this - * point. - * - * Any NMI handlers starting after this point will see the IDLE state. - */ - synchronize_rcu(); - - if (ret) { - do_for_each_linked_func(kpmod, func) { - func->op = KPATCH_OP_NONE; - } while_for_each_linked_func(); - goto out; - } - - list_for_each_entry(object, &kpmod->objects, list) { - if (!kpatch_object_linked(object)) - continue; - ret = kpatch_unlink_object(object); - if (ret) - goto out; - } - - pr_notice("unloaded patch module '%s'\n", kpmod->mod->name); - - kpmod->enabled = false; - - /* - * Don't allow modules with forced functions to be removed because they - * might still be in use. - */ - if (!force) - module_put(kpmod->mod); - - list_del(&kpmod->list); - -out: - up(&kpatch_mutex); - return ret; -} -EXPORT_SYMBOL(kpatch_unregister); - - -static struct notifier_block kpatch_module_nb_coming = { - .notifier_call = kpatch_module_notify_coming, - .priority = INT_MIN, /* called last */ -}; -static struct notifier_block kpatch_module_nb_going = { - .notifier_call = kpatch_module_notify_going, - .priority = INT_MAX, /* called first */ -}; - -static int kpatch_init(void) -{ - int ret; - - kpatch_set_memory_rw = (void *)kallsyms_lookup_name("set_memory_rw"); - if (!kpatch_set_memory_rw) { - pr_err("can't find set_memory_rw symbol\n"); - return -ENXIO; - } - - kpatch_set_memory_ro = (void *)kallsyms_lookup_name("set_memory_ro"); - if (!kpatch_set_memory_ro) { - pr_err("can't find set_memory_ro symbol\n"); - return -ENXIO; - } - - kpatch_root_kobj = kobject_create_and_add("kpatch", kernel_kobj); - if (!kpatch_root_kobj) - return -ENOMEM; - - ret = register_module_notifier(&kpatch_module_nb_coming); - if (ret) - goto err_root_kobj; - ret = register_module_notifier(&kpatch_module_nb_going); - if (ret) - goto err_unregister_coming; - - return 0; - -err_unregister_coming: - WARN_ON(unregister_module_notifier(&kpatch_module_nb_coming)); -err_root_kobj: - kobject_put(kpatch_root_kobj); - return ret; -} - -static void kpatch_exit(void) -{ - rcu_barrier(); - - WARN_ON(kpatch_num_patched != 0); - WARN_ON(unregister_module_notifier(&kpatch_module_nb_coming)); - WARN_ON(unregister_module_notifier(&kpatch_module_nb_going)); - kobject_put(kpatch_root_kobj); -} - -module_init(kpatch_init); -module_exit(kpatch_exit); -MODULE_LICENSE("GPL"); diff --git a/kmod/core/kpatch.h b/kmod/core/kpatch.h deleted file mode 100644 index 36f021f..0000000 --- a/kmod/core/kpatch.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * kpatch.h - * - * Copyright (C) 2014 Seth Jennings - * Copyright (C) 2013-2014 Josh Poimboeuf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - * Contains the API for the core kpatch module used by the patch modules - */ - -#ifndef _KPATCH_H_ -#define _KPATCH_H_ - -#include -#include - -enum kpatch_op { - KPATCH_OP_NONE, - KPATCH_OP_PATCH, - KPATCH_OP_UNPATCH, -}; - -struct kpatch_func { - /* public */ - unsigned long new_addr; - unsigned long new_size; - unsigned long old_addr; - unsigned long old_size; - unsigned long sympos; - const char *name; - struct list_head list; - int force; - - /* private */ - struct hlist_node node; - enum kpatch_op op; - struct kobject kobj; -}; - -struct kpatch_dynrela { - unsigned long dest; - unsigned long src; - unsigned long type; - unsigned long sympos; - const char *name; - int addend; - int external; - struct list_head list; -}; - -struct kpatch_object { - struct list_head list; - const char *name; - struct list_head funcs; - struct list_head dynrelas; - - int (*pre_patch_callback)(struct kpatch_object *); - void (*post_patch_callback)(struct kpatch_object *); - void (*pre_unpatch_callback)(struct kpatch_object *); - void (*post_unpatch_callback)(struct kpatch_object *); - bool callbacks_enabled; - - /* private */ - struct module *mod; - struct kobject kobj; -}; - -struct kpatch_module { - /* public */ - struct module *mod; - struct list_head objects; - - /* public read-only */ - bool enabled; - - /* private */ - struct list_head list; - struct kobject kobj; -}; - -extern struct kobject *kpatch_root_kobj; - -extern int kpatch_register(struct kpatch_module *kpmod, bool replace); -extern int kpatch_unregister(struct kpatch_module *kpmod); - -extern void *kpatch_shadow_alloc(void *obj, char *var, size_t size, gfp_t gfp); -extern void kpatch_shadow_free(void *obj, char *var); -extern void *kpatch_shadow_get(void *obj, char *var); - -#endif /* _KPATCH_H_ */ diff --git a/kmod/core/shadow.c b/kmod/core/shadow.c deleted file mode 100644 index 627928a..0000000 --- a/kmod/core/shadow.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2014 Josh Poimboeuf - * Copyright (C) 2014 Seth Jennings - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -/* - * kpatch shadow variables - * - * These functions can be used to add new "shadow" fields to existing data - * structures. For example, to allocate a "newpid" variable associated with an - * instance of task_struct, and assign it a value of 1000: - * - * struct task_struct *tsk = current; - * int *newpid; - * newpid = kpatch_shadow_alloc(tsk, "newpid", sizeof(int), GFP_KERNEL); - * if (newpid) - * *newpid = 1000; - * - * To retrieve a pointer to the variable: - * - * struct task_struct *tsk = current; - * int *newpid; - * newpid = kpatch_shadow_get(tsk, "newpid"); - * if (newpid) - * printk("task newpid = %d\n", *newpid); // prints "task newpid = 1000" - * - * To free it: - * - * kpatch_shadow_free(tsk, "newpid"); - */ - -#include -#include -#include "kpatch.h" - -static DEFINE_HASHTABLE(kpatch_shadow_hash, 12); -static DEFINE_SPINLOCK(kpatch_shadow_lock); - -struct kpatch_shadow { - struct hlist_node node; - struct rcu_head rcu_head; - void *obj; - union { - char *var; /* assumed to be 4-byte aligned */ - unsigned long flags; - }; - void *data; -}; - -#define SHADOW_FLAG_INPLACE 0x1 -#define SHADOW_FLAG_RESERVED0 0x2 /* reserved for future use */ - -#define SHADOW_FLAG_MASK 0x3 -#define SHADOW_PTR_MASK (~(SHADOW_FLAG_MASK)) - -static inline void shadow_set_inplace(struct kpatch_shadow *shadow) -{ - shadow->flags |= SHADOW_FLAG_INPLACE; -} - -static inline int shadow_is_inplace(struct kpatch_shadow *shadow) -{ - return shadow->flags & SHADOW_FLAG_INPLACE; -} - -static inline char *shadow_var(struct kpatch_shadow *shadow) -{ - return (char *)((unsigned long)shadow->var & SHADOW_PTR_MASK); -} - -void *kpatch_shadow_alloc(void *obj, char *var, size_t size, gfp_t gfp) -{ - unsigned long flags; - struct kpatch_shadow *shadow; - - shadow = kmalloc(sizeof(*shadow), gfp); - if (!shadow) - return NULL; - - shadow->obj = obj; - - shadow->var = kstrdup(var, gfp); - if (!shadow->var) { - kfree(shadow); - return NULL; - } - - if (size <= sizeof(shadow->data)) { - shadow->data = &shadow->data; - shadow_set_inplace(shadow); - } else { - shadow->data = kmalloc(size, gfp); - if (!shadow->data) { - kfree(shadow->var); - kfree(shadow); - return NULL; - } - } - - spin_lock_irqsave(&kpatch_shadow_lock, flags); - hash_add_rcu(kpatch_shadow_hash, &shadow->node, (unsigned long)obj); - spin_unlock_irqrestore(&kpatch_shadow_lock, flags); - - return shadow->data; -} -EXPORT_SYMBOL_GPL(kpatch_shadow_alloc); - -static void kpatch_shadow_rcu_free(struct rcu_head *head) -{ - struct kpatch_shadow *shadow; - - shadow = container_of(head, struct kpatch_shadow, rcu_head); - - if (!shadow_is_inplace(shadow)) - kfree(shadow->data); - kfree(shadow_var(shadow)); - kfree(shadow); -} - -void kpatch_shadow_free(void *obj, char *var) -{ - unsigned long flags; - struct kpatch_shadow *shadow; - - spin_lock_irqsave(&kpatch_shadow_lock, flags); - - hash_for_each_possible(kpatch_shadow_hash, shadow, node, - (unsigned long)obj) { - if (shadow->obj == obj && !strcmp(shadow_var(shadow), var)) { - hash_del_rcu(&shadow->node); - spin_unlock_irqrestore(&kpatch_shadow_lock, flags); - call_rcu(&shadow->rcu_head, kpatch_shadow_rcu_free); - return; - } - } - - spin_unlock_irqrestore(&kpatch_shadow_lock, flags); -} -EXPORT_SYMBOL_GPL(kpatch_shadow_free); - -void *kpatch_shadow_get(void *obj, char *var) -{ - struct kpatch_shadow *shadow; - - rcu_read_lock(); - - hash_for_each_possible_rcu(kpatch_shadow_hash, shadow, node, - (unsigned long)obj) { - if (shadow->obj == obj && !strcmp(shadow_var(shadow), var)) { - rcu_read_unlock(); - if (shadow_is_inplace(shadow)) - return &(shadow->data); - - return shadow->data; - } - } - - rcu_read_unlock(); - - return NULL; -} -EXPORT_SYMBOL_GPL(kpatch_shadow_get); diff --git a/kmod/patch/Makefile b/kmod/patch/Makefile deleted file mode 100644 index bb4d49c..0000000 --- a/kmod/patch/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -KPATCH_BUILD ?= /lib/modules/$(shell uname -r)/build -KPATCH_MAKE = $(MAKE) -C $(KPATCH_BUILD) M=$(PWD) CFLAGS_MODULE='$(CFLAGS_MODULE)' -LDFLAGS += $(KPATCH_LDFLAGS) - -# object files that this Makefile can (re)build on its own -BUILDABLE_OBJS=$(filter-out output.o, $(wildcard *.o)) - -obj-m += $(KPATCH_NAME).o -ldflags-y += -T $(src)/kpatch.lds -targets += kpatch.lds - -$(KPATCH_NAME)-objs += patch-hook.o output.o - -all: $(KPATCH_NAME).ko - -$(KPATCH_NAME).ko: - $(KPATCH_MAKE) - -$(obj)/$(KPATCH_NAME).o: $(src)/kpatch.lds - -patch-hook.o: patch-hook.c kpatch-patch-hook.c livepatch-patch-hook.c - $(KPATCH_MAKE) patch-hook.o - -clean: - $(RM) -Rf .*.o.cmd .*.ko.cmd .tmp_versions $(BUILDABLE_OBJS) *.ko *.mod.c \ - Module.symvers diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h deleted file mode 100644 index 8e09702..0000000 --- a/kmod/patch/kpatch-macros.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef __KPATCH_MACROS_H_ -#define __KPATCH_MACROS_H_ - -#include -#include -#include -#include "kpatch-syscall.h" - -/* upstream 33def8498fdd "treewide: Convert macro and uses of __section(foo) to __section("foo")" */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) -# define __kpatch_section(section) __section(section) -#else -# define __kpatch_section(section) __section(#section) -#endif - -/* - * KPATCH_IGNORE_SECTION macro - * - * This macro is for ignoring sections that may change as a side effect of - * another change or might be a non-bundlable section; that is one that does - * not honor -ffunction-section and create a one-to-one relation from function - * symbol to section. - */ -#define KPATCH_IGNORE_SECTION(_sec) \ - char *__UNIQUE_ID(kpatch_ignore_section_) __kpatch_section(.kpatch.ignore.sections) = _sec; - -/* - * KPATCH_IGNORE_FUNCTION macro - * - * This macro is for ignoring functions that may change as a side effect of a - * change in another function. The WARN class of macros, for example, embed - * the line number in an instruction, which will cause the function to be - * detected as changed when, in fact, there has been no functional change. - */ -#define KPATCH_IGNORE_FUNCTION(_fn) \ - void *__kpatch_ignore_func_##_fn __kpatch_section(.kpatch.ignore.functions) = _fn; - - -/* Support for livepatch callbacks */ -#if IS_ENABLED(CONFIG_LIVEPATCH) -# ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 5) -# define HAS_LIVEPATCH_CALLBACKS -# endif -# elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -# define HAS_LIVEPATCH_CALLBACKS -# endif -#endif - -#ifdef HAS_LIVEPATCH_CALLBACKS -# include -typedef struct klp_object patch_object; -#else -# include "kpatch.h" -typedef struct kpatch_object patch_object; -#endif /* HAS_LIVEPATCH_CALLBACKS */ - -typedef int (*kpatch_pre_patch_call_t)(patch_object *obj); -typedef void (*kpatch_post_patch_call_t)(patch_object *obj); -typedef void (*kpatch_pre_unpatch_call_t)(patch_object *obj); -typedef void (*kpatch_post_unpatch_call_t)(patch_object *obj); - -struct kpatch_pre_patch_callback { - kpatch_pre_patch_call_t fn; - char *objname; /* filled in by create-diff-object */ -}; - -struct kpatch_post_patch_callback { - kpatch_post_patch_call_t fn; - char *objname; /* filled in by create-diff-object */ -}; - -struct kpatch_pre_unpatch_callback { - kpatch_pre_unpatch_call_t fn; - char *objname; /* filled in by create-diff-object */ -}; - -struct kpatch_post_unpatch_callback { - kpatch_post_unpatch_call_t fn; - char *objname; /* filled in by create-diff-object */ -}; - - -#define KPATCH_PRE_PATCH_CALLBACK(_fn) \ - static inline kpatch_pre_patch_call_t __pre_patchtest(void) { return _fn; } \ - static struct kpatch_pre_patch_callback kpatch_pre_patch_data __kpatch_section(.kpatch.callbacks.pre_patch) __used = { \ - .fn = _fn, \ - .objname = NULL \ - }; -#define KPATCH_POST_PATCH_CALLBACK(_fn) \ - static inline kpatch_post_patch_call_t __post_patchtest(void) { return _fn; } \ - static struct kpatch_post_patch_callback kpatch_post_patch_data __kpatch_section(.kpatch.callbacks.post_patch) __used = { \ - .fn = _fn, \ - .objname = NULL \ - }; -#define KPATCH_PRE_UNPATCH_CALLBACK(_fn) \ - static inline kpatch_pre_unpatch_call_t __pre_unpatchtest(void) { return _fn; } \ - static struct kpatch_pre_unpatch_callback kpatch_pre_unpatch_data __kpatch_section(.kpatch.callbacks.pre_unpatch) __used = { \ - .fn = _fn, \ - .objname = NULL \ - }; -#define KPATCH_POST_UNPATCH_CALLBACK(_fn) \ - static inline kpatch_post_unpatch_call_t __post_unpatchtest(void) { return _fn; } \ - static struct kpatch_post_unpatch_callback kpatch_post_unpatch_data __kpatch_section(.kpatch.callbacks.post_unpatch) __used = { \ - .fn = _fn, \ - .objname = NULL \ - }; - -/* - * KPATCH_FORCE_UNSAFE macro - * - * USE WITH EXTREME CAUTION! - * - * Allows patch authors to bypass the activeness safety check at patch load - * time. Do this ONLY IF 1) the patch application will always/likely fail due - * to the function being on the stack of at least one thread at all times and - * 2) it is safe for both the original and patched versions of the function to - * run concurrently. - */ -#define KPATCH_FORCE_UNSAFE(_fn) \ - void *__kpatch_force_func_##_fn __kpatch_section(.kpatch.force) = _fn; - -/* - * KPATCH_PRINTK macro - * - * Use this instead of calling printk to avoid unwanted compiler optimizations - * which cause kpatch-build errors. - * - * The printk function is annotated with the __cold attribute, which tells gcc - * that the function is unlikely to be called. A side effect of this is that - * code paths containing calls to printk might also be marked cold, leading to - * other functions called in those code paths getting moved into .text.unlikely - * or being uninlined. - * - * This macro places printk in its own code path so as not to make the - * surrounding code path cold. - */ -#define KPATCH_PRINTK(_fmt, ...) \ -({ \ - if (jiffies) \ - printk(_fmt, ## __VA_ARGS__); \ -}) - -#endif /* __KPATCH_MACROS_H_ */ diff --git a/kmod/patch/kpatch-patch-hook.c b/kmod/patch/kpatch-patch-hook.c deleted file mode 100644 index 92f101d..0000000 --- a/kmod/patch/kpatch-patch-hook.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2013-2014 Josh Poimboeuf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include "kpatch.h" -#include "kpatch-patch.h" - -static bool replace; -module_param(replace, bool, S_IRUGO); -MODULE_PARM_DESC(replace, "replace all previously loaded patch modules"); - -extern struct kpatch_patch_func __kpatch_funcs[], __kpatch_funcs_end[]; -extern struct kpatch_patch_dynrela __kpatch_dynrelas[], __kpatch_dynrelas_end[]; -extern struct kpatch_pre_patch_callback __kpatch_callbacks_pre_patch[], __kpatch_callbacks_pre_patch_end[]; -extern struct kpatch_post_patch_callback __kpatch_callbacks_post_patch[], __kpatch_callbacks_post_patch_end[]; -extern struct kpatch_pre_unpatch_callback __kpatch_callbacks_pre_unpatch[], __kpatch_callbacks_pre_unpatch_end[]; -extern struct kpatch_post_unpatch_callback __kpatch_callbacks_post_unpatch[], __kpatch_callbacks_post_unpatch_end[]; -extern unsigned long __kpatch_force_funcs[], __kpatch_force_funcs_end[]; -extern char __kpatch_checksum[]; - -static struct kpatch_module kpmod; - -static ssize_t patch_enabled_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", kpmod.enabled); -} - -static ssize_t patch_enabled_store(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, - size_t count) -{ - int ret; - unsigned long val; - - ret = kstrtoul(buf, 10, &val); - if (ret) - return ret; - - val = !!val; - - if (val) - ret = kpatch_register(&kpmod, replace); - else - ret = kpatch_unregister(&kpmod); - - if (ret) - return ret; - - return count; -} - -static ssize_t patch_checksum_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", __kpatch_checksum); -} - -static struct kobj_attribute patch_enabled_attr = - __ATTR(enabled, 0644, patch_enabled_show, patch_enabled_store); -static struct kobj_attribute patch_checksum_attr = - __ATTR(checksum, 0444, patch_checksum_show, NULL); - -static struct attribute *patch_attrs[] = { - &patch_enabled_attr.attr, - &patch_checksum_attr.attr, - NULL, -}; - -static void patch_kobj_free(struct kobject *kobj) -{ -} - -static struct kobj_type patch_ktype = { - .release = patch_kobj_free, - .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = patch_attrs, -}; - -static ssize_t patch_func_old_addr_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct kpatch_func *func = - container_of(kobj, struct kpatch_func, kobj); - - return sprintf(buf, "0x%lx\n", func->old_addr); -} - -static ssize_t patch_func_new_addr_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct kpatch_func *func = - container_of(kobj, struct kpatch_func, kobj); - - return sprintf(buf, "0x%lx\n", func->new_addr); -} - -static struct kobj_attribute patch_old_addr_attr = - __ATTR(old_addr, S_IRUSR, patch_func_old_addr_show, NULL); - -static struct kobj_attribute patch_new_addr_attr = - __ATTR(new_addr, S_IRUSR, patch_func_new_addr_show, NULL); - -static struct attribute *patch_func_kobj_attrs[] = { - &patch_old_addr_attr.attr, - &patch_new_addr_attr.attr, - NULL, -}; - -static ssize_t patch_func_kobj_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct kobj_attribute *func_attr = - container_of(attr, struct kobj_attribute, attr); - - return func_attr->show(kobj, func_attr, buf); -} - -static const struct sysfs_ops patch_func_sysfs_ops = { - .show = patch_func_kobj_show, -}; - -static void patch_func_kobj_free(struct kobject *kobj) -{ - struct kpatch_func *func = - container_of(kobj, struct kpatch_func, kobj); - kfree(func); -} - -static struct kobj_type patch_func_ktype = { - .release = patch_func_kobj_free, - .sysfs_ops = &patch_func_sysfs_ops, - .default_attrs = patch_func_kobj_attrs, -}; - -static void patch_object_kobj_free(struct kobject *kobj) -{ - struct kpatch_object *obj = - container_of(kobj, struct kpatch_object, kobj); - kfree(obj); -} - -static struct kobj_type patch_object_ktype = { - .release = patch_object_kobj_free, - .sysfs_ops = &kobj_sysfs_ops, -}; - -static struct kpatch_object *patch_find_or_add_object(struct list_head *head, - const char *name) -{ - struct kpatch_object *object; - int ret; - - list_for_each_entry(object, head, list) { - if (!strcmp(object->name, name)) - return object; - } - - object = kzalloc(sizeof(*object), GFP_KERNEL); - if (!object) - return NULL; - - object->name = name; - INIT_LIST_HEAD(&object->funcs); - INIT_LIST_HEAD(&object->dynrelas); - - list_add_tail(&object->list, head); - - ret = kobject_init_and_add(&object->kobj, &patch_object_ktype, - &kpmod.kobj, "%s", object->name); - if (ret) { - list_del(&object->list); - kfree(object); - return NULL; - } - - return object; -} - -static void patch_free_objects(void) -{ - struct kpatch_object *object, *object_safe; - struct kpatch_func *func, *func_safe; - struct kpatch_dynrela *dynrela, *dynrela_safe; - - list_for_each_entry_safe(object, object_safe, &kpmod.objects, list) { - list_for_each_entry_safe(func, func_safe, &object->funcs, - list) { - list_del(&func->list); - kobject_put(&func->kobj); - } - list_for_each_entry_safe(dynrela, dynrela_safe, - &object->dynrelas, list) { - list_del(&dynrela->list); - kfree(dynrela); - } - list_del(&object->list); - kobject_put(&object->kobj); - } -} - -static int patch_is_func_forced(unsigned long addr) -{ - unsigned long *a; - for (a = __kpatch_force_funcs; a < __kpatch_force_funcs_end; a++) - if (*a == addr) - return 1; - return 0; -} - -static int patch_make_funcs_list(struct list_head *objects) -{ - struct kpatch_object *object; - struct kpatch_patch_func *p_func; - struct kpatch_func *func; - int ret; - - for (p_func = __kpatch_funcs; p_func < __kpatch_funcs_end; p_func++) { - object = patch_find_or_add_object(&kpmod.objects, - p_func->objname); - if (!object) - return -ENOMEM; - - func = kzalloc(sizeof(*func), GFP_KERNEL); - if (!func) - return -ENOMEM; - - func->new_addr = p_func->new_addr; - func->new_size = p_func->new_size; - func->old_size = p_func->old_size; - func->sympos = p_func->sympos; - func->name = p_func->name; - func->force = patch_is_func_forced(func->new_addr); - list_add_tail(&func->list, &object->funcs); - - ret = kobject_init_and_add(&func->kobj, &patch_func_ktype, - &object->kobj, "%s,%lu", - func->name, func->sympos ? func->sympos : 1); - if (ret) - return ret; - } - - return 0; -} - -static int patch_make_dynrelas_list(struct list_head *objects) -{ - struct kpatch_object *object; - struct kpatch_patch_dynrela *p_dynrela; - struct kpatch_dynrela *dynrela; - - for (p_dynrela = __kpatch_dynrelas; p_dynrela < __kpatch_dynrelas_end; - p_dynrela++) { - object = patch_find_or_add_object(objects, p_dynrela->objname); - if (!object) - return -ENOMEM; - - dynrela = kzalloc(sizeof(*dynrela), GFP_KERNEL); - if (!dynrela) - return -ENOMEM; - - dynrela->dest = p_dynrela->dest; - dynrela->type = p_dynrela->type; - dynrela->sympos = p_dynrela->sympos; - dynrela->name = p_dynrela->name; - dynrela->external = p_dynrela->external; - dynrela->addend = p_dynrela->addend; - list_add_tail(&dynrela->list, &object->dynrelas); - } - - return 0; -} - -static int patch_set_callbacks(struct list_head *objects) -{ - struct kpatch_pre_patch_callback *p_pre_patch_callback; - struct kpatch_post_patch_callback *p_post_patch_callback; - struct kpatch_pre_unpatch_callback *p_pre_unpatch_callback; - struct kpatch_post_unpatch_callback *p_post_unpatch_callback; - struct kpatch_object *object; - - for (p_pre_patch_callback = __kpatch_callbacks_pre_patch; - p_pre_patch_callback < __kpatch_callbacks_pre_patch_end; - p_pre_patch_callback++) { - - object = patch_find_or_add_object(objects, p_pre_patch_callback->objname); - if (!object) - return -ENOMEM; - - if (object->pre_patch_callback) { - pr_err("extra pre-patch callback for object: %s\n", - object->name); - return -EINVAL; - } - - object->pre_patch_callback = - (int (*)(struct kpatch_object *)) p_pre_patch_callback->callback; - } - - for (p_post_patch_callback = __kpatch_callbacks_post_patch; - p_post_patch_callback < __kpatch_callbacks_post_patch_end; - p_post_patch_callback++) { - - object = patch_find_or_add_object(objects, p_post_patch_callback->objname); - if (!object) - return -ENOMEM; - - if (object->post_patch_callback) { - pr_err("extra post-patch callback for object: %s\n", - object->name); - return -EINVAL; - } - - object->post_patch_callback = - (void (*)(struct kpatch_object *)) p_post_patch_callback->callback; - } - - for (p_pre_unpatch_callback = __kpatch_callbacks_pre_unpatch; - p_pre_unpatch_callback < __kpatch_callbacks_pre_unpatch_end; - p_pre_unpatch_callback++) { - - object = patch_find_or_add_object(objects, p_pre_unpatch_callback->objname); - if (!object) - return -ENOMEM; - - if (object->pre_unpatch_callback) { - pr_err("extra pre-unpatch callback for object: %s\n", - object->name); - return -EINVAL; - } - - object->pre_unpatch_callback = - (void (*)(struct kpatch_object *)) p_pre_unpatch_callback->callback; - } - - for (p_post_unpatch_callback = __kpatch_callbacks_post_unpatch; - p_post_unpatch_callback < __kpatch_callbacks_post_unpatch_end; - p_post_unpatch_callback++) { - - object = patch_find_or_add_object(objects, p_post_unpatch_callback->objname); - if (!object) - return -ENOMEM; - - if (object->post_unpatch_callback) { - pr_err("extra post-unpatch callback for object: %s\n", - object->name); - return -EINVAL; - } - - object->post_unpatch_callback = - (void (*)(struct kpatch_object *)) p_post_unpatch_callback->callback; - } - return 0; -} - -static int __init patch_init(void) -{ - int ret; - - ret = kobject_init_and_add(&kpmod.kobj, &patch_ktype, - kpatch_root_kobj, "%s", - THIS_MODULE->name); - if (ret) - return -ENOMEM; - - kpmod.mod = THIS_MODULE; - INIT_LIST_HEAD(&kpmod.objects); - - ret = patch_make_funcs_list(&kpmod.objects); - if (ret) - goto err_objects; - - ret = patch_make_dynrelas_list(&kpmod.objects); - if (ret) - goto err_objects; - - ret = patch_set_callbacks(&kpmod.objects); - if (ret) - goto err_objects; - - ret = kpatch_register(&kpmod, replace); - if (ret) - goto err_objects; - - return 0; - -err_objects: - patch_free_objects(); - kobject_put(&kpmod.kobj); - return ret; -} - -static void __exit patch_exit(void) -{ - WARN_ON(kpmod.enabled); - - patch_free_objects(); - kobject_put(&kpmod.kobj); -} - -module_init(patch_init); -module_exit(patch_exit); -MODULE_LICENSE("GPL"); diff --git a/kmod/patch/kpatch-patch.h b/kmod/patch/kpatch-patch.h deleted file mode 100644 index da4f6a0..0000000 --- a/kmod/patch/kpatch-patch.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * kpatch-patch.h - * - * Copyright (C) 2014 Josh Poimboeuf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - * Contains the structs used for the patch module special sections - */ - -#ifndef _KPATCH_PATCH_H_ -#define _KPATCH_PATCH_H_ - -struct kpatch_patch_func { - unsigned long new_addr; - unsigned long new_size; - unsigned long old_addr; - unsigned long old_size; - unsigned long sympos; - char *name; - char *objname; -}; - -struct kpatch_patch_dynrela { - unsigned long dest; - unsigned long src; - unsigned long type; - unsigned long sympos; - char *name; - char *objname; - int external; - long addend; -}; - -struct kpatch_pre_patch_callback { - int (*callback)(void *obj); - char *objname; -}; -struct kpatch_post_patch_callback { - void (*callback)(void *obj); - char *objname; -}; -struct kpatch_pre_unpatch_callback { - void (*callback)(void *obj); - char *objname; -}; -struct kpatch_post_unpatch_callback { - void (*callback)(void *obj); - char *objname; -}; - -#endif /* _KPATCH_PATCH_H_ */ diff --git a/kmod/patch/kpatch-syscall.h b/kmod/patch/kpatch-syscall.h deleted file mode 100644 index ff62327..0000000 --- a/kmod/patch/kpatch-syscall.h +++ /dev/null @@ -1,207 +0,0 @@ -#ifndef __KPATCH_SYSCALL_H_ -#define __KPATCH_SYSCALL_H_ - -#include "kpatch-macros.h" - -/* - * These kpatch-specific syscall definition macros can be used for patching a - * syscall. - * - * Attempting to patch a syscall typically results in an error, due to a - * missing fentry hook in the inner __do_sys##name() function. The fentry hook - * is missing because of the 'inline' annotation, which invokes 'notrace'. - * - * These macros are copied almost verbatim from the kernel, the main difference - * being a 'kpatch' prefix added to the __do_sys##name() function name. This - * causes kpatch-build to treat it as a new function (due to - * its new name), and its caller __se_sys##name() function is inlined by its own - * caller __x64_sys##name() function, which has an fentry hook. - - * To patch a syscall, just replace the use of the SYSCALL_DEFINE1 (or similar) - * macro with the "KPATCH_" prefixed version. - */ - -#define KPATCH_IGNORE_SYSCALL_SECTIONS \ - KPATCH_IGNORE_SECTION("__syscalls_metadata"); \ - KPATCH_IGNORE_SECTION("_ftrace_events") - -#define KPATCH_SYSCALL_DEFINE1(name, ...) KPATCH_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) -#define KPATCH_SYSCALL_DEFINE2(name, ...) KPATCH_SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) -#define KPATCH_SYSCALL_DEFINE3(name, ...) KPATCH_SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) -#define KPATCH_SYSCALL_DEFINE4(name, ...) KPATCH_SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) -#define KPATCH_SYSCALL_DEFINE5(name, ...) KPATCH_SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) -#define KPATCH_SYSCALL_DEFINE6(name, ...) KPATCH_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) - -#define KPATCH_SYSCALL_DEFINEx(x, sname, ...) \ - KPATCH_IGNORE_SYSCALL_SECTIONS; \ - __KPATCH_SYSCALL_DEFINEx(x, sname, __VA_ARGS__) - -#ifdef CONFIG_X86_64 - -/* x86/include/asm/syscall_wrapper.h versions */ - -# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) - -# define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ - __X64_SYS_STUBx(x, name, __VA_ARGS__) \ - __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ - static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -# elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) - -# define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long __x64_sys##name(const struct pt_regs *regs); \ - ALLOW_ERROR_INJECTION(__x64_sys##name, ERRNO); \ - static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ - asmlinkage long __x64_sys##name(const struct pt_regs *regs) \ - { \ - return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\ - } \ - __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ - static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -# endif /* LINUX_VERSION_CODE */ - -#elif defined(CONFIG_S390) - -/* s390/include/asm/syscall_wrapper.h versions */ - -#define __KPATCH_S390_SYS_STUBx(x, name, ...) \ - long __s390_sys##name(struct pt_regs *regs); \ - ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO); \ - long __s390_sys##name(struct pt_regs *regs) \ - { \ - long ret = __kpatch_do_sys##name(SYSCALL_PT_ARGS(x, regs, \ - __SC_COMPAT_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__))); \ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - return ret; \ - } - -#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - __diag_push(); \ - __diag_ignore(GCC, 8, "-Wattribute-alias", \ - "Type aliasing is used to sanitize syscall arguments"); \ - long __s390x_sys##name(struct pt_regs *regs) \ - __attribute__((alias(__stringify(__se_sys##name)))); \ - ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ - long __se_sys##name(struct pt_regs *regs); \ - __KPATCH_S390_SYS_STUBx(x, name, __VA_ARGS__) \ - long __se_sys##name(struct pt_regs *regs) \ - { \ - long ret = __kpatch_do_sys##name(SYSCALL_PT_ARGS(x, regs, \ - __SC_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__))); \ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - return ret; \ - } \ - __diag_pop(); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -#elif defined(CONFIG_ARM64) - -/* arm64/include/asm/syscall_wrapper.h versions */ - -#define SC_ARM64_REGS_TO_ARGS(x, ...) \ - __MAP(x,__SC_ARGS \ - ,,regs->regs[0],,regs->regs[1],,regs->regs[2] \ - ,,regs->regs[3],,regs->regs[4],,regs->regs[5]) - -#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long __arm64_sys##name(const struct pt_regs *regs); \ - ALLOW_ERROR_INJECTION(__arm64_sys##name, ERRNO); \ - static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ - asmlinkage long __arm64_sys##name(const struct pt_regs *regs) \ - { \ - return __se_sys##name(SC_ARM64_REGS_TO_ARGS(x,__VA_ARGS__)); \ - } \ - static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -#endif /* CONFIG_X86_64 */ - - -#ifndef __KPATCH_SYSCALL_DEFINEx - -/* include/linux/syscalls.h versions */ - -# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) -# define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - __diag_push(); \ - __diag_ignore(GCC, 8, "-Wattribute-alias", \ - "Type aliasing is used to sanitize syscall arguments");\ - asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ - __attribute__((alias(__stringify(__se_sys##name)))); \ - ALLOW_ERROR_INJECTION(sys##name, ERRNO); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ - asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - asmlinkage long __attribute__((optimize("-fno-optimize-sibling-calls")))\ - __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - __diag_pop(); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -# elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) -# define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ - __attribute__((alias(__stringify(__se_sys##name)))); \ - ALLOW_ERROR_INJECTION(sys##name, ERRNO); \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ - asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -# else -# define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ - __attribute__((alias(__stringify(SyS##name)))); \ - static inline long __kpatch_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ - asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = __kpatch_SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - static inline long __kpatch_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -# endif - -#endif /* __KPATCH_SYSCALL_DEFINEx */ - -#endif /* __KPATCH_SYSCALL_H_ */ diff --git a/kmod/patch/kpatch.h b/kmod/patch/kpatch.h deleted file mode 120000 index e8de666..0000000 --- a/kmod/patch/kpatch.h +++ /dev/null @@ -1 +0,0 @@ -../core/kpatch.h \ No newline at end of file diff --git a/kmod/patch/kpatch.lds.S b/kmod/patch/kpatch.lds.S deleted file mode 100644 index bc5de82..0000000 --- a/kmod/patch/kpatch.lds.S +++ /dev/null @@ -1,50 +0,0 @@ -__kpatch_funcs = ADDR(.kpatch.funcs); -__kpatch_funcs_end = ADDR(.kpatch.funcs) + SIZEOF(.kpatch.funcs); - -#ifdef __KPATCH_MODULE__ -__kpatch_dynrelas = ADDR(.kpatch.dynrelas); -__kpatch_dynrelas_end = ADDR(.kpatch.dynrelas) + SIZEOF(.kpatch.dynrelas); -__kpatch_checksum = ADDR(.kpatch.checksum); -#endif - -SECTIONS -{ - .kpatch.callbacks.pre_patch : { - __kpatch_callbacks_pre_patch = . ; - *(.kpatch.callbacks.pre_patch) - __kpatch_callbacks_pre_patch_end = . ; - /* - * Pad the end of the section with zeros in case the section is empty. - * This prevents the kernel from discarding the section at module - * load time. __kpatch_callbacks_pre_patch_end will still point to the - * end of the section before the padding. If the - * .kpatch.callbacks.pre_patch section is empty, - * __kpatch_callbacks_pre_patch equals __kpatch_callbacks_pre_patch_end. - */ - QUAD(0); - } - .kpatch.callbacks.post_patch : { - __kpatch_callbacks_post_patch = . ; - *(.kpatch.callbacks.post_patch) - __kpatch_callbacks_post_patch_end = . ; - QUAD(0); - } - .kpatch.callbacks.pre_unpatch : { - __kpatch_callbacks_pre_unpatch = . ; - *(.kpatch.callbacks.pre_unpatch) - __kpatch_callbacks_pre_unpatch_end = . ; - QUAD(0); - } - .kpatch.callbacks.post_unpatch : { - __kpatch_callbacks_post_unpatch = . ; - *(.kpatch.callbacks.post_unpatch) - __kpatch_callbacks_post_unpatch_end = . ; - QUAD(0); - } - .kpatch.force : { - __kpatch_force_funcs = . ; - *(.kpatch.force) - __kpatch_force_funcs_end = . ; - QUAD(0); - } -} diff --git a/kmod/patch/livepatch-patch-hook.c b/kmod/patch/livepatch-patch-hook.c deleted file mode 100644 index c09406e..0000000 --- a/kmod/patch/livepatch-patch-hook.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (C) 2013-2014 Josh Poimboeuf - * Copyright (C) 2014 Seth Jennings - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include - -#include "kpatch-patch.h" - -#ifndef UTS_UBUNTU_RELEASE_ABI -#define UTS_UBUNTU_RELEASE_ABI 0 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) || \ - defined(RHEL_RELEASE_CODE) -#define HAVE_ELF_RELOCS -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) && \ - UTS_UBUNTU_RELEASE_ABI >= 7) || \ - defined(RHEL_RELEASE_CODE) -#define HAVE_SYMPOS -#endif - -#ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7, 5) -# define HAVE_IMMEDIATE -# endif -#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) && \ - LINUX_VERSION_CODE <= KERNEL_VERSION(4, 15, 0)) -# define HAVE_IMMEDIATE -#endif - -#ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 5) -# define HAVE_CALLBACKS -# endif -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0) -# define HAVE_CALLBACKS -#endif - -#ifdef RHEL_RELEASE_CODE -# if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7, 8) && \ - RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8, 0)) || \ - RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8, 2) -# define HAVE_SIMPLE_ENABLE -# endif -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) -# define HAVE_SIMPLE_ENABLE -#endif - -#ifdef RHEL_RELEASE_CODE -# if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8, 2) -# define HAVE_KLP_REPLACE -# endif -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) -# define HAVE_KLP_REPLACE -#endif - - -#ifndef KLP_REPLACE_ENABLE -#define KLP_REPLACE_ENABLE true -#endif - -/* - * There are quite a few similar structures at play in this file: - * - livepatch.h structs prefixed with klp_* - * - kpatch-patch.h structs prefixed with kpatch_patch_* - * - local scaffolding structs prefixed with patch_* - * - * The naming of the struct variables follows this convention: - * - livepatch struct being with "l" (e.g. lfunc) - * - kpatch_patch structs being with "k" (e.g. kfunc) - * - local scaffolding structs have no prefix (e.g. func) - * - * The program reads in kpatch_patch structures, arranges them into the - * scaffold structures, then creates a livepatch structure suitable for - * registration with the livepatch kernel API. The scaffold structs only - * exist to allow the construction of the klp_patch struct. Once that is - * done, the scaffold structs are no longer needed. - */ - -/* - * lpatch is the kernel data structure that will be created on patch - * init, registered with the livepatch API on init, and finally - * unregistered when the patch exits. Its struct klp_object *objs - * member must be dynamically allocated according to the number of - * target objects it will be patching. - */ -static struct klp_patch *lpatch; - -static LIST_HEAD(patch_objects); -static int patch_objects_nr; - -/** - * struct patch_object - scaffolding structure tracking patch target objects - * @list: list of patch_object (threaded onto patch_objects) - * @funcs: list of patch_func associated with this object - * @relocs: list of patch_reloc associated with this object - * @callbacks: kernel struct of object callbacks - * @name: patch target object name (NULL for vmlinux) - * @funcs_nr: count of kpatch_patch_func added to @funcs - * @relocs_nr: count of patch_reloc added to @relocs - */ -struct patch_object { - struct list_head list; - struct list_head funcs; - struct list_head relocs; -#ifdef HAVE_CALLBACKS - struct klp_callbacks callbacks; -#endif - const char *name; - int funcs_nr, relocs_nr; -}; - -/** - * struct patch_func - scaffolding structure for kpatch_patch_func - * @list: list of patch_func (threaded onto patch_object.funcs) - * @kfunc: array of kpatch_patch_func - */ -struct patch_func { - struct list_head list; - struct kpatch_patch_func *kfunc; -}; - -/** - * struct patch_reloc - scaffolding structure for kpatch_patch_dynrela - * @list: list of patch_reloc (threaded onto patch_object.relocs) - * @kdynrela: array of kpatch_patch_dynrela - */ -struct patch_reloc { - struct list_head list; - struct kpatch_patch_dynrela *kdynrela; -}; - -/** - * patch_alloc_new_object() - creates and initializes a new patch_object - * @name: target object name - * - * Return: pointer to new patch_object, NULL on failure. - * - * Does not check for previously created patch_objects with the same - * name. Updates patch_objects_nr and threads new data structure onto - * the patch_objects list. - */ -static struct patch_object *patch_alloc_new_object(const char *name) -{ - struct patch_object *object; - - object = kzalloc(sizeof(*object), GFP_KERNEL); - if (!object) - return NULL; - INIT_LIST_HEAD(&object->funcs); -#ifndef HAVE_ELF_RELOCS - INIT_LIST_HEAD(&object->relocs); -#endif - if (strcmp(name, "vmlinux")) - object->name = name; - list_add(&object->list, &patch_objects); - patch_objects_nr++; - return object; -} - -/** - * patch_find_object_by_name() - find or create a patch_object with a - * given name - * @name: target object name - * - * Return: pointer to patch_object, NULL on failure. - * - * Searches the patch_objects list for an already created instance with - * @name, otherwise tries to create it via patch_alloc_new_object() - */ -static struct patch_object *patch_find_object_by_name(const char *name) -{ - struct patch_object *object; - - list_for_each_entry(object, &patch_objects, list) - if ((!strcmp(name, "vmlinux") && !object->name) || - (object->name && !strcmp(object->name, name))) - return object; - return patch_alloc_new_object(name); -} - -/** - * patch_add_func_to_object() - create scaffolding from kpatch_patch_func data - * - * @kfunc: Individual kpatch_patch_func pointer - * - * Return: 0 on success, -ENOMEM on failure. - * - * Builds scaffolding data structures from .kpatch.funcs section's array - * of kpatch_patch_func structures. Updates the associated - * patch_object's funcs_nr count. - */ -static int patch_add_func_to_object(struct kpatch_patch_func *kfunc) -{ - struct patch_func *func; - struct patch_object *object; - - func = kzalloc(sizeof(*func), GFP_KERNEL); - if (!func) - return -ENOMEM; - INIT_LIST_HEAD(&func->list); - func->kfunc = kfunc; - - object = patch_find_object_by_name(kfunc->objname); - if (!object) { - kfree(func); - return -ENOMEM; - } - list_add(&func->list, &object->funcs); - object->funcs_nr++; - return 0; -} - -#ifndef HAVE_ELF_RELOCS -/** - * patch_add_reloc_to_object() - create scaffolding from kpatch_patch_dynrela data - * - * @kdynrela: Individual kpatch_patch_dynrela pointer - * - * Return: 0 on success, -ENOMEM on failure. - * - * Builds scaffolding data structures from .kpatch.dynrelas section's array - * of kpatch_patch_dynrela structures. Updates the associated - * patch_object's relocs_nr count. - */ -static int patch_add_reloc_to_object(struct kpatch_patch_dynrela *kdynrela) -{ - struct patch_reloc *reloc; - struct patch_object *object; - - reloc = kzalloc(sizeof(*reloc), GFP_KERNEL); - if (!reloc) - return -ENOMEM; - INIT_LIST_HEAD(&reloc->list); - reloc->kdynrela = kdynrela; - - object = patch_find_object_by_name(kdynrela->objname); - if (!object) { - kfree(reloc); - return -ENOMEM; - } - list_add(&reloc->list, &object->relocs); - object->relocs_nr++; - return 0; -} -#endif - -/** - * patch_free_scaffold() - tear down the temporary kpatch scaffolding - */ -static void patch_free_scaffold(void) { - struct patch_func *func, *safefunc; - struct patch_object *object, *safeobject; -#ifndef HAVE_ELF_RELOCS - struct patch_reloc *reloc, *safereloc; -#endif - - list_for_each_entry_safe(object, safeobject, &patch_objects, list) { - list_for_each_entry_safe(func, safefunc, - &object->funcs, list) { - list_del(&func->list); - kfree(func); - } -#ifndef HAVE_ELF_RELOCS - list_for_each_entry_safe(reloc, safereloc, - &object->relocs, list) { - list_del(&reloc->list); - kfree(reloc); - } -#endif - list_del(&object->list); - kfree(object); - } -} - -/** - * patch_free_livepatch() - release the klp_patch and friends - */ -static void patch_free_livepatch(struct klp_patch *patch) -{ - struct klp_object *object; - - if (patch) { - for (object = patch->objs; object && object->funcs; object++) { - if (object->funcs) - kfree(object->funcs); -#ifndef HAVE_ELF_RELOCS - if (object->relocs) - kfree(object->relocs); -#endif - } - if (patch->objs) - kfree(patch->objs); - kfree(patch); - } -} - -/* Defined by kpatch.lds.S */ -extern struct kpatch_pre_patch_callback __kpatch_callbacks_pre_patch[], __kpatch_callbacks_pre_patch_end[]; -extern struct kpatch_post_patch_callback __kpatch_callbacks_post_patch[], __kpatch_callbacks_post_patch_end[]; -extern struct kpatch_pre_unpatch_callback __kpatch_callbacks_pre_unpatch[], __kpatch_callbacks_pre_unpatch_end[]; -extern struct kpatch_post_unpatch_callback __kpatch_callbacks_post_unpatch[], __kpatch_callbacks_post_unpatch_end[]; - -#ifdef HAVE_CALLBACKS -/** - * add_callbacks_to_patch_objects() - create patch_objects that have callbacks - * - * Return: 0 on success, -ENOMEM or -EINVAL on failure - * - * Iterates through all kpatch pre/post-(un)patch callback data - * structures and creates scaffolding patch_objects for them. - */ -static int add_callbacks_to_patch_objects(void) -{ - struct kpatch_pre_patch_callback *p_pre_patch_callback; - struct kpatch_post_patch_callback *p_post_patch_callback; - struct kpatch_pre_unpatch_callback *p_pre_unpatch_callback; - struct kpatch_post_unpatch_callback *p_post_unpatch_callback; - struct patch_object *object; - - for (p_pre_patch_callback = __kpatch_callbacks_pre_patch; - p_pre_patch_callback < __kpatch_callbacks_pre_patch_end; - p_pre_patch_callback++) { - object = patch_find_object_by_name(p_pre_patch_callback->objname); - if (!object) - return -ENOMEM; - if (object->callbacks.pre_patch) { - pr_err("extra pre-patch callback for object: %s\n", - object->name ? object->name : "vmlinux"); - return -EINVAL; - } - object->callbacks.pre_patch = (int (*)(struct klp_object *)) - p_pre_patch_callback->callback; - } - - for (p_post_patch_callback = __kpatch_callbacks_post_patch; - p_post_patch_callback < __kpatch_callbacks_post_patch_end; - p_post_patch_callback++) { - object = patch_find_object_by_name(p_post_patch_callback->objname); - if (!object) - return -ENOMEM; - if (object->callbacks.post_patch) { - pr_err("extra post-patch callback for object: %s\n", - object->name ? object->name : "vmlinux"); - return -EINVAL; - } - object->callbacks.post_patch = (void (*)(struct klp_object *)) - p_post_patch_callback->callback; - } - - for (p_pre_unpatch_callback = __kpatch_callbacks_pre_unpatch; - p_pre_unpatch_callback < __kpatch_callbacks_pre_unpatch_end; - p_pre_unpatch_callback++) { - object = patch_find_object_by_name(p_pre_unpatch_callback->objname); - if (!object) - return -ENOMEM; - if (object->callbacks.pre_unpatch) { - pr_err("extra pre-unpatch callback for object: %s\n", - object->name ? object->name : "vmlinux"); - return -EINVAL; - } - object->callbacks.pre_unpatch = (void (*)(struct klp_object *)) - p_pre_unpatch_callback->callback; - } - - for (p_post_unpatch_callback = __kpatch_callbacks_post_unpatch; - p_post_unpatch_callback < __kpatch_callbacks_post_unpatch_end; - p_post_unpatch_callback++) { - object = patch_find_object_by_name(p_post_unpatch_callback->objname); - if (!object) - return -ENOMEM; - if (object->callbacks.post_unpatch) { - pr_err("extra post-unpatch callback for object: %s\n", - object->name ? object->name : "vmlinux"); - return -EINVAL; - } - object->callbacks.post_unpatch = (void (*)(struct klp_object *)) - p_post_unpatch_callback->callback; - } - - return 0; -} -#else /* HAVE_CALLBACKS */ -static inline int add_callbacks_to_patch_objects(void) -{ - if (__kpatch_callbacks_pre_patch != - __kpatch_callbacks_pre_patch_end || - __kpatch_callbacks_post_patch != - __kpatch_callbacks_post_patch_end || - __kpatch_callbacks_pre_unpatch != - __kpatch_callbacks_pre_unpatch_end || - __kpatch_callbacks_post_unpatch != - __kpatch_callbacks_post_unpatch_end) { - pr_err("patch callbacks are not supported\n"); - return -EINVAL; - } - - return 0; -} -#endif /* HAVE_CALLBACKS */ - -/* Defined by kpatch.lds.S */ -extern struct kpatch_patch_func __kpatch_funcs[], __kpatch_funcs_end[]; -#ifndef HAVE_ELF_RELOCS -extern struct kpatch_patch_dynrela __kpatch_dynrelas[], __kpatch_dynrelas_end[]; -#endif - -static int __init patch_init(void) -{ - struct kpatch_patch_func *kfunc; - struct klp_object *lobjects, *lobject; - struct klp_func *lfuncs, *lfunc; - struct patch_object *object; - struct patch_func *func; - int ret = 0, i, j; -#ifndef HAVE_ELF_RELOCS - struct kpatch_patch_dynrela *kdynrela; - struct patch_reloc *reloc; - struct klp_reloc *lrelocs, *lreloc; -#endif - - - /* - * Step 1 - read from output.o, create temporary scaffolding - * data-structures - */ - - /* organize functions and relocs by object in scaffold */ - for (kfunc = __kpatch_funcs; - kfunc != __kpatch_funcs_end; - kfunc++) { - ret = patch_add_func_to_object(kfunc); - if (ret) - goto out; - } - -#ifndef HAVE_ELF_RELOCS - for (kdynrela = __kpatch_dynrelas; - kdynrela != __kpatch_dynrelas_end; - kdynrela++) { - ret = patch_add_reloc_to_object(kdynrela); - if (ret) - goto out; - } -#endif - - ret = add_callbacks_to_patch_objects(); - if (ret) - goto out; - - /* past this point, only possible return code is -ENOMEM */ - ret = -ENOMEM; - - /* - * Step 2 - create livepatch klp_patch and friends - * - * There are two dynamically allocated parts: - * - * klp_patch - * klp_object objs [patch_objects_nr] <= i - * klp_func funcs [object->funcs_nr] <= j - */ - - /* allocate and fill livepatch structures */ - lpatch = kzalloc(sizeof(*lpatch), GFP_KERNEL); - if (!lpatch) - goto out; - - lobjects = kzalloc(sizeof(*lobjects) * (patch_objects_nr+1), - GFP_KERNEL); - if (!lobjects) - goto out; - lpatch->mod = THIS_MODULE; - lpatch->objs = lobjects; -#ifdef HAVE_KLP_REPLACE - lpatch->replace = KLP_REPLACE_ENABLE; -#endif -#if defined(__powerpc64__) && defined(HAVE_IMMEDIATE) - lpatch->immediate = true; -#endif - - i = 0; - list_for_each_entry(object, &patch_objects, list) { - lobject = &lobjects[i]; - lobject->name = object->name; - lfuncs = kzalloc(sizeof(struct klp_func) * - (object->funcs_nr+1), GFP_KERNEL); - if (!lfuncs) - goto out; - lobject->funcs = lfuncs; - j = 0; - list_for_each_entry(func, &object->funcs, list) { - lfunc = &lfuncs[j]; - lfunc->old_name = func->kfunc->name; - lfunc->new_func = (void *)func->kfunc->new_addr; -#ifdef HAVE_SYMPOS - lfunc->old_sympos = func->kfunc->sympos; -#else - lfunc->old_addr = func->kfunc->old_addr; -#endif - j++; - } - -#ifndef HAVE_ELF_RELOCS - lrelocs = kzalloc(sizeof(struct klp_reloc) * - (object->relocs_nr+1), GFP_KERNEL); - if (!lrelocs) - goto out; - lobject->relocs = lrelocs; - j = 0; - list_for_each_entry(reloc, &object->relocs, list) { - lreloc = &lrelocs[j]; - lreloc->loc = reloc->kdynrela->dest; -#ifdef HAVE_SYMPOS - lreloc->sympos = reloc->kdynrela->sympos; -#else - lreloc->val = reloc->kdynrela->src; -#endif /* HAVE_SYMPOS */ - lreloc->type = reloc->kdynrela->type; - lreloc->name = reloc->kdynrela->name; - lreloc->addend = reloc->kdynrela->addend; - lreloc->external = reloc->kdynrela->external; - j++; - } -#endif /* HAVE_ELF_RELOCS */ - -#ifdef HAVE_CALLBACKS - lobject->callbacks = object->callbacks; -#endif - - i++; - } - - /* - * Step 3 - throw away scaffolding - */ - - /* - * Once the patch structure that the live patching API expects - * has been built, we can release the scaffold structure. - */ - patch_free_scaffold(); - -#ifndef HAVE_SIMPLE_ENABLE - ret = klp_register_patch(lpatch); - if (ret) { - patch_free_livepatch(lpatch); - return ret; - } -#endif - - ret = klp_enable_patch(lpatch); - if (ret) { -#ifndef HAVE_SIMPLE_ENABLE - WARN_ON(klp_unregister_patch(lpatch)); -#endif - patch_free_livepatch(lpatch); - return ret; - } - - return 0; -out: - patch_free_livepatch(lpatch); - patch_free_scaffold(); - return ret; -} - -static void __exit patch_exit(void) -{ -#ifndef HAVE_SIMPLE_ENABLE - WARN_ON(klp_unregister_patch(lpatch)); -#endif - patch_free_livepatch(lpatch); -} - -module_init(patch_init); -module_exit(patch_exit); -MODULE_LICENSE("GPL"); -MODULE_INFO(livepatch, "Y"); diff --git a/kmod/patch/patch-hook.c b/kmod/patch/patch-hook.c deleted file mode 100644 index 2b080a9..0000000 --- a/kmod/patch/patch-hook.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2015 Seth Jennings - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#if IS_ENABLED(CONFIG_LIVEPATCH) && (USE_KLP == 1) -#include "livepatch-patch-hook.c" -#else -#include "kpatch-patch-hook.c" -#endif - diff --git a/kpatch-build/Makefile b/kpatch-build/Makefile deleted file mode 100644 index 7fb2231..0000000 --- a/kpatch-build/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -include ../Makefile.inc - -CFLAGS += -MMD -MP -I../kmod/patch -Iinsn -Wall -Wsign-compare \ - -Wconversion -Wno-sign-conversion -g -Werror -LDLIBS = -lelf - -TARGETS = create-diff-object create-klp-module create-kpatch-module -SOURCES = create-diff-object.c kpatch-elf.c \ - create-klp-module.c \ - create-kpatch-module.c \ - create-kpatch-module.c lookup.c - -SOURCES += insn/insn.c insn/inat.c -INSN = insn/insn.o insn/inat.o -insn/%.o: CFLAGS := $(filter-out -Wconversion, $(CFLAGS)) -ifeq ($(ARCH),ppc64le) -SOURCES += gcc-plugins/ppc64le-plugin.c -PLUGIN = gcc-plugins/ppc64le-plugin.so -TARGETS += $(PLUGIN) -GCC_PLUGINS_DIR := $(shell $(CROSS_COMPILE)gcc -print-file-name=plugin) -PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS)) -PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \ - -Igcc-plugins -fPIC -fno-rtti -O2 -Wall -endif -ifeq ($(filter $(ARCH),aarch64 s390x x86_64 ppc64le),) -$(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures) -endif - - -all: $(TARGETS) - --include $(SOURCES:.c=.d) - -create-diff-object: create-diff-object.o kpatch-elf.o lookup.o $(INSN) -create-klp-module: create-klp-module.o kpatch-elf.o $(INSN) -create-kpatch-module: create-kpatch-module.o kpatch-elf.o $(INSN) - -$(PLUGIN): gcc-plugins/ppc64le-plugin.c - g++ $(PLUGIN_CFLAGS) $< -o $@ - -install: all - $(INSTALL) -d $(LIBEXECDIR) - $(INSTALL) $(TARGETS) kpatch-cc $(LIBEXECDIR) - $(INSTALL) -d $(BINDIR) - $(INSTALL) kpatch-build $(BINDIR) - -uninstall: - $(RM) -R $(LIBEXECDIR) - $(RM) $(BINDIR)/kpatch-build - -clean: - $(RM) $(TARGETS) *.{o,d} insn/*.{o,d} gcc-plugins/*.{so,d} diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c deleted file mode 100644 index 431d1e7..0000000 --- a/kpatch-build/create-diff-object.c +++ /dev/null @@ -1,4362 +0,0 @@ -/* - * create-diff-object.c - * - * Copyright (C) 2014 Seth Jennings - * Copyright (C) 2013-2014 Josh Poimboeuf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -/* - * This file contains the heart of the ELF object differencing engine. - * - * The tool takes two ELF objects from two versions of the same source - * file; a "orig" object and a "patched" object. These object need to have - * been compiled with the -ffunction-sections and -fdata-sections GCC options. - * - * The tool compares the objects at a section level to determine what - * sections have changed. Once a list of changed sections has been generated, - * various rules are applied to determine any object local sections that - * are dependencies of the changed section and also need to be included in - * the output object. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "list.h" -#include "lookup.h" -#include "kpatch-patch.h" -#include "kpatch-elf.h" -#include "kpatch-intermediate.h" -#include "kpatch.h" - -#define DIFF_FATAL(format, ...) \ -({ \ - fprintf(stderr, "ERROR: %s: " format "\n", childobj, ##__VA_ARGS__); \ - err(EXIT_STATUS_DIFF_FATAL, "unreconcilable difference"); \ -}) - -char *childobj; - -enum subsection { - SUBSECTION_NORMAL, - SUBSECTION_HOT, - SUBSECTION_UNLIKELY -}; - -enum loglevel loglevel = NORMAL; - -bool KLP_ARCH; -bool multi_pfe; - -int jump_label_errors; - -/******************* - * Data structures - * ****************/ -struct special_section { - char *name; - enum architecture arch; - int (*group_size)(struct kpatch_elf *kelf, int offset); - bool (*group_filter)(struct lookup_table *lookup, - struct section *relasec, unsigned int offset, - unsigned int size); -}; - -/************* - * Functions - * **********/ - -static bool is_bundleable(struct symbol *sym) -{ - if (sym->type == STT_FUNC && - !strncmp(sym->sec->name, ".text.",6) && - !strcmp(sym->sec->name + 6, sym->name)) - return true; - - if (sym->type == STT_FUNC && - !strncmp(sym->sec->name, ".text.unlikely.",15) && - (!strcmp(sym->sec->name + 15, sym->name) || - (strstr(sym->name, ".cold") && - !strncmp(sym->sec->name + 15, sym->name, strlen(sym->sec->name) - 15)))) - return true; - - if (sym->type == STT_FUNC && - !strncmp(sym->sec->name, ".text.hot.",10) && - !strcmp(sym->sec->name + 10, sym->name)) - return true; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".data.",6) && - !strcmp(sym->sec->name + 6, sym->name)) - return true; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".data.rel.", 10) && - !strcmp(sym->sec->name + 10, sym->name)) - return true; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".data.rel.ro.", 13) && - !strcmp(sym->sec->name + 13, sym->name)) - return true; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".data.rel.ro.local.", 19) && - !strcmp(sym->sec->name + 19, sym->name)) - return 1; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".data.rel.local.", 16) && - !strcmp(sym->sec->name + 16, sym->name)) - return 1; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".rodata.",8) && - !strcmp(sym->sec->name + 8, sym->name)) - return true; - - if (sym->type == STT_OBJECT && - !strncmp(sym->sec->name, ".bss.",5) && - !strcmp(sym->sec->name + 5, sym->name)) - return true; - - return false; -} - -/* Symbol st_others value for powerpc */ -#define STO_PPC64_LOCAL_BIT 5 -#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) -#define PPC64_LOCAL_ENTRY_OFFSET(other) \ - (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2) - -/* - * On ppc64le, the function prologue generated by GCC 6+ has the sequence: - * - * .globl my_func - * .type my_func, @function - * .quad .TOC.-my_func - * my_func: - * .reloc ., R_PPC64_ENTRY ; optional - * ld r2,-8(r12) - * add r2,r2,r12 - * .localentry my_func, .-my_func - * - * my_func is the global entry point, which, when called, sets up the TOC. - * .localentry is the local entry point, for calls to the function from within - * the object file. The local entry point is 8 bytes after the global entry - * point. - */ -static bool is_gcc6_localentry_bundled_sym(struct kpatch_elf *kelf, - struct symbol *sym) -{ - switch(kelf->arch) { - case AARCH64: - return false; - case PPC64: - return ((PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other) != 0) && - sym->sym.st_value == 8); - case X86_64: - return false; - case S390: - return false; - default: - ERROR("unsupported arch"); - } - - return false; -} - -/* - * On ppc64le, when a function references data, it does so indirectly, via the - * .toc section. So there are *two* levels of relas: - * - * 1) the original function rela, referring to the .toc section; and - * - * 2) the .toc section rela, referring to the data needed by the function. - * - * For example: - * - * Relocation section '.rela.text.netlink_release' at offset 0xcadf0 contains 44 entries: - * ... - * 0000000000000398 0000007300000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 138 - * 00000000000003a0 0000007300000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 138 - * - * Relocation section '.rela.toc' at offset 0xcc6b0 contains 46 entries: - * ... - * 0000000000000138 0000002a00000026 R_PPC64_ADDR64 0000000000000000 .text.deferred_put_nlk_sk + 8 - * - * The below function takes the "first level" rela as input, and, if it refers - * to .toc, returns the "second level" rela, which is the one that refers to - * the actual data symbol. - * - * In some rare cases, a .toc entry has constant data, and thus has no - * corresponding rela. In that case, NULL is returned. - */ -static struct rela *toc_rela(const struct rela *rela) -{ - if (rela->type != R_PPC64_TOC16_HA && - rela->type != R_PPC64_TOC16_LO_DS) - return (struct rela *)rela; - - /* Only constants in toc */ - if (!rela->sym->sec->rela) - return NULL; - - /* Will return NULL for .toc constant entries */ - return find_rela_by_offset(rela->sym->sec->rela, - (unsigned int)rela->addend); -} - -/* - * Mapping symbols are used to mark and label the transitions between code and - * data in elf files. They begin with a "$" dollar symbol. Don't correlate them - * as they often all have the same name either "$x" to mark the start of code - * or "$d" to mark the start of data. - */ -static bool kpatch_is_mapping_symbol(struct kpatch_elf *kelf, struct symbol *sym) -{ - if (kelf->arch != AARCH64) - return false; - - if (sym->name && sym->name[0] == '$' - && sym->type == STT_NOTYPE \ - && sym->bind == STB_LOCAL) - return true; - return false; -} - -/* - * When compiling with -ffunction-sections and -fdata-sections, almost every - * symbol gets its own dedicated section. We call such symbols "bundled" - * symbols. They're indicated by "sym->sec->sym == sym". - */ -static void kpatch_bundle_symbols(struct kpatch_elf *kelf) -{ - struct symbol *sym; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (is_bundleable(sym)) { - if (sym->sym.st_value != 0 && - !is_gcc6_localentry_bundled_sym(kelf, sym)) { - ERROR("symbol %s at offset %lu within section %s, expected 0", - sym->name, sym->sym.st_value, - sym->sec->name); - } - - sym->sec->sym = sym; - } - } -} - -static struct symbol *kpatch_lookup_parent(struct kpatch_elf *kelf, - const char *symname, - const char *child_suffix) -{ - struct symbol *parent; - char *pname; - - pname = strndup(symname, child_suffix - symname); - if (!pname) - ERROR("strndup"); - - parent = find_symbol_by_name(&kelf->symbols, pname); - free(pname); - - return parent; -} - -/* - * During optimization gcc may move unlikely execution branches into *.cold - * subfunctions. Some functions can also be split into multiple *.part - * functions. - * kpatch_detect_child_functions detects such subfunctions and - * crossreferences them with their parent functions through parent/child - * pointers. - */ -static void kpatch_detect_child_functions(struct kpatch_elf *kelf) -{ - struct symbol *sym; - - list_for_each_entry(sym, &kelf->symbols, list) { - char *childstr; - - if (sym->type != STT_FUNC) - continue; - - childstr = strstr(sym->name, ".cold"); - if (childstr) { - sym->parent = kpatch_lookup_parent(kelf, sym->name, - childstr); - if (!sym->parent) - ERROR("failed to find parent function for %s", - sym->name); - } else { - childstr = strstr(sym->name, ".part."); - if (!childstr) - continue; - sym->parent = kpatch_lookup_parent(kelf, sym->name, - childstr); - } - - if (sym->parent) - list_add_tail(&sym->subfunction_node, &sym->parent->children); - } -} - -static bool is_dynamic_debug_symbol(struct symbol *sym) -{ - if (sym->type == STT_OBJECT && !strcmp(sym->sec->name, "__verbose")) - return true; - if (sym->type == STT_OBJECT && !strcmp(sym->sec->name, "__dyndbg")) - return true; - if (sym->type == STT_SECTION && !strcmp(sym->name, "__verbose")) - return true; - if (sym->type == STT_SECTION && !strcmp(sym->name, "__dyndbg")) - return true; - return false; -} - -static bool is_string_literal_section(struct section *sec) -{ - return !strncmp(sec->name, ".rodata.", 8) && strstr(sec->name, ".str"); -} - -/* - * This function detects whether the given symbol is a "special" static local - * variable (for lack of a better term). - * - * Special static local variables should never be correlated and should always - * be included if they are referenced by an included function. - */ -static bool is_special_static(struct symbol *sym) -{ - static char *var_names[] = { - "__key", - "__warned", - "__already_done.", - "__func__", - "__FUNCTION__", - "_rs", - "CSWTCH", - "_entry", - NULL, - }; - char **var_name; - - if (!sym) - return false; - - /* pr_debug() uses static local variables in the __verbose or __dyndbg section */ - if (is_dynamic_debug_symbol(sym)) - return true; - - if (sym->type == STT_SECTION) { - /* make sure section is bundled */ - if (!sym->sec->sym) - return false; - - /* use bundled object/function symbol for matching */ - sym = sym->sec->sym; - } - - if (sym->type != STT_OBJECT || sym->bind != STB_LOCAL) - return false; - - if (!strcmp(sym->sec->name, ".data.once")) - return true; - - for (var_name = var_names; *var_name; var_name++) { - size_t var_name_len = strlen(*var_name); - char buf[256]; - - snprintf(buf, 256, ".%s.", *var_name); - - /* First look for gcc-style statics: '.' */ - if (!strncmp(sym->name, buf + 1, var_name_len + 1)) - return true; - - buf[var_name_len + 1] = '\0'; - /* Next clang-style statics: '.' */ - if (strstr(sym->name, buf)) - return true; - } - - return false; -} - -static bool has_digit_tail(char *tail) -{ - if (*tail != '.') - return false; - - while (isdigit(*++tail)) - ; - - if (!*tail) - return true; - - return false; -} - -/* - * Hack for __UNIQUE_ID(). The following should match: - * - * __UNIQUE_ID_ddebug1131.186 - * __UNIQUE_ID_ddebug1132.187 - */ -static int __kpatch_unique_id_strcmp(char *s1, char *s2) -{ - /* match '__UNIQUE_ID_ddebug' */ - while (*s1 == *s2) { - if (!*s1) - return 0; - s1++; - s2++; - } - - /* skip digits before '.' or EOL */ - while (isdigit(*s1)) - s1++; - while (isdigit(*s2)) - s2++; - - if ((!*s1 || has_digit_tail(s1)) && - (!*s2 || has_digit_tail(s2))) - return 0; - - return 1; -} - -/* - * This is like strcmp, but for gcc-mangled symbols. It skips the comparison - * of any substring which consists of '.' followed by any number of digits. - */ -static int kpatch_mangled_strcmp(char *s1, char *s2) -{ - /* - * ELF string sections aren't mangled, though they look that way. Just - * compare them normally. - */ - if (strstr(s1, ".str1.")) - return strcmp(s1, s2); - - if (!strncmp(s1, "__UNIQUE_ID_", 12)) - return __kpatch_unique_id_strcmp(s1, s2); - - while (*s1 == *s2) { - if (!*s1) - return 0; - if (*s1 == '.' && isdigit(s1[1])) { - if (!isdigit(s2[1])) - return 1; - while (isdigit(*++s1)) - ; - while (isdigit(*++s2)) - ; - } else { - s1++; - s2++; - } - } - - if ((!*s1 && has_digit_tail(s2)) || - (!*s2 && has_digit_tail(s1))) - return 0; - - return 1; -} - -static bool rela_equal(struct rela *rela1, struct rela *rela2) -{ - struct rela *rela_toc1, *rela_toc2; - unsigned long toc_data1 = 0, toc_data2 = 0; /* = 0 to prevent gcc warning */ - - if (rela1->type != rela2->type || - rela1->offset != rela2->offset) - return false; - - /* - * On x86, .altinstr_aux is used to store temporary code which allows - * static_cpu_has() to work before apply_alternatives() has run. This - * code is completely inert for modules, because apply_alternatives() - * runs during module init, before the module is fully formed. Any - * changed references to it (i.e. changed addend) can be ignored. As - * long as they're both references to .altinstr_aux, they can be - * considered equal, even if the addends differ. - */ - if (!strcmp(rela1->sym->name, ".altinstr_aux") && - !strcmp(rela2->sym->name, ".altinstr_aux")) - return true; - - /* - * With -mcmodel=large on ppc64le, GCC might generate entries in the .toc - * section for relocation symbol references. The .toc offsets may change - * between the original and patched .o, so comparing ".toc + offset" isn't - * right. Compare the .toc-based symbols by reading the corresponding relas - * from the .toc section. - */ - rela_toc1 = toc_rela(rela1); - if (!rela_toc1) { - /* - * .toc section entries are mostly place holder for relocation entries, specified - * in .rela.toc section. Sometimes, .toc section may have constants as entries. - * These constants are not reference to any symbols, but plain instructions mostly - * due to some arithmetics in the functions referring them. - * - * They are referred by the functions like normal .toc entries, these entries can - * not be resolved to any symbols. - * - * Disassembly of section .toc: - * - * 0000000000000000 <.toc>: - * ... - * 148: R_PPC64_ADDR64 .data.capacity_margin - * 150: 0b d7 a3 70 andi. r3,r5,55051 - * 154: 3d 0a d7 a3 lhz r30,2621(r23) - * 158: R_PPC64_ADDR64 sched_max_numa_distance - * - * Relocation section '.rela.toc' at offset 0xadac0 contains 160 entries: - * Offset Info Type Symbol's Value Symbol's Name + Addend - * ... - * 0000000000000148 0000009100000026 R_PPC64_ADDR64 0000000000000000 .data.capacity_margin + 0 - * 0000000000000158 000001a500000026 R_PPC64_ADDR64 0000000000000000 sched_max_numa_distance + 0 - * - * Relocation section '.rela.text.select_task_rq_fair' at offset 0x90e98 contains 37 entries: - * Offset Info Type Symbol's Value Symbol's Name + Addend - * ... - * 00000000000004a0 0000008800000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 148 - * 00000000000004ac 0000008800000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 148 - * 0000000000000514 0000008800000032 R_PPC64_TOC16_HA 0000000000000000 .toc + 150 - * 000000000000051c 0000008800000040 R_PPC64_TOC16_LO_DS 0000000000000000 .toc + 150 - */ - memcpy(&toc_data1, rela1->sym->sec->data->d_buf + rela1->addend, sizeof(toc_data1)); - if (!toc_data1) - ERROR(".toc entry not found %s + %lx", rela1->sym->name, rela1->addend); - } - - rela_toc2 = toc_rela(rela2); - if (!rela_toc2) { - memcpy(&toc_data2, rela2->sym->sec->data->d_buf + rela2->addend, sizeof(toc_data2)); - if (!toc_data2) - ERROR(".toc entry not found %s + %lx", rela2->sym->name, rela2->addend); - } - - if (!rela_toc1 && !rela_toc2) - return toc_data1 == toc_data2; - - if (!rela_toc1 || !rela_toc2) - return false; - - if (rela_toc1->string) - return rela_toc2->string && !strcmp(rela_toc1->string, rela_toc2->string); - - if (rela_toc1->addend != rela_toc2->addend) - return false; - - return !kpatch_mangled_strcmp(rela_toc1->sym->name, rela_toc2->sym->name); -} - -static void kpatch_compare_correlated_rela_section(struct section *relasec) -{ - struct rela *rela1, *rela2 = NULL; - - /* - * On ppc64le, don't compare the .rela.toc section. The .toc and - * .rela.toc sections are included as standard elements. - */ - if (!strcmp(relasec->name, ".rela.toc")) { - relasec->status = SAME; - return; - } - - rela2 = list_entry(relasec->twin->relas.next, struct rela, list); - list_for_each_entry(rela1, &relasec->relas, list) { - if (rela_equal(rela1, rela2)) { - rela2 = list_entry(rela2->list.next, struct rela, list); - continue; - } - relasec->status = CHANGED; - return; - } - - relasec->status = SAME; -} - -static void kpatch_compare_correlated_nonrela_section(struct section *sec) -{ - struct section *sec1 = sec, *sec2 = sec->twin; - - if (sec1->sh.sh_type != SHT_NOBITS && - memcmp(sec1->data->d_buf, sec2->data->d_buf, sec1->data->d_size)) - sec->status = CHANGED; - else - sec->status = SAME; -} - -static void kpatch_compare_correlated_section(struct section *sec) -{ - struct section *sec1 = sec, *sec2 = sec->twin; - - /* Compare section headers (must match or fatal) */ - if (sec1->sh.sh_type != sec2->sh.sh_type || - sec1->sh.sh_flags != sec2->sh.sh_flags || - sec1->sh.sh_entsize != sec2->sh.sh_entsize || - (sec1->sh.sh_addralign != sec2->sh.sh_addralign && - !is_text_section(sec1))) - DIFF_FATAL("%s section header details differ from %s", sec1->name, sec2->name); - - /* Short circuit for mcount sections, we rebuild regardless */ - if (!strcmp(sec->name, ".rela__mcount_loc") || - !strcmp(sec->name, "__mcount_loc")) { - sec->status = SAME; - goto out; - } - - /* As above but for aarch64 */ - if (!strcmp(sec->name, ".rela__patchable_function_entries") || - !strcmp(sec->name, "__patchable_function_entries")) { - sec->status = SAME; - goto out; - } - - if (sec1->sh.sh_size != sec2->sh.sh_size || - sec1->data->d_size != sec2->data->d_size || - (sec1->rela && !sec2->rela) || - (sec2->rela && !sec1->rela)) { - sec->status = CHANGED; - goto out; - } - - if (is_rela_section(sec)) - kpatch_compare_correlated_rela_section(sec); - else - kpatch_compare_correlated_nonrela_section(sec); -out: - if (sec->status == CHANGED) - log_debug("section %s has changed\n", sec->name); -} - -/* - * This function is not comprehensive, i.e. it doesn't detect immediate loads - * to *all* registers. It only detects those which have been found in the wild - * to be involved in the load of a __LINE__ immediate. If we miss some, that's - * ok, we'll find them later when someone notices a function falsely being - * reported as changed ;-) - * - * Right now we're only checking immediate loads to the registers corresponding - * to function arguments 2 and 3 for each respective arch's calling convention. - * (Argument 1 is typically the printf format string). Eventually we might - * want to consider just checking *all* registers which could conceivably be - * used as function arguments. But in practice, arg2 and arg3 seem to be the - * main ones, so for now, take a more conservative approach at the risk of - * failing to detect some of the more obscure __LINE__-only changed functions. - */ -static bool insn_is_load_immediate(struct kpatch_elf *kelf, void *addr) -{ - unsigned char *insn = addr; - - switch(kelf->arch) { - - case X86_64: - /* arg2: mov $imm, %esi */ - if (insn[0] == 0xbe) - return true; - - /* arg3: mov $imm, %edx */ - if (insn[0] == 0xba) - return true; - - break; - - case PPC64: - /* - * ppc64le insns are LE-encoded: - * - * 0a 00 80 38 li r4,10 - * 47 14 a0 38 li r5,5191 - */ - - /* arg2: li r4, imm */ - if (insn[3] == 0x38 && insn[2] == 0x80) - return true; - - /* arg3: li r5, imm */ - if (insn[3] == 0x38 && insn[2] == 0xa0) - return true; - - break; - - case S390: - /* arg2: lghi %r3, imm */ - if (insn[0] == 0xa7 && insn[1] == 0x39) - return true; - - /* arg3: lghi %r4, imm */ - if (insn[0] == 0xa7 && insn[1] == 0x49) - return true; - - break; - - default: - ERROR("unsupported arch"); - } - - return false; -} - -/* - * Determine if a section has changed only due to a __LINE__ number change, - * e.g. a WARN() or might_sleep() macro's embedding of the line number into an - * instruction operand. - * - * Warning: Hackery lies herein. It's hopefully justified by the fact that - * this issue is very common. - * - * Example WARN(): - * - * 938: be 70 00 00 00 mov $0x70,%esi - * 93d: 48 c7 c7 00 00 00 00 mov $0x0,%rdi - * 940: R_X86_64_32S .rodata.tcp_conn_request.str1.8+0x88 - * 944: c6 05 00 00 00 00 01 movb $0x1,0x0(%rip) # 94b - * 946: R_X86_64_PC32 .data.unlikely-0x1 - * 94b: e8 00 00 00 00 callq 950 - * 94c: R_X86_64_PC32 warn_slowpath_null-0x4 - * - * Example might_sleep: - * - * 50f: be f7 01 00 00 mov $0x1f7,%esi - * 514: 48 c7 c7 00 00 00 00 mov $0x0,%rdi - * 517: R_X86_64_32S .rodata.do_select.str1.8+0x98 - * 51b: e8 00 00 00 00 callq 520 - * 51c: R_X86_64_PC32 ___might_sleep-0x4 - */ -static bool _kpatch_line_macro_change_only(struct kpatch_elf *kelf, - struct section *sec) -{ - unsigned long offset, insn1_len, insn2_len; - void *data1, *data2, *insn1, *insn2; - struct rela *r, *rela; - bool found, found_any = false; - - if (sec->status != CHANGED || - is_rela_section(sec) || - !is_text_section(sec) || - sec->sh.sh_size != sec->twin->sh.sh_size || - !sec->rela || - sec->rela->status != SAME) - return false; - - data1 = sec->twin->data->d_buf; - data2 = sec->data->d_buf; - for (offset = 0; offset < sec->sh.sh_size; offset += insn1_len) { - - insn1 = data1 + offset; - insn2 = data2 + offset; - - insn1_len = insn_length(kelf, insn1); - insn2_len = insn_length(kelf, insn2); - - if (!insn1_len || !insn2_len) - ERROR("can't decode instruction in section %s at offset 0x%lx", - sec->name, offset); - - if (insn1_len != insn2_len) - return false; - - if (!memcmp(insn1, insn2, insn1_len)) - continue; - - /* - * Here we found a difference between two instructions of the - * same length. Only ignore the change if: - * - * a) the instructions match a known pattern of a '__LINE__' - * macro immediate value which was embedded in the - * instruction; and - * - * b) the instructions are followed by certain expected - * relocations. - */ - - if (!insn_is_load_immediate(kelf, insn1) || - !insn_is_load_immediate(kelf, insn2)) - return false; - - found = false; - list_for_each_entry(r, &sec->rela->relas, list) { - - if (r->offset < offset + insn1_len) - continue; - - rela = toc_rela(r); - if (!rela) - continue; - - if (rela->string) - continue; - - if (!strncmp(rela->sym->name, "__warned.", 9) || - !strncmp(rela->sym->name, "__already_done.", 15) || - !strncmp(rela->sym->name, "__func__.", 9)) - continue; - - if (!strncmp(rela->sym->name, "warn_slowpath_", 14) || - !strcmp(rela->sym->name, "__warn_printk") || - !strcmp(rela->sym->name, "__might_sleep") || - !strcmp(rela->sym->name, "___might_sleep") || - !strcmp(rela->sym->name, "__might_fault") || - !strcmp(rela->sym->name, "printk") || - !strcmp(rela->sym->name, "_printk") || - !strcmp(rela->sym->name, "lockdep_rcu_suspicious") || - !strcmp(rela->sym->name, "__btrfs_abort_transaction") || - !strcmp(rela->sym->name, "__btrfs_handle_fs_error") || - !strcmp(rela->sym->name, "__btrfs_panic")) { - found = true; - break; - } - return false; - } - if (!found) - return false; - - found_any = true; - } - - if (!found_any) - ERROR("no instruction changes detected for changed section %s", - sec->name); - - return true; -} - -static bool _kpatch_line_macro_change_only_aarch64(struct kpatch_elf *kelf, - struct section *sec) -{ - unsigned char *start1, *start2; - unsigned long size, offset, insn_len; - struct rela *rela; - int lineonly = 0, found; - - insn_len = insn_length(kelf, NULL); - - if (sec->status != CHANGED || - is_rela_section(sec) || - !is_text_section(sec) || - sec->sh.sh_size != sec->twin->sh.sh_size || - !sec->rela || - sec->rela->status != SAME) - return false; - - start1 = sec->twin->data->d_buf; - start2 = sec->data->d_buf; - size = sec->sh.sh_size; - for (offset = 0; offset < size; offset += insn_len) { - if (!memcmp(start1 + offset, start2 + offset, insn_len)) - continue; - - /* Verify mov w2 */ - if (((start1[offset] & 0b11111) != 0x2) || (start1[offset+3] != 0x52) || - ((start1[offset] & 0b11111) != 0x2) || (start2[offset+3] != 0x52)) - return false; - - /* - * Verify zero or more string relas followed by a - * warn_slowpath_* or another similar rela. - */ - found = 0; - list_for_each_entry(rela, &sec->rela->relas, list) { - if (rela->offset < offset + insn_len) - continue; - if (rela->string) - continue; - if (!strncmp(rela->sym->name, "__warned.", 9) || - !strncmp(rela->sym->name, "__already_done.", 15)) - continue; - if (!strcmp(rela->sym->name, "__warn_printk")) { - found = 1; - break; - } - return false; - } - if (!found) - return false; - - lineonly = 1; - } - - if (!lineonly) - ERROR("no instruction changes detected for changed section %s", - sec->name); - - return true; -} - -static bool kpatch_line_macro_change_only(struct kpatch_elf *kelf, - struct section *sec) -{ - switch(kelf->arch) { - case AARCH64: - return _kpatch_line_macro_change_only_aarch64(kelf, sec); - case PPC64: - case S390: - case X86_64: - return _kpatch_line_macro_change_only(kelf, sec); - default: - ERROR("unsupported arch"); - } - return false; -} - -/* - * Child functions with "*.cold" names don't have _fentry_ calls, but "*.part", - * often do. In the later case, it is not necessary to include the parent - * in the output object when the child function has changed. - */ -static bool kpatch_changed_child_needs_parent_profiling(struct symbol *sym) -{ - struct symbol *child; - - list_for_each_entry(child, &sym->children, subfunction_node) { - if (child->has_func_profiling) - continue; - if (child->sec->status == CHANGED || - kpatch_changed_child_needs_parent_profiling(child)) - return true; - } - - return false; -} - -static void kpatch_compare_sections(struct kpatch_elf *kelf) -{ - struct section *sec; - struct list_head *seclist = &kelf->sections; - - /* compare all sections */ - list_for_each_entry(sec, seclist, list) { - if (sec->twin) - kpatch_compare_correlated_section(sec); - else - sec->status = NEW; - } - - /* exclude WARN-only, might_sleep changes */ - list_for_each_entry(sec, seclist, list) { - if (kpatch_line_macro_change_only(kelf, sec)) { - log_debug("reverting macro / line number section %s status to SAME\n", - sec->name); - sec->status = SAME; - } - } - - /* sync symbol status */ - list_for_each_entry(sec, seclist, list) { - if (is_rela_section(sec)) { - if (sec->base->sym && sec->base->sym->status != CHANGED) - sec->base->sym->status = sec->status; - } else { - struct symbol *sym = sec->sym; - - if (sym && sym->status != CHANGED) - sym->status = sec->status; - - if (sym && sym->status == SAME && - kpatch_changed_child_needs_parent_profiling(sym)) - sym->status = CHANGED; - } - } -} - -static enum subsection kpatch_subsection_type(struct section *sec) -{ - if (!strncmp(sec->name, ".text.unlikely.", 15)) - return SUBSECTION_UNLIKELY; - - if (!strncmp(sec->name, ".text.hot.", 10)) - return SUBSECTION_HOT; - - return SUBSECTION_NORMAL; -} - -static bool kpatch_subsection_changed(struct section *sec1, struct section *sec2) -{ - return kpatch_subsection_type(sec1) != kpatch_subsection_type(sec2); -} - -static struct symbol *kpatch_get_correlated_parent(struct symbol *sym) -{ - while (sym->parent && !sym->parent->twin) - sym = sym->parent; - return sym->parent; -} - -static void kpatch_compare_correlated_symbol(struct symbol *sym) -{ - struct symbol *sym1 = sym, *sym2 = sym->twin; - - if (sym1->sym.st_info != sym2->sym.st_info || - (sym1->sec && !sym2->sec) || - (sym2->sec && !sym1->sec)) - DIFF_FATAL("symbol info mismatch: %s", sym1->name); - - /* - * If two symbols are correlated but their sections are not, then the - * symbol has changed sections. This is only allowed if the symbol is - * moving out of an ignored section, or moving between normal/hot/unlikely - * subsections. - */ - if (sym1->sec && sym2->sec && sym1->sec->twin != sym2->sec) { - if ((sym2->sec->twin && sym2->sec->twin->ignore) || - kpatch_subsection_changed(sym1->sec, sym2->sec)) - sym->status = CHANGED; - else - DIFF_FATAL("symbol changed sections: %s", sym1->name); - } - - if (sym1->type == STT_OBJECT && - sym1->sym.st_size != sym2->sym.st_size) - DIFF_FATAL("object size mismatch: %s", sym1->name); - - if (sym1->sym.st_shndx == SHN_UNDEF || - sym1->sym.st_shndx == SHN_ABS) - sym1->status = SAME; - - /* - * The status of LOCAL symbols is dependent on the status of their - * matching section and is set during section comparison. - */ -} - -static void kpatch_compare_symbols(struct list_head *symlist) -{ - struct symbol *sym; - - list_for_each_entry(sym, symlist, list) { - if (sym->twin) - kpatch_compare_correlated_symbol(sym); - else - sym->status = NEW; - - log_debug("symbol %s is %s\n", sym->name, status_str(sym->status)); - } -} - -#define CORRELATE_ELEMENT(_e1_, _e2_, kindstr) \ -do { \ - typeof(_e1_) e1 = (_e1_); \ - typeof(_e2_) e2 = (_e2_); \ - e1->twin = e2; \ - e2->twin = e1; \ - /* set initial status, might change */ \ - e1->status = e2->status = SAME; \ - if (strcmp(e1->name, e2->name)) { \ - /* Rename mangled element */ \ - log_debug("renaming %s %s to %s\n", \ - kindstr, e2->name, e1->name); \ - e2->name = strdup(e1->name); \ - if (!e2->name) \ - ERROR("strdup"); \ - } \ -} while (0) - -#define UNCORRELATE_ELEMENT(_elem_) \ -do { \ - typeof(_elem_) elem = (_elem_); \ - elem->twin->twin = NULL; \ - elem->twin = NULL; \ -} while (0) - -static void __kpatch_correlate_section(struct section *sec_orig, - struct section *sec_patched) -{ - CORRELATE_ELEMENT(sec_orig, sec_patched, "section"); -} - -static void kpatch_correlate_symbol(struct symbol *sym_orig, - struct symbol *sym_patched) -{ - CORRELATE_ELEMENT(sym_orig, sym_patched, "symbol"); - if (sym_orig->lookup_table_file_sym && !sym_patched->lookup_table_file_sym) - sym_patched->lookup_table_file_sym = sym_orig->lookup_table_file_sym; -} - -static void kpatch_correlate_static_local(struct symbol *sym_orig, - struct symbol *sym_patched) -{ - CORRELATE_ELEMENT(sym_orig, sym_patched, "static local"); -} - -static void kpatch_correlate_section(struct section *sec_orig, - struct section *sec_patched) -{ - __kpatch_correlate_section(sec_orig, sec_patched); - - if (is_rela_section(sec_orig)) { - __kpatch_correlate_section(sec_orig->base, sec_patched->base); - sec_orig = sec_orig->base; - sec_patched = sec_patched->base; - } else if (sec_orig->rela && sec_patched->rela) { - __kpatch_correlate_section(sec_orig->rela, sec_patched->rela); - } - - if (sec_orig->secsym) - kpatch_correlate_symbol(sec_orig->secsym, sec_patched->secsym); - if (sec_orig->sym) - kpatch_correlate_symbol(sec_orig->sym, sec_patched->sym); -} - -static void kpatch_correlate_sections(struct list_head *seclist_orig, - struct list_head *seclist_patched) -{ - struct section *sec_orig, *sec_patched; - - list_for_each_entry(sec_orig, seclist_orig, list) { - if (sec_orig->twin) - continue; - list_for_each_entry(sec_patched, seclist_patched, list) { - if (kpatch_mangled_strcmp(sec_orig->name, sec_patched->name) || - sec_patched->twin) - continue; - - if (is_special_static(is_rela_section(sec_orig) ? - sec_orig->base->secsym : - sec_orig->secsym)) - continue; - - /* - * Group sections must match exactly to be correlated. - * Changed group sections are currently not supported. - */ - if (sec_orig->sh.sh_type == SHT_GROUP) { - if (sec_orig->data->d_size != sec_patched->data->d_size) - continue; - if (memcmp(sec_orig->data->d_buf, sec_patched->data->d_buf, - sec_orig->data->d_size)) - continue; - } - - kpatch_correlate_section(sec_orig, sec_patched); - break; - } - } -} - -static void kpatch_correlate_symbols(struct kpatch_elf *kelf_orig, - struct kpatch_elf *kelf_patched) -{ - struct symbol *sym_orig, *sym_patched; - - list_for_each_entry(sym_orig, &kelf_orig->symbols, list) { - if (sym_orig->twin) - continue; - list_for_each_entry(sym_patched, &kelf_patched->symbols, list) { - if (kpatch_mangled_strcmp(sym_orig->name, sym_patched->name) || - sym_orig->type != sym_patched->type || sym_patched->twin) - continue; - - if (is_special_static(sym_orig)) - continue; - - /* - * The .LCx symbols point to string literals in - * '.rodata..str1.*' sections. They get included - * in kpatch_include_standard_elements(). - */ - if (sym_orig->type == STT_NOTYPE && - !strncmp(sym_orig->name, ".LC", 3)) - continue; - - if (kpatch_is_mapping_symbol(kelf_orig, sym_orig)) - continue; - - /* group section symbols must have correlated sections */ - if (sym_orig->sec && - sym_orig->sec->sh.sh_type == SHT_GROUP && - sym_orig->sec->twin != sym_patched->sec) - continue; - - kpatch_correlate_symbol(sym_orig, sym_patched); - break; - } - } -} - -static void kpatch_compare_elf_headers(Elf *elf_orig, Elf *elf_patched) -{ - GElf_Ehdr ehdr_orig, ehdr_patched; - - if (!gelf_getehdr(elf_orig, &ehdr_orig)) - ERROR("gelf_getehdr"); - - if (!gelf_getehdr(elf_patched, &ehdr_patched)) - ERROR("gelf_getehdr"); - - if (memcmp(ehdr_orig.e_ident, ehdr_patched.e_ident, EI_NIDENT) || - ehdr_orig.e_type != ehdr_patched.e_type || - ehdr_orig.e_machine != ehdr_patched.e_machine || - ehdr_orig.e_version != ehdr_patched.e_version || - ehdr_orig.e_entry != ehdr_patched.e_entry || - ehdr_orig.e_phoff != ehdr_patched.e_phoff || - ehdr_orig.e_flags != ehdr_patched.e_flags || - ehdr_orig.e_ehsize != ehdr_patched.e_ehsize || - ehdr_orig.e_phentsize != ehdr_patched.e_phentsize || - ehdr_orig.e_shentsize != ehdr_patched.e_shentsize) - DIFF_FATAL("ELF headers differ"); -} - -static void kpatch_check_program_headers(Elf *elf) -{ - size_t ph_nr; - - if (elf_getphdrnum(elf, &ph_nr)) - ERROR("elf_getphdrnum"); - - if (ph_nr != 0) - DIFF_FATAL("ELF contains program header"); -} - -static void kpatch_mark_grouped_sections(struct kpatch_elf *kelf) -{ - struct section *groupsec, *sec; - unsigned int *data, *end; - - list_for_each_entry(groupsec, &kelf->sections, list) { - if (groupsec->sh.sh_type != SHT_GROUP) - continue; - data = groupsec->data->d_buf; - end = groupsec->data->d_buf + groupsec->data->d_size; - data++; /* skip first flag word (e.g. GRP_COMDAT) */ - while (data < end) { - sec = find_section_by_index(&kelf->sections, *data); - if (!sec) - ERROR("group section not found"); - sec->grouped = 1; - log_debug("marking section %s (%d) as grouped\n", - sec->name, sec->index); - data++; - } - } -} - -static char *kpatch_section_function_name(struct section *sec) -{ - if (is_rela_section(sec)) - sec = sec->base; - return sec->sym ? sec->sym->name : sec->name; -} - -static struct symbol *kpatch_find_uncorrelated_rela(struct section *relasec, - struct symbol *sym) -{ - struct rela *rela, *rela_toc; - - /* find the patched object's corresponding variable */ - list_for_each_entry(rela, &relasec->relas, list) { - struct symbol *patched_sym; - - rela_toc = toc_rela(rela); - if (!rela_toc) - continue; /* skip toc constants */ - - patched_sym = rela_toc->sym; - - if (patched_sym->twin) - continue; - - if (sym->type != patched_sym->type || - (sym->type == STT_OBJECT && - sym->sym.st_size != patched_sym->sym.st_size)) - continue; - - if (kpatch_mangled_strcmp(patched_sym->name, sym->name)) - continue; - - return patched_sym; - } - - return NULL; -} - -static struct symbol *kpatch_find_static_twin_in_children(struct symbol *parent, - struct symbol *sym) -{ - struct symbol *child; - - list_for_each_entry(child, &parent->children, subfunction_node) { - struct symbol *res; - - /* Only look in children whose rela section differ from the parent's */ - if (child->sec->rela == parent->sec->rela || !child->sec->rela) - continue; - - res = kpatch_find_uncorrelated_rela(child->sec->rela, sym); - /* Need to go deeper */ - if (!res) - res = kpatch_find_static_twin_in_children(child, sym); - if (res != NULL) - return res; - } - - return NULL; -} - -/* - * Given a static local variable symbol and a rela section which references it - * in the base object, find a corresponding usage of a similarly named symbol - * in the patched object. - */ -static struct symbol *kpatch_find_static_twin(struct section *relasec, - struct symbol *sym) -{ - struct symbol *res; - - if (!relasec->twin && relasec->base->sym) { - struct symbol *parent = NULL; - - /* - * The static twin might have been in a .part. symbol in the - * original object that got removed in the patched object. - */ - parent = kpatch_get_correlated_parent(relasec->base->sym); - if (parent) - relasec = parent->sec->rela; - - } - - if (!relasec->twin) - return NULL; - - res = kpatch_find_uncorrelated_rela(relasec->twin, sym); - if (res != NULL) - return res; - - /* Look if reference might have moved to child functions' sections */ - if (relasec->twin->base->sym) - return kpatch_find_static_twin_in_children(relasec->twin->base->sym, - sym); - - return NULL; -} - -static bool kpatch_is_normal_static_local(struct symbol *sym) -{ - if (sym->type != STT_OBJECT || sym->bind != STB_LOCAL) - return false; - - if (!strncmp(sym->name, ".L", 2)) - return false; - - if (!strchr(sym->name, '.')) - return false; - - if (is_special_static(sym)) - return false; - - return true; -} - -static struct rela *kpatch_find_static_twin_ref(struct section *relasec, - struct symbol *sym) -{ - struct rela *rela; - - list_for_each_entry(rela, &relasec->relas, list) { - if (rela->sym == sym->twin) - return rela; - } - - /* Reference to static variable might have moved to child function section */ - if (relasec->base->sym) { - struct symbol *parent = relasec->base->sym; - struct symbol *child; - - list_for_each_entry(child, &parent->children, subfunction_node) { - /* Only look in children whose rela section differ from the parent's */ - if (child->sec->rela == parent->sec->rela || - !child->sec->rela) - continue; - - rela = kpatch_find_static_twin_ref(child->sec->rela, sym); - if (rela) - return rela; - } - } - - return NULL; -} - -/* - * gcc renames static local variables by appending a period and a number. For - * example, __foo could be renamed to __foo.31452. Unfortunately this number - * can arbitrarily change. Correlate them by comparing which functions - * reference them, and rename the patched symbols to match the base symbol - * names. - * - * Some surprising facts about static local variable symbols: - * - * - It's possible for multiple functions to use the same - * static local variable if the variable is defined in an - * inlined function. - * - * - It's also possible for multiple static local variables - * with the same name to be used in the same function if they - * have different scopes. (We have to assume that in such - * cases, the order in which they're referenced remains the - * same between the orig and patched objects, as there's no - * other way to distinguish them.) - * - * - Static locals are usually referenced by functions, but - * they can occasionally be referenced by data sections as - * well. - */ -static void kpatch_correlate_static_local_variables(struct kpatch_elf *orig, - struct kpatch_elf *patched) -{ - struct symbol *sym, *patched_sym; - struct section *relasec; - struct rela *rela; - int bundled, patched_bundled; - - /* - * First undo the correlations for all static locals. Two static - * locals can have the same numbered suffix in the orig and patched - * objects by coincidence. - */ - list_for_each_entry(sym, &orig->symbols, list) { - - if (!kpatch_is_normal_static_local(sym)) - continue; - - if (sym->twin) - UNCORRELATE_ELEMENT(sym); - - bundled = sym == sym->sec->sym; - if (bundled && sym->sec->twin) { - UNCORRELATE_ELEMENT(sym->sec); - - if (sym->sec->secsym) - UNCORRELATE_ELEMENT(sym->sec->secsym); - - if (sym->sec->rela) - UNCORRELATE_ELEMENT(sym->sec->rela); - } - } - - /* - * Do the correlations: for each section reference to a static local, - * look for a corresponding reference in the section's twin. - */ - list_for_each_entry(relasec, &orig->sections, list) { - - if (!is_rela_section(relasec) || - is_debug_section(relasec) || - !strcmp(relasec->name, ".rela.toc")) - continue; - - list_for_each_entry(rela, &relasec->relas, list) { - - if (!toc_rela(rela)) - continue; /* skip toc constants */ - sym = toc_rela(rela)->sym; - - if (!kpatch_is_normal_static_local(sym)) - continue; - - if (sym->twin) - continue; - - bundled = sym == sym->sec->sym; - if (bundled && sym->sec == relasec->base) { - /* - * A rare case where a static local data - * structure references itself. There's no - * reliable way to correlate this. Hopefully - * there's another reference to the symbol - * somewhere that can be used. - */ - log_debug("can't correlate static local %s's reference to itself\n", - sym->name); - continue; - } - - patched_sym = kpatch_find_static_twin(relasec, sym); - if (!patched_sym) - DIFF_FATAL("reference to static local variable %s in %s was removed", - sym->name, - kpatch_section_function_name(relasec)); - - patched_bundled = patched_sym == patched_sym->sec->sym; - if (bundled != patched_bundled) - ERROR("bundle mismatch for symbol %s", sym->name); - if (!bundled && sym->sec->twin != patched_sym->sec) - ERROR("sections %s and %s aren't correlated for symbol %s", - sym->sec->name, patched_sym->sec->name, sym->name); - - kpatch_correlate_static_local(sym, patched_sym); - - if (bundled) - kpatch_correlate_section(sym->sec, patched_sym->sec); - } - } - - /* - * Make sure that: - * - * 1. all the orig object's referenced static locals have been - * correlated; and - * - * 2. each reference to a static local in the orig object has a - * corresponding reference in the patched object (because a static - * local can be referenced by more than one section). - */ - list_for_each_entry(relasec, &orig->sections, list) { - - if (!is_rela_section(relasec) || - is_debug_section(relasec)) - continue; - - list_for_each_entry(rela, &relasec->relas, list) { - struct section *target_sec = relasec; - - sym = rela->sym; - if (!kpatch_is_normal_static_local(sym)) - continue; - - if (!relasec->twin && relasec->base->sym) { - struct symbol *parent = NULL; - - parent = kpatch_get_correlated_parent(relasec->base->sym); - if (parent) - target_sec = parent->sec->rela; - } - - if (!sym->twin || !target_sec->twin) - DIFF_FATAL("reference to static local variable %s in %s was removed", - sym->name, - kpatch_section_function_name(target_sec)); - - if (!kpatch_find_static_twin_ref(target_sec->twin, sym)) - DIFF_FATAL("static local %s has been correlated with %s, but patched %s is missing a reference to it", - sym->name, sym->twin->name, - kpatch_section_function_name(target_sec->twin)); - } - } - - /* - * Now go through the patched object and look for any uncorrelated - * static locals to see if we need to print any warnings about new - * variables. - */ - list_for_each_entry(relasec, &patched->sections, list) { - - if (!is_rela_section(relasec) || - is_debug_section(relasec)) - continue; - - list_for_each_entry(rela, &relasec->relas, list) { - - sym = rela->sym; - if (!kpatch_is_normal_static_local(sym)) - continue; - - if (sym->twin) - continue; - - log_normal("WARNING: unable to correlate static local variable %s used by %s, assuming variable is new\n", - sym->name, - kpatch_section_function_name(relasec)); - return; - } - } -} - -static void kpatch_correlate_elfs(struct kpatch_elf *kelf_orig, - struct kpatch_elf *kelf_patched) -{ - kpatch_correlate_sections(&kelf_orig->sections, &kelf_patched->sections); - kpatch_correlate_symbols(kelf_orig, kelf_patched); -} - -static void kpatch_compare_correlated_elements(struct kpatch_elf *kelf) -{ - /* lists are already correlated at this point */ - kpatch_compare_sections(kelf); - kpatch_compare_symbols(&kelf->symbols); -} - -static bool is_callback_section(struct section *sec) { - - static char *callback_sections[] = { - ".kpatch.callbacks.pre_patch", - ".kpatch.callbacks.post_patch", - ".kpatch.callbacks.pre_unpatch", - ".kpatch.callbacks.post_unpatch", - ".rela.kpatch.callbacks.pre_patch", - ".rela.kpatch.callbacks.post_patch", - ".rela.kpatch.callbacks.pre_unpatch", - ".rela.kpatch.callbacks.post_unpatch", - NULL, - }; - char **callback_sec; - - for (callback_sec = callback_sections; *callback_sec; callback_sec++) - if (!strcmp(sec->name, *callback_sec)) - return true; - - return false; -} - -/* - * Mangle the relas a little. The compiler will sometimes use section symbols - * to reference local objects and functions rather than the object or function - * symbols themselves. We substitute the object/function symbols for the - * section symbol in this case so that the relas can be properly correlated and - * so that the existing object/function in vmlinux can be linked to. - */ -static void kpatch_replace_sections_syms(struct kpatch_elf *kelf) -{ - struct section *relasec; - struct rela *rela; - struct symbol *sym; - long target_off; - bool found = false; - - log_debug("\n"); - - list_for_each_entry(relasec, &kelf->sections, list) { - if (!is_rela_section(relasec) || is_debug_section(relasec)) - continue; - - list_for_each_entry(rela, &relasec->relas, list) { - - if (rela->sym->type != STT_SECTION || !rela->sym->sec) - continue; - - /* - * These sections don't have symbols associated with - * them: - */ - if (!strcmp(rela->sym->name, ".toc") || - !strcmp(rela->sym->name, ".fixup") || - !strcmp(rela->sym->name, ".altinstr_replacement") || - !strcmp(rela->sym->name, ".altinstr_aux") || - !strcmp(rela->sym->name, ".text..refcount")) - continue; - - /* - * Replace references to bundled sections with their - * symbols. - */ - if (rela->sym->sec->sym) { - rela->sym = rela->sym->sec->sym; - - /* - * On ppc64le with GCC6+, even with - * -ffunction-sections, the function symbol - * starts 8 bytes past the beginning of the - * section, because the .TOC pointer is at the - * beginning, right before the code. So even - * though the symbol is bundled, we can't - * assume it's at offset 0 in the section. - */ - rela->addend -= rela->sym->sym.st_value; - - continue; - } - - target_off = rela_target_offset(kelf, relasec, rela); - - /* - * Attempt to replace references to unbundled sections - * with their symbols. - */ - list_for_each_entry(sym, &kelf->symbols, list) { - long start, end; - - if (sym->type == STT_SECTION || - sym->sec != rela->sym->sec) - continue; - - start = sym->sym.st_value; - end = sym->sym.st_value + sym->sym.st_size; - - if (is_text_section(relasec->base) && - !is_text_section(sym->sec) && - (rela->type == R_X86_64_32S || - rela->type == R_AARCH64_ABS64) && - rela->addend == (long)sym->sec->sh.sh_size && - end == (long)sym->sec->sh.sh_size) { - - /* - * A special case where gcc needs a - * pointer to the address at the end of - * a data section. - * - * This is usually used with a compare - * instruction to determine when to end - * a loop. The code doesn't actually - * dereference the pointer so this is - * "normal" and we just replace the - * section reference with a reference - * to the last symbol in the section. - * - * Note that this only catches the - * issue when it happens at the end of - * a section. It can also happen in - * the middle of a section. In that - * case, the wrong symbol will be - * associated with the reference. But - * that's ok because: - * - * 1) This situation only occurs when - * gcc is trying to get the address - * of the symbol, not the contents - * of its data; and - * - * 2) Because kpatch doesn't allow data - * sections to change, - * &(var1+sizeof(var1)) will always - * be the same as &var2. - */ - } else if (target_off == start && target_off == end) { - - if(kpatch_is_mapping_symbol(kelf, sym)) - continue; - - /* - * Allow replacement for references to - * empty symbols. - */ - - } else if (target_off < start || target_off >= end) - continue; - - log_debug("%s: replacing %s+%ld reference with %s+%ld\n", - relasec->name, - rela->sym->name, rela->addend, - sym->name, rela->addend - start); - found = true; - - rela->sym = sym; - rela->addend -= start; - break; - } - - if (!found && !is_string_literal_section(rela->sym->sec) && - strncmp(rela->sym->name, ".rodata", 7)) { - ERROR("%s+0x%x: can't find replacement symbol for %s+%ld reference", - relasec->base->name, rela->offset, rela->sym->name, rela->addend); - } - } - } - log_debug("\n"); -} - -static void kpatch_check_func_profiling_calls(struct kpatch_elf *kelf) -{ - struct symbol *sym; - int errs = 0; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type != STT_FUNC || sym->status != CHANGED || - (sym->parent && sym->parent->status == CHANGED)) - continue; - if (!sym->twin->has_func_profiling) { - log_normal("function %s doesn't have patchable function entry, unable to patch\n", - sym->name); - errs++; - } - } - - if (errs) - DIFF_FATAL("%d function(s) can not be patched", errs); -} - -static void kpatch_verify_patchability(struct kpatch_elf *kelf) -{ - struct section *sec; - int errs = 0; - - list_for_each_entry(sec, &kelf->sections, list) { - if (sec->status == CHANGED && !sec->include) { - log_normal("changed section %s not selected for inclusion\n", - sec->name); - errs++; - } - - if (sec->status != SAME && sec->grouped) { - log_normal("changed section %s is part of a section group\n", - sec->name); - errs++; - } - - if (sec->sh.sh_type == SHT_GROUP && sec->status == NEW) { - log_normal("new/changed group sections are not supported\n"); - errs++; - } - - /* - * ensure we aren't including .data.* or .bss.* - * (.data.unlikely and .data.once is ok b/c it only has __warned vars) - */ - if (sec->include && sec->status != NEW && - (!strncmp(sec->name, ".data", 5) || !strncmp(sec->name, ".bss", 4)) && - (strcmp(sec->name, ".data.unlikely") && strcmp(sec->name, ".data.once"))) { - log_normal("data section %s selected for inclusion\n", - sec->name); - errs++; - } - } - - if (errs) - DIFF_FATAL("%d unsupported section change(s)", errs); -} - -static void kpatch_include_symbol(struct symbol *sym); - -static void kpatch_include_section(struct section *sec) -{ - struct rela *rela; - - /* Include the section and its section symbol */ - if (sec->include) - return; - sec->include = 1; - if (sec->secsym) - sec->secsym->include = 1; - - /* - * Include the section's rela section and then recursively include the - * symbols needed by its relas. - */ - if (!sec->rela) - return; - sec->rela->include = 1; - list_for_each_entry(rela, &sec->rela->relas, list) - kpatch_include_symbol(rela->sym); -} - -static void kpatch_include_symbol(struct symbol *sym) -{ - /* - * This function is called recursively from kpatch_include_section(). - * Make sure we don't get into an endless loop. - */ - if (sym->include) - return; - - /* - * The symbol gets included even if its section isn't needed, as it - * might be needed: either permanently for a rela, or temporarily for - * the later creation of a dynrela. - */ - sym->include = 1; - - /* - * For a function/object symbol, if it has a section, we only need to - * include the section if it has changed. Otherwise the symbol will be - * used by relas/dynrelas to link to the real symbol externally. - * - * For section symbols, we always include the section because - * references to them can't otherwise be resolved externally. - */ - if (sym->sec && (sym->type == STT_SECTION || sym->status != SAME)) - kpatch_include_section(sym->sec); -} - -static void kpatch_include_standard_elements(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - - list_for_each_entry(sec, &kelf->sections, list) { - /* - * Include the following sections even if they haven't changed. - * - * Notes about some of the more interesting sections: - * - * - With -fdata-sections, .rodata is only used for: - * - * switch jump tables; - * KASAN data (with KASAN enabled, which is rare); and - * an ugly hack in vmx_vcpu_run(). - * - * Those data are all local to the functions which use them. - * So it's safe to include .rodata. - * - * - On ppc64le, the .toc section is used for all data - * accesses. - * - * Note that if any of these sections have rela sections, they - * will also be included in their entirety. That may result in - * some extra (unused) dynrelas getting created, which should - * be harmless. - */ - if (!strcmp(sec->name, ".shstrtab") || - !strcmp(sec->name, ".strtab") || - !strcmp(sec->name, ".symtab") || - !strcmp(sec->name, ".toc") || - !strcmp(sec->name, ".rodata") || - is_string_literal_section(sec)) { - kpatch_include_section(sec); - } - } - - list_for_each_entry(sym, &kelf->symbols, list) - if (sym->sec && is_string_literal_section(sym->sec)) - sym->include = 1; - - /* include the NULL symbol */ - list_entry(kelf->symbols.next, struct symbol, list)->include = 1; -} - -static bool kpatch_include_callback_elements(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - struct rela *rela; - bool found = false; - - /* include load/unload sections */ - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_callback_section(sec)) - continue; - - sec->include = 1; - found = true; - if (is_rela_section(sec)) { - /* include callback dependencies */ - rela = list_entry(sec->relas.next, struct rela, list); - sym = rela->sym; - log_normal("found callback: %s\n",sym->name); - kpatch_include_symbol(sym); - } else if (sec->secsym) { - sec->secsym->include = 1; - } - } - - /* Strip temporary structure symbols used by the callback macros. */ - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type == STT_OBJECT && sym->sec && - is_callback_section(sym->sec)) - sym->include = 0; - } - - return found; -} - -static void kpatch_include_force_elements(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - struct rela *rela; - - /* include force sections */ - list_for_each_entry(sec, &kelf->sections, list) { - if (!strcmp(sec->name, ".kpatch.force") || - !strcmp(sec->name, ".rela.kpatch.force")) { - sec->include = 1; - if (!is_rela_section(sec)) { - /* .kpatch.force */ - if (sec->secsym) - sec->secsym->include = 1; - continue; - } - /* .rela.kpatch.force */ - list_for_each_entry(rela, &sec->relas, list) - log_normal("function '%s' marked with KPATCH_FORCE_UNSAFE!\n", - rela->sym->name); - } - } - - /* strip temporary global kpatch_force_func_* symbols */ - list_for_each_entry(sym, &kelf->symbols, list) - if (!strncmp(sym->name, "__kpatch_force_func_", - strlen("__kpatch_force_func_"))) - sym->include = 0; -} - -static int kpatch_include_new_globals(struct kpatch_elf *kelf) -{ - struct symbol *sym; - int nr = 0; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->bind == STB_GLOBAL && sym->sec && - sym->status == NEW) { - kpatch_include_symbol(sym); - nr++; - } - } - - return nr; -} - -static int kpatch_include_changed_functions(struct kpatch_elf *kelf) -{ - struct symbol *sym; - int changed_nr = 0; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->status == CHANGED && - sym->type == STT_FUNC) { - changed_nr++; - kpatch_include_symbol(sym); - } - - if (sym->type == STT_FILE) - sym->include = 1; - } - - return changed_nr; -} - -static void kpatch_print_changes(struct kpatch_elf *kelf) -{ - struct symbol *sym; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (!sym->include || !sym->sec || sym->type != STT_FUNC || sym->parent) - continue; - if (sym->status == NEW) - log_normal("new function: %s\n", sym->name); - else if (sym->status == CHANGED) - log_normal("changed function: %s\n", sym->name); - } -} - -static void kpatch_migrate_symbols(struct list_head *src, - struct list_head *dst, - bool (*select)(struct symbol *)) -{ - struct symbol *sym, *safe; - - list_for_each_entry_safe(sym, safe, src, list) { - if (select && !select(sym)) - continue; - - list_del(&sym->list); - list_add_tail(&sym->list, dst); - } -} - -static void kpatch_migrate_included_elements(struct kpatch_elf *kelf, struct kpatch_elf **kelfout) -{ - struct section *sec, *safesec; - struct symbol *sym, *safesym; - struct kpatch_elf *out; - - /* allocate output kelf */ - out = malloc(sizeof(*out)); - if (!out) - ERROR("malloc"); - memset(out, 0, sizeof(*out)); - out->arch = kelf->arch; - INIT_LIST_HEAD(&out->sections); - INIT_LIST_HEAD(&out->symbols); - INIT_LIST_HEAD(&out->strings); - - /* migrate included sections from kelf to out */ - list_for_each_entry_safe(sec, safesec, &kelf->sections, list) { - if (!sec->include) - continue; - list_del(&sec->list); - list_add_tail(&sec->list, &out->sections); - sec->index = 0; - if (!is_rela_section(sec) && sec->secsym && !sec->secsym->include) - /* break link to non-included section symbol */ - sec->secsym = NULL; - } - - /* migrate included symbols from kelf to out */ - list_for_each_entry_safe(sym, safesym, &kelf->symbols, list) { - if (!sym->include) - continue; - list_del(&sym->list); - list_add_tail(&sym->list, &out->symbols); - sym->index = 0; - sym->strip = SYMBOL_DEFAULT; - if (sym->sec && !sym->sec->include) - /* break link to non-included section */ - sym->sec = NULL; - - } - - *kelfout = out; -} - -static void kpatch_reorder_symbols(struct kpatch_elf *kelf) -{ - LIST_HEAD(symbols); - - /* migrate NULL sym */ - kpatch_migrate_symbols(&kelf->symbols, &symbols, is_null_sym); - /* migrate LOCAL FILE sym */ - kpatch_migrate_symbols(&kelf->symbols, &symbols, is_file_sym); - /* migrate LOCAL FUNC syms */ - kpatch_migrate_symbols(&kelf->symbols, &symbols, is_local_func_sym); - /* migrate all other LOCAL syms */ - kpatch_migrate_symbols(&kelf->symbols, &symbols, is_local_sym); - /* migrate all other (GLOBAL) syms */ - kpatch_migrate_symbols(&kelf->symbols, &symbols, NULL); - - list_replace(&symbols, &kelf->symbols); -} - -static int bug_table_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("BUG_STRUCT_SIZE"); - if (!str) - ERROR("BUG_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int ex_table_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("EX_STRUCT_SIZE"); - if (!str) - ERROR("EX_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int jump_table_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("JUMP_STRUCT_SIZE"); - if (!str) - ERROR("JUMP_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int printk_index_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("PRINTK_INDEX_STRUCT_SIZE"); - if (!str) - ERROR("PRINTK_INDEX_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int parainstructions_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("PARA_STRUCT_SIZE"); - if (!str) - ERROR("PARA_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int altinstructions_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("ALT_STRUCT_SIZE"); - if (!str) - ERROR("ALT_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int smp_locks_group_size(struct kpatch_elf *kelf, int offset) -{ - return 4; -} - -static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("STATIC_CALL_STRUCT_SIZE"); - if (!str) - ERROR("STATIC_CALL_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int retpoline_sites_group_size(struct kpatch_elf *kelf, int offset) -{ - return 4; -} - -static int return_sites_group_size(struct kpatch_elf *kelf, int offset) -{ - return 4; -} - -static int fixup_entry_group_size(struct kpatch_elf *kelf, int offset) -{ - static int size = 0; - char *str; - - if (!size) { - str = getenv("FIXUP_STRUCT_SIZE"); - if (!str) - ERROR("FIXUP_STRUCT_SIZE not set"); - size = atoi(str); - } - - return size; -} - -static int fixup_lwsync_group_size(struct kpatch_elf *kelf, int offset) -{ - return 8; -} - -static int fixup_barrier_nospec_group_size(struct kpatch_elf *kelf, int offset) -{ - return 8; -} - -/* - * .s390_indirect_jump, .s390_indirect_call, .s390_indirect_branches, - * .s390_return_reg, .s390_return_mem contains indirect branch locations. This - * is an array of 32 bit elements. These sections could be used during runtime - * to replace the expolines with the normal indirect jump. - */ -static int s390_expolines_group_size(struct kpatch_elf *kelf, int offset) -{ - return 4; -} - -/* - * The rela groups in the .fixup section vary in size. The beginning of each - * .fixup rela group is referenced by the __ex_table section. To find the size - * of a .fixup rela group, we have to traverse the __ex_table relas. - */ -static int fixup_group_size(struct kpatch_elf *kelf, int offset) -{ - struct section *relasec; - struct rela *rela; - int found; - - relasec = find_section_by_name(&kelf->sections, ".rela__ex_table"); - if (!relasec) - ERROR("missing .rela__ex_table section"); - - /* find beginning of this group */ - found = 0; - list_for_each_entry(rela, &relasec->relas, list) { - if (!strcmp(rela->sym->name, ".fixup") && - rela->addend == offset) { - found = 1; - break; - } - } - - if (!found) - ERROR("can't find .fixup rela group at offset %d\n", offset); - - /* find beginning of next group */ - found = 0; - list_for_each_entry_continue(rela, &relasec->relas, list) { - if (!strcmp(rela->sym->name, ".fixup") && - rela->addend > offset) { - found = 1; - break; - } - } - - if (!found) { - /* last group */ - struct section *fixupsec; - fixupsec = find_section_by_name(&kelf->sections, ".fixup"); - if (!fixupsec) - ERROR("missing .fixup section"); - return (int)(fixupsec->sh.sh_size - offset); - } - - return (int)(rela->addend - offset); -} - -static bool jump_table_group_filter(struct lookup_table *lookup, - struct section *relasec, - unsigned int group_offset, - unsigned int group_size) -{ - struct rela *code = NULL, *key = NULL, *rela; - bool tracepoint = false, dynamic_debug = false; - struct lookup_result symbol; - int i = 0; - - /* - * Here we hard-code knowledge about the contents of the jump_entry - * struct. It has three fields: code, target, and key. Each field has - * a relocation associated with it. - */ - list_for_each_entry(rela, &relasec->relas, list) { - if (rela->offset >= group_offset && - rela->offset < group_offset + group_size) { - if (i == 0) - code = rela; - else if (i == 2) - key = rela; - i++; - } - } - - if (i != 3 || !key || !code) - ERROR("BUG: __jump_table has an unexpected format"); - - if (!strncmp(key->sym->name, "__tracepoint_", 13)) - tracepoint = true; - - if (is_dynamic_debug_symbol(key->sym)) - dynamic_debug = true; - - if (KLP_ARCH) { - /* - * On older kernels (with .klp.arch support), jump labels - * aren't supported at all. Error out when they occur in a - * replacement function, with the exception of tracepoints and - * dynamic debug printks. An inert tracepoint or printk is - * harmless enough, but a broken jump label can cause - * unexpected behavior. - */ - if (tracepoint || dynamic_debug) - return false; - - /* - * This will be upgraded to an error after all jump labels have - * been reported. - */ - log_normal("Found a jump label at %s()+0x%lx, using key %s. Jump labels aren't supported with this kernel. Use static_key_enabled() instead.\n", - code->sym->name, code->addend, key->sym->name); - jump_label_errors++; - return false; - } - - /* - * On newer (5.8+) kernels, jump labels are supported in the case where - * the corresponding static key lives in vmlinux. That's because such - * kernels apply vmlinux-specific .klp.rela sections at the same time - * (in the klp module load) as normal relas, before jump label init. - * On the other hand, jump labels based on static keys which are - * defined in modules aren't supported, because late module patching - * can result in the klp relas getting applied *after* the klp module's - * jump label init. - */ - - if (lookup_symbol(lookup, key->sym, &symbol) && - strcmp(symbol.objname, "vmlinux")) { - - /* The static key lives in a module -- not supported */ - - /* Inert tracepoints and dynamic debug printks are harmless */ - if (tracepoint || dynamic_debug) - return false; - - /* - * This will be upgraded to an error after all jump label - * errors have been reported. - */ - log_normal("Found a jump label at %s()+0x%lx, using key %s, which is defined in a module. Use static_key_enabled() instead.\n", - code->sym->name, code->addend, key->sym->name); - jump_label_errors++; - return false; - } - - /* The static key lives in vmlinux or the patch module itself */ - - /* - * If the jump label key lives in the '__dyndbg' section, make sure - * the section gets included, because we don't use klp relocs for - * dynamic debug symbols. For an example of such a key, see - * DYNAMIC_DEBUG_BRANCH(). - */ - if (dynamic_debug) - kpatch_include_symbol(key->sym); - - return true; -} - -static struct special_section special_sections[] = { - { - .name = "__bug_table", - .arch = AARCH64 | X86_64 | PPC64 | S390, - .group_size = bug_table_group_size, - }, - { - .name = ".fixup", - .arch = AARCH64 | X86_64 | PPC64 | S390, - .group_size = fixup_group_size, - }, - { - .name = "__ex_table", /* must come after .fixup */ - .arch = AARCH64 | X86_64 | PPC64 | S390, - .group_size = ex_table_group_size, - }, - { - .name = "__jump_table", - .arch = AARCH64 | X86_64 | PPC64 | S390, - .group_size = jump_table_group_size, - .group_filter = jump_table_group_filter, - }, - { - .name = ".printk_index", - .arch = AARCH64 | X86_64 | PPC64 | S390, - .group_size = printk_index_group_size, - }, - { - .name = ".smp_locks", - .arch = X86_64, - .group_size = smp_locks_group_size, - }, - { - .name = ".parainstructions", - .arch = X86_64, - .group_size = parainstructions_group_size, - }, - { - .name = ".altinstructions", - .arch = AARCH64 | X86_64 | S390, - .group_size = altinstructions_group_size, - }, - { - .name = ".static_call_sites", - .arch = X86_64, - .group_size = static_call_sites_group_size, - }, - { - .name = ".retpoline_sites", - .arch = X86_64, - .group_size = retpoline_sites_group_size, - }, - { - .name = ".return_sites", - .arch = X86_64, - .group_size = return_sites_group_size, - }, - { - .name = "__ftr_fixup", - .arch = PPC64, - .group_size = fixup_entry_group_size, - }, - { - .name = "__mmu_ftr_fixup", - .arch = PPC64, - .group_size = fixup_entry_group_size, - }, - { - .name = "__fw_ftr_fixup", - .arch = PPC64, - .group_size = fixup_entry_group_size, - }, - { - .name = "__lwsync_fixup", - .arch = PPC64, - .group_size = fixup_lwsync_group_size, - }, - { - .name = "__barrier_nospec_fixup", - .arch = PPC64, - .group_size = fixup_barrier_nospec_group_size, - }, - { - .name = ".s390_return_mem", - .arch = S390, - .group_size = s390_expolines_group_size, - }, - { - .name = ".s390_return_reg", - .arch = S390, - .group_size = s390_expolines_group_size, - }, - { - .name = ".s390_indirect_call", - .arch = S390, - .group_size = s390_expolines_group_size, - }, - { - .name = ".s390_indirect_branches", - .arch = S390, - .group_size = s390_expolines_group_size, - }, - { - .name = ".s390_indirect_jump", - .arch = S390, - .group_size = s390_expolines_group_size, - }, - {}, -}; - -static bool should_keep_rela_group(struct lookup_table *lookup, - struct section *relasec, unsigned int offset, - unsigned int size) -{ - struct rela *rela; - bool found = false; - - /* check if any relas in the group reference any changed functions */ - list_for_each_entry(rela, &relasec->relas, list) { - if (rela->offset >= offset && - rela->offset < offset + size && - rela->sym->type == STT_FUNC && - rela->sym->sec->include) { - found = true; - log_debug("new/changed symbol %s found in special section %s\n", - rela->sym->name, relasec->name); - } - } - - if (!found) - return false; - - return true; -} - -/* - * When updating .fixup, the corresponding addends in .ex_table need to be - * updated too. Stash the result in rela.r_addend so that the calculation in - * fixup_group_size() is not affected. - */ -static void kpatch_update_ex_table_addend(struct kpatch_elf *kelf, - struct special_section *special, - int src_offset, int dest_offset, - int group_size) -{ - struct rela *rela; - struct section *relasec; - - relasec = find_section_by_name(&kelf->sections, ".rela__ex_table"); - if (!relasec) - ERROR("missing .rela__ex_table section"); - - list_for_each_entry(rela, &relasec->relas, list) { - if (!strcmp(rela->sym->name, ".fixup") && - rela->addend >= src_offset && - rela->addend < src_offset + group_size) - rela->rela.r_addend = rela->addend - (src_offset - dest_offset); - } -} - -static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, - struct lookup_table *lookup, - struct special_section *special, - struct section *relasec) -{ - struct rela *rela, *safe; - char *src, *dest; - unsigned int group_size, src_offset, dest_offset; - - LIST_HEAD(newrelas); - - src = relasec->base->data->d_buf; - /* alloc buffer for new base section */ - dest = malloc(relasec->base->sh.sh_size); - if (!dest) - ERROR("malloc"); - - /* Restore the stashed r_addend from kpatch_update_ex_table_addend. */ - if (!strcmp(special->name, "__ex_table")) { - list_for_each_entry(rela, &relasec->relas, list) { - if (!strcmp(rela->sym->name, ".fixup")) - rela->addend = rela->rela.r_addend; - } - } - - src_offset = 0; - dest_offset = 0; - for ( ; src_offset < relasec->base->sh.sh_size; src_offset += group_size) { - - group_size = special->group_size(kelf, src_offset); - - /* - * In some cases the struct has padding at the end to ensure - * that all structs after it are properly aligned. But the - * last struct in the section may not be padded. In that case, - * shrink the group_size such that it still (hopefully) - * contains the data but doesn't go past the end of the - * section. - */ - if (src_offset + group_size > relasec->base->sh.sh_size) - group_size = (unsigned int)(relasec->base->sh.sh_size - src_offset); - - if (!should_keep_rela_group(lookup, relasec, src_offset, group_size)) - continue; - - if (special->group_filter && - !special->group_filter(lookup, relasec, src_offset, group_size)) - continue; - - /* - * Copy all relas in the group. It's possible that the relas - * aren't sorted (e.g. .rela.fixup), so go through the entire - * rela list each time. - */ - list_for_each_entry_safe(rela, safe, &relasec->relas, list) { - if (rela->offset >= src_offset && - rela->offset < src_offset + group_size) { - /* copy rela entry */ - list_del(&rela->list); - list_add_tail(&rela->list, &newrelas); - - rela->offset -= src_offset - dest_offset; - rela->rela.r_offset = rela->offset; - - rela->sym->include = 1; - - if (!strcmp(special->name, ".fixup")) - kpatch_update_ex_table_addend(kelf, special, - src_offset, - dest_offset, - group_size); - } - } - - /* copy base section group */ - memcpy(dest + dest_offset, src + src_offset, group_size); - dest_offset += group_size; - } - - if (jump_label_errors) - ERROR("Found %d unsupported jump label(s) in the patched code. Use static_key_enabled() instead.", - jump_label_errors); - - if (!dest_offset) { - /* no changed or global functions referenced */ - relasec->status = relasec->base->status = SAME; - relasec->include = relasec->base->include = 0; - free(dest); - return; - } - - /* overwrite with new relas list */ - list_replace(&newrelas, &relasec->relas); - - /* include both rela and base sections */ - relasec->include = 1; - relasec->base->include = 1; - /* include secsym so .kpatch.arch relas can point to section symbols */ - if (relasec->base->secsym) - relasec->base->secsym->include = 1; - - /* - * Update text section data buf and size. - * - * The rela section's data buf and size will be regenerated in - * kpatch_rebuild_rela_section_data(). - */ - relasec->base->data->d_buf = dest; - relasec->base->data->d_size = dest_offset; -} - -#define ORC_IP_PTR_SIZE 4 - -/* - * This function is similar to kpatch_regenerate_special_section(), but - * customized for the ORC-related sections. ORC is more special than the other - * special sections because each ORC entry is split into .orc_unwind (struct - * orc_entry) and .orc_unwind_ip. - */ -static void kpatch_regenerate_orc_sections(struct kpatch_elf *kelf) -{ - struct rela *rela, *safe; - char *src, *dest, *str; - unsigned int src_idx = 0, dest_idx = 0, orc_entry_size; - struct section *orc_sec, *ip_sec; - - - str = getenv("ORC_STRUCT_SIZE"); - if (!str) - return; - orc_entry_size = atoi(str); - - if (!orc_entry_size) - ERROR("bad ORC_STRUCT_SIZE"); - - LIST_HEAD(newrelas); - - orc_sec = find_section_by_name(&kelf->sections, ".orc_unwind"); - ip_sec = find_section_by_name(&kelf->sections, ".orc_unwind_ip"); - - if (!orc_sec || !ip_sec) - return; - - if (orc_sec->sh.sh_size % orc_entry_size != 0) - ERROR("bad .orc_unwind size"); - - if (ip_sec->sh.sh_size != - (orc_sec->sh.sh_size / orc_entry_size) * ORC_IP_PTR_SIZE) - ERROR(".orc_unwind/.orc_unwind_ip size mismatch"); - - src = orc_sec->data->d_buf; - dest = malloc(orc_sec->sh.sh_size); - if (!dest) - ERROR("malloc"); - - list_for_each_entry_safe(rela, safe, &ip_sec->rela->relas, list) { - - if (rela->sym->type != STT_FUNC || !rela->sym->sec->include) - goto next; - - /* copy orc entry */ - memcpy(dest + (dest_idx * orc_entry_size), - src + (src_idx * orc_entry_size), - orc_entry_size); - - /* move ip rela */ - list_del(&rela->list); - list_add_tail(&rela->list, &newrelas); - rela->offset = dest_idx * ORC_IP_PTR_SIZE; - rela->sym->include = 1; - - dest_idx++; -next: - src_idx++; - } - - if (!dest_idx) { - /* no changed or global functions referenced */ - orc_sec->status = ip_sec->status = ip_sec->rela->status = SAME; - orc_sec->include = ip_sec->include = ip_sec->rela->include = 0; - free(dest); - return; - } - - /* overwrite with new relas list */ - list_replace(&newrelas, &ip_sec->rela->relas); - - /* include the sections */ - orc_sec->include = ip_sec->include = ip_sec->rela->include = 1; - - /* - * Update data buf/size. - * - * The ip section can keep its old (zeroed data), though its size has - * possibly decreased. The ip rela section's data buf and size will be - * regenerated in kpatch_rebuild_rela_section_data(). - */ - orc_sec->data->d_buf = dest; - orc_sec->data->d_size = dest_idx * orc_entry_size; - ip_sec->data->d_size = dest_idx * ORC_IP_PTR_SIZE; -} - -static void kpatch_check_relocations(struct kpatch_elf *kelf) -{ - struct rela *rela; - struct section *relasec; - long sec_size; - long sec_off; - - list_for_each_entry(relasec, &kelf->sections, list) { - if (!is_rela_section(relasec)) - continue; - list_for_each_entry(rela, &relasec->relas, list) { - if (!rela->sym->sec) - continue; - - sec_size = rela->sym->sec->data->d_size; - sec_off = (long)rela->sym->sym.st_value + - rela_target_offset(kelf, relasec, rela); - - /* - * This check isn't perfect: we still allow relocations - * to the end of a section. There are real instances - * of that, including ORC entries, LOCKDEP=n - * zero-length '__key' passing, and the loop edge case - * described in kpatch_replace_sections_syms(). For - * now, just allow all such cases. - */ - if (sec_off < 0 || sec_off > sec_size) { - ERROR("%s+0x%x: out-of-range relocation %s+%lx", - relasec->base->name, rela->offset, - rela->sym->name, rela->addend); - } - } - } -} - -static void kpatch_include_debug_sections(struct kpatch_elf *kelf) -{ - struct section *sec; - struct rela *rela, *saferela; - - /* include all .debug_* sections */ - list_for_each_entry(sec, &kelf->sections, list) { - if (is_debug_section(sec)) { - sec->include = 1; - if (!is_rela_section(sec) && sec->secsym) - sec->secsym->include = 1; - } - } - - /* - * Go through the .rela.debug_ sections and strip entries - * referencing unchanged symbols - */ - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec) || !is_debug_section(sec)) - continue; - list_for_each_entry_safe(rela, saferela, &sec->relas, list) - if (!rela->sym->sec->include) - list_del(&rela->list); - } -} - -static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf) -{ - struct section *sec, *strsec, *ignoresec; - struct rela *rela; - char *name; - - /* Ignore any discarded sections */ - list_for_each_entry(sec, &kelf->sections, list) { - if (!strncmp(sec->name, ".discard", 8) || - !strncmp(sec->name, ".rela.discard", 13) || - !strncmp(sec->name, ".llvm_addrsig", 13) || - !strncmp(sec->name, ".llvm.", 6)) - sec->ignore = 1; - } - - sec = find_section_by_name(&kelf->sections, ".kpatch.ignore.sections"); - if (!sec) - return; - - list_for_each_entry(rela, &sec->rela->relas, list) { - strsec = rela->sym->sec; - strsec->status = CHANGED; - /* - * Include the string section here. This is because the - * KPATCH_IGNORE_SECTION() macro is passed a literal string - * by the patch author, resulting in a change to the string - * section. If we don't include it, then we will potentially - * get a "changed section not included" error in - * kpatch_verify_patchability() if no other function based change - * also changes the string section. We could try to exclude each - * literal string added to the section by KPATCH_IGNORE_SECTION() - * from the section data comparison, but this is a simpler way. - */ - strsec->include = 1; - if (strsec->secsym) - strsec->secsym->include = 1; - - name = strsec->data->d_buf + rela->addend; - ignoresec = find_section_by_name(&kelf->sections, name); - if (!ignoresec) - ERROR("KPATCH_IGNORE_SECTION: can't find %s", name); - log_normal("ignoring section: %s\n", name); - if (is_rela_section(ignoresec)) - ignoresec = ignoresec->base; - ignoresec->ignore = 1; - if (ignoresec->twin) - ignoresec->twin->ignore = 1; - } -} - -static void kpatch_mark_ignored_sections_same(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - - list_for_each_entry(sec, &kelf->sections, list) { - if (!sec->ignore) - continue; - sec->status = SAME; - if (!is_rela_section(sec)) { - if (sec->secsym) - sec->secsym->status = SAME; - if (sec->rela) - sec->rela->status = SAME; - } - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->sec != sec) - continue; - sym->status = SAME; - } - } - - /* strip temporary global __UNIQUE_ID_kpatch_ignore_section_* symbols */ - list_for_each_entry(sym, &kelf->symbols, list) - if (!strncmp(sym->name, "__UNIQUE_ID_kpatch_ignore_section_", - strlen("__UNIQUE_ID_kpatch_ignore_section_"))) - sym->status = SAME; -} - -static void kpatch_mark_ignored_children_same(struct symbol *sym) -{ - struct symbol *child; - - list_for_each_entry(child, &sym->children, subfunction_node) { - child->status = SAME; - kpatch_mark_ignored_children_same(child); - } -} - -static void kpatch_mark_ignored_functions_same(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - struct rela *rela; - - sec = find_section_by_name(&kelf->sections, ".kpatch.ignore.functions"); - if (!sec) - return; - - list_for_each_entry(rela, &sec->rela->relas, list) { - if (!rela->sym->sec) - ERROR("expected bundled symbol"); - if (rela->sym->type != STT_FUNC) - ERROR("expected function symbol"); - log_normal("ignoring function: %s\n", rela->sym->name); - if (rela->sym->status != CHANGED) - log_normal("NOTICE: no change detected in function %s, unnecessary KPATCH_IGNORE_FUNCTION()?\n", rela->sym->name); - rela->sym->status = SAME; - rela->sym->sec->status = SAME; - - kpatch_mark_ignored_children_same(rela->sym); - - if (rela->sym->sec->secsym) - rela->sym->sec->secsym->status = SAME; - if (rela->sym->sec->rela) - rela->sym->sec->rela->status = SAME; - } - - /* strip temporary global kpatch_ignore_func_* symbols */ - list_for_each_entry(sym, &kelf->symbols, list) - if (!strncmp(sym->name, "__kpatch_ignore_func_", - strlen("__kpatch_ignore_func_"))) - sym->status = SAME; -} - -static void kpatch_create_kpatch_arch_section(struct kpatch_elf *kelf, char *objname) -{ - struct special_section *special; - struct symbol *strsym; - struct section *sec, *karch_sec; - struct rela *rela; - int nr, index = 0; - - if (!KLP_ARCH) - return; - - nr = sizeof(special_sections) / sizeof(special_sections[0]); - karch_sec = create_section_pair(kelf, ".kpatch.arch", sizeof(struct kpatch_arch), nr); - - /* lookup strings symbol */ - strsym = find_symbol_by_name(&kelf->symbols, ".kpatch.strings"); - if (!strsym) - ERROR("can't find .kpatch.strings symbol"); - - for (special = special_sections; special->name; special++) { - if ((special->arch & kelf->arch) == 0) - continue; - - if (strcmp(special->name, ".parainstructions") && - strcmp(special->name, ".altinstructions")) - continue; - - sec = find_section_by_name(&kelf->sections, special->name); - if (!sec) - continue; - - /* entries[index].sec */ - ALLOC_LINK(rela, &karch_sec->rela->relas); - rela->sym = sec->secsym; - rela->type = absolute_rela_type(kelf); - rela->addend = 0; - rela->offset = (unsigned int)(index * sizeof(struct kpatch_arch) + \ - offsetof(struct kpatch_arch, sec)); - - /* entries[index].objname */ - ALLOC_LINK(rela, &karch_sec->rela->relas); - rela->sym = strsym; - rela->type = absolute_rela_type(kelf); - rela->addend = offset_of_string(&kelf->strings, objname); - rela->offset = (unsigned int)(index * sizeof(struct kpatch_arch) + \ - offsetof(struct kpatch_arch, objname)); - - index++; - } - - karch_sec->data->d_size = index * sizeof(struct kpatch_arch); - karch_sec->sh.sh_size = karch_sec->data->d_size; -} - -static void kpatch_process_special_sections(struct kpatch_elf *kelf, - struct lookup_table *lookup) -{ - struct special_section *special; - struct section *sec; - struct symbol *sym; - struct rela *rela; - int altinstr = 0; - - for (special = special_sections; special->name; special++) { - if ((special->arch & kelf->arch) == 0) - continue; - - sec = find_section_by_name(&kelf->sections, special->name); - if (!sec || !sec->rela) - continue; - - kpatch_regenerate_special_section(kelf, lookup, special, sec->rela); - - if (!strcmp(special->name, ".altinstructions") && sec->include) - altinstr = 1; - } - - /* - * The following special sections don't have relas which reference - * non-included symbols, so their entire rela section can be included. - */ - list_for_each_entry(sec, &kelf->sections, list) { - if (strcmp(sec->name, ".altinstr_replacement")) - continue; - /* - * Only include .altinstr_replacement if .altinstructions - * is also included. - */ - if (!altinstr) - break; - - /* include base section */ - sec->include = 1; - - /* include all symbols in the section */ - list_for_each_entry(sym, &kelf->symbols, list) - if (sym->sec == sec) - sym->include = 1; - - /* include rela section */ - if (sec->rela) { - sec->rela->include = 1; - /* include all symbols referenced by relas */ - list_for_each_entry(rela, &sec->rela->relas, list) - kpatch_include_symbol(rela->sym); - } - } - - if (KLP_ARCH) { - /* - * The following special sections aren't supported with older - * kernels, so make sure we don't ever try to include them. - * Otherwise the kernel will see the jump table during module - * loading and get confused. Generally it should be safe to - * exclude them, it just means that you can't modify jump - * labels and enable tracepoints in a patched function. - */ - list_for_each_entry(sec, &kelf->sections, list) { - if (strcmp(sec->name, "__jump_table") && - strcmp(sec->name, "__tracepoints") && - strcmp(sec->name, "__tracepoints_ptrs") && - strcmp(sec->name, "__tracepoints_strings")) - continue; - - sec->status = SAME; - sec->include = 0; - if (sec->rela) { - sec->rela->status = SAME; - sec->rela->include = 0; - } - } - } - - kpatch_regenerate_orc_sections(kelf); -} - -static void kpatch_create_patches_sections(struct kpatch_elf *kelf, - struct lookup_table *table, - char *objname) -{ - int nr, index, objname_offset; - struct section *sec, *relasec; - struct symbol *sym, *strsym; - struct rela *rela; - struct lookup_result symbol; - struct kpatch_patch_func *funcs; - - /* count patched functions */ - nr = 0; - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type != STT_FUNC || sym->status != CHANGED || - sym->parent) - continue; - nr++; - } - - /* create text/rela section pair */ - sec = create_section_pair(kelf, ".kpatch.funcs", sizeof(*funcs), nr); - relasec = sec->rela; - funcs = sec->data->d_buf; - - /* lookup strings symbol */ - strsym = find_symbol_by_name(&kelf->symbols, ".kpatch.strings"); - if (!strsym) - ERROR("can't find .kpatch.strings symbol"); - - /* add objname to strings */ - objname_offset = offset_of_string(&kelf->strings, objname); - - /* populate sections */ - index = 0; - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type != STT_FUNC || sym->status != CHANGED || - sym->parent) - continue; - - if (!lookup_symbol(table, sym, &symbol)) - ERROR("can't find symbol '%s' in symbol table", sym->name); - - if (sym->bind == STB_LOCAL && symbol.global) - ERROR("can't find local symbol '%s' in symbol table", sym->name); - - log_debug("lookup for %s: obj=%s sympos=%lu size=%lu\n", - sym->name, symbol.objname, symbol.sympos, - symbol.size); - - /* - * Convert global symbols to local so other objects in the - * patch module (like the patch callback object's init code) - * won't link to this function and call it before its - * relocations have been applied. - */ - sym->bind = STB_LOCAL; - sym->sym.st_info = (unsigned char) - GELF_ST_INFO(sym->bind, sym->type); - - /* add entry in text section */ - funcs[index].old_addr = symbol.addr; - funcs[index].old_size = symbol.size; - funcs[index].new_size = sym->sym.st_size; - funcs[index].sympos = symbol.sympos; - - /* - * Add a relocation that will populate the - * funcs[index].new_addr field at module load time. - */ - ALLOC_LINK(rela, &relasec->relas); - rela->sym = sym; - rela->type = absolute_rela_type(kelf); - rela->addend = 0; - rela->offset = (unsigned int)(index * sizeof(*funcs)); - - /* - * Add a relocation that will populate the funcs[index].name - * field. - */ - ALLOC_LINK(rela, &relasec->relas); - rela->sym = strsym; - rela->type = absolute_rela_type(kelf); - rela->addend = offset_of_string(&kelf->strings, sym->name); - rela->offset = (unsigned int)(index * sizeof(*funcs) + - offsetof(struct kpatch_patch_func, name)); - - /* - * Add a relocation that will populate the funcs[index].objname - * field. - */ - ALLOC_LINK(rela, &relasec->relas); - rela->sym = strsym; - rela->type = absolute_rela_type(kelf); - rela->addend = objname_offset; - rela->offset = (unsigned int)(index * sizeof(*funcs) + - offsetof(struct kpatch_patch_func,objname)); - - index++; - } - - /* sanity check, index should equal nr */ - if (index != nr) - ERROR("size mismatch in funcs sections"); - -} - -static bool kpatch_is_core_module_symbol(char *name) -{ - return (!strcmp(name, "kpatch_shadow_alloc") || - !strcmp(name, "kpatch_shadow_free") || - !strcmp(name, "kpatch_shadow_get")); -} - -static bool is_expoline(struct kpatch_elf *kelf, char *name) -{ - return kelf->arch == S390 && !strncmp(name, "__s390_indirect_jump_r", 22); -} - -static int function_ptr_rela(const struct rela *rela) -{ - const struct rela *rela_toc = toc_rela(rela); - - return (rela_toc && rela_toc->sym->type == STT_FUNC && - !rela_toc->sym->parent && - rela_toc->addend == (int)rela_toc->sym->sym.st_value && - (rela->type == R_X86_64_32S || - rela->type == R_PPC64_TOC16_HA || - rela->type == R_PPC64_TOC16_LO_DS)); -} - -static bool need_dynrela(struct kpatch_elf *kelf, struct lookup_table *table, - struct section *relasec, const struct rela *rela) -{ - struct lookup_result symbol; - - if (is_debug_section(relasec)) - return false; - - /* - * These references are treated specially by the module loader and - * should never be converted to dynrelas. - */ - if (rela->type == R_PPC64_REL16_HA || rela->type == R_PPC64_REL16_LO || - rela->type == R_PPC64_ENTRY) - return false; - - /* v5.13+ kernels use relative jump labels */ - if (rela->type == R_PPC64_REL64 && strcmp(relasec->name, ".rela__jump_table")) - return false; - - /* - * On powerpc, the function prologue generated by GCC 6 has the - * sequence: - * - * .globl my_func - * .type my_func, @function - * .quad .TOC.-my_func - * my_func: - * .reloc ., R_PPC64_ENTRY ; optional - * ld r2,-8(r12) - * add r2,r2,r12 - * .localentry my_func, .-my_func - * - * The R_PPC64_ENTRY is optional and its symbol might have an empty - * name. Leave it as a normal rela. - */ - if (rela->type == R_PPC64_ENTRY) - return false; - - /* - * Allow references to core module symbols to remain as normal - * relas. They should be exported. - */ - if (kpatch_is_core_module_symbol(rela->sym->name)) - return false; - - /* - * Allow references to s390 expolines to remain as normal relas. They - * will be generated in the module by the kernel module link. - */ - if (is_expoline(kelf, rela->sym->name)) - return false; - - if (rela->sym->sec) { - /* - * Internal symbols usually don't need dynrelas, because they - * live in the patch module and can be relocated normally. - * - * There's one exception: function pointers. - * - * If the rela references a function pointer, we convert it to - * a dynrela, so that the function pointer will refer to the - * original function rather than the patched function. This - * can prevent crashes in cases where the function pointer is - * called asynchronously after the patch module has been - * unloaded. - */ - if (!function_ptr_rela(rela)) - return false; - - /* - * Function pointers which refer to _nested_ functions are a - * special case. They are not supposed to be visible outside - * of the function that defines them. Their names may differ - * in the original and the patched kernels which makes it - * difficult to use dynrelas. Fortunately, nested functions - * are rare and are unlikely to be used as asynchronous - * callbacks, so the patched code can refer to them directly. - * It seems, one can only distinguish such functions by their - * names containing a dot. Other kinds of functions with such - * names (e.g. optimized copies of functions) are unlikely to - * be used as callbacks. - * - * Function pointers to *new* functions don't have this issue, - * just use a normal rela for them. - */ - return toc_rela(rela)->sym->status != NEW && - !strchr(toc_rela(rela)->sym->name, '.'); - } - - if (!lookup_symbol(table, rela->sym, &symbol)) { - /* - * Assume the symbol lives in another .o in the patch module. - * A normal rela should work. - */ - return false; - } - - if (rela->sym->bind == STB_LOCAL) { - - if (symbol.global) - ERROR("can't find local symbol '%s' in symbol table", - rela->sym->name); - - /* - * The symbol is (formerly) local. Use a dynrela to access the - * original version of the symbol in the patched object. - */ - return true; - } - - if (symbol.exported) { - - if (is_gcc6_localentry_bundled_sym(kelf, rela->sym)) { - /* - * On powerpc, the symbol is global and exported, but - * it was also in the changed object file. In this - * case the rela refers to the 'localentry' point, so a - * normal rela wouldn't work. Force a dynrela so it - * can be handled correctly by the livepatch relocation - * code. - */ - return true; - } - - if (!strcmp(symbol.objname, "vmlinux")) { - /* - * The symbol is exported by vmlinux. Use a normal - * rela. - */ - return false; - } - - /* - * The symbol is exported by the to-be-patched module, or by - * another module which the patched module depends on. Use a - * dynrela because of late module loading: the patch module may - * be loaded before the to-be-patched (or other) module. - */ - return true; - } - - if (symbol.global) { - /* - * The symbol is global in the to-be-patched object, but not - * exported. Use a dynrela to work around the fact that it's - * an unexported sybmbol. - */ - return true; - } - - /* - * The symbol is global and not exported, but it's not in the parent - * object. The only explanation is that it's defined in another object - * in the patch module. A normal rela should resolve it. - */ - return false; -} - -/* - * kpatch_create_intermediate_sections() - * - * The primary purpose of this function is to convert some relas (also known as - * relocations) to dynrelas (also known as dynamic relocations or livepatch - * relocations or klp relas). - * - * If the patched code refers to a symbol, for example, if it calls a function - * or stores a pointer to a function somewhere or accesses some global data, - * the address of that symbol must be resolved somehow before the patch is - * applied. - * - * If the symbol lives outside the patch module, and if it's not exported by - * vmlinux (e.g., with EXPORT_SYMBOL) then the rela needs to be converted to a - * dynrela so the livepatch code can resolve it at runtime. - */ -static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf, - struct lookup_table *table, - char *objname, - char *pmod_name) -{ - int nr, index; - struct section *relasec, *ksym_sec, *krela_sec; - struct rela *rela, *rela2, *safe; - struct symbol *strsym, *ksym_sec_sym; - struct kpatch_symbol *ksyms; - struct kpatch_relocation *krelas; - struct lookup_result symbol; - bool special; - bool vmlinux = !strcmp(objname, "vmlinux"); - struct special_section *s; - - /* count rela entries that need to be dynamic */ - nr = 0; - list_for_each_entry(relasec, &kelf->sections, list) { - if (!is_rela_section(relasec)) - continue; - if (!strcmp(relasec->name, ".rela.kpatch.funcs")) - continue; - list_for_each_entry(rela, &relasec->relas, list) { - - /* upper bound on number of kpatch relas and symbols */ - nr++; - - /* - * We set 'need_dynrela' here in the first pass because - * the .toc section's 'need_dynrela' values are - * dependent on all the other sections. Otherwise, if - * we did this analysis in the second pass, we'd have - * to convert .toc dynrelas at the very end. - * - * Specifically, this is needed for the powerpc - * internal symbol function pointer check which is done - * via .toc indirection in need_dynrela(). - */ - if (need_dynrela(kelf, table, relasec, rela)) - toc_rela(rela)->need_dynrela = 1; - } - } - - /* create .kpatch.relocations text/rela section pair */ - krela_sec = create_section_pair(kelf, ".kpatch.relocations", sizeof(*krelas), nr); - krelas = krela_sec->data->d_buf; - - /* create .kpatch.symbols text/rela section pair */ - ksym_sec = create_section_pair(kelf, ".kpatch.symbols", sizeof(*ksyms), nr); - ksyms = ksym_sec->data->d_buf; - - /* create .kpatch.symbols section symbol (to set rela->sym later) */ - ALLOC_LINK(ksym_sec_sym, &kelf->symbols); - ksym_sec_sym->sec = ksym_sec; - ksym_sec_sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); - ksym_sec_sym->type = STT_SECTION; - ksym_sec_sym->bind = STB_LOCAL; - ksym_sec_sym->name = ".kpatch.symbols"; - - /* lookup strings symbol */ - strsym = find_symbol_by_name(&kelf->symbols, ".kpatch.strings"); - if (!strsym) - ERROR("can't find .kpatch.strings symbol"); - - /* populate sections */ - index = 0; - list_for_each_entry(relasec, &kelf->sections, list) { - if (!is_rela_section(relasec)) - continue; - if (!strcmp(relasec->name, ".rela.kpatch.funcs") || - !strcmp(relasec->name, ".rela.kpatch.relocations") || - !strcmp(relasec->name, ".rela.kpatch.symbols")) - continue; - - special = false; - for (s = special_sections; s->name; s++) { - if ((s->arch & kelf->arch) == 0) - continue; - - if (!strcmp(relasec->base->name, s->name)) - special = true; - } - - list_for_each_entry_safe(rela, safe, &relasec->relas, list) { - if (!rela->need_dynrela) { - rela->sym->strip = SYMBOL_USED; - continue; - } - - /* - * Starting with Linux 5.8, .klp.arch sections are no - * longer supported: now that vmlinux relocations are - * written early, before paravirt and alternative - * module init, .klp.arch is technically not needed. - * - * For sanity we just need to make sure that there are - * no .klp.rela.{module}.{section} sections for special - * sections. Otherwise there might be ordering issues, - * if the .klp.relas are applied after the module - * special section init code (e.g., apply_paravirt) - * runs due to late module patching. - */ - if (!KLP_ARCH && !vmlinux && special) - ERROR("unsupported dynrela reference to symbol '%s' in module-specific special section '%s'", - rela->sym->name, relasec->base->name); - - if (!lookup_symbol(table, rela->sym, &symbol)) - ERROR("can't find symbol '%s' in symbol table", - rela->sym->name); - - log_debug("lookup for %s: obj=%s sympos=%lu\n", - rela->sym->name, symbol.objname, - symbol.sympos); - - /* Fill in ksyms[index] */ - if (vmlinux) - ksyms[index].src = symbol.addr; - else - /* for modules, src is discovered at runtime */ - ksyms[index].src = 0; - ksyms[index].sympos = symbol.sympos; - ksyms[index].type = rela->sym->type; - ksyms[index].bind = rela->sym->bind; - - /* add rela to fill in ksyms[index].name field */ - ALLOC_LINK(rela2, &ksym_sec->rela->relas); - rela2->sym = strsym; - rela2->type = absolute_rela_type(kelf); - rela2->addend = offset_of_string(&kelf->strings, rela->sym->name); - rela2->offset = (unsigned int)(index * sizeof(*ksyms) + \ - offsetof(struct kpatch_symbol, name)); - - /* add rela to fill in ksyms[index].objname field */ - ALLOC_LINK(rela2, &ksym_sec->rela->relas); - rela2->sym = strsym; - rela2->type = absolute_rela_type(kelf); - rela2->addend = offset_of_string(&kelf->strings, symbol.objname); - rela2->offset = (unsigned int)(index * sizeof(*ksyms) + \ - offsetof(struct kpatch_symbol, objname)); - - /* Fill in krelas[index] */ - if (is_gcc6_localentry_bundled_sym(kelf, rela->sym) && - rela->addend == (int)rela->sym->sym.st_value) - rela->addend -= rela->sym->sym.st_value; - krelas[index].addend = rela->addend; - krelas[index].type = rela->type; - krelas[index].external = !vmlinux && symbol.exported; - - /* add rela to fill in krelas[index].dest field */ - ALLOC_LINK(rela2, &krela_sec->rela->relas); - if (!relasec->base->secsym) { - struct symbol *sym; - - /* - * Newer toolchains are stingy with their - * section symbols, create one if it doesn't - * exist already. - */ - ALLOC_LINK(sym, &kelf->symbols); - sym->sec = relasec->base; - sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); - sym->type = STT_SECTION; - sym->bind = STB_LOCAL; - sym->name = relasec->base->name; - relasec->base->secsym = sym; - } - rela2->sym = relasec->base->secsym; - rela2->type = absolute_rela_type(kelf); - rela2->addend = rela->offset; - rela2->offset = (unsigned int)(index * sizeof(*krelas) + \ - offsetof(struct kpatch_relocation, dest)); - - /* add rela to fill in krelas[index].objname field */ - ALLOC_LINK(rela2, &krela_sec->rela->relas); - rela2->sym = strsym; - rela2->type = absolute_rela_type(kelf); - rela2->addend = offset_of_string(&kelf->strings, objname); - rela2->offset = (unsigned int)(index * sizeof(*krelas) + \ - offsetof(struct kpatch_relocation, objname)); - - /* add rela to fill in krelas[index].ksym field */ - ALLOC_LINK(rela2, &krela_sec->rela->relas); - rela2->sym = ksym_sec_sym; - rela2->type = absolute_rela_type(kelf); - rela2->addend = (unsigned int)(index * sizeof(*ksyms)); - rela2->offset = (unsigned int)(index * sizeof(*krelas) + \ - offsetof(struct kpatch_relocation, ksym)); - - /* - * Mark the referred to symbol for removal but - * only if it is not from this object file. - * The symbols from this object file may be needed - * later (for example, they may have relocations - * of their own which should be processed). - */ - if (!rela->sym->sec && rela->sym->strip != SYMBOL_USED) - rela->sym->strip = SYMBOL_STRIP; - list_del(&rela->list); - free(rela); - - index++; - } - } - - /* set size to actual number of ksyms/krelas */ - ksym_sec->data->d_size = index * sizeof(struct kpatch_symbol); - ksym_sec->sh.sh_size = ksym_sec->data->d_size; - - krela_sec->data->d_size = index * sizeof(struct kpatch_relocation); - krela_sec->sh.sh_size = krela_sec->data->d_size; -} - -static void kpatch_create_callbacks_objname_rela(struct kpatch_elf *kelf, char *objname) -{ - struct section *sec; - struct rela *rela; - struct symbol *strsym; - int objname_offset; - - struct callback { char *name; int offset; }; - static struct callback callbacks[] = { - { .name = ".rela.kpatch.callbacks.pre_patch", - .offset = offsetof(struct kpatch_pre_patch_callback, objname) }, - { .name = ".rela.kpatch.callbacks.post_patch", - .offset = offsetof(struct kpatch_post_patch_callback, objname) }, - { .name = ".rela.kpatch.callbacks.pre_unpatch", - .offset = offsetof(struct kpatch_pre_unpatch_callback, objname) }, - { .name = ".rela.kpatch.callbacks.post_unpatch", - .offset = offsetof(struct kpatch_post_patch_callback, objname) }, - { .name = NULL, .offset = 0 }, - }; - struct callback *callbackp; - - /* lookup strings symbol */ - strsym = find_symbol_by_name(&kelf->symbols, ".kpatch.strings"); - if (!strsym) - ERROR("can't find .kpatch.strings symbol"); - - /* add objname to strings */ - objname_offset = offset_of_string(&kelf->strings, objname); - - list_for_each_entry(sec, &kelf->sections, list) { - for (callbackp = callbacks; callbackp->name; callbackp++) { - if (!strcmp(callbackp->name, sec->name)) { - ALLOC_LINK(rela, &sec->relas); - rela->sym = strsym; - rela->type = absolute_rela_type(kelf); - rela->addend = objname_offset; - rela->offset = callbackp->offset; - break; - } - } - } -} - -/* - * Allocate the mcount/patchable_function_entry sections which must be done - * before the patched object is torn down so that the section flags can be - * copied. - */ -static void kpatch_alloc_mcount_sections(struct kpatch_elf *kelf, struct kpatch_elf *kelfout) -{ - int nr; - struct symbol *sym; - int text_idx = 0; - - nr = 0; - list_for_each_entry(sym, &kelfout->symbols, list) { - if (sym->type == STT_FUNC && sym->status != SAME && - sym->has_func_profiling) { - text_idx = sym->sec->index; - nr++; - } - } - - /* create text/rela section pair */ - switch(kelf->arch) { - case AARCH64: { - struct section *sec; - int entries = multi_pfe ? 1 : nr; - int copies = multi_pfe ? nr : 1; - int flags = 0, rflags = 0; - - /* - * Depending on the compiler the __patchable_function_entries section - * can be ordered or not, copy this flag to the section we created to - * avoid: - * ld: __patchable_function_entries has both ordered [...] and unordered [...] sections - */ - sec = find_section_by_name(&kelf->sections, "__patchable_function_entries"); - if (sec) { - flags = (sec->sh.sh_flags & (SHF_LINK_ORDER|SHF_WRITE)); - if (sec->rela) - rflags = (sec->rela->sh.sh_flags & (SHF_LINK_ORDER|SHF_WRITE)); - } - - for (nr = 0; nr < copies; nr++) { - sec = create_section_pair(kelfout, - "__patchable_function_entries", - sizeof(void*), entries); - - sec->sh.sh_flags |= flags; - if (sec->rela) - sec->rela->sh.sh_flags |= rflags; - if (multi_pfe) - sec->sh.sh_link = 0; /* set later */ - else - sec->sh.sh_link = text_idx; - } - break; - } - case PPC64: - case X86_64: - case S390: - create_section_pair(kelfout, "__mcount_loc", sizeof(void*), nr); - break; - default: - ERROR("unsupported arch"); - } -} - -/* - * Populate the mcount sections allocated by kpatch_alloc_mcount_sections() - * previously. - * This function basically reimplements the functionality of the Linux - * recordmcount script, so that patched functions can be recognized by ftrace. - * - * TODO: Eventually we can modify recordmount so that it recognizes our bundled - * sections as valid and does this work for us. - */ -static void kpatch_populate_mcount_sections(struct kpatch_elf *kelf) -{ - int nr, index; - struct section *sec, *relasec; - struct symbol *sym; - struct rela *rela, *mcount_rela; - void **funcs; - - switch(kelf->arch) { - case AARCH64: - if (multi_pfe) - sec = NULL; - else - sec = find_section_by_name(&kelf->sections, - "__patchable_function_entries"); - break; - case PPC64: - case X86_64: - case S390: - sec = find_section_by_name(&kelf->sections, "__mcount_loc"); - break; - default: - ERROR("unsupported arch"); - } - - if (multi_pfe) { - relasec = NULL; - nr = 0; - } else { - relasec = sec->rela; - nr = (int) (sec->data->d_size / sizeof(void *)); - } - - /* populate sections */ - index = 0; - list_for_each_entry(sym, &kelf->symbols, list) { - unsigned long insn_offset = 0; - - if (sym->type != STT_FUNC || sym->status == SAME) - continue; - - if (!sym->has_func_profiling) { - log_debug("function %s has no fentry/mcount call, no mcount record is needed\n", - sym->name); - continue; - } - - switch(kelf->arch) { - case AARCH64: { - unsigned char *insn; - int i; - - insn = sym->sec->data->d_buf; - - /* - * If BTI (Branch Target Identification) is enabled then there - * might be an additional 'BTI C' instruction before the two - * patchable function entry 'NOP's. - * i.e. 0xd503245f (little endian) - */ - if (insn[0] == 0x5f) { - if (insn[1] != 0x24 || insn[2] != 0x03 || insn[3] != 0xd5) - ERROR("%s: unexpected instruction in patch section of function", sym->name); - insn_offset += 4; - insn += 4; - } - for (i = 0; i < 8; i += 4) { - /* We expect a NOP i.e. 0xd503201f (little endian) */ - if (insn[i] != 0x1f || insn[i + 1] != 0x20 || - insn[i + 2] != 0x03 || insn [i + 3] != 0xd5) - ERROR("%s: unexpected instruction in patch section of function", sym->name); - } - - break; - } - case PPC64: { - bool found = false; - - list_for_each_entry(rela, &sym->sec->rela->relas, list) - if (!strcmp(rela->sym->name, "_mcount")) { - found = true; - break; - } - - if (!found) - ERROR("%s: unexpected missing call to _mcount()", __func__); - - insn_offset = rela->offset; - break; - } - case X86_64: { - unsigned char *insn; - void *newdata; - - rela = list_first_entry(&sym->sec->rela->relas, struct rela, list); - - /* - * For "call fentry", the relocation points to 1 byte past the - * beginning of the instruction. - */ - insn_offset = rela->offset - 1; - - /* - * R_X86_64_NONE is only generated by older versions of - * kernel/gcc which use the mcount script. There's a - * NOP instead of a call to fentry. - */ - if (rela->type != R_X86_64_NONE) - break; - - /* Make a writable copy of the text section data */ - newdata = malloc(sym->sec->data->d_size); - if (!newdata) - ERROR("malloc"); - memcpy(newdata, sym->sec->data->d_buf, sym->sec->data->d_size); - sym->sec->data->d_buf = newdata; - insn = newdata; - - /* - * Replace the NOP with a call to fentry. The fentry - * rela symbol is already there, just need to change - * the relocation type accordingly. - */ - insn = sym->sec->data->d_buf; - if (insn[0] != 0xf) - ERROR("%s: unexpected instruction at the start of the function", sym->name); - insn[0] = 0xe8; - insn[1] = 0; - insn[2] = 0; - insn[3] = 0; - insn[4] = 0; - - rela->type = R_X86_64_PC32; - break; - } - case S390: { - insn_offset = sym->sym.st_value; - break; - } - default: - ERROR("unsupported arch"); - } - - if (multi_pfe) { - sec = find_nth_section_by_name(&kelf->sections, nr, - "__patchable_function_entries"); - if (!sec) - ERROR("cannot retrieve pre-allocated __pfe #%d\n", - nr); - - relasec = sec->rela; - sym->sec->pfe = sec; - sec->sh.sh_link = sec->index; - - nr++; - } - - /* - * 'rela' points to the mcount/fentry call. - * - * Create a .rela__mcount_loc entry which also points to it. - */ - ALLOC_LINK(mcount_rela, &relasec->relas); - mcount_rela->sym = sym; - mcount_rela->type = absolute_rela_type(kelf); - mcount_rela->addend = insn_offset - sym->sym.st_value; - - if (multi_pfe) { - mcount_rela->offset = 0; - sec = NULL; - } else { - mcount_rela->offset = (unsigned int) (index * sizeof(*funcs)); - } - - index++; - } - - /* sanity check, index should equal nr */ - if (index != nr) - ERROR("size mismatch in funcs sections"); -} - -/* - * This function strips out symbols that were referenced by changed rela - * sections, but the rela entries that referenced them were converted to - * dynrelas and are no longer needed. - */ -static void kpatch_strip_unneeded_syms(struct kpatch_elf *kelf, - struct lookup_table *table) -{ - struct symbol *sym, *safe; - - list_for_each_entry_safe(sym, safe, &kelf->symbols, list) { - if (sym->strip == SYMBOL_STRIP) { - list_del(&sym->list); - free(sym); - } - } -} - -static void kpatch_create_strings_elements(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - - /* create .kpatch.strings */ - - /* allocate section resources */ - ALLOC_LINK(sec, &kelf->sections); - sec->name = ".kpatch.strings"; - - /* set data */ - sec->data = malloc(sizeof(*sec->data)); - if (!sec->data) - ERROR("malloc"); - sec->data->d_type = ELF_T_BYTE; - - /* set section header */ - sec->sh.sh_type = SHT_PROGBITS; - sec->sh.sh_entsize = 1; - sec->sh.sh_addralign = 1; - sec->sh.sh_flags = SHF_ALLOC; - - /* create .kpatch.strings section symbol (reuse sym variable) */ - - ALLOC_LINK(sym, &kelf->symbols); - sym->sec = sec; - sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION); - sym->type = STT_SECTION; - sym->bind = STB_LOCAL; - sym->name = ".kpatch.strings"; -} - -static void kpatch_build_strings_section_data(struct kpatch_elf *kelf) -{ - struct string *string; - struct section *sec; - size_t size; - char *strtab; - - sec = find_section_by_name(&kelf->sections, ".kpatch.strings"); - if (!sec) - ERROR("can't find .kpatch.strings"); - - /* determine size */ - size = 0; - list_for_each_entry(string, &kelf->strings, list) - size += strlen(string->name) + 1; - - /* allocate section resources */ - strtab = malloc(size); - if (!strtab) - ERROR("malloc"); - sec->data->d_buf = strtab; - sec->data->d_size = size; - - /* populate strings section data */ - list_for_each_entry(string, &kelf->strings, list) { - strcpy(strtab, string->name); - strtab += strlen(string->name) + 1; - } -} - -/* - * Don't allow sibling calls from patched functions on ppc64le. Before doing a - * sibling call, the patched function restores the stack to its caller's stack. - * The kernel-generated stub then writes the patch module's r2 (toc) value to - * the caller's stack, corrupting it, eventually causing a panic after it - * returns to the caller and the caller tries to use the livepatch module's toc - * value. - * - * In theory we could instead a) generate a custom stub, or b) modify the - * kernel livepatch_handler code to save/restore the stack r2 value, but this - * is easier for now. - */ -static void kpatch_no_sibling_calls_ppc64le(struct kpatch_elf *kelf) -{ - struct symbol *sym; - unsigned char *insn; - unsigned int offset; - - if (kelf->arch != PPC64) - return; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type != STT_FUNC || sym->status != CHANGED) - continue; - - for (offset = 0; offset < sym->sec->data->d_size; offset += 4) { - - insn = sym->sec->data->d_buf + offset; - - /* - * The instruction 0x48000000 can be assumed to be a - * sibling call: - * - * Bits 0-5 (opcode) == 0x9: unconditional branch - * Bit 30 (absolute) == 0: relative address - * Bit 31 (link) == 0: doesn't set LR (not a call) - * - * Bits 6-29 (branch address) == zero, which means - * it's either a branch to self (infinite loop), or - * there's a REL24 relocation for the address which - * will be written by the linker or the kernel. - */ - if (insn[3] != 0x48 || insn[2] != 0x00 || - insn[1] != 0x00 || insn[0] != 0x00) - continue; - - /* Make sure it's not a branch-to-self: */ - if (!find_rela_by_offset(sym->sec->rela, offset)) - continue; - - ERROR("Found an unsupported sibling call at %s()+0x%lx. Add __attribute__((optimize(\"-fno-optimize-sibling-calls\"))) to %s() definition.", - sym->name, sym->sym.st_value + offset, sym->name); - } - } -} - -/* Check which functions have fentry/mcount calls; save this info for later use. */ -static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf) -{ - struct symbol *sym; - struct rela *rela; - unsigned char *insn; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type != STT_FUNC || !sym->sec) - continue; - - switch(kelf->arch) { - case AARCH64: { - struct section *sec; - - list_for_each_entry(sec, &kelf->sections, list) { - if (strcmp(sec->name, "__patchable_function_entries")) - continue; - if (multi_pfe && sym->sec->pfe != sec) - continue; - /* - * If we can't find the __patchable_function_entries section or - * there are no relocations in it then not patchable. - */ - if (!sec->rela) - continue; - - list_for_each_entry(rela, &sec->rela->relas, list) { - if (rela->sym->sec && sym->sec == rela->sym->sec) { - sym->has_func_profiling = 1; - goto next_symbol; - } - } - } - break; - } - case PPC64: - if (!sym->sec->rela) - continue; - list_for_each_entry(rela, &sym->sec->rela->relas, list) { - if (!strcmp(rela->sym->name, "_mcount")) { - sym->has_func_profiling = 1; - break; - } - } - break; - case X86_64: - if (!sym->sec->rela) - continue; - rela = list_first_entry(&sym->sec->rela->relas, struct rela, - list); - if ((rela->type != R_X86_64_NONE && - rela->type != R_X86_64_PC32 && - rela->type != R_X86_64_PLT32) || - strcmp(rela->sym->name, "__fentry__")) - continue; - - sym->has_func_profiling = 1; - break; - case S390: - if (!sym->sec->rela) - continue; - /* Check for compiler generated fentry nop - jgnop 0 */ - insn = sym->sec->data->d_buf; - if (insn[0] == 0xc0 && insn[1] == 0x04 && - insn[2] == 0x00 && insn[3] == 0x00 && - insn[4] == 0x00 && insn[5] == 0x00) - sym->has_func_profiling = 1; - break; - default: - ERROR("unsupported arch"); - } - next_symbol:; - } -} - -struct arguments { - char *args[7]; - bool debug, klp_arch; -}; - -static char args_doc[] = "original.o patched.o parent-name parent-symtab Module.symvers patch-module-name output.o"; - -static struct argp_option options[] = { - {"debug", 'd', NULL, 0, "Show debug output" }, - {"klp-arch", 'a', NULL, 0, "Kernel supports .klp.arch section" }, - { NULL } -}; - -static error_t parse_opt (int key, char *arg, struct argp_state *state) -{ - /* Get the input argument from argp_parse, which we - know is a pointer to our arguments structure. */ - struct arguments *arguments = state->input; - - switch (key) - { - case 'd': - arguments->debug = 1; - break; - case 'a': - arguments->klp_arch = 1; - break; - case ARGP_KEY_ARG: - if (state->arg_num >= 7) - /* Too many arguments. */ - argp_usage (state); - arguments->args[state->arg_num] = arg; - break; - case ARGP_KEY_END: - if (state->arg_num < 7) - /* Not enough arguments. */ - argp_usage (state); - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static bool has_multi_pfe(struct kpatch_elf *kelf) -{ - return !!find_nth_section_by_name(&kelf->sections, 1, - "__patchable_function_entries"); -} - -static struct argp argp = { options, parse_opt, args_doc, NULL }; - -int main(int argc, char *argv[]) -{ - struct kpatch_elf *kelf_orig, *kelf_patched, *kelf_out; - struct arguments arguments; - int num_changed, callbacks_exist, new_globals_exist; - struct lookup_table *lookup; - struct section *relasec, *symtab; - char *orig_obj, *patched_obj, *parent_name; - char *parent_symtab, *mod_symvers, *patch_name, *output_obj; - - memset(&arguments, 0, sizeof(arguments)); - argp_parse (&argp, argc, argv, 0, NULL, &arguments); - if (arguments.debug) - loglevel = DEBUG; - if (arguments.klp_arch) - KLP_ARCH = true; - - elf_version(EV_CURRENT); - - orig_obj = arguments.args[0]; - patched_obj = arguments.args[1]; - parent_name = arguments.args[2]; - parent_symtab = arguments.args[3]; - mod_symvers = arguments.args[4]; - patch_name = arguments.args[5]; - output_obj = arguments.args[6]; - - childobj = basename(orig_obj); - - kelf_orig = kpatch_elf_open(orig_obj); - kelf_patched = kpatch_elf_open(patched_obj); - multi_pfe = has_multi_pfe(kelf_orig) || has_multi_pfe(kelf_patched); - kpatch_find_func_profiling_calls(kelf_orig); - kpatch_find_func_profiling_calls(kelf_patched); - - kpatch_compare_elf_headers(kelf_orig->elf, kelf_patched->elf); - kpatch_check_program_headers(kelf_orig->elf); - kpatch_check_program_headers(kelf_patched->elf); - - kpatch_bundle_symbols(kelf_orig); - kpatch_bundle_symbols(kelf_patched); - - kpatch_detect_child_functions(kelf_orig); - kpatch_detect_child_functions(kelf_patched); - - lookup = lookup_open(parent_symtab, parent_name, mod_symvers, kelf_orig); - - kpatch_mark_grouped_sections(kelf_patched); - kpatch_replace_sections_syms(kelf_orig); - kpatch_replace_sections_syms(kelf_patched); - - kpatch_correlate_elfs(kelf_orig, kelf_patched); - kpatch_correlate_static_local_variables(kelf_orig, kelf_patched); - - /* - * After this point, we don't care about kelf_orig anymore. - * We access its sections via the twin pointers in the - * section, symbol, and rela lists of kelf_patched. - */ - kpatch_mark_ignored_sections(kelf_patched); - kpatch_compare_correlated_elements(kelf_patched); - kpatch_mark_ignored_functions_same(kelf_patched); - kpatch_mark_ignored_sections_same(kelf_patched); - kpatch_check_func_profiling_calls(kelf_patched); - kpatch_elf_teardown(kelf_orig); - kpatch_elf_free(kelf_orig); - - kpatch_include_standard_elements(kelf_patched); - num_changed = kpatch_include_changed_functions(kelf_patched); - callbacks_exist = kpatch_include_callback_elements(kelf_patched); - kpatch_include_force_elements(kelf_patched); - new_globals_exist = kpatch_include_new_globals(kelf_patched); - kpatch_include_debug_sections(kelf_patched); - - kpatch_process_special_sections(kelf_patched, lookup); - - kpatch_print_changes(kelf_patched); - kpatch_dump_kelf(kelf_patched); - - kpatch_verify_patchability(kelf_patched); - - if (!num_changed && !new_globals_exist) { - if (callbacks_exist) - log_debug("no changed functions were found, but callbacks exist\n"); - else { - log_debug("no changed functions were found\n"); - return EXIT_STATUS_NO_CHANGE; - } - } - - /* this is destructive to kelf_patched */ - kpatch_migrate_included_elements(kelf_patched, &kelf_out); - - /* this must be done before kelf_patched is torn down */ - kpatch_alloc_mcount_sections(kelf_patched, kelf_out); - - /* - * Teardown kelf_patched since we shouldn't access sections or symbols - * through it anymore. Don't free however, since our section and symbol - * name fields still point to strings in the Elf object owned by - * kpatch_patched. - */ - kpatch_elf_teardown(kelf_patched); - - kpatch_no_sibling_calls_ppc64le(kelf_out); - - /* create strings, patches, and dynrelas sections */ - kpatch_create_strings_elements(kelf_out); - kpatch_create_patches_sections(kelf_out, lookup, parent_name); - kpatch_create_intermediate_sections(kelf_out, lookup, parent_name, patch_name); - kpatch_create_kpatch_arch_section(kelf_out, parent_name); - kpatch_create_callbacks_objname_rela(kelf_out, parent_name); - kpatch_build_strings_section_data(kelf_out); - - kpatch_populate_mcount_sections(kelf_out); - - /* - * At this point, the set of output sections and symbols is - * finalized. Reorder the symbols into linker-compliant - * order and index all the symbols and sections. After the - * indexes have been established, update index data - * throughout the structure. - */ - kpatch_reorder_symbols(kelf_out); - kpatch_strip_unneeded_syms(kelf_out, lookup); - kpatch_reindex_elements(kelf_out); - - /* - * Update rela section headers and rebuild the rela section data - * buffers from the relas lists. - */ - symtab = find_section_by_name(&kelf_out->sections, ".symtab"); - if (!symtab) - ERROR("missing .symtab section"); - - list_for_each_entry(relasec, &kelf_out->sections, list) { - if (!is_rela_section(relasec)) - continue; - relasec->sh.sh_link = symtab->index; - relasec->sh.sh_info = relasec->base->index; - kpatch_rebuild_rela_section_data(relasec); - } - kpatch_check_relocations(kelf_out); - - kpatch_create_shstrtab(kelf_out); - kpatch_create_strtab(kelf_out); - kpatch_create_symtab(kelf_out); - kpatch_dump_kelf(kelf_out); - kpatch_write_output_elf(kelf_out, kelf_patched->elf, output_obj, 0664); - - lookup_close(lookup); - kpatch_elf_free(kelf_patched); - kpatch_elf_teardown(kelf_out); - kpatch_elf_free(kelf_out); - - return EXIT_STATUS_SUCCESS; -} diff --git a/kpatch-build/create-klp-module.c b/kpatch-build/create-klp-module.c deleted file mode 100644 index e942b9e..0000000 --- a/kpatch-build/create-klp-module.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * create-klp-module.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include "log.h" -#include "kpatch-elf.h" -#include "kpatch-intermediate.h" - -/* For log.h */ -char *childobj; -enum loglevel loglevel = NORMAL; - -/* - * Add a symbol from .kpatch.symbols to the symbol table - * - * If a symbol matching the .kpatch.symbols entry already - * exists, return it. - */ -static struct symbol *find_or_add_ksym_to_symbols(struct kpatch_elf *kelf, - struct section *ksymsec, - char *strings, int offset) -{ - struct kpatch_symbol *ksyms, *ksym; - struct symbol *sym; - struct rela *rela; - char *objname, *name; - char pos[32], buf[256]; - unsigned int index; - - ksyms = ksymsec->data->d_buf; - index = (unsigned int)(offset / sizeof(*ksyms)); - ksym = &ksyms[index]; - - /* Get name of ksym */ - rela = find_rela_by_offset(ksymsec->rela, - (unsigned int)(offset + offsetof(struct kpatch_symbol, name))); - if (!rela) - ERROR("name of ksym not found?"); - - name = strings + rela->addend; - - /* Get objname of ksym */ - rela = find_rela_by_offset(ksymsec->rela, - (unsigned int)(offset + offsetof(struct kpatch_symbol, objname))); - if (!rela) - ERROR("objname of ksym not found?"); - - objname = strings + rela->addend; - - snprintf(pos, 32, "%lu", ksym->sympos); - /* .klp.sym.objname.name,pos */ - snprintf(buf, 256, KLP_SYM_PREFIX "%s.%s,%s", objname, name, pos); - - /* Look for an already allocated symbol */ - list_for_each_entry(sym, &kelf->symbols, list) { - if (!strcmp(buf, sym->name)) - return sym; - } - - ALLOC_LINK(sym, NULL); - sym->name = strdup(buf); - if (!sym->name) - ERROR("strdup"); - sym->type = ksym->type; - sym->bind = ksym->bind; - /* - * Note that st_name will be set in kpatch_create_strtab(), - * and sym->index is set in kpatch_reindex_elements() - */ - sym->sym.st_shndx = SHN_LIVEPATCH; - sym->sym.st_info = (unsigned char)GELF_ST_INFO(sym->bind, sym->type); - /* - * Figure out where to put the new symbol: - * a) locals need to be grouped together, before globals - * b) globals can be tacked into the end of the list - */ - if (is_local_sym(sym)) { - struct list_head *head; - struct symbol *s; - - head = &kelf->symbols; - list_for_each_entry(s, &kelf->symbols, list) { - if (!is_local_sym(s)) - break; - head = &s->list; - } - list_add_tail(&sym->list, head); - } else { - list_add_tail(&sym->list, &kelf->symbols); - } - - return sym; -} - -/* - * Create a klp rela section given the base section and objname - * - * If a klp rela section matching the base section and objname - * already exists, return it. - */ -static struct section *find_or_add_klp_relasec(struct kpatch_elf *kelf, - struct section *base, - char *objname) -{ - struct section *relasec; - char buf[256]; - - /* .klp.rela.objname.secname */ - snprintf(buf, 256, KLP_RELASEC_PREFIX "%s.%s", objname, base->name); - - list_for_each_entry(relasec, &kelf->sections, list) { - if (!strcmp(relasec->name, buf)) - return relasec; - } - - ALLOC_LINK(relasec, &kelf->sections); - relasec->name = strdup(buf); - if (!relasec->name) - ERROR("strdup"); - relasec->base = base; - - INIT_LIST_HEAD(&relasec->relas); - - relasec->data = malloc(sizeof(*relasec->data)); - if (!relasec->data) - ERROR("malloc"); - relasec->data->d_type = ELF_T_RELA; - - /* sh_info and sh_link are set when rebuilding rela sections */ - relasec->sh.sh_type = SHT_RELA; - relasec->sh.sh_entsize = sizeof(GElf_Rela); - relasec->sh.sh_addralign = 8; - relasec->sh.sh_flags = SHF_RELA_LIVEPATCH | SHF_INFO_LINK | SHF_ALLOC; - - return relasec; -} - -/* - * Create klp relocation sections and klp symbols from .kpatch.relocations - * and .kpatch.symbols sections - * - * For every entry in .kpatch.relocations: - * 1) Allocate a symbol for the corresponding .kpatch.symbols entry if - * it doesn't already exist (find_or_add_ksym_to_symbols()) - * This is the symbol that the relocation points to (rela->sym) - * 2) Allocate a rela, and add it to the corresponding .klp.rela. section. If - * the matching .klp.rela. section (given the base section and objname) - * doesn't exist yet, create it (find_or_add_klp_relasec()) - */ -static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section *krelasec, - struct section *ksymsec, char *strings) -{ - struct section *klp_relasec; - struct kpatch_relocation *krelas; - struct symbol *sym, *dest; - struct rela *rela; - char *objname; - unsigned int nr, index, offset, dest_off; - - krelas = krelasec->data->d_buf; - nr = (unsigned int)(krelasec->data->d_size / sizeof(*krelas)); - - for (index = 0; index < nr; index++) { - offset = (unsigned int)(index * sizeof(*krelas)); - - /* Get the rela dest sym + offset */ - rela = find_rela_by_offset(krelasec->rela, - offset + offsetof(struct kpatch_relocation, dest)); - if (!rela) - ERROR("find_rela_by_offset"); - - dest = rela->sym; - dest_off = (unsigned int)rela->addend; - - /* Get the name of the object the dest belongs to */ - rela = find_rela_by_offset(krelasec->rela, - (unsigned int)(offset + offsetof(struct kpatch_relocation, objname))); - if (!rela) - ERROR("find_rela_by_offset"); - - objname = strings + rela->addend; - - /* Get the .kpatch.symbol entry for the rela src */ - rela = find_rela_by_offset(krelasec->rela, - (unsigned int)(offset + offsetof(struct kpatch_relocation, ksym))); - if (!rela) - ERROR("find_rela_by_offset"); - - /* Create (or find) a klp symbol from the rela src entry */ - sym = find_or_add_ksym_to_symbols(kelf, ksymsec, strings, - (unsigned int)rela->addend); - if (!sym) - ERROR("error finding or adding ksym to symtab"); - - /* Create (or find) the .klp.rela. section for the dest sec and object */ - klp_relasec = find_or_add_klp_relasec(kelf, dest->sec, objname); - if (!klp_relasec) - ERROR("error finding or adding klp relasec"); - - /* Add the klp rela to the .klp.rela. section */ - ALLOC_LINK(rela, &klp_relasec->relas); - rela->offset = (unsigned int)(dest->sym.st_value + dest_off); - rela->type = krelas[index].type; - rela->sym = sym; - rela->addend = krelas[index].addend; - } -} - -/* - * Create .klp.arch. sections by iterating through the .kpatch.arch section - * - * A .kpatch.arch section is just an array of kpatch_arch structs: - * - * struct kpatch_arch { - * unsigned long sec; - * char *objname; - * }; - * - * There are two relas associated with each kpatch arch entry, one that points - * to the section of interest (.parainstructions or .altinstructions), and one - * rela points to the name of the object the section belongs to in - * .kpatch.strings. This gives us the necessary information to create .klp.arch - * sections, which use the '.klp.arch.objname.secname' name format. - */ -static void create_klp_arch_sections(struct kpatch_elf *kelf, char *strings) -{ - struct section *karch, *sec, *base = NULL; - struct rela *rela, *rela2; - char *secname, *objname = NULL; - char buf[256]; - unsigned int nr, index, offset; - size_t new_size, old_size; - - karch = find_section_by_name(&kelf->sections, ".kpatch.arch"); - if (!karch) - return; - - nr = (unsigned int)(karch->data->d_size / sizeof(struct kpatch_arch)); - - for (index = 0; index < nr; index++) { - offset = (unsigned int)(index * sizeof(struct kpatch_arch)); - - /* Get the base section (.parainstructions or .altinstructions) */ - rela = find_rela_by_offset(karch->rela, - offset + offsetof(struct kpatch_arch, sec)); - if (!rela) - ERROR("find_rela_by_offset"); - - base = rela->sym->sec; - if (!base) - ERROR("base sec of kpatch_arch entry not found"); - - /* Get the name of the object the base section belongs to */ - rela = find_rela_by_offset(karch->rela, - (unsigned int)(offset + offsetof(struct kpatch_arch, objname))); - if (!rela) - ERROR("find_rela_by_offset"); - - objname = strings + rela->addend; - - /* Example: .klp.arch.vmlinux..parainstructions */ - snprintf(buf, 256, "%s%s.%s", KLP_ARCH_PREFIX, objname, base->name); - - /* Check if the .klp.arch. section already exists */ - sec = find_section_by_name(&kelf->sections, buf); - if (!sec) { - secname = strdup(buf); - if (!secname) - ERROR("strdup"); - - /* Start with a new section with size 0 first */ - sec = create_section_pair(kelf, secname, 1, 0); - } - - /* - * Merge .klp.arch. sections if necessary - * - * Example: - * If there are multiple .parainstructions sections for vmlinux - * (this can happen when, using the --unique option for ld, - * we've linked together multiple .o's with .parainstructions - * sections for the same object), they will be merged under a - * single .klp.arch.vmlinux..parainstructions section - */ - old_size = sec->data->d_size; - - /* - * Due to a quirk in how .parainstructions gets linked, the - * section size doesn't encompass the last 4 bytes of the last - * entry. Align the old size properly before merging. - */ - if (!strcmp(base->name, ".parainstructions")) { - char *str; - static int align_mask = 0; - - if (!align_mask) { - str = getenv("PARA_STRUCT_SIZE"); - if (!str) - ERROR("PARA_STRUCT_SIZE not set"); - - align_mask = atoi(str) - 1; - } - - old_size = (old_size + align_mask) & ~align_mask; - } - - new_size = old_size + base->data->d_size; - sec->data->d_buf = realloc(sec->data->d_buf, new_size); - if (!sec->data->d_buf) - ERROR("realloc"); - sec->data->d_size = new_size; - sec->sh.sh_size = sec->data->d_size; - memcpy(sec->data->d_buf + old_size, - base->data->d_buf, base->data->d_size); - - list_for_each_entry(rela, &base->rela->relas, list) { - ALLOC_LINK(rela2, &sec->rela->relas); - rela2->sym = rela->sym; - rela2->type = rela->type; - rela2->addend = rela->addend; - rela2->offset = (unsigned int)(old_size + rela->offset); - } - } -} - -/* - * We can't keep these sections since the module loader will apply them before - * the patch module gets a chance to load (that's why we copied these sections - * into .klp.arch. sections. Hence we remove them here. - */ -static void remove_arch_sections(struct kpatch_elf *kelf) -{ - size_t i; - char *arch_sections[] = { - ".parainstructions", - ".rela.parainstructions", - ".altinstructions", - ".rela.altinstructions" - }; - - for (i = 0; i < sizeof(arch_sections)/sizeof(arch_sections[0]); i++) - kpatch_remove_and_free_section(kelf, arch_sections[i]); - -} - -static void remove_intermediate_sections(struct kpatch_elf *kelf) -{ - size_t i; - char *intermediate_sections[] = { - ".kpatch.symbols", - ".rela.kpatch.symbols", - ".kpatch.relocations", - ".rela.kpatch.relocations", - ".kpatch.arch", - ".rela.kpatch.arch" - }; - - for (i = 0; i < sizeof(intermediate_sections)/sizeof(intermediate_sections[0]); i++) - kpatch_remove_and_free_section(kelf, intermediate_sections[i]); -} - -struct arguments { - char *args[2]; - int debug; - int no_klp_arch; -}; - -static char args_doc[] = "input.ko output.ko"; - -static struct argp_option options[] = { - {"debug", 'd', 0, 0, "Show debug output" }, - {"no-klp-arch-sections", 'n', 0, 0, "Do not output .klp.arch.* sections" }, - { 0 } -}; - -static error_t parse_opt (int key, char *arg, struct argp_state *state) -{ - /* Get the input argument from argp_parse, which we - know is a pointer to our arguments structure. */ - struct arguments *arguments = state->input; - - switch (key) - { - case 'd': - arguments->debug = 1; - break; - case 'n': - arguments->no_klp_arch = 1; - break; - case ARGP_KEY_ARG: - if (state->arg_num >= 2) - /* Too many arguments. */ - argp_usage (state); - arguments->args[state->arg_num] = arg; - break; - case ARGP_KEY_END: - if (state->arg_num < 2) - /* Not enough arguments. */ - argp_usage (state); - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static struct argp argp = { options, parse_opt, args_doc, 0 }; - -int main(int argc, char *argv[]) -{ - struct kpatch_elf *kelf; - struct section *symtab, *relasec; - struct section *ksymsec, *krelasec, *strsec; - struct arguments arguments; - char *strings; - unsigned int ksyms_nr, krelas_nr; - - memset(&arguments, 0, sizeof(arguments)); - argp_parse (&argp, argc, argv, 0, 0, &arguments); - if (arguments.debug) - loglevel = DEBUG; - - elf_version(EV_CURRENT); - - childobj = basename(arguments.args[0]); - - kelf = kpatch_elf_open(arguments.args[0]); - - /* - * Sanity checks: - * - Make sure all the required sections exist - * - Make sure that the number of entries in - * .kpatch.{symbols,relocations} match - */ - strsec = find_section_by_name(&kelf->sections, ".kpatch.strings"); - if (!strsec) - ERROR("missing .kpatch.strings"); - strings = strsec->data->d_buf; - - ksymsec = find_section_by_name(&kelf->sections, ".kpatch.symbols"); - if (!ksymsec) - ERROR("missing .kpatch.symbols section"); - ksyms_nr = (unsigned int)(ksymsec->data->d_size / sizeof(struct kpatch_symbol)); - - krelasec = find_section_by_name(&kelf->sections, ".kpatch.relocations"); - if (!krelasec) - ERROR("missing .kpatch.relocations section"); - krelas_nr = (unsigned int)(krelasec->data->d_size / sizeof(struct kpatch_relocation)); - - if (krelas_nr != ksyms_nr) - ERROR("number of krelas and ksyms do not match"); - - /* - * Create klp rela sections and klp symbols from - * .kpatch.{relocations,symbols} sections - */ - create_klp_relasecs_and_syms(kelf, krelasec, ksymsec, strings); - - /* - * If --no-klp-arch-sections wasn't set, additionally - * create .klp.arch. sections - */ - if (!arguments.no_klp_arch) { - create_klp_arch_sections(kelf, strings); - remove_arch_sections(kelf); - } - - remove_intermediate_sections(kelf); - kpatch_reindex_elements(kelf); - - /* Rebuild rela sections, new klp rela sections will be rebuilt too. */ - symtab = find_section_by_name(&kelf->sections, ".symtab"); - if (!symtab) - ERROR("missing .symtab section"); - - list_for_each_entry(relasec, &kelf->sections, list) { - if (!is_rela_section(relasec)) - continue; - relasec->sh.sh_link = symtab->index; - relasec->sh.sh_info = relasec->base->index; - kpatch_rebuild_rela_section_data(relasec); - } - - kpatch_create_shstrtab(kelf); - kpatch_create_strtab(kelf); - kpatch_create_symtab(kelf); - - kpatch_write_output_elf(kelf, kelf->elf, arguments.args[1], 0664); - kpatch_elf_teardown(kelf); - kpatch_elf_free(kelf); - - return 0; -} diff --git a/kpatch-build/create-kpatch-module.c b/kpatch-build/create-kpatch-module.c deleted file mode 100644 index 2884f93..0000000 --- a/kpatch-build/create-kpatch-module.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * create-kpatch-module.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include "log.h" -#include "kpatch-elf.h" -#include "kpatch-intermediate.h" -#include "kpatch-patch.h" - -/* For log.h */ -char *childobj; -enum loglevel loglevel = NORMAL; - -/* - * Create .kpatch.dynrelas from .kpatch.relocations and .kpatch.symbols sections - * - * Iterate through .kpatch.relocations and fill in the corresponding dynrela - * entry using information from .kpatch.relocations and .kpatch.symbols - */ -static void create_dynamic_rela_sections(struct kpatch_elf *kelf, struct section *krelasec, - struct section *ksymsec, struct section *strsec) -{ - struct kpatch_patch_dynrela *dynrelas; - struct kpatch_relocation *krelas; - struct kpatch_symbol *ksym, *ksyms; - struct section *dynsec; - struct symbol *sym; - struct rela *rela; - unsigned int index, nr, offset, dest_offset, objname_offset, name_offset; - unsigned int type; - long addend; - char *target_name; - - ksyms = ksymsec->data->d_buf; - krelas = krelasec->data->d_buf; - nr = (unsigned int)(krelasec->data->d_size / sizeof(*krelas)); - - dynsec = create_section_pair(kelf, ".kpatch.dynrelas", sizeof(*dynrelas), nr); - dynrelas = dynsec->data->d_buf; - - for (index = 0; index < nr; index++) { - offset = index * (unsigned int)sizeof(*krelas); - - /* - * To fill in each dynrela entry, find dest location, - * objname offset, ksym, and symbol name offset - */ - - /* Get dest location */ - rela = find_rela_by_offset(krelasec->rela, - offset + offsetof(struct kpatch_relocation, dest)); - if (!rela) - ERROR("find_rela_by_offset"); - sym = rela->sym; - dest_offset = (unsigned int)rela->addend; - - /* Get objname offset */ - rela = find_rela_by_offset(krelasec->rela, - (unsigned int)(offset + offsetof(struct kpatch_relocation, objname))); - if (!rela) - ERROR("find_rela_by_offset"); - objname_offset = (unsigned int)rela->addend; - - /* Get ksym (.kpatch.symbols entry) and symbol name offset */ - rela = find_rela_by_offset(krelasec->rela, - (unsigned int)(offset + offsetof(struct kpatch_relocation, ksym))); - if (!rela) - ERROR("find_rela_by_offset"); - ksym = ksyms + (rela->addend / sizeof(*ksyms)); - - offset = (unsigned int )(index * sizeof(*ksyms)); - rela = find_rela_by_offset(ksymsec->rela, - (unsigned int)(offset + offsetof(struct kpatch_symbol, name))); - if (!rela) - ERROR("find_rela_by_offset"); - name_offset = (unsigned int)rela->addend; - - /* Fill in dynrela entry */ - type = krelas[index].type; - addend = krelas[index].addend; - if (type == R_X86_64_64 && (addend > INT_MAX || addend <= INT_MIN)) { - target_name = (char *)strsec->data->d_buf + name_offset; - ERROR("got R_X86_64_64 dynrela for '%s' with addend too large or too small for an int: %lx", - target_name, addend); - } - - dynrelas[index].src = ksym->src; - dynrelas[index].addend = addend; - dynrelas[index].type = type; - dynrelas[index].external = krelas[index].external; - dynrelas[index].sympos = ksym->sympos; - - /* dest */ - ALLOC_LINK(rela, &dynsec->rela->relas); - rela->sym = sym; - rela->type = R_X86_64_64; - rela->addend = dest_offset; - rela->offset = (unsigned int)(index * sizeof(*dynrelas)); - - /* name */ - ALLOC_LINK(rela, &dynsec->rela->relas); - rela->sym = strsec->secsym; - rela->type = R_X86_64_64; - rela->addend = name_offset; - rela->offset = (unsigned int)(index * sizeof(*dynrelas) + \ - offsetof(struct kpatch_patch_dynrela, name)); - - /* objname */ - ALLOC_LINK(rela, &dynsec->rela->relas); - rela->sym = strsec->secsym; - rela->type = R_X86_64_64; - rela->addend = objname_offset; - rela->offset = (unsigned int)(index * sizeof(*dynrelas) + \ - offsetof(struct kpatch_patch_dynrela, objname)); - } -} - -static void remove_intermediate_sections(struct kpatch_elf *kelf) -{ - size_t i; - char *intermediate_sections[] = { - ".kpatch.symbols", - ".rela.kpatch.symbols", - ".kpatch.relocations", - ".rela.kpatch.relocations", - ".kpatch.arch", - ".rela.kpatch.arch" - }; - - for (i = 0; i < sizeof(intermediate_sections)/sizeof(intermediate_sections[0]); i++) - kpatch_remove_and_free_section(kelf, intermediate_sections[i]); -} - -struct arguments { - char *args[2]; - int debug; -}; - -static char args_doc[] = "input.o output.o"; - -static struct argp_option options[] = { - {"debug", 'd', 0, 0, "Show debug output" }, - { 0 } -}; - -static error_t parse_opt (int key, char *arg, struct argp_state *state) -{ - /* Get the input argument from argp_parse, which we - know is a pointer to our arguments structure. */ - struct arguments *arguments = state->input; - - switch (key) - { - case 'd': - arguments->debug = 1; - break; - case ARGP_KEY_ARG: - if (state->arg_num >= 2) - /* Too many arguments. */ - argp_usage (state); - arguments->args[state->arg_num] = arg; - break; - case ARGP_KEY_END: - if (state->arg_num < 2) - /* Not enough arguments. */ - argp_usage (state); - break; - default: - return ARGP_ERR_UNKNOWN; - } - return 0; -} - -static struct argp argp = { options, parse_opt, args_doc, 0 }; - -int main(int argc, char *argv[]) -{ - struct kpatch_elf *kelf; - struct section *symtab, *sec; - struct section *ksymsec, *krelasec, *strsec; - struct arguments arguments; - unsigned int ksyms_nr, krelas_nr; - - arguments.debug = 0; - argp_parse (&argp, argc, argv, 0, 0, &arguments); - if (arguments.debug) - loglevel = DEBUG; - - elf_version(EV_CURRENT); - - childobj = basename(arguments.args[0]); - - kelf = kpatch_elf_open(arguments.args[0]); - - /* - * Sanity checks: - * - Make sure all the required sections exist - * - Make sure that the number of entries in - * .kpatch.{symbols,relocations} match - */ - strsec = find_section_by_name(&kelf->sections, ".kpatch.strings"); - if (!strsec) - ERROR("missing .kpatch.strings"); - - ksymsec = find_section_by_name(&kelf->sections, ".kpatch.symbols"); - if (!ksymsec) - ERROR("missing .kpatch.symbols section"); - ksyms_nr = (unsigned int)(ksymsec->data->d_size / sizeof(struct kpatch_symbol)); - - krelasec = find_section_by_name(&kelf->sections, ".kpatch.relocations"); - if (!krelasec) - ERROR("missing .kpatch.relocations section"); - krelas_nr = (unsigned int)(krelasec->data->d_size / sizeof(struct kpatch_relocation)); - - if (krelas_nr != ksyms_nr) - ERROR("number of krelas and ksyms do not match"); - - /* Create dynrelas from .kpatch.{relocations,symbols} sections */ - create_dynamic_rela_sections(kelf, krelasec, ksymsec, strsec); - remove_intermediate_sections(kelf); - - kpatch_reindex_elements(kelf); - - symtab = find_section_by_name(&kelf->sections, ".symtab"); - if (!symtab) - ERROR("missing .symtab section"); - - list_for_each_entry(sec, &kelf->sections, list) { - if (!is_rela_section(sec)) - continue; - sec->sh.sh_link = symtab->index; - sec->sh.sh_info = sec->base->index; - kpatch_rebuild_rela_section_data(sec); - } - - kpatch_create_shstrtab(kelf); - kpatch_create_strtab(kelf); - kpatch_create_symtab(kelf); - - kpatch_write_output_elf(kelf, kelf->elf, arguments.args[1], 0664); - kpatch_elf_teardown(kelf); - kpatch_elf_free(kelf); - - return 0; -} diff --git a/kpatch-build/gcc-plugins/gcc-common.h b/kpatch-build/gcc-plugins/gcc-common.h deleted file mode 100644 index 443faf6..0000000 --- a/kpatch-build/gcc-plugins/gcc-common.h +++ /dev/null @@ -1,969 +0,0 @@ -#ifndef GCC_COMMON_H_INCLUDED -#define GCC_COMMON_H_INCLUDED - -#include "bversion.h" -#if BUILDING_GCC_VERSION >= 6000 -#include "gcc-plugin.h" -#else -#include "plugin.h" -#endif -#include "plugin-version.h" -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "line-map.h" -#include "input.h" -#include "tree.h" - -#include "tree-inline.h" -#include "version.h" -#include "rtl.h" -#include "tm_p.h" -#include "flags.h" -#include "hard-reg-set.h" -#include "output.h" -#include "except.h" -#include "function.h" -#include "toplev.h" -#if BUILDING_GCC_VERSION >= 5000 -#include "expr.h" -#endif -#include "basic-block.h" -#include "intl.h" -#include "ggc.h" -#include "timevar.h" - -#if BUILDING_GCC_VERSION < 10000 -#include "params.h" -#endif - -#if BUILDING_GCC_VERSION <= 4009 -#include "pointer-set.h" -#else -#include "hash-map.h" -#endif - -#if BUILDING_GCC_VERSION >= 7000 -#include "memmodel.h" -#endif -#include "emit-rtl.h" -#include "debug.h" -#include "target.h" -#include "langhooks.h" -#include "cfgloop.h" -#include "cgraph.h" -#include "opts.h" - -#if BUILDING_GCC_VERSION == 4005 -#include -#endif - -#if BUILDING_GCC_VERSION >= 4007 -#include "tree-pretty-print.h" -#include "gimple-pretty-print.h" -#endif - -#if BUILDING_GCC_VERSION >= 4006 -/* - * The c-family headers were moved into a subdirectory in GCC version - * 4.7, but most plugin-building users of GCC 4.6 are using the Debian - * or Ubuntu package, which has an out-of-tree patch to move this to the - * same location as found in 4.7 and later: - * https://sources.debian.net/src/gcc-4.6/4.6.3-14/debian/patches/pr45078.diff/ - */ -#include "c-family/c-common.h" -#else -#include "c-common.h" -#endif - -#if BUILDING_GCC_VERSION <= 4008 -#include "tree-flow.h" -#else -#include "tree-cfgcleanup.h" -#include "tree-ssa-operands.h" -#include "tree-into-ssa.h" -#endif - -#if BUILDING_GCC_VERSION >= 4008 -#include "is-a.h" -#endif - -#include "diagnostic.h" -#include "tree-dump.h" -#include "tree-pass.h" -#if BUILDING_GCC_VERSION >= 4009 -#include "pass_manager.h" -#endif -#include "predict.h" -#include "ipa-utils.h" - -#if BUILDING_GCC_VERSION >= 8000 -#include "stringpool.h" -#endif - -#if BUILDING_GCC_VERSION >= 4009 -#include "attribs.h" -#include "varasm.h" -#include "stor-layout.h" -#include "internal-fn.h" -#include "gimple-expr.h" -#include "gimple-fold.h" -#include "context.h" -#include "tree-ssa-alias.h" -#include "tree-ssa.h" -#include "stringpool.h" -#if BUILDING_GCC_VERSION >= 7000 -#include "tree-vrp.h" -#endif -#include "tree-ssanames.h" -#include "print-tree.h" -#include "tree-eh.h" -#include "stmt.h" -#include "gimplify.h" -#endif - -#include "gimple.h" - -#if BUILDING_GCC_VERSION >= 4009 -#include "tree-ssa-operands.h" -#include "tree-phinodes.h" -#include "tree-cfg.h" -#include "gimple-iterator.h" -#include "gimple-ssa.h" -#include "ssa-iterators.h" -#endif - -#if BUILDING_GCC_VERSION >= 5000 -#include "builtins.h" -#endif - -/* missing from basic_block.h... */ -void debug_dominance_info(enum cdi_direction dir); -void debug_dominance_tree(enum cdi_direction dir, basic_block root); - -#if BUILDING_GCC_VERSION == 4006 -void debug_gimple_stmt(gimple); -void debug_gimple_seq(gimple_seq); -void print_gimple_seq(FILE *, gimple_seq, int, int); -void print_gimple_stmt(FILE *, gimple, int, int); -void print_gimple_expr(FILE *, gimple, int, int); -void dump_gimple_stmt(pretty_printer *, gimple, int, int); -#endif - -#define __unused __attribute__((__unused__)) -#define __visible __attribute__((visibility("default"))) - -#define DECL_NAME_POINTER(node) IDENTIFIER_POINTER(DECL_NAME(node)) -#define DECL_NAME_LENGTH(node) IDENTIFIER_LENGTH(DECL_NAME(node)) -#define TYPE_NAME_POINTER(node) IDENTIFIER_POINTER(TYPE_NAME(node)) -#define TYPE_NAME_LENGTH(node) IDENTIFIER_LENGTH(TYPE_NAME(node)) - -/* should come from c-tree.h if only it were installed for gcc 4.5... */ -#define C_TYPE_FIELDS_READONLY(TYPE) TREE_LANG_FLAG_1(TYPE) - -static inline tree build_const_char_string(int len, const char *str) -{ - tree cstr, elem, index, type; - - cstr = build_string(len, str); - elem = build_type_variant(char_type_node, 1, 0); - index = build_index_type(size_int(len - 1)); - type = build_array_type(elem, index); - TREE_TYPE(cstr) = type; - TREE_CONSTANT(cstr) = 1; - TREE_READONLY(cstr) = 1; - TREE_STATIC(cstr) = 1; - return cstr; -} - -#define PASS_INFO(NAME, REF, ID, POS) \ -struct register_pass_info NAME##_pass_info = { \ - .pass = make_##NAME##_pass(), \ - .reference_pass_name = REF, \ - .ref_pass_instance_number = ID, \ - .pos_op = POS, \ -} - -#if BUILDING_GCC_VERSION == 4005 -#define FOR_EACH_LOCAL_DECL(FUN, I, D) \ - for (tree vars = (FUN)->local_decls, (I) = 0; \ - vars && ((D) = TREE_VALUE(vars)); \ - vars = TREE_CHAIN(vars), (I)++) -#define DECL_CHAIN(NODE) (TREE_CHAIN(DECL_MINIMAL_CHECK(NODE))) -#define FOR_EACH_VEC_ELT(T, V, I, P) \ - for (I = 0; VEC_iterate(T, (V), (I), (P)); ++(I)) -#define TODO_rebuild_cgraph_edges 0 -#define SCOPE_FILE_SCOPE_P(EXP) (!(EXP)) - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -typedef struct varpool_node *varpool_node_ptr; - -static inline bool gimple_call_builtin_p(gimple stmt, enum built_in_function code) -{ - tree fndecl; - - if (!is_gimple_call(stmt)) - return false; - fndecl = gimple_call_fndecl(stmt); - if (!fndecl || DECL_BUILT_IN_CLASS(fndecl) != BUILT_IN_NORMAL) - return false; - return DECL_FUNCTION_CODE(fndecl) == code; -} - -static inline bool is_simple_builtin(tree decl) -{ - if (decl && DECL_BUILT_IN_CLASS(decl) != BUILT_IN_NORMAL) - return false; - - switch (DECL_FUNCTION_CODE(decl)) { - /* Builtins that expand to constants. */ - case BUILT_IN_CONSTANT_P: - case BUILT_IN_EXPECT: - case BUILT_IN_OBJECT_SIZE: - case BUILT_IN_UNREACHABLE: - /* Simple register moves or loads from stack. */ - case BUILT_IN_RETURN_ADDRESS: - case BUILT_IN_EXTRACT_RETURN_ADDR: - case BUILT_IN_FROB_RETURN_ADDR: - case BUILT_IN_RETURN: - case BUILT_IN_AGGREGATE_INCOMING_ADDRESS: - case BUILT_IN_FRAME_ADDRESS: - case BUILT_IN_VA_END: - case BUILT_IN_STACK_SAVE: - case BUILT_IN_STACK_RESTORE: - /* Exception state returns or moves registers around. */ - case BUILT_IN_EH_FILTER: - case BUILT_IN_EH_POINTER: - case BUILT_IN_EH_COPY_VALUES: - return true; - - default: - return false; - } -} - -static inline void add_local_decl(struct function *fun, tree d) -{ - gcc_assert(TREE_CODE(d) == VAR_DECL); - fun->local_decls = tree_cons(NULL_TREE, d, fun->local_decls); -} -#endif - -#if BUILDING_GCC_VERSION <= 4006 -#define ANY_RETURN_P(rtx) (GET_CODE(rtx) == RETURN) -#define C_DECL_REGISTER(EXP) DECL_LANG_FLAG_4(EXP) -#define EDGE_PRESERVE 0ULL -#define HOST_WIDE_INT_PRINT_HEX_PURE "%" HOST_WIDE_INT_PRINT "x" -#define flag_fat_lto_objects true - -#define get_random_seed(noinit) ({ \ - unsigned HOST_WIDE_INT seed; \ - sscanf(get_random_seed(noinit), "%" HOST_WIDE_INT_PRINT "x", &seed); \ - seed * seed; }) - -#define int_const_binop(code, arg1, arg2) \ - int_const_binop((code), (arg1), (arg2), 0) - -static inline bool gimple_clobber_p(gimple s __unused) -{ - return false; -} - -static inline bool gimple_asm_clobbers_memory_p(const_gimple stmt) -{ - unsigned i; - - for (i = 0; i < gimple_asm_nclobbers(stmt); i++) { - tree op = gimple_asm_clobber_op(stmt, i); - - if (!strcmp(TREE_STRING_POINTER(TREE_VALUE(op)), "memory")) - return true; - } - - return false; -} - -static inline tree builtin_decl_implicit(enum built_in_function fncode) -{ - return implicit_built_in_decls[fncode]; -} - -static inline int ipa_reverse_postorder(struct cgraph_node **order) -{ - return cgraph_postorder(order); -} - -static inline struct cgraph_node *cgraph_create_node(tree decl) -{ - return cgraph_node(decl); -} - -static inline struct cgraph_node *cgraph_get_create_node(tree decl) -{ - struct cgraph_node *node = cgraph_get_node(decl); - - return node ? node : cgraph_node(decl); -} - -static inline bool cgraph_function_with_gimple_body_p(struct cgraph_node *node) -{ - return node->analyzed && !node->thunk.thunk_p && !node->alias; -} - -static inline struct cgraph_node *cgraph_first_function_with_gimple_body(void) -{ - struct cgraph_node *node; - - for (node = cgraph_nodes; node; node = node->next) - if (cgraph_function_with_gimple_body_p(node)) - return node; - return NULL; -} - -static inline struct cgraph_node *cgraph_next_function_with_gimple_body(struct cgraph_node *node) -{ - for (node = node->next; node; node = node->next) - if (cgraph_function_with_gimple_body_p(node)) - return node; - return NULL; -} - -static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable) -{ - cgraph_node_ptr alias; - - if (callback(node, data)) - return true; - - for (alias = node->same_body; alias; alias = alias->next) { - if (include_overwritable || cgraph_function_body_availability(alias) > AVAIL_OVERWRITABLE) - if (cgraph_for_node_and_aliases(alias, callback, data, include_overwritable)) - return true; - } - - return false; -} - -#define FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) \ - for ((node) = cgraph_first_function_with_gimple_body(); (node); \ - (node) = cgraph_next_function_with_gimple_body(node)) - -static inline void varpool_add_new_variable(tree decl) -{ - varpool_finalize_decl(decl); -} -#endif - -#if BUILDING_GCC_VERSION <= 4007 -#define FOR_EACH_FUNCTION(node) \ - for (node = cgraph_nodes; node; node = node->next) -#define FOR_EACH_VARIABLE(node) \ - for (node = varpool_nodes; node; node = node->next) -#define PROP_loops 0 -#define NODE_SYMBOL(node) (node) -#define NODE_DECL(node) (node)->decl -#define INSN_LOCATION(INSN) RTL_LOCATION(INSN) -#define vNULL NULL - -static inline int bb_loop_depth(const_basic_block bb) -{ - return bb->loop_father ? loop_depth(bb->loop_father) : 0; -} - -static inline bool gimple_store_p(gimple gs) -{ - tree lhs = gimple_get_lhs(gs); - - return lhs && !is_gimple_reg(lhs); -} - -static inline void gimple_init_singleton(gimple g __unused) -{ -} -#endif - -#if BUILDING_GCC_VERSION == 4007 || BUILDING_GCC_VERSION == 4008 -static inline struct cgraph_node *cgraph_alias_target(struct cgraph_node *n) -{ - return cgraph_alias_aliased_node(n); -} -#endif - -#if BUILDING_GCC_VERSION >= 4007 && BUILDING_GCC_VERSION <= 4009 -#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \ - cgraph_create_edge((caller), (callee), (call_stmt), (count), (freq)) -#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \ - cgraph_create_edge_including_clones((caller), (callee), (old_call_stmt), (call_stmt), (count), (freq), (reason)) -#endif - -#if BUILDING_GCC_VERSION <= 4008 -#define ENTRY_BLOCK_PTR_FOR_FN(FN) ENTRY_BLOCK_PTR_FOR_FUNCTION(FN) -#define EXIT_BLOCK_PTR_FOR_FN(FN) EXIT_BLOCK_PTR_FOR_FUNCTION(FN) -#define basic_block_info_for_fn(FN) ((FN)->cfg->x_basic_block_info) -#define n_basic_blocks_for_fn(FN) ((FN)->cfg->x_n_basic_blocks) -#define n_edges_for_fn(FN) ((FN)->cfg->x_n_edges) -#define last_basic_block_for_fn(FN) ((FN)->cfg->x_last_basic_block) -#define label_to_block_map_for_fn(FN) ((FN)->cfg->x_label_to_block_map) -#define profile_status_for_fn(FN) ((FN)->cfg->x_profile_status) -#define BASIC_BLOCK_FOR_FN(FN, N) BASIC_BLOCK_FOR_FUNCTION((FN), (N)) -#define NODE_IMPLICIT_ALIAS(node) (node)->same_body_alias -#define VAR_P(NODE) (TREE_CODE(NODE) == VAR_DECL) - -static inline bool tree_fits_shwi_p(const_tree t) -{ - if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST) - return false; - - if (TREE_INT_CST_HIGH(t) == 0 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) >= 0) - return true; - - if (TREE_INT_CST_HIGH(t) == -1 && (HOST_WIDE_INT)TREE_INT_CST_LOW(t) < 0 && !TYPE_UNSIGNED(TREE_TYPE(t))) - return true; - - return false; -} - -static inline bool tree_fits_uhwi_p(const_tree t) -{ - if (t == NULL_TREE || TREE_CODE(t) != INTEGER_CST) - return false; - - return TREE_INT_CST_HIGH(t) == 0; -} - -static inline HOST_WIDE_INT tree_to_shwi(const_tree t) -{ - gcc_assert(tree_fits_shwi_p(t)); - return TREE_INT_CST_LOW(t); -} - -static inline unsigned HOST_WIDE_INT tree_to_uhwi(const_tree t) -{ - gcc_assert(tree_fits_uhwi_p(t)); - return TREE_INT_CST_LOW(t); -} - -static inline const char *get_tree_code_name(enum tree_code code) -{ - gcc_assert(code < MAX_TREE_CODES); - return tree_code_name[code]; -} - -#define ipa_remove_stmt_references(cnode, stmt) - -typedef union gimple_statement_d gasm; -typedef union gimple_statement_d gassign; -typedef union gimple_statement_d gcall; -typedef union gimple_statement_d gcond; -typedef union gimple_statement_d gdebug; -typedef union gimple_statement_d ggoto; -typedef union gimple_statement_d gphi; -typedef union gimple_statement_d greturn; - -static inline gasm *as_a_gasm(gimple stmt) -{ - return stmt; -} - -static inline const gasm *as_a_const_gasm(const_gimple stmt) -{ - return stmt; -} - -static inline gassign *as_a_gassign(gimple stmt) -{ - return stmt; -} - -static inline const gassign *as_a_const_gassign(const_gimple stmt) -{ - return stmt; -} - -static inline gcall *as_a_gcall(gimple stmt) -{ - return stmt; -} - -static inline const gcall *as_a_const_gcall(const_gimple stmt) -{ - return stmt; -} - -static inline gcond *as_a_gcond(gimple stmt) -{ - return stmt; -} - -static inline const gcond *as_a_const_gcond(const_gimple stmt) -{ - return stmt; -} - -static inline gdebug *as_a_gdebug(gimple stmt) -{ - return stmt; -} - -static inline const gdebug *as_a_const_gdebug(const_gimple stmt) -{ - return stmt; -} - -static inline ggoto *as_a_ggoto(gimple stmt) -{ - return stmt; -} - -static inline const ggoto *as_a_const_ggoto(const_gimple stmt) -{ - return stmt; -} - -static inline gphi *as_a_gphi(gimple stmt) -{ - return stmt; -} - -static inline const gphi *as_a_const_gphi(const_gimple stmt) -{ - return stmt; -} - -static inline greturn *as_a_greturn(gimple stmt) -{ - return stmt; -} - -static inline const greturn *as_a_const_greturn(const_gimple stmt) -{ - return stmt; -} -#endif - -#if BUILDING_GCC_VERSION == 4008 -#define NODE_SYMBOL(node) (&(node)->symbol) -#define NODE_DECL(node) (node)->symbol.decl -#endif - -#if BUILDING_GCC_VERSION >= 4008 -#define add_referenced_var(var) -#define mark_sym_for_renaming(var) -#define varpool_mark_needed_node(node) -#define create_var_ann(var) -#define TODO_dump_func 0 -#define TODO_dump_cgraph 0 -#endif - -#if BUILDING_GCC_VERSION <= 4009 -#define TODO_verify_il 0 -#define AVAIL_INTERPOSABLE AVAIL_OVERWRITABLE - -#define section_name_prefix LTO_SECTION_NAME_PREFIX -#define fatal_error(loc, gmsgid, ...) fatal_error((gmsgid), __VA_ARGS__) - -rtx emit_move_insn(rtx x, rtx y); - -typedef struct rtx_def rtx_insn; - -static inline const char *get_decl_section_name(const_tree decl) -{ - if (DECL_SECTION_NAME(decl) == NULL_TREE) - return NULL; - - return TREE_STRING_POINTER(DECL_SECTION_NAME(decl)); -} - -static inline void set_decl_section_name(tree node, const char *value) -{ - if (value) - DECL_SECTION_NAME(node) = build_string(strlen(value) + 1, value); - else - DECL_SECTION_NAME(node) = NULL; -} -#endif - -#if BUILDING_GCC_VERSION == 4009 -typedef struct gimple_statement_asm gasm; -typedef struct gimple_statement_base gassign; -typedef struct gimple_statement_call gcall; -typedef struct gimple_statement_base gcond; -typedef struct gimple_statement_base gdebug; -typedef struct gimple_statement_base ggoto; -typedef struct gimple_statement_phi gphi; -typedef struct gimple_statement_base greturn; - -static inline gasm *as_a_gasm(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gasm *as_a_const_gasm(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline gassign *as_a_gassign(gimple stmt) -{ - return stmt; -} - -static inline const gassign *as_a_const_gassign(const_gimple stmt) -{ - return stmt; -} - -static inline gcall *as_a_gcall(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gcall *as_a_const_gcall(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline gcond *as_a_gcond(gimple stmt) -{ - return stmt; -} - -static inline const gcond *as_a_const_gcond(const_gimple stmt) -{ - return stmt; -} - -static inline gdebug *as_a_gdebug(gimple stmt) -{ - return stmt; -} - -static inline const gdebug *as_a_const_gdebug(const_gimple stmt) -{ - return stmt; -} - -static inline ggoto *as_a_ggoto(gimple stmt) -{ - return stmt; -} - -static inline const ggoto *as_a_const_ggoto(const_gimple stmt) -{ - return stmt; -} - -static inline gphi *as_a_gphi(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gphi *as_a_const_gphi(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline greturn *as_a_greturn(gimple stmt) -{ - return stmt; -} - -static inline const greturn *as_a_const_greturn(const_gimple stmt) -{ - return stmt; -} -#endif - -#if BUILDING_GCC_VERSION >= 4009 -#define TODO_ggc_collect 0 -#define NODE_SYMBOL(node) (node) -#define NODE_DECL(node) (node)->decl -#define cgraph_node_name(node) (node)->name() -#define NODE_IMPLICIT_ALIAS(node) (node)->cpp_implicit_alias - -static inline opt_pass *get_pass_for_id(int id) -{ - return g->get_passes()->get_pass_for_id(id); -} -#endif - -#if BUILDING_GCC_VERSION >= 5000 && BUILDING_GCC_VERSION < 6000 -/* gimple related */ -template <> -template <> -inline bool is_a_helper::test(const_gimple gs) -{ - return gs->code == GIMPLE_ASSIGN; -} -#endif - -#if BUILDING_GCC_VERSION >= 5000 -#define TODO_verify_ssa TODO_verify_il -#define TODO_verify_flow TODO_verify_il -#define TODO_verify_stmts TODO_verify_il -#define TODO_verify_rtl_sharing TODO_verify_il - -#define INSN_DELETED_P(insn) (insn)->deleted() - -static inline const char *get_decl_section_name(const_tree decl) -{ - return DECL_SECTION_NAME(decl); -} - -/* symtab/cgraph related */ -#define debug_cgraph_node(node) (node)->debug() -#define cgraph_get_node(decl) cgraph_node::get(decl) -#define cgraph_get_create_node(decl) cgraph_node::get_create(decl) -#define cgraph_create_node(decl) cgraph_node::create(decl) -#define cgraph_n_nodes symtab->cgraph_count -#define cgraph_max_uid symtab->cgraph_max_uid -#define varpool_get_node(decl) varpool_node::get(decl) -#define dump_varpool_node(file, node) (node)->dump(file) - -#define cgraph_create_edge(caller, callee, call_stmt, count, freq, nest) \ - (caller)->create_edge((callee), (call_stmt), (count), (freq)) -#define cgraph_create_edge_including_clones(caller, callee, old_call_stmt, call_stmt, count, freq, nest, reason) \ - (caller)->create_edge_including_clones((callee), (old_call_stmt), (call_stmt), (count), (freq), (reason)) - -typedef struct cgraph_node *cgraph_node_ptr; -typedef struct cgraph_edge *cgraph_edge_p; -typedef struct varpool_node *varpool_node_ptr; - -static inline void change_decl_assembler_name(tree decl, tree name) -{ - symtab->change_decl_assembler_name(decl, name); -} - -static inline void varpool_finalize_decl(tree decl) -{ - varpool_node::finalize_decl(decl); -} - -static inline void varpool_add_new_variable(tree decl) -{ - varpool_node::add(decl); -} - -static inline unsigned int rebuild_cgraph_edges(void) -{ - return cgraph_edge::rebuild_edges(); -} - -static inline cgraph_node_ptr cgraph_function_node(cgraph_node_ptr node, enum availability *availability) -{ - return node->function_symbol(availability); -} - -static inline cgraph_node_ptr cgraph_function_or_thunk_node(cgraph_node_ptr node, enum availability *availability = NULL) -{ - return node->ultimate_alias_target(availability); -} - -static inline bool cgraph_only_called_directly_p(cgraph_node_ptr node) -{ - return node->only_called_directly_p(); -} - -static inline enum availability cgraph_function_body_availability(cgraph_node_ptr node) -{ - return node->get_availability(); -} - -static inline cgraph_node_ptr cgraph_alias_target(cgraph_node_ptr node) -{ - return node->get_alias_target(); -} - -static inline bool cgraph_for_node_and_aliases(cgraph_node_ptr node, bool (*callback)(cgraph_node_ptr, void *), void *data, bool include_overwritable) -{ - return node->call_for_symbol_thunks_and_aliases(callback, data, include_overwritable); -} - -static inline struct cgraph_node_hook_list *cgraph_add_function_insertion_hook(cgraph_node_hook hook, void *data) -{ - return symtab->add_cgraph_insertion_hook(hook, data); -} - -static inline void cgraph_remove_function_insertion_hook(struct cgraph_node_hook_list *entry) -{ - symtab->remove_cgraph_insertion_hook(entry); -} - -static inline struct cgraph_node_hook_list *cgraph_add_node_removal_hook(cgraph_node_hook hook, void *data) -{ - return symtab->add_cgraph_removal_hook(hook, data); -} - -static inline void cgraph_remove_node_removal_hook(struct cgraph_node_hook_list *entry) -{ - symtab->remove_cgraph_removal_hook(entry); -} - -static inline struct cgraph_2node_hook_list *cgraph_add_node_duplication_hook(cgraph_2node_hook hook, void *data) -{ - return symtab->add_cgraph_duplication_hook(hook, data); -} - -static inline void cgraph_remove_node_duplication_hook(struct cgraph_2node_hook_list *entry) -{ - symtab->remove_cgraph_duplication_hook(entry); -} - -static inline void cgraph_call_node_duplication_hooks(cgraph_node_ptr node, cgraph_node_ptr node2) -{ - symtab->call_cgraph_duplication_hooks(node, node2); -} - -static inline void cgraph_call_edge_duplication_hooks(cgraph_edge *cs1, cgraph_edge *cs2) -{ - symtab->call_edge_duplication_hooks(cs1, cs2); -} - -#if BUILDING_GCC_VERSION >= 6000 -typedef gimple *gimple_ptr; -typedef const gimple *const_gimple_ptr; -#define gimple gimple_ptr -#define const_gimple const_gimple_ptr -#undef CONST_CAST_GIMPLE -#define CONST_CAST_GIMPLE(X) CONST_CAST(gimple, (X)) -#endif - -/* gimple related */ -static inline gimple gimple_build_assign_with_ops(enum tree_code subcode, tree lhs, tree op1, tree op2 MEM_STAT_DECL) -{ - return gimple_build_assign(lhs, subcode, op1, op2 PASS_MEM_STAT); -} - -#if BUILDING_GCC_VERSION < 10000 -template <> -template <> -inline bool is_a_helper::test(const_gimple gs) -{ - return gs->code == GIMPLE_GOTO; -} - -template <> -template <> -inline bool is_a_helper::test(const_gimple gs) -{ - return gs->code == GIMPLE_RETURN; -} -#endif - -static inline gasm *as_a_gasm(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gasm *as_a_const_gasm(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline gassign *as_a_gassign(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gassign *as_a_const_gassign(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline gcall *as_a_gcall(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gcall *as_a_const_gcall(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline ggoto *as_a_ggoto(gimple stmt) -{ - return as_a(stmt); -} - -static inline const ggoto *as_a_const_ggoto(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline gphi *as_a_gphi(gimple stmt) -{ - return as_a(stmt); -} - -static inline const gphi *as_a_const_gphi(const_gimple stmt) -{ - return as_a(stmt); -} - -static inline greturn *as_a_greturn(gimple stmt) -{ - return as_a(stmt); -} - -static inline const greturn *as_a_const_greturn(const_gimple stmt) -{ - return as_a(stmt); -} - -/* IPA/LTO related */ -#define ipa_ref_list_referring_iterate(L, I, P) \ - (L)->referring.iterate((I), &(P)) -#define ipa_ref_list_reference_iterate(L, I, P) \ - (L)->reference.iterate((I), &(P)) - -static inline cgraph_node_ptr ipa_ref_referring_node(struct ipa_ref *ref) -{ - return dyn_cast(ref->referring); -} - -static inline void ipa_remove_stmt_references(symtab_node *referring_node, gimple stmt) -{ - referring_node->remove_stmt_references(stmt); -} -#endif - -#if BUILDING_GCC_VERSION < 6000 -#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \ - get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, pvolatilep, keep_aligning) -#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET(VOIDmode, (ARG0), (ARG1)) -#endif - -#if BUILDING_GCC_VERSION >= 6000 -#define gen_rtx_set(ARG0, ARG1) gen_rtx_SET((ARG0), (ARG1)) -#endif - -#ifdef __cplusplus -static inline void debug_tree(const_tree t) -{ - debug_tree(CONST_CAST_TREE(t)); -} - -static inline void debug_gimple_stmt(const_gimple s) -{ - debug_gimple_stmt(CONST_CAST_GIMPLE(s)); -} -#else -#define debug_tree(t) debug_tree(CONST_CAST_TREE(t)) -#define debug_gimple_stmt(s) debug_gimple_stmt(CONST_CAST_GIMPLE(s)) -#endif - -#if BUILDING_GCC_VERSION >= 7000 -#define get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep, keep_aligning) \ - get_inner_reference(exp, pbitsize, pbitpos, poffset, pmode, punsignedp, preversep, pvolatilep) -#endif - -#if BUILDING_GCC_VERSION < 7000 -#define SET_DECL_ALIGN(decl, align) DECL_ALIGN(decl) = (align) -#define SET_DECL_MODE(decl, mode) DECL_MODE(decl) = (mode) -#endif - -#endif diff --git a/kpatch-build/gcc-plugins/gcc-generate-rtl-pass.h b/kpatch-build/gcc-plugins/gcc-generate-rtl-pass.h deleted file mode 100644 index d69cd80..0000000 --- a/kpatch-build/gcc-plugins/gcc-generate-rtl-pass.h +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Generator for RTL pass related boilerplate code/data - * - * Supports gcc 4.5-6 - * - * Usage: - * - * 1. before inclusion define PASS_NAME - * 2. before inclusion define NO_* for unimplemented callbacks - * NO_GATE - * NO_EXECUTE - * 3. before inclusion define PROPERTIES_* and TODO_FLAGS_* to override - * the default 0 values - * 4. for convenience, all the above will be undefined after inclusion! - * 5. the only exported name is make_PASS_NAME_pass() to register with gcc - */ - -#ifndef PASS_NAME -#error at least PASS_NAME must be defined -#else -#define __GCC_PLUGIN_STRINGIFY(n) #n -#define _GCC_PLUGIN_STRINGIFY(n) __GCC_PLUGIN_STRINGIFY(n) -#define _GCC_PLUGIN_CONCAT2(x, y) x ## y -#define _GCC_PLUGIN_CONCAT3(x, y, z) x ## y ## z - -#define __PASS_NAME_PASS_DATA(n) _GCC_PLUGIN_CONCAT2(n, _pass_data) -#define _PASS_NAME_PASS_DATA __PASS_NAME_PASS_DATA(PASS_NAME) - -#define __PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT2(n, _pass) -#define _PASS_NAME_PASS __PASS_NAME_PASS(PASS_NAME) - -#define _PASS_NAME_NAME _GCC_PLUGIN_STRINGIFY(PASS_NAME) - -#define __MAKE_PASS_NAME_PASS(n) _GCC_PLUGIN_CONCAT3(make_, n, _pass) -#define _MAKE_PASS_NAME_PASS __MAKE_PASS_NAME_PASS(PASS_NAME) - -#ifdef NO_GATE -#define _GATE NULL -#define _HAS_GATE false -#else -#define __GATE(n) _GCC_PLUGIN_CONCAT2(n, _gate) -#define _GATE __GATE(PASS_NAME) -#define _HAS_GATE true -#endif - -#ifdef NO_EXECUTE -#define _EXECUTE NULL -#define _HAS_EXECUTE false -#else -#define __EXECUTE(n) _GCC_PLUGIN_CONCAT2(n, _execute) -#define _EXECUTE __EXECUTE(PASS_NAME) -#define _HAS_EXECUTE true -#endif - -#ifndef PROPERTIES_REQUIRED -#define PROPERTIES_REQUIRED 0 -#endif - -#ifndef PROPERTIES_PROVIDED -#define PROPERTIES_PROVIDED 0 -#endif - -#ifndef PROPERTIES_DESTROYED -#define PROPERTIES_DESTROYED 0 -#endif - -#ifndef TODO_FLAGS_START -#define TODO_FLAGS_START 0 -#endif - -#ifndef TODO_FLAGS_FINISH -#define TODO_FLAGS_FINISH 0 -#endif - -#if BUILDING_GCC_VERSION >= 4009 -namespace { -static const pass_data _PASS_NAME_PASS_DATA = { -#else -static struct rtl_opt_pass _PASS_NAME_PASS = { - .pass = { -#endif - .type = RTL_PASS, - .name = _PASS_NAME_NAME, -#if BUILDING_GCC_VERSION >= 4008 - .optinfo_flags = OPTGROUP_NONE, -#endif -#if BUILDING_GCC_VERSION >= 5000 -#elif BUILDING_GCC_VERSION == 4009 - .has_gate = _HAS_GATE, - .has_execute = _HAS_EXECUTE, -#else - .gate = _GATE, - .execute = _EXECUTE, - .sub = NULL, - .next = NULL, - .static_pass_number = 0, -#endif - .tv_id = TV_NONE, - .properties_required = PROPERTIES_REQUIRED, - .properties_provided = PROPERTIES_PROVIDED, - .properties_destroyed = PROPERTIES_DESTROYED, - .todo_flags_start = TODO_FLAGS_START, - .todo_flags_finish = TODO_FLAGS_FINISH, -#if BUILDING_GCC_VERSION < 4009 - } -#endif -}; - -#if BUILDING_GCC_VERSION >= 4009 -class _PASS_NAME_PASS : public rtl_opt_pass { -public: - _PASS_NAME_PASS() : rtl_opt_pass(_PASS_NAME_PASS_DATA, g) {} - -#ifndef NO_GATE -#if BUILDING_GCC_VERSION >= 5000 - virtual bool gate(function *) { return _GATE(); } -#else - virtual bool gate(void) { return _GATE(); } -#endif -#endif - - virtual opt_pass *clone() { return new _PASS_NAME_PASS(); } - -#ifndef NO_EXECUTE -#if BUILDING_GCC_VERSION >= 5000 - virtual unsigned int execute(function *) { return _EXECUTE(); } -#else - virtual unsigned int execute(void) { return _EXECUTE(); } -#endif -#endif -}; -} - -opt_pass *_MAKE_PASS_NAME_PASS(void) -{ - return new _PASS_NAME_PASS(); -} -#else -struct opt_pass *_MAKE_PASS_NAME_PASS(void) -{ - return &_PASS_NAME_PASS.pass; -} -#endif - -/* clean up user provided defines */ -#undef PASS_NAME -#undef NO_GATE -#undef NO_EXECUTE - -#undef PROPERTIES_DESTROYED -#undef PROPERTIES_PROVIDED -#undef PROPERTIES_REQUIRED -#undef TODO_FLAGS_FINISH -#undef TODO_FLAGS_START - -/* clean up generated defines */ -#undef _EXECUTE -#undef __EXECUTE -#undef _GATE -#undef __GATE -#undef _GCC_PLUGIN_CONCAT2 -#undef _GCC_PLUGIN_CONCAT3 -#undef _GCC_PLUGIN_STRINGIFY -#undef __GCC_PLUGIN_STRINGIFY -#undef _HAS_EXECUTE -#undef _HAS_GATE -#undef _MAKE_PASS_NAME_PASS -#undef __MAKE_PASS_NAME_PASS -#undef _PASS_NAME_NAME -#undef _PASS_NAME_PASS -#undef __PASS_NAME_PASS -#undef _PASS_NAME_PASS_DATA -#undef __PASS_NAME_PASS_DATA - -#endif /* PASS_NAME */ diff --git a/kpatch-build/gcc-plugins/ppc64le-plugin.c b/kpatch-build/gcc-plugins/ppc64le-plugin.c deleted file mode 100644 index ba4a01e..0000000 --- a/kpatch-build/gcc-plugins/ppc64le-plugin.c +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include "gcc-common.h" - -#define PLUGIN_NAME "ppc64le-plugin" - -#if BUILDING_GCC_VERSION < 10000 -#define CALL_LOCAL "*call_local_aixdi" -#define CALL_NONLOCAL "*call_nonlocal_aixdi" -#define CALL_VALUE_LOCAL "*call_value_local_aixdi" -#define CALL_VALUE_NONLOCAL "*call_value_nonlocal_aixdi" -#else -#define CALL_LOCAL "*call_localdi" -#define CALL_NONLOCAL "*call_nonlocal_aixdi" -#define CALL_VALUE_LOCAL "*call_value_localdi" -#define CALL_VALUE_NONLOCAL "*call_value_nonlocal_aixdi" -#endif - -int plugin_is_GPL_compatible; - -struct plugin_info plugin_info = { - .version = "1", - .help = PLUGIN_NAME ": insert nops after local calls\n", -}; - -static unsigned int ppc64le_plugin_execute(void) -{ - rtx_insn *insn; - int code; - const char *name; - static int nonlocal_code = -1, local_code = -1, - value_nonlocal_code = -1, value_local_code = -1; - static bool initialized = false; - - if (initialized) - goto found; - - /* Find the rs6000.md code numbers for local and non-local calls */ - initialized = true; - for (code = 0; code < 1000; code++) { - name = get_insn_name(code); - if (!name) - continue; - - if (!strcmp(name , CALL_LOCAL)) - local_code = code; - else if (!strcmp(name , CALL_NONLOCAL)) - nonlocal_code = code; - else if (!strcmp(name, CALL_VALUE_LOCAL)) - value_local_code = code; - else if (!strcmp(name, CALL_VALUE_NONLOCAL)) - value_nonlocal_code = code; - - if (nonlocal_code != -1 && local_code != -1 && - value_nonlocal_code != -1 && value_local_code != -1) - goto found; - } - -found: - if (nonlocal_code == -1 || local_code == -1 || - value_nonlocal_code == -1 || value_local_code == -1) { - error("%s: cannot find call instruction codes", PLUGIN_NAME); - } - - /* Convert local calls to non-local */ - for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) { - if (GET_CODE(insn) == CALL_INSN) { - if (INSN_CODE(insn) == local_code) - INSN_CODE(insn) = nonlocal_code; - else if (INSN_CODE(insn) == value_local_code) - INSN_CODE(insn) = value_nonlocal_code; - } - } - - return 0; -} - -#define PASS_NAME ppc64le_plugin -#define NO_GATE -#include "gcc-generate-rtl-pass.h" - -int plugin_init(struct plugin_name_args *plugin_info, - struct plugin_gcc_version *version) -{ - const char * const plugin_name = plugin_info->base_name; - - PASS_INFO(ppc64le_plugin, "vregs", 1, PASS_POS_INSERT_AFTER); - - if (!plugin_default_version_check(version, &gcc_version)) - error(1, 0, PLUGIN_NAME ": incompatible gcc/plugin versions"); - - register_callback(plugin_name, PLUGIN_INFO, NULL, &plugin_info); - register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, - &ppc64le_plugin_pass_info); - - return 0; -} - diff --git a/kpatch-build/insn/asm/inat.h b/kpatch-build/insn/asm/inat.h deleted file mode 100644 index 74a2e31..0000000 --- a/kpatch-build/insn/asm/inat.h +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef _ASM_X86_INAT_H -#define _ASM_X86_INAT_H -/* - * x86 instruction attributes - * - * Written by Masami Hiramatsu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#include - -/* - * Internal bits. Don't use bitmasks directly, because these bits are - * unstable. You should use checking functions. - */ - -#define INAT_OPCODE_TABLE_SIZE 256 -#define INAT_GROUP_TABLE_SIZE 8 - -/* Legacy last prefixes */ -#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ -#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ -#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ -/* Other Legacy prefixes */ -#define INAT_PFX_LOCK 4 /* 0xF0 */ -#define INAT_PFX_CS 5 /* 0x2E */ -#define INAT_PFX_DS 6 /* 0x3E */ -#define INAT_PFX_ES 7 /* 0x26 */ -#define INAT_PFX_FS 8 /* 0x64 */ -#define INAT_PFX_GS 9 /* 0x65 */ -#define INAT_PFX_SS 10 /* 0x36 */ -#define INAT_PFX_ADDRSZ 11 /* 0x67 */ -/* x86-64 REX prefix */ -#define INAT_PFX_REX 12 /* 0x4X */ -/* AVX VEX prefixes */ -#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ -#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ - -#define INAT_LSTPFX_MAX 3 -#define INAT_LGCPFX_MAX 11 - -/* Immediate size */ -#define INAT_IMM_BYTE 1 -#define INAT_IMM_WORD 2 -#define INAT_IMM_DWORD 3 -#define INAT_IMM_QWORD 4 -#define INAT_IMM_PTR 5 -#define INAT_IMM_VWORD32 6 -#define INAT_IMM_VWORD 7 - -/* Legacy prefix */ -#define INAT_PFX_OFFS 0 -#define INAT_PFX_BITS 4 -#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) -#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) -/* Escape opcodes */ -#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) -#define INAT_ESC_BITS 2 -#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) -#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) -/* Group opcodes (1-16) */ -#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) -#define INAT_GRP_BITS 5 -#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) -#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) -/* Immediates */ -#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) -#define INAT_IMM_BITS 3 -#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) -/* Flags */ -#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) -#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) -#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) -#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) -#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) -#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) -#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) -#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) -/* Attribute making macros for attribute tables */ -#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) -#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) -#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) -#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) - -/* Attribute search APIs */ -extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); -extern int inat_get_last_prefix_id(insn_byte_t last_pfx); -extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, - int lpfx_id, - insn_attr_t esc_attr); -extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, - int lpfx_id, - insn_attr_t esc_attr); -extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, - insn_byte_t vex_m, - insn_byte_t vex_pp); - -/* Attribute checking functions */ -static inline int inat_is_legacy_prefix(insn_attr_t attr) -{ - attr &= INAT_PFX_MASK; - return attr && attr <= INAT_LGCPFX_MAX; -} - -static inline int inat_is_address_size_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; -} - -static inline int inat_is_operand_size_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; -} - -static inline int inat_is_rex_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_REX; -} - -static inline int inat_last_prefix_id(insn_attr_t attr) -{ - if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) - return 0; - else - return attr & INAT_PFX_MASK; -} - -static inline int inat_is_vex_prefix(insn_attr_t attr) -{ - attr &= INAT_PFX_MASK; - return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3; -} - -static inline int inat_is_vex3_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; -} - -static inline int inat_is_escape(insn_attr_t attr) -{ - return attr & INAT_ESC_MASK; -} - -static inline int inat_escape_id(insn_attr_t attr) -{ - return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; -} - -static inline int inat_is_group(insn_attr_t attr) -{ - return attr & INAT_GRP_MASK; -} - -static inline int inat_group_id(insn_attr_t attr) -{ - return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; -} - -static inline int inat_group_common_attribute(insn_attr_t attr) -{ - return attr & ~INAT_GRP_MASK; -} - -static inline int inat_has_immediate(insn_attr_t attr) -{ - return attr & INAT_IMM_MASK; -} - -static inline int inat_immediate_size(insn_attr_t attr) -{ - return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; -} - -static inline int inat_has_modrm(insn_attr_t attr) -{ - return attr & INAT_MODRM; -} - -static inline int inat_is_force64(insn_attr_t attr) -{ - return attr & INAT_FORCE64; -} - -static inline int inat_has_second_immediate(insn_attr_t attr) -{ - return attr & INAT_SCNDIMM; -} - -static inline int inat_has_moffset(insn_attr_t attr) -{ - return attr & INAT_MOFFSET; -} - -static inline int inat_has_variant(insn_attr_t attr) -{ - return attr & INAT_VARIANT; -} - -static inline int inat_accept_vex(insn_attr_t attr) -{ - return attr & INAT_VEXOK; -} - -static inline int inat_must_vex(insn_attr_t attr) -{ - return attr & INAT_VEXONLY; -} -#endif diff --git a/kpatch-build/insn/asm/inat_types.h b/kpatch-build/insn/asm/inat_types.h deleted file mode 100644 index cb3c20c..0000000 --- a/kpatch-build/insn/asm/inat_types.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _ASM_X86_INAT_TYPES_H -#define _ASM_X86_INAT_TYPES_H -/* - * x86 instruction attributes - * - * Written by Masami Hiramatsu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* Instruction attributes */ -typedef unsigned int insn_attr_t; -typedef unsigned char insn_byte_t; -typedef signed int insn_value_t; - -#endif diff --git a/kpatch-build/insn/asm/insn.h b/kpatch-build/insn/asm/insn.h deleted file mode 100644 index 48eb30a..0000000 --- a/kpatch-build/insn/asm/insn.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef _ASM_X86_INSN_H -#define _ASM_X86_INSN_H -/* - * x86 instruction analysis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2009 - */ - -/* insn_attr_t is defined in inat.h */ -#include - -struct insn_field { - union { - insn_value_t value; - insn_byte_t bytes[4]; - }; - /* !0 if we've run insn_get_xxx() for this field */ - unsigned char got; - unsigned char nbytes; -}; - -struct insn { - struct insn_field prefixes; /* - * Prefixes - * prefixes.bytes[3]: last prefix - */ - struct insn_field rex_prefix; /* REX prefix */ - struct insn_field vex_prefix; /* VEX prefix */ - struct insn_field opcode; /* - * opcode.bytes[0]: opcode1 - * opcode.bytes[1]: opcode2 - * opcode.bytes[2]: opcode3 - */ - struct insn_field modrm; - struct insn_field sib; - struct insn_field displacement; - union { - struct insn_field immediate; - struct insn_field moffset1; /* for 64bit MOV */ - struct insn_field immediate1; /* for 64bit imm or off16/32 */ - }; - union { - struct insn_field moffset2; /* for 64bit MOV */ - struct insn_field immediate2; /* for 64bit imm or seg16 */ - }; - - insn_attr_t attr; - unsigned char opnd_bytes; - unsigned char addr_bytes; - unsigned char length; - unsigned char x86_64; - - const insn_byte_t *kaddr; /* kernel address of insn to analyze */ - const insn_byte_t *next_byte; -}; - -#define MAX_INSN_SIZE 16 - -#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) -#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) -#define X86_MODRM_RM(modrm) ((modrm) & 0x07) - -#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) -#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) -#define X86_SIB_BASE(sib) ((sib) & 0x07) - -#define X86_REX_W(rex) ((rex) & 8) -#define X86_REX_R(rex) ((rex) & 4) -#define X86_REX_X(rex) ((rex) & 2) -#define X86_REX_B(rex) ((rex) & 1) - -/* VEX bit flags */ -#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ -#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ -#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ -#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ -#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ -/* VEX bit fields */ -#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ -#define X86_VEX2_M 1 /* VEX2.M always 1 */ -#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ -#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ -#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ - -extern void insn_init(struct insn *insn, const void *kaddr, int x86_64); -extern void insn_get_prefixes(struct insn *insn); -extern void insn_get_opcode(struct insn *insn); -extern void insn_get_modrm(struct insn *insn); -extern void insn_get_sib(struct insn *insn); -extern void insn_get_displacement(struct insn *insn); -extern void insn_get_immediate(struct insn *insn); -extern void insn_get_length(struct insn *insn); - -/* Attribute will be determined after getting ModRM (for opcode groups) */ -static inline void insn_get_attribute(struct insn *insn) -{ - insn_get_modrm(insn); -} - -/* Instruction uses RIP-relative addressing */ -extern int insn_rip_relative(struct insn *insn); - -/* Init insn for kernel text */ -static inline void kernel_insn_init(struct insn *insn, const void *kaddr) -{ -#ifdef CONFIG_X86_64 - insn_init(insn, kaddr, 1); -#else /* CONFIG_X86_32 */ - insn_init(insn, kaddr, 0); -#endif -} - -static inline int insn_is_avx(struct insn *insn) -{ - if (!insn->prefixes.got) - insn_get_prefixes(insn); - return (insn->vex_prefix.value != 0); -} - -/* Ensure this instruction is decoded completely */ -static inline int insn_complete(struct insn *insn) -{ - return insn->opcode.got && insn->modrm.got && insn->sib.got && - insn->displacement.got && insn->immediate.got; -} - -static inline insn_byte_t insn_vex_m_bits(struct insn *insn) -{ - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ - return X86_VEX2_M; - else - return X86_VEX3_M(insn->vex_prefix.bytes[1]); -} - -static inline insn_byte_t insn_vex_p_bits(struct insn *insn) -{ - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ - return X86_VEX_P(insn->vex_prefix.bytes[1]); - else - return X86_VEX_P(insn->vex_prefix.bytes[2]); -} - -/* Get the last prefix id from last prefix or VEX prefix */ -static inline int insn_last_prefix_id(struct insn *insn) -{ - if (insn_is_avx(insn)) - return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ - - if (insn->prefixes.bytes[3]) - return inat_get_last_prefix_id(insn->prefixes.bytes[3]); - - return 0; -} - -/* Offset of each field from kaddr */ -static inline int insn_offset_rex_prefix(struct insn *insn) -{ - return insn->prefixes.nbytes; -} -static inline int insn_offset_vex_prefix(struct insn *insn) -{ - return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; -} -static inline int insn_offset_opcode(struct insn *insn) -{ - return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; -} -static inline int insn_offset_modrm(struct insn *insn) -{ - return insn_offset_opcode(insn) + insn->opcode.nbytes; -} -static inline int insn_offset_sib(struct insn *insn) -{ - return insn_offset_modrm(insn) + insn->modrm.nbytes; -} -static inline int insn_offset_displacement(struct insn *insn) -{ - return insn_offset_sib(insn) + insn->sib.nbytes; -} -static inline int insn_offset_immediate(struct insn *insn) -{ - return insn_offset_displacement(insn) + insn->displacement.nbytes; -} - -#endif /* _ASM_X86_INSN_H */ diff --git a/kpatch-build/insn/inat-tables.c b/kpatch-build/insn/inat-tables.c deleted file mode 100644 index 10de26c..0000000 --- a/kpatch-build/insn/inat-tables.c +++ /dev/null @@ -1,1146 +0,0 @@ -/* x86 opcode map generated from x86-opcode-map.txt */ -/* Do not change this code. */ - -/* Table: one byte opcode */ -const insn_attr_t inat_primary_table[INAT_OPCODE_TABLE_SIZE] = { - [0x00] = INAT_MODRM, - [0x01] = INAT_MODRM, - [0x02] = INAT_MODRM, - [0x03] = INAT_MODRM, - [0x04] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x05] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x08] = INAT_MODRM, - [0x09] = INAT_MODRM, - [0x0a] = INAT_MODRM, - [0x0b] = INAT_MODRM, - [0x0c] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x0d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x0f] = INAT_MAKE_ESCAPE(1), - [0x10] = INAT_MODRM, - [0x11] = INAT_MODRM, - [0x12] = INAT_MODRM, - [0x13] = INAT_MODRM, - [0x14] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x15] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x18] = INAT_MODRM, - [0x19] = INAT_MODRM, - [0x1a] = INAT_MODRM, - [0x1b] = INAT_MODRM, - [0x1c] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x1d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x20] = INAT_MODRM, - [0x21] = INAT_MODRM, - [0x22] = INAT_MODRM, - [0x23] = INAT_MODRM, - [0x24] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x25] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x26] = INAT_MAKE_PREFIX(INAT_PFX_ES), - [0x28] = INAT_MODRM, - [0x29] = INAT_MODRM, - [0x2a] = INAT_MODRM, - [0x2b] = INAT_MODRM, - [0x2c] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x2d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x2e] = INAT_MAKE_PREFIX(INAT_PFX_CS), - [0x30] = INAT_MODRM, - [0x31] = INAT_MODRM, - [0x32] = INAT_MODRM, - [0x33] = INAT_MODRM, - [0x34] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x35] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x36] = INAT_MAKE_PREFIX(INAT_PFX_SS), - [0x38] = INAT_MODRM, - [0x39] = INAT_MODRM, - [0x3a] = INAT_MODRM, - [0x3b] = INAT_MODRM, - [0x3c] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x3d] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0x3e] = INAT_MAKE_PREFIX(INAT_PFX_DS), - [0x40] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x41] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x42] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x43] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x44] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x45] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x46] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x47] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x48] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x49] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x4a] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x4b] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x4c] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x4d] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x4e] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x4f] = INAT_MAKE_PREFIX(INAT_PFX_REX), - [0x50] = INAT_FORCE64, - [0x51] = INAT_FORCE64, - [0x52] = INAT_FORCE64, - [0x53] = INAT_FORCE64, - [0x54] = INAT_FORCE64, - [0x55] = INAT_FORCE64, - [0x56] = INAT_FORCE64, - [0x57] = INAT_FORCE64, - [0x58] = INAT_FORCE64, - [0x59] = INAT_FORCE64, - [0x5a] = INAT_FORCE64, - [0x5b] = INAT_FORCE64, - [0x5c] = INAT_FORCE64, - [0x5d] = INAT_FORCE64, - [0x5e] = INAT_FORCE64, - [0x5f] = INAT_FORCE64, - [0x62] = INAT_MODRM, - [0x63] = INAT_MODRM | INAT_MODRM, - [0x64] = INAT_MAKE_PREFIX(INAT_PFX_FS), - [0x65] = INAT_MAKE_PREFIX(INAT_PFX_GS), - [0x66] = INAT_MAKE_PREFIX(INAT_PFX_OPNDSZ), - [0x67] = INAT_MAKE_PREFIX(INAT_PFX_ADDRSZ), - [0x68] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x69] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, - [0x6a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, - [0x6b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, - [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x71] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x72] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x73] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x74] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x75] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x76] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x77] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x78] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x79] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x7a] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x7b] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x7c] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x7d] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x7e] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x7f] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0x80] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), - [0x81] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM | INAT_MAKE_GROUP(1), - [0x82] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), - [0x83] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(1), - [0x84] = INAT_MODRM, - [0x85] = INAT_MODRM, - [0x86] = INAT_MODRM, - [0x87] = INAT_MODRM, - [0x88] = INAT_MODRM, - [0x89] = INAT_MODRM, - [0x8a] = INAT_MODRM, - [0x8b] = INAT_MODRM, - [0x8c] = INAT_MODRM, - [0x8d] = INAT_MODRM, - [0x8e] = INAT_MODRM, - [0x8f] = INAT_MAKE_GROUP(2) | INAT_MODRM | INAT_FORCE64, - [0x9a] = INAT_MAKE_IMM(INAT_IMM_PTR), - [0x9c] = INAT_FORCE64, - [0x9d] = INAT_FORCE64, - [0xa0] = INAT_MOFFSET, - [0xa1] = INAT_MOFFSET, - [0xa2] = INAT_MOFFSET, - [0xa3] = INAT_MOFFSET, - [0xa8] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xa9] = INAT_MAKE_IMM(INAT_IMM_VWORD32), - [0xb0] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb1] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb2] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb3] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb4] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb5] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb6] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb7] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xb8] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xb9] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xba] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xbb] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xbc] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xbd] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xbe] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xbf] = INAT_MAKE_IMM(INAT_IMM_VWORD), - [0xc0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(3), - [0xc1] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(3), - [0xc2] = INAT_MAKE_IMM(INAT_IMM_WORD) | INAT_FORCE64, - [0xc4] = INAT_MODRM | INAT_MAKE_PREFIX(INAT_PFX_VEX3), - [0xc5] = INAT_MODRM | INAT_MAKE_PREFIX(INAT_PFX_VEX2), - [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(4), - [0xc7] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM | INAT_MAKE_GROUP(5), - [0xc8] = INAT_MAKE_IMM(INAT_IMM_WORD) | INAT_SCNDIMM, - [0xc9] = INAT_FORCE64, - [0xca] = INAT_MAKE_IMM(INAT_IMM_WORD), - [0xcd] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xd0] = INAT_MODRM | INAT_MAKE_GROUP(3), - [0xd1] = INAT_MODRM | INAT_MAKE_GROUP(3), - [0xd2] = INAT_MODRM | INAT_MAKE_GROUP(3), - [0xd3] = INAT_MODRM | INAT_MAKE_GROUP(3), - [0xd4] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xd5] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xd8] = INAT_MODRM, - [0xd9] = INAT_MODRM, - [0xda] = INAT_MODRM, - [0xdb] = INAT_MODRM, - [0xdc] = INAT_MODRM, - [0xdd] = INAT_MODRM, - [0xde] = INAT_MODRM, - [0xdf] = INAT_MODRM, - [0xe0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, - [0xe1] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, - [0xe2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, - [0xe3] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, - [0xe4] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xe5] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xe6] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xe7] = INAT_MAKE_IMM(INAT_IMM_BYTE), - [0xe8] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0xe9] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0xea] = INAT_MAKE_IMM(INAT_IMM_PTR), - [0xeb] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_FORCE64, - [0xf0] = INAT_MAKE_PREFIX(INAT_PFX_LOCK), - [0xf2] = INAT_MAKE_PREFIX(INAT_PFX_REPNE) | INAT_MAKE_PREFIX(INAT_PFX_REPNE), - [0xf3] = INAT_MAKE_PREFIX(INAT_PFX_REPE) | INAT_MAKE_PREFIX(INAT_PFX_REPE), - [0xf6] = INAT_MODRM | INAT_MAKE_GROUP(6), - [0xf7] = INAT_MODRM | INAT_MAKE_GROUP(7), - [0xfe] = INAT_MAKE_GROUP(8), - [0xff] = INAT_MAKE_GROUP(9), -}; - -/* Table: 2-byte opcode (0x0f) */ -const insn_attr_t inat_escape_table_1[INAT_OPCODE_TABLE_SIZE] = { - [0x00] = INAT_MAKE_GROUP(10), - [0x01] = INAT_MAKE_GROUP(11), - [0x02] = INAT_MODRM, - [0x03] = INAT_MODRM, - [0x0d] = INAT_MAKE_GROUP(12), - [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, - [0x10] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x11] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x12] = INAT_MODRM | INAT_VEXOK | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x13] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x14] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x15] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x16] = INAT_MODRM | INAT_VEXOK | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x17] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x18] = INAT_MAKE_GROUP(13), - [0x1a] = INAT_MODRM | INAT_MODRM | INAT_MODRM | INAT_MODRM, - [0x1b] = INAT_MODRM | INAT_MODRM | INAT_MODRM | INAT_MODRM, - [0x1f] = INAT_MODRM, - [0x20] = INAT_MODRM, - [0x21] = INAT_MODRM, - [0x22] = INAT_MODRM, - [0x23] = INAT_MODRM, - [0x28] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x29] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x2a] = INAT_MODRM | INAT_VARIANT, - [0x2b] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x2c] = INAT_MODRM | INAT_VARIANT, - [0x2d] = INAT_MODRM | INAT_VARIANT, - [0x2e] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x2f] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x38] = INAT_MAKE_ESCAPE(2), - [0x3a] = INAT_MAKE_ESCAPE(3), - [0x40] = INAT_MODRM, - [0x41] = INAT_MODRM, - [0x42] = INAT_MODRM, - [0x43] = INAT_MODRM, - [0x44] = INAT_MODRM, - [0x45] = INAT_MODRM, - [0x46] = INAT_MODRM, - [0x47] = INAT_MODRM, - [0x48] = INAT_MODRM, - [0x49] = INAT_MODRM, - [0x4a] = INAT_MODRM, - [0x4b] = INAT_MODRM, - [0x4c] = INAT_MODRM, - [0x4d] = INAT_MODRM, - [0x4e] = INAT_MODRM, - [0x4f] = INAT_MODRM, - [0x50] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x51] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x52] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x53] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x54] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x55] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x56] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x57] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x58] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x59] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x5a] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x5b] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x5c] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x5d] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x5e] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x5f] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x60] = INAT_MODRM | INAT_VARIANT, - [0x61] = INAT_MODRM | INAT_VARIANT, - [0x62] = INAT_MODRM | INAT_VARIANT, - [0x63] = INAT_MODRM | INAT_VARIANT, - [0x64] = INAT_MODRM | INAT_VARIANT, - [0x65] = INAT_MODRM | INAT_VARIANT, - [0x66] = INAT_MODRM | INAT_VARIANT, - [0x67] = INAT_MODRM | INAT_VARIANT, - [0x68] = INAT_MODRM | INAT_VARIANT, - [0x69] = INAT_MODRM | INAT_VARIANT, - [0x6a] = INAT_MODRM | INAT_VARIANT, - [0x6b] = INAT_MODRM | INAT_VARIANT, - [0x6c] = INAT_VARIANT, - [0x6d] = INAT_VARIANT, - [0x6e] = INAT_MODRM | INAT_VARIANT, - [0x6f] = INAT_MODRM | INAT_VARIANT, - [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x71] = INAT_MAKE_GROUP(14), - [0x72] = INAT_MAKE_GROUP(15), - [0x73] = INAT_MAKE_GROUP(16), - [0x74] = INAT_MODRM | INAT_VARIANT, - [0x75] = INAT_MODRM | INAT_VARIANT, - [0x76] = INAT_MODRM | INAT_VARIANT, - [0x77] = INAT_VEXOK | INAT_VEXOK, - [0x78] = INAT_MODRM, - [0x79] = INAT_MODRM, - [0x7c] = INAT_VARIANT, - [0x7d] = INAT_VARIANT, - [0x7e] = INAT_MODRM | INAT_VARIANT, - [0x7f] = INAT_MODRM | INAT_VARIANT, - [0x80] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x81] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x82] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x83] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x84] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x85] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x86] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x87] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x88] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x89] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x8a] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x8b] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x8c] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x8d] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x8e] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x8f] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_FORCE64, - [0x90] = INAT_MODRM, - [0x91] = INAT_MODRM, - [0x92] = INAT_MODRM, - [0x93] = INAT_MODRM, - [0x94] = INAT_MODRM, - [0x95] = INAT_MODRM, - [0x96] = INAT_MODRM, - [0x97] = INAT_MODRM, - [0x98] = INAT_MODRM, - [0x99] = INAT_MODRM, - [0x9a] = INAT_MODRM, - [0x9b] = INAT_MODRM, - [0x9c] = INAT_MODRM, - [0x9d] = INAT_MODRM, - [0x9e] = INAT_MODRM, - [0x9f] = INAT_MODRM, - [0xa0] = INAT_FORCE64, - [0xa1] = INAT_FORCE64, - [0xa3] = INAT_MODRM, - [0xa4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, - [0xa5] = INAT_MODRM, - [0xa6] = INAT_MAKE_GROUP(17), - [0xa7] = INAT_MAKE_GROUP(18), - [0xa8] = INAT_FORCE64, - [0xa9] = INAT_FORCE64, - [0xab] = INAT_MODRM, - [0xac] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, - [0xad] = INAT_MODRM, - [0xae] = INAT_MAKE_GROUP(19), - [0xaf] = INAT_MODRM, - [0xb0] = INAT_MODRM, - [0xb1] = INAT_MODRM, - [0xb2] = INAT_MODRM, - [0xb3] = INAT_MODRM, - [0xb4] = INAT_MODRM, - [0xb5] = INAT_MODRM, - [0xb6] = INAT_MODRM, - [0xb7] = INAT_MODRM, - [0xb8] = INAT_VARIANT, - [0xb9] = INAT_MAKE_GROUP(20), - [0xba] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_MAKE_GROUP(21), - [0xbb] = INAT_MODRM, - [0xbc] = INAT_MODRM | INAT_VARIANT, - [0xbd] = INAT_MODRM | INAT_VARIANT, - [0xbe] = INAT_MODRM, - [0xbf] = INAT_MODRM, - [0xc0] = INAT_MODRM, - [0xc1] = INAT_MODRM, - [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0xc3] = INAT_MODRM, - [0xc4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0xc5] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0xc7] = INAT_MAKE_GROUP(22), - [0xd0] = INAT_VARIANT, - [0xd1] = INAT_MODRM | INAT_VARIANT, - [0xd2] = INAT_MODRM | INAT_VARIANT, - [0xd3] = INAT_MODRM | INAT_VARIANT, - [0xd4] = INAT_MODRM | INAT_VARIANT, - [0xd5] = INAT_MODRM | INAT_VARIANT, - [0xd6] = INAT_VARIANT, - [0xd7] = INAT_MODRM | INAT_VARIANT, - [0xd8] = INAT_MODRM | INAT_VARIANT, - [0xd9] = INAT_MODRM | INAT_VARIANT, - [0xda] = INAT_MODRM | INAT_VARIANT, - [0xdb] = INAT_MODRM | INAT_VARIANT, - [0xdc] = INAT_MODRM | INAT_VARIANT, - [0xdd] = INAT_MODRM | INAT_VARIANT, - [0xde] = INAT_MODRM | INAT_VARIANT, - [0xdf] = INAT_MODRM | INAT_VARIANT, - [0xe0] = INAT_MODRM | INAT_VARIANT, - [0xe1] = INAT_MODRM | INAT_VARIANT, - [0xe2] = INAT_MODRM | INAT_VARIANT, - [0xe3] = INAT_MODRM | INAT_VARIANT, - [0xe4] = INAT_MODRM | INAT_VARIANT, - [0xe5] = INAT_MODRM | INAT_VARIANT, - [0xe6] = INAT_VARIANT, - [0xe7] = INAT_MODRM | INAT_VARIANT, - [0xe8] = INAT_MODRM | INAT_VARIANT, - [0xe9] = INAT_MODRM | INAT_VARIANT, - [0xea] = INAT_MODRM | INAT_VARIANT, - [0xeb] = INAT_MODRM | INAT_VARIANT, - [0xec] = INAT_MODRM | INAT_VARIANT, - [0xed] = INAT_MODRM | INAT_VARIANT, - [0xee] = INAT_MODRM | INAT_VARIANT, - [0xef] = INAT_MODRM | INAT_VARIANT, - [0xf0] = INAT_VARIANT, - [0xf1] = INAT_MODRM | INAT_VARIANT, - [0xf2] = INAT_MODRM | INAT_VARIANT, - [0xf3] = INAT_MODRM | INAT_VARIANT, - [0xf4] = INAT_MODRM | INAT_VARIANT, - [0xf5] = INAT_MODRM | INAT_VARIANT, - [0xf6] = INAT_MODRM | INAT_VARIANT, - [0xf7] = INAT_MODRM | INAT_VARIANT, - [0xf8] = INAT_MODRM | INAT_VARIANT, - [0xf9] = INAT_MODRM | INAT_VARIANT, - [0xfa] = INAT_MODRM | INAT_VARIANT, - [0xfb] = INAT_MODRM | INAT_VARIANT, - [0xfc] = INAT_MODRM | INAT_VARIANT, - [0xfd] = INAT_MODRM | INAT_VARIANT, - [0xfe] = INAT_MODRM | INAT_VARIANT, -}; -const insn_attr_t inat_escape_table_1_1[INAT_OPCODE_TABLE_SIZE] = { - [0x10] = INAT_MODRM | INAT_VEXOK, - [0x11] = INAT_MODRM | INAT_VEXOK, - [0x12] = INAT_MODRM | INAT_VEXOK, - [0x13] = INAT_MODRM | INAT_VEXOK, - [0x14] = INAT_MODRM | INAT_VEXOK, - [0x15] = INAT_MODRM | INAT_VEXOK, - [0x16] = INAT_MODRM | INAT_VEXOK, - [0x17] = INAT_MODRM | INAT_VEXOK, - [0x28] = INAT_MODRM | INAT_VEXOK, - [0x29] = INAT_MODRM | INAT_VEXOK, - [0x2a] = INAT_MODRM, - [0x2b] = INAT_MODRM | INAT_VEXOK, - [0x2c] = INAT_MODRM, - [0x2d] = INAT_MODRM, - [0x2e] = INAT_MODRM | INAT_VEXOK, - [0x2f] = INAT_MODRM | INAT_VEXOK, - [0x50] = INAT_MODRM | INAT_VEXOK, - [0x51] = INAT_MODRM | INAT_VEXOK, - [0x54] = INAT_MODRM | INAT_VEXOK, - [0x55] = INAT_MODRM | INAT_VEXOK, - [0x56] = INAT_MODRM | INAT_VEXOK, - [0x57] = INAT_MODRM | INAT_VEXOK, - [0x58] = INAT_MODRM | INAT_VEXOK, - [0x59] = INAT_MODRM | INAT_VEXOK, - [0x5a] = INAT_MODRM | INAT_VEXOK, - [0x5b] = INAT_MODRM | INAT_VEXOK, - [0x5c] = INAT_MODRM | INAT_VEXOK, - [0x5d] = INAT_MODRM | INAT_VEXOK, - [0x5e] = INAT_MODRM | INAT_VEXOK, - [0x5f] = INAT_MODRM | INAT_VEXOK, - [0x60] = INAT_MODRM | INAT_VEXOK, - [0x61] = INAT_MODRM | INAT_VEXOK, - [0x62] = INAT_MODRM | INAT_VEXOK, - [0x63] = INAT_MODRM | INAT_VEXOK, - [0x64] = INAT_MODRM | INAT_VEXOK, - [0x65] = INAT_MODRM | INAT_VEXOK, - [0x66] = INAT_MODRM | INAT_VEXOK, - [0x67] = INAT_MODRM | INAT_VEXOK, - [0x68] = INAT_MODRM | INAT_VEXOK, - [0x69] = INAT_MODRM | INAT_VEXOK, - [0x6a] = INAT_MODRM | INAT_VEXOK, - [0x6b] = INAT_MODRM | INAT_VEXOK, - [0x6c] = INAT_MODRM | INAT_VEXOK, - [0x6d] = INAT_MODRM | INAT_VEXOK, - [0x6e] = INAT_MODRM | INAT_VEXOK, - [0x6f] = INAT_MODRM | INAT_VEXOK, - [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x74] = INAT_MODRM | INAT_VEXOK, - [0x75] = INAT_MODRM | INAT_VEXOK, - [0x76] = INAT_MODRM | INAT_VEXOK, - [0x7c] = INAT_MODRM | INAT_VEXOK, - [0x7d] = INAT_MODRM | INAT_VEXOK, - [0x7e] = INAT_MODRM | INAT_VEXOK, - [0x7f] = INAT_MODRM | INAT_VEXOK, - [0xbc] = INAT_MODRM, - [0xbd] = INAT_MODRM, - [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xc4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xc5] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xc6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xd0] = INAT_MODRM | INAT_VEXOK, - [0xd1] = INAT_MODRM | INAT_VEXOK, - [0xd2] = INAT_MODRM | INAT_VEXOK, - [0xd3] = INAT_MODRM | INAT_VEXOK, - [0xd4] = INAT_MODRM | INAT_VEXOK, - [0xd5] = INAT_MODRM | INAT_VEXOK, - [0xd6] = INAT_MODRM | INAT_VEXOK, - [0xd7] = INAT_MODRM | INAT_VEXOK, - [0xd8] = INAT_MODRM | INAT_VEXOK, - [0xd9] = INAT_MODRM | INAT_VEXOK, - [0xda] = INAT_MODRM | INAT_VEXOK, - [0xdb] = INAT_MODRM | INAT_VEXOK, - [0xdc] = INAT_MODRM | INAT_VEXOK, - [0xdd] = INAT_MODRM | INAT_VEXOK, - [0xde] = INAT_MODRM | INAT_VEXOK, - [0xdf] = INAT_MODRM | INAT_VEXOK, - [0xe0] = INAT_MODRM | INAT_VEXOK, - [0xe1] = INAT_MODRM | INAT_VEXOK, - [0xe2] = INAT_MODRM | INAT_VEXOK, - [0xe3] = INAT_MODRM | INAT_VEXOK, - [0xe4] = INAT_MODRM | INAT_VEXOK, - [0xe5] = INAT_MODRM | INAT_VEXOK, - [0xe6] = INAT_MODRM | INAT_VEXOK, - [0xe7] = INAT_MODRM | INAT_VEXOK, - [0xe8] = INAT_MODRM | INAT_VEXOK, - [0xe9] = INAT_MODRM | INAT_VEXOK, - [0xea] = INAT_MODRM | INAT_VEXOK, - [0xeb] = INAT_MODRM | INAT_VEXOK, - [0xec] = INAT_MODRM | INAT_VEXOK, - [0xed] = INAT_MODRM | INAT_VEXOK, - [0xee] = INAT_MODRM | INAT_VEXOK, - [0xef] = INAT_MODRM | INAT_VEXOK, - [0xf1] = INAT_MODRM | INAT_VEXOK, - [0xf2] = INAT_MODRM | INAT_VEXOK, - [0xf3] = INAT_MODRM | INAT_VEXOK, - [0xf4] = INAT_MODRM | INAT_VEXOK, - [0xf5] = INAT_MODRM | INAT_VEXOK, - [0xf6] = INAT_MODRM | INAT_VEXOK, - [0xf7] = INAT_MODRM | INAT_VEXOK, - [0xf8] = INAT_MODRM | INAT_VEXOK, - [0xf9] = INAT_MODRM | INAT_VEXOK, - [0xfa] = INAT_MODRM | INAT_VEXOK, - [0xfb] = INAT_MODRM | INAT_VEXOK, - [0xfc] = INAT_MODRM | INAT_VEXOK, - [0xfd] = INAT_MODRM | INAT_VEXOK, - [0xfe] = INAT_MODRM | INAT_VEXOK, -}; -const insn_attr_t inat_escape_table_1_2[INAT_OPCODE_TABLE_SIZE] = { - [0x10] = INAT_MODRM | INAT_VEXOK, - [0x11] = INAT_MODRM | INAT_VEXOK, - [0x12] = INAT_MODRM | INAT_VEXOK, - [0x16] = INAT_MODRM | INAT_VEXOK, - [0x2a] = INAT_MODRM | INAT_VEXOK, - [0x2c] = INAT_MODRM | INAT_VEXOK, - [0x2d] = INAT_MODRM | INAT_VEXOK, - [0x51] = INAT_MODRM | INAT_VEXOK, - [0x52] = INAT_MODRM | INAT_VEXOK, - [0x53] = INAT_MODRM | INAT_VEXOK, - [0x58] = INAT_MODRM | INAT_VEXOK, - [0x59] = INAT_MODRM | INAT_VEXOK, - [0x5a] = INAT_MODRM | INAT_VEXOK, - [0x5b] = INAT_MODRM | INAT_VEXOK, - [0x5c] = INAT_MODRM | INAT_VEXOK, - [0x5d] = INAT_MODRM | INAT_VEXOK, - [0x5e] = INAT_MODRM | INAT_VEXOK, - [0x5f] = INAT_MODRM | INAT_VEXOK, - [0x6f] = INAT_MODRM | INAT_VEXOK, - [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x7e] = INAT_MODRM | INAT_VEXOK, - [0x7f] = INAT_MODRM | INAT_VEXOK, - [0xb8] = INAT_MODRM, - [0xbc] = INAT_MODRM, - [0xbd] = INAT_MODRM, - [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xd6] = INAT_MODRM, - [0xe6] = INAT_MODRM | INAT_VEXOK, -}; -const insn_attr_t inat_escape_table_1_3[INAT_OPCODE_TABLE_SIZE] = { - [0x10] = INAT_MODRM | INAT_VEXOK, - [0x11] = INAT_MODRM | INAT_VEXOK, - [0x12] = INAT_MODRM | INAT_VEXOK, - [0x2a] = INAT_MODRM | INAT_VEXOK, - [0x2c] = INAT_MODRM | INAT_VEXOK, - [0x2d] = INAT_MODRM | INAT_VEXOK, - [0x51] = INAT_MODRM | INAT_VEXOK, - [0x58] = INAT_MODRM | INAT_VEXOK, - [0x59] = INAT_MODRM | INAT_VEXOK, - [0x5a] = INAT_MODRM | INAT_VEXOK, - [0x5c] = INAT_MODRM | INAT_VEXOK, - [0x5d] = INAT_MODRM | INAT_VEXOK, - [0x5e] = INAT_MODRM | INAT_VEXOK, - [0x5f] = INAT_MODRM | INAT_VEXOK, - [0x70] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x7c] = INAT_MODRM | INAT_VEXOK, - [0x7d] = INAT_MODRM | INAT_VEXOK, - [0xbc] = INAT_MODRM, - [0xbd] = INAT_MODRM, - [0xc2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xd0] = INAT_MODRM | INAT_VEXOK, - [0xd6] = INAT_MODRM, - [0xe6] = INAT_MODRM | INAT_VEXOK, - [0xf0] = INAT_MODRM | INAT_VEXOK, -}; - -/* Table: 3-byte opcode 1 (0x0f 0x38) */ -const insn_attr_t inat_escape_table_2[INAT_OPCODE_TABLE_SIZE] = { - [0x00] = INAT_MODRM | INAT_VARIANT, - [0x01] = INAT_MODRM | INAT_VARIANT, - [0x02] = INAT_MODRM | INAT_VARIANT, - [0x03] = INAT_MODRM | INAT_VARIANT, - [0x04] = INAT_MODRM | INAT_VARIANT, - [0x05] = INAT_MODRM | INAT_VARIANT, - [0x06] = INAT_MODRM | INAT_VARIANT, - [0x07] = INAT_MODRM | INAT_VARIANT, - [0x08] = INAT_MODRM | INAT_VARIANT, - [0x09] = INAT_MODRM | INAT_VARIANT, - [0x0a] = INAT_MODRM | INAT_VARIANT, - [0x0b] = INAT_MODRM | INAT_VARIANT, - [0x0c] = INAT_VARIANT, - [0x0d] = INAT_VARIANT, - [0x0e] = INAT_VARIANT, - [0x0f] = INAT_VARIANT, - [0x10] = INAT_VARIANT, - [0x13] = INAT_VARIANT, - [0x14] = INAT_VARIANT, - [0x15] = INAT_VARIANT, - [0x16] = INAT_VARIANT, - [0x17] = INAT_VARIANT, - [0x18] = INAT_VARIANT, - [0x19] = INAT_VARIANT, - [0x1a] = INAT_VARIANT, - [0x1c] = INAT_MODRM | INAT_VARIANT, - [0x1d] = INAT_MODRM | INAT_VARIANT, - [0x1e] = INAT_MODRM | INAT_VARIANT, - [0x20] = INAT_VARIANT, - [0x21] = INAT_VARIANT, - [0x22] = INAT_VARIANT, - [0x23] = INAT_VARIANT, - [0x24] = INAT_VARIANT, - [0x25] = INAT_VARIANT, - [0x28] = INAT_VARIANT, - [0x29] = INAT_VARIANT, - [0x2a] = INAT_VARIANT, - [0x2b] = INAT_VARIANT, - [0x2c] = INAT_VARIANT, - [0x2d] = INAT_VARIANT, - [0x2e] = INAT_VARIANT, - [0x2f] = INAT_VARIANT, - [0x30] = INAT_VARIANT, - [0x31] = INAT_VARIANT, - [0x32] = INAT_VARIANT, - [0x33] = INAT_VARIANT, - [0x34] = INAT_VARIANT, - [0x35] = INAT_VARIANT, - [0x36] = INAT_VARIANT, - [0x37] = INAT_VARIANT, - [0x38] = INAT_VARIANT, - [0x39] = INAT_VARIANT, - [0x3a] = INAT_VARIANT, - [0x3b] = INAT_VARIANT, - [0x3c] = INAT_VARIANT, - [0x3d] = INAT_VARIANT, - [0x3e] = INAT_VARIANT, - [0x3f] = INAT_VARIANT, - [0x40] = INAT_VARIANT, - [0x41] = INAT_VARIANT, - [0x45] = INAT_VARIANT, - [0x46] = INAT_VARIANT, - [0x47] = INAT_VARIANT, - [0x58] = INAT_VARIANT, - [0x59] = INAT_VARIANT, - [0x5a] = INAT_VARIANT, - [0x78] = INAT_VARIANT, - [0x79] = INAT_VARIANT, - [0x80] = INAT_VARIANT, - [0x81] = INAT_VARIANT, - [0x82] = INAT_VARIANT, - [0x8c] = INAT_VARIANT, - [0x8e] = INAT_VARIANT, - [0x90] = INAT_VARIANT, - [0x91] = INAT_VARIANT, - [0x92] = INAT_VARIANT, - [0x93] = INAT_VARIANT, - [0x96] = INAT_VARIANT, - [0x97] = INAT_VARIANT, - [0x98] = INAT_VARIANT, - [0x99] = INAT_VARIANT, - [0x9a] = INAT_VARIANT, - [0x9b] = INAT_VARIANT, - [0x9c] = INAT_VARIANT, - [0x9d] = INAT_VARIANT, - [0x9e] = INAT_VARIANT, - [0x9f] = INAT_VARIANT, - [0xa6] = INAT_VARIANT, - [0xa7] = INAT_VARIANT, - [0xa8] = INAT_VARIANT, - [0xa9] = INAT_VARIANT, - [0xaa] = INAT_VARIANT, - [0xab] = INAT_VARIANT, - [0xac] = INAT_VARIANT, - [0xad] = INAT_VARIANT, - [0xae] = INAT_VARIANT, - [0xaf] = INAT_VARIANT, - [0xb6] = INAT_VARIANT, - [0xb7] = INAT_VARIANT, - [0xb8] = INAT_VARIANT, - [0xb9] = INAT_VARIANT, - [0xba] = INAT_VARIANT, - [0xbb] = INAT_VARIANT, - [0xbc] = INAT_VARIANT, - [0xbd] = INAT_VARIANT, - [0xbe] = INAT_VARIANT, - [0xbf] = INAT_VARIANT, - [0xdb] = INAT_VARIANT, - [0xdc] = INAT_VARIANT, - [0xdd] = INAT_VARIANT, - [0xde] = INAT_VARIANT, - [0xdf] = INAT_VARIANT, - [0xf0] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, - [0xf1] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, - [0xf2] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xf3] = INAT_MAKE_GROUP(23), - [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY | INAT_VARIANT, - [0xf6] = INAT_VARIANT, - [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY | INAT_VARIANT, -}; -const insn_attr_t inat_escape_table_2_1[INAT_OPCODE_TABLE_SIZE] = { - [0x00] = INAT_MODRM | INAT_VEXOK, - [0x01] = INAT_MODRM | INAT_VEXOK, - [0x02] = INAT_MODRM | INAT_VEXOK, - [0x03] = INAT_MODRM | INAT_VEXOK, - [0x04] = INAT_MODRM | INAT_VEXOK, - [0x05] = INAT_MODRM | INAT_VEXOK, - [0x06] = INAT_MODRM | INAT_VEXOK, - [0x07] = INAT_MODRM | INAT_VEXOK, - [0x08] = INAT_MODRM | INAT_VEXOK, - [0x09] = INAT_MODRM | INAT_VEXOK, - [0x0a] = INAT_MODRM | INAT_VEXOK, - [0x0b] = INAT_MODRM | INAT_VEXOK, - [0x0c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x0d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x0e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x0f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x10] = INAT_MODRM, - [0x13] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x14] = INAT_MODRM, - [0x15] = INAT_MODRM, - [0x16] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x17] = INAT_MODRM | INAT_VEXOK, - [0x18] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x19] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x1a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x1c] = INAT_MODRM | INAT_VEXOK, - [0x1d] = INAT_MODRM | INAT_VEXOK, - [0x1e] = INAT_MODRM | INAT_VEXOK, - [0x20] = INAT_MODRM | INAT_VEXOK, - [0x21] = INAT_MODRM | INAT_VEXOK, - [0x22] = INAT_MODRM | INAT_VEXOK, - [0x23] = INAT_MODRM | INAT_VEXOK, - [0x24] = INAT_MODRM | INAT_VEXOK, - [0x25] = INAT_MODRM | INAT_VEXOK, - [0x28] = INAT_MODRM | INAT_VEXOK, - [0x29] = INAT_MODRM | INAT_VEXOK, - [0x2a] = INAT_MODRM | INAT_VEXOK, - [0x2b] = INAT_MODRM | INAT_VEXOK, - [0x2c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x2d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x2e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x2f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x30] = INAT_MODRM | INAT_VEXOK, - [0x31] = INAT_MODRM | INAT_VEXOK, - [0x32] = INAT_MODRM | INAT_VEXOK, - [0x33] = INAT_MODRM | INAT_VEXOK, - [0x34] = INAT_MODRM | INAT_VEXOK, - [0x35] = INAT_MODRM | INAT_VEXOK, - [0x36] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x37] = INAT_MODRM | INAT_VEXOK, - [0x38] = INAT_MODRM | INAT_VEXOK, - [0x39] = INAT_MODRM | INAT_VEXOK, - [0x3a] = INAT_MODRM | INAT_VEXOK, - [0x3b] = INAT_MODRM | INAT_VEXOK, - [0x3c] = INAT_MODRM | INAT_VEXOK, - [0x3d] = INAT_MODRM | INAT_VEXOK, - [0x3e] = INAT_MODRM | INAT_VEXOK, - [0x3f] = INAT_MODRM | INAT_VEXOK, - [0x40] = INAT_MODRM | INAT_VEXOK, - [0x41] = INAT_MODRM | INAT_VEXOK, - [0x45] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x46] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x47] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x58] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x59] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x5a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x78] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x79] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x80] = INAT_MODRM, - [0x81] = INAT_MODRM, - [0x82] = INAT_MODRM, - [0x8c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x8e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x90] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x91] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x92] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x93] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x96] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x97] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x98] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x99] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x9a] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x9b] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x9c] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x9d] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x9e] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x9f] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xa6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xa7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xa8] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xa9] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xaa] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xab] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xac] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xad] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xae] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xaf] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xb6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xb7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xb8] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xb9] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xba] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xbb] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xbc] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xbd] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xbe] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xbf] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xdb] = INAT_MODRM | INAT_VEXOK, - [0xdc] = INAT_MODRM | INAT_VEXOK, - [0xdd] = INAT_MODRM | INAT_VEXOK, - [0xde] = INAT_MODRM | INAT_VEXOK, - [0xdf] = INAT_MODRM | INAT_VEXOK, - [0xf0] = INAT_MODRM, - [0xf1] = INAT_MODRM, - [0xf6] = INAT_MODRM, - [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, -}; -const insn_attr_t inat_escape_table_2_2[INAT_OPCODE_TABLE_SIZE] = { - [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xf6] = INAT_MODRM, - [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, -}; -const insn_attr_t inat_escape_table_2_3[INAT_OPCODE_TABLE_SIZE] = { - [0xf0] = INAT_MODRM | INAT_MODRM, - [0xf1] = INAT_MODRM | INAT_MODRM, - [0xf5] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xf6] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0xf7] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, -}; - -/* Table: 3-byte opcode 2 (0x0f 0x3a) */ -const insn_attr_t inat_escape_table_3[INAT_OPCODE_TABLE_SIZE] = { - [0x00] = INAT_VARIANT, - [0x01] = INAT_VARIANT, - [0x02] = INAT_VARIANT, - [0x04] = INAT_VARIANT, - [0x05] = INAT_VARIANT, - [0x06] = INAT_VARIANT, - [0x08] = INAT_VARIANT, - [0x09] = INAT_VARIANT, - [0x0a] = INAT_VARIANT, - [0x0b] = INAT_VARIANT, - [0x0c] = INAT_VARIANT, - [0x0d] = INAT_VARIANT, - [0x0e] = INAT_VARIANT, - [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x14] = INAT_VARIANT, - [0x15] = INAT_VARIANT, - [0x16] = INAT_VARIANT, - [0x17] = INAT_VARIANT, - [0x18] = INAT_VARIANT, - [0x19] = INAT_VARIANT, - [0x1d] = INAT_VARIANT, - [0x20] = INAT_VARIANT, - [0x21] = INAT_VARIANT, - [0x22] = INAT_VARIANT, - [0x38] = INAT_VARIANT, - [0x39] = INAT_VARIANT, - [0x40] = INAT_VARIANT, - [0x41] = INAT_VARIANT, - [0x42] = INAT_VARIANT, - [0x44] = INAT_VARIANT, - [0x46] = INAT_VARIANT, - [0x4a] = INAT_VARIANT, - [0x4b] = INAT_VARIANT, - [0x4c] = INAT_VARIANT, - [0x60] = INAT_VARIANT, - [0x61] = INAT_VARIANT, - [0x62] = INAT_VARIANT, - [0x63] = INAT_VARIANT, - [0xdf] = INAT_VARIANT, - [0xf0] = INAT_VARIANT, -}; -const insn_attr_t inat_escape_table_3_1[INAT_OPCODE_TABLE_SIZE] = { - [0x00] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x01] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x02] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x04] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x05] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x06] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x08] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x09] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x0a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x0b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x0c] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x0d] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x0e] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x0f] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x14] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x15] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x16] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x17] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x18] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x19] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x1d] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x20] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x21] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x22] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x38] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x39] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x40] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x41] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x42] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x44] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x46] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x4a] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x4b] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x4c] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x60] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x61] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x62] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x63] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0xdf] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, -}; -const insn_attr_t inat_escape_table_3_3[INAT_OPCODE_TABLE_SIZE] = { - [0xf0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, -}; - -/* GrpTable: Grp1 */ - -/* GrpTable: Grp1A */ - -/* GrpTable: Grp2 */ - -/* GrpTable: Grp3_1 */ -const insn_attr_t inat_group_table_6[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, - [0x2] = INAT_MODRM, - [0x3] = INAT_MODRM, - [0x4] = INAT_MODRM, - [0x5] = INAT_MODRM, - [0x6] = INAT_MODRM, - [0x7] = INAT_MODRM, -}; - -/* GrpTable: Grp3_2 */ -const insn_attr_t inat_group_table_7[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, - [0x2] = INAT_MODRM, - [0x3] = INAT_MODRM, - [0x4] = INAT_MODRM, - [0x5] = INAT_MODRM, - [0x6] = INAT_MODRM, - [0x7] = INAT_MODRM, -}; - -/* GrpTable: Grp4 */ -const insn_attr_t inat_group_table_8[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MODRM, - [0x1] = INAT_MODRM, -}; - -/* GrpTable: Grp5 */ -const insn_attr_t inat_group_table_9[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MODRM, - [0x1] = INAT_MODRM, - [0x2] = INAT_MODRM | INAT_FORCE64, - [0x3] = INAT_MODRM, - [0x4] = INAT_MODRM | INAT_FORCE64, - [0x5] = INAT_MODRM, - [0x6] = INAT_MODRM | INAT_FORCE64, -}; - -/* GrpTable: Grp6 */ -const insn_attr_t inat_group_table_10[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MODRM, - [0x1] = INAT_MODRM, - [0x2] = INAT_MODRM, - [0x3] = INAT_MODRM, - [0x4] = INAT_MODRM, - [0x5] = INAT_MODRM, -}; - -/* GrpTable: Grp7 */ -const insn_attr_t inat_group_table_11[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MODRM, - [0x1] = INAT_MODRM, - [0x2] = INAT_MODRM, - [0x3] = INAT_MODRM, - [0x4] = INAT_MODRM, - [0x6] = INAT_MODRM, - [0x7] = INAT_MODRM, -}; - -/* GrpTable: Grp8 */ - -/* GrpTable: Grp9 */ -const insn_attr_t inat_group_table_22[INAT_GROUP_TABLE_SIZE] = { - [0x1] = INAT_MODRM, - [0x6] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, - [0x7] = INAT_MODRM | INAT_MODRM | INAT_VARIANT, -}; -const insn_attr_t inat_group_table_22_1[INAT_GROUP_TABLE_SIZE] = { - [0x6] = INAT_MODRM, -}; -const insn_attr_t inat_group_table_22_2[INAT_GROUP_TABLE_SIZE] = { - [0x6] = INAT_MODRM, - [0x7] = INAT_MODRM, -}; - -/* GrpTable: Grp10 */ - -/* GrpTable: Grp11A */ -const insn_attr_t inat_group_table_4[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM, - [0x7] = INAT_MAKE_IMM(INAT_IMM_BYTE), -}; - -/* GrpTable: Grp11B */ -const insn_attr_t inat_group_table_5[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MAKE_IMM(INAT_IMM_VWORD32) | INAT_MODRM, - [0x7] = INAT_MAKE_IMM(INAT_IMM_VWORD32), -}; - -/* GrpTable: Grp12 */ -const insn_attr_t inat_group_table_14[INAT_GROUP_TABLE_SIZE] = { - [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, -}; -const insn_attr_t inat_group_table_14_1[INAT_GROUP_TABLE_SIZE] = { - [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, -}; - -/* GrpTable: Grp13 */ -const insn_attr_t inat_group_table_15[INAT_GROUP_TABLE_SIZE] = { - [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, -}; -const insn_attr_t inat_group_table_15_1[INAT_GROUP_TABLE_SIZE] = { - [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x4] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, -}; - -/* GrpTable: Grp14 */ -const insn_attr_t inat_group_table_16[INAT_GROUP_TABLE_SIZE] = { - [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x3] = INAT_VARIANT, - [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VARIANT, - [0x7] = INAT_VARIANT, -}; -const insn_attr_t inat_group_table_16_1[INAT_GROUP_TABLE_SIZE] = { - [0x2] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x3] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x6] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, - [0x7] = INAT_MAKE_IMM(INAT_IMM_BYTE) | INAT_MODRM | INAT_VEXOK, -}; - -/* GrpTable: Grp15 */ -const insn_attr_t inat_group_table_19[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_VARIANT, - [0x1] = INAT_VARIANT, - [0x2] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, - [0x3] = INAT_MODRM | INAT_VEXOK | INAT_VARIANT, -}; -const insn_attr_t inat_group_table_19_2[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MODRM, - [0x1] = INAT_MODRM, - [0x2] = INAT_MODRM, - [0x3] = INAT_MODRM, -}; - -/* GrpTable: Grp16 */ -const insn_attr_t inat_group_table_13[INAT_GROUP_TABLE_SIZE] = { - [0x0] = INAT_MODRM, - [0x1] = INAT_MODRM, - [0x2] = INAT_MODRM, - [0x3] = INAT_MODRM, -}; - -/* GrpTable: Grp17 */ -const insn_attr_t inat_group_table_23[INAT_GROUP_TABLE_SIZE] = { - [0x1] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x2] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, - [0x3] = INAT_MODRM | INAT_VEXOK | INAT_VEXONLY, -}; - -/* GrpTable: GrpP */ - -/* GrpTable: GrpPDLK */ - -/* GrpTable: GrpRNG */ - -/* Escape opcode map array */ -const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1][INAT_LSTPFX_MAX + 1] = { - [1][0] = inat_escape_table_1, - [1][1] = inat_escape_table_1_1, - [1][2] = inat_escape_table_1_2, - [1][3] = inat_escape_table_1_3, - [2][0] = inat_escape_table_2, - [2][1] = inat_escape_table_2_1, - [2][2] = inat_escape_table_2_2, - [2][3] = inat_escape_table_2_3, - [3][0] = inat_escape_table_3, - [3][1] = inat_escape_table_3_1, - [3][3] = inat_escape_table_3_3, -}; - -/* Group opcode map array */ -const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1][INAT_LSTPFX_MAX + 1] = { - [4][0] = inat_group_table_4, - [5][0] = inat_group_table_5, - [6][0] = inat_group_table_6, - [7][0] = inat_group_table_7, - [8][0] = inat_group_table_8, - [9][0] = inat_group_table_9, - [10][0] = inat_group_table_10, - [11][0] = inat_group_table_11, - [13][0] = inat_group_table_13, - [14][0] = inat_group_table_14, - [14][1] = inat_group_table_14_1, - [15][0] = inat_group_table_15, - [15][1] = inat_group_table_15_1, - [16][0] = inat_group_table_16, - [16][1] = inat_group_table_16_1, - [19][0] = inat_group_table_19, - [19][2] = inat_group_table_19_2, - [22][0] = inat_group_table_22, - [22][1] = inat_group_table_22_1, - [22][2] = inat_group_table_22_2, - [23][0] = inat_group_table_23, -}; - -/* AVX opcode map array */ -const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1][INAT_LSTPFX_MAX + 1] = { - [1][0] = inat_escape_table_1, - [1][1] = inat_escape_table_1_1, - [1][2] = inat_escape_table_1_2, - [1][3] = inat_escape_table_1_3, - [2][0] = inat_escape_table_2, - [2][1] = inat_escape_table_2_1, - [2][2] = inat_escape_table_2_2, - [2][3] = inat_escape_table_2_3, - [3][0] = inat_escape_table_3, - [3][1] = inat_escape_table_3_1, - [3][3] = inat_escape_table_3_3, -}; diff --git a/kpatch-build/insn/inat.c b/kpatch-build/insn/inat.c deleted file mode 100644 index c1f01a8..0000000 --- a/kpatch-build/insn/inat.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * x86 instruction attribute tables - * - * Written by Masami Hiramatsu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#include - -/* Attribute tables are generated from opcode map */ -#include "inat-tables.c" - -/* Attribute search APIs */ -insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) -{ - return inat_primary_table[opcode]; -} - -int inat_get_last_prefix_id(insn_byte_t last_pfx) -{ - insn_attr_t lpfx_attr; - - lpfx_attr = inat_get_opcode_attribute(last_pfx); - return inat_last_prefix_id(lpfx_attr); -} - -insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, - insn_attr_t esc_attr) -{ - const insn_attr_t *table; - int n; - - n = inat_escape_id(esc_attr); - - table = inat_escape_tables[n][0]; - if (!table) - return 0; - if (inat_has_variant(table[opcode]) && lpfx_id) { - table = inat_escape_tables[n][lpfx_id]; - if (!table) - return 0; - } - return table[opcode]; -} - -insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, - insn_attr_t grp_attr) -{ - const insn_attr_t *table; - int n; - - n = inat_group_id(grp_attr); - - table = inat_group_tables[n][0]; - if (!table) - return inat_group_common_attribute(grp_attr); - if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { - table = inat_group_tables[n][lpfx_id]; - if (!table) - return inat_group_common_attribute(grp_attr); - } - return table[X86_MODRM_REG(modrm)] | - inat_group_common_attribute(grp_attr); -} - -insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, - insn_byte_t vex_p) -{ - const insn_attr_t *table; - if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) - return 0; - /* At first, this checks the master table */ - table = inat_avx_tables[vex_m][0]; - if (!table) - return 0; - if (!inat_is_group(table[opcode]) && vex_p) { - /* If this is not a group, get attribute directly */ - table = inat_avx_tables[vex_m][vex_p]; - if (!table) - return 0; - } - return table[opcode]; -} - diff --git a/kpatch-build/insn/insn.c b/kpatch-build/insn/insn.c deleted file mode 100644 index 7acdc96..0000000 --- a/kpatch-build/insn/insn.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * x86 instruction analysis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2002, 2004, 2009 - */ - -#ifdef __KERNEL__ -#include -#else -#include -#endif -#include -#include - -#define unlikely(a) a - -/* Verify next sizeof(t) bytes can be on the same instruction */ -#define validate_next(t, insn, n) \ - ((insn)->next_byte + sizeof(t) + n - (insn)->kaddr <= MAX_INSN_SIZE) - -#define __get_next(t, insn) \ - ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) - -#define __peek_nbyte_next(t, insn, n) \ - ({ t r = *(t*)((insn)->next_byte + n); r; }) - -#define get_next(t, insn) \ - ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) - -#define peek_nbyte_next(t, insn, n) \ - ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) - -#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) - -/** - * insn_init() - initialize struct insn - * @insn: &struct insn to be initialized - * @kaddr: address (in kernel memory) of instruction (or copy thereof) - * @x86_64: !0 for 64-bit kernel or 64-bit app - */ -void insn_init(struct insn *insn, const void *kaddr, int x86_64) -{ - memset(insn, 0, sizeof(*insn)); - insn->kaddr = kaddr; - insn->next_byte = kaddr; - insn->x86_64 = x86_64 ? 1 : 0; - insn->opnd_bytes = 4; - if (x86_64) - insn->addr_bytes = 8; - else - insn->addr_bytes = 4; -} - -/** - * insn_get_prefixes - scan x86 instruction prefix bytes - * @insn: &struct insn containing instruction - * - * Populates the @insn->prefixes bitmap, and updates @insn->next_byte - * to point to the (first) opcode. No effect if @insn->prefixes.got - * is already set. - */ -void insn_get_prefixes(struct insn *insn) -{ - struct insn_field *prefixes = &insn->prefixes; - insn_attr_t attr; - insn_byte_t b, lb; - int i, nb; - - if (prefixes->got) - return; - - nb = 0; - lb = 0; - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - while (inat_is_legacy_prefix(attr)) { - /* Skip if same prefix */ - for (i = 0; i < nb; i++) - if (prefixes->bytes[i] == b) - goto found; - if (nb == 4) - /* Invalid instruction */ - break; - prefixes->bytes[nb++] = b; - if (inat_is_address_size_prefix(attr)) { - /* address size switches 2/4 or 4/8 */ - if (insn->x86_64) - insn->addr_bytes ^= 12; - else - insn->addr_bytes ^= 6; - } else if (inat_is_operand_size_prefix(attr)) { - /* oprand size switches 2/4 */ - insn->opnd_bytes ^= 6; - } -found: - prefixes->nbytes++; - insn->next_byte++; - lb = b; - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - } - /* Set the last prefix */ - if (lb && lb != insn->prefixes.bytes[3]) { - if (unlikely(insn->prefixes.bytes[3])) { - /* Swap the last prefix */ - b = insn->prefixes.bytes[3]; - for (i = 0; i < nb; i++) - if (prefixes->bytes[i] == lb) - prefixes->bytes[i] = b; - } - insn->prefixes.bytes[3] = lb; - } - - /* Decode REX prefix */ - if (insn->x86_64) { - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_rex_prefix(attr)) { - insn->rex_prefix.value = b; - insn->rex_prefix.nbytes = 1; - insn->next_byte++; - if (X86_REX_W(b)) - /* REX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } - } - insn->rex_prefix.got = 1; - - /* Decode VEX prefix */ - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_vex_prefix(attr)) { - insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); - if (!insn->x86_64) { - /* - * In 32-bits mode, if the [7:6] bits (mod bits of - * ModRM) on the second byte are not 11b, it is - * LDS or LES. - */ - if (X86_MODRM_MOD(b2) != 3) - goto vex_end; - } - insn->vex_prefix.bytes[0] = b; - insn->vex_prefix.bytes[1] = b2; - if (inat_is_vex3_prefix(attr)) { - b2 = peek_nbyte_next(insn_byte_t, insn, 2); - insn->vex_prefix.bytes[2] = b2; - insn->vex_prefix.nbytes = 3; - insn->next_byte += 3; - if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } else { - insn->vex_prefix.nbytes = 2; - insn->next_byte += 2; - } - } -vex_end: - insn->vex_prefix.got = 1; - - prefixes->got = 1; - -err_out: - return; -} - -/** - * insn_get_opcode - collect opcode(s) - * @insn: &struct insn containing instruction - * - * Populates @insn->opcode, updates @insn->next_byte to point past the - * opcode byte(s), and set @insn->attr (except for groups). - * If necessary, first collects any preceding (prefix) bytes. - * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got - * is already 1. - */ -void insn_get_opcode(struct insn *insn) -{ - struct insn_field *opcode = &insn->opcode; - insn_byte_t op; - int pfx_id; - if (opcode->got) - return; - if (!insn->prefixes.got) - insn_get_prefixes(insn); - - /* Get first opcode */ - op = get_next(insn_byte_t, insn); - opcode->bytes[0] = op; - opcode->nbytes = 1; - - /* Check if there is VEX prefix or not */ - if (insn_is_avx(insn)) { - insn_byte_t m, p; - m = insn_vex_m_bits(insn); - p = insn_vex_p_bits(insn); - insn->attr = inat_get_avx_attribute(op, m, p); - if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) - insn->attr = 0; /* This instruction is bad */ - goto end; /* VEX has only 1 byte for opcode */ - } - - insn->attr = inat_get_opcode_attribute(op); - while (inat_is_escape(insn->attr)) { - /* Get escaped opcode */ - op = get_next(insn_byte_t, insn); - opcode->bytes[opcode->nbytes++] = op; - pfx_id = insn_last_prefix_id(insn); - insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); - } - if (inat_must_vex(insn->attr)) - insn->attr = 0; /* This instruction is bad */ -end: - opcode->got = 1; - -err_out: - return; -} - -/** - * insn_get_modrm - collect ModRM byte, if any - * @insn: &struct insn containing instruction - * - * Populates @insn->modrm and updates @insn->next_byte to point past the - * ModRM byte, if any. If necessary, first collects the preceding bytes - * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. - */ -void insn_get_modrm(struct insn *insn) -{ - struct insn_field *modrm = &insn->modrm; - insn_byte_t pfx_id, mod; - if (modrm->got) - return; - if (!insn->opcode.got) - insn_get_opcode(insn); - - if (inat_has_modrm(insn->attr)) { - mod = get_next(insn_byte_t, insn); - modrm->value = mod; - modrm->nbytes = 1; - if (inat_is_group(insn->attr)) { - pfx_id = insn_last_prefix_id(insn); - insn->attr = inat_get_group_attribute(mod, pfx_id, - insn->attr); - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) - insn->attr = 0; /* This is bad */ - } - } - - if (insn->x86_64 && inat_is_force64(insn->attr)) - insn->opnd_bytes = 8; - modrm->got = 1; - -err_out: - return; -} - - -/** - * insn_rip_relative() - Does instruction use RIP-relative addressing mode? - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * ModRM byte. No effect if @insn->x86_64 is 0. - */ -int insn_rip_relative(struct insn *insn) -{ - struct insn_field *modrm = &insn->modrm; - - if (!insn->x86_64) - return 0; - if (!modrm->got) - insn_get_modrm(insn); - /* - * For rip-relative instructions, the mod field (top 2 bits) - * is zero and the r/m field (bottom 3 bits) is 0x5. - */ - return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); -} - -/** - * insn_get_sib() - Get the SIB byte of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * ModRM byte. - */ -void insn_get_sib(struct insn *insn) -{ - insn_byte_t modrm; - - if (insn->sib.got) - return; - if (!insn->modrm.got) - insn_get_modrm(insn); - if (insn->modrm.nbytes) { - modrm = (insn_byte_t)insn->modrm.value; - if (insn->addr_bytes != 2 && - X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { - insn->sib.value = get_next(insn_byte_t, insn); - insn->sib.nbytes = 1; - } - } - insn->sib.got = 1; - -err_out: - return; -} - - -/** - * insn_get_displacement() - Get the displacement of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * SIB byte. - * Displacement value is sign-expanded. - */ -void insn_get_displacement(struct insn *insn) -{ - insn_byte_t mod, rm, base; - - if (insn->displacement.got) - return; - if (!insn->sib.got) - insn_get_sib(insn); - if (insn->modrm.nbytes) { - /* - * Interpreting the modrm byte: - * mod = 00 - no displacement fields (exceptions below) - * mod = 01 - 1-byte displacement field - * mod = 10 - displacement field is 4 bytes, or 2 bytes if - * address size = 2 (0x67 prefix in 32-bit mode) - * mod = 11 - no memory operand - * - * If address size = 2... - * mod = 00, r/m = 110 - displacement field is 2 bytes - * - * If address size != 2... - * mod != 11, r/m = 100 - SIB byte exists - * mod = 00, SIB base = 101 - displacement field is 4 bytes - * mod = 00, r/m = 101 - rip-relative addressing, displacement - * field is 4 bytes - */ - mod = X86_MODRM_MOD(insn->modrm.value); - rm = X86_MODRM_RM(insn->modrm.value); - base = X86_SIB_BASE(insn->sib.value); - if (mod == 3) - goto out; - if (mod == 1) { - insn->displacement.value = get_next(char, insn); - insn->displacement.nbytes = 1; - } else if (insn->addr_bytes == 2) { - if ((mod == 0 && rm == 6) || mod == 2) { - insn->displacement.value = - get_next(short, insn); - insn->displacement.nbytes = 2; - } - } else { - if ((mod == 0 && rm == 5) || mod == 2 || - (mod == 0 && base == 5)) { - insn->displacement.value = get_next(int, insn); - insn->displacement.nbytes = 4; - } - } - } -out: - insn->displacement.got = 1; - -err_out: - return; -} - -/* Decode moffset16/32/64. Return 0 if failed */ -static int __get_moffset(struct insn *insn) -{ - switch (insn->addr_bytes) { - case 2: - insn->moffset1.value = get_next(short, insn); - insn->moffset1.nbytes = 2; - break; - case 4: - insn->moffset1.value = get_next(int, insn); - insn->moffset1.nbytes = 4; - break; - case 8: - insn->moffset1.value = get_next(int, insn); - insn->moffset1.nbytes = 4; - insn->moffset2.value = get_next(int, insn); - insn->moffset2.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->moffset1.got = insn->moffset2.got = 1; - - return 1; - -err_out: - return 0; -} - -/* Decode imm v32(Iz). Return 0 if failed */ -static int __get_immv32(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate.value = get_next(short, insn); - insn->immediate.nbytes = 2; - break; - case 4: - case 8: - insn->immediate.value = get_next(int, insn); - insn->immediate.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - - return 1; - -err_out: - return 0; -} - -/* Decode imm v64(Iv/Ov), Return 0 if failed */ -static int __get_immv(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate1.value = get_next(short, insn); - insn->immediate1.nbytes = 2; - break; - case 4: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - break; - case 8: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - insn->immediate2.value = get_next(int, insn); - insn->immediate2.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->immediate1.got = insn->immediate2.got = 1; - - return 1; -err_out: - return 0; -} - -/* Decode ptr16:16/32(Ap) */ -static int __get_immptr(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate1.value = get_next(short, insn); - insn->immediate1.nbytes = 2; - break; - case 4: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - break; - case 8: - /* ptr16:64 is not exist (no segment) */ - return 0; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->immediate2.value = get_next(unsigned short, insn); - insn->immediate2.nbytes = 2; - insn->immediate1.got = insn->immediate2.got = 1; - - return 1; -err_out: - return 0; -} - -/** - * insn_get_immediate() - Get the immediates of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * displacement bytes. - * Basically, most of immediates are sign-expanded. Unsigned-value can be - * get by bit masking with ((1 << (nbytes * 8)) - 1) - */ -void insn_get_immediate(struct insn *insn) -{ - if (insn->immediate.got) - return; - if (!insn->displacement.got) - insn_get_displacement(insn); - - if (inat_has_moffset(insn->attr)) { - if (!__get_moffset(insn)) - goto err_out; - goto done; - } - - if (!inat_has_immediate(insn->attr)) - /* no immediates */ - goto done; - - switch (inat_immediate_size(insn->attr)) { - case INAT_IMM_BYTE: - insn->immediate.value = get_next(char, insn); - insn->immediate.nbytes = 1; - break; - case INAT_IMM_WORD: - insn->immediate.value = get_next(short, insn); - insn->immediate.nbytes = 2; - break; - case INAT_IMM_DWORD: - insn->immediate.value = get_next(int, insn); - insn->immediate.nbytes = 4; - break; - case INAT_IMM_QWORD: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - insn->immediate2.value = get_next(int, insn); - insn->immediate2.nbytes = 4; - break; - case INAT_IMM_PTR: - if (!__get_immptr(insn)) - goto err_out; - break; - case INAT_IMM_VWORD32: - if (!__get_immv32(insn)) - goto err_out; - break; - case INAT_IMM_VWORD: - if (!__get_immv(insn)) - goto err_out; - break; - default: - /* Here, insn must have an immediate, but failed */ - goto err_out; - } - if (inat_has_second_immediate(insn->attr)) { - insn->immediate2.value = get_next(char, insn); - insn->immediate2.nbytes = 1; - } -done: - insn->immediate.got = 1; - -err_out: - return; -} - -/** - * insn_get_length() - Get the length of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * immediates bytes. - */ -void insn_get_length(struct insn *insn) -{ - if (insn->length) - return; - if (!insn->immediate.got) - insn_get_immediate(insn); - insn->length = (unsigned char)((unsigned long)insn->next_byte - - (unsigned long)insn->kaddr); -} diff --git a/kpatch-build/kpatch-build b/kpatch-build/kpatch-build deleted file mode 100755 index 3d77a67..0000000 --- a/kpatch-build/kpatch-build +++ /dev/null @@ -1,1466 +0,0 @@ -#!/bin/bash -# -# kpatch build script -# -# Copyright (C) 2014 Seth Jennings -# Copyright (C) 2013,2014 Josh Poimboeuf -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, -# 02110-1301, USA. - -# This script takes a patch based on the version of the kernel -# currently running and creates a kernel module that will -# replace modified functions in the kernel such that the -# patched code takes effect. - -# This script: -# - Either uses a specified kernel source directory or downloads the kernel -# source package for the currently running kernel -# - Unpacks and prepares the source package for building if necessary -# - Builds the base kernel or module -# - Builds the patched kernel/module and monitors changed objects -# - Builds the patched objects with gcc flags -f[function|data]-sections -# - Runs kpatch tools to create and link the patch kernel module - -set -o pipefail - -BASE="$PWD" -SCRIPTDIR="$(readlink -f "$(dirname "$(type -p "$0")")")" -ARCH="$(uname -m)" -CPUS="$(getconf _NPROCESSORS_ONLN)" -CACHEDIR="${CACHEDIR:-$HOME/.kpatch}" -KERNEL_SRCDIR="$CACHEDIR/src" -RPMTOPDIR="$CACHEDIR/buildroot" -VERSIONFILE="$CACHEDIR/version" -TEMPDIR="$CACHEDIR/tmp" -ENVFILE="$TEMPDIR/kpatch-build.env" -LOGFILE="$CACHEDIR/build.log" -RELEASE_FILE=/etc/os-release -DEBUG=0 -SKIPCLEANUP=0 -SKIPCOMPILERCHECK=0 -ARCH_KCFLAGS="" -DEBUG_KCFLAGS="" -declare -a PATCH_LIST -APPLIED_PATCHES=0 -OOT_MODULE= -KLP_REPLACE=0 -KPATCH_MODULE_ENABLE=0 - -GCC="${CROSS_COMPILE:-}gcc" -CLANG="${CROSS_COMPILE:-}clang" -LD="${CROSS_COMPILE:-}ld" -LLD="${CROSS_COMPILE:-}ld.lld" -READELF="${CROSS_COMPILE:-}readelf" -OBJCOPY="${CROSS_COMPILE:-}objcopy" - -warn() { - echo "ERROR: $1" >&2 -} - -die() { - if [[ -z "$1" ]]; then - msg="kpatch build failed" - else - msg="$1" - fi - - if [[ -e "$LOGFILE" ]]; then - warn "$msg. Check $LOGFILE for more details." - else - warn "$msg." - fi - - exit 1 -} - -logger() { - local to_stdout=${1:-0} - - if [[ $DEBUG -ge 2 ]] || [[ "$to_stdout" -eq 1 ]]; then - # Log to both stdout and the logfile - tee -a "$LOGFILE" - else - # Log only to the logfile - cat >> "$LOGFILE" - fi -} - -trace_on() { - if [[ $DEBUG -eq 1 ]] || [[ $DEBUG -ge 3 ]]; then - set -o xtrace - fi -} - -trace_off() { - if [[ $DEBUG -eq 1 ]] || [[ $DEBUG -ge 3 ]]; then - set +o xtrace - fi -} - -save_env() { - export -p | grep -wv -e 'OLDPWD=' -e 'PWD=' > "$ENVFILE" -} - -verify_patch_files() { - local path - local dir - local ret=0 - - for patch in "${PATCH_LIST[@]}"; do - for path in $(lsdiff "$patch" 2>/dev/null); do - - dir=$(dirname "$path") - ext="${path##*.}" - - if [[ "$dir" =~ ^lib$ ]] || [[ "$dir" =~ ^lib/ ]] ; then - warn "$patch: unsupported patch to lib/: $path" - ret=1 - fi - - if [[ "$ext" == "S" ]] ; then - warn "$patch: unsupported patch to assembly: $path" - ret=1 - fi - - done - done - - [[ $ret == 1 ]] && die "Unsupported changes detected" -} - -apply_patches() { - local patch - - for patch in "${PATCH_LIST[@]}"; do - patch -N -p1 --dry-run < "$patch" 2>&1 | logger || die "$patch file failed to apply" - patch -N -p1 < "$patch" 2>&1 | logger || die "$patch file failed to apply" - (( APPLIED_PATCHES++ )) - done -} - -remove_patches() { - local patch - local idx - - for (( ; APPLIED_PATCHES>0; APPLIED_PATCHES-- )); do - idx=$(( APPLIED_PATCHES - 1)) - patch="${PATCH_LIST[$idx]}" - patch -p1 -R -d "$BUILDDIR" < "$patch" &> /dev/null - done - - # If $BUILDDIR was a git repo, make sure git actually sees that - # we've reverted our patch(es). - [[ -d "$BUILDDIR/.git" ]] && (cd "$BUILDDIR" && git update-index -q --refresh) -} - -cleanup() { - rm -f "$BUILDDIR/.scmversion" - - remove_patches - - # restore original vmlinux if it was overwritten by sourcedir build - [[ -e "$TEMPDIR/vmlinux" ]] && mv -f "$TEMPDIR/vmlinux" "$KERNEL_SRCDIR/" - - # restore original link-vmlinux.sh if we updated it for the build - [[ -e "$TEMPDIR/link-vmlinux.sh" ]] && mv -f "$TEMPDIR/link-vmlinux.sh" "$KERNEL_SRCDIR/scripts" - - # restore original Makefile.modfinal if we updated it for the build - [[ -e "$TEMPDIR/Makefile.modfinal" ]] && mv -f "$TEMPDIR/Makefile.modfinal" "$KERNEL_SRCDIR/scripts" - - [[ "$DEBUG" -eq 0 ]] && rm -rf "$TEMPDIR" - rm -rf "$RPMTOPDIR" - unset KCFLAGS - unset KCPPFLAGS -} - -clean_cache() { - rm -rf "${CACHEDIR:?}"/* - mkdir -p "$TEMPDIR" || die "Couldn't create $TEMPDIR" -} - -check_pipe_status() { - rc="${PIPESTATUS[0]}" - if [[ "$rc" = 139 ]]; then - # There doesn't seem to be a consistent/portable way of - # accessing the last executed command in bash, so just - # pass in the script name for now.. - warn "$1 SIGSEGV" - if ls core* &> /dev/null; then - cp core* /tmp - die "core file at /tmp/$(ls core*)" - fi - die "There was a SIGSEGV, but no core dump was found in the current directory. Depending on your distro you might find it in /var/lib/systemd/coredump or /var/crash." - fi -} - -kernel_version_gte() { - [ "${ARCHVERSION//-*/}" = "$(echo -e "${ARCHVERSION//-*}\\n$1" | sort -rV | head -n1)" ] -} - -kernel_is_rhel() { - [[ "$ARCHVERSION" =~ \.el[789] ]] -} - -rhel_kernel_version_gte() { - [ "${ARCHVERSION}" = "$(echo -e "${ARCHVERSION}\\n$1" | sort -rV | head -n1)" ] -} - -# klp.arch relocations were supported prior to v5.8 -# and prior to 4.18.0-284.el8 -use_klp_arch() -{ - if kernel_is_rhel; then - ! rhel_kernel_version_gte 4.18.0-284.el8 - else - ! kernel_version_gte 5.8.0 - fi -} - -new_use_klp_arch() -{ - "$READELF" -s --wide "$VMLINUX" | grep -w "arch_klp_init_object_loaded" -} -klp_register_patch() -{ - "$READELF" -s --wide "$VMLINUX" | grep -w "klp_register_patch" -} - - -support_klp_replace() -{ - if kernel_is_rhel; then - rhel_kernel_version_gte 4.18.0-193.el8 - else - kernel_version_gte 5.1.0 - fi -} - -find_dirs() { - if [[ -e "$SCRIPTDIR/create-diff-object" ]]; then - # git repo - TOOLSDIR="$SCRIPTDIR" - DATADIR="$(readlink -f "$SCRIPTDIR/../kmod")" - PLUGINDIR="$(readlink -f "$SCRIPTDIR/gcc-plugins")" - elif [[ -e "$SCRIPTDIR/../libexec/kpatch/create-diff-object" ]]; then - # installation path - TOOLSDIR="$(readlink -f "$SCRIPTDIR/../libexec/kpatch")" - DATADIR="$(readlink -f "$SCRIPTDIR/../share/kpatch")" - PLUGINDIR="$TOOLSDIR" - else - return 1 - fi -} - -find_core_symvers() { - SYMVERSFILE="" - if [[ -e "$SCRIPTDIR/create-diff-object" ]]; then - # git repo - SYMVERSFILE="$DATADIR/core/Module.symvers" - elif [[ -e "$SCRIPTDIR/../libexec/kpatch/create-diff-object" ]]; then - # installation path - if [[ -e "$SCRIPTDIR/../lib/kpatch/$ARCHVERSION/Module.symvers" ]]; then - SYMVERSFILE="$(readlink -f "$SCRIPTDIR/../lib/kpatch/$ARCHVERSION/Module.symvers")" - elif [[ -e /lib/modules/$ARCHVERSION/extra/kpatch/Module.symvers ]]; then - SYMVERSFILE="$(readlink -f "/lib/modules/$ARCHVERSION/extra/kpatch/Module.symvers")" - fi - fi - - [[ -e "$SYMVERSFILE" ]] -} - -gcc_version_from_file() { - "$READELF" -p .comment "$1" | grep -m 1 -o 'GCC:.*'| cut -d ' ' -f 3- -} - -gcc_version_from_config() { - local gccver - if [[ -f "$CONFIGFILE" ]]; then - # Compiler: gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-4) - gccver="$(sed -n '/Compiler:/p' "$CONFIGFILE" | cut -d ' ' -f 5-)" - if [[ -z "$gccver" ]];then - #CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0" - gccver="$(sed -n '/CONFIG_CC_VERSION_TEXT/p' "$CONFIGFILE" | cut -d ' ' -f 3-)" - gccver=${gccver%\"*} - fi - fi - echo "$gccver" -} - -kernel_version_from_config() { - if [[ -f "$CONFIGFILE" ]]; then - sed -n '/Kernel Configuration/p' "$CONFIGFILE" | cut -d ' ' -f 3 - fi -} - -gcc_version_check() { - local target="$1" - local c="$TEMPDIR/test.c" o="$TEMPDIR/test.o" - local out gccver kgccver - - # gcc --version varies between distributions therefore extract version - # by compiling a test file and compare it to vmlinux's version. - echo 'void main(void) {}' > "$c" - out="$("$GCC" -c -pg -ffunction-sections -o "$o" "$c" 2>&1)" - gccver="$(gcc_version_from_file "$o")" - if [[ -f "$target" ]]; then - kgccver="$(gcc_version_from_file "$target")" - else - kgccver="$(gcc_version_from_config)" - fi - - if [[ -n "$out" ]]; then - warn "gcc >= 4.8 required for -pg -ffunction-settings" - echo "gcc output: $out" - return 1 - fi - - out="$("$GCC" -c -gz=none -o "$o" "$c" 2>&1)" - if [[ -z "$out" ]]; then - DEBUG_KCFLAGS="-gz=none" - fi - rm -f "$c" "$o" - - # ensure gcc version matches that used to build the kernel - if [[ "$gccver" != "$kgccver" ]]; then - warn "gcc/kernel version mismatch" - echo "gcc version: $gccver" - echo "kernel version: $kgccver" - echo "Install the matching gcc version (recommended) or use --skip-compiler-check" - echo "to skip the version matching enforcement (not recommended)" - return 1 - fi - - return -} - -clang_version_from_file() { - "$READELF" -p .comment "$1" | grep -m 1 -Eo 'clang version [0-9.]+' -} - -clang_version_check() { - local target="$1" - local clangver kclangver - - clangver=$("$CLANG" --version | grep -m 1 -Eo 'clang version [0-9.]+') - kclangver="$(clang_version_from_file "$target")" - - # ensure clang version matches that used to build the kernel - if [[ "$clangver" != "$kclangver" ]]; then - warn "clang/kernel version mismatch" - echo "clang version: $clangver" - echo "kernel version: $kclangver" - echo "Install the matching clang version (recommended) or use --skip-compiler-check" - echo "to skip the version matching enforcement (not recommended)" - return 1 - fi - - return -} - -find_special_section_data() { - local -A check - - # Common features across all arches - check[b]=true # bug_entry - check[e]=true # exception_table_entry - - # Arch-specific features, without kernel CONFIG_ toggle - case "$ARCH" in - "aarch64") - check[a]=true # alt_instr - ;; - "x86_64") - check[a]=true # alt_instr - kernel_version_gte 5.10.0 && check[s]=true # static_call_site - [[ -n "$CONFIG_PARAVIRT" ]] && check[p]=true # paravirt_patch_site - ;; - "ppc64le") - check[f]=true # fixup_entry - ;; - "s390x") - check[a]=true # alt_instr - ;; - esac - - # Kernel CONFIG_ features - [[ -n "$CONFIG_PRINTK_INDEX" ]] && check[i]=true # pi_entry - [[ -n "$CONFIG_JUMP_LABEL" ]] && check[j]=true # jump_entry - [[ -n "$CONFIG_UNWINDER_ORC" ]] && check[o]=true # orc_entry - - local c AWK_OPTIONS - for c in "${!check[@]}"; do - AWK_OPTIONS+=" -vcheck_${c}=1" - done - - local SPECIAL_VARS - # If $AWK_OPTIONS are blank gawk would treat "" as a blank script - # shellcheck disable=SC2086 - SPECIAL_VARS="$("$READELF" -wi "$VMLINUX" | - gawk --non-decimal-data $AWK_OPTIONS ' - BEGIN { a = b = e = f = i = j = o = p = s = 0 } - - # Set state if name matches - check_a && a == 0 && /DW_AT_name.* alt_instr[[:space:]]*$/ {a = 1; next} - check_b && b == 0 && /DW_AT_name.* bug_entry[[:space:]]*$/ {b = 1; next} - check_e && e == 0 && /DW_AT_name.* exception_table_entry[[:space:]]*$/ {e = 1; next} - check_f && f == 0 && /DW_AT_name.* fixup_entry[[:space:]]*$/ {f = 1; next} - check_i && i == 0 && /DW_AT_name.* pi_entry[[:space:]]*$/ {i = 1; next} - check_j && j == 0 && /DW_AT_name.* jump_entry[[:space:]]*$/ {j = 1; next} - check_o && o == 0 && /DW_AT_name.* orc_entry[[:space:]]*$/ {o = 1; next} - check_p && p == 0 && /DW_AT_name.* paravirt_patch_site[[:space:]]*$/ {p = 1; next} - check_s && s == 0 && /DW_AT_name.* static_call_site[[:space:]]*$/ {s = 1; next} - - # Reset state unless this abbrev describes the struct size - a == 1 && !/DW_AT_byte_size/ { a = 0; next } - b == 1 && !/DW_AT_byte_size/ { b = 0; next } - e == 1 && !/DW_AT_byte_size/ { e = 0; next } - f == 1 && !/DW_AT_byte_size/ { f = 0; next } - i == 1 && !/DW_AT_byte_size/ { i = 0; next } - j == 1 && !/DW_AT_byte_size/ { j = 0; next } - o == 1 && !/DW_AT_byte_size/ { o = 0; next } - p == 1 && !/DW_AT_byte_size/ { p = 0; next } - s == 1 && !/DW_AT_byte_size/ { s = 0; next } - - # Now that we know the size, stop parsing for it - a == 1 {printf("export ALT_STRUCT_SIZE=%d\n", $4); a = 2} - b == 1 {printf("export BUG_STRUCT_SIZE=%d\n", $4); b = 2} - e == 1 {printf("export EX_STRUCT_SIZE=%d\n", $4); e = 2} - f == 1 {printf("export FIXUP_STRUCT_SIZE=%d\n", $4); f = 2} - i == 1 {printf("export PRINTK_INDEX_STRUCT_SIZE=%d\n", $4); i = 2} - j == 1 {printf("export JUMP_STRUCT_SIZE=%d\n", $4); j = 2} - o == 1 {printf("export ORC_STRUCT_SIZE=%d\n", $4); o = 2} - p == 1 {printf("export PARA_STRUCT_SIZE=%d\n", $4); p = 2} - s == 1 {printf("export STATIC_CALL_STRUCT_SIZE=%d\n", $4); s = 2} - - # Bail out once we have everything - (!check_a || a == 2) && - (!check_b || b == 2) && - (!check_e || e == 2) && - (!check_f || f == 2) && - (!check_i || i == 2) && - (!check_j || j == 2) && - (!check_o || o == 2) && - (!check_p || p == 2) && - (!check_s || s == 2) {exit}')" - - [[ -n "$SPECIAL_VARS" ]] && eval "$SPECIAL_VARS" - - [[ ${check[a]} && -z "$ALT_STRUCT_SIZE" ]] && die "can't find special struct alt_instr size" - [[ ${check[b]} && -z "$BUG_STRUCT_SIZE" ]] && die "can't find special struct bug_entry size" - [[ ${check[e]} && -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct exception_table_entry size" - [[ ${check[f]} && -z "$FIXUP_STRUCT_SIZE" ]] && die "can't find special struct fixup_entry size" - [[ ${check[i]} && -z "$PRINTK_INDEX_STRUCT_SIZE" ]] && die "can't find special struct pi_entry size" - [[ ${check[j]} && -z "$JUMP_STRUCT_SIZE" ]] && die "can't find special struct jump_entry size" - [[ ${check[o]} && -z "$ORC_STRUCT_SIZE" ]] && die "can't find special struct orc_entry size" - [[ ${check[p]} && -z "$PARA_STRUCT_SIZE" ]] && die "can't find special struct paravirt_patch_site size" - [[ ${check[s]} && -z "$STATIC_CALL_STRUCT_SIZE" ]] && die "can't find special struct static_call_site size" - - save_env - return -} - -# path of file, relative to dir -# adapted from https://stackoverflow.com/a/24848739 -relpath() { - local file="$1" - local dir="$2" - - local filedir - local common - local result - - filedir="$(dirname "$(readlink -f "$file")")" - common="$(readlink -f "$dir")" - - if [[ "$filedir" = "$common" ]]; then - basename "$file" - return - fi - - while [[ "${filedir#$common/}" = "$filedir" ]]; do - common="$(dirname "$common")" - result="../$result" - done - - result="${result}${filedir#$common/}" - echo "${result}/$(basename "$file")" -} - -cmd_file_to_o_file() { - local parent="$1" - - # convert cmd file name to corresponding .o - parent_dir="$(dirname "$parent")" - parent_dir="${parent_dir#./}" - parent="$(basename "$parent")" - parent="${parent#.}" - parent="${parent%.cmd}" - parent="$parent_dir/$parent" - - [[ -f $parent ]] || die "can't find $parent associated with $1" - - echo "$parent" -} - -get_parent_from_parents() { - local parents=("$@") - - [[ ${#parents[@]} -eq 0 ]] && PARENT="" && return - [[ ${#parents[@]} -eq 1 ]] && PARENT="${parents[0]}" && return - - # multiple parents: - local parent - local mod_name="${parents[0]%.*}" - local mod_file - for parent in "${parents[@]}"; do - # for modules, there can be multiple matches. Some - # combination of foo.o, foo.mod, and foo.ko, depending - # on kernel version and whether the module is single or - # multi-object. Make sure a .mod and/or .ko exists, and no - # more than one .mod/.ko exists. - - [[ $parent = *.o ]] && continue - - if [[ ${parent%.*} != "$mod_name" ]]; then - mod_file="" - break - fi - - if [[ $parent = *.mod || $parent = *.ko ]]; then - mod_file=$parent - continue - fi - - mod_file="" - break - done - - if [[ -n $mod_file ]]; then - PARENT="$mod_file" - return - fi - - ERROR_IF_DIFF="multiple parent matches for $file: ${parents[*]}" - PARENT="${parents[0]}" -} - -__find_parent_obj_in_dir() { - local file="$1" - local dir="$2" - - declare -a parents - - while IFS='' read -r parent; do - parent="$(cmd_file_to_o_file "$parent")" - [[ $parent -ef $file ]] && continue - parents+=("$parent") - done < <(grep -El "[ ]${file/./\\.}([ \)]|$)" "$dir"/.*.cmd) - - get_parent_from_parents "${parents[@]}" -} - -find_parent_obj_in_dir() { - local file="$1" - local dir="$2" - - # make sure the dir has .cmd files - if ! compgen -G "$dir"/.*.cmd > /dev/null; then - PARENT="" - return - fi - - # 5.19+: ../acp/acp_hw.o - __find_parent_obj_in_dir "$(relpath "$file" "$dir")" "$dir" - [[ -n $PARENT ]] && return - - # pre-5.19 (and 5.19+ single-object modules): - if [[ $file == $dir* ]]; then - # arch/x86/kernel/smp.o - __find_parent_obj_in_dir "$file" "$dir" - else - # drivers/gpu/drm/amd/amdgpu/../acp/acp_hw.o - __find_parent_obj_in_dir "$dir"/"$(relpath "$file" "$dir")" "$dir" - fi -} - -find_parent_obj() { - local file="$1" - - # common case: look in same directory - find_parent_obj_in_dir "$file" "$(dirname "$file")" - [[ -n $PARENT ]] && return - - # if we previously had a successful deep find, try that dir first - if [[ -n "$LAST_DEEP_FIND_DIR" ]]; then - find_parent_obj_in_dir "$file" "$LAST_DEEP_FIND_DIR" - [[ -n "$PARENT" ]] && return - fi - - # prevent known deep finds - if [[ $file = drivers/gpu/drm/amd/* ]]; then - find_parent_obj_in_dir "$file" "drivers/gpu/drm/amd/amdgpu" - [[ -n "$PARENT" ]] && return - fi - if [[ $file = virt/kvm/* ]]; then - find_parent_obj_in_dir "$file" "arch/x86/kvm" - [[ -n "$PARENT" ]] && return - fi - if [[ $file = drivers/oprofile/* ]]; then - find_parent_obj_in_dir "$file" "arch/x86/oprofile" - [[ -n "$PARENT" ]] && return - fi - - # check higher-level dirs - local dir - dir="$(dirname "$file")" - while [[ ! $dir -ef . ]]; do - dir="$(dirname "$dir")" - find_parent_obj_in_dir "$file" "$dir" - [[ -n $PARENT ]] && return - done - - # slow path: search the entire tree ("deep find") - echo 'doing "deep find" for parent object' - declare -a parents - while IFS= read -r -d '' dir; do - find_parent_obj_in_dir "$file" "$dir" - if [[ -n $PARENT ]]; then - parents+=("$PARENT") - LAST_DEEP_FIND_DIR="$dir" - fi - done < <(find . -type d -print0) - - get_parent_from_parents "${parents[@]}" -} - -# find vmlinux or .ko associated with a .o file -find_kobj() { - local file="$1" - - if [[ -n $OOT_MODULE ]]; then - KOBJFILE="$OOT_MODULE" - return - fi - - KOBJFILE="$file" - ERROR_IF_DIFF= - while true; do - case "$KOBJFILE" in - *.mod) - KOBJFILE=${PARENT/.mod/.ko} - [[ -e $KOBJFILE ]] || die "can't find .ko for $PARENT" - return - ;; - *.ko) - return - ;; - */built-in.o|\ - */built-in.a|\ - arch/x86/kernel/ebda.o|\ - arch/x86/kernel/head*.o|\ - arch/x86/kernel/platform-quirks.o|\ - arch/x86/lib/lib.a|\ - lib/lib.a) - KOBJFILE=vmlinux - return - ;; - esac - - find_parent_obj "$KOBJFILE" - [[ -z "$PARENT" ]] && die "invalid ancestor $KOBJFILE for $file" - KOBJFILE="$PARENT" - done -} - -# Only allow alphanumerics and '_' and '-' in the module name. Everything else -# is replaced with '-'. Also truncate to 55 chars so the full name + NUL -# terminator fits in the kernel's 56-byte module name array. -module_name_string() { - echo "${1//[^a-zA-Z0-9_-]/-}" | cut -c 1-55 -} - -usage() { - echo "usage: $(basename "$0") [options] " >&2 - echo " patchN Input patchfile(s)" >&2 - echo " -h, --help Show this help message" >&2 - echo " -a, --archversion Specify the kernel arch version" >&2 - echo " -r, --sourcerpm Specify kernel source RPM" >&2 - echo " -s, --sourcedir Specify kernel source directory" >&2 - echo " -c, --config Specify kernel config file" >&2 - echo " -v, --vmlinux Specify original vmlinux" >&2 - echo " -j, --jobs Specify the number of make jobs" >&2 - echo " -t, --target Specify custom kernel build targets" >&2 - echo " -n, --name Specify the name of the kpatch module" >&2 - echo " -o, --output Specify output folder" >&2 - echo " -d, --debug Enable 'xtrace' and keep scratch files" >&2 - echo " in /tmp" >&2 - echo " (can be specified multiple times)" >&2 - echo " --oot-module Enable patching out-of-tree module," >&2 - echo " specify current version of module" >&2 - echo " --oot-module-src Specify out-of-tree module source directory" >&2 - echo " -R, --non-replace Disable replace patch (replace is on by default)" >&2 - echo " --skip-cleanup Skip post-build cleanup" >&2 - echo " --skip-compiler-check Skip compiler version matching check" >&2 - echo " (not recommended)" >&2 -} - -options="$(getopt -o ha:r:s:c:v:j:t:n:o:dR -l "help,archversion:,sourcerpm:,sourcedir:,config:,vmlinux:,jobs:,target:,name:,output:,oot-module:,oot-module-src:,debug,skip-gcc-check,skip-compiler-check,skip-cleanup,non-replace,use-kpatch-module" -- "$@")" || die "getopt failed" - -eval set -- "$options" - -while [[ $# -gt 0 ]]; do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -a|--archversion) - ARCHVERSION="$2" - shift - ;; - -r|--sourcerpm) - [[ ! -f "$2" ]] && die "source rpm '$2' not found" - SRCRPM="$(readlink -f "$2")" - shift - ;; - -s|--sourcedir) - [[ ! -d "$2" ]] && die "source dir '$2' not found" - USERSRCDIR="$(readlink -f "$2")" - shift - ;; - -c|--config) - [[ ! -f "$2" ]] && die "config file '$2' not found" - CONFIGFILE="$(readlink -f "$2")" - shift - ;; - -v|--vmlinux) - [[ ! -f "$2" ]] && die "vmlinux file '$2' not found" - VMLINUX="$(readlink -f "$2")" - shift - ;; - -j|--jobs) - [[ ! "$2" -gt 0 ]] && die "Invalid number of make jobs '$2'" - CPUS="$2" - shift - ;; - -t|--target) - TARGETS="$TARGETS $2" - shift - ;; - -n|--name) - MODNAME="$(module_name_string "$2")" - shift - ;; - -o|--output) - [[ ! -d "$2" ]] && die "output dir '$2' not found" - BASE="$(readlink -f "$2")" - shift - ;; - -d|--debug) - DEBUG=$((DEBUG + 1)) - if [[ $DEBUG -eq 1 ]]; then - echo "DEBUG mode enabled" - fi - ;; - --oot-module) - [[ ! -f "$2" ]] && die "out-of-tree module '$2' not found" - OOT_MODULE="$(readlink -f "$2")" - shift - ;; - --oot-module-src) - [[ ! -d "$2" ]] && die "out-of-tree module source dir '$2' not found" - OOT_MODULE_SRCDIR="$(readlink -f "$2")" - shift - ;; - -R|--non-replace) - KLP_REPLACE=0 - ;; - --skip-cleanup) - echo "Skipping cleanup" - SKIPCLEANUP=1 - ;; - --use-kpatch-module) - echo "Enable kpatch module" - KPATCH_MODULE_ENABLE=1 - ;; - --skip-gcc-check) - echo "DEPRECATED: --skip-gcc-check is deprecated, use --skip-compiler-check instead" - ;& - --skip-compiler-check) - echo "WARNING: Skipping compiler version matching check (not recommended)" - SKIPCOMPILERCHECK=1 - ;; - *) - [[ "$1" = "--" ]] && shift && continue - [[ ! -f "$1" ]] && die "patch file '$1' not found" - PATCH_LIST+=("$(readlink -f "$1")") - ;; - esac - shift -done - -if [[ ${#PATCH_LIST[@]} -eq 0 ]]; then - warn "no patch file(s) specified" - usage - exit 1 -fi - -trace_on - -if [[ -n "$SRCRPM" ]]; then - if [[ -n "$ARCHVERSION" ]]; then - warn "--archversion is incompatible with --sourcerpm" - exit 1 - fi - rpmname="$(basename "$SRCRPM")" - ARCHVERSION="${rpmname%.src.rpm}.$(uname -m)" - ARCHVERSION="${ARCHVERSION#kernel-}" - ARCHVERSION="${ARCHVERSION#alt-}" -fi - -if [[ -n "$OOT_MODULE" ]] && [[ -z "$OOT_MODULE_SRCDIR" ]]; then - warn "--oot-module requires --oot-module-src" - exit 1 -fi - -# ensure cachedir and tempdir are setup properly and cleaned -mkdir -p "$TEMPDIR" || die "Couldn't create $TEMPDIR" -rm -rf "${TEMPDIR:?}"/* -rm -f "$LOGFILE" - -if [[ -n "$USERSRCDIR" ]]; then - KERNEL_SRCDIR="$USERSRCDIR" - - [[ -z "$VMLINUX" ]] && VMLINUX="$KERNEL_SRCDIR"/vmlinux - # Extract the target kernel version from vmlinux in this case. - if [[ -f "$VMLINUX" ]]; then - VMLINUX_VER="$(strings "$VMLINUX" | grep -m 1 -e "^Linux version" | awk '{ print($3); }')" - fi - if [[ -n "$ARCHVERSION" ]]; then - if [[ -n "$VMLINUX_VER" ]] && [[ "$ARCHVERSION" != "$VMLINUX_VER" ]]; then - die "Kernel version mismatch: $ARCHVERSION was specified but vmlinux was built for $VMLINUX_VER" - fi - else - if [[ -z "$VMLINUX_VER" ]] && [[ -f "$VMLINUX" ]]; then - die "Unable to determine the kernel version from vmlinux" - fi - ARCHVERSION="$VMLINUX_VER" - if [[ -z "$ARCHVERSION" ]] && [[ -f "$CONFIGFILE" ]]; then - ARCHVERSION="$(kernel_version_from_config)" - fi - sed -i "s/^EXTRAVERSION.*/EXTRAVERSION = -${ARCHVERSION##*-}/" "$KERNEL_SRCDIR/Makefile" || die - fi -fi - -if [[ -n "$OOT_MODULE" ]]; then - ARCHVERSION="$(modinfo -F vermagic "$OOT_MODULE" | awk '{print $1}')" -fi - -[[ -z "$ARCHVERSION" ]] && ARCHVERSION="$(uname -r)" - -if [[ -n "$OOT_MODULE" ]]; then - if [[ -z "$USERSRCDIR" ]]; then - KERNEL_SRCDIR="/lib/modules/$ARCHVERSION/build/" - fi - BUILDDIR="$OOT_MODULE_SRCDIR" -else - BUILDDIR="$KERNEL_SRCDIR" -fi - -[[ "$SKIPCLEANUP" -eq 0 ]] && trap cleanup EXIT INT TERM HUP - -KVER="${ARCHVERSION%%-*}" -if [[ "$ARCHVERSION" =~ - ]]; then - KREL="${ARCHVERSION##*-}" - KREL="${KREL%.*}" -fi -[[ "$ARCHVERSION" =~ .el7a. ]] && ALT="-alt" - -[[ -z "$TARGETS" ]] && TARGETS="vmlinux modules" - -# Don't check external file. -# shellcheck disable=SC1090 -if [[ -z "$USERSRCDIR" ]] && [[ -f "$RELEASE_FILE" ]]; then - source "$RELEASE_FILE" - DISTRO="$ID" -fi - -if [[ "$DISTRO" = fedora ]] || [[ "$DISTRO" = rhel ]] || [[ "$DISTRO" = ol ]] || [[ "$DISTRO" = centos ]] || [[ "$DISTRO" = openEuler ]] || [[ "$DISTRO" = anolis ]]; then - [[ -z "$VMLINUX" ]] && VMLINUX="/usr/lib/debug/lib/modules/$ARCHVERSION/vmlinux" - [[ -e "$VMLINUX" ]] || die "kernel-debuginfo-$ARCHVERSION not installed" - - export PATH="/usr/lib64/ccache:$PATH" - -elif [[ "$DISTRO" = ubuntu ]] || [[ "$DISTRO" = debian ]]; then - [[ -z "$VMLINUX" ]] && VMLINUX="/usr/lib/debug/boot/vmlinux-$ARCHVERSION" - - if [[ "$DISTRO" = ubuntu ]]; then - [[ -e "$VMLINUX" ]] || die "linux-image-$ARCHVERSION-dbgsym not installed" - - elif [[ "$DISTRO" = debian ]]; then - [[ -e "$VMLINUX" ]] || die "linux-image-$ARCHVERSION-dbg not installed" - fi - - export PATH="/usr/lib/ccache:$PATH" -fi -save_env - -find_dirs || die "can't find supporting tools" - -if [[ -n "$USERSRCDIR" ]]; then - echo "Using source directory at $USERSRCDIR" - - # save original vmlinux before it gets overwritten by sourcedir build - if [[ "$VMLINUX" -ef "$KERNEL_SRCDIR"/vmlinux ]]; then - cp -f "$VMLINUX" "$TEMPDIR/vmlinux" || die - VMLINUX="$TEMPDIR/vmlinux" - fi -elif [[ -n "$OOT_MODULE" ]]; then - if [[ -z "${CONFIGFILE}" ]]; then - CONFIGFILE="/boot/config-${ARCHVERSION}" - fi -elif [[ -e "$KERNEL_SRCDIR"/.config ]] && [[ -e "$VERSIONFILE" ]] && [[ "$(cat "$VERSIONFILE")" = "$ARCHVERSION" ]]; then - echo "Using cache at $KERNEL_SRCDIR" - -else - if [[ "$DISTRO" = fedora ]] || [[ "$DISTRO" = rhel ]] || [[ "$DISTRO" = ol ]] || [[ "$DISTRO" = centos ]] || [[ "$DISTRO" = openEuler ]] || [[ "$DISTRO" = anolis ]]; then - - [[ "$DISTRO" = fedora ]] && echo "Fedora distribution detected" - [[ "$DISTRO" = rhel ]] && echo "RHEL distribution detected" - [[ "$DISTRO" = ol ]] && echo "Oracle Linux distribution detected" - [[ "$DISTRO" = centos ]] && echo "CentOS distribution detected" - [[ "$DISTRO" = openEuler ]] && echo "OpenEuler distribution detected" - [[ "$DISTRO" = anolis ]] && echo "Anolis distribution detected" - - clean_cache - - echo "Downloading kernel source for $ARCHVERSION" - if [[ -z "$SRCRPM" ]]; then - if [[ "$DISTRO" = fedora ]]; then - wget -P "$TEMPDIR" "http://kojipkgs.fedoraproject.org/packages/kernel/$KVER/$KREL/src/kernel-$KVER-$KREL.src.rpm" 2>&1 | logger || die - else - command -v yumdownloader &>/dev/null || die "yumdownloader (yum-utils or dnf-utils) not installed" - yumdownloader --source --destdir "$TEMPDIR" "kernel$ALT-$KVER-$KREL" 2>&1 | logger || die - fi - SRCRPM="$TEMPDIR/kernel$ALT-$KVER-$KREL.src.rpm" - fi - - echo "Unpacking kernel source" - - rpm -D "_topdir $RPMTOPDIR" -ivh "$SRCRPM" 2>&1 | logger || die - rpmbuild -D "_topdir $RPMTOPDIR" -bp --nodeps "--target=$(uname -m)" "$RPMTOPDIR"/SPECS/kernel$ALT.spec 2>&1 | logger || - die "rpmbuild -bp failed. you may need to run 'yum-builddep kernel' first." - - if [[ "$DISTRO" = openEuler ]]; then - # openEuler has two directories with the same content after 'rpm -D' - # openEuler 21.09 has linux-* and linux-*-source while openEuler 20.03 has linux-* and linux-*-Source - mv "$RPMTOPDIR"/BUILD/kernel-*/linux-*[sS]ource "$KERNEL_SRCDIR" 2>&1 | logger || die - else - mv "$RPMTOPDIR"/BUILD/kernel-*/linux-* "$KERNEL_SRCDIR" 2>&1 | logger || die - fi - rm -rf "$RPMTOPDIR" - rm -rf "$KERNEL_SRCDIR/.git" - - if [[ "$ARCHVERSION" == *-* ]]; then - sed -i "s/^EXTRAVERSION.*/EXTRAVERSION = -${ARCHVERSION##*-}/" "$KERNEL_SRCDIR/Makefile" || die - fi - - echo "$ARCHVERSION" > "$VERSIONFILE" || die - - if [[ "$DISTRO" = openEuler ]]; then - [[ -z "$CONFIGFILE" ]] && CONFIGFILE="/boot/config-${ARCHVERSION}" - else - [[ -z "$CONFIGFILE" ]] && CONFIGFILE="$KERNEL_SRCDIR/configs/kernel$ALT-$KVER-$ARCH.config" - fi - - (cd "$KERNEL_SRCDIR" && make mrproper 2>&1 | logger) || die - - elif [[ "$DISTRO" = ubuntu ]] || [[ "$DISTRO" = debian ]]; then - - echo "Debian/Ubuntu distribution detected" - - if [[ "$DISTRO" = ubuntu ]]; then - - # url may be changed for a different mirror - url="http://archive.ubuntu.com/ubuntu/pool/main/l" - sublevel="SUBLEVEL = 0" - - elif [[ "$DISTRO" = debian ]]; then - - # url may be changed for a different mirror - url="http://ftp.debian.org/debian/pool/main/l" - sublevel="SUBLEVEL =" - fi - - pkgname="$(dpkg-query -W -f='${Source}' "linux-image-$ARCHVERSION" | sed s/-signed//)" - pkgver="$(dpkg-query -W -f='${Version}' "linux-image-$ARCHVERSION")" - dscname="${pkgname}_${pkgver}.dsc" - - clean_cache - - cd "$TEMPDIR" || die - echo "Downloading and unpacking the kernel source for $ARCHVERSION" - # Download source deb pkg - (dget -u "$url/${pkgname}/${dscname}" 2>&1) | logger || die "dget: Could not fetch/unpack $url/${pkgname}/${dscname}" - mv "${pkgname}-$KVER" "$KERNEL_SRCDIR" || die - [[ -z "$CONFIGFILE" ]] && CONFIGFILE="/boot/config-${ARCHVERSION}" - if [[ "$ARCHVERSION" == *-* ]]; then - echo "-${ARCHVERSION#*-}" > "$KERNEL_SRCDIR/localversion" || die - fi - # for some reason the Ubuntu kernel versions don't follow the - # upstream SUBLEVEL; they are always at SUBLEVEL 0 - sed -i "s/^SUBLEVEL.*/${sublevel}/" "$KERNEL_SRCDIR/Makefile" || die - echo "$ARCHVERSION" > "$VERSIONFILE" || die - - else - die "Unsupported distribution" - fi -fi - -[[ -z "$CONFIGFILE" ]] && CONFIGFILE="$KERNEL_SRCDIR"/.config -[[ ! -e "$CONFIGFILE" ]] && die "can't find config file" -if [[ -z "$OOT_MODULE" && ! "$CONFIGFILE" -ef "$KERNEL_SRCDIR"/.config ]] ; then - cp -f "$CONFIGFILE" "$KERNEL_SRCDIR/.config" || die -fi - -# kernel option checking - -trace_off "reading .config" -# Don't check external file. -# shellcheck disable=SC1090 -source "$CONFIGFILE" -trace_on - -[[ "$DISTRO" = openEuler ]] && [[ -z "$CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY" ]] && \ - die "openEuler kernel doesn't have 'CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY' enabled" - -[[ -z "$CONFIG_DEBUG_INFO" ]] && die "kernel doesn't have 'CONFIG_DEBUG_INFO' enabled" -[[ "$ARCH" = "s390x" ]] && [[ -z "$CONFIG_EXPOLINE_EXTERN" ]] && [[ -n "$CONFIG_EXPOLINE" ]] && die "kernel doesn't have 'CONFIG_EXPOLINE_EXTERN' enabled" - -# Build variables - Set some defaults, then adjust features -# according to .config and kernel version -KPATCH_LDFLAGS="" -USE_KLP=0 -USE_KLP_ARCH=0 - -# support kpatch module when user want kpatch module in greater version of kernel -if [[ $KPATCH_MODULE_ENABLE -eq 0 ]] && [[ -n "$CONFIG_LIVEPATCH" ]] && (kernel_is_rhel || kernel_version_gte 4.9.0); then - - USE_KLP=1 - - if [[ "$KLP_REPLACE" -eq 1 ]] ; then - support_klp_replace || die "The kernel doesn't support klp replace" - else - export CFLAGS_MODULE="$CFLAGS_MODULE -DKLP_REPLACE_ENABLE=false" - fi -else - # No support for livepatch in the kernel. Kpatch core module is needed. - - # There may be ordering bugs, with jump labels and other special - # sections. Use with caution! - echo "WARNING: Use of kpatch core module (kpatch.ko) is deprecated! There may be bugs!" >&2 - - find_core_symvers || die "unable to find Module.symvers for kpatch core module" - KBUILD_EXTRA_SYMBOLS="$SYMVERSFILE" -fi - -# unsupported kernel option checking -[[ -n "$CONFIG_DEBUG_INFO_SPLIT" ]] && die "kernel option 'CONFIG_DEBUG_INFO_SPLIT' not supported" -[[ -n "$CONFIG_GCC_PLUGIN_LATENT_ENTROPY" ]] && die "kernel option 'CONFIG_GCC_PLUGIN_LATENT_ENTROPY' not supported" -[[ -n "$CONFIG_GCC_PLUGIN_RANDSTRUCT" ]] && die "kernel option 'CONFIG_GCC_PLUGIN_RANDSTRUCT' not supported" - -# CONFIG_DEBUG_INFO_BTF invokes pahole, for which some versions don't -# support extended ELF sections. Disable the BTF typeinfo generation in -# link-vmlinux.sh and Makefile.modfinal since kpatch doesn't care about -# that anyway. -if [[ -n "$CONFIG_DEBUG_INFO_BTF" ]]; then - cp -f "$KERNEL_SRCDIR/scripts/link-vmlinux.sh" "$TEMPDIR/link-vmlinux.sh" || die - sed -i 's/CONFIG_DEBUG_INFO_BTF/DISABLED_FOR_KPATCH_BUILD/g' "$KERNEL_SRCDIR"/scripts/link-vmlinux.sh || die - - if [[ -e "$KERNEL_SRCDIR/scripts/Makefile.modfinal" ]]; then - cp -f "$KERNEL_SRCDIR/scripts/Makefile.modfinal" "$TEMPDIR/Makefile.modfinal" || die - sed -i 's/CONFIG_DEBUG_INFO_BTF_MODULES/DISABLED_FOR_KPATCH_BUILD/g' "$KERNEL_SRCDIR"/scripts/Makefile.modfinal || die - fi -fi - -if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then - echo "WARNING: Clang support is experimental" -fi - -if [[ "$SKIPCOMPILERCHECK" -eq 0 ]]; then - if [[ -n "$OOT_MODULE" ]]; then - target="$OOT_MODULE" - else - target="$VMLINUX" - fi - if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then - clang_version_check "$target" || die - else - gcc_version_check "$target" || die - fi -fi - -echo "Testing patch file(s)" -cd "$BUILDDIR" || die -verify_patch_files -apply_patches -remove_patches - -cp -LR "$DATADIR/patch" "$TEMPDIR" || die - -if [[ "$ARCH" = "ppc64le" ]]; then - ARCH_KCFLAGS="-mcmodel=large -fplugin=$PLUGINDIR/ppc64le-plugin.so" -fi - -if [[ "$ARCH" = "s390x" ]]; then - ARCH_KCFLAGS="-mno-pic-data-is-text-relative -fno-section-anchors" -fi - -export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections -fno-reorder-functions \ - $ARCH_KCFLAGS $DEBUG_KCFLAGS" - - -if [[ $DEBUG -ge 4 ]]; then - export KPATCH_GCC_DEBUG=1 -fi -save_env - -echo "Building original source" -[[ -n "$OOT_MODULE" ]] || ./scripts/setlocalversion --save-scmversion || die -unset KPATCH_GCC_TEMPDIR - -KPATCH_CC_PREFIX="$TOOLSDIR/kpatch-cc " -declare -a MAKEVARS -if [[ -n "$CONFIG_CC_IS_CLANG" ]]; then - MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${CLANG}") - MAKEVARS+=("HOSTCC=clang") -else - MAKEVARS+=("CC=${KPATCH_CC_PREFIX}${GCC}") -fi - -if [[ -n "$CONFIG_LD_IS_LLD" ]]; then - MAKEVARS+=("LD=${KPATCH_CC_PREFIX}${LLD}") - MAKEVARS+=("HOSTLD=ld.lld") -else - MAKEVARS+=("LD=${KPATCH_CC_PREFIX}${LD}") -fi - - -# $TARGETS used as list, no quotes. -# shellcheck disable=SC2086 -make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die - -if [[ -n "$CONFIG_LIVEPATCH" ]] && [[ $USE_KLP -eq 1 ]]; then - if new_use_klp_arch; then - USE_KLP_ARCH=1 - KPATCH_LDFLAGS="--unique=.parainstructions --unique=.altinstructions" - CDO_FLAGS="--klp-arch" - fi - if klp_register_patch; then - echo "use klp_register_patch" - else - echo "don't use klp_register_patch" - export CFLAGS_MODULE="$CFLAGS_MODULE -DHAVE_SIMPLE_ENABLE" - fi -fi - -echo "Reading special section data" -find_special_section_data - -# Save original module symvers -cp -f "$BUILDDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die - -echo "Building patched source" -apply_patches -mkdir -p "$TEMPDIR/orig" "$TEMPDIR/patched" -export KPATCH_GCC_TEMPDIR="$TEMPDIR" -export KPATCH_GCC_SRCDIR="$BUILDDIR" -save_env -# $TARGETS used as list, no quotes. -# shellcheck disable=SC2086 -KBUILD_MODPOST_WARN=1 make "${MAKEVARS[@]}" "-j$CPUS" $TARGETS 2>&1 | logger || die - -# source.c:(.section+0xFF): undefined reference to `symbol' -grep "undefined reference" "$LOGFILE" | sed -r "s/^.*\`(.*)'$/\\1/" \ - >"${TEMPDIR}"/undefined_references - -# WARNING: "symbol" [path/to/module.ko] undefined! -grep "undefined!" "$LOGFILE" | cut -d\" -f2 >>"${TEMPDIR}"/undefined_references - -if [[ ! -e "$TEMPDIR/changed_objs" ]]; then - die "no changed objects found" -fi - -grep -q vmlinux "$KERNEL_SRCDIR/Module.symvers" || die "truncated $KERNEL_SRCDIR/Module.symvers file" - -if [[ -n "$CONFIG_MODVERSIONS" ]]; then - trace_off "reading Module.symvers" - while read -ra sym_line; do - if [[ ${#sym_line[@]} -lt 4 ]]; then - die "Malformed ${TEMPDIR}/Module.symvers file" - fi - - sym=${sym_line[1]} - - read -ra patched_sym_line <<< "$(grep "\s$sym\s" "$BUILDDIR/Module.symvers")" - if [[ ${#patched_sym_line[@]} -lt 4 ]]; then - die "Malformed symbol entry for ${sym} in ${BUILDDIR}/Module.symvers file" - fi - - # Assume that both original and patched symvers have the same format. - # In both cases, the symbol should have the same CRC, belong to the same - # Module/Namespace and have the same export type. - if [[ ${#sym_line[@]} -ne ${#patched_sym_line[@]} || \ - "${sym_line[*]}" != "${patched_sym_line[*]}" ]]; then - warn "Version disagreement for symbol ${sym}" - fi - done < "${TEMPDIR}/Module.symvers" - trace_on -fi - -# Read as words, no quotes. -# shellcheck disable=SC2013 -for i in $(cat "$TEMPDIR/changed_objs") -do - mkdir -p "$TEMPDIR/patched/$(dirname "$i")" || die - cp -f "$BUILDDIR/$i" "$TEMPDIR/patched/$i" || die -done - -echo "Extracting new and modified ELF sections" -# If no kpatch module name was provided on the command line: -# - For single input .patch, use the patch filename -# - For multiple input .patches, use "patch" -# - Prefix with "kpatch" or "livepatch" accordingly -if [[ -z "$MODNAME" ]] ; then - if [[ "${#PATCH_LIST[@]}" -eq 1 ]]; then - MODNAME="$(basename "${PATCH_LIST[0]}")" - if [[ "$MODNAME" =~ \.patch$ ]] || [[ "$MODNAME" =~ \.diff$ ]]; then - MODNAME="${MODNAME%.*}" - fi - else - MODNAME="patch" - fi - - if [[ "$USE_KLP" -eq 1 ]]; then - MODNAME="livepatch-$MODNAME" - else - MODNAME="kpatch-$MODNAME" - fi - - MODNAME="$(module_name_string "$MODNAME")" -fi -FILES="$(cat "$TEMPDIR/changed_objs")" -cd "$TEMPDIR" || die -mkdir output -declare -a objnames -CHANGED=0 -ERROR=0 - -# Prepare OOT module symvers file -if [[ -n "$OOT_MODULE" ]]; then - cp -f "$OOT_MODULE_SRCDIR/Module.symvers" "$TEMPDIR/Module.symvers" || die - awk '{ print $1 "\t" $2 "\t" $3 "\t" $4}' "${KERNEL_SRCDIR}/Module.symvers" >> "$TEMPDIR/Module.symvers" -fi - -for i in $FILES; do - # In RHEL 7 based kernels, copy_user_64.o misuses the .fixup section, - # which confuses create-diff-object. It's fine to skip it, it's an - # assembly file anyway. - [[ "$DISTRO" = rhel ]] || [[ "$DISTRO" = centos ]] || [[ "$DISTRO" = ol ]] && \ - [[ "$i" = arch/x86/lib/copy_user_64.o ]] && continue - - [[ "$i" = usr/initramfs_data.o ]] && continue - - mkdir -p "output/$(dirname "$i")" - cd "$BUILDDIR" || die - find_kobj "$i" - cd "$TEMPDIR" || die - if [[ -e "orig/$i" ]]; then - if [[ -n $OOT_MODULE ]]; then - KOBJFILE_NAME="$(basename --suffix=.ko "$OOT_MODULE")" - KOBJFILE_NAME="${KOBJFILE_NAME//-/_}" - KOBJFILE_PATH="$OOT_MODULE" - SYMTAB="${TEMPDIR}/module/${KOBJFILE_NAME}.symtab" - SYMVERS_FILE="$TEMPDIR/Module.symvers" - elif [[ "$(basename "$KOBJFILE")" = vmlinux ]]; then - KOBJFILE_NAME=vmlinux - KOBJFILE_PATH="$VMLINUX" - SYMTAB="${TEMPDIR}/${KOBJFILE_NAME}.symtab" - SYMVERS_FILE="$BUILDDIR/Module.symvers" - else - KOBJFILE_NAME=$(basename "${KOBJFILE%.ko}") - KOBJFILE_NAME="${KOBJFILE_NAME//-/_}" - KOBJFILE_PATH="${TEMPDIR}/module/$KOBJFILE" - SYMTAB="${KOBJFILE_PATH}.symtab" - SYMVERS_FILE="$BUILDDIR/Module.symvers" - fi - - "$READELF" -s --wide "$KOBJFILE_PATH" > "$SYMTAB" - if [[ "$ARCH" = "ppc64le" ]]; then - sed -ri 's/\s+\[: 8\]//' "$SYMTAB" - fi - - # create-diff-object orig.o patched.o parent-name parent-symtab - # Module.symvers patch-mod-name output.o - "$TOOLSDIR"/create-diff-object $CDO_FLAGS "orig/$i" "patched/$i" "$KOBJFILE_NAME" \ - "$SYMTAB" "$SYMVERS_FILE" "${MODNAME//-/_}" \ - "output/$i" 2>&1 | logger 1 - check_pipe_status create-diff-object - # create-diff-object returns 3 if no functional change is found - [[ "$rc" -eq 0 ]] || [[ "$rc" -eq 3 ]] || ERROR="$((ERROR + 1))" - if [[ "$rc" -eq 0 ]]; then - [[ -n "$ERROR_IF_DIFF" ]] && die "$ERROR_IF_DIFF" - CHANGED=1 - objnames[${#objnames[@]}]="$KOBJFILE" - fi - else - cp -f "patched/$i" "output/$i" || die - objnames[${#objnames[@]}]="$KOBJFILE" - fi -done - -if [[ "$ERROR" -ne 0 ]]; then - die "$ERROR error(s) encountered" -fi - -if [[ "$CHANGED" -eq 0 ]]; then - die "no functional changes found" -fi - -echo -n "Patched objects:" -for i in $(echo "${objnames[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ') -do - echo -n " $i" -done -echo - -export KCFLAGS="-I$DATADIR/patch $ARCH_KCFLAGS" -if [[ "$USE_KLP" -eq 0 ]]; then - export KCPPFLAGS="-D__KPATCH_MODULE__" -fi -save_env - -echo "Building patch module: $MODNAME.ko" - -if [[ -z "$USERSRCDIR" ]] && [[ "$DISTRO" = ubuntu ]]; then - # UBUNTU: add UTS_UBUNTU_RELEASE_ABI to utsrelease.h after regenerating it - UBUNTU_ABI="${ARCHVERSION#*-}" - UBUNTU_ABI="${UBUNTU_ABI%-*}" - echo "#define UTS_UBUNTU_RELEASE_ABI $UBUNTU_ABI" >> "$KERNEL_SRCDIR"/include/generated/utsrelease.h -fi - -cd "$TEMPDIR/output" || die -# $KPATCH_LDFLAGS and result of find used as list, no quotes. -# shellcheck disable=SC2086,SC2046 -"$LD" -r $KPATCH_LDFLAGS -o ../patch/tmp_output.o $(find . -name "*.o") 2>&1 | logger || die - -if [[ "$USE_KLP" -eq 1 ]]; then - cp -f "$TEMPDIR"/patch/tmp_output.o "$TEMPDIR"/patch/output.o || die - # Avoid MODPOST warning (pre-v5.8) and error (v5.8+) with an empty .cmd file - touch "$TEMPDIR"/patch/.output.o.cmd || die -else - # Add .kpatch.checksum for kpatch script - echo "Addind .kpatch.checksum" - md5sum ../patch/tmp_output.o | awk '{printf "%s\0", $1}' > checksum.tmp || die - "$OBJCOPY" --add-section .kpatch.checksum=checksum.tmp --set-section-flags .kpatch.checksum=alloc,load,contents,readonly ../patch/tmp_output.o || die - rm -f checksum.tmp - "$TOOLSDIR"/create-kpatch-module "$TEMPDIR"/patch/tmp_output.o "$TEMPDIR"/patch/output.o 2>&1 | logger 1 - check_pipe_status create-kpatch-module - [[ "$rc" -ne 0 ]] && die "create-kpatch-module: exited with return code: $rc" -fi - -cd "$TEMPDIR/patch" || die - -# We no longer need kpatch-cc -for ((idx=0; idx<${#MAKEVARS[@]}; idx++)); do - MAKEVARS[$idx]=${MAKEVARS[$idx]/${KPATCH_CC_PREFIX}/} -done - -export KPATCH_BUILD="$KERNEL_SRCDIR" KPATCH_NAME="$MODNAME" \ -KBUILD_EXTRA_SYMBOLS="$KBUILD_EXTRA_SYMBOLS" \ -KPATCH_LDFLAGS="$KPATCH_LDFLAGS" \ -CROSS_COMPILE="$CROSS_COMPILE" -save_env - - -if [[ $USE_KLP -eq 1 ]]; then - export CFLAGS_MODULE=$CFLAGS_MODULE" -DUSE_KLP=1" -else - export CFLAGS_MODULE=$CFLAGS_MODULE" -DUSE_KLP=0" -fi - -make "${MAKEVARS[@]}" 2>&1 | logger || die - -if [[ "$USE_KLP" -eq 1 ]]; then - if [[ "$USE_KLP_ARCH" -eq 0 ]]; then - extra_flags="--no-klp-arch-sections" - fi - cp -f "$TEMPDIR/patch/$MODNAME.ko" "$TEMPDIR/patch/tmp.ko" || die - "$TOOLSDIR"/create-klp-module $extra_flags "$TEMPDIR/patch/tmp.ko" "$TEMPDIR/patch/$MODNAME.ko" 2>&1 | logger 1 - check_pipe_status create-klp-module - [[ "$rc" -ne 0 ]] && die "create-klp-module: exited with return code: $rc" -fi - -if [[ -n "$CONFIG_MODVERSIONS" ]]; then - # Check that final module does not reference symbols with different version - # than the target kernel - KP_MOD_VALID=true - # shellcheck disable=SC2086 - while read -ra mod_symbol; do - if [[ ${#mod_symbol[@]} -lt 2 ]]; then - continue - fi - - # Check if the symbol exists in the old Module.symvers, and if it does - # check that the CRCs are unchanged. - if ! awk -v sym="${mod_symbol[1]}" -v crc="${mod_symbol[0]}" \ - '$2==sym && $1!=crc { exit 1 }' "$TEMPDIR/Module.symvers"; then - warn "Patch module references ${mod_symbol[1]} with invalid version" - KP_MOD_VALID=false - fi - done <<< "$(modprobe --dump-modversions $TEMPDIR/patch/$MODNAME.ko)" - if ! $KP_MOD_VALID; then - die "Patch module referencing altered exported kernel symbols cannot be loaded" - fi -fi - -"$READELF" --wide --symbols "$TEMPDIR/patch/$MODNAME.ko" 2>/dev/null | \ - sed -r 's/\s+\[: 8\]//' | \ - awk '($4=="FUNC" || $4=="OBJECT") && ($5=="GLOBAL" || $5=="WEAK") && $7!="UND" {print $NF}' \ - >"${TEMPDIR}"/new_symbols - -if [[ "$USE_KLP" -eq 0 ]]; then - cat >>"${TEMPDIR}"/new_symbols <<-EOF - kpatch_shadow_free - kpatch_shadow_alloc - kpatch_register - kpatch_shadow_get - kpatch_unregister - kpatch_root_kobj - EOF -fi - -# Compare undefined_references and new_symbols files and print only the first -# column containing lines unique to first file. -UNDEFINED=$(comm -23 <(sort -u "${TEMPDIR}"/undefined_references) \ - <(sort -u "${TEMPDIR}"/new_symbols) | tr '\n' ' ') -[[ -n "$UNDEFINED" ]] && die "Undefined symbols: $UNDEFINED" - -cp -f "$TEMPDIR/patch/$MODNAME.ko" "$BASE" || die - -[[ "$DEBUG" -eq 0 && "$SKIPCLEANUP" -eq 0 ]] && rm -f "$LOGFILE" - -echo "SUCCESS" diff --git a/kpatch-build/kpatch-cc b/kpatch-build/kpatch-cc deleted file mode 100755 index 44f83d5..0000000 --- a/kpatch-build/kpatch-cc +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/bash - -if [[ ${KPATCH_GCC_DEBUG:-0} -ne 0 ]]; then - set -o xtrace -fi - -TOOLCHAINCMD="$1" -shift - -if [[ -z "$KPATCH_GCC_TEMPDIR" ]]; then - exec "$TOOLCHAINCMD" "$@" -fi - -declare -a args=("$@") - -if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; then - while [ "$#" -gt 0 ]; do - if [ "$1" = "-o" ]; then - obj="$2" - - # skip copying the temporary .o files created by - # recordmcount.pl - [[ "$obj" = */.tmp_mc_*.o ]] && break; - - [[ "$obj" = */.tmp_*.o ]] && obj="${obj/.tmp_/}" - relobj=${obj##$KPATCH_GCC_SRCDIR/} - case "$relobj" in - *.mod.o|\ - *built-in.o|\ - *built-in.a|\ - vmlinux.o|\ - .tmp_kallsyms1.o|\ - .tmp_kallsyms2.o|\ - arch/x86/boot/*|\ - arch/x86/entry/vdso/*|\ - arch/x86/purgatory/*|\ - arch/x86/realmode/*|\ - arch/x86/tools/*|\ - arch/x86/vdso/*|\ - arch/powerpc/kernel/prom_init.o|\ - arch/powerpc/kernel/vdso64/*|\ - arch/s390/boot/*|\ - arch/s390/purgatory/*|\ - arch/s390/kernel/vdso64/*|\ - arch/arm64/kernel/vdso*/*|\ - drivers/firmware/efi/libstub/*|\ - init/version.o|\ - kernel/system_certificates.o|\ - lib/*|\ - tools/*|\ - .*.o|\ - */.lib_exports.o) - break - ;; - *.o) - mkdir -p "$KPATCH_GCC_TEMPDIR/orig/$(dirname "$relobj")" - [[ -e "$obj" ]] && cp -f "$obj" "$KPATCH_GCC_TEMPDIR/orig/$relobj" - echo "$relobj" >> "$KPATCH_GCC_TEMPDIR/changed_objs" - break - ;; - *) - break - ;; - esac - fi - shift - done -elif [[ "$TOOLCHAINCMD" =~ ^(.*-)?ld || "$TOOLCHAINCMD" =~ ^(.*-)?ld.lld ]] ; then - while [ "$#" -gt 0 ]; do - if [ "$1" = "-o" ]; then - obj="$2" - relobj=${obj//$KPATCH_GCC_SRCDIR\//} - case "$obj" in - *.ko) - mkdir -p "$KPATCH_GCC_TEMPDIR/module/$(dirname "$relobj")" - cp -f "$obj" "$KPATCH_GCC_TEMPDIR/module/$relobj" - break - ;; - .tmp_vmlinux*|vmlinux) - args+=(--warn-unresolved-symbols) - break - ;; - *) - break - ;; - esac - fi - shift - done -fi - -exec "$TOOLCHAINCMD" "${args[@]}" diff --git a/kpatch-build/kpatch-elf.c b/kpatch-build/kpatch-elf.c deleted file mode 100755 index 3cfc89a..0000000 --- a/kpatch-build/kpatch-elf.c +++ /dev/null @@ -1,1069 +0,0 @@ -/* - * kpatch-elf.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -/* - * This file provides a common api to create, inspect, and manipulate - * kpatch_elf objects. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "asm/insn.h" -#include "kpatch-elf.h" - -/******************* - * Helper functions - ******************/ - -char *status_str(enum status status) -{ - switch(status) { - case NEW: - return "NEW"; - case CHANGED: - return "CHANGED"; - case SAME: - return "SAME"; - default: - ERROR("status_str"); - } - /* never reached */ - return NULL; -} - -bool is_rela_section(struct section *sec) -{ - return (sec->sh.sh_type == SHT_RELA); -} - -bool is_text_section(struct section *sec) -{ - return (sec->sh.sh_type == SHT_PROGBITS && - (sec->sh.sh_flags & SHF_EXECINSTR)); -} - -bool is_debug_section(struct section *sec) -{ - char *name; - if (is_rela_section(sec)) - name = sec->base->name; - else - name = sec->name; - - return !strncmp(name, ".debug_", 7) || - !strncmp(name, ".eh_frame", 9); -} - -struct section *find_section_by_index(struct list_head *list, unsigned int index) -{ - struct section *sec; - - list_for_each_entry(sec, list, list) - if (sec->index == index) - return sec; - - return NULL; -} - -struct section *find_nth_section_by_name( - struct list_head *list, int nth, - const char *name) -{ - struct section *sec; - - if (!list || !list->next || !name) - return NULL; - - list_for_each_entry(sec, list, list) { - if (strcmp(sec->name, name)) - continue; - if (--nth >= 0) - continue; - return sec; - } - - return NULL; -} - -struct section *find_section_by_name(struct list_head *list, const char *name) -{ - return find_nth_section_by_name(list, 0, name); -} - -struct symbol *find_symbol_by_index(struct list_head *list, size_t index) -{ - struct symbol *sym; - - list_for_each_entry(sym, list, list) - if (sym->index == index) - return sym; - - return NULL; -} - -struct symbol *find_symbol_by_name(struct list_head *list, const char *name) -{ - struct symbol *sym; - - list_for_each_entry(sym, list, list) - if (sym->name && !strcmp(sym->name, name)) - return sym; - - return NULL; -} - -struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset) -{ - struct rela *rela; - - list_for_each_entry(rela, &relasec->relas, list) { - if (rela->offset == offset) - return rela; - } - - return NULL; -} - -unsigned int absolute_rela_type(struct kpatch_elf *kelf) -{ - switch(kelf->arch) { - case AARCH64: - return R_AARCH64_ABS64; - case PPC64: - return R_PPC64_ADDR64; - case X86_64: - return R_X86_64_64; - case S390: - return R_390_64; - default: - ERROR("unsupported arch"); - } - return 0; -} - -/* returns the offset of the string in the string table */ -int offset_of_string(struct list_head *list, char *name) -{ - struct string *string; - int index = 0; - - /* try to find string in the string list */ - list_for_each_entry(string, list, list) { - if (!strcmp(string->name, name)) - return index; - index += (int)strlen(string->name) + 1; - } - - /* allocate a new string */ - ALLOC_LINK(string, list); - string->name = name; - return index; -} - -static void rela_insn(const struct section *sec, const struct rela *rela, - struct insn *insn) -{ - unsigned long insn_addr, start, end, rela_addr; - - start = (unsigned long)sec->data->d_buf; - end = start + sec->sh.sh_size; - - if (end <= start) - ERROR("bad section size"); - - rela_addr = start + rela->offset; - for (insn_addr = start; insn_addr < end; insn_addr += insn->length) { - insn_init(insn, (void *)insn_addr, 1); - insn_get_length(insn); - if (!insn->length) - ERROR("can't decode instruction in section %s at offset 0x%lx", - sec->name, insn_addr); - if (rela_addr >= insn_addr && - rela_addr < insn_addr + insn->length) - return; - } - - ERROR("can't find instruction for rela at %s+0x%x", - sec->name, rela->offset); -} - -/* - * Return the addend, adjusted for any PC-relative relocation trickery, to - * point to the relevant symbol offset. - */ -long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, - struct rela *rela) -{ - long add_off; - struct section *sec = relasec->base; - - switch(kelf->arch) { - case AARCH64: - case PPC64: - add_off = 0; - break; - case X86_64: - if (!is_text_section(sec) || - rela->type == R_X86_64_64 || - rela->type == R_X86_64_32S) - add_off = 0; - else if (rela->type == R_X86_64_PC32 || - rela->type == R_X86_64_PLT32 || - rela->type == R_X86_64_NONE) { - struct insn insn; - rela_insn(sec, rela, &insn); - add_off = (long)insn.next_byte - - (long)sec->data->d_buf - - rela->offset; - } else - ERROR("unhandled rela type %d", rela->type); - break; - case S390: - /* - * For branch and relative load instructions, - * add_off is -2. - */ - if (rela->type == R_390_GOTENT || - rela->type == R_390_PLT32DBL || - rela->type == R_390_PC32DBL) - add_off = -2; - else if (rela->type == R_390_32 || - rela->type == R_390_64 || - rela->type == R_390_PC32 || - rela->type == R_390_PC64) - add_off = 0; - else - ERROR("unhandled rela type %d", rela->type); - break; - default: - ERROR("unsupported arch\n"); - } - - return rela->addend + add_off; -} - -unsigned int insn_length(struct kpatch_elf *kelf, void *addr) -{ - struct insn decoded_insn; - char *insn = addr; - - switch(kelf->arch) { - case AARCH64: - return 4; - - case X86_64: - insn_init(&decoded_insn, addr, 1); - insn_get_length(&decoded_insn); - return decoded_insn.length; - - case PPC64: - return 4; - - case S390: - switch(insn[0] >> 6) { - case 0: - return 2; - case 1: - case 2: - return 4; - case 3: - return 6; - } - - default: - ERROR("unsupported arch"); - } - - return 0; -} - -static void kpatch_create_rela_list(struct kpatch_elf *kelf, - struct section *relasec) -{ - int index = 0, skip = 0; - struct rela *rela; - unsigned int symndx; - unsigned long rela_nr; - - /* find matching base (text/data) section */ - relasec->base = find_section_by_index(&kelf->sections, relasec->sh.sh_info); - if (!relasec->base) - ERROR("can't find base section for rela section %s", relasec->name); - - /* create reverse link from base section to this rela section */ - relasec->base->rela = relasec; - - rela_nr = relasec->sh.sh_size / relasec->sh.sh_entsize; - - log_debug("\n=== rela list for %s (%ld entries) ===\n", - relasec->base->name, rela_nr); - - if (is_debug_section(relasec)) { - log_debug("skipping rela listing for .debug_* section\n"); - skip = 1; - } - - /* read and store the rela entries */ - while (rela_nr--) { - ALLOC_LINK(rela, &relasec->relas); - - if (!gelf_getrela(relasec->data, index, &rela->rela)) - ERROR("gelf_getrela"); - index++; - - rela->type = GELF_R_TYPE(rela->rela.r_info); - rela->addend = rela->rela.r_addend; - rela->offset = (unsigned int)rela->rela.r_offset; - symndx = (unsigned int)GELF_R_SYM(rela->rela.r_info); - rela->sym = find_symbol_by_index(&kelf->symbols, symndx); - if (!rela->sym) - ERROR("could not find rela entry symbol\n"); - if (rela->sym->sec && - (rela->sym->sec->sh.sh_flags & SHF_STRINGS)) { - rela->string = rela->sym->sec->data->d_buf + - rela->sym->sym.st_value + - rela_target_offset(kelf, relasec, rela); - if (!rela->string) - ERROR("could not lookup rela string for %s+%ld", - rela->sym->name, rela->addend); - } - - if (skip) - continue; - log_debug("offset %d, type %d, %s %s %ld", rela->offset, - rela->type, rela->sym->name, - (rela->addend < 0)?"-":"+", labs(rela->addend)); - if (rela->string) - log_debug(" (string = %s)", rela->string); - log_debug("\n"); - } -} - -static void kpatch_create_section_list(struct kpatch_elf *kelf) -{ - Elf_Scn *scn = NULL; - struct section *sec; - size_t shstrndx, sections_nr; - - if (elf_getshdrnum(kelf->elf, §ions_nr)) - ERROR("elf_getshdrnum"); - - /* - * elf_getshdrnum() includes section index 0 but elf_nextscn - * doesn't return that section so subtract one. - */ - sections_nr--; - - if (elf_getshdrstrndx(kelf->elf, &shstrndx)) - ERROR("elf_getshdrstrndx"); - - log_debug("=== section list (%zu) ===\n", sections_nr); - - while (sections_nr--) { - ALLOC_LINK(sec, &kelf->sections); - - scn = elf_nextscn(kelf->elf, scn); - if (!scn) - ERROR("scn NULL"); - - if (!gelf_getshdr(scn, &sec->sh)) - ERROR("gelf_getshdr"); - - sec->name = elf_strptr(kelf->elf, shstrndx, sec->sh.sh_name); - if (!sec->name) - ERROR("elf_strptr"); - - sec->data = elf_getdata(scn, NULL); - if (!sec->data) - ERROR("elf_getdata"); - - sec->index = (unsigned int)elf_ndxscn(scn); - - - if (sec->sh.sh_type == SHT_SYMTAB_SHNDX) - kelf->symtab_shndx = sec->data; - - log_debug("ndx %02d, data %p, size %zu, name %s\n", - sec->index, sec->data->d_buf, sec->data->d_size, - sec->name); - } - - /* Sanity check, one more call to elf_nextscn() should return NULL */ - if (elf_nextscn(kelf->elf, scn)) - ERROR("expected NULL"); -} - -static void kpatch_create_symbol_list(struct kpatch_elf *kelf) -{ - struct section *symtab; - struct symbol *sym; - unsigned int symbols_nr, index = 0; - Elf32_Word shndx; - - symtab = find_section_by_name(&kelf->sections, ".symtab"); - if (!symtab) - ERROR("missing symbol table"); - - symbols_nr = (unsigned int)(symtab->sh.sh_size / symtab->sh.sh_entsize); - - log_debug("\n=== symbol list (%d entries) ===\n", symbols_nr); - - while (symbols_nr--) { - ALLOC_LINK(sym, &kelf->symbols); - - INIT_LIST_HEAD(&sym->children); - - sym->index = index; - if (!gelf_getsym(symtab->data, index, &sym->sym)) - ERROR("gelf_getsym"); - index++; - - sym->name = elf_strptr(kelf->elf, symtab->sh.sh_link, - sym->sym.st_name); - if (!sym->name) - ERROR("elf_strptr"); - - sym->type = GELF_ST_TYPE(sym->sym.st_info); - sym->bind = GELF_ST_BIND(sym->sym.st_info); - - shndx = sym->sym.st_shndx; - if (shndx == SHN_XINDEX && - !gelf_getsymshndx(symtab->data, kelf->symtab_shndx, sym->index, &sym->sym, &shndx)) - ERROR("couldn't find extended section index for symbol %s; idx=%d", - sym->name, sym->index); - - if ((sym->sym.st_shndx > SHN_UNDEF && - sym->sym.st_shndx < SHN_LORESERVE) || - sym->sym.st_shndx == SHN_XINDEX) { - sym->sec = find_section_by_index(&kelf->sections, shndx); - if (!sym->sec) - ERROR("couldn't find section for symbol %s\n", - sym->name); - - if (sym->type == STT_SECTION) { - sym->sec->secsym = sym; - /* use the section name as the symbol name */ - sym->name = sym->sec->name; - } - } - - log_debug("sym %02d, type %d, bind %d, ndx %02d, name %s", - sym->index, sym->type, sym->bind, sym->sym.st_shndx, - sym->name); - if (sym->sec) - log_debug(" -> %s", sym->sec->name); - log_debug("\n"); - } - -} - -struct kpatch_elf *kpatch_elf_open(const char *name) -{ - Elf *elf; - int fd; - struct kpatch_elf *kelf; - struct section *relasec; - GElf_Ehdr ehdr; - - fd = open(name, O_RDONLY); - if (fd == -1) - ERROR("open"); - - elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); - if (!elf) - ERROR("elf_begin"); - - kelf = malloc(sizeof(*kelf)); - if (!kelf) - ERROR("malloc"); - memset(kelf, 0, sizeof(*kelf)); - INIT_LIST_HEAD(&kelf->sections); - INIT_LIST_HEAD(&kelf->symbols); - INIT_LIST_HEAD(&kelf->strings); - - /* read and store section, symbol entries from file */ - kelf->elf = elf; - kelf->fd = fd; - - if (!gelf_getehdr(kelf->elf, &ehdr)) - ERROR("gelf_getehdr"); - switch (ehdr.e_machine) { - case EM_AARCH64: - kelf->arch = AARCH64; - break; - case EM_PPC64: - kelf->arch = PPC64; - break; - case EM_X86_64: - kelf->arch = X86_64; - break; - case EM_S390: - kelf->arch = S390; - break; - default: - ERROR("Unsupported target architecture"); - } - - kpatch_create_section_list(kelf); - kpatch_create_symbol_list(kelf); - - /* for each rela section, read and store the rela entries */ - list_for_each_entry(relasec, &kelf->sections, list) { - if (!is_rela_section(relasec)) - continue; - INIT_LIST_HEAD(&relasec->relas); - kpatch_create_rela_list(kelf, relasec); - } - - return kelf; -} - -void kpatch_dump_kelf(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - struct rela *rela; - - if (loglevel > DEBUG) - return; - - printf("\n=== Sections ===\n"); - list_for_each_entry(sec, &kelf->sections, list) { - printf("%02d %s (%s)", sec->index, sec->name, status_str(sec->status)); - if (is_rela_section(sec)) { - printf(", base-> %s\n", sec->base->name); - /* skip .debug_* sections */ - if (is_debug_section(sec)) - goto next; - printf("rela section expansion\n"); - list_for_each_entry(rela, &sec->relas, list) { - printf("sym %d, offset %d, type %d, %s %s %ld\n", - rela->sym->index, rela->offset, - rela->type, rela->sym->name, - (rela->addend < 0)?"-":"+", - labs(rela->addend)); - } - } else { - if (sec->sym) - printf(", sym-> %s", sec->sym->name); - if (sec->secsym) - printf(", secsym-> %s", sec->secsym->name); - if (sec->rela) - printf(", rela-> %s", sec->rela->name); - } -next: - printf("\n"); - } - - printf("\n=== Symbols ===\n"); - list_for_each_entry(sym, &kelf->symbols, list) { - printf("sym %02d, type %d, bind %d, ndx %02d, name %s (%s)", - sym->index, sym->type, sym->bind, sym->sym.st_shndx, - sym->name, status_str(sym->status)); - if (sym->sec && (sym->type == STT_FUNC || sym->type == STT_OBJECT)) - printf(" -> %s", sym->sec->name); - printf("\n"); - } -} - -bool is_null_sym(struct symbol *sym) -{ - return !strlen(sym->name); -} - -bool is_file_sym(struct symbol *sym) -{ - return sym->type == STT_FILE; -} - -bool is_local_func_sym(struct symbol *sym) -{ - return sym->bind == STB_LOCAL && sym->type == STT_FUNC; -} - -bool is_local_sym(struct symbol *sym) -{ - return sym->bind == STB_LOCAL; -} - -void print_strtab(char *buf, size_t size) -{ - size_t i; - - for (i = 0; i < size; i++) { - if (buf[i] == 0) - printf("\\0"); - else - printf("%c",buf[i]); - } -} - -void kpatch_create_shstrtab(struct kpatch_elf *kelf) -{ - struct section *shstrtab, *sec; - size_t size, offset, len; - char *buf; - - shstrtab = find_section_by_name(&kelf->sections, ".shstrtab"); - if (!shstrtab) - return; - - /* determine size of string table */ - size = 1; /* for initial NULL terminator */ - list_for_each_entry(sec, &kelf->sections, list) - size += strlen(sec->name) + 1; /* include NULL terminator */ - - /* allocate data buffer */ - buf = malloc(size); - if (!buf) - ERROR("malloc"); - memset(buf, 0, size); - - /* populate string table and link with section header */ - offset = 1; - list_for_each_entry(sec, &kelf->sections, list) { - len = strlen(sec->name) + 1; - sec->sh.sh_name = (unsigned int)offset; - memcpy(buf + offset, sec->name, len); - offset += len; - } - - if (offset != size) - ERROR("shstrtab size mismatch"); - - shstrtab->data->d_buf = buf; - shstrtab->data->d_size = size; - - if (loglevel <= DEBUG) { - printf("shstrtab: "); - print_strtab(buf, size); - printf("\n"); - - list_for_each_entry(sec, &kelf->sections, list) - printf("%s @ shstrtab offset %d\n", - sec->name, sec->sh.sh_name); - } -} - -void kpatch_create_strtab(struct kpatch_elf *kelf) -{ - struct section *strtab, *shstrtab; - struct symbol *sym; - size_t size = 0, offset = 0, len; - char *buf; - - strtab = find_section_by_name(&kelf->sections, ".strtab"); - if (!strtab) - ERROR("find_section_by_name"); - - shstrtab = find_section_by_name(&kelf->sections, ".shstrtab"); - - /* determine size of string table */ - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type == STT_SECTION) - continue; - size += strlen(sym->name) + 1; /* include NULL terminator */ - } - - /* and when covering for missing .shstrtab ... */ - if (!shstrtab) { - /* factor out into common (sh)strtab feeder */ - struct section *sec; - - list_for_each_entry(sec, &kelf->sections, list) - size += strlen(sec->name) + 1; /* include NULL terminator */ - } - - /* allocate data buffer */ - buf = malloc(size); - if (!buf) - ERROR("malloc"); - memset(buf, 0, size); - - /* populate string table and link with section header */ - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type == STT_SECTION) { - sym->sym.st_name = 0; - continue; - } - len = strlen(sym->name) + 1; - sym->sym.st_name = (unsigned int)offset; - memcpy(buf + offset, sym->name, len); - offset += len; - } - - if (!shstrtab) { - struct section *sec; - - /* populate string table and link with section header */ - list_for_each_entry(sec, &kelf->sections, list) { - len = strlen(sec->name) + 1; - sec->sh.sh_name = (unsigned int)offset; - memcpy(buf + offset, sec->name, len); - offset += len; - } - } - - if (offset != size) - ERROR("strtab size mismatch"); - - strtab->data->d_buf = buf; - strtab->data->d_size = size; - - if (loglevel <= DEBUG) { - printf("strtab: "); - print_strtab(buf, size); - printf("\n"); - - list_for_each_entry(sym, &kelf->symbols, list) - printf("%s @ strtab offset %d\n", - sym->name, sym->sym.st_name); - } -} - -void kpatch_create_symtab(struct kpatch_elf *kelf) -{ - struct section *symtab; - struct section *strtab; - struct symbol *sym; - char *buf; - size_t size; - int nr = 0, nr_local = 0; - unsigned long offset = 0; - - symtab = find_section_by_name(&kelf->sections, ".symtab"); - if (!symtab) - ERROR("find_section_by_name"); - - /* count symbols */ - list_for_each_entry(sym, &kelf->symbols, list) - nr++; - - /* create new symtab buffer */ - size = nr * symtab->sh.sh_entsize; - buf = malloc(size); - if (!buf) - ERROR("malloc"); - memset(buf, 0, size); - - offset = 0; - list_for_each_entry(sym, &kelf->symbols, list) { - memcpy(buf + offset, &sym->sym, symtab->sh.sh_entsize); - offset += symtab->sh.sh_entsize; - - if (is_local_sym(sym)) - nr_local++; - } - - symtab->data->d_buf = buf; - symtab->data->d_size = size; - - /* update symtab section header */ - strtab = find_section_by_name(&kelf->sections, ".strtab"); - if (!strtab) - ERROR("missing .strtab section"); - - symtab->sh.sh_link = strtab->index; - symtab->sh.sh_info = nr_local; -} - -struct section *create_section_pair(struct kpatch_elf *kelf, char *name, - int entsize, int nr) -{ - char *relaname; - struct section *sec, *relasec; - int size = entsize * nr; - - relaname = malloc(strlen(name) + strlen(".rela") + 1); - if (!relaname) - ERROR("malloc"); - strcpy(relaname, ".rela"); - strcat(relaname, name); - - /* allocate text section resources */ - ALLOC_LINK(sec, &kelf->sections); - sec->name = name; - - /* set data */ - sec->data = malloc(sizeof(*sec->data)); - if (!sec->data) - ERROR("malloc"); - sec->data->d_buf = malloc(size); - if (!sec->data->d_buf) - ERROR("malloc"); - memset(sec->data->d_buf, 0, size); - sec->data->d_size = size; - sec->data->d_type = ELF_T_BYTE; - - /* set section header */ - sec->sh.sh_type = SHT_PROGBITS; - sec->sh.sh_entsize = entsize; - sec->sh.sh_addralign = 8; - sec->sh.sh_flags = SHF_ALLOC; - sec->sh.sh_size = size; - - /* allocate rela section resources */ - ALLOC_LINK(relasec, &kelf->sections); - relasec->name = relaname; - relasec->base = sec; - INIT_LIST_HEAD(&relasec->relas); - - /* set data, buffers generated by kpatch_rebuild_rela_section_data() */ - relasec->data = malloc(sizeof(*relasec->data)); - if (!relasec->data) - ERROR("malloc"); - relasec->data->d_type = ELF_T_RELA; - - /* set section header */ - relasec->sh.sh_type = SHT_RELA; - relasec->sh.sh_entsize = sizeof(GElf_Rela); - relasec->sh.sh_addralign = 8; - - /* set text rela section pointer */ - sec->rela = relasec; - - return sec; -} - -void kpatch_remove_and_free_section(struct kpatch_elf *kelf, char *secname) -{ - struct section *sec, *safesec; - struct rela *rela, *saferela; - - list_for_each_entry_safe(sec, safesec, &kelf->sections, list) { - if (strcmp(secname, sec->name)) - continue; - - if (is_rela_section(sec)) { - list_for_each_entry_safe(rela, saferela, &sec->relas, list) { - list_del(&rela->list); - memset(rela, 0, sizeof(*rela)); - free(rela); - } - } - - /* - * Remove the STT_SECTION symbol from the symtab, - * otherwise when we remove the section we'll end up - * with UNDEF section symbols in the symtab. - */ - if (!is_rela_section(sec) && sec->secsym) { - list_del(&sec->secsym->list); - memset(sec->secsym, 0, sizeof(*sec->secsym)); - free(sec->secsym); - } - - list_del(&sec->list); - memset(sec, 0, sizeof(*sec)); - free(sec); - } -} - -void kpatch_reindex_elements(struct kpatch_elf *kelf) -{ - struct section *sec; - struct symbol *sym; - unsigned int index; - - index = 1; /* elf write function handles NULL section 0 */ - list_for_each_entry(sec, &kelf->sections, list) - sec->index = index++; - - index = 0; - list_for_each_entry(sym, &kelf->symbols, list) { - sym->index = index++; - if (sym->sec) { - sym->sym.st_shndx = (unsigned short)sym->sec->index; - if (sym->sec->pfe) { - sym->sec->pfe->sh.sh_link = sym->sec->index; - if (sym->sec->pfe->rela) - sym->sec->pfe->rela->sh.sh_info = sym->sec->index; - } - } else if (sym->sym.st_shndx != SHN_ABS && - sym->sym.st_shndx != SHN_LIVEPATCH) { - sym->sym.st_shndx = SHN_UNDEF; - } - } -} - -void kpatch_rebuild_rela_section_data(struct section *sec) -{ - struct rela *rela; - int nr = 0, index = 0; - GElf_Rela *relas; - size_t size; - - list_for_each_entry(rela, &sec->relas, list) - nr++; - - size = nr * sizeof(*relas); - relas = malloc(size); - if (!relas) - ERROR("malloc"); - - sec->data->d_buf = relas; - sec->data->d_size = size; - /* d_type remains ELF_T_RELA */ - - sec->sh.sh_size = size; - - list_for_each_entry(rela, &sec->relas, list) { - relas[index].r_offset = rela->offset; - relas[index].r_addend = rela->addend; - relas[index].r_info = GELF_R_INFO(rela->sym->index, rela->type); - index++; - } - - /* sanity check, index should equal nr */ - if (index != nr) - ERROR("size mismatch in rebuilt rela section"); -} - -void kpatch_write_output_elf(struct kpatch_elf *kelf, Elf *elf, char *outfile, - mode_t mode) -{ - int fd; - struct section *sec; - struct section *shstrtab; - Elf *elfout; - GElf_Ehdr eh, ehout; - Elf_Scn *scn; - Elf_Data *data; - GElf_Shdr sh; - - fd = creat(outfile, mode); - if (fd == -1) - ERROR("creat"); - - elfout = elf_begin(fd, ELF_C_WRITE, NULL); - if (!elfout) - ERROR("elf_begin"); - - if (!gelf_newehdr(elfout, gelf_getclass(elf))) - ERROR("gelf_newehdr"); - - if (!gelf_getehdr(elfout, &ehout)) - ERROR("gelf_getehdr"); - - if (!gelf_getehdr(elf, &eh)) - ERROR("gelf_getehdr"); - - memset(&ehout, 0, sizeof(ehout)); - ehout.e_ident[EI_DATA] = eh.e_ident[EI_DATA]; - ehout.e_machine = eh.e_machine; - ehout.e_type = eh.e_type; - ehout.e_version = EV_CURRENT; - - shstrtab = find_section_by_name(&kelf->sections, ".shstrtab"); - if (!shstrtab) - shstrtab = find_section_by_name(&kelf->sections, ".strtab"); - if (!shstrtab) - ERROR("missing .shstrtab, .strtab sections"); - - ehout.e_shstrndx = (unsigned short)shstrtab->index; - - /* add changed sections */ - list_for_each_entry(sec, &kelf->sections, list) { - scn = elf_newscn(elfout); - if (!scn) - ERROR("elf_newscn"); - - data = elf_newdata(scn); - if (!data) - ERROR("elf_newdata"); - - if (!elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY)) - ERROR("elf_flagdata"); - - data->d_type = sec->data->d_type; - data->d_buf = sec->data->d_buf; - data->d_size = sec->data->d_size; - - if(!gelf_getshdr(scn, &sh)) - ERROR("gelf_getshdr"); - - sh = sec->sh; - - if (!gelf_update_shdr(scn, &sh)) - ERROR("gelf_update_shdr"); - } - - if (!gelf_update_ehdr(elfout, &ehout)) - ERROR("gelf_update_ehdr"); - - if (elf_update(elfout, ELF_C_WRITE) < 0) { - printf("%s\n",elf_errmsg(-1)); - ERROR("elf_update"); - } - - elf_end(elfout); - close(fd); -} - -/* - * While this is a one-shot program without a lot of proper cleanup in case - * of an error, this function serves a debugging purpose: to break down and - * zero data structures we shouldn't be accessing anymore. This should - * help cause an immediate and obvious issue when a logic error leads to - * accessing data that is not intended to be accessed past a particular point. - */ -void kpatch_elf_teardown(struct kpatch_elf *kelf) -{ - struct section *sec, *safesec; - struct symbol *sym, *safesym; - struct rela *rela, *saferela; - - list_for_each_entry_safe(sec, safesec, &kelf->sections, list) { - if (sec->twin) - sec->twin->twin = NULL; - if (is_rela_section(sec)) { - list_for_each_entry_safe(rela, saferela, &sec->relas, list) { - memset(rela, 0, sizeof(*rela)); - free(rela); - } - } - memset(sec, 0, sizeof(*sec)); - free(sec); - } - - list_for_each_entry_safe(sym, safesym, &kelf->symbols, list) { - if (sym->twin) - sym->twin->twin = NULL; - memset(sym, 0, sizeof(*sym)); - free(sym); - } - - INIT_LIST_HEAD(&kelf->sections); - INIT_LIST_HEAD(&kelf->symbols); -} - -void kpatch_elf_free(struct kpatch_elf *kelf) -{ - elf_end(kelf->elf); - close(kelf->fd); - memset(kelf, 0, sizeof(*kelf)); - free(kelf); -} diff --git a/kpatch-build/kpatch-elf.h b/kpatch-build/kpatch-elf.h deleted file mode 100644 index 1ee4d91..0000000 --- a/kpatch-build/kpatch-elf.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * kpatch-elf.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#ifndef _KPATCH_ELF_H_ -#define _KPATCH_ELF_H_ - -#include -#include -#include "list.h" -#include "log.h" - -#define KLP_SYM_PREFIX ".klp.sym." -#define KLP_RELASEC_PREFIX ".klp.rela." -#define KLP_ARCH_PREFIX ".klp.arch." -#define SHF_RELA_LIVEPATCH 0x00100000 -#define SHN_LIVEPATCH 0xff20 - -/******************* - * Data structures - * ****************/ -struct section; -struct symbol; -struct rela; - -enum status { - NEW, - CHANGED, - SAME -}; - -struct section { - struct list_head list; - struct section *twin; - GElf_Shdr sh; - Elf_Data *data; - char *name; - unsigned int index; - enum status status; - int include; - int ignore; - int grouped; - union { - struct { /* if (is_rela_section()) */ - struct section *base; - struct list_head relas; - }; - struct { /* else */ - struct section *rela; - struct symbol *secsym, *sym; - }; - }; - struct section *pfe; /* arm64 per-func __patchable_function_entries */ -}; - -enum symbol_strip { - SYMBOL_DEFAULT, - SYMBOL_USED, - SYMBOL_STRIP, -}; - -struct symbol { - struct list_head list; - struct symbol *twin; - struct symbol *parent; - struct list_head children; - struct list_head subfunction_node; - struct section *sec; - GElf_Sym sym; - char *name; - struct object_symbol *lookup_table_file_sym; - unsigned int index; - unsigned char bind, type; - enum status status; - union { - int include; /* used in the patched elf */ - enum symbol_strip strip; /* used in the output elf */ - }; - int has_func_profiling; -}; - -struct rela { - struct list_head list; - GElf_Rela rela; - struct symbol *sym; - unsigned int type; - unsigned int offset; - long addend; - char *string; - bool need_dynrela; -}; - -struct string { - struct list_head list; - char *name; -}; - -enum architecture { - PPC64 = 0x1 << 0, - X86_64 = 0x1 << 1, - S390 = 0x1 << 2, - AARCH64 = 0x1 << 3, -}; - -struct kpatch_elf { - Elf *elf; - enum architecture arch; - struct list_head sections; - struct list_head symbols; - struct list_head strings; - Elf_Data *symtab_shndx; - int fd; -}; - -/******************* - * Helper functions - ******************/ -char *status_str(enum status status); -bool is_rela_section(struct section *sec); -bool is_text_section(struct section *sec); -bool is_debug_section(struct section *sec); - -struct section *find_section_by_index(struct list_head *list, unsigned int index); -struct section *find_section_by_name(struct list_head *list, const char *name); -struct section *find_nth_section_by_name(struct list_head *list, int nth, - const char *name); -struct symbol *find_symbol_by_index(struct list_head *list, size_t index); -struct symbol *find_symbol_by_name(struct list_head *list, const char *name); -struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset); - -#define ALLOC_LINK(_new, _list) \ -{ \ - (_new) = malloc(sizeof(*(_new))); \ - if (!(_new)) \ - ERROR("malloc"); \ - memset((_new), 0, sizeof(*(_new))); \ - INIT_LIST_HEAD(&(_new)->list); \ - if (_list) \ - list_add_tail(&(_new)->list, (_list)); \ -} - -unsigned int absolute_rela_type(struct kpatch_elf *kelf); -int offset_of_string(struct list_head *list, char *name); -long rela_target_offset(struct kpatch_elf *kelf, struct section *relasec, - struct rela *rela); -unsigned int insn_length(struct kpatch_elf *kelf, void *addr); - -#ifndef R_PPC64_ENTRY -#define R_PPC64_ENTRY 118 -#endif - -/************* - * Functions - * **********/ -struct kpatch_elf *kpatch_elf_open(const char *name); -void kpatch_dump_kelf(struct kpatch_elf *kelf); - -bool is_null_sym(struct symbol *sym); -bool is_file_sym(struct symbol *sym); -bool is_local_func_sym(struct symbol *sym); -bool is_local_sym(struct symbol *sym); - -void print_strtab(char *buf, size_t size); -void kpatch_create_shstrtab(struct kpatch_elf *kelf); -void kpatch_create_strtab(struct kpatch_elf *kelf); -void kpatch_create_symtab(struct kpatch_elf *kelf); -struct section *create_section_pair(struct kpatch_elf *kelf, char *name, - int entsize, int nr); -void kpatch_remove_and_free_section(struct kpatch_elf *kelf, char *secname); -void kpatch_reindex_elements(struct kpatch_elf *kelf); -void kpatch_rebuild_rela_section_data(struct section *sec); -void kpatch_write_output_elf(struct kpatch_elf *kelf, Elf *elf, char *outfile, - mode_t mode); -void kpatch_elf_teardown(struct kpatch_elf *kelf); -void kpatch_elf_free(struct kpatch_elf *kelf); -#endif /* _KPATCH_ELF_H_ */ diff --git a/kpatch-build/kpatch-intermediate.h b/kpatch-build/kpatch-intermediate.h deleted file mode 100644 index 2036cb3..0000000 --- a/kpatch-build/kpatch-intermediate.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * kpatch-intermediate.h - * - * Structures for intermediate .kpatch.* sections - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#ifndef _KPATCH_INTERMEDIATE_H_ -#define _KPATCH_INTERMEDIATE_H_ - -/* For .kpatch.{symbols,relocations,arch} sections */ - -struct kpatch_symbol { - unsigned long src; - unsigned long sympos; - unsigned char bind, type; - char *name; - char *objname; /* object to which this sym belongs */ -}; - -struct kpatch_relocation { - unsigned long dest; - unsigned int type; - int external; - long addend; - char *objname; /* object to which this rela applies to */ - struct kpatch_symbol *ksym; -}; - -struct kpatch_arch { - unsigned long sec; - char *objname; -}; -#endif /* _KPATCH_INTERMEDIATE_H_ */ diff --git a/kpatch-build/kpatch.h b/kpatch-build/kpatch.h deleted file mode 100644 index ffdb854..0000000 --- a/kpatch-build/kpatch.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _KPATCH_H_ -#define _KPATCH_H_ - -enum exit_status { - EXIT_STATUS_SUCCESS = 0, - EXIT_STATUS_ERROR = 1, - EXIT_STATUS_DIFF_FATAL = 2, - EXIT_STATUS_NO_CHANGE = 3, -}; - -#endif /* _KPATCH_H_ */ diff --git a/kpatch-build/list.h b/kpatch-build/list.h deleted file mode 100644 index e95593c..0000000 --- a/kpatch-build/list.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * list.h - * - * Adapted from http://www.mcs.anl.gov/~kazutomo/list/list.h which is a - * userspace port of the Linux kernel implementation in include/linux/list.h - * - * Thus licensed as GPLv2. - * - * Copyright (C) 2014 Seth Jennings - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#ifndef _LIST_H -#define _LIST_H - -/** - * Get offset of a member - */ -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/** - * Casts a member of a structure out to the containing structure - * @param ptr the pointer to the member. - * @param type the type of the container struct this is embedded in. - * @param member the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) - -/** - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_next_entry - get the next element in list - * @pos: the type * to cursor - * @member: the name of the list_struct within the struct. - */ -#define list_next_entry(pos, member) \ - list_entry((pos)->member.next, typeof(*(pos)), member) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_next_entry(pos, member); \ - &pos->member != (head); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -#endif /* _LIST_H_ */ diff --git a/kpatch-build/log.h b/kpatch-build/log.h deleted file mode 100644 index eefa0fc..0000000 --- a/kpatch-build/log.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _LOG_H_ -#define _LOG_H_ - -#include -#include "kpatch.h" - -/* Files that include log.h must define loglevel and childobj */ -extern enum loglevel loglevel; -extern char *childobj; - -#define ERROR(format, ...) \ - err(EXIT_STATUS_ERROR, "ERROR: %s: %s: %d: " format, childobj, __FUNCTION__, __LINE__, ##__VA_ARGS__) - -#define log_debug(format, ...) log(DEBUG, format, ##__VA_ARGS__) -#define log_normal(format, ...) log(NORMAL, "%s: " format, childobj, ##__VA_ARGS__) - -#define log(level, format, ...) \ -({ \ - if (loglevel <= (level)) \ - printf(format, ##__VA_ARGS__); \ -}) - -enum loglevel { - DEBUG, - NORMAL -}; -#endif /* _LOG_H_ */ diff --git a/kpatch-build/lookup.c b/kpatch-build/lookup.c deleted file mode 100644 index f2596b1..0000000 --- a/kpatch-build/lookup.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * lookup.c - * - * This file contains functions that assist in the reading and searching - * the symbol table of an ELF object. - * - * Copyright (C) 2014 Seth Jennings - * Copyright (C) 2014 Josh Poimboeuf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, - * 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lookup.h" -#include "log.h" - -struct object_symbol { - unsigned long addr; - unsigned long size; - char *name; - int type, bind; -}; - -struct export_symbol { - char *name; - char *objname; -}; - -struct lookup_table { - int obj_nr, exp_nr; - struct object_symbol *obj_syms; - struct export_symbol *exp_syms; - char *objname; -}; - -#define for_each_obj_symbol(ndx, iter, table) \ - for (ndx = 0, iter = table->obj_syms; ndx < table->obj_nr; ndx++, iter++) - -#define for_each_obj_symbol_continue(ndx, iter, table) \ - for (iter = table->obj_syms + ndx; ndx < table->obj_nr; ndx++, iter++) - -#define for_each_exp_symbol(ndx, iter, table) \ - for (ndx = 0, iter = table->exp_syms; ndx < table->exp_nr; ndx++, iter++) - -static bool maybe_discarded_sym(const char *name) -{ - if (!name) - return false; - - /* - * Sometimes these symbols are discarded during linking, and sometimes - * they're not, depending on whether the parent object is vmlinux or a - * module, and also depending on the kernel version. For simplicity, - * we just always skip them when comparing object symbol tables. - */ - if (!strncmp(name, "__exitcall_", 11) || - !strncmp(name, "__brk_reservation_fn_", 21) || - !strncmp(name, "__func_stack_frame_non_standard_", 32) || - strstr(name, "__addressable_") || - strstr(name, "__UNIQUE_ID_") || - !strncmp(name, ".L.str", 6)) - return true; - - return false; -} - -static bool locals_match(struct lookup_table *table, int idx, - struct symbol *file_sym, struct list_head *sym_list) -{ - struct symbol *sym; - struct object_symbol *table_sym; - int i, found; - - i = idx + 1; - for_each_obj_symbol_continue(i, table_sym, table) { - if (table_sym->type == STT_FILE) - break; - if (table_sym->bind != STB_LOCAL) - continue; - if (table_sym->type != STT_FUNC && table_sym->type != STT_OBJECT) - continue; - - found = 0; - sym = file_sym; - list_for_each_entry_continue(sym, sym_list, list) { - if (sym->type == STT_FILE) - break; - if (sym->bind != STB_LOCAL) - continue; - - if (sym->type == table_sym->type && - !strcmp(sym->name, table_sym->name)) { - found = 1; - break; - } - } - - if (!found) - return false; - } - - sym = file_sym; - list_for_each_entry_continue(sym, sym_list, list) { - if (sym->type == STT_FILE) - break; - if (sym->bind != STB_LOCAL) - continue; - if (sym->type != STT_FUNC && sym->type != STT_OBJECT) - continue; - /* - * Symbols which get discarded at link time are missing from - * the lookup table, so skip them. - */ - if (maybe_discarded_sym(sym->name)) - continue; - - found = 0; - i = idx + 1; - for_each_obj_symbol_continue(i, table_sym, table) { - if (table_sym->type == STT_FILE) - break; - if (table_sym->bind != STB_LOCAL) - continue; - if (maybe_discarded_sym(table_sym->name)) - continue; - - if (sym->type == table_sym->type && - !strcmp(sym->name, table_sym->name)) { - found = 1; - break; - } - } - - if (!found) - return false; - } - - return true; -} - -static void find_local_syms(struct lookup_table *table, struct symbol *file_sym, - struct list_head *sym_list) -{ - struct object_symbol *sym; - struct object_symbol *lookup_table_file_sym = NULL; - int i; - - for_each_obj_symbol(i, sym, table) { - if (sym->type != STT_FILE) - continue; - if (strcmp(file_sym->name, sym->name)) - continue; - if (!locals_match(table, i, file_sym, sym_list)) - continue; - if (lookup_table_file_sym) - ERROR("found duplicate matches for %s local symbols in %s symbol table", - file_sym->name, table->objname); - - lookup_table_file_sym = sym; - } - - if (!lookup_table_file_sym) - ERROR("couldn't find matching %s local symbols in %s symbol table", - file_sym->name, table->objname); - - list_for_each_entry_continue(file_sym, sym_list, list) { - if (file_sym->type == STT_FILE) - break; - file_sym->lookup_table_file_sym = lookup_table_file_sym; - } -} - -/* - * Because there can be duplicate symbols and duplicate filenames we need to - * correlate each symbol from the elf file to it's corresponding symbol in - * lookup table. Both the elf file and the lookup table can be split on - * STT_FILE symbols into blocks of symbols originating from a single source - * file. We then compare local symbol lists from both blocks and store the - * pointer to STT_FILE symbol in lookup table for later use in - * lookup_local_symbol(). - */ -static void find_local_syms_multiple(struct lookup_table *table, - struct kpatch_elf *kelf) -{ - struct symbol *sym; - - list_for_each_entry(sym, &kelf->symbols, list) { - if (sym->type == STT_FILE) - find_local_syms(table, sym, &kelf->symbols); - } -} - -/* Strip the path and replace '-' with '_' */ -static char *make_modname(char *modname) -{ - char *cur, *name; - - if (!modname) - return NULL; - - name = strdup(basename(modname)); - if (!name) - ERROR("strdup"); - - cur = name; /* use cur as tmp */ - while (*cur != '\0') { - if (*cur == '-') - *cur = '_'; - cur++; - } - - return name; -} - -static void symtab_read(struct lookup_table *table, char *path) -{ - FILE *file; - long unsigned int addr; - int alloc_nr = 0, i = 0; - int matched; - bool skip = false; - char line[256], name[256], size[16], type[16], bind[16], ndx[16]; - - if ((file = fopen(path, "r")) == NULL) - ERROR("fopen"); - - /* - * First, get an upper limit on the number of entries for allocation - * purposes: - */ - while (fgets(line, 256, file)) - alloc_nr++; - - table->obj_syms = malloc(alloc_nr * sizeof(*table->obj_syms)); - if (!table->obj_syms) - ERROR("malloc table.obj_syms"); - memset(table->obj_syms, 0, alloc_nr * sizeof(*table->obj_syms)); - - rewind(file); - - /* Now read the actual entries: */ - while (fgets(line, 256, file)) { - - /* - * On powerpc, "readelf -s" shows both .dynsym and .symtab - * tables. .dynsym is just a subset of .symtab, so skip it to - * avoid duplicates. - */ - if (!strncmp(line, "Symbol table ", 13)) { - if (strstr(line, ".dynsym")) { - skip = true; - continue; - } else if (strstr(line, ".symtab")) { - skip = false; - continue; - } - } - if (skip) - continue; - - matched = sscanf(line, "%*s %lx %s %s %s %*s %s %s\n", - &addr, size, type, bind, ndx, name); - - if (matched == 5) { - name[0] = '\0'; - matched++; - } - - if (matched != 6 || - !strcmp(ndx, "UND") || - !strcmp(type, "SECTION")) - continue; - - table->obj_syms[i].addr = addr; - table->obj_syms[i].size = strtoul(size, NULL, 0); - - if (!strcmp(bind, "LOCAL")) { - table->obj_syms[i].bind = STB_LOCAL; - } else if (!strcmp(bind, "GLOBAL")) { - table->obj_syms[i].bind = STB_GLOBAL; - } else if (!strcmp(bind, "WEAK")) { - table->obj_syms[i].bind = STB_WEAK; - } else { - ERROR("unknown symbol bind %s", bind); - } - - if (!strcmp(type, "NOTYPE")) { - table->obj_syms[i].type = STT_NOTYPE; - } else if (!strcmp(type, "OBJECT")) { - table->obj_syms[i].type = STT_OBJECT; - } else if (!strcmp(type, "FUNC")) { - table->obj_syms[i].type = STT_FUNC; - } else if (!strcmp(type, "FILE")) { - table->obj_syms[i].type = STT_FILE; - } else { - ERROR("unknown symbol type %s", type); - } - - table->obj_syms[i].name = strdup(name); - if (!table->obj_syms[i].name) - ERROR("strdup"); - - i++; - } - - table->obj_nr = i; - - fclose(file); -} - -/* - * The Module.symvers file format is one of the following, depending on kernel - * version: - * - * - * - * - * - * All we care about is Symbol and Module. Since the format is unpredictable, - * we have to dynamically determine which column is Module by looking for - * "vmlinux". - */ -static void symvers_read(struct lookup_table *table, char *path) -{ - FILE *file; - int i, column, mod_column = 0; - char line[4096]; - char *tmp, *objname, *symname; - - if ((file = fopen(path, "r")) == NULL) - ERROR("fopen"); - - while (fgets(line, 4096, file)) { - table->exp_nr++; - - if (mod_column) - continue; - - /* Find the module column */ - for (column = 1, tmp = line; (tmp = strchr(tmp, '\t')); column++) { - tmp++; - if (*tmp && !strncmp(tmp, "vmlinux", 7)) - mod_column = column; - } - } - - if (table->exp_nr && !mod_column) - ERROR("Module.symvers: invalid format"); - - table->exp_syms = malloc(table->exp_nr * sizeof(*table->exp_syms)); - if (!table->exp_syms) - ERROR("malloc table.exp_syms"); - memset(table->exp_syms, 0, - table->exp_nr * sizeof(*table->exp_syms)); - - rewind(file); - for (i = 0; fgets(line, 4096, file); i++) { - char *name = NULL, *mod = NULL; - - for (column = 1, tmp = line; (tmp = strchr(tmp, '\t')); column++) { - *tmp++ = '\0'; - if (*tmp && column == 1) - name = tmp; - else if (*tmp && column == mod_column) - mod = tmp; - } - - if (!name || !mod) - continue; - - symname = strdup(name); - if (!symname) - perror("strdup"); - - objname = make_modname(mod); - - table->exp_syms[i].name = symname; - table->exp_syms[i].objname = objname; - } - - fclose(file); -} - -struct lookup_table *lookup_open(char *symtab_path, char *objname, - char *symvers_path, struct kpatch_elf *kelf) -{ - struct lookup_table *table; - - table = malloc(sizeof(*table)); - if (!table) - ERROR("malloc table"); - memset(table, 0, sizeof(*table)); - - table->objname = objname; - symtab_read(table, symtab_path); - symvers_read(table, symvers_path); - - find_local_syms_multiple(table, kelf); - - return table; -} - -void lookup_close(struct lookup_table *table) -{ - int i; - struct object_symbol *obj_sym; - struct export_symbol *exp_sym; - - for_each_obj_symbol(i, obj_sym, table) - free(obj_sym->name); - free(table->obj_syms); - - for_each_exp_symbol(i, exp_sym, table) { - free(exp_sym->name); - free(exp_sym->objname); - } - free(table->exp_syms); - free(table); -} - -static bool lookup_local_symbol(struct lookup_table *table, - struct symbol *lookup_sym, - struct lookup_result *result) -{ - struct object_symbol *sym; - unsigned long sympos = 0; - int i, in_file = 0; - - memset(result, 0, sizeof(*result)); - for_each_obj_symbol(i, sym, table) { - if (sym->bind == STB_LOCAL && !strcmp(sym->name, - lookup_sym->name)) - sympos++; - - if (lookup_sym->lookup_table_file_sym == sym) { - in_file = 1; - continue; - } - - if (!in_file) - continue; - - if (sym->type == STT_FILE) - break; - - if (sym->bind == STB_LOCAL && !strcmp(sym->name, - lookup_sym->name)) { - if (result->objname) - ERROR("duplicate local symbol found for %s", - lookup_sym->name); - - result->objname = table->objname; - result->addr = sym->addr; - result->size = sym->size; - result->sympos = sympos; - result->global = false; - result->exported = false; - } - } - - return !!result->objname; -} - -static bool lookup_exported_symbol(struct lookup_table *table, char *name, - struct lookup_result *result) -{ - struct export_symbol *sym; - int i; - - if (result) - memset(result, 0, sizeof(*result)); - - for_each_exp_symbol(i, sym, table) { - if (!strcmp(sym->name, name)) { - - if (!result) - return true; - - if (result->objname) - ERROR("duplicate exported symbol found for %s", name); - - result->objname = sym->objname; - result->addr = 0; /* determined at runtime */ - result->size = 0; /* not used for exported symbols */ - result->sympos = 0; /* always 0 for exported symbols */ - result->global = true; - result->exported = true; - } - } - - return result && result->objname; -} - -bool is_exported(struct lookup_table *table, char *name) -{ - return lookup_exported_symbol(table, name, NULL); -} - -static bool lookup_global_symbol(struct lookup_table *table, char *name, - struct lookup_result *result) -{ - struct object_symbol *sym; - int i; - - memset(result, 0, sizeof(*result)); - for_each_obj_symbol(i, sym, table) { - if ((sym->bind == STB_GLOBAL || sym->bind == STB_WEAK) && - !strcmp(sym->name, name)) { - - if (result->objname) - ERROR("duplicate global symbol found for %s", name); - - result->objname = table->objname; - result->addr = sym->addr; - result->size = sym->size; - result->sympos = 0; /* always 0 for global symbols */ - result->global = true; - result->exported = is_exported(table, name); - } - } - - return !!result->objname; -} - -bool lookup_symbol(struct lookup_table *table, struct symbol *sym, - struct lookup_result *result) -{ - if (lookup_local_symbol(table, sym, result)) - return true; - - if (lookup_global_symbol(table, sym->name, result)) - return true; - - return lookup_exported_symbol(table, sym->name, result); -} diff --git a/kpatch-build/lookup.h b/kpatch-build/lookup.h deleted file mode 100644 index e1277f1..0000000 --- a/kpatch-build/lookup.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _LOOKUP_H_ -#define _LOOKUP_H_ - -#include -#include "kpatch-elf.h" - -struct lookup_table; - -struct lookup_result { - char *objname; - unsigned long addr; - unsigned long size; - unsigned long sympos; - bool global, exported; -}; - -struct lookup_table *lookup_open(char *symtab_path, char *objname, - char *symvers_path, struct kpatch_elf *kelf); -void lookup_close(struct lookup_table *table); -bool lookup_symbol(struct lookup_table *table, struct symbol *sym, - struct lookup_result *result); - -#endif /* _LOOKUP_H_ */ diff --git a/kpatch.spec b/kpatch.spec new file mode 100755 index 0000000..d5c5e0e --- /dev/null +++ b/kpatch.spec @@ -0,0 +1,121 @@ +Name: kpatch +Version: 0.9.9 +Release: 1 +Summary: Dynamic kernel patch manager + +Group: System Environment/Kernel +License: GPLv2 +URL: https://github.com/dynup/kpatch +Source0: https://github.com/dynup/kpatch/archive/v%{version}.tar.gz + +Patch0001: 0001-kpatch-don-t-need-vmlinux.patch +Patch0002: 0002-kpatch-build-fix-some-subfunction-.cold-change-error.patch +Patch0003: 0003-kpatch-get-gcc-version-from-config-file.patch +Patch0004: 0004-get-kernel-version-from-kpatch-build.patch +Patch0005: 0005-kpatch-build-use-new-klp-arch.patch +Patch0006: 0006-check-klp_register_patch-function-symbol.patch +Patch0007: 0007-kpatch-build-set-EXTRAVERSION.patch +Patch0008: 0008-devel-an-options-for-kpatch-module-build-mode.patch +Patch0009: 0009-kpatch-build-add-DISTRO-anolis.patch + +Requires: bash kmod binutils + +BuildArch: noarch + + +%description +kpatch is a dynamic kernel patch module manager. It allows the user to manage +a collection of binary kernel patch modules which can be used to dynamically +patch the kernel without rebooting. + + +%prep +%setup -q +%autosetup -n v%{version} -p1 -Sgit + +%build +make -C man + + +%install +make install PREFIX=/usr DESTDIR=%{buildroot} -C kpatch +make install PREFIX=/usr DESTDIR=%{buildroot} -C man +make install PREFIX=/usr DESTDIR=%{buildroot} -C contrib +rm -f %{buildroot}/usr/share/man/man1/kpatch-build.1.gz +install -m 755 %{SOURCE1} %{buildroot}/usr/sbin/ + +%files +%{_sbindir}/kpatch +%{_usr}/lib/systemd/system/kpatch.service +%doc %{_mandir}/man1/kpatch.1.gz + + +%changelog +* Thu Jan 18 2024 zhangyongde - 0.9.9-1 +- Bump version to 0.9.9 + +* Fri Sep 6 2019 Joe Lawrence 0.6.1-5 +- kpatch: clarify that "kpatch unload" isn't supported (rhbz#1749299) + +* Sun Jun 23 2019 Joe Lawrence 0.6.1-3 +- Rebuild with correct RHEL-7.7 bugzilla number (rhbz#1719309) + +* Sun Jun 23 2019 Joe Lawrence 0.6.1-3 +- kpatch script: don't fail if module already loaded+enabled (rhbz#1719309) + +* Wed Jun 12 2019 Joe Lawrence 0.6.1-2 +- kpatch: patches shouldn't be unloaded on system shutdown (rhbz#1719309) + +* Thu Jun 21 2018 Joe Lawrence 0.6.1-1 +- update to 0.6.1 (rhbz#1562976) + +* Thu Nov 16 2017 Joe Lawrence 0.4.0-3 +- kpatch: better livepatch module support (rhbz#1504066) + +* Wed Oct 18 2017 Josh Poimboeuf 0.4.0-2 +- fix backwards compatibility with RHEL 7.3 patches (rhbz#1497735) + +* Mon Mar 13 2017 Josh Poimboeuf 0.4.0-1 +- update to 0.4.0 (rhbz#1427642) + +* Wed Jun 15 2016 Josh Poimboeuf 0.3.2-1 +- update to 0.3.2 (rhbz#1282508) + +* Wed Nov 18 2015 Josh Poimboeuf 0.3.1-1 +- update to 0.3.1 (rhbz#1282508) + +* Tue Sep 16 2014 Seth Jennings 0.1.10-4 +- fix dracut dependencies (rhbz#1170369) + +* Tue Sep 16 2014 Seth Jennings 0.1.10-3 +- support re-enabling forced modules (rhbz#1140268) + +* Thu Sep 11 2014 Seth Jennings 0.1.10-2 +- support modprobe format names (rhbz#1133045) + +* Thu Jul 31 2014 Josh Poimboeuf 0.1.10-1 +- update to kpatch 0.1.10 + +* Wed Jul 23 2014 Josh Poimboeuf 0.1.9-1 +- update to kpatch 0.1.9 + +* Tue Jul 15 2014 Josh Poimboeuf 0.1.8-1 +- update to kpatch 0.1.8 + +* Wed May 21 2014 Josh Poimboeuf 0.1.2-1 +- update to kpatch 0.1.2 + +* Mon May 19 2014 Josh Poimboeuf 0.1.1-2 +- fix initramfs core module path + +* Mon May 19 2014 Josh Poimboeuf 0.1.1-1 +- rebase to kpatch 0.1.1 + +* Fri May 9 2014 Josh Poimboeuf 0.1.0-2 +- modprobe core module + +* Tue May 6 2014 Josh Poimboeuf 0.1.0-1 +- Initial kpatch release 0.1.0 + +* Thu Jan 30 2014 Josh Poimboeuf 0.0-1 +- Initial build diff --git a/kpatch/Makefile b/kpatch/Makefile deleted file mode 100644 index 448968f..0000000 --- a/kpatch/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../Makefile.inc - -all: - -install: all - $(INSTALL) -d $(SBINDIR) - $(INSTALL) kpatch $(SBINDIR) - -uninstall: - $(RM) $(SBINDIR)/kpatch - -clean: diff --git a/kpatch/kpatch b/kpatch/kpatch deleted file mode 100755 index 2a00b07..0000000 --- a/kpatch/kpatch +++ /dev/null @@ -1,649 +0,0 @@ -#!/bin/bash -# -# kpatch hot patch module management script -# -# Copyright (C) 2014 Seth Jennings -# Copyright (C) 2014 Josh Poimboeuf -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, -# 02110-1301, USA. - -# This is the kpatch user script that manages installing, loading, and -# displaying information about kernel patch modules installed on the system. - -INSTALLDIR=/var/lib/kpatch -SCRIPTDIR="$(readlink -f "$(dirname "$(type -p "$0")")")" -VERSION="0.9.7" -POST_ENABLE_WAIT=15 # seconds -POST_SIGNAL_WAIT=60 # seconds -MODULE_REF_WAIT=15 # seconds - -# How many times to try loading the patch if activeness safety check fails. -MAX_LOAD_ATTEMPTS=5 -# How long to wait before retry, in seconds. -RETRY_INTERVAL=2 - -usage_cmd() { - printf ' %-20s\n%s\n' "$1" "$(fmt -w 80 <(echo " $2"))" >&2 -} - -usage () { - # ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION - # When changing this, please also update the man page. Thanks! - echo "usage: kpatch []" >&2 - echo >&2 - echo "Valid commands:" >&2 - usage_cmd "install [-k|--kernel-version=] " "install patch module to be loaded at boot" - usage_cmd "uninstall [-k|--kernel-version=] " "uninstall patch module" - echo >&2 - usage_cmd "load --all" "load all installed patch modules into the running kernel" - usage_cmd "load " "load patch module into the running kernel" - usage_cmd "unload --all" "unload all patch modules from the running kernel" - usage_cmd "unload " "unload patch module from the running kernel" - echo >&2 - usage_cmd "info " "show information about a patch module" - echo >&2 - usage_cmd "list" "list installed patch modules" - echo >&2 - usage_cmd "signal" "signal/poke any process stalling the current patch transition. This is only useful on systems that have the sysfs livepatch signal interface. On other systems, the signaling should be done automatically by the OS and this subcommand is a no-op." - echo >&2 - usage_cmd "version" "display the kpatch version" - exit 1 -} - -warn() { - echo "kpatch: $*" >&2 -} - -die() { - warn "$@" - exit 1 -} - -__find_module () { - MODULE="$1" - [[ -f "$MODULE" ]] && return - - MODULE="$INSTALLDIR/$(uname -r)/$1" - [[ -f "$MODULE" ]] && return - - return 1 -} - -mod_name () { - MODNAME="$(basename "$1")" - MODNAME="${MODNAME%.ko}" - MODNAME="${MODNAME//-/_}" -} - -find_module () { - arg="$1" - if [[ "$arg" =~ \.ko ]]; then - __find_module "$arg" || return 1 - mod_name "$MODULE" - return - else - for i in "$INSTALLDIR/$(uname -r)"/*; do - mod_name "$i" - if [[ "$MODNAME" == "$arg" ]]; then - MODULE="$i" - return - fi - done - fi - - return 1 -} - -find_core_module() { - COREMOD="$SCRIPTDIR"/../kmod/core/kpatch.ko - [[ -f "$COREMOD" ]] && return - - COREMOD="/usr/local/lib/kpatch/$(uname -r)/kpatch.ko" - [[ -f "$COREMOD" ]] && return - - COREMOD="/usr/lib/kpatch/$(uname -r)/kpatch.ko" - [[ -f "$COREMOD" ]] && return - - COREMOD="/usr/local/lib/modules/$(uname -r)/extra/kpatch/kpatch.ko" - [[ -f "$COREMOD" ]] && return - - COREMOD="/usr/lib/modules/$(uname -r)/extra/kpatch/kpatch.ko" - [[ -f "$COREMOD" ]] && return - - return 1 -} - -kpatch_core_loaded() { - [[ -d "/sys/kernel/kpatch" ]] -} - -core_loaded () { - [[ -d "/sys/kernel/kpatch" ]] || [[ -d "/sys/kernel/livepatch" ]] -} - -get_module_name () { - readelf -p .gnu.linkonce.this_module "$1" | grep '\[.*\]' | awk '{print $3}' -} - -init_sysfs_var() { - # If the kernel is configured with CONFIG_LIVEPATCH, use that. - # Otherwise, use the kpatch core module (kpatch.ko). - if [[ -e /sys/kernel/livepatch ]] ; then - # livepatch ABI - SYSFS="/sys/kernel/livepatch" - - elif [[ -e /sys/kernel/kpatch/patches ]] ; then - # kpatch pre-0.4 ABI - SYSFS="/sys/kernel/kpatch/patches" - - else - # kpatch 0.4 ABI - SYSFS="/sys/kernel/kpatch" - fi -} - -verify_module_checksum () { - modname="$(get_module_name "$1")" - [[ -z "$modname" ]] && return 1 - - checksum="$(readelf -p .kpatch.checksum "$1" 2>&1 | grep '\[.*\]' | awk '{print $3}')" - - # Fail checksum match only if both exist and diverge - if [[ -n "$checksum" ]] && [[ -e "$SYSFS/${modname}/checksum" ]] ; then - sysfs_checksum="$(cat "$SYSFS/${modname}/checksum")" - [[ "$checksum" == "$sysfs_checksum" ]] || return 1 - fi - - return 0 -} - -in_transition() { - local moddir="$SYSFS/$1" - [[ $(cat "$moddir/transition" 2>/dev/null) == "1" ]] && return 0 - return 1 -} - -is_stalled() { - local module="$1" - local pid="$2" - local patch_enabled - local patch_state - - patch_enabled="$(cat "$SYSFS/$module/enabled" 2>/dev/null)" - patch_state="$(cat "/proc/$pid/patch_state" 2>/dev/null)" - - # No patch transition in progress - [[ "$patch_state" == "-1" ]] && return 1 - - [[ -z "$patch_enabled" ]] || [[ -z "$patch_state" ]] && return 1 - - # Stalls can be determined if the process state does not match - # the transition target (ie, "enabled" and "patched", "disabled" - # and "unpatched"). The state value enumerations match, so we - # can just compare them directly: - [[ "$patch_enabled" != "$patch_state" ]] && return 0 - return 1 -} - -get_transition_patch() { - local module - local modname - for module in "$SYSFS"/*; do - modname=$(basename "$module") - if in_transition "$modname" ; then - echo "$modname" - return - fi - done -} - -show_stalled_processes() { - local module - local proc_task - local tid - - module=$(get_transition_patch) - [[ -z "$module" ]] && return - - echo "" - echo "Stalled processes:" - for proc_task in /proc/[0-9]*/task/[0-9]*; do - tid=${proc_task#*/task/} - is_stalled "$module" "$tid" && echo -e "$tid $(cat "$proc_task"/comm 2>/dev/null)\nstack:\n$(cat "$proc_task"/stack 2>/dev/null)" - done -} - -signal_stalled_processes() { - local module - local proc_task - local tid - - module=$(get_transition_patch) - [[ -z "$module" ]] && return - - if [[ -e "/sys/kernel/livepatch/$module/signal" ]] ; then - echo "signaling stalled process(es):" - echo 1 > "/sys/kernel/livepatch/$module/signal" - else - warn "Livepatch process signaling is performed automatically on your system." - warn "Skipping manual process signaling." - fi -} - -wait_for_patch_transition() { - local module="$1" - local i - - in_transition "$module" || return 0 - - echo "waiting (up to $POST_ENABLE_WAIT seconds) for patch transition to complete..." - for (( i=0; i/dev/null) -gt "0" ]] -} - -wait_for_zero_module_ref_count() { - local modname="$1" - local i=0 - - # We can't rely on a zero refcount with kpatch.ko as it - # implements KPATCH_FORCE_UNSAFE with an additional reference on - # kpatch-patch modules to avoid potential crashes. - kpatch_core_loaded && return 0 - - module_ref_count "$modname" || return 0 - - echo "waiting (up to $MODULE_REF_WAIT seconds) for module refcount..." - for (( i=0; i "${moddir}/enabled" || die "failed to re-enable module $modname" - if ! wait_for_patch_transition "$modname" ; then - show_stalled_processes - echo "module $modname did not complete its transition, disabling..." - echo 0 > "${moddir}/enabled" || die "failed to disable module $modname" - wait_for_patch_transition "$modname" - die "error: failed to re-enable module $modname (transition stalled), patch disabled" - fi - return - else - die "error: cannot re-enable patch module $modname, cannot verify checksum match" - fi - else - echo "module named $modname already loaded and enabled" - fi - else - # Cleanup possibly loaded, but disabled patch. - remove_module "$modname" "quiet" - - echo "loading patch module: $module" - local i=0 - while true; do - out="$(LC_ALL=C insmod "$module" 2>&1)" - [[ -z "$out" ]] && break - echo "$out" 1>&2 - [[ ! "$out" =~ "Device or resource busy" ]] && - die "failed to load module $module" - - # "Device or resource busy" means the activeness safety check - # failed. Retry in a few seconds. - i=$((i+1)) - if [[ $i -eq $MAX_LOAD_ATTEMPTS ]]; then - die "failed to load module $module" - break - else - warn "retrying..." - sleep $RETRY_INTERVAL - fi - done - fi - - if ! wait_for_patch_transition "$modname" ; then - show_stalled_processes - echo "module $modname did not complete its transition, unloading..." - unload_module "$modname" - die "error: failed to load module $modname (transition stalled)" - fi - - return 0 -} - -disable_patch () { - local modname="$1" - - local enabled="$SYSFS/$modname/enabled" - if ! [[ -e "$enabled" ]]; then - if [[ -d "/sys/module/$modname" ]] ; then - # Module is loaded, but already disabled - return 0 - fi - warn "patch module $modname is not loaded" - return 1 - fi - - if [[ "$(cat "$enabled")" -eq 1 ]]; then - echo "disabling patch module: $modname" - local i=0 - while true; do - out="$(export LC_ALL=C; sh -c "echo 0 > $enabled" 2>&1)" - [[ -z "$out" ]] && break - echo "$out" 1>&2 - if [[ ! "$out" =~ "Device or resource busy" ]]; then - return 1 - fi - - # "Device or resource busy" means the activeness safety check - # failed. Retry in a few seconds. - i=$((i+1)) - if [[ $i -eq $MAX_LOAD_ATTEMPTS ]]; then - return 1 - else - warn "retrying..." - sleep $RETRY_INTERVAL - fi - done - fi -} - -disable_patch_strict () { - local modname="$1" - - disable_patch "$modname" || die "failed to disable module $modname" - - if ! wait_for_patch_transition "$modname" ; then - die "transition stalled for $modname" - fi -} - -remove_module () { - local modname="$1" - - if ! wait_for_zero_module_ref_count "$modname"; then - die "failed to unload module $modname (refcnt)" - fi - - if [[ "$#" -lt 2 || "$2" != "quiet" ]] ; then - echo "unloading patch module: $modname" - fi - # ignore any error here because rmmod can fail if the module used - # KPATCH_FORCE_UNSAFE. - rmmod "$modname" 2> /dev/null || return 0 -} - -unload_module () { - PATCH="${1//-/_}" - PATCH="${PATCH%.ko}" - disable_patch_strict "$PATCH" - remove_module "$PATCH" -} - -get_module_version() { - MODVER="$(modinfo -F vermagic "$1")" || return 1 - MODVER="${MODVER/ */}" -} - -unset MODULE - -# Initialize the $SYSFS var. This only works if the core module has been -# loaded. Otherwise, the value of $SYSFS doesn't matter at this point anyway, -# and we'll have to call this function again after loading it. -init_sysfs_var - -[[ "$#" -lt 1 ]] && usage -case "$1" in -"load") - [[ "$#" -ne 2 ]] && usage - case "$2" in - "--all") - for i in "$INSTALLDIR/$(uname -r)"/*.ko; do - [[ -e "$i" ]] || continue - load_module "$i" || die "failed to load module $i" - done - ;; - *) - PATCH="$2" - find_module "$PATCH" || die "can't find $PATCH" - load_module "$MODULE" || die "failed to load module $PATCH" - ;; - esac - ;; - -"unload") - [[ "$#" -ne 2 ]] && usage - case "$2" in - "--all") - # Versions of linux < 5.1 livepatching require patches to be - # disabled in the inverse order in which they were enabled. - while true; do - nr_disabled=0 - for module in "$SYSFS"/*; do - modname="$(basename "$module")" - - [[ -e "$module" ]] || continue - disable_patch "$modname" || continue - if ! wait_for_patch_transition "$modname" ; then - warn "transition stalled for $modname" - continue - fi - remove_module "$modname" - nr_disabled=$((nr_disabled + 1)) - done - if [ $nr_disabled -eq 0 ]; then - break - fi - done - - nr_remaining=0 - for module in "$SYSFS"/*; do - modname="$(basename "$module")" - - [[ -e "$module" ]] || continue - nr_remaining=$((nr_remaining + 1)) - warn "failed to unload module $modname" - done - - if [ $nr_remaining -gt 0 ]; then - exit 1 - fi - ;; - *) - unload_module "$(basename "$2")" || die "failed to unload module $2" - ;; - esac - ;; - -"install") - KVER="$(uname -r)" - shift - options="$(getopt -o k: -l "kernel-version:" -- "$@")" || die "getopt failed" - eval set -- "$options" - while [[ $# -gt 0 ]]; do - case "$1" in - -k|--kernel-version) - KVER="$2" - shift - ;; - --) - [[ -z "$2" ]] && die "no module file specified" - PATCH="$2" - ;; - esac - shift - done - - [[ ! -e "$PATCH" ]] && die "$PATCH doesn't exist" - [[ "${PATCH: -3}" == ".ko" ]] || die "$PATCH isn't a .ko file" - - get_module_version "$PATCH" || die "modinfo failed" - [[ "$KVER" != "$MODVER" ]] && die "invalid module version $MODVER for kernel $KVER" - - [[ -e "$INSTALLDIR/$KVER/$(basename "$PATCH")" ]] && die "$PATCH is already installed" - - echo "installing $PATCH ($KVER)" - mkdir -p "$INSTALLDIR/$KVER" || die "failed to create install directory" - cp -f "$PATCH" "$INSTALLDIR/$KVER" || die "failed to install module $PATCH" - command -v systemctl > /dev/null 2>&1 && systemctl enable kpatch.service - ;; - -"uninstall") - KVER="$(uname -r)" - shift - options="$(getopt -o k: -l "kernel-version:" -- "$@")" || die "getopt failed" - eval set -- "$options" - while [[ $# -gt 0 ]]; do - case "$1" in - -k|--kernel-version) - KVER="$2" - shift - ;; - --) - [[ -z "$2" ]] && die "no module file specified" - PATCH="$2" - [[ "$PATCH" != "$(basename "$PATCH")" ]] && die "please supply patch module name without path" - ;; - esac - shift - done - - MODULE="$INSTALLDIR/$KVER/$PATCH" - if [[ ! -f "$MODULE" ]]; then - mod_name "$PATCH" - PATCHNAME="$MODNAME" - for i in "$INSTALLDIR/$KVER"/*; do - mod_name "$i" - if [[ "$MODNAME" == "$PATCHNAME" ]]; then - MODULE="$i" - break - fi - done - fi - - [[ ! -e "$MODULE" ]] && die "$PATCH is not installed for kernel $KVER" - - echo "uninstalling $PATCH ($KVER)" - rm -f "$MODULE" || die "failed to uninstall module $PATCH" - rmdir --ignore-fail-on-non-empty "$INSTALLDIR/$KVER" || die "failed to remove directory $INSTALLDIR/$KVER" - rmdir --ignore-fail-on-non-empty "$INSTALLDIR" || die "failed to remove directory $INSTALLDIR" - - ;; - -"list") - [[ "$#" -ne 1 ]] && usage - echo "Loaded patch modules:" - for module in "$SYSFS"/*; do - if [[ -e "$module" ]]; then - modname=$(basename "$module") - if [[ "$(cat "$module/enabled" 2>/dev/null)" -eq 1 ]]; then - in_transition "$modname" && state="enabling..." \ - || state="enabled" - else - in_transition "$modname" && state="disabling..." \ - || state="disabled" - fi - echo "$modname [$state]" - fi - done - show_stalled_processes - echo "" - echo "Installed patch modules:" - for kdir in "$INSTALLDIR"/*; do - [[ -e "$kdir" ]] || continue - for module in "$kdir"/*.ko; do - [[ -e "$module" ]] || continue - mod_name "$module" - echo "$MODNAME ($(basename "$kdir"))" - done - done - ;; - -"info") - [[ "$#" -ne 2 ]] && usage - PATCH="$2" - find_module "$PATCH" || die "can't find $PATCH" - echo "Patch information for $PATCH:" - modinfo "$MODULE" || die "failed to get info for module $PATCH" - ;; - -"signal") - [[ "$#" -ne 1 ]] && usage - signal_stalled_processes - ;; - -"help"|"-h"|"--help") - usage - ;; - -"version"|"-v"|"--version") - echo "$VERSION" - ;; - -*) - echo "subcommand $1 not recognized" - usage - ;; -esac diff --git a/man/Makefile b/man/Makefile deleted file mode 100644 index 762042d..0000000 --- a/man/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -include ../Makefile.inc - -all: kpatch.1.gz kpatch-build.1.gz - -kpatch.1.gz: kpatch.1 - gzip -c -9 $< > $@ - -kpatch-build.1.gz: kpatch-build.1 - gzip -c -9 $< > $@ - -install: all - $(INSTALL) -d $(MANDIR) - $(INSTALL) -m 644 kpatch.1.gz $(MANDIR) - $(INSTALL) -m 644 kpatch-build.1.gz $(MANDIR) - -uninstall: - $(RM) $(MANDIR)/kpatch.1* - $(RM) $(MANDIR)/kpatch-build.1* - -clean: - $(RM) kpatch.1.gz - $(RM) kpatch-build.1.gz diff --git a/man/kpatch-build.1 b/man/kpatch-build.1 deleted file mode 100644 index f0e4d7d..0000000 --- a/man/kpatch-build.1 +++ /dev/null @@ -1,83 +0,0 @@ -.\" Manpage for kpatch-build. -.\" Contact udoseidel@gmx.de to correct errors or typos. -.TH man 1 "23 Mar 2014" "1.0" "kpatch-build man page" -.SH NAME -kpatch-build \- build script -.SH SYNOPSIS -kpatch-build [options] -.SH DESCRIPTION -This script takes a patch based on the version of the kernel -currently running and creates a kernel module that will replace -modified functions in the kernel such that the patched code takes -effect. - -.SH OPTIONS - --h|--help - Show this help message - --a|--archversion - Specify the kernel arch version - --r|--sourcerpm - Specify kernel source RPM - --s|--sourcedir - Specify kernel source directory - --c|--config - Specify kernel config file - --v|--vmlinux - Specify original vmlinux - --j|--jobs - Specify the number of make jobs - --t|--target - Specify custom kernel build targets - --n|--name - Specify the name of the kpatch module - --o|--output - Specify output folder - --d|--debug - Keep scratch files in /tmp - (can be specified multiple times) - ---oot-module - Enable patching out-of-tree module, - specify current version of module - ---oot-module-src - Specify out-of-tree module source directory - --R|--non-replace - Disable replace flag of KLP - (replace is on by default) - ---skip-cleanup - Skip post-build cleanup - ---skip-compiler-check - Skips check that ensures that the system compiler version and - the compiler version that built the kernel match. Skipping this - check is not recommended, but is useful if the exact compiler - version is not available or is not easily installed. Use - only when confident that the two versions of compiler output - identical objects for a given target. Otherwise, use of - this option might result in unexpected changed objects - being detected. - -.SH SEE ALSO -kpatch(1) -.SH BUGS -No known bugs. -.SH AUTHOR -Udo Seidel (udoseidel@gmx.de) -.SH COPYRIGHT -Copyright (C) 2014: Seth Jennings , Copyright (C) -2013,2014: Josh Poimboeuf - diff --git a/man/kpatch.1 b/man/kpatch.1 deleted file mode 100644 index 51c9811..0000000 --- a/man/kpatch.1 +++ /dev/null @@ -1,56 +0,0 @@ -.\" Manpage for kpatch. -.\" Contact udoseidel@gmx.de to correct errors or typos. -.TH man 1 "23 Mar 2014" "1.0" "kpatch man page" -.SH NAME -kpatch \- hot patch module management -.SH SYNOPSIS -kpatch [] -.SH DESCRIPTION -kpatch is a user script that manages installing, loading, and -displaying information about kernel patch modules installed on -the system. -.SH COMMANDS - -install [-k|--kernel-version=] - install patch module to be loaded at boot - -uninstall [-k|--kernel-version=] - uninstall patch module - -load --all - load all installed patch modules into the running kernel - -load - load patch module into the running kernel - -unload --all - unload all patch modules from the running kernel - -unload - unload patch module from the running kernel - -info - show information about a patch module - -list - list installed patch modules - -signal - signal/poke any process stalling the current patch transition. - This is only useful on systems that have the sysfs livepatch signal interface. - On other systems, the signaling should be done automatically by the OS and - this subcommand is a no-op. - -version - display the kpatch version - -.SH SEE ALSO -kpatch-build(1) -.SH BUGS -No known bugs. -.SH AUTHOR -Udo Seidel (udoseidel@gmx.de) -.SH COPYRIGHT -Copyright (C) 2014: Seth Jennings and -Josh Poimboeuf - diff --git a/test/difftree.sh b/test/difftree.sh deleted file mode 100755 index 9a0ebf4..0000000 --- a/test/difftree.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -# The purpose of this test script is to determine if create-diff-object can -# properly recognize object file equivalence when passed the same file for both -# the original and patched objects. This verifies that create-diff-object is -# correctly parsing, correlating, and comparing the different elements of the -# object file. In practice, a situation similar to the test case occurs when a -# commonly included header file changes, causing Make to rebuild many objects -# that have no functional change. - -# This script requires a built kernel object tree to be in the kpatch cache -# directory at $HOME/.kpatch/obj - -#set -x - -OBJDIR="$HOME/.kpatch/obj" -# shellcheck disable=SC2046 -SCRIPTDIR=$(readlink -f $(dirname $(type -p "$0"))) -TEMPDIR=$(mktemp -d) -RESULTSDIR="$TEMPDIR/results" - -if [[ ! -d $OBJDIR ]]; then - echo "please run kpatch-build to populate the object tree in $OBJDIR" -fi - -cd "$OBJDIR" || exit 1 -# shellcheck disable=SC2044 -for i in $(find ./* -name '*.o') -do - # copied from kpatch-build/kpatch-gcc; keep in sync - case $i in - *.mod.o|\ - *built-in.o|\ - *built-in.a|\ - vmlinux.o|\ - .tmp_kallsyms1.o|\ - .tmp_kallsyms2.o|\ - init/version.o|\ - arch/x86/boot/version.o|\ - arch/x86/boot/compressed/eboot.o|\ - arch/x86/boot/header.o|\ - arch/x86/boot/compressed/efi_stub_64.o|\ - arch/x86/boot/compressed/piggy.o|\ - kernel/system_certificates.o|\ - .*.o) - continue - ;; - esac - # skip objects that are the linked product of more than one object file - [[ $(readelf -s "$i" | awk '$4=="FILE" {n++} END {print n}') -ne 1 ]] && continue - "$SCRIPTDIR"/../kpatch-build/create-diff-object "$i" "$i" "/usr/lib/debug/lib/modules/$(uname -r)/vmlinux" "$TEMPDIR/output.o" > "$TEMPDIR/log.txt" 2>&1 - RETCODE=$? - # expect RETCODE to be 3 indicating no change - [[ $RETCODE -eq 3 ]] && continue - # otherwise record error - # shellcheck disable=SC2046 - mkdir -p "$RESULTSDIR"/$(dirname "$i") || exit 1 - cp "$i" "$RESULTSDIR/$i" || exit 1 - case $RETCODE in - 139) - echo "$i: segfault" | tee - if [[ ! -e core ]]; then - echo "no corefile, run "ulimit -c unlimited" to capture corefile" - else - mv core "$RESULTSDIR/$i.core" || exit 1 - fi - ;; - 0) - echo "$i: incorrectly detected change" - mv "$TEMPDIR/log.txt" "$RESULTSDIR/$i.log" || exit 1 - ;; - 1|2) - echo "$i: error code $RETCODE" - mv "$TEMPDIR/log.txt" "$RESULTSDIR/$i.log" || exit 1 - ;; - *) - exit 1 # script error - ;; - esac -done -rm -f "$TEMPDIR/log.txt" > /dev/null 2>&1 - -# try to group the errors together in some meaningful way -cd "$RESULTSDIR" || exit 1 -echo "" -echo "Results:" -# shellcheck disable=SC2044 -for i in $(find ./* -iname '*.log') -do - head -1 "$i" | cut -f2-3 -d':' -done | sort | uniq -c | sort -n -r | tee "$TEMPDIR/results.log" - -echo "results are in $TEMPDIR" diff --git a/test/integration/.gitignore b/test/integration/.gitignore deleted file mode 100644 index 42aff9e..0000000 --- a/test/integration/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -test.log -COMBINED.patch diff --git a/test/integration/Makefile b/test/integration/Makefile deleted file mode 100644 index e18d8d0..0000000 --- a/test/integration/Makefile +++ /dev/null @@ -1,51 +0,0 @@ -include /etc/os-release - -PATCH_DIR?=${ID}-${VERSION_ID} - -all: - $(error please specify local or remote) - -local: slow - -remote: remote_slow - -slow: clean - ./kpatch-test --kpatch-build-opts="$(KPATCH_BUILD_OPTS)" -d $(PATCH_DIR) $(PATCHES) - -quick: clean - ./kpatch-test --kpatch-build-opts="$(KPATCH_BUILD_OPTS)" -d $(PATCH_DIR) --quick $(PATCHES) - -cached: - ./kpatch-test --kpatch-build-opts="$(KPATCH_BUILD_OPTS)" -d $(PATCH_DIR) --cached $(PATCHES) - -vagrant: vagrant-quick - -vagrant-quick: - ./test-vagrant - -vagrant-slow: - ./test-vagrant --slow - -clean: - rm -f *.ko *.log COMBINED.patch - -check_host: -ifndef SSH_HOST - $(error SSH_HOST is undefined) -endif - -SSH_USER ?= root - -remote_setup: check_host - ssh $(SSH_USER)@$(SSH_HOST) exit - ssh $(SSH_USER)@$(SSH_HOST) "ls kpatch-setup &> /dev/null" || \ - (scp remote-setup $(SSH_USER)@$(SSH_HOST):kpatch-setup && \ - ssh $(SSH_USER)@$(SSH_HOST) "./kpatch-setup") - -remote_sync: remote_setup - ssh $(SSH_USER)@$(SSH_HOST) "rm -rf kpatch-test" - rsync -Cavz --include=core $(shell readlink -f ../../..) $(SSH_USER)@$(SSH_HOST):kpatch-test - ssh $(SSH_USER)@$(SSH_HOST) "cd kpatch-test/kpatch && make" - -remote_slow: remote_sync - ssh $(SSH_USER)@$(SSH_HOST) "cd kpatch-test/kpatch/test/integration && make slow" diff --git a/test/integration/centos-7 b/test/integration/centos-7 deleted file mode 120000 index 66d70af..0000000 --- a/test/integration/centos-7 +++ /dev/null @@ -1 +0,0 @@ -rhel-7.8/ \ No newline at end of file diff --git a/test/integration/centos-8 b/test/integration/centos-8 deleted file mode 120000 index 64546c1..0000000 --- a/test/integration/centos-8 +++ /dev/null @@ -1 +0,0 @@ -rhel-8.2 \ No newline at end of file diff --git a/test/integration/common/multiple.template b/test/integration/common/multiple.template deleted file mode 100755 index 678279c..0000000 --- a/test/integration/common/multiple.template +++ /dev/null @@ -1,80 +0,0 @@ -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" -ROOTDIR="$(readlink -f $SCRIPTDIR/../../..)" -KPATCH="sudo $ROOTDIR/kpatch/kpatch" - -MODULE_PREFIX="test-" -MODULE_POSTFIX=".ko" -TEST_POSTFIX="-LOADED.test" -PATCH_POSTFIX=".patch" -DISABLED_POSTFIX="${PATCH_POSTFIX}.disabled" - -set -o errexit - -declare -a loaded_modules - -cleanup_modules() { - for ((idx=${#loaded_modules[@]}-1 ; idx>=0 ; idx--)); do - mod=${loaded_modules[idx]} - $KPATCH unload $mod - done -} - -die_clean() { - cleanup_modules - exit 1 -} - -die() { - echo "ERROR: $@" >&2 - die_clean -} - -ko_to_test() { - tmp=${1%${MODULE_POSTFIX}}${TEST_POSTFIX} - echo ${tmp#${MODULE_PREFIX}} -} - -# make sure any modules added here are disjoint -declare -a modules - -for file in "${SCRIPTDIR}"/*"${TEST_POSTFIX}"; do - name=$(basename ${file}) - skip=0 - for bname in "${blacklist[@]}"; do - if [ "${bname}" == "${name}" ]; then - skip=1 - break - fi - done - if ! [ -e ${file/${TEST_POSTFIX}/${PATCH_POSTFIX}} ] && \ - [ -e ${file/${TEST_POSTFIX}/${DISABLED_POSTFIX}} ]; then - skip=1 - fi - if [ ${skip} -eq 0 ]; then - modules+=(${MODULE_PREFIX}${name%${TEST_POSTFIX}}${MODULE_POSTFIX}) - fi -done - -for mod in "${modules[@]}"; do - testprog=$(ko_to_test $mod) - $SCRIPTDIR/$testprog && die "$SCRIPTDIR/$testprog succeeded before loading any modules" -done - -for mod in "${modules[@]}"; do - $KPATCH load $mod || die_clean - loaded_modules+=($mod) -done - -for mod in "${modules[@]}"; do - testprog=$(ko_to_test $mod) - $SCRIPTDIR/$testprog || die "$SCRIPTDIR/$testprog failed after loading modules" -done - -cleanup_modules - -for mod in "${modules[@]}"; do - testprog=$(ko_to_test $mod) - $SCRIPTDIR/$testprog && die "$SCRIPTDIR/$testprog succeeded after unloading modules" -done - -exit 0 diff --git a/test/integration/fedora-27/README b/test/integration/fedora-27/README deleted file mode 100644 index 82dad91..0000000 --- a/test/integration/fedora-27/README +++ /dev/null @@ -1 +0,0 @@ -4.13.9-300.fc27.x86_64 diff --git a/test/integration/fedora-27/data-new-LOADED.test b/test/integration/fedora-27/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/fedora-27/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/fedora-27/data-new.patch b/test/integration/fedora-27/data-new.patch deleted file mode 100644 index a205824..0000000 --- a/test/integration/fedora-27/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-11-17 15:58:41.113211972 -0500 -+++ src/fs/proc/meminfo.c 2017-11-17 15:58:58.554211972 -0500 -@@ -42,6 +42,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -153,6 +155,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/fedora-27/gcc-static-local-var-6.patch b/test/integration/fedora-27/gcc-static-local-var-6.patch deleted file mode 100644 index 0272159..0000000 --- a/test/integration/fedora-27/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c -index 9bf2604..026ac6c 100644 ---- a/net/ipv6/netfilter.c -+++ b/net/ipv6/netfilter.c -@@ -109,6 +109,8 @@ static int nf_ip6_reroute(struct net *net, struct sk_buff *skb, - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -122,6 +124,9 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/fedora-27/macro-callbacks.patch b/test/integration/fedora-27/macro-callbacks.patch deleted file mode 100644 index 569cc7c..0000000 --- a/test/integration/fedora-27/macro-callbacks.patch +++ /dev/null @@ -1,163 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - -diff -Nupr src.old/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.old/drivers/input/joydev.c 2017-09-03 16:56:17.000000000 -0400 -+++ src/drivers/input/joydev.c 2018-03-22 16:32:40.963082354 -0400 -@@ -1010,3 +1010,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.old/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.old/drivers/input/misc/pcspkr.c 2018-03-22 16:29:27.716082354 -0400 -+++ src/drivers/input/misc/pcspkr.c 2018-03-22 16:32:40.963082354 -0400 -@@ -132,3 +132,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.old/fs/aio.c src/fs/aio.c ---- src.old/fs/aio.c 2017-09-03 16:56:17.000000000 -0400 -+++ src/fs/aio.c 2018-03-22 16:32:40.962082354 -0400 -@@ -46,6 +46,50 @@ - - #include "internal.h" - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled b/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled deleted file mode 100755 index e2b647d..0000000 --- a/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo && grep kpatch=1 /proc/cmdline diff --git a/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW.patch.disabled b/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW.patch.disabled deleted file mode 100644 index a0a183b..0000000 --- a/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW.patch.disabled +++ /dev/null @@ -1,40 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/767 ---- -Index: src/fs/proc/cmdline.c -=================================================================== ---- src.orig/fs/proc/cmdline.c -+++ src/fs/proc/cmdline.c -@@ -7,7 +7,7 @@ - static int cmdline_proc_show(struct seq_file *m, void *v) - { - seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_puts(m, " kpatch=1\n"); - return 0; - } - -Index: src/fs/proc/meminfo.c -=================================================================== ---- src.orig/fs/proc/meminfo.c -+++ src/fs/proc/meminfo.c -@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - - #ifdef CONFIG_MEMORY_FAILURE - seq_printf(m, "HardwareCorrupted: %5lu kB\n", -Index: src/include/linux/kernel.h -=================================================================== ---- src.orig/include/linux/kernel.h -+++ src/include/linux/kernel.h -@@ -3,6 +3,7 @@ - #define _LINUX_KERNEL_H - - -+ - #include - #include - #include diff --git a/test/integration/fedora-27/module-call-external.patch b/test/integration/fedora-27/module-call-external.patch deleted file mode 100644 index 5dced50..0000000 --- a/test/integration/fedora-27/module-call-external.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2017-11-17 15:58:26.667211972 -0500 -+++ src/fs/nfsd/export.c 2017-11-17 15:59:26.338211972 -0500 -@@ -1194,6 +1194,8 @@ static void exp_flags(struct seq_file *m - } - } - -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1203,6 +1205,7 @@ static int e_show(struct seq_file *m, vo - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2017-11-17 15:58:49.333211972 -0500 -+++ src/net/netlink/af_netlink.c 2017-11-17 15:59:26.338211972 -0500 -@@ -2739,4 +2739,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/fedora-27/module-shadow.patch.disabled b/test/integration/fedora-27/module-shadow.patch.disabled deleted file mode 100644 index 37c7997..0000000 --- a/test/integration/fedora-27/module-shadow.patch.disabled +++ /dev/null @@ -1,24 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/vmx.c src/arch/x86/kvm/vmx.c ---- src.orig/arch/x86/kvm/vmx.c 2017-11-17 15:58:19.369211972 -0500 -+++ src/arch/x86/kvm/vmx.c 2017-11-17 15:59:29.615211972 -0500 -@@ -11259,10 +11259,20 @@ static void vmx_leave_nested(struct kvm_ - * It should only be called before L2 actually succeeded to run, and when - * vmcs01 is current (it doesn't leave_guest_mode() or switch vmcss). - */ -+#include "kpatch.h" - static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification) - { -+ int *kpatch; -+ -+ kpatch = kpatch_shadow_alloc(vcpu, "kpatch", sizeof(*kpatch), -+ GFP_KERNEL); -+ if (kpatch) { -+ kpatch_shadow_get(vcpu, "kpatch"); -+ kpatch_shadow_free(vcpu, "kpatch"); -+ } -+ - load_vmcs12_host_state(vcpu, vmcs12); - vmcs12->vm_exit_reason = reason | VMX_EXIT_REASONS_FAILED_VMENTRY; - vmcs12->exit_qualification = qualification; diff --git a/test/integration/fedora-27/multiple.test b/test/integration/fedora-27/multiple.test deleted file mode 100755 index a7ea608..0000000 --- a/test/integration/fedora-27/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-cmdline-rebuild-SLOW-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/fedora-27/new-function.patch b/test/integration/fedora-27/new-function.patch deleted file mode 100644 index 9ba590f..0000000 --- a/test/integration/fedora-27/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2017-11-17 15:58:00.462211972 -0500 -+++ src/drivers/tty/n_tty.c 2017-11-17 15:59:31.240211972 -0500 -@@ -2269,7 +2269,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2356,6 +2356,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/fedora-27/new-globals.patch b/test/integration/fedora-27/new-globals.patch deleted file mode 100644 index ef638e7..0000000 --- a/test/integration/fedora-27/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-11-17 15:58:41.126211972 -0500 -+++ src/fs/proc/cmdline.c 2017-11-17 15:59:32.886211972 -0500 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-11-17 15:59:24.724211972 -0500 -+++ src/fs/proc/meminfo.c 2017-11-17 15:59:32.887211972 -0500 -@@ -19,6 +19,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -65,6 +67,7 @@ static int meminfo_proc_show(struct seq_ - - available = si_mem_available(); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/fedora-27/remote-setup b/test/integration/fedora-27/remote-setup deleted file mode 100755 index dfcb7ae..0000000 --- a/test/integration/fedora-27/remote-setup +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -x - -# install rpms on a Fedora 22 system to prepare it for kpatch integration tests - -set -o errexit - -[[ $UID != 0 ]] && sudo=sudo - -warn() { - echo "ERROR: $1" >&2 -} - -die() { - warn "$@" - exit 1 -} - -install_rpms() { - # crude workaround for a weird dnf bug where it fails to download - $sudo dnf install -y $* || $sudo dnf install -y $* -} - -install_rpms gcc elfutils elfutils-devel pesign openssl numactl-devel wget patchutils - -$sudo dnf builddep -y kernel || $sudo dnf builddep -y kernel - -# install kernel debuginfo and devel RPMs for target kernel -kverrel=$(uname -r) -kverrel=${kverrel%.x86_64} -kver=${kverrel%%-*} -krel=${kverrel#*-} -install_rpms https://kojipkgs.fedoraproject.org/packages/kernel/$kver/$krel/x86_64/kernel-debuginfo-$kver-$krel.x86_64.rpm https://kojipkgs.fedoraproject.org/packages/kernel/$kver/$krel/x86_64/kernel-debuginfo-common-x86_64-$kver-$krel.x86_64.rpm https://kojipkgs.fedoraproject.org/packages/kernel/$kver/$krel/x86_64/kernel-devel-$kver-$krel.x86_64.rpm - -# install version of gcc which was used to build the target kernel -gccver=$(gcc --version |head -n1 |cut -d' ' -f3-) -kgccver=$(readelf -p .comment /usr/lib/debug/lib/modules/$(uname -r)/vmlinux |grep GCC: | tr -s ' ' | cut -d ' ' -f6-) -if [[ $gccver != $kgccver ]]; then - gver=$(echo $kgccver | awk '{print $1}') - grel=$(echo $kgccver | sed 's/.*-\(.*\))/\1/') - grel=$grel.$(rpm -q gcc |sed 's/.*\.\(.*\)\.x86_64/\1/') - install_rpms https://kojipkgs.fedoraproject.org/packages/gcc/$gver/$grel/x86_64/cpp-$gver-$grel.x86_64.rpm https://kojipkgs.fedoraproject.org/packages/gcc/$gver/$grel/x86_64/gcc-$gver-$grel.x86_64.rpm https://kojipkgs.fedoraproject.org/packages/gcc/$gver/$grel/x86_64/libgomp-$gver-$grel.x86_64.rpm -fi - -install_rpms ccache -ccache -M 5G diff --git a/test/integration/fedora-27/shadow-newpid-LOADED.test b/test/integration/fedora-27/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/fedora-27/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/fedora-27/shadow-newpid.patch.disabled b/test/integration/fedora-27/shadow-newpid.patch.disabled deleted file mode 100644 index 1a2c1b6..0000000 --- a/test/integration/fedora-27/shadow-newpid.patch.disabled +++ /dev/null @@ -1,78 +0,0 @@ -Index: src/fs/proc/array.c -=================================================================== ---- src.orig/fs/proc/array.c -+++ src/fs/proc/array.c -@@ -363,12 +363,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include "kpatch.h" - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = kpatch_shadow_get(p, "newpid"); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -Index: src/kernel/exit.c -=================================================================== ---- src.orig/kernel/exit.c -+++ src/kernel/exit.c -@@ -760,6 +760,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include "kpatch.h" - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -865,6 +866,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ kpatch_shadow_free(tsk, "newpid"); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -Index: src/kernel/fork.c -=================================================================== ---- src.orig/kernel/fork.c -+++ src/kernel/fork.c -@@ -2062,6 +2062,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include "kpatch.h" - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2074,6 +2075,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2100,6 +2103,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = kpatch_shadow_alloc(p, "newpid", sizeof(*newpid), -+ GFP_KERNEL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/fedora-27/warn-detect-FAIL.patch b/test/integration/fedora-27/warn-detect-FAIL.patch deleted file mode 100644 index b178639..0000000 --- a/test/integration/fedora-27/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff --git a/net/core/dev.c b/net/core/dev.c -index ef0cc6ea5f8d..9a840ec54270 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -1,3 +1,4 @@ -+ - /* - * NET3 Protocol independent device support routines. - * diff --git a/test/integration/kpatch-test b/test/integration/kpatch-test deleted file mode 100755 index 688ab1d..0000000 --- a/test/integration/kpatch-test +++ /dev/null @@ -1,398 +0,0 @@ -#!/bin/bash -# -# kpatch integration test framework -# -# Copyright (C) 2014 Josh Poimboeuf -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA, -# 02110-1301, USA. -# -# -# This is a basic integration test framework for kpatch, which tests building, -# loading, and unloading patches, as well as any other related custom tests. -# -# This script looks for test input files in the current directory. It expects -# certain file naming conventions: -# -# - foo.patch: patch that should build successfully -# -# - bar-FAIL.patch: patch that should fail to build -# -# - foo-LOADED.test: executable which tests whether the foo.patch module is -# loaded. It will be used to test that loading/unloading the patch module -# works as expected. -# -# Any other *.test files will be executed after all the patch modules have been -# built from the *.patch files. They can be used for more custom tests above -# and beyond the simple loading and unloading tests. - -shopt -s nullglob - -# shellcheck disable=SC2046 -SCRIPTDIR=$(readlink -f $(dirname $(type -p "$0"))) -ROOTDIR=$(readlink -f "$SCRIPTDIR/../..") -KPATCH="sudo $ROOTDIR/kpatch/kpatch" -unset CCACHE_HASHDIR -KPATCHBUILD="$ROOTDIR"/kpatch-build/kpatch-build -ERROR=0 -LOG=test.log -DYNDEBUG_CONTROL=/sys/kernel/debug/dynamic_debug/control -DYNDEBUG_ENABLED=1 -ARCHVERSION="$(uname -r)" -rm -f ./*.log - -PATCHDIR="${PATCHDIR:-$PWD}" -declare -a PATCH_LIST -declare -a TEST_LIST - -usage() { - echo "usage: $0 [options] [patch1 ... patchN]" >&2 - echo " patchN Pathnames of patches to test" >&2 - echo " -h, --help Show this help message" >&2 - echo " -c, --cached Don't rebuild patch modules" >&2 - echo " -d, --directory Patch directory" >&2 - echo " -q, --quick Test combined patch and -FAIL patches only" >&2 - echo " --system-kpatch-tools Use kpatch tools installed in the system" >&2 - echo " --kpatch-build-opts Additional options to pass to kpatch-build" >&2 -} - -options=$(getopt -o hcd:q -l "help,cached,directory,quick,system-kpatch-tools,kpatch-build-opts:" -- "$@") || exit 1 - -eval set -- "$options" - -while [[ $# -gt 0 ]]; do - case "$1" in - -h|--help) - usage - exit 0 - ;; - -c|--cached) - SKIPBUILD=1 - ;; - -d|--directory) - PATCHDIR="$2" - shift - ;; - -q|--quick) - QUICK=1 - ;; - --system-kpatch-tools) - KPATCH="sudo kpatch" - KPATCHBUILD="kpatch-build" - ;; - --kpatch-build-opts) - KPATCHBUILD_OPTS=$2 - shift - ;; - *) - [[ "$1" = "--" ]] && shift && continue - PATCH_LIST+=("$1") - ;; - esac - shift -done - -if [[ ${#PATCH_LIST[@]} = 0 ]]; then - PATCH_LIST=("$PATCHDIR"/*.patch) - TEST_LIST=("$PATCHDIR"/*.test) - if [[ ${#PATCH_LIST[@]} = 0 ]]; then - echo "No patches found!" - exit 1 - fi -else - for file in "${PATCH_LIST[@]}"; do - prefix=${file%%.patch} - [[ -e "$prefix-FAIL.test" ]] && TEST_LIST+=("$prefix-FAIL.test") - [[ -e "$prefix-LOADED.test" ]] && TEST_LIST+=("$prefix-LOADED.test") - done -fi - -error() { - echo "ERROR: $*" |tee -a $LOG >&2 - ERROR=$((ERROR + 1)) -} - -log() { - echo "$@" |tee -a $LOG -} - -unload_all() { - $KPATCH unload --all -} - -build_module() { - file=$1 - prefix=$(basename "${file%%.patch}") - modname="test-$prefix" - module="${modname}.ko" - - if [[ $prefix =~ -FAIL ]]; then - shouldfail=1 - else - shouldfail=0 - fi - - if [[ $SKIPBUILD -eq 1 ]]; then - skip=0 - [[ $shouldfail -eq 1 ]] && skip=1 - [[ -e $module ]] && skip=1 - [[ $skip -eq 1 ]] && log "skipping build: $prefix" && return - fi - - log "build: $prefix" - - # shellcheck disable=SC2086 - # KPATCHBUILD_OPTS may contain several space-separated options, - # it should remain without quotes. - if ! $KPATCHBUILD $KPATCHBUILD_OPTS -n "$modname" "$file" >> $LOG 2>&1; then - if [[ $shouldfail -eq 0 ]]; then - error "$prefix: build failed" - cp "$HOME/.kpatch/build.log" "$prefix.log" - fi - else - [[ $shouldfail -eq 1 ]] && error "$prefix: build succeeded when it should have failed" - fi -} - -run_load_test() { - file=$1 - prefix=$(basename "${file%%.patch}") - modname="test-$prefix" - module="${modname}.ko" - testprog=$(dirname "$1")/"$prefix-LOADED.test" - - [[ $prefix =~ -FAIL ]] && return - - if [[ ! -e $module ]]; then - log "can't find $module, skipping" - return - fi - - if [[ -e $testprog ]]; then - log "load test: $prefix" - else - log "load test: $prefix (no test prog)" - fi - - - if [[ -e $testprog ]] && $testprog >> $LOG 2>&1; then - error "$prefix: $testprog succeeded before kpatch load" - return - fi - - if ! $KPATCH load "$module" >> $LOG 2>&1; then - error "$prefix: kpatch load failed" - return - fi - - if [[ -e $testprog ]] && ! $testprog >> $LOG 2>&1; then - error "$prefix: $testprog failed after kpatch load" - fi - - if ! $KPATCH unload "$module" >> $LOG 2>&1; then - error "$prefix: kpatch unload failed" - return - fi - - if [[ -e $testprog ]] && $testprog >> $LOG 2>&1; then - error "$prefix: $testprog succeeded after kpatch unload" - return - fi -} - -run_custom_test() { - testprog=$1 - prefix=$(basename "${testprog%%.test}") - - [[ $testprog = *-LOADED.test ]] && return - - log "custom test: $prefix" - - if ! $testprog >> $LOG 2>&1; then - error "$prefix: test failed" - fi -} - -build_combined_module() { - - if [[ $SKIPBUILD -eq 1 ]] && [[ -e test-COMBINED.ko ]]; then - log "skipping build: combined" - return - fi - - declare -a COMBINED_LIST - for file in "${PATCH_LIST[@]}"; do - [[ $file =~ -FAIL ]] && log "combine: skipping $file" && continue - COMBINED_LIST+=("$file") - done - if [[ ${#COMBINED_LIST[@]} -le 1 ]]; then - log "skipping build: combined (only ${#PATCH_LIST[@]} patch(es))" - return - fi - - log "build: combined module" - - # shellcheck disable=SC2086 - if ! $KPATCHBUILD $KPATCHBUILD_OPTS -n test-COMBINED "${COMBINED_LIST[@]}" >> $LOG 2>&1; then - error "combined build failed" - cp "$HOME/.kpatch/build.log" combined.log - fi -} - -run_combined_test() { - if [[ ! -e test-COMBINED.ko ]]; then - log "can't find test-COMBINED.ko, skipping" - return - fi - - log "load test: combined module" - - unload_all - - for testprog in "${TEST_LIST[@]}"; do - [[ $testprog != *-LOADED.test ]] && continue - if $testprog >> $LOG 2>&1; then - error "combined: $testprog succeeded before kpatch load" - return - fi - done - - if ! $KPATCH load test-COMBINED.ko >> $LOG 2>&1; then - error "combined: kpatch load failed" - return - fi - - for testprog in "${TEST_LIST[@]}"; do - [[ $testprog != *-LOADED.test ]] && continue - [ -e "${testprog/-LOADED.test/.patch.disabled}" ] && continue - if ! $testprog >> $LOG 2>&1; then - error "combined: $testprog failed after kpatch load" - fi - done - - if ! $KPATCH unload test-COMBINED.ko >> $LOG 2>&1; then - error "combined: kpatch unload failed" - return - fi - - for testprog in "${TEST_LIST[@]}"; do - [[ $testprog != *-LOADED.test ]] && continue - if $testprog >> $LOG 2>&1; then - error "combined: $testprog succeeded after kpatch unload" - return - fi - done - -} - -# save existing dmesg so we can detect new content -save_dmesg() { - SAVED_DMESG="$(dmesg | tail -n1)" -} - -# new dmesg entries since our saved entry -new_dmesg() { - if ! dmesg | awk -v last="$SAVED_DMESG" 'p; $0 == last{p=1} END {exit !p}'; then - error "dmesg overflow, try increasing kernel log buffer size" - fi -} - -kernel_version_gte() { - [ "${ARCHVERSION//-*/}" = "$(echo -e "${ARCHVERSION//-*}\\n$1" | sort -rV | head -n1)" ] -} - -support_klp_replace() -{ - if kernel_is_rhel; then - rhel_kernel_version_gte 4.18.0-193.el8 - else - kernel_version_gte 5.1.0 - fi -} - -kernel_is_rhel() { - [[ "$ARCHVERSION" =~ \.el[789] ]] -} - -rhel_kernel_version_gte() { - [ "${ARCHVERSION}" = "$(echo -e "${ARCHVERSION}\\n$1" | sort -rV | head -n1)" ] -} - -# shellcheck disable=SC1091 -source /etc/os-release -if [[ "${ID}" == "rhel" && "${VERSION_ID%%.*}" == "7" && "${VERSION_ID##*.}" -le "6" ]]; then - DYNDEBUG_ENABLED=0 - echo "Dynamic debug is not supported on '${PRETTY_NAME}', disabling." -fi - -if ! support_klp_replace ; then - KPATCHBUILD_OPTS="$KPATCHBUILD_OPTS -R" - echo "KLP replace is not supported on '${PRETTY_NAME}', disabling." -fi - -for file in "${PATCH_LIST[@]}"; do - if [[ $QUICK != 1 || "$file" =~ -FAIL ]]; then - build_module "$file" - fi -done - -build_combined_module - -unload_all - -save_dmesg - -if [ "${DYNDEBUG_ENABLED}" == "1" ]; then - prev_dyndebug=$(sudo sh -c "grep klp_try_switch_task ${DYNDEBUG_CONTROL}" | awk '{print $3;}') - sudo sh -c "echo 'func klp_try_switch_task +p' > ${DYNDEBUG_CONTROL} 2>/dev/null" -fi - -if [[ $QUICK != 1 ]]; then - for file in "${PATCH_LIST[@]}"; do - run_load_test "$file" - done -fi - -run_combined_test - -if [[ $QUICK != 1 ]]; then - for testprog in "${TEST_LIST[@]}"; do - if [[ ! $testprog =~ -FAIL ]]; then - unload_all - run_custom_test "$testprog" - fi - done -fi - - -unload_all - -if [ "${DYNDEBUG_ENABLED}" == "1" ]; then - sudo sh -c "echo \"func klp_try_switch_task ${prev_dyndebug}\" > ${DYNDEBUG_CONTROL} 2>/dev/null" -fi - -if new_dmesg | grep -q "Call Trace"; then - new_dmesg > dmesg.log - error "kernel error detected in printk buffer" -fi - -if [[ $ERROR -gt 0 ]]; then - log "$ERROR errors encountered" - echo "see test.log for more information" -else - log "SUCCESS" -fi - -exit $ERROR diff --git a/test/integration/lib.sh b/test/integration/lib.sh deleted file mode 100644 index 4ab2c92..0000000 --- a/test/integration/lib.sh +++ /dev/null @@ -1,316 +0,0 @@ -#!/bin/bash - -kpatch_set_ccache_max_size() -{ - local ccache_max_size=${1:-10G} - - ccache --max-size="${ccache_max_size}" -} - -kpatch_ubuntu_dependencies() -{ - sudo sed -i 's/# deb-src/deb-src/' /etc/apt/sources.list - sudo apt-get update - - sudo apt-get install -y make gcc libelf-dev elfutils - sudo apt-get install -y dpkg-dev devscripts - sudo apt-get build-dep -y linux - - sudo apt-get install -y ccache - - # Add ddebs repository - if ! grep -q 'ddebs.ubuntu.com' /etc/apt/sources.list.d/ddebs.list; then - local codename - codename=$(lsb_release -sc) - sudo tee /etc/apt/sources.list.d/ddebs.list <<-EOF - deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse - deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse - deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse - deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse - EOF - - # add APT key - wget -Nq http://ddebs.ubuntu.com/dbgsym-release-key.asc -O- | sudo apt-key add - - sudo apt-get update - fi - sudo apt-get install -y "linux-image-$(uname -r)-dbgsym" -} - -kpatch_rhel_dependencies() -{ - local kernel_version - local arch - local rhel_major - local yum_utils_version - kernel_version=$(uname -r) - arch=$(uname -m) - rhel_major=${VERSION_ID%%.*} - - # kpatch-build dependencies - sudo yum install -y \ - elfutils \ - elfutils-devel \ - gcc \ - gcc-c++ \ - git \ - "kernel-devel-${kernel_version%.*}" \ - rpm-build \ - wget \ - yum-utils - sudo debuginfo-install -y "kernel-${kernel_version%.*}" - [[ "$arch" == "ppc64le" ]] && sudo yum install -y gcc-plugin-devel - - # kernel dependencies - yum_utils_version=$(rpm -q --queryformat="%{version}" yum-utils) - if [[ "${yum_utils_version}" = "$(echo -e "${yum_utils_version}\\n4.0.12" | sort -rV | head -n1)" ]]; then - sudo yum-builddep -y --skip-unavailable "kernel-${kernel_version%.*}" - else - sudo yum-builddep -y "kernel-${kernel_version%.*}" - fi - [[ "$arch" == "x86_64" ]] && sudo yum install -y pesign - - # ccache - if ! command -v ccache &> /dev/null; then - if ! sudo yum install -y ccache; then - sudo yum install -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-${rhel_major}.noarch.rpm" && \ - sudo yum install -y ccache && \ - sudo yum remove -y epel-release - fi - fi -} - -kpatch_centos_dependencies() -{ - kpatch_rhel_dependencies -} - -kpatch_fedora_dependencies() -{ - kpatch_rhel_dependencies -} - -kpatch_openEuler_dependencies() -{ - local kernel_version - local arch - kernel_version=$(uname -r) - arch=$(uname -m) - - sudo yum install -y make gcc patch bison flex openssl-devel dwarves \ - rpm-build dnf-plugins-core python3-devel openssl-devel ncurses-devel elfutils-libelf-devel - sudo yum install -y "kernel-source-${kernel_version%.*}" \ - "kernel-debuginfo-${kernel_version%.*}" "kernel-devel-${kernel_version%.*}" -} - -kpatch_dependencies() -{ - # shellcheck disable=SC1091 - source /etc/os-release - - eval "kpatch_${ID}_dependencies" || { echo "Unsupported distro: ${ID}"; exit 1; } -} - -kpatch_separate_partition_cache() -{ - local partition=${1} - local mountpoint=${2} - local reformat=${3} - local owner=${USER} - - if [[ "${reformat}" == "y" ]]; then - sudo mkfs.xfs -f "${partition}" - fi - - sudo mkdir -p "${mountpoint}" - sudo mount "${partition}" "${mountpoint}" - sudo chown "${owner}":"${owner}" "${mountpoint}" - - rm -rf "${mountpoint}/.ccache" - rm -rf "${mountpoint}/.kpatch" - mkdir "${mountpoint}/.ccache" - mkdir "${mountpoint}/.kpatch" - - rm -rf "${HOME}/.ccache" - rm -rf "${HOME}/.kpatch" - - ln -sv "${mountpoint}/.ccache" "${HOME}/.ccache" - ln -sv "${mountpoint}/.kpatch" "${HOME}/.kpatch" -} - -kpatch_separate_disk_cache() -{ - local device=${1} - local mountpoint=${2} - local partition="${device}1" - - echo -e "o\\nn\\np\\n1\\n\\n\\nw\\n" | sudo fdisk "${device}" - kpatch_separate_partition_cache "${partition}" "${mountpoint}" y -} - -kpatch_install_vagrant_centos() -{ - local image_path=${1} - - sudo yum group install -y "Development Tools" - sudo yum -y install qemu-kvm libvirt virt-install bridge-utils libvirt-devel libxslt-devel libxml2-devel libvirt-devel libguestfs-tools-c libvirt-client - - echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ipforward.conf - sudo sysctl -p /etc/sysctl.d/99-ipforward.conf - - sudo systemctl enable libvirtd - sudo systemctl start libvirtd || exit 1 - - if [[ -n "${image_path}" ]]; then - mkdir -p "${image_path}/libvirt/images" - virsh pool-define-as --target "${image_path}/libvirt/images" default dir || exit 1 - virsh pool-start default || exit 1 - fi - - sudo yum install -y https://releases.hashicorp.com/vagrant/2.1.2/vagrant_2.1.2_x86_64.rpm || exit 1 - - vagrant plugin install vagrant-libvirt -} - -kpatch_install_vagrant_rhel() -{ - local image_path=${1} - - kpatch_install_vagrant_centos "${image_path}" - - sudo systemctl enable nfs - sudo systemctl start nfs || exit 1 - -} - -kpatch_install_vagrant_fedora() -{ - local image_path=${1} - - echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ipforward.conf - sudo sysctl -p /etc/sysctl.d/99-ipforward.conf - - sudo dnf install -y libvirt virt-install libvirt-client nfs-utils vagrant vagrant-libvirt - - echo "[nfsd]" | sudo tee -a /etc/nfs.conf - echo "udp=y" | sudo tee -a /etc/nfs.conf - echo "vers3=y" | sudo tee -a /etc/nfs.conf - sudo systemctl restart nfs - - sudo systemctl enable libvirtd - sudo systemctl start libvirtd || exit 1 - - if [[ -n "${image_path}" ]]; then - mkdir -p "${image_path}/libvirt/images" - virsh pool-define-as --target "${image_path}/libvirt/images" default dir || exit 1 - virsh pool-start default || exit 1 - fi -} - -kpatch_install_vagrant() -{ - local image_path=${1} - - # shellcheck disable=SC1091 - source /etc/os-release - - eval "kpatch_install_vagrant_${ID} ${image_path}" || { echo "Unsupported distro: ${ID}"; exit 1; } -} - -kpatch_check_install_vagrant() -{ - local image_path=${1} - # shellcheck disable=SC2230 - [ "$(which vagrant)" == "" ] && kpatch_install_vagrant "${image_path}" - return 0 -} - -kpatch_write_vagrantfile_template() -{ - local target_distro=${1} - - local box_prefix="kpatch" - - cat >Vagrantfile < '40G' - libvirt.cpus = $(getconf _NPROCESSORS_ONLN) - libvirt.memory = $(awk '/MemTotal/ {printf("%d\n", ($2*0.8)/1024)}' /proc/meminfo) - libvirt.graphics_type = "none" - libvirt.disk_bus = 'virtio' - libvirt.disk_device = 'vda' - end - config.vm.box = "${box_prefix}/${target_distro}" - config.vm.synced_folder ".", "/vagrant", type: "nfs" -EOF -} - -kpatch_write_vagrantfile_centos_provision() -{ - cat >>Vagrantfile <>Vagrantfile -} - -kpatch_integration_tests_vagrant_distro() -{ - local target_distro=${1} - local test_script=${2} - local slowtest=${3} - - local testdir - local workdir - local logdir - - testdir="$(pwd)" - workdir="${target_distro}.vagrant" - rm -rf "${workdir}" - mkdir -p "${workdir}" - cd "${workdir}" || exit 1 - - kpatch_write_vagrantfile "${target_distro}" - - vagrant up || { vagrant destroy -f; exit 1; } - - local test_cmd="KPATCH_GIT=${KPATCH_GIT} KPATCH_REV=${KPATCH_REV} bash /vagrant/runtest.sh" - if [ "${slowtest}" == "1" ]; then - test_cmd="${test_cmd} --slow" - fi - - cp "${test_script}" ./runtest.sh - vagrant ssh -c "${test_cmd}" - local rc=$? - - if [ $rc -eq 0 ]; then - echo "${target_distro} PASS" - else - echo "${target_distro} FAIL" - fi - - logdir="${testdir}/${target_distro}_log" - rm -rf "${logdir}" - mkdir -p "${logdir}" - cp logs/* "${logdir}" - - vagrant destroy -f - - cd "${testdir}" || exit 1 - if [ $rc -eq 0 ]; then - rm -rf "${workdir}" - fi - - return "${rc}" -} diff --git a/test/integration/linux-5.10.11/data-new-LOADED.test b/test/integration/linux-5.10.11/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/linux-5.10.11/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/linux-5.10.11/data-new.patch b/test/integration/linux-5.10.11/data-new.patch deleted file mode 100644 index 927d088..0000000 --- a/test/integration/linux-5.10.11/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-01-28 04:47:10.916473090 -0500 -+++ src/fs/proc/meminfo.c 2021-01-28 04:47:11.459467821 -0500 -@@ -29,6 +29,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -139,6 +141,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "FilePmdMapped: ", - global_node_page_state(NR_FILE_PMDMAPPED) * HPAGE_PMD_NR); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - #ifdef CONFIG_CMA - show_val_kb(m, "CmaTotal: ", totalcma_pages); diff --git a/test/integration/linux-5.10.11/gcc-static-local-var-6.patch b/test/integration/linux-5.10.11/gcc-static-local-var-6.patch deleted file mode 100644 index 8254b6c..0000000 --- a/test/integration/linux-5.10.11/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr linux-5.10.11.bak/net/ipv6/netfilter.c linux-5.10.11/net/ipv6/netfilter.c ---- linux-5.10.11.bak/net/ipv6/netfilter.c 2021-01-28 08:18:59.575109041 -0500 -+++ linux-5.10.11/net/ipv6/netfilter.c 2021-01-28 08:20:52.399053360 -0500 -@@ -89,6 +89,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -102,6 +104,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/linux-5.10.11/macro-callbacks.patch b/test/integration/linux-5.10.11/macro-callbacks.patch deleted file mode 100644 index 735ed9f..0000000 --- a/test/integration/linux-5.10.11/macro-callbacks.patch +++ /dev/null @@ -1,163 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2021-01-28 04:45:56.883192829 -0500 -+++ src/drivers/input/joydev.c 2021-01-28 04:51:13.998114373 -0500 -@@ -1084,3 +1084,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2021-01-28 04:45:56.892192742 -0500 -+++ src/drivers/input/misc/pcspkr.c 2021-01-28 04:51:14.086113519 -0500 -@@ -133,3 +133,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2021-01-28 04:47:10.885473391 -0500 -+++ src/fs/aio.c 2021-01-28 04:51:14.115113237 -0500 -@@ -51,6 +51,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/linux-5.10.11/module-call-external.patch b/test/integration/linux-5.10.11/module-call-external.patch deleted file mode 100644 index ee84137..0000000 --- a/test/integration/linux-5.10.11/module-call-external.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c -index 21e404e7cb68..3a282338d6d9 100644 ---- a/fs/nfsd/export.c -+++ b/fs/nfsd/export.c -@@ -1234,6 +1234,9 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, - } - } - -+extern char *kpatch_string(void); -+ -+__attribute__((optimize("-fno-optimize-sibling-calls"))) - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1243,6 +1246,7 @@ static int e_show(struct seq_file *m, void *p) - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index daca50d6bb12..a657a0e073f8 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -2898,4 +2898,9 @@ static int __init netlink_proto_init(void) - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/linux-5.10.11/multiple.test b/test/integration/linux-5.10.11/multiple.test deleted file mode 100755 index a7ea608..0000000 --- a/test/integration/linux-5.10.11/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-cmdline-rebuild-SLOW-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/linux-5.10.11/new-function.patch b/test/integration/linux-5.10.11/new-function.patch deleted file mode 100644 index 1b0e8a0..0000000 --- a/test/integration/linux-5.10.11/new-function.patch +++ /dev/null @@ -1,27 +0,0 @@ -diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c -index c2869489ba68..7a46fc7a88f1 100644 ---- a/drivers/tty/n_tty.c -+++ b/drivers/tty/n_tty.c -@@ -2295,7 +2295,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2382,6 +2382,13 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, - return (b - buf) ? b - buf : retval; - } - -+__attribute__((optimize("-fno-optimize-sibling-calls"))) -+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/linux-5.10.11/new-globals.patch b/test/integration/linux-5.10.11/new-globals.patch deleted file mode 100644 index 18a234e..0000000 --- a/test/integration/linux-5.10.11/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2021-01-28 04:47:10.915473099 -0500 -+++ src/fs/proc/cmdline.c 2021-01-28 05:04:23.106898578 -0500 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-01-28 04:47:10.916473090 -0500 -+++ src/fs/proc/meminfo.c 2021-01-28 05:04:23.141898268 -0500 -@@ -19,6 +19,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -55,6 +57,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/linux-5.10.11/syscall-LOADED.test b/test/integration/linux-5.10.11/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/linux-5.10.11/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/linux-5.10.11/syscall.patch b/test/integration/linux-5.10.11/syscall.patch deleted file mode 100644 index f86d695..0000000 --- a/test/integration/linux-5.10.11/syscall.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/kernel/sys.c b/kernel/sys.c -index 2e2e3f378d97..05271fe26c89 100644 ---- a/kernel/sys.c -+++ b/kernel/sys.c -@@ -1250,13 +1250,15 @@ static int override_release(char __user *release, size_t len) - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { - struct new_utsname tmp; - - down_read(&uts_sem); - memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); - if (copy_to_user(name, &tmp, sizeof(tmp))) - return -EFAULT; - diff --git a/test/integration/linux-5.10.11/warn-detect-FAIL.patch b/test/integration/linux-5.10.11/warn-detect-FAIL.patch deleted file mode 100644 index 940590f..0000000 --- a/test/integration/linux-5.10.11/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr linux-5.10.11.bak/net/core/dev.c linux-5.10.11/net/core/dev.c ---- linux-5.10.11.bak/net/core/dev.c 2021-01-28 08:18:59.936105663 -0500 -+++ linux-5.10.11/net/core/dev.c 2021-01-28 08:34:03.120655935 -0500 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-or-later -+ - /* - * NET3 Protocol independent device support routines. - * diff --git a/test/integration/linux-5.18.0/data-new-LOADED.test b/test/integration/linux-5.18.0/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/linux-5.18.0/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/linux-5.18.0/data-new.patch b/test/integration/linux-5.18.0/data-new.patch deleted file mode 100644 index 27df4ac..0000000 --- a/test/integration/linux-5.18.0/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-06-15 10:04:10.540915757 -0400 -+++ src/fs/proc/meminfo.c 2022-06-15 10:04:12.104923244 -0400 -@@ -29,6 +29,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -145,6 +147,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/linux-5.18.0/gcc-static-local-var-6.patch b/test/integration/linux-5.18.0/gcc-static-local-var-6.patch deleted file mode 100644 index 896dfd7..0000000 --- a/test/integration/linux-5.18.0/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2022-06-15 10:04:10.984917882 -0400 -+++ src/net/ipv6/netfilter.c 2022-06-15 10:04:25.898989277 -0400 -@@ -97,6 +97,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -110,6 +112,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/linux-5.18.0/macro-callbacks.patch b/test/integration/linux-5.18.0/macro-callbacks.patch deleted file mode 100644 index 0a72181..0000000 --- a/test/integration/linux-5.18.0/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2022-06-15 10:04:09.640911448 -0400 -+++ src/drivers/input/joydev.c 2022-06-15 10:04:37.199043370 -0400 -@@ -1096,3 +1096,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2022-06-15 10:04:09.649911492 -0400 -+++ src/drivers/input/misc/pcspkr.c 2022-06-15 10:04:37.200043375 -0400 -@@ -134,3 +134,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-06-15 10:04:10.537915743 -0400 -+++ src/fs/aio.c 2022-06-15 10:04:37.201043380 -0400 -@@ -50,6 +50,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/linux-5.18.0/module-LOADED.test b/test/integration/linux-5.18.0/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/linux-5.18.0/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/linux-5.18.0/module.patch b/test/integration/linux-5.18.0/module.patch deleted file mode 100644 index af01b1c..0000000 --- a/test/integration/linux-5.18.0/module.patch +++ /dev/null @@ -1,79 +0,0 @@ -kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2022-06-15 10:04:10.582915958 -0400 -+++ src/fs/nfsd/export.c 2022-06-15 10:04:48.309096555 -0400 -@@ -1294,6 +1294,10 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ -+__attribute__((optimize("-fno-optimize-sibling-calls"))) - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1301,12 +1305,36 @@ static int e_show(struct seq_file *m, vo - struct cache_detail *cd = m->private; - bool export_stats = is_export_stats_file(m); - -+#ifdef CONFIG_X86_64 -+ alternative("ud2", "call single_task_running", X86_FEATURE_ALWAYS); -+ alternative("call single_task_running", "ud2", X86_FEATURE_IA64); -+ -+ slow_down_io(); /* paravirt call */ -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&memcg_kmem_enabled_key)) -+ printk("kpatch: memcg_kmem_enabled_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif -+ - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - if (export_stats) - seq_puts(m, "# Path Client Start-time\n#\tStats\n"); - else - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2022-06-15 10:04:11.011918011 -0400 -+++ src/net/netlink/af_netlink.c 2022-06-15 10:04:48.312096569 -0400 -@@ -2908,4 +2908,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/linux-5.18.0/multiple.test b/test/integration/linux-5.18.0/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/linux-5.18.0/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/linux-5.18.0/new-function.patch b/test/integration/linux-5.18.0/new-function.patch deleted file mode 100644 index c29fd4e..0000000 --- a/test/integration/linux-5.18.0/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2022-06-15 10:04:10.454915345 -0400 -+++ src/drivers/tty/n_tty.c 2022-06-15 10:04:59.142148413 -0400 -@@ -2213,7 +2213,7 @@ more_to_be_read: - * (note that the process_output*() functions take this lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2300,6 +2300,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/linux-5.18.0/new-globals.patch b/test/integration/linux-5.18.0/new-globals.patch deleted file mode 100644 index 04d3c55..0000000 --- a/test/integration/linux-5.18.0/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-06-15 10:04:10.539915752 -0400 -+++ src/fs/proc/cmdline.c 2022-06-15 10:05:10.193201315 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-06-15 10:04:10.540915757 -0400 -+++ src/fs/proc/meminfo.c 2022-06-15 10:05:10.193201315 -0400 -@@ -19,6 +19,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -55,6 +57,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/linux-5.18.0/shadow-newpid-LOADED.test b/test/integration/linux-5.18.0/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/linux-5.18.0/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/linux-5.18.0/shadow-newpid.patch b/test/integration/linux-5.18.0/shadow-newpid.patch deleted file mode 100644 index 8b543d7..0000000 --- a/test/integration/linux-5.18.0/shadow-newpid.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2022-06-15 10:04:10.539915752 -0400 -+++ src/fs/proc/array.c 2022-06-15 10:05:21.025253168 -0400 -@@ -394,12 +394,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2022-06-15 10:04:10.881917389 -0400 -+++ src/kernel/exit.c 2022-06-15 10:05:21.025253168 -0400 -@@ -733,6 +733,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -795,6 +796,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-06-15 10:04:10.879917380 -0400 -+++ src/kernel/fork.c 2022-06-15 10:05:21.026253173 -0400 -@@ -2595,6 +2595,7 @@ struct task_struct *create_io_thread(int - * - * args->exit_signal is expected to be checked for sanity by the caller. - */ -+#include - pid_t kernel_clone(struct kernel_clone_args *args) - { - u64 clone_flags = args->flags; -@@ -2603,6 +2604,8 @@ pid_t kernel_clone(struct kernel_clone_a - struct task_struct *p; - int trace = 0; - pid_t nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * For legacy clone() calls, CLONE_PIDFD uses the parent_tid argument -@@ -2642,6 +2645,11 @@ pid_t kernel_clone(struct kernel_clone_a - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/linux-5.18.0/special-static.patch b/test/integration/linux-5.18.0/special-static.patch deleted file mode 100644 index b19093e..0000000 --- a/test/integration/linux-5.18.0/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-06-15 10:04:10.879917380 -0400 -+++ src/kernel/fork.c 2022-06-15 10:05:31.745304485 -0400 -@@ -1676,10 +1676,18 @@ static void posix_cpu_timers_init_group( - posix_cputimers_group_init(pct, cpu_limit); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/linux-5.18.0/symvers-disagreement-FAIL.patch b/test/integration/linux-5.18.0/symvers-disagreement-FAIL.patch deleted file mode 100644 index 9dac457..0000000 --- a/test/integration/linux-5.18.0/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c ---- src.orig/drivers/base/core.c 2022-06-15 10:04:08.806907456 -0400 -+++ src/drivers/base/core.c 2022-06-15 10:05:42.555356233 -0400 -@@ -34,6 +34,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c ---- src.orig/drivers/usb/core/usb.c 2022-06-15 10:04:10.469915417 -0400 -+++ src/drivers/usb/core/usb.c 2022-06-15 10:05:42.556356238 -0400 -@@ -697,6 +697,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; diff --git a/test/integration/linux-5.18.0/syscall-LOADED.test b/test/integration/linux-5.18.0/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/linux-5.18.0/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/linux-5.18.0/syscall.patch b/test/integration/linux-5.18.0/syscall.patch deleted file mode 100644 index 57a65ab..0000000 --- a/test/integration/linux-5.18.0/syscall.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2022-06-15 10:04:10.881917389 -0400 -+++ src/kernel/sys.c 2022-06-15 10:05:53.708409623 -0400 -@@ -1278,13 +1278,15 @@ static int override_release(char __user - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { - struct new_utsname tmp; - - down_read(&uts_sem); - memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); - if (copy_to_user(name, &tmp, sizeof(tmp))) - return -EFAULT; - diff --git a/test/integration/linux-5.18.0/warn-detect-FAIL.patch b/test/integration/linux-5.18.0/warn-detect-FAIL.patch deleted file mode 100644 index 3a27c2e..0000000 --- a/test/integration/linux-5.18.0/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2022-06-15 10:04:08.731907097 -0400 -+++ src/arch/x86/kvm/x86.c 2022-06-15 10:06:04.480461189 -0400 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-only -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rebase-patches b/test/integration/rebase-patches deleted file mode 100755 index 64faed6..0000000 --- a/test/integration/rebase-patches +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -# -# rebase a set of integration test patches -# -# Example: -# -# 1 - Extract kernel sources: -# -# % (rpm -ivh kernel-3.10.0-1127.el7.src.rpm; \ -# cd ~/rpmbuild/SPECS; \ -# rpmbuild --nodeps -bp kernel.spec) -# -# -# 2 - Rebase from previous release tests: -# -# % cd test/integration -# % SRCDIR="$HOME/rpmbuild/BUILD/kernel-3.10.0-1127.el7/linux-3.10.0-1127.el7.x86_64" \ -# ID=rhel VERSION_ID=7.8 ./rebase-patches rhel-7.7/*{.patch,.disabled} -# % cp rhel-7.7/*.test rhel-7.8/ - -OUTDIR=$(pwd)/${ID}-${VERSION_ID} -mkdir -p "$OUTDIR" - -echo "* Making backup copy of kernel sources" -rm -rf "${SRCDIR}.orig" -cp -r "$SRCDIR" "${SRCDIR}.orig" - -for P in "$@"; do - - echo - echo "* Patch: $(basename "$P")" - - echo "** dry run..." - if ! patch -d "$SRCDIR" --dry-run --quiet -p1 < "$P"; then - echo "*** Skipping! ***" && continue - fi - - echo "** patching..." - patch -d "$SRCDIR" -p1 --no-backup-if-mismatch < "$P" - - echo "** generating new $(basename "$P")..." - NEWP="$OUTDIR"/$(basename "$P") - awk '/^Index|^diff|^patch/{exit} {print $LF}' "$P" > "$NEWP" - diff -Nupr "$SRCDIR.orig" "${SRCDIR}" >> "$NEWP" - sed -i "s#$SRCDIR#src#g" "$NEWP" - - echo "** reversing patch to restore tree..." - patch -d "$SRCDIR" -p1 -R < "$NEWP" - -done - -echo "*** Removing backup copy of kernel sources" -rm -rf "${SRCDIR}.orig" - -echo -echo "*** Done" diff --git a/test/integration/rhel-7.4/bug-table-section.patch b/test/integration/rhel-7.4/bug-table-section.patch deleted file mode 100644 index 71f8c1b..0000000 --- a/test/integration/rhel-7.4/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/proc_sysctl.c 2017-09-22 15:27:21.769056469 -0400 -@@ -266,6 +266,8 @@ void sysctl_head_put(struct ctl_table_he - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-7.4/cmdline-string-LOADED.test b/test/integration/rhel-7.4/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-7.4/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-7.4/cmdline-string.patch b/test/integration/rhel-7.4/cmdline-string.patch deleted file mode 100644 index 749861f..0000000 --- a/test/integration/rhel-7.4/cmdline-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/cmdline.c 2017-09-22 15:27:22.955061380 -0400 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-7.4/data-new-LOADED.test b/test/integration/rhel-7.4/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/rhel-7.4/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-7.4/data-new.patch b/test/integration/rhel-7.4/data-new.patch deleted file mode 100644 index 879828c..0000000 --- a/test/integration/rhel-7.4/data-new.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:24.102066130 -0400 -@@ -20,6 +20,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -106,6 +108,7 @@ static int meminfo_proc_show(struct seq_ - #ifdef CONFIG_TRANSPARENT_HUGEPAGE - "AnonHugePages: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -167,6 +170,7 @@ static int meminfo_proc_show(struct seq_ - ,K(global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/rhel-7.4/data-read-mostly.patch.disabled b/test/integration/rhel-7.4/data-read-mostly.patch.disabled deleted file mode 100644 index 611662f..0000000 --- a/test/integration/rhel-7.4/data-read-mostly.patch.disabled +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2017-09-22 15:27:21.759056428 -0400 -+++ src/net/core/dev.c 2017-09-22 15:27:25.244070859 -0400 -@@ -4012,6 +4012,7 @@ ncls: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-7.4/fixup-section.patch b/test/integration/rhel-7.4/fixup-section.patch deleted file mode 100644 index 0e2022e..0000000 --- a/test/integration/rhel-7.4/fixup-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/readdir.c b/fs/readdir.c -index fee38e04fae4..bce1e5ce74e5 100644 ---- a/fs/readdir.c -+++ b/fs/readdir.c -@@ -166,6 +166,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-7.4/gcc-constprop.patch b/test/integration/rhel-7.4/gcc-constprop.patch deleted file mode 100644 index 63ba45d..0000000 --- a/test/integration/rhel-7.4/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/time/timekeeping.c 2017-09-22 15:27:27.522080292 -0400 -@@ -877,6 +877,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-7.4/gcc-isra.patch b/test/integration/rhel-7.4/gcc-isra.patch deleted file mode 100644 index a869797..0000000 --- a/test/integration/rhel-7.4/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/proc_sysctl.c 2017-09-22 15:27:28.670085046 -0400 -@@ -24,6 +24,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-7.4/gcc-mangled-3.patch b/test/integration/rhel-7.4/gcc-mangled-3.patch deleted file mode 100644 index 5828680..0000000 --- a/test/integration/rhel-7.4/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2017-09-22 15:27:21.618055844 -0400 -+++ src/mm/slub.c 2017-09-22 15:27:29.830089850 -0400 -@@ -5528,6 +5528,9 @@ void get_slabinfo(struct kmem_cache *s, - unsigned long nr_free = 0; - int node; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_online_node(node) { - struct kmem_cache_node *n = get_node(s, node); - diff --git a/test/integration/rhel-7.4/gcc-static-local-var-2.patch b/test/integration/rhel-7.4/gcc-static-local-var-2.patch deleted file mode 100644 index 4f653d7..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2017-09-22 15:27:21.618055844 -0400 -+++ src/mm/mmap.c 2017-09-22 15:27:31.024094794 -0400 -@@ -1687,6 +1688,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-7.4/gcc-static-local-var-3.patch b/test/integration/rhel-7.4/gcc-static-local-var-3.patch deleted file mode 100644 index d87677b..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2017-09-22 15:27:21.601055773 -0400 -+++ src/kernel/sys.c 2017-09-22 15:27:32.170099540 -0400 -@@ -554,8 +554,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-7.4/gcc-static-local-var-4.patch b/test/integration/rhel-7.4/gcc-static-local-var-4.patch deleted file mode 100644 index e22ead7..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var-4.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2017-09-22 15:27:21.702056192 -0400 -+++ src/fs/aio.c 2017-09-22 15:27:33.299104215 -0400 -@@ -219,9 +219,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/rhel-7.4/gcc-static-local-var-4.test b/test/integration/rhel-7.4/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-7.4/gcc-static-local-var-5.patch b/test/integration/rhel-7.4/gcc-static-local-var-5.patch deleted file mode 100644 index 540affa..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/audit.c 2017-09-22 15:27:34.429108894 -0400 -@@ -205,6 +205,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -215,6 +221,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -234,6 +241,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -282,6 +294,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-7.4/gcc-static-local-var-6.patch b/test/integration/rhel-7.4/gcc-static-local-var-6.patch deleted file mode 100644 index bd5493c..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c -index a9d587a..23336ed 100644 ---- a/net/ipv6/netfilter.c -+++ b/net/ipv6/netfilter.c -@@ -106,6 +106,8 @@ static int nf_ip6_reroute(struct sk_buff *skb, - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -119,6 +121,9 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-7.4/gcc-static-local-var.patch b/test/integration/rhel-7.4/gcc-static-local-var.patch deleted file mode 100644 index 2dab9db..0000000 --- a/test/integration/rhel-7.4/gcc-static-local-var.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/arch/x86/kernel/ldt.c src/arch/x86/kernel/ldt.c ---- src.orig/arch/x86/kernel/ldt.c 2017-09-22 15:27:20.847052651 -0400 -+++ src/arch/x86/kernel/ldt.c 2017-09-22 15:27:35.573113632 -0400 -@@ -98,6 +98,12 @@ static inline int copy_ldt(mm_context_t - return 0; - } - -+void hi_there(void) -+{ -+ if (!jiffies) -+ printk("hi there\n"); -+} -+ - /* - * we do not have to muck with descriptors here, that is - * done in switch_mm() as needed. -@@ -107,6 +113,8 @@ int init_new_context(struct task_struct - struct mm_struct *old_mm; - int retval = 0; - -+ hi_there(); -+ - mutex_init(&mm->context.lock); - mm->context.size = 0; - old_mm = current->mm; diff --git a/test/integration/rhel-7.4/macro-callbacks.patch b/test/integration/rhel-7.4/macro-callbacks.patch deleted file mode 100644 index 0d6831b..0000000 --- a/test/integration/rhel-7.4/macro-callbacks.patch +++ /dev/null @@ -1,160 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - ---- src.old/fs/aio.c 2018-02-26 11:07:51.522610407 -0500 -+++ src/fs/aio.c 2018-03-05 11:17:21.560015449 -0500 -@@ -42,6 +42,50 @@ - #include - #include - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 ---- src.old/drivers/input/joydev.c 2018-02-26 11:07:49.470610407 -0500 -+++ src/drivers/input/joydev.c 2018-03-05 11:18:13.998015449 -0500 -@@ -954,3 +954,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); ---- src.old/drivers/input/misc/pcspkr.c 2018-02-26 11:07:49.477610407 -0500 -+++ src/drivers/input/misc/pcspkr.c 2018-03-05 11:18:23.411015449 -0500 -@@ -136,3 +136,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); diff --git a/test/integration/rhel-7.4/macro-printk.patch b/test/integration/rhel-7.4/macro-printk.patch deleted file mode 100644 index 9f591f4..0000000 --- a/test/integration/rhel-7.4/macro-printk.patch +++ /dev/null @@ -1,147 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2017-09-22 16:52:10.646110299 -0400 -+++ src/net/ipv4/fib_frontend.c 2017-09-22 16:55:14.395870305 -0400 -@@ -633,6 +633,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -651,6 +652,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(net, tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2017-09-22 16:52:10.645110295 -0400 -+++ src/net/ipv4/fib_semantics.c 2017-09-22 16:54:05.175584004 -0400 -@@ -925,6 +925,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -949,6 +950,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -969,6 +971,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) -@@ -980,6 +983,7 @@ struct fib_info *fib_create_info(struct - } else - fi->fib_metrics = (u32 *) dst_default_metrics; - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); - - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; -@@ -996,8 +1000,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1048,6 +1054,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1065,6 +1072,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1087,6 +1095,7 @@ struct fib_info *fib_create_info(struct - goto failure; - } endfor_nexthops(fi) - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || -@@ -1099,6 +1108,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1110,6 +1120,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1133,6 +1144,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1143,6 +1155,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2017-09-22 16:52:10.645110295 -0400 -+++ src/net/ipv4/fib_trie.c 2017-09-22 16:55:39.940975963 -0400 -@@ -1191,6 +1191,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) - { -@@ -1216,11 +1217,14 @@ int fib_table_insert(struct net *net, st - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority) : NULL; diff --git a/test/integration/rhel-7.4/meminfo-init-FAIL.patch b/test/integration/rhel-7.4/meminfo-init-FAIL.patch deleted file mode 100644 index 5df5225..0000000 --- a/test/integration/rhel-7.4/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:40.130132502 -0400 -@@ -191,6 +191,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.4/meminfo-init2-FAIL.patch b/test/integration/rhel-7.4/meminfo-init2-FAIL.patch deleted file mode 100644 index c030f61..0000000 --- a/test/integration/rhel-7.4/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:38.972127707 -0400 -@@ -30,6 +30,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -191,6 +192,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.4/meminfo-string-LOADED.test b/test/integration/rhel-7.4/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-7.4/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-7.4/meminfo-string.patch b/test/integration/rhel-7.4/meminfo-string.patch deleted file mode 100644 index afdc5d0..0000000 --- a/test/integration/rhel-7.4/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:41.274137239 -0400 -@@ -99,7 +99,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" - #endif diff --git a/test/integration/rhel-7.4/module-call-external.patch b/test/integration/rhel-7.4/module-call-external.patch deleted file mode 100644 index 754d725..0000000 --- a/test/integration/rhel-7.4/module-call-external.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2017-09-22 15:27:21.705056204 -0400 -+++ src/fs/nfsd/export.c 2017-09-22 15:27:42.411141948 -0400 -@@ -1184,6 +1184,8 @@ static void exp_flags(struct seq_file *m - } - } - -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1193,6 +1195,7 @@ static int e_show(struct seq_file *m, vo - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2017-09-22 15:27:21.754056407 -0400 -+++ src/net/netlink/af_netlink.c 2017-09-22 15:27:42.412141952 -0400 -@@ -3260,4 +3260,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-7.4/module-kvm-fixup.patch b/test/integration/rhel-7.4/module-kvm-fixup.patch deleted file mode 100644 index 174ad65..0000000 --- a/test/integration/rhel-7.4/module-kvm-fixup.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/vmx.c src/arch/x86/kvm/vmx.c ---- src.orig/arch/x86/kvm/vmx.c 2017-09-22 15:27:20.853052676 -0400 -+++ src/arch/x86/kvm/vmx.c 2017-09-22 15:27:43.583146801 -0400 -@@ -10597,6 +10597,8 @@ static int vmx_check_intercept(struct kv - struct x86_instruction_info *info, - enum x86_intercept_stage stage) - { -+ if (!jiffies) -+ printk("kpatch vmx_check_intercept\n"); - return X86EMUL_CONTINUE; - } - diff --git a/test/integration/rhel-7.4/module-shadow.patch b/test/integration/rhel-7.4/module-shadow.patch deleted file mode 100644 index c7da353..0000000 --- a/test/integration/rhel-7.4/module-shadow.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/vmx.c src/arch/x86/kvm/vmx.c ---- src.orig/arch/x86/kvm/vmx.c 2017-09-22 15:27:20.853052676 -0400 -+++ src/arch/x86/kvm/vmx.c 2017-09-22 15:27:44.742151601 -0400 -@@ -10581,10 +10581,20 @@ static void vmx_leave_nested(struct kvm_ - * It should only be called before L2 actually succeeded to run, and when - * vmcs01 is current (it doesn't leave_guest_mode() or switch vmcss). - */ -+#include "kpatch.h" - static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification) - { -+ int *kpatch; -+ -+ kpatch = kpatch_shadow_alloc(vcpu, "kpatch", sizeof(*kpatch), -+ GFP_KERNEL); -+ if (kpatch) { -+ kpatch_shadow_get(vcpu, "kpatch"); -+ kpatch_shadow_free(vcpu, "kpatch"); -+ } -+ - load_vmcs12_host_state(vcpu, vmcs12); - vmcs12->vm_exit_reason = reason | VMX_EXIT_REASONS_FAILED_VMENTRY; - vmcs12->exit_qualification = qualification; diff --git a/test/integration/rhel-7.4/multiple.test b/test/integration/rhel-7.4/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-7.4/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-7.4/new-function.patch b/test/integration/rhel-7.4/new-function.patch deleted file mode 100644 index cf47c83..0000000 --- a/test/integration/rhel-7.4/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2017-09-22 15:27:21.084053633 -0400 -+++ src/drivers/tty/n_tty.c 2017-09-22 15:27:45.888156346 -0400 -@@ -2016,7 +2016,7 @@ do_it_again: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2098,6 +2098,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-7.4/new-globals.patch b/test/integration/rhel-7.4/new-globals.patch deleted file mode 100644 index 3d9d349..0000000 --- a/test/integration/rhel-7.4/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/cmdline.c 2017-09-22 15:27:47.028161067 -0400 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - module_init(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:47.029161071 -0400 -@@ -16,6 +16,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -53,6 +55,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/rhel-7.4/parainstructions-section.patch b/test/integration/rhel-7.4/parainstructions-section.patch deleted file mode 100644 index 809dce4..0000000 --- a/test/integration/rhel-7.4/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/generic.c 2017-09-22 15:27:48.190165879 -0400 -@@ -194,6 +194,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/rhel-7.4/replace-section-references.patch b/test/integration/rhel-7.4/replace-section-references.patch deleted file mode 100644 index e41bba9..0000000 --- a/test/integration/rhel-7.4/replace-section-references.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:49.362170732 -0400 -@@ -248,6 +248,8 @@ static void shared_msr_update(unsigned s - - void kvm_define_shared_msr(unsigned slot, u32 msr) - { -+ if (!jiffies) -+ printk("kpatch kvm define shared msr\n"); - BUG_ON(slot >= KVM_NR_SHARED_MSRS); - shared_msrs_global.msrs[slot] = msr; - if (slot >= shared_msrs_global.nr) diff --git a/test/integration/rhel-7.4/shadow-newpid-LOADED.test b/test/integration/rhel-7.4/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-7.4/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-7.4/shadow-newpid.patch b/test/integration/rhel-7.4/shadow-newpid.patch deleted file mode 100644 index cde1810..0000000 --- a/test/integration/rhel-7.4/shadow-newpid.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2017-09-22 16:52:10.597110096 -0400 -+++ src/fs/proc/array.c 2017-09-22 16:59:40.799972178 -0400 -@@ -359,13 +359,20 @@ static inline void task_seccomp(struct s - #endif - } - -+#include "kpatch.h" - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" - "nonvoluntary_ctxt_switches:\t%lu\n", - p->nvcsw, - p->nivcsw); -+ -+ newpid = kpatch_shadow_get(p, "newpid"); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2017-09-22 16:52:10.506109720 -0400 -+++ src/kernel/exit.c 2017-09-22 16:59:40.799972178 -0400 -@@ -715,6 +715,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include "kpatch.h" - void do_exit(long code) - { - struct task_struct *tsk = current; -@@ -812,6 +813,8 @@ void do_exit(long code) - check_stack_usage(); - exit_thread(); - -+ kpatch_shadow_free(tsk, "newpid"); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2017-09-22 16:52:10.504109711 -0400 -+++ src/kernel/fork.c 2017-09-22 17:00:44.938237460 -0400 -@@ -1700,6 +1700,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include "kpatch.h" - long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -1737,6 +1738,13 @@ long do_fork(unsigned long clone_flags, - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; -+ int *newpid; -+ static int ctr = 0; -+ -+ newpid = kpatch_shadow_alloc(p, "newpid", sizeof(*newpid), -+ GFP_KERNEL); -+ if (newpid) -+ *newpid = ctr++; - - trace_sched_process_fork(current, p); - diff --git a/test/integration/rhel-7.4/smp-locks-section.patch b/test/integration/rhel-7.4/smp-locks-section.patch deleted file mode 100644 index 6f39d53..0000000 --- a/test/integration/rhel-7.4/smp-locks-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2017-09-22 15:27:21.077053604 -0400 -+++ src/drivers/tty/tty_buffer.c 2017-09-22 15:27:50.542175618 -0400 -@@ -217,6 +217,10 @@ int tty_buffer_request_room(struct tty_p - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ -+ -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b != NULL) - left = b->size - b->used; diff --git a/test/integration/rhel-7.4/special-static-2.patch b/test/integration/rhel-7.4/special-static-2.patch deleted file mode 100644 index 146d5b5..0000000 --- a/test/integration/rhel-7.4/special-static-2.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:51.744180596 -0400 -@@ -2093,12 +2093,20 @@ static void record_steal_time(struct kvm - &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); - } - -+void kpatch_kvm_x86_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch kvm x86 foo\n"); -+} -+ - int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) - { - bool pr = false; - u32 msr = msr_info->index; - u64 data = msr_info->data; - -+ kpatch_kvm_x86_foo(); -+ - switch (msr) { - case MSR_AMD64_NB_CFG: - case MSR_IA32_UCODE_REV: diff --git a/test/integration/rhel-7.4/special-static.patch b/test/integration/rhel-7.4/special-static.patch deleted file mode 100644 index 84647ec..0000000 --- a/test/integration/rhel-7.4/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2017-09-22 15:27:21.600055769 -0400 -+++ src/kernel/fork.c 2017-09-22 15:27:53.052186012 -0400 -@@ -1129,10 +1129,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-7.4/tracepoints-section.patch b/test/integration/rhel-7.4/tracepoints-section.patch deleted file mode 100644 index b770f9e..0000000 --- a/test/integration/rhel-7.4/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/timer.c src/kernel/timer.c ---- src.orig/kernel/timer.c 2017-09-22 15:27:21.600055769 -0400 -+++ src/kernel/timer.c 2017-09-22 15:27:54.288191131 -0400 -@@ -1390,6 +1390,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = __this_cpu_read(tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/rhel-7.4/warn-detect-FAIL.patch b/test/integration/rhel-7.4/warn-detect-FAIL.patch deleted file mode 100644 index 8efa782..0000000 --- a/test/integration/rhel-7.4/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:55.489196104 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-7.5/bug-table-section.patch b/test/integration/rhel-7.5/bug-table-section.patch deleted file mode 100644 index 71f8c1b..0000000 --- a/test/integration/rhel-7.5/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/proc_sysctl.c 2017-09-22 15:27:21.769056469 -0400 -@@ -266,6 +266,8 @@ void sysctl_head_put(struct ctl_table_he - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-7.5/cmdline-string-LOADED.test b/test/integration/rhel-7.5/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-7.5/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-7.5/cmdline-string.patch b/test/integration/rhel-7.5/cmdline-string.patch deleted file mode 100644 index 749861f..0000000 --- a/test/integration/rhel-7.5/cmdline-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/cmdline.c 2017-09-22 15:27:22.955061380 -0400 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-7.5/data-new-LOADED.test b/test/integration/rhel-7.5/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/rhel-7.5/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-7.5/data-new.patch b/test/integration/rhel-7.5/data-new.patch deleted file mode 100644 index 879828c..0000000 --- a/test/integration/rhel-7.5/data-new.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:24.102066130 -0400 -@@ -20,6 +20,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -106,6 +108,7 @@ static int meminfo_proc_show(struct seq_ - #ifdef CONFIG_TRANSPARENT_HUGEPAGE - "AnonHugePages: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -167,6 +170,7 @@ static int meminfo_proc_show(struct seq_ - ,K(global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/rhel-7.5/data-read-mostly.patch.disabled b/test/integration/rhel-7.5/data-read-mostly.patch.disabled deleted file mode 100644 index 611662f..0000000 --- a/test/integration/rhel-7.5/data-read-mostly.patch.disabled +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2017-09-22 15:27:21.759056428 -0400 -+++ src/net/core/dev.c 2017-09-22 15:27:25.244070859 -0400 -@@ -4012,6 +4012,7 @@ ncls: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-7.5/fixup-section.patch b/test/integration/rhel-7.5/fixup-section.patch deleted file mode 100644 index 18d13b5..0000000 --- a/test/integration/rhel-7.5/fixup-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/readdir.c b/fs/readdir.c -index febd02dfbe2d..064db7bd70d0 100644 ---- a/fs/readdir.c -+++ b/fs/readdir.c -@@ -176,6 +176,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-7.5/gcc-constprop.patch b/test/integration/rhel-7.5/gcc-constprop.patch deleted file mode 100644 index 63ba45d..0000000 --- a/test/integration/rhel-7.5/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/time/timekeeping.c 2017-09-22 15:27:27.522080292 -0400 -@@ -877,6 +877,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-7.5/gcc-isra.patch b/test/integration/rhel-7.5/gcc-isra.patch deleted file mode 100644 index a869797..0000000 --- a/test/integration/rhel-7.5/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/proc_sysctl.c 2017-09-22 15:27:28.670085046 -0400 -@@ -24,6 +24,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-7.5/gcc-mangled-3.patch b/test/integration/rhel-7.5/gcc-mangled-3.patch deleted file mode 100644 index 5828680..0000000 --- a/test/integration/rhel-7.5/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2017-09-22 15:27:21.618055844 -0400 -+++ src/mm/slub.c 2017-09-22 15:27:29.830089850 -0400 -@@ -5528,6 +5528,9 @@ void get_slabinfo(struct kmem_cache *s, - unsigned long nr_free = 0; - int node; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_online_node(node) { - struct kmem_cache_node *n = get_node(s, node); - diff --git a/test/integration/rhel-7.5/gcc-static-local-var-2.patch b/test/integration/rhel-7.5/gcc-static-local-var-2.patch deleted file mode 100644 index 4f653d7..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2017-09-22 15:27:21.618055844 -0400 -+++ src/mm/mmap.c 2017-09-22 15:27:31.024094794 -0400 -@@ -1687,6 +1688,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-7.5/gcc-static-local-var-3.patch b/test/integration/rhel-7.5/gcc-static-local-var-3.patch deleted file mode 100644 index d87677b..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2017-09-22 15:27:21.601055773 -0400 -+++ src/kernel/sys.c 2017-09-22 15:27:32.170099540 -0400 -@@ -554,8 +554,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-7.5/gcc-static-local-var-4.patch b/test/integration/rhel-7.5/gcc-static-local-var-4.patch deleted file mode 100644 index e22ead7..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var-4.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2017-09-22 15:27:21.702056192 -0400 -+++ src/fs/aio.c 2017-09-22 15:27:33.299104215 -0400 -@@ -219,9 +219,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/rhel-7.5/gcc-static-local-var-4.test b/test/integration/rhel-7.5/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-7.5/gcc-static-local-var-5.patch b/test/integration/rhel-7.5/gcc-static-local-var-5.patch deleted file mode 100644 index 540affa..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/audit.c 2017-09-22 15:27:34.429108894 -0400 -@@ -205,6 +205,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -215,6 +221,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -234,6 +241,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -282,6 +294,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-7.5/gcc-static-local-var-6.patch b/test/integration/rhel-7.5/gcc-static-local-var-6.patch deleted file mode 100644 index bd5493c..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c -index a9d587a..23336ed 100644 ---- a/net/ipv6/netfilter.c -+++ b/net/ipv6/netfilter.c -@@ -106,6 +106,8 @@ static int nf_ip6_reroute(struct sk_buff *skb, - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -119,6 +121,9 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-7.5/gcc-static-local-var.patch b/test/integration/rhel-7.5/gcc-static-local-var.patch deleted file mode 100644 index 2dab9db..0000000 --- a/test/integration/rhel-7.5/gcc-static-local-var.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/arch/x86/kernel/ldt.c src/arch/x86/kernel/ldt.c ---- src.orig/arch/x86/kernel/ldt.c 2017-09-22 15:27:20.847052651 -0400 -+++ src/arch/x86/kernel/ldt.c 2017-09-22 15:27:35.573113632 -0400 -@@ -98,6 +98,12 @@ static inline int copy_ldt(mm_context_t - return 0; - } - -+void hi_there(void) -+{ -+ if (!jiffies) -+ printk("hi there\n"); -+} -+ - /* - * we do not have to muck with descriptors here, that is - * done in switch_mm() as needed. -@@ -107,6 +113,8 @@ int init_new_context(struct task_struct - struct mm_struct *old_mm; - int retval = 0; - -+ hi_there(); -+ - mutex_init(&mm->context.lock); - mm->context.size = 0; - old_mm = current->mm; diff --git a/test/integration/rhel-7.5/macro-callbacks.patch b/test/integration/rhel-7.5/macro-callbacks.patch deleted file mode 100644 index 0d6831b..0000000 --- a/test/integration/rhel-7.5/macro-callbacks.patch +++ /dev/null @@ -1,160 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - ---- src.old/fs/aio.c 2018-02-26 11:07:51.522610407 -0500 -+++ src/fs/aio.c 2018-03-05 11:17:21.560015449 -0500 -@@ -42,6 +42,50 @@ - #include - #include - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 ---- src.old/drivers/input/joydev.c 2018-02-26 11:07:49.470610407 -0500 -+++ src/drivers/input/joydev.c 2018-03-05 11:18:13.998015449 -0500 -@@ -954,3 +954,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); ---- src.old/drivers/input/misc/pcspkr.c 2018-02-26 11:07:49.477610407 -0500 -+++ src/drivers/input/misc/pcspkr.c 2018-03-05 11:18:23.411015449 -0500 -@@ -136,3 +136,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); diff --git a/test/integration/rhel-7.5/macro-printk.patch b/test/integration/rhel-7.5/macro-printk.patch deleted file mode 100644 index 9f591f4..0000000 --- a/test/integration/rhel-7.5/macro-printk.patch +++ /dev/null @@ -1,147 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2017-09-22 16:52:10.646110299 -0400 -+++ src/net/ipv4/fib_frontend.c 2017-09-22 16:55:14.395870305 -0400 -@@ -633,6 +633,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -651,6 +652,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(net, tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2017-09-22 16:52:10.645110295 -0400 -+++ src/net/ipv4/fib_semantics.c 2017-09-22 16:54:05.175584004 -0400 -@@ -925,6 +925,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -949,6 +950,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -969,6 +971,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) -@@ -980,6 +983,7 @@ struct fib_info *fib_create_info(struct - } else - fi->fib_metrics = (u32 *) dst_default_metrics; - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); - - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; -@@ -996,8 +1000,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1048,6 +1054,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1065,6 +1072,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1087,6 +1095,7 @@ struct fib_info *fib_create_info(struct - goto failure; - } endfor_nexthops(fi) - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || -@@ -1099,6 +1108,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1110,6 +1120,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1133,6 +1144,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1143,6 +1155,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2017-09-22 16:52:10.645110295 -0400 -+++ src/net/ipv4/fib_trie.c 2017-09-22 16:55:39.940975963 -0400 -@@ -1191,6 +1191,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) - { -@@ -1216,11 +1217,14 @@ int fib_table_insert(struct net *net, st - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority) : NULL; diff --git a/test/integration/rhel-7.5/meminfo-init-FAIL.patch b/test/integration/rhel-7.5/meminfo-init-FAIL.patch deleted file mode 100644 index 5df5225..0000000 --- a/test/integration/rhel-7.5/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:40.130132502 -0400 -@@ -191,6 +191,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.5/meminfo-init2-FAIL.patch b/test/integration/rhel-7.5/meminfo-init2-FAIL.patch deleted file mode 100644 index c030f61..0000000 --- a/test/integration/rhel-7.5/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:38.972127707 -0400 -@@ -30,6 +30,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -191,6 +192,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.5/meminfo-string-LOADED.test b/test/integration/rhel-7.5/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-7.5/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-7.5/meminfo-string.patch b/test/integration/rhel-7.5/meminfo-string.patch deleted file mode 100644 index afdc5d0..0000000 --- a/test/integration/rhel-7.5/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:41.274137239 -0400 -@@ -99,7 +99,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" - #endif diff --git a/test/integration/rhel-7.5/module-call-external.patch b/test/integration/rhel-7.5/module-call-external.patch deleted file mode 100644 index 754d725..0000000 --- a/test/integration/rhel-7.5/module-call-external.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2017-09-22 15:27:21.705056204 -0400 -+++ src/fs/nfsd/export.c 2017-09-22 15:27:42.411141948 -0400 -@@ -1184,6 +1184,8 @@ static void exp_flags(struct seq_file *m - } - } - -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1193,6 +1195,7 @@ static int e_show(struct seq_file *m, vo - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2017-09-22 15:27:21.754056407 -0400 -+++ src/net/netlink/af_netlink.c 2017-09-22 15:27:42.412141952 -0400 -@@ -3260,4 +3260,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-7.5/module-kvm-fixup.patch b/test/integration/rhel-7.5/module-kvm-fixup.patch deleted file mode 100644 index 174ad65..0000000 --- a/test/integration/rhel-7.5/module-kvm-fixup.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/vmx.c src/arch/x86/kvm/vmx.c ---- src.orig/arch/x86/kvm/vmx.c 2017-09-22 15:27:20.853052676 -0400 -+++ src/arch/x86/kvm/vmx.c 2017-09-22 15:27:43.583146801 -0400 -@@ -10597,6 +10597,8 @@ static int vmx_check_intercept(struct kv - struct x86_instruction_info *info, - enum x86_intercept_stage stage) - { -+ if (!jiffies) -+ printk("kpatch vmx_check_intercept\n"); - return X86EMUL_CONTINUE; - } - diff --git a/test/integration/rhel-7.5/module-shadow.patch.disabled b/test/integration/rhel-7.5/module-shadow.patch.disabled deleted file mode 100644 index e4821c9..0000000 --- a/test/integration/rhel-7.5/module-shadow.patch.disabled +++ /dev/null @@ -1,25 +0,0 @@ -Index: src/arch/x86/kvm/vmx.c -=================================================================== ---- src.orig/arch/x86/kvm/vmx.c -+++ src/arch/x86/kvm/vmx.c -@@ -11168,10 +11168,20 @@ static void vmx_leave_nested(struct kvm_ - * It should only be called before L2 actually succeeded to run, and when - * vmcs01 is current (it doesn't leave_guest_mode() or switch vmcss). - */ -+#include - static void nested_vmx_entry_failure(struct kvm_vcpu *vcpu, - struct vmcs12 *vmcs12, - u32 reason, unsigned long qualification) - { -+ int *kpatch; -+ -+ kpatch = klp_shadow_alloc(vcpu, 0, NULL, sizeof(*kpatch), -+ GFP_KERNEL); -+ if (kpatch) { -+ klp_shadow_get(vcpu, 0); -+ klp_shadow_free(vcpu, 0); -+ } -+ - load_vmcs12_host_state(vcpu, vmcs12); - vmcs12->vm_exit_reason = reason | VMX_EXIT_REASONS_FAILED_VMENTRY; - vmcs12->exit_qualification = qualification; diff --git a/test/integration/rhel-7.5/multiple.test b/test/integration/rhel-7.5/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-7.5/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-7.5/new-function.patch b/test/integration/rhel-7.5/new-function.patch deleted file mode 100644 index bef6803..0000000 --- a/test/integration/rhel-7.5/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2017-09-22 15:27:21.084053633 -0400 -+++ src/drivers/tty/n_tty.c 2017-09-22 15:27:45.888156346 -0400 -@@ -2016,7 +2016,7 @@ do_it_again: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2098,6 +2098,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-7.5/new-globals.patch b/test/integration/rhel-7.5/new-globals.patch deleted file mode 100644 index 3d9d349..0000000 --- a/test/integration/rhel-7.5/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/cmdline.c 2017-09-22 15:27:47.028161067 -0400 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - module_init(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:47.029161071 -0400 -@@ -16,6 +16,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -53,6 +55,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/rhel-7.5/parainstructions-section.patch b/test/integration/rhel-7.5/parainstructions-section.patch deleted file mode 100644 index 809dce4..0000000 --- a/test/integration/rhel-7.5/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/generic.c 2017-09-22 15:27:48.190165879 -0400 -@@ -194,6 +194,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/rhel-7.5/replace-section-references.patch b/test/integration/rhel-7.5/replace-section-references.patch deleted file mode 100644 index e41bba9..0000000 --- a/test/integration/rhel-7.5/replace-section-references.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:49.362170732 -0400 -@@ -248,6 +248,8 @@ static void shared_msr_update(unsigned s - - void kvm_define_shared_msr(unsigned slot, u32 msr) - { -+ if (!jiffies) -+ printk("kpatch kvm define shared msr\n"); - BUG_ON(slot >= KVM_NR_SHARED_MSRS); - shared_msrs_global.msrs[slot] = msr; - if (slot >= shared_msrs_global.nr) diff --git a/test/integration/rhel-7.5/shadow-newpid-LOADED.test b/test/integration/rhel-7.5/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-7.5/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-7.5/shadow-newpid.patch b/test/integration/rhel-7.5/shadow-newpid.patch deleted file mode 100644 index ff2019c..0000000 --- a/test/integration/rhel-7.5/shadow-newpid.patch +++ /dev/null @@ -1,72 +0,0 @@ -Index: src/fs/proc/array.c -=================================================================== ---- src.orig/fs/proc/array.c -+++ src/fs/proc/array.c -@@ -394,13 +394,20 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" - "nonvoluntary_ctxt_switches:\t%lu\n", - p->nvcsw, - p->nivcsw); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -Index: src/kernel/exit.c -=================================================================== ---- src.orig/kernel/exit.c -+++ src/kernel/exit.c -@@ -715,6 +715,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void do_exit(long code) - { - struct task_struct *tsk = current; -@@ -812,6 +813,8 @@ void do_exit(long code) - check_stack_usage(); - exit_thread(); - -+ klp_shadow_free(tsk, 0); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -Index: src/kernel/fork.c -=================================================================== ---- src.orig/kernel/fork.c -+++ src/kernel/fork.c -@@ -1751,6 +1751,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -1788,6 +1789,13 @@ long do_fork(unsigned long clone_flags, - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; -+ int *newpid; -+ static int ctr = 0; -+ -+ newpid = klp_shadow_get_or_alloc(p, 0, NULL, sizeof(*newpid), -+ GFP_KERNEL); -+ if (newpid) -+ *newpid = ctr++; - - trace_sched_process_fork(current, p); - diff --git a/test/integration/rhel-7.5/smp-locks-section.patch b/test/integration/rhel-7.5/smp-locks-section.patch deleted file mode 100644 index 6f39d53..0000000 --- a/test/integration/rhel-7.5/smp-locks-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2017-09-22 15:27:21.077053604 -0400 -+++ src/drivers/tty/tty_buffer.c 2017-09-22 15:27:50.542175618 -0400 -@@ -217,6 +217,10 @@ int tty_buffer_request_room(struct tty_p - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ -+ -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b != NULL) - left = b->size - b->used; diff --git a/test/integration/rhel-7.5/special-static-2.patch b/test/integration/rhel-7.5/special-static-2.patch deleted file mode 100644 index 146d5b5..0000000 --- a/test/integration/rhel-7.5/special-static-2.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:51.744180596 -0400 -@@ -2093,12 +2093,20 @@ static void record_steal_time(struct kvm - &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); - } - -+void kpatch_kvm_x86_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch kvm x86 foo\n"); -+} -+ - int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) - { - bool pr = false; - u32 msr = msr_info->index; - u64 data = msr_info->data; - -+ kpatch_kvm_x86_foo(); -+ - switch (msr) { - case MSR_AMD64_NB_CFG: - case MSR_IA32_UCODE_REV: diff --git a/test/integration/rhel-7.5/special-static.patch b/test/integration/rhel-7.5/special-static.patch deleted file mode 100644 index 84647ec..0000000 --- a/test/integration/rhel-7.5/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2017-09-22 15:27:21.600055769 -0400 -+++ src/kernel/fork.c 2017-09-22 15:27:53.052186012 -0400 -@@ -1129,10 +1129,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-7.5/tracepoints-section.patch b/test/integration/rhel-7.5/tracepoints-section.patch deleted file mode 100644 index b770f9e..0000000 --- a/test/integration/rhel-7.5/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/timer.c src/kernel/timer.c ---- src.orig/kernel/timer.c 2017-09-22 15:27:21.600055769 -0400 -+++ src/kernel/timer.c 2017-09-22 15:27:54.288191131 -0400 -@@ -1390,6 +1390,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = __this_cpu_read(tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/rhel-7.5/warn-detect-FAIL.patch b/test/integration/rhel-7.5/warn-detect-FAIL.patch deleted file mode 100644 index 8efa782..0000000 --- a/test/integration/rhel-7.5/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:55.489196104 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-7.6/bug-table-section.patch b/test/integration/rhel-7.6/bug-table-section.patch deleted file mode 100644 index f75e398..0000000 --- a/test/integration/rhel-7.6/bug-table-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: kernel-rhel7/fs/proc/proc_sysctl.c -=================================================================== ---- kernel-rhel7.orig/fs/proc/proc_sysctl.c -+++ kernel-rhel7/fs/proc/proc_sysctl.c -@@ -301,6 +301,8 @@ void sysctl_head_put(struct ctl_table_he - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-7.6/cmdline-string-LOADED.test b/test/integration/rhel-7.6/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-7.6/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-7.6/cmdline-string.patch b/test/integration/rhel-7.6/cmdline-string.patch deleted file mode 100644 index 749861f..0000000 --- a/test/integration/rhel-7.6/cmdline-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/cmdline.c 2017-09-22 15:27:22.955061380 -0400 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-7.6/data-new-LOADED.test b/test/integration/rhel-7.6/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/rhel-7.6/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-7.6/data-new.patch b/test/integration/rhel-7.6/data-new.patch deleted file mode 100644 index e2f9333..0000000 --- a/test/integration/rhel-7.6/data-new.patch +++ /dev/null @@ -1,29 +0,0 @@ -Index: kernel-rhel7/fs/proc/meminfo.c -=================================================================== ---- kernel-rhel7.orig/fs/proc/meminfo.c -+++ kernel-rhel7/fs/proc/meminfo.c -@@ -20,6 +20,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -110,6 +112,7 @@ static int meminfo_proc_show(struct seq_ - "CmaTotal: %8lu kB\n" - "CmaFree: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -175,6 +178,7 @@ static int meminfo_proc_show(struct seq_ - , K(totalcma_pages) - , K(global_page_state(NR_FREE_CMA_PAGES)) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/rhel-7.6/data-read-mostly.patch.disabled b/test/integration/rhel-7.6/data-read-mostly.patch.disabled deleted file mode 100644 index 42b02cb..0000000 --- a/test/integration/rhel-7.6/data-read-mostly.patch.disabled +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel-rhel7/net/core/dev.c -=================================================================== ---- kernel-rhel7.orig/net/core/dev.c -+++ kernel-rhel7/net/core/dev.c -@@ -4199,6 +4199,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-7.6/fixup-section.patch b/test/integration/rhel-7.6/fixup-section.patch deleted file mode 100644 index 18d13b5..0000000 --- a/test/integration/rhel-7.6/fixup-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/readdir.c b/fs/readdir.c -index febd02dfbe2d..064db7bd70d0 100644 ---- a/fs/readdir.c -+++ b/fs/readdir.c -@@ -176,6 +176,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-7.6/gcc-constprop.patch.disabled b/test/integration/rhel-7.6/gcc-constprop.patch.disabled deleted file mode 100644 index 63ba45d..0000000 --- a/test/integration/rhel-7.6/gcc-constprop.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/time/timekeeping.c 2017-09-22 15:27:27.522080292 -0400 -@@ -877,6 +877,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-7.6/gcc-isra.patch b/test/integration/rhel-7.6/gcc-isra.patch deleted file mode 100644 index 1eab35c..0000000 --- a/test/integration/rhel-7.6/gcc-isra.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel-rhel7/fs/proc/proc_sysctl.c -=================================================================== ---- kernel-rhel7.orig/fs/proc/proc_sysctl.c -+++ kernel-rhel7/fs/proc/proc_sysctl.c -@@ -46,6 +46,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-7.6/gcc-mangled-3.patch b/test/integration/rhel-7.6/gcc-mangled-3.patch deleted file mode 100644 index 92ba80e..0000000 --- a/test/integration/rhel-7.6/gcc-mangled-3.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: kernel-rhel7/mm/slub.c -=================================================================== ---- kernel-rhel7.orig/mm/slub.c -+++ kernel-rhel7/mm/slub.c -@@ -5611,6 +5611,9 @@ void get_slabinfo(struct kmem_cache *s, - unsigned long nr_free = 0; - int node; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_online_node(node) { - struct kmem_cache_node *n = get_node(s, node); - diff --git a/test/integration/rhel-7.6/gcc-static-local-var-2.patch b/test/integration/rhel-7.6/gcc-static-local-var-2.patch deleted file mode 100644 index 7153968..0000000 --- a/test/integration/rhel-7.6/gcc-static-local-var-2.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: kernel-rhel7/mm/mmap.c -=================================================================== ---- kernel-rhel7.orig/mm/mmap.c -+++ kernel-rhel7/mm/mmap.c -@@ -1715,6 +1715,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-7.6/gcc-static-local-var-3.patch b/test/integration/rhel-7.6/gcc-static-local-var-3.patch deleted file mode 100644 index d751fc6..0000000 --- a/test/integration/rhel-7.6/gcc-static-local-var-3.patch +++ /dev/null @@ -1,20 +0,0 @@ -Index: kernel-rhel7/kernel/sys.c -=================================================================== ---- kernel-rhel7.orig/kernel/sys.c -+++ kernel-rhel7/kernel/sys.c -@@ -559,8 +559,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-7.6/gcc-static-local-var-4.patch b/test/integration/rhel-7.6/gcc-static-local-var-4.patch deleted file mode 100644 index e25d343..0000000 --- a/test/integration/rhel-7.6/gcc-static-local-var-4.patch +++ /dev/null @@ -1,21 +0,0 @@ -Index: kernel-rhel7/fs/aio.c -=================================================================== ---- kernel-rhel7.orig/fs/aio.c -+++ kernel-rhel7/fs/aio.c -@@ -223,9 +223,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/rhel-7.6/gcc-static-local-var-4.test b/test/integration/rhel-7.6/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-7.6/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-7.6/gcc-static-local-var-5.patch b/test/integration/rhel-7.6/gcc-static-local-var-5.patch deleted file mode 100644 index 540affa..0000000 --- a/test/integration/rhel-7.6/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/audit.c 2017-09-22 15:27:34.429108894 -0400 -@@ -205,6 +205,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -215,6 +221,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -234,6 +241,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -282,6 +294,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-7.6/gcc-static-local-var-6.patch b/test/integration/rhel-7.6/gcc-static-local-var-6.patch deleted file mode 100644 index bd5493c..0000000 --- a/test/integration/rhel-7.6/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c -index a9d587a..23336ed 100644 ---- a/net/ipv6/netfilter.c -+++ b/net/ipv6/netfilter.c -@@ -106,6 +106,8 @@ static int nf_ip6_reroute(struct sk_buff *skb, - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -119,6 +121,9 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-7.6/macro-callbacks.patch b/test/integration/rhel-7.6/macro-callbacks.patch deleted file mode 100644 index 0d6831b..0000000 --- a/test/integration/rhel-7.6/macro-callbacks.patch +++ /dev/null @@ -1,160 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - ---- src.old/fs/aio.c 2018-02-26 11:07:51.522610407 -0500 -+++ src/fs/aio.c 2018-03-05 11:17:21.560015449 -0500 -@@ -42,6 +42,50 @@ - #include - #include - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 ---- src.old/drivers/input/joydev.c 2018-02-26 11:07:49.470610407 -0500 -+++ src/drivers/input/joydev.c 2018-03-05 11:18:13.998015449 -0500 -@@ -954,3 +954,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); ---- src.old/drivers/input/misc/pcspkr.c 2018-02-26 11:07:49.477610407 -0500 -+++ src/drivers/input/misc/pcspkr.c 2018-03-05 11:18:23.411015449 -0500 -@@ -136,3 +136,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); diff --git a/test/integration/rhel-7.6/macro-printk.patch b/test/integration/rhel-7.6/macro-printk.patch deleted file mode 100644 index e837173..0000000 --- a/test/integration/rhel-7.6/macro-printk.patch +++ /dev/null @@ -1,151 +0,0 @@ -Index: kernel-rhel7/net/ipv4/fib_frontend.c -=================================================================== ---- kernel-rhel7.orig/net/ipv4/fib_frontend.c -+++ kernel-rhel7/net/ipv4/fib_frontend.c -@@ -685,6 +685,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -703,6 +704,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(net, tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -Index: kernel-rhel7/net/ipv4/fib_semantics.c -=================================================================== ---- kernel-rhel7.orig/net/ipv4/fib_semantics.c -+++ kernel-rhel7/net/ipv4/fib_semantics.c -@@ -969,6 +969,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -993,6 +994,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1013,6 +1015,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) -@@ -1028,6 +1031,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1043,8 +1048,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1095,6 +1102,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1112,6 +1120,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1134,6 +1143,7 @@ struct fib_info *fib_create_info(struct - goto failure; - } endfor_nexthops(fi) - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || -@@ -1146,6 +1156,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1157,6 +1168,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1180,6 +1192,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1190,6 +1203,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -Index: kernel-rhel7/net/ipv4/fib_trie.c -=================================================================== ---- kernel-rhel7.orig/net/ipv4/fib_trie.c -+++ kernel-rhel7/net/ipv4/fib_trie.c -@@ -1105,6 +1105,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) - { -@@ -1130,11 +1131,14 @@ int fib_table_insert(struct net *net, st - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-7.6/meminfo-init-FAIL.patch b/test/integration/rhel-7.6/meminfo-init-FAIL.patch deleted file mode 100644 index 3b8672d..0000000 --- a/test/integration/rhel-7.6/meminfo-init-FAIL.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel-rhel7/fs/proc/meminfo.c -=================================================================== ---- kernel-rhel7.orig/fs/proc/meminfo.c -+++ kernel-rhel7/fs/proc/meminfo.c -@@ -199,6 +199,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.6/meminfo-init2-FAIL.patch b/test/integration/rhel-7.6/meminfo-init2-FAIL.patch deleted file mode 100644 index cd70ef9..0000000 --- a/test/integration/rhel-7.6/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,20 +0,0 @@ -Index: kernel-rhel7/fs/proc/meminfo.c -=================================================================== ---- kernel-rhel7.orig/fs/proc/meminfo.c -+++ kernel-rhel7/fs/proc/meminfo.c -@@ -30,6 +30,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -199,6 +200,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.6/meminfo-string-LOADED.test b/test/integration/rhel-7.6/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-7.6/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-7.6/meminfo-string.patch b/test/integration/rhel-7.6/meminfo-string.patch deleted file mode 100644 index afdc5d0..0000000 --- a/test/integration/rhel-7.6/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:41.274137239 -0400 -@@ -99,7 +99,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" - #endif diff --git a/test/integration/rhel-7.6/module-call-external.patch b/test/integration/rhel-7.6/module-call-external.patch deleted file mode 100644 index f149edf..0000000 --- a/test/integration/rhel-7.6/module-call-external.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c -index 27459a453bb8..2247255877be 100644 ---- a/fs/nfsd/export.c -+++ b/fs/nfsd/export.c -@@ -1184,7 +1184,13 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, - } - } - -+extern char *kpatch_string(void); -+ -+#ifdef CONFIG_PPC64 -+static int __attribute__((optimize("-fno-optimize-sibling-calls"))) e_show(struct seq_file *m, void *p) -+#else - static int e_show(struct seq_file *m, void *p) -+#endif - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); -@@ -1193,6 +1199,7 @@ static int e_show(struct seq_file *m, void *p) - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index 592f64643491..21b87cb948c9 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -2568,4 +2568,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-7.6/multiple.test b/test/integration/rhel-7.6/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-7.6/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-7.6/new-function.patch b/test/integration/rhel-7.6/new-function.patch deleted file mode 100644 index a9a0724..0000000 --- a/test/integration/rhel-7.6/new-function.patch +++ /dev/null @@ -1,26 +0,0 @@ -Index: kernel-rhel7/drivers/tty/n_tty.c -=================================================================== ---- kernel-rhel7.orig/drivers/tty/n_tty.c -+++ kernel-rhel7/drivers/tty/n_tty.c -@@ -2128,7 +2128,7 @@ do_it_again: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2210,6 +2210,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-7.6/new-globals.patch b/test/integration/rhel-7.6/new-globals.patch deleted file mode 100644 index 3d9d349..0000000 --- a/test/integration/rhel-7.6/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/cmdline.c 2017-09-22 15:27:47.028161067 -0400 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - module_init(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2017-09-22 15:27:21.699056179 -0400 -+++ src/fs/proc/meminfo.c 2017-09-22 15:27:47.029161071 -0400 -@@ -16,6 +16,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -53,6 +55,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/rhel-7.6/parainstructions-section.patch b/test/integration/rhel-7.6/parainstructions-section.patch deleted file mode 100644 index 809dce4..0000000 --- a/test/integration/rhel-7.6/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2017-09-22 15:27:21.698056175 -0400 -+++ src/fs/proc/generic.c 2017-09-22 15:27:48.190165879 -0400 -@@ -194,6 +194,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/rhel-7.6/shadow-newpid-LOADED.test b/test/integration/rhel-7.6/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-7.6/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-7.6/shadow-newpid.patch b/test/integration/rhel-7.6/shadow-newpid.patch deleted file mode 100644 index 17bf527..0000000 --- a/test/integration/rhel-7.6/shadow-newpid.patch +++ /dev/null @@ -1,72 +0,0 @@ -diff --git a/fs/proc/array.c b/fs/proc/array.c -index 39684c79e8e2..138b60d1314d 100644 ---- a/fs/proc/array.c -+++ b/fs/proc/array.c -@@ -394,13 +394,20 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" - "nonvoluntary_ctxt_switches:\t%lu\n", - p->nvcsw, - p->nivcsw); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff --git a/kernel/exit.c b/kernel/exit.c -index 148a7842928d..e1dbab71b37d 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -791,6 +791,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void do_exit(long code) - { - struct task_struct *tsk = current; -@@ -888,6 +889,8 @@ void do_exit(long code) - check_stack_usage(); - exit_thread(); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff --git a/kernel/fork.c b/kernel/fork.c -index 9bff3b28c357..529a2c943d7c 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1757,6 +1757,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -1794,6 +1795,13 @@ long do_fork(unsigned long clone_flags, - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; -+ int *newpid; -+ static int ctr = 0; -+ -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; - - trace_sched_process_fork(current, p); - diff --git a/test/integration/rhel-7.6/smp-locks-section.patch b/test/integration/rhel-7.6/smp-locks-section.patch deleted file mode 100644 index 6f39d53..0000000 --- a/test/integration/rhel-7.6/smp-locks-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2017-09-22 15:27:21.077053604 -0400 -+++ src/drivers/tty/tty_buffer.c 2017-09-22 15:27:50.542175618 -0400 -@@ -217,6 +217,10 @@ int tty_buffer_request_room(struct tty_p - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ -+ -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b != NULL) - left = b->size - b->used; diff --git a/test/integration/rhel-7.6/special-static.patch b/test/integration/rhel-7.6/special-static.patch deleted file mode 100644 index 7fa529f..0000000 --- a/test/integration/rhel-7.6/special-static.patch +++ /dev/null @@ -1,23 +0,0 @@ -Index: kernel-rhel7/kernel/fork.c -=================================================================== ---- kernel-rhel7.orig/kernel/fork.c -+++ kernel-rhel7/kernel/fork.c -@@ -1146,10 +1146,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-7.6/symvers-disagreement-FAIL.patch b/test/integration/rhel-7.6/symvers-disagreement-FAIL.patch deleted file mode 100644 index d8ef754..0000000 --- a/test/integration/rhel-7.6/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,51 +0,0 @@ -From bcb86fa4e9c31379a9e2716eae29cd53ccca064f Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index b9a71137208..4af27e069c2 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -31,6 +31,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index f9db3660999..bece0bf4f5a 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -691,6 +691,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.1 - diff --git a/test/integration/rhel-7.6/tracepoints-section.patch b/test/integration/rhel-7.6/tracepoints-section.patch deleted file mode 100644 index 512e512..0000000 --- a/test/integration/rhel-7.6/tracepoints-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: kernel-rhel7/kernel/timer.c -=================================================================== ---- kernel-rhel7.orig/kernel/timer.c -+++ kernel-rhel7/kernel/timer.c -@@ -1454,6 +1454,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = __this_cpu_read(tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/rhel-7.6/warn-detect-FAIL.patch b/test/integration/rhel-7.6/warn-detect-FAIL.patch deleted file mode 100644 index 8efa782..0000000 --- a/test/integration/rhel-7.6/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2017-09-22 15:27:20.852052672 -0400 -+++ src/arch/x86/kvm/x86.c 2017-09-22 15:27:55.489196104 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-7.7/bug-table-section.patch b/test/integration/rhel-7.7/bug-table-section.patch deleted file mode 100644 index 34342c0..0000000 --- a/test/integration/rhel-7.7/bug-table-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: kernel/fs/proc/proc_sysctl.c -=================================================================== ---- kernel.orig/fs/proc/proc_sysctl.c -+++ kernel/fs/proc/proc_sysctl.c -@@ -301,6 +301,8 @@ void sysctl_head_put(struct ctl_table_he - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-7.7/cmdline-string-LOADED.test b/test/integration/rhel-7.7/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-7.7/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-7.7/cmdline-string.patch b/test/integration/rhel-7.7/cmdline-string.patch deleted file mode 100644 index f1f12b3..0000000 --- a/test/integration/rhel-7.7/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: kernel/fs/proc/cmdline.c -=================================================================== ---- kernel.orig/fs/proc/cmdline.c -+++ kernel/fs/proc/cmdline.c -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-7.7/data-new-LOADED.test b/test/integration/rhel-7.7/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/rhel-7.7/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-7.7/data-new.patch b/test/integration/rhel-7.7/data-new.patch deleted file mode 100644 index 4f9abcf..0000000 --- a/test/integration/rhel-7.7/data-new.patch +++ /dev/null @@ -1,29 +0,0 @@ -Index: kernel/fs/proc/meminfo.c -=================================================================== ---- kernel.orig/fs/proc/meminfo.c -+++ kernel/fs/proc/meminfo.c -@@ -20,6 +20,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -110,6 +112,7 @@ static int meminfo_proc_show(struct seq_ - "CmaTotal: %8lu kB\n" - "CmaFree: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -175,6 +178,7 @@ static int meminfo_proc_show(struct seq_ - , K(totalcma_pages) - , K(global_page_state(NR_FREE_CMA_PAGES)) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/rhel-7.7/data-read-mostly.patch.disabled b/test/integration/rhel-7.7/data-read-mostly.patch.disabled deleted file mode 100644 index 5e55826..0000000 --- a/test/integration/rhel-7.7/data-read-mostly.patch.disabled +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel/net/core/dev.c -=================================================================== ---- kernel.orig/net/core/dev.c -+++ kernel/net/core/dev.c -@@ -4327,6 +4327,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-7.7/fixup-section.patch b/test/integration/rhel-7.7/fixup-section.patch deleted file mode 100644 index 27c01cf..0000000 --- a/test/integration/rhel-7.7/fixup-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel/fs/readdir.c -=================================================================== ---- kernel.orig/fs/readdir.c -+++ kernel/fs/readdir.c -@@ -176,6 +176,7 @@ static int filldir(void * __buf, const c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-7.7/gcc-constprop.patch.disabled b/test/integration/rhel-7.7/gcc-constprop.patch.disabled deleted file mode 100644 index 63ba45d..0000000 --- a/test/integration/rhel-7.7/gcc-constprop.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2017-09-22 15:27:21.602055778 -0400 -+++ src/kernel/time/timekeeping.c 2017-09-22 15:27:27.522080292 -0400 -@@ -877,6 +877,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-7.7/gcc-isra.patch b/test/integration/rhel-7.7/gcc-isra.patch deleted file mode 100644 index ce5434a..0000000 --- a/test/integration/rhel-7.7/gcc-isra.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel/fs/proc/proc_sysctl.c -=================================================================== ---- kernel.orig/fs/proc/proc_sysctl.c -+++ kernel/fs/proc/proc_sysctl.c -@@ -46,6 +46,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-7.7/gcc-mangled-3.patch b/test/integration/rhel-7.7/gcc-mangled-3.patch deleted file mode 100644 index 7dbfc62..0000000 --- a/test/integration/rhel-7.7/gcc-mangled-3.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: kernel/mm/slub.c -=================================================================== ---- kernel.orig/mm/slub.c -+++ kernel/mm/slub.c -@@ -5675,6 +5675,9 @@ void get_slabinfo(struct kmem_cache *s, - unsigned long nr_free = 0; - int node; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_online_node(node) { - struct kmem_cache_node *n = get_node(s, node); - diff --git a/test/integration/rhel-7.7/gcc-static-local-var-2.patch b/test/integration/rhel-7.7/gcc-static-local-var-2.patch deleted file mode 100644 index d1b70f1..0000000 --- a/test/integration/rhel-7.7/gcc-static-local-var-2.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: kernel/mm/mmap.c -=================================================================== ---- kernel.orig/mm/mmap.c -+++ kernel/mm/mmap.c -@@ -1716,6 +1716,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-7.7/gcc-static-local-var-3.patch b/test/integration/rhel-7.7/gcc-static-local-var-3.patch deleted file mode 100644 index 584c869..0000000 --- a/test/integration/rhel-7.7/gcc-static-local-var-3.patch +++ /dev/null @@ -1,20 +0,0 @@ -Index: kernel/kernel/sys.c -=================================================================== ---- kernel.orig/kernel/sys.c -+++ kernel/kernel/sys.c -@@ -559,8 +559,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-7.7/gcc-static-local-var-4.patch b/test/integration/rhel-7.7/gcc-static-local-var-4.patch deleted file mode 100644 index 85e4df5..0000000 --- a/test/integration/rhel-7.7/gcc-static-local-var-4.patch +++ /dev/null @@ -1,21 +0,0 @@ -Index: kernel/fs/aio.c -=================================================================== ---- kernel.orig/fs/aio.c -+++ kernel/fs/aio.c -@@ -223,9 +223,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/rhel-7.7/gcc-static-local-var-4.test b/test/integration/rhel-7.7/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-7.7/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-7.7/gcc-static-local-var-5.patch b/test/integration/rhel-7.7/gcc-static-local-var-5.patch deleted file mode 100644 index 3028676..0000000 --- a/test/integration/rhel-7.7/gcc-static-local-var-5.patch +++ /dev/null @@ -1,46 +0,0 @@ -Index: kernel/kernel/audit.c -=================================================================== ---- kernel.orig/kernel/audit.c -+++ kernel/kernel/audit.c -@@ -205,6 +205,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -215,6 +221,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -234,6 +241,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -282,6 +294,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-7.7/gcc-static-local-var-6.patch b/test/integration/rhel-7.7/gcc-static-local-var-6.patch deleted file mode 100644 index 53c3946..0000000 --- a/test/integration/rhel-7.7/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -Index: kernel/net/ipv6/netfilter.c -=================================================================== ---- kernel.orig/net/ipv6/netfilter.c -+++ kernel/net/ipv6/netfilter.c -@@ -112,6 +112,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -125,6 +127,9 @@ static int nf_ip6_route(struct net *net, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-7.7/macro-callbacks.patch b/test/integration/rhel-7.7/macro-callbacks.patch deleted file mode 100644 index d6757e0..0000000 --- a/test/integration/rhel-7.7/macro-callbacks.patch +++ /dev/null @@ -1,166 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - -Index: kernel/fs/aio.c -=================================================================== ---- kernel.orig/fs/aio.c -+++ kernel/fs/aio.c -@@ -42,6 +42,50 @@ - #include - #include - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 -Index: kernel/drivers/input/joydev.c -=================================================================== ---- kernel.orig/drivers/input/joydev.c -+++ kernel/drivers/input/joydev.c -@@ -954,3 +954,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -Index: kernel/drivers/input/misc/pcspkr.c -=================================================================== ---- kernel.orig/drivers/input/misc/pcspkr.c -+++ kernel/drivers/input/misc/pcspkr.c -@@ -136,3 +136,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); diff --git a/test/integration/rhel-7.7/macro-printk.patch b/test/integration/rhel-7.7/macro-printk.patch deleted file mode 100644 index a4ff62c..0000000 --- a/test/integration/rhel-7.7/macro-printk.patch +++ /dev/null @@ -1,151 +0,0 @@ -Index: kernel/net/ipv4/fib_frontend.c -=================================================================== ---- kernel.orig/net/ipv4/fib_frontend.c -+++ kernel/net/ipv4/fib_frontend.c -@@ -686,6 +686,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -704,6 +705,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(net, tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -Index: kernel/net/ipv4/fib_semantics.c -=================================================================== ---- kernel.orig/net/ipv4/fib_semantics.c -+++ kernel/net/ipv4/fib_semantics.c -@@ -985,6 +985,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -1009,6 +1010,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1029,6 +1031,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) -@@ -1044,6 +1047,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1059,8 +1064,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1111,6 +1118,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1128,6 +1136,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1150,6 +1159,7 @@ struct fib_info *fib_create_info(struct - goto failure; - } endfor_nexthops(fi) - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || -@@ -1162,6 +1172,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1173,6 +1184,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1196,6 +1208,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1206,6 +1219,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -Index: kernel/net/ipv4/fib_trie.c -=================================================================== ---- kernel.orig/net/ipv4/fib_trie.c -+++ kernel/net/ipv4/fib_trie.c -@@ -1105,6 +1105,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) - { -@@ -1130,11 +1131,14 @@ int fib_table_insert(struct net *net, st - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-7.7/meminfo-init-FAIL.patch b/test/integration/rhel-7.7/meminfo-init-FAIL.patch deleted file mode 100644 index f3e6c73..0000000 --- a/test/integration/rhel-7.7/meminfo-init-FAIL.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel/fs/proc/meminfo.c -=================================================================== ---- kernel.orig/fs/proc/meminfo.c -+++ kernel/fs/proc/meminfo.c -@@ -199,6 +199,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.7/meminfo-init2-FAIL.patch b/test/integration/rhel-7.7/meminfo-init2-FAIL.patch deleted file mode 100644 index e225294..0000000 --- a/test/integration/rhel-7.7/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,20 +0,0 @@ -Index: kernel/fs/proc/meminfo.c -=================================================================== ---- kernel.orig/fs/proc/meminfo.c -+++ kernel/fs/proc/meminfo.c -@@ -30,6 +30,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -199,6 +200,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.7/meminfo-string-LOADED.test b/test/integration/rhel-7.7/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-7.7/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-7.7/meminfo-string.patch b/test/integration/rhel-7.7/meminfo-string.patch deleted file mode 100644 index 23ff7a7..0000000 --- a/test/integration/rhel-7.7/meminfo-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: kernel/fs/proc/meminfo.c -=================================================================== ---- kernel.orig/fs/proc/meminfo.c -+++ kernel/fs/proc/meminfo.c -@@ -99,7 +99,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" - #endif diff --git a/test/integration/rhel-7.7/module-call-external.patch b/test/integration/rhel-7.7/module-call-external.patch deleted file mode 100644 index f149edf..0000000 --- a/test/integration/rhel-7.7/module-call-external.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c -index 27459a453bb8..2247255877be 100644 ---- a/fs/nfsd/export.c -+++ b/fs/nfsd/export.c -@@ -1184,7 +1184,13 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, - } - } - -+extern char *kpatch_string(void); -+ -+#ifdef CONFIG_PPC64 -+static int __attribute__((optimize("-fno-optimize-sibling-calls"))) e_show(struct seq_file *m, void *p) -+#else - static int e_show(struct seq_file *m, void *p) -+#endif - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); -@@ -1193,6 +1199,7 @@ static int e_show(struct seq_file *m, void *p) - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index 592f64643491..21b87cb948c9 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -2568,4 +2568,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-7.7/multiple.test b/test/integration/rhel-7.7/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-7.7/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-7.7/new-function.patch b/test/integration/rhel-7.7/new-function.patch deleted file mode 100644 index 604dbe5..0000000 --- a/test/integration/rhel-7.7/new-function.patch +++ /dev/null @@ -1,26 +0,0 @@ -Index: kernel/drivers/tty/n_tty.c -=================================================================== ---- kernel.orig/drivers/tty/n_tty.c -+++ kernel/drivers/tty/n_tty.c -@@ -2175,7 +2175,7 @@ do_it_again: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2264,6 +2264,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-7.7/new-globals.patch b/test/integration/rhel-7.7/new-globals.patch deleted file mode 100644 index e18d09d..0000000 --- a/test/integration/rhel-7.7/new-globals.patch +++ /dev/null @@ -1,36 +0,0 @@ -Index: kernel/fs/proc/cmdline.c -=================================================================== ---- kernel.orig/fs/proc/cmdline.c -+++ kernel/fs/proc/cmdline.c -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - module_init(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -Index: kernel/fs/proc/meminfo.c -=================================================================== ---- kernel.orig/fs/proc/meminfo.c -+++ kernel/fs/proc/meminfo.c -@@ -16,6 +16,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -53,6 +55,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/rhel-7.7/parainstructions-section.patch b/test/integration/rhel-7.7/parainstructions-section.patch deleted file mode 100644 index 151d263..0000000 --- a/test/integration/rhel-7.7/parainstructions-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -Index: kernel/fs/proc/generic.c -=================================================================== ---- kernel.orig/fs/proc/generic.c -+++ kernel/fs/proc/generic.c -@@ -194,6 +194,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/rhel-7.7/shadow-newpid-LOADED.test b/test/integration/rhel-7.7/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-7.7/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-7.7/shadow-newpid.patch b/test/integration/rhel-7.7/shadow-newpid.patch deleted file mode 100644 index cae690d..0000000 --- a/test/integration/rhel-7.7/shadow-newpid.patch +++ /dev/null @@ -1,72 +0,0 @@ -Index: kernel/fs/proc/array.c -=================================================================== ---- kernel.orig/fs/proc/array.c -+++ kernel/fs/proc/array.c -@@ -395,13 +395,20 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" - "nonvoluntary_ctxt_switches:\t%lu\n", - p->nvcsw, - p->nivcsw); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -Index: kernel/kernel/exit.c -=================================================================== ---- kernel.orig/kernel/exit.c -+++ kernel/kernel/exit.c -@@ -791,6 +791,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void do_exit(long code) - { - struct task_struct *tsk = current; -@@ -888,6 +889,8 @@ void do_exit(long code) - check_stack_usage(); - exit_thread(); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -Index: kernel/kernel/fork.c -=================================================================== ---- kernel.orig/kernel/fork.c -+++ kernel/kernel/fork.c -@@ -1760,6 +1760,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -1797,6 +1798,13 @@ long do_fork(unsigned long clone_flags, - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; -+ int *newpid; -+ static int ctr = 0; -+ -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; - - trace_sched_process_fork(current, p); - diff --git a/test/integration/rhel-7.7/smp-locks-section.patch b/test/integration/rhel-7.7/smp-locks-section.patch deleted file mode 100644 index 7aa1c31..0000000 --- a/test/integration/rhel-7.7/smp-locks-section.patch +++ /dev/null @@ -1,15 +0,0 @@ -Index: kernel/drivers/tty/tty_buffer.c -=================================================================== ---- kernel.orig/drivers/tty/tty_buffer.c -+++ kernel/drivers/tty/tty_buffer.c -@@ -217,6 +217,10 @@ int tty_buffer_request_room(struct tty_p - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ -+ -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b != NULL) - left = b->size - b->used; diff --git a/test/integration/rhel-7.7/special-static.patch b/test/integration/rhel-7.7/special-static.patch deleted file mode 100644 index 8a757ba..0000000 --- a/test/integration/rhel-7.7/special-static.patch +++ /dev/null @@ -1,23 +0,0 @@ -Index: kernel/kernel/fork.c -=================================================================== ---- kernel.orig/kernel/fork.c -+++ kernel/kernel/fork.c -@@ -1146,10 +1146,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-7.7/symvers-disagreement-FAIL.patch b/test/integration/rhel-7.7/symvers-disagreement-FAIL.patch deleted file mode 100644 index e940645..0000000 --- a/test/integration/rhel-7.7/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,51 +0,0 @@ -From d5513eae5155c6e7e884554d5e3e2c65a7b39cbe Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index b9a71137208..4af27e069c2 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -31,6 +31,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index d6337db2164..0ff9722dfa2 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -693,6 +693,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-7.7/tracepoints-section.patch b/test/integration/rhel-7.7/tracepoints-section.patch deleted file mode 100644 index b992e14..0000000 --- a/test/integration/rhel-7.7/tracepoints-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -Index: kernel/kernel/timer.c -=================================================================== ---- kernel.orig/kernel/timer.c -+++ kernel/kernel/timer.c -@@ -1454,6 +1454,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = __this_cpu_read(tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/rhel-7.7/warn-detect-FAIL.patch b/test/integration/rhel-7.7/warn-detect-FAIL.patch deleted file mode 100644 index 801fa4c..0000000 --- a/test/integration/rhel-7.7/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -Index: kernel/arch/x86/kvm/x86.c -=================================================================== ---- kernel.orig/arch/x86/kvm/x86.c -+++ kernel/arch/x86/kvm/x86.c -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-7.8/bug-table-section.patch b/test/integration/rhel-7.8/bug-table-section.patch deleted file mode 100644 index 864ad9b..0000000 --- a/test/integration/rhel-7.8/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-03-10 10:35:54.568563834 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-03-10 10:35:57.040558842 -0400 -@@ -331,6 +331,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-7.8/cmdline-string-LOADED.test b/test/integration/rhel-7.8/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-7.8/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-7.8/cmdline-string.patch b/test/integration/rhel-7.8/cmdline-string.patch deleted file mode 100644 index 0c691b1..0000000 --- a/test/integration/rhel-7.8/cmdline-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-03-10 10:35:54.567563836 -0400 -+++ src/fs/proc/cmdline.c 2020-03-10 10:36:03.207546389 -0400 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-7.8/data-new-LOADED.test b/test/integration/rhel-7.8/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/rhel-7.8/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-7.8/data-new.patch b/test/integration/rhel-7.8/data-new.patch deleted file mode 100644 index e213f82..0000000 --- a/test/integration/rhel-7.8/data-new.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-10 10:35:54.568563834 -0400 -+++ src/fs/proc/meminfo.c 2020-03-10 10:36:07.968536775 -0400 -@@ -21,6 +21,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -112,6 +114,7 @@ static int meminfo_proc_show(struct seq_ - "CmaTotal: %8lu kB\n" - "CmaFree: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -178,6 +181,7 @@ static int meminfo_proc_show(struct seq_ - , K(totalcma_pages) - , K(global_page_state(NR_FREE_CMA_PAGES)) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/rhel-7.8/data-read-mostly.patch.disabled b/test/integration/rhel-7.8/data-read-mostly.patch.disabled deleted file mode 100644 index 12f3b0c..0000000 --- a/test/integration/rhel-7.8/data-read-mostly.patch.disabled +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2020-03-10 10:35:55.176562607 -0400 -+++ src/net/core/dev.c 2020-03-10 10:37:54.458302249 -0400 -@@ -4327,6 +4327,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-7.8/fixup-section.patch b/test/integration/rhel-7.8/fixup-section.patch deleted file mode 100644 index 65b3ed5..0000000 --- a/test/integration/rhel-7.8/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2020-03-10 10:35:54.574563822 -0400 -+++ src/fs/readdir.c 2020-03-10 10:36:12.621527378 -0400 -@@ -176,6 +176,7 @@ static int filldir(void * __buf, const c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-7.8/gcc-constprop.patch.disabled b/test/integration/rhel-7.8/gcc-constprop.patch.disabled deleted file mode 100644 index 609f52d..0000000 --- a/test/integration/rhel-7.8/gcc-constprop.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2020-03-10 10:35:55.091562778 -0400 -+++ src/kernel/time/timekeeping.c 2020-03-10 10:37:59.105290886 -0400 -@@ -852,6 +852,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-7.8/gcc-isra.patch b/test/integration/rhel-7.8/gcc-isra.patch deleted file mode 100644 index dc58bdb..0000000 --- a/test/integration/rhel-7.8/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-03-10 10:35:54.568563834 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-03-10 10:36:17.393517742 -0400 -@@ -46,6 +46,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-7.8/gcc-mangled-3.patch b/test/integration/rhel-7.8/gcc-mangled-3.patch deleted file mode 100644 index 29477f1..0000000 --- a/test/integration/rhel-7.8/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2020-03-10 10:35:55.138562683 -0400 -+++ src/mm/slub.c 2020-03-10 10:36:22.189508057 -0400 -@@ -5716,6 +5716,9 @@ void get_slabinfo(struct kmem_cache *s, - unsigned long nr_free = 0; - int node; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_online_node(node) { - struct kmem_cache_node *n = get_node(s, node); - diff --git a/test/integration/rhel-7.8/gcc-static-local-var-2.patch b/test/integration/rhel-7.8/gcc-static-local-var-2.patch deleted file mode 100644 index 34087aa..0000000 --- a/test/integration/rhel-7.8/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2020-03-10 10:35:55.133562693 -0400 -+++ src/mm/mmap.c 2020-03-10 10:36:26.787498772 -0400 -@@ -1721,6 +1721,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-7.8/gcc-static-local-var-3.patch b/test/integration/rhel-7.8/gcc-static-local-var-3.patch deleted file mode 100644 index 3f9723b..0000000 --- a/test/integration/rhel-7.8/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2020-03-10 10:35:55.088562784 -0400 -+++ src/kernel/sys.c 2020-03-10 10:36:31.420489416 -0400 -@@ -559,8 +559,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-7.8/gcc-static-local-var-4.patch b/test/integration/rhel-7.8/gcc-static-local-var-4.patch deleted file mode 100644 index 0533a9f..0000000 --- a/test/integration/rhel-7.8/gcc-static-local-var-4.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-03-10 10:35:54.403564168 -0400 -+++ src/fs/aio.c 2020-03-10 10:36:36.025480117 -0400 -@@ -223,9 +223,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/rhel-7.8/gcc-static-local-var-4.test b/test/integration/rhel-7.8/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-7.8/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-7.8/gcc-static-local-var-5.patch b/test/integration/rhel-7.8/gcc-static-local-var-5.patch deleted file mode 100644 index 12a072a..0000000 --- a/test/integration/rhel-7.8/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2020-03-10 10:35:55.059562843 -0400 -+++ src/kernel/audit.c 2020-03-10 10:36:41.387468209 -0400 -@@ -205,6 +205,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -215,6 +221,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -234,6 +241,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -282,6 +294,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-7.8/gcc-static-local-var-6.patch b/test/integration/rhel-7.8/gcc-static-local-var-6.patch deleted file mode 100644 index 81e7ad1..0000000 --- a/test/integration/rhel-7.8/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2020-03-10 10:35:55.213562532 -0400 -+++ src/net/ipv6/netfilter.c 2020-03-10 10:36:47.062455553 -0400 -@@ -112,6 +112,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -125,6 +127,9 @@ static int nf_ip6_route(struct net *net, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-7.8/macro-callbacks.patch b/test/integration/rhel-7.8/macro-callbacks.patch deleted file mode 100644 index 0ca7098..0000000 --- a/test/integration/rhel-7.8/macro-callbacks.patch +++ /dev/null @@ -1,163 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2020-03-10 10:35:52.635567738 -0400 -+++ src/drivers/input/joydev.c 2020-03-10 10:36:51.651445319 -0400 -@@ -954,3 +954,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2020-03-10 10:35:52.650567707 -0400 -+++ src/drivers/input/misc/pcspkr.c 2020-03-10 10:36:51.652445316 -0400 -@@ -136,3 +136,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-03-10 10:35:54.403564168 -0400 -+++ src/fs/aio.c 2020-03-10 10:36:51.651445319 -0400 -@@ -42,6 +42,50 @@ - #include - #include - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-7.8/macro-printk.patch b/test/integration/rhel-7.8/macro-printk.patch deleted file mode 100644 index f360d82..0000000 --- a/test/integration/rhel-7.8/macro-printk.patch +++ /dev/null @@ -1,148 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2020-03-10 10:35:55.194562570 -0400 -+++ src/net/ipv4/fib_frontend.c 2020-03-10 10:36:56.379434774 -0400 -@@ -690,6 +690,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -708,6 +709,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(net, tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2020-03-10 10:35:55.194562570 -0400 -+++ src/net/ipv4/fib_semantics.c 2020-03-10 10:36:56.380434772 -0400 -@@ -985,6 +985,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -1009,6 +1010,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1029,6 +1031,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) -@@ -1044,6 +1047,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1059,8 +1064,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1111,6 +1118,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1128,6 +1136,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1150,6 +1159,7 @@ struct fib_info *fib_create_info(struct - goto failure; - } endfor_nexthops(fi) - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || -@@ -1162,6 +1172,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1173,6 +1184,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1196,6 +1208,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1206,6 +1219,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2020-03-10 10:35:55.195562568 -0400 -+++ src/net/ipv4/fib_trie.c 2020-03-10 10:36:56.381434770 -0400 -@@ -1105,6 +1105,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) - { -@@ -1130,11 +1131,14 @@ int fib_table_insert(struct net *net, st - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-7.8/meminfo-init-FAIL.patch b/test/integration/rhel-7.8/meminfo-init-FAIL.patch deleted file mode 100644 index 05f0c37..0000000 --- a/test/integration/rhel-7.8/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-10 10:35:54.568563834 -0400 -+++ src/fs/proc/meminfo.c 2020-03-10 10:37:07.161410729 -0400 -@@ -202,6 +202,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.8/meminfo-init2-FAIL.patch b/test/integration/rhel-7.8/meminfo-init2-FAIL.patch deleted file mode 100644 index ad0664b..0000000 --- a/test/integration/rhel-7.8/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-10 10:35:54.568563834 -0400 -+++ src/fs/proc/meminfo.c 2020-03-10 10:37:00.986424500 -0400 -@@ -31,6 +31,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -202,6 +203,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.8/meminfo-string-LOADED.test b/test/integration/rhel-7.8/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-7.8/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-7.8/meminfo-string.patch b/test/integration/rhel-7.8/meminfo-string.patch deleted file mode 100644 index 33e3a17..0000000 --- a/test/integration/rhel-7.8/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr linux-3.10.0-1127.fc30.x86_64.orig/fs/proc/meminfo.c linux-3.10.0-1127.fc30.x86_64/fs/proc/meminfo.c ---- linux-3.10.0-1127.fc30.x86_64.orig/fs/proc/meminfo.c 2020-03-10 09:40:37.849666782 -0400 -+++ linux-3.10.0-1127.fc30.x86_64/fs/proc/meminfo.c 2020-03-10 09:50:26.871990501 -0400 -@@ -100,7 +100,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - "Percpu: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" diff --git a/test/integration/rhel-7.8/module-call-external.patch b/test/integration/rhel-7.8/module-call-external.patch deleted file mode 100644 index b1c594d..0000000 --- a/test/integration/rhel-7.8/module-call-external.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2020-03-10 10:35:54.521563929 -0400 -+++ src/fs/nfsd/export.c 2020-03-10 10:37:11.704400597 -0400 -@@ -1184,7 +1184,13 @@ static void exp_flags(struct seq_file *m - } - } - -+extern char *kpatch_string(void); -+ -+#ifdef CONFIG_PPC64 -+static int __attribute__((optimize("-fno-optimize-sibling-calls"))) e_show(struct seq_file *m, void *p) -+#else - static int e_show(struct seq_file *m, void *p) -+#endif - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); -@@ -1193,6 +1199,7 @@ static int e_show(struct seq_file *m, vo - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2020-03-10 10:35:56.447560040 -0400 -+++ src/net/netlink/af_netlink.c 2020-03-10 10:37:11.705400594 -0400 -@@ -2568,4 +2568,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-7.8/multiple.test b/test/integration/rhel-7.8/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-7.8/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-7.8/new-function.patch b/test/integration/rhel-7.8/new-function.patch deleted file mode 100644 index bcd6643..0000000 --- a/test/integration/rhel-7.8/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2020-03-10 10:35:54.135564709 -0400 -+++ src/drivers/tty/n_tty.c 2020-03-10 10:37:16.551389787 -0400 -@@ -2175,7 +2175,7 @@ do_it_again: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2264,6 +2264,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-7.8/new-globals.patch b/test/integration/rhel-7.8/new-globals.patch deleted file mode 100644 index 49e98e6..0000000 --- a/test/integration/rhel-7.8/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-03-10 10:35:54.567563836 -0400 -+++ src/fs/proc/cmdline.c 2020-03-10 10:37:21.219379377 -0400 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - module_init(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-10 10:35:54.568563834 -0400 -+++ src/fs/proc/meminfo.c 2020-03-10 10:37:21.220379374 -0400 -@@ -17,6 +17,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -54,6 +56,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/rhel-7.8/parainstructions-section.patch b/test/integration/rhel-7.8/parainstructions-section.patch deleted file mode 100644 index 5f801c4..0000000 --- a/test/integration/rhel-7.8/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2020-03-10 10:35:54.567563836 -0400 -+++ src/fs/proc/generic.c 2020-03-10 10:37:25.973368774 -0400 -@@ -194,6 +194,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/rhel-7.8/shadow-newpid-LOADED.test b/test/integration/rhel-7.8/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-7.8/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-7.8/shadow-newpid.patch b/test/integration/rhel-7.8/shadow-newpid.patch deleted file mode 100644 index e8a4d78..0000000 --- a/test/integration/rhel-7.8/shadow-newpid.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2020-03-10 10:35:54.566563838 -0400 -+++ src/fs/proc/array.c 2020-03-10 10:37:30.688358259 -0400 -@@ -395,13 +395,20 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" - "nonvoluntary_ctxt_switches:\t%lu\n", - p->nvcsw, - p->nivcsw); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2020-03-10 10:35:55.068562825 -0400 -+++ src/kernel/exit.c 2020-03-10 10:37:30.689358257 -0400 -@@ -791,6 +791,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void do_exit(long code) - { - struct task_struct *tsk = current; -@@ -888,6 +889,8 @@ void do_exit(long code) - check_stack_usage(); - exit_thread(); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-03-10 10:35:55.068562825 -0400 -+++ src/kernel/fork.c 2020-03-10 10:37:30.690358255 -0400 -@@ -1784,6 +1784,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -1821,6 +1822,13 @@ long do_fork(unsigned long clone_flags, - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; -+ int *newpid; -+ static int ctr = 0; -+ -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; - - trace_sched_process_fork(current, p); - diff --git a/test/integration/rhel-7.8/smp-locks-section.patch b/test/integration/rhel-7.8/smp-locks-section.patch deleted file mode 100644 index 6f9700d..0000000 --- a/test/integration/rhel-7.8/smp-locks-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2020-03-10 10:35:54.155564668 -0400 -+++ src/drivers/tty/tty_buffer.c 2020-03-10 10:37:35.446347648 -0400 -@@ -217,6 +217,10 @@ int tty_buffer_request_room(struct tty_p - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ -+ -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b != NULL) - left = b->size - b->used; diff --git a/test/integration/rhel-7.8/special-static.patch b/test/integration/rhel-7.8/special-static.patch deleted file mode 100644 index 02bd105..0000000 --- a/test/integration/rhel-7.8/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-03-10 10:35:55.068562825 -0400 -+++ src/kernel/fork.c 2020-03-10 10:37:40.182337086 -0400 -@@ -1153,10 +1153,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-7.8/symvers-disagreement-FAIL.patch b/test/integration/rhel-7.8/symvers-disagreement-FAIL.patch deleted file mode 100644 index 300f8b9..0000000 --- a/test/integration/rhel-7.8/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,49 +0,0 @@ -From da109d66a890373d0aa831f97b49aaffcc4eeb45 Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes a function referencing a function whose CRC has changed, - causing the symbol and the new CRC to be included in the __version - section of the final module. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index b9a71137208..4af27e069c2 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -31,6 +31,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index 8b1c4a5ee78..1b7997b58c0 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -693,6 +693,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-7.8/tracepoints-section.patch b/test/integration/rhel-7.8/tracepoints-section.patch deleted file mode 100644 index 20e9b79..0000000 --- a/test/integration/rhel-7.8/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/timer.c src/kernel/timer.c ---- src.orig/kernel/timer.c 2020-03-10 10:35:55.092562776 -0400 -+++ src/kernel/timer.c 2020-03-10 10:37:44.918325578 -0400 -@@ -1454,6 +1454,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = __this_cpu_read(tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/rhel-7.8/warn-detect-FAIL.patch b/test/integration/rhel-7.8/warn-detect-FAIL.patch deleted file mode 100644 index d2792db..0000000 --- a/test/integration/rhel-7.8/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2020-03-10 10:35:51.514570002 -0400 -+++ src/arch/x86/kvm/x86.c 2020-03-10 10:37:49.745313774 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-7.9/bug-table-section.patch b/test/integration/rhel-7.9/bug-table-section.patch deleted file mode 100644 index 92e66d4..0000000 --- a/test/integration/rhel-7.9/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-09-03 11:48:31.009727724 -0400 -@@ -331,6 +331,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-7.9/cmdline-string-LOADED.test b/test/integration/rhel-7.9/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-7.9/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-7.9/cmdline-string.patch b/test/integration/rhel-7.9/cmdline-string.patch deleted file mode 100644 index 719445d..0000000 --- a/test/integration/rhel-7.9/cmdline-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-09-03 11:48:30.496726119 -0400 -+++ src/fs/proc/cmdline.c 2020-09-03 11:48:33.073734181 -0400 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-7.9/data-new-LOADED.test b/test/integration/rhel-7.9/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/rhel-7.9/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-7.9/data-new.patch b/test/integration/rhel-7.9/data-new.patch deleted file mode 100644 index 2e4e824..0000000 --- a/test/integration/rhel-7.9/data-new.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/meminfo.c 2020-09-03 11:48:35.069740426 -0400 -@@ -21,6 +21,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -112,6 +114,7 @@ static int meminfo_proc_show(struct seq_ - "CmaTotal: %8lu kB\n" - "CmaFree: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -178,6 +181,7 @@ static int meminfo_proc_show(struct seq_ - , K(totalcma_pages) - , K(global_page_state(NR_FREE_CMA_PAGES)) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/rhel-7.9/data-read-mostly.patch.disabled b/test/integration/rhel-7.9/data-read-mostly.patch.disabled deleted file mode 100644 index 50f4c9b..0000000 --- a/test/integration/rhel-7.9/data-read-mostly.patch.disabled +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2020-09-03 11:48:30.763726955 -0400 -+++ src/net/core/dev.c 2020-09-03 11:49:21.514885728 -0400 -@@ -4327,6 +4327,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-7.9/fixup-section.patch b/test/integration/rhel-7.9/fixup-section.patch deleted file mode 100644 index 465e23a..0000000 --- a/test/integration/rhel-7.9/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2020-09-03 11:48:30.499726129 -0400 -+++ src/fs/readdir.c 2020-09-03 11:48:37.119746839 -0400 -@@ -176,6 +176,7 @@ static int filldir(void * __buf, const c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-7.9/gcc-constprop.patch b/test/integration/rhel-7.9/gcc-constprop.patch deleted file mode 100644 index 4ab8c1b..0000000 --- a/test/integration/rhel-7.9/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2020-09-03 11:48:30.726726839 -0400 -+++ src/kernel/time/timekeeping.c 2020-09-03 11:49:23.433891731 -0400 -@@ -852,6 +852,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-7.9/gcc-isra.patch b/test/integration/rhel-7.9/gcc-isra.patch deleted file mode 100644 index 6996eeb..0000000 --- a/test/integration/rhel-7.9/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-09-03 11:48:39.089753002 -0400 -@@ -46,6 +46,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-7.9/gcc-mangled-3.patch b/test/integration/rhel-7.9/gcc-mangled-3.patch deleted file mode 100644 index 5a7904e..0000000 --- a/test/integration/rhel-7.9/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2020-09-03 11:48:30.747726905 -0400 -+++ src/mm/slub.c 2020-09-03 11:48:41.106759312 -0400 -@@ -5716,6 +5716,9 @@ void get_slabinfo(struct kmem_cache *s, - unsigned long nr_free = 0; - int node; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_online_node(node) { - struct kmem_cache_node *n = get_node(s, node); - diff --git a/test/integration/rhel-7.9/gcc-static-local-var-2.patch b/test/integration/rhel-7.9/gcc-static-local-var-2.patch deleted file mode 100644 index a3e8366..0000000 --- a/test/integration/rhel-7.9/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2020-09-03 11:48:30.745726898 -0400 -+++ src/mm/mmap.c 2020-09-03 11:48:43.078765482 -0400 -@@ -1721,6 +1721,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-7.9/gcc-static-local-var-3.patch b/test/integration/rhel-7.9/gcc-static-local-var-3.patch deleted file mode 100644 index 6d8ae91..0000000 --- a/test/integration/rhel-7.9/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2020-09-03 11:48:30.725726836 -0400 -+++ src/kernel/sys.c 2020-09-03 11:48:45.101771811 -0400 -@@ -559,8 +559,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-7.9/gcc-static-local-var-4.patch b/test/integration/rhel-7.9/gcc-static-local-var-4.patch deleted file mode 100644 index d63af5b..0000000 --- a/test/integration/rhel-7.9/gcc-static-local-var-4.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-09-03 11:48:30.426725900 -0400 -+++ src/fs/aio.c 2020-09-03 11:48:47.163778261 -0400 -@@ -223,9 +223,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/rhel-7.9/gcc-static-local-var-4.test b/test/integration/rhel-7.9/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-7.9/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-7.9/gcc-static-local-var-5.patch b/test/integration/rhel-7.9/gcc-static-local-var-5.patch deleted file mode 100644 index 52d7f8b..0000000 --- a/test/integration/rhel-7.9/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2020-09-03 11:48:30.713726798 -0400 -+++ src/kernel/audit.c 2020-09-03 11:48:49.166784528 -0400 -@@ -205,6 +205,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -215,6 +221,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -234,6 +241,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -282,6 +294,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-7.9/gcc-static-local-var-6.patch b/test/integration/rhel-7.9/gcc-static-local-var-6.patch deleted file mode 100644 index 2b33da4..0000000 --- a/test/integration/rhel-7.9/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2020-09-03 11:48:30.779727005 -0400 -+++ src/net/ipv6/netfilter.c 2020-09-03 11:48:51.172790803 -0400 -@@ -112,6 +112,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -125,6 +127,9 @@ static int nf_ip6_route(struct net *net, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-7.9/macro-callbacks.patch b/test/integration/rhel-7.9/macro-callbacks.patch deleted file mode 100644 index 96c1a3f..0000000 --- a/test/integration/rhel-7.9/macro-callbacks.patch +++ /dev/null @@ -1,163 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2020-09-03 11:48:29.019721499 -0400 -+++ src/drivers/input/joydev.c 2020-09-03 11:48:53.152796998 -0400 -@@ -954,3 +954,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2020-09-03 11:48:29.025721517 -0400 -+++ src/drivers/input/misc/pcspkr.c 2020-09-03 11:48:53.152796998 -0400 -@@ -136,3 +136,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-09-03 11:48:30.426725900 -0400 -+++ src/fs/aio.c 2020-09-03 11:48:53.153797001 -0400 -@@ -42,6 +42,50 @@ - #include - #include - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-7.9/macro-printk.patch b/test/integration/rhel-7.9/macro-printk.patch deleted file mode 100644 index 28e618d..0000000 --- a/test/integration/rhel-7.9/macro-printk.patch +++ /dev/null @@ -1,148 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2020-09-03 11:48:30.771726980 -0400 -+++ src/net/ipv4/fib_frontend.c 2020-09-03 11:48:55.130803186 -0400 -@@ -690,6 +690,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -708,6 +709,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(net, tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2020-09-03 11:48:30.771726980 -0400 -+++ src/net/ipv4/fib_semantics.c 2020-09-03 11:48:55.130803186 -0400 -@@ -985,6 +985,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -1009,6 +1010,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1029,6 +1031,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (fi == NULL) -@@ -1044,6 +1047,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1059,8 +1064,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1111,6 +1118,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1128,6 +1136,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1150,6 +1159,7 @@ struct fib_info *fib_create_info(struct - goto failure; - } endfor_nexthops(fi) - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc) { - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || -@@ -1162,6 +1172,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1173,6 +1184,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1196,6 +1208,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1206,6 +1219,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2020-09-03 11:48:30.771726980 -0400 -+++ src/net/ipv4/fib_trie.c 2020-09-03 11:48:55.131803189 -0400 -@@ -1105,6 +1105,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) - { -@@ -1130,11 +1131,14 @@ int fib_table_insert(struct net *net, st - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-7.9/meminfo-init-FAIL.patch b/test/integration/rhel-7.9/meminfo-init-FAIL.patch deleted file mode 100644 index ad677ca..0000000 --- a/test/integration/rhel-7.9/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/meminfo.c 2020-09-03 11:48:59.106815625 -0400 -@@ -202,6 +202,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.9/meminfo-init2-FAIL.patch b/test/integration/rhel-7.9/meminfo-init2-FAIL.patch deleted file mode 100644 index 792028e..0000000 --- a/test/integration/rhel-7.9/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/meminfo.c 2020-09-03 11:48:57.163809546 -0400 -@@ -31,6 +31,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -202,6 +203,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/rhel-7.9/meminfo-string-LOADED.test b/test/integration/rhel-7.9/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-7.9/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-7.9/meminfo-string.patch b/test/integration/rhel-7.9/meminfo-string.patch deleted file mode 100644 index 7c8114e..0000000 --- a/test/integration/rhel-7.9/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/meminfo.c 2020-09-03 11:49:01.546823258 -0400 -@@ -100,7 +100,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - "Percpu: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" diff --git a/test/integration/rhel-7.9/module-call-external.patch b/test/integration/rhel-7.9/module-call-external.patch deleted file mode 100644 index e346edc..0000000 --- a/test/integration/rhel-7.9/module-call-external.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2020-09-03 11:48:30.477726060 -0400 -+++ src/fs/nfsd/export.c 2020-09-03 11:49:03.743830132 -0400 -@@ -1184,7 +1184,13 @@ static void exp_flags(struct seq_file *m - } - } - -+extern char *kpatch_string(void); -+ -+#ifdef CONFIG_PPC64 -+static int __attribute__((optimize("-fno-optimize-sibling-calls"))) e_show(struct seq_file *m, void *p) -+#else - static int e_show(struct seq_file *m, void *p) -+#endif - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); -@@ -1193,6 +1199,7 @@ static int e_show(struct seq_file *m, vo - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2020-09-03 11:48:30.802727077 -0400 -+++ src/net/netlink/af_netlink.c 2020-09-03 11:49:03.743830132 -0400 -@@ -2573,4 +2573,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-7.9/multiple.test b/test/integration/rhel-7.9/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-7.9/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-7.9/new-function.patch b/test/integration/rhel-7.9/new-function.patch deleted file mode 100644 index e83487a..0000000 --- a/test/integration/rhel-7.9/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2020-09-03 11:48:29.609723344 -0400 -+++ src/drivers/tty/n_tty.c 2020-09-03 11:49:05.751836414 -0400 -@@ -2175,7 +2175,7 @@ do_it_again: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2264,6 +2264,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-7.9/new-globals.patch b/test/integration/rhel-7.9/new-globals.patch deleted file mode 100644 index 4840c97..0000000 --- a/test/integration/rhel-7.9/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-09-03 11:48:30.496726119 -0400 -+++ src/fs/proc/cmdline.c 2020-09-03 11:49:07.740842636 -0400 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - module_init(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-09-03 11:48:30.497726123 -0400 -+++ src/fs/proc/meminfo.c 2020-09-03 11:49:07.740842636 -0400 -@@ -17,6 +17,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -54,6 +56,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/rhel-7.9/parainstructions-section.patch b/test/integration/rhel-7.9/parainstructions-section.patch deleted file mode 100644 index d7a02f9..0000000 --- a/test/integration/rhel-7.9/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2020-09-03 11:48:30.496726119 -0400 -+++ src/fs/proc/generic.c 2020-09-03 11:49:09.715848815 -0400 -@@ -194,6 +194,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/rhel-7.9/shadow-newpid-LOADED.test b/test/integration/rhel-7.9/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-7.9/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-7.9/shadow-newpid.patch b/test/integration/rhel-7.9/shadow-newpid.patch deleted file mode 100644 index 2c4ae45..0000000 --- a/test/integration/rhel-7.9/shadow-newpid.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2020-09-03 11:48:30.496726119 -0400 -+++ src/fs/proc/array.c 2020-09-03 11:49:11.696855012 -0400 -@@ -395,13 +395,20 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_printf(m, "voluntary_ctxt_switches:\t%lu\n" - "nonvoluntary_ctxt_switches:\t%lu\n", - p->nvcsw, - p->nivcsw); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2020-09-03 11:48:30.717726811 -0400 -+++ src/kernel/exit.c 2020-09-03 11:49:11.696855012 -0400 -@@ -791,6 +791,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void do_exit(long code) - { - struct task_struct *tsk = current; -@@ -888,6 +889,8 @@ void do_exit(long code) - check_stack_usage(); - exit_thread(); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-09-03 11:48:30.717726811 -0400 -+++ src/kernel/fork.c 2020-09-03 11:49:11.697855015 -0400 -@@ -1784,6 +1784,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -1821,6 +1822,13 @@ long do_fork(unsigned long clone_flags, - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; -+ int *newpid; -+ static int ctr = 0; -+ -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; - - trace_sched_process_fork(current, p); - diff --git a/test/integration/rhel-7.9/smp-locks-section.patch b/test/integration/rhel-7.9/smp-locks-section.patch deleted file mode 100644 index a044e41..0000000 --- a/test/integration/rhel-7.9/smp-locks-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2020-09-03 11:48:29.616723366 -0400 -+++ src/drivers/tty/tty_buffer.c 2020-09-03 11:49:13.626861050 -0400 -@@ -217,6 +217,10 @@ int tty_buffer_request_room(struct tty_p - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ -+ -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b != NULL) - left = b->size - b->used; diff --git a/test/integration/rhel-7.9/special-static.patch b/test/integration/rhel-7.9/special-static.patch deleted file mode 100644 index c098331..0000000 --- a/test/integration/rhel-7.9/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-09-03 11:48:30.717726811 -0400 -+++ src/kernel/fork.c 2020-09-03 11:49:15.602867232 -0400 -@@ -1153,10 +1153,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-7.9/symvers-disagreement-FAIL.patch b/test/integration/rhel-7.9/symvers-disagreement-FAIL.patch deleted file mode 100644 index 300f8b9..0000000 --- a/test/integration/rhel-7.9/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,49 +0,0 @@ -From da109d66a890373d0aa831f97b49aaffcc4eeb45 Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes a function referencing a function whose CRC has changed, - causing the symbol and the new CRC to be included in the __version - section of the final module. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index b9a71137208..4af27e069c2 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -31,6 +31,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index 8b1c4a5ee78..1b7997b58c0 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -693,6 +693,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-7.9/syscall-LOADED.test b/test/integration/rhel-7.9/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/rhel-7.9/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/rhel-7.9/syscall.patch b/test/integration/rhel-7.9/syscall.patch deleted file mode 100644 index 729340d..0000000 --- a/test/integration/rhel-7.9/syscall.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/kernel/sys.c b/kernel/sys.c -index 1fbf388279832..b5186aa83adfa 100644 ---- a/kernel/sys.c -+++ b/kernel/sys.c -@@ -1392,14 +1392,18 @@ static int override_release(char __user *release, size_t len) - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { -+ struct new_utsname tmp; - int errno = 0; - - down_read(&uts_sem); -- if (copy_to_user(name, utsname(), sizeof *name)) -- errno = -EFAULT; -+ memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); -+ if (copy_to_user(name, &tmp, sizeof(tmp))) -+ errno = -EFAULT; - - if (!errno && override_release(name->release, sizeof(name->release))) - errno = -EFAULT; diff --git a/test/integration/rhel-7.9/tracepoints-section.patch b/test/integration/rhel-7.9/tracepoints-section.patch deleted file mode 100644 index 33a15ed..0000000 --- a/test/integration/rhel-7.9/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/timer.c src/kernel/timer.c ---- src.orig/kernel/timer.c 2020-09-03 11:48:30.726726839 -0400 -+++ src/kernel/timer.c 2020-09-03 11:49:17.588873445 -0400 -@@ -1454,6 +1454,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = __this_cpu_read(tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/rhel-7.9/warn-detect-FAIL.patch b/test/integration/rhel-7.9/warn-detect-FAIL.patch deleted file mode 100644 index 2f51ba7..0000000 --- a/test/integration/rhel-7.9/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2020-09-03 11:48:30.386725775 -0400 -+++ src/arch/x86/kvm/x86.c 2020-09-03 11:49:19.587879699 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.0/README b/test/integration/rhel-8.0/README deleted file mode 100644 index d46fbcb..0000000 --- a/test/integration/rhel-8.0/README +++ /dev/null @@ -1 +0,0 @@ -4.18.0-80.el8 diff --git a/test/integration/rhel-8.0/bug-table-section.patch b/test/integration/rhel-8.0/bug-table-section.patch deleted file mode 100644 index 842ae4a..0000000 --- a/test/integration/rhel-8.0/bug-table-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c -index 89921a0..ac129b6 100644 ---- a/fs/proc/proc_sysctl.c -+++ b/fs/proc/proc_sysctl.c -@@ -333,6 +333,8 @@ static void start_unregistering(struct ctl_table_header *p) - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.0/cmdline-string-LOADED.test b/test/integration/rhel-8.0/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.0/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.0/cmdline-string.patch b/test/integration/rhel-8.0/cmdline-string.patch deleted file mode 100644 index 665c763..0000000 --- a/test/integration/rhel-8.0/cmdline-string.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c -index fa762c5..bd66027 100644 ---- a/fs/proc/cmdline.c -+++ b/fs/proc/cmdline.c -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.0/data-new-LOADED.test b/test/integration/rhel-8.0/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.0/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.0/data-new.patch b/test/integration/rhel-8.0/data-new.patch deleted file mode 100644 index 78d1b97..0000000 --- a/test/integration/rhel-8.0/data-new.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c -index 2fb0484..79ead86 100644 ---- a/fs/proc/meminfo.c -+++ b/fs/proc/meminfo.c -@@ -30,6 +30,8 @@ static void show_val_kb(struct seq_file *m, const char *s, unsigned long num) - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -141,6 +143,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.0/data-read-mostly.patch.disabled b/test/integration/rhel-8.0/data-read-mostly.patch.disabled deleted file mode 100644 index ed4eef0..0000000 --- a/test/integration/rhel-8.0/data-read-mostly.patch.disabled +++ /dev/null @@ -1,14 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/940 ---- -diff --git a/net/core/dev.c b/net/core/dev.c -index b6f9647..b376a48 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -4858,6 +4858,7 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.0/fixup-section.patch b/test/integration/rhel-8.0/fixup-section.patch deleted file mode 100644 index 78ab6dd..0000000 --- a/test/integration/rhel-8.0/fixup-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/readdir.c b/fs/readdir.c -index d97f548..58863b6 100644 ---- a/fs/readdir.c -+++ b/fs/readdir.c -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.0/gcc-constprop.patch.disabled b/test/integration/rhel-8.0/gcc-constprop.patch.disabled deleted file mode 100644 index 3fbc577..0000000 --- a/test/integration/rhel-8.0/gcc-constprop.patch.disabled +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c -index 4786df9..c73a687 100644 ---- a/kernel/time/timekeeping.c -+++ b/kernel/time/timekeeping.c -@@ -1211,6 +1211,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.0/gcc-isra.patch b/test/integration/rhel-8.0/gcc-isra.patch deleted file mode 100644 index 0903f24..0000000 --- a/test/integration/rhel-8.0/gcc-isra.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c -index 89921a0..199b1d7 100644 ---- a/fs/proc/proc_sysctl.c -+++ b/fs/proc/proc_sysctl.c -@@ -48,6 +48,7 @@ void proc_sys_poll_notify(struct ctl_table_poll *poll) - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.0/gcc-mangled-3.patch b/test/integration/rhel-8.0/gcc-mangled-3.patch deleted file mode 100644 index bcb5e62..0000000 --- a/test/integration/rhel-8.0/gcc-mangled-3.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/mm/slub.c b/mm/slub.c -index 51258ef..3cb5264 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -5852,6 +5852,9 @@ void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo) - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.0/gcc-static-local-var-2.patch b/test/integration/rhel-8.0/gcc-static-local-var-2.patch deleted file mode 100644 index a884bfa..0000000 --- a/test/integration/rhel-8.0/gcc-static-local-var-2.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/mm/mmap.c b/mm/mmap.c -index bf46096..4bc085c 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -1684,6 +1684,9 @@ unsigned long mmap_region(struct file *file, unsigned long addr, - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.0/gcc-static-local-var-3.patch b/test/integration/rhel-8.0/gcc-static-local-var-3.patch deleted file mode 100644 index da2acc0..0000000 --- a/test/integration/rhel-8.0/gcc-static-local-var-3.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/kernel/reboot.c b/kernel/reboot.c -index e4ced88..0c0b5a2 100644 ---- a/kernel/reboot.c -+++ b/kernel/reboot.c -@@ -393,8 +393,15 @@ void kernel_power_off(void) - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.0/gcc-static-local-var-4.patch.disabled b/test/integration/rhel-8.0/gcc-static-local-var-4.patch.disabled deleted file mode 100644 index 17e269d..0000000 --- a/test/integration/rhel-8.0/gcc-static-local-var-4.patch.disabled +++ /dev/null @@ -1,25 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/940 ---- -diff --git a/fs/aio.c b/fs/aio.c -index e1f8f01..4dfb05c 100644 ---- a/fs/aio.c -+++ b/fs/aio.c -@@ -263,11 +263,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.0/gcc-static-local-var-4.test.disabled b/test/integration/rhel-8.0/gcc-static-local-var-4.test.disabled deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.0/gcc-static-local-var-4.test.disabled +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.0/gcc-static-local-var-5.patch b/test/integration/rhel-8.0/gcc-static-local-var-5.patch deleted file mode 100644 index 0e3e2d3..0000000 --- a/test/integration/rhel-8.0/gcc-static-local-var-5.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/kernel/audit.c b/kernel/audit.c -index e7478cb..ed2546a 100644 ---- a/kernel/audit.c -+++ b/kernel/audit.c -@@ -325,6 +325,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -335,6 +341,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -354,6 +361,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -400,6 +412,8 @@ static int audit_log_config_change(char *function_name, u32 new, u32 old, - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.0/gcc-static-local-var-6.patch b/test/integration/rhel-8.0/gcc-static-local-var-6.patch deleted file mode 100644 index 91c72b6..0000000 --- a/test/integration/rhel-8.0/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c -index 531d695..a536c74 100644 ---- a/net/ipv6/netfilter.c -+++ b/net/ipv6/netfilter.c -@@ -84,6 +84,8 @@ static int nf_ip6_reroute(struct sk_buff *skb, - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -97,6 +99,9 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.0/macro-callbacks.patch b/test/integration/rhel-8.0/macro-callbacks.patch deleted file mode 100644 index b7f0077..0000000 --- a/test/integration/rhel-8.0/macro-callbacks.patch +++ /dev/null @@ -1,158 +0,0 @@ -diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c -index 4c1e427..7e46aaf 100644 ---- a/drivers/input/joydev.c -+++ b/drivers/input/joydev.c -@@ -1068,3 +1068,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c -index 56ddba2..d188b12 100644 ---- a/drivers/input/misc/pcspkr.c -+++ b/drivers/input/misc/pcspkr.c -@@ -138,3 +138,46 @@ static void pcspkr_shutdown(struct platform_device *dev) - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff --git a/fs/aio.c b/fs/aio.c -index e1f8f01..5efe496 100644 ---- a/fs/aio.c -+++ b/fs/aio.c -@@ -49,6 +49,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.0/macro-printk.patch.disabled b/test/integration/rhel-8.0/macro-printk.patch.disabled deleted file mode 100644 index dfe0586..0000000 --- a/test/integration/rhel-8.0/macro-printk.patch.disabled +++ /dev/null @@ -1,151 +0,0 @@ -diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c -index 0113993..0ea4967 100644 ---- a/net/ipv4/fib_frontend.c -+++ b/net/ipv4/fib_frontend.c -@@ -767,6 +767,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -788,6 +789,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c -index 446204c..5b73a01 100644 ---- a/net/ipv4/fib_semantics.c -+++ b/net/ipv4/fib_semantics.c -@@ -1025,6 +1025,7 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) - fi->fib_metrics->metrics); - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1058,6 +1059,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1078,6 +1080,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1093,6 +1096,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1109,8 +1114,10 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1172,6 +1179,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1193,6 +1201,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1231,6 +1240,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1240,6 +1250,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1251,6 +1262,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1274,6 +1286,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1284,6 +1297,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg, - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c -index 5bc0c89..d57b327 100644 ---- a/net/ipv4/fib_trie.c -+++ b/net/ipv4/fib_trie.c -@@ -1121,6 +1121,7 @@ static bool fib_valid_key_len(u32 key, u8 plen, struct netlink_ext_ack *extack) - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1143,11 +1144,14 @@ int fib_table_insert(struct net *net, struct fib_table *tb, - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.0/meminfo-init-FAIL.patch b/test/integration/rhel-8.0/meminfo-init-FAIL.patch deleted file mode 100644 index a3361ed..0000000 --- a/test/integration/rhel-8.0/meminfo-init-FAIL.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c -index 2fb0484..b981fab 100644 ---- a/fs/proc/meminfo.c -+++ b/fs/proc/meminfo.c -@@ -151,6 +151,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.0/meminfo-init2-FAIL.patch b/test/integration/rhel-8.0/meminfo-init2-FAIL.patch deleted file mode 100644 index 28f8445..0000000 --- a/test/integration/rhel-8.0/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c -index 2fb0484..eb61884 100644 ---- a/fs/proc/meminfo.c -+++ b/fs/proc/meminfo.c -@@ -39,6 +39,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -151,6 +152,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.0/meminfo-string-LOADED.test b/test/integration/rhel-8.0/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.0/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.0/meminfo-string.patch b/test/integration/rhel-8.0/meminfo-string.patch deleted file mode 100644 index e20210f..0000000 --- a/test/integration/rhel-8.0/meminfo-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c -index 2fb0484..804bc35 100644 ---- a/fs/proc/meminfo.c -+++ b/fs/proc/meminfo.c -@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - - #ifdef CONFIG_MEMORY_FAILURE - seq_printf(m, "HardwareCorrupted: %5lu kB\n", diff --git a/test/integration/rhel-8.0/module-call-external.patch b/test/integration/rhel-8.0/module-call-external.patch deleted file mode 100644 index 44e546f..0000000 --- a/test/integration/rhel-8.0/module-call-external.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c -index a1143f7..950403a 100644 ---- a/fs/nfsd/export.c -+++ b/fs/nfsd/export.c -@@ -1196,6 +1196,8 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, - } - } - -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1205,6 +1207,7 @@ static int e_show(struct seq_file *m, void *p) - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index 56704d9..851d41d 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -2779,4 +2779,9 @@ static int __init netlink_proto_init(void) - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-8.0/multiple.test b/test/integration/rhel-8.0/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.0/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.0/new-function.patch b/test/integration/rhel-8.0/new-function.patch deleted file mode 100644 index f1f21a7..0000000 --- a/test/integration/rhel-8.0/new-function.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c -index 3ad4602..f3cda7e 100644 ---- a/drivers/tty/n_tty.c -+++ b/drivers/tty/n_tty.c -@@ -2296,7 +2296,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2383,6 +2383,12 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.0/new-globals.patch b/test/integration/rhel-8.0/new-globals.patch deleted file mode 100644 index 38892a4..0000000 --- a/test/integration/rhel-8.0/new-globals.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c -index fa762c5..cc67970 100644 ---- a/fs/proc/cmdline.c -+++ b/fs/proc/cmdline.c -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void) - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c -index 2fb0484..7dd8350 100644 ---- a/fs/proc/meminfo.c -+++ b/fs/proc/meminfo.c -@@ -20,6 +20,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -53,6 +55,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v) - - available = si_mem_available(); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.0/parainstructions-section.patch b/test/integration/rhel-8.0/parainstructions-section.patch deleted file mode 100644 index d3af7a6..0000000 --- a/test/integration/rhel-8.0/parainstructions-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/proc/generic.c b/fs/proc/generic.c -index bb1c162..2b3f7ec 100644 ---- a/fs/proc/generic.c -+++ b/fs/proc/generic.c -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.0/shadow-newpid-LOADED.test b/test/integration/rhel-8.0/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.0/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.0/shadow-newpid.patch.disabled b/test/integration/rhel-8.0/shadow-newpid.patch.disabled deleted file mode 100644 index 19109a3..0000000 --- a/test/integration/rhel-8.0/shadow-newpid.patch.disabled +++ /dev/null @@ -1,80 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/940 ---- -diff --git a/fs/proc/array.c b/fs/proc/array.c -index 0ceb3b6..1b44c7f 100644 ---- a/fs/proc/array.c -+++ b/fs/proc/array.c -@@ -370,12 +370,19 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff --git a/kernel/exit.c b/kernel/exit.c -index deaa53a..01f5776 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -760,6 +760,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -865,6 +866,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff --git a/kernel/fork.c b/kernel/fork.c -index 3311231..2c12c1a 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -2093,6 +2093,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2105,6 +2106,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2131,6 +2134,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.0/smp-locks-section.patch b/test/integration/rhel-8.0/smp-locks-section.patch deleted file mode 100644 index 5166614..0000000 --- a/test/integration/rhel-8.0/smp-locks-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c -index ae3ce33..37727fe 100644 ---- a/drivers/tty/tty_buffer.c -+++ b/drivers/tty/tty_buffer.c -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.0/special-static.patch b/test/integration/rhel-8.0/special-static.patch deleted file mode 100644 index 22502df..0000000 --- a/test/integration/rhel-8.0/special-static.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/kernel/fork.c b/kernel/fork.c -index 3311231..f6e66b7 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -1461,10 +1461,18 @@ static void posix_cpu_timers_init_group(struct signal_struct *sig) - static inline void posix_cpu_timers_init_group(struct signal_struct *sig) { } - #endif - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.0/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.0/symvers-disagreement-FAIL.patch deleted file mode 100644 index e3a672a..0000000 --- a/test/integration/rhel-8.0/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 7085a655b8d665b6314e8dab2f803bac0aea04ec Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index df3e1a44707a..15c9d6e2e1e0 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -29,6 +29,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index 623be3174fb3..4ddd74ae0bb9 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -685,6 +685,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-8.0/tracepoints-section.patch b/test/integration/rhel-8.0/tracepoints-section.patch deleted file mode 100644 index 0dfea0c..0000000 --- a/test/integration/rhel-8.0/tracepoints-section.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/kernel/time/timer.c b/kernel/time/timer.c -index 786f8c0..1105697 100644 ---- a/kernel/time/timer.c -+++ b/kernel/time/timer.c -@@ -1692,6 +1692,9 @@ static __latent_entropy void run_timer_softirq(struct softirq_action *h) - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.0/warn-detect-FAIL.patch b/test/integration/rhel-8.0/warn-detect-FAIL.patch deleted file mode 100644 index f57bd0e..0000000 --- a/test/integration/rhel-8.0/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c -index 4fa858b..ef1a710 100644 ---- a/arch/x86/kvm/x86.c -+++ b/arch/x86/kvm/x86.c -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.1/bug-table-section.patch b/test/integration/rhel-8.1/bug-table-section.patch deleted file mode 100644 index b37f545..0000000 --- a/test/integration/rhel-8.1/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src/fs/proc/proc_sysctl.c 2020-03-11 11:23:26.886602663 +0000 -+++ src/fs/proc/proc_sysctl.c 2020-03-11 11:23:39.822895153 +0000 -@@ -333,6 +333,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.1/cmdline-string-LOADED.test b/test/integration/rhel-8.1/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.1/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.1/cmdline-string.patch b/test/integration/rhel-8.1/cmdline-string.patch deleted file mode 100644 index 2ba1762..0000000 --- a/test/integration/rhel-8.1/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src/fs/proc/cmdline.c 2020-03-11 11:23:26.878602482 +0000 -+++ src/fs/proc/cmdline.c 2020-03-11 11:24:37.984218859 +0000 -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.1/data-new-LOADED.test b/test/integration/rhel-8.1/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.1/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.1/data-new.patch b/test/integration/rhel-8.1/data-new.patch deleted file mode 100644 index a33a233..0000000 --- a/test/integration/rhel-8.1/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src/fs/proc/meminfo.c 2020-03-11 11:23:26.882602572 +0000 -+++ src/fs/proc/meminfo.c 2020-03-11 11:25:35.401538436 +0000 -@@ -30,6 +30,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -141,6 +143,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.1/data-read-mostly.patch.disabled b/test/integration/rhel-8.1/data-read-mostly.patch.disabled deleted file mode 100644 index 3569b7d..0000000 --- a/test/integration/rhel-8.1/data-read-mostly.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -Disabled due to https:/github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src/net/core/dev.c src/net/core/dev.c ---- src/net/core/dev.c 2020-03-11 11:23:32.550730639 +0000 -+++ src/net/core/dev.c 2020-03-11 11:43:53.348022834 +0000 -@@ -4893,6 +4893,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.1/fixup-section.patch b/test/integration/rhel-8.1/fixup-section.patch deleted file mode 100644 index 7446a29..0000000 --- a/test/integration/rhel-8.1/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src/fs/readdir.c src/fs/readdir.c ---- src/fs/readdir.c 2020-03-11 11:23:24.210542249 +0000 -+++ src/fs/readdir.c 2020-03-11 11:26:32.322857837 +0000 -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.1/gcc-constprop.patch.disabled b/test/integration/rhel-8.1/gcc-constprop.patch.disabled deleted file mode 100644 index 1c8ca71..0000000 --- a/test/integration/rhel-8.1/gcc-constprop.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src/kernel/time/timekeeping.c 2020-03-11 11:23:30.538685163 +0000 -+++ src/kernel/time/timekeeping.c 2020-03-11 11:44:47.885367244 +0000 -@@ -1221,6 +1221,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.1/gcc-isra.patch b/test/integration/rhel-8.1/gcc-isra.patch deleted file mode 100644 index 3ae952f..0000000 --- a/test/integration/rhel-8.1/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src/fs/proc/proc_sysctl.c 2020-03-11 11:23:26.886602663 +0000 -+++ src/fs/proc/proc_sysctl.c 2020-03-11 11:27:30.392214139 +0000 -@@ -48,6 +48,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.1/gcc-mangled-3.patch b/test/integration/rhel-8.1/gcc-mangled-3.patch deleted file mode 100644 index 65e757a..0000000 --- a/test/integration/rhel-8.1/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src/mm/slub.c src/mm/slub.c ---- src/mm/slub.c 2020-03-11 11:23:32.406727384 +0000 -+++ src/mm/slub.c 2020-03-11 11:28:27.973568215 +0000 -@@ -5836,6 +5836,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.1/gcc-static-local-var-2.patch b/test/integration/rhel-8.1/gcc-static-local-var-2.patch deleted file mode 100644 index a17a1be..0000000 --- a/test/integration/rhel-8.1/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src/mm/mmap.c src/mm/mmap.c ---- src/mm/mmap.c 2020-03-11 11:23:32.386726932 +0000 -+++ src/mm/mmap.c 2020-03-11 11:29:26.610955502 +0000 -@@ -1685,6 +1685,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.1/gcc-static-local-var-3.patch b/test/integration/rhel-8.1/gcc-static-local-var-3.patch deleted file mode 100644 index 81a0b32..0000000 --- a/test/integration/rhel-8.1/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src/kernel/reboot.c src/kernel/reboot.c ---- src/kernel/reboot.c 2020-03-11 11:23:30.502684349 +0000 -+++ src/kernel/reboot.c 2020-03-11 11:30:24.412330397 +0000 -@@ -393,8 +393,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.1/gcc-static-local-var-4.patch.disabled b/test/integration/rhel-8.1/gcc-static-local-var-4.patch.disabled deleted file mode 100644 index 63481a7..0000000 --- a/test/integration/rhel-8.1/gcc-static-local-var-4.patch.disabled +++ /dev/null @@ -1,24 +0,0 @@ -Disabled due to https:/github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src/fs/aio.c src/fs/aio.c ---- src/fs/aio.c 2020-03-11 11:23:24.150540895 +0000 -+++ src/fs/aio.c 2020-03-11 11:45:44.710769201 +0000 -@@ -251,11 +251,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.1/gcc-static-local-var-4.test.disabled b/test/integration/rhel-8.1/gcc-static-local-var-4.test.disabled deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.1/gcc-static-local-var-4.test.disabled +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.1/gcc-static-local-var-5.patch b/test/integration/rhel-8.1/gcc-static-local-var-5.patch deleted file mode 100644 index 3f639ac..0000000 --- a/test/integration/rhel-8.1/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src/kernel/audit.c src/kernel/audit.c ---- src/kernel/audit.c 2020-03-11 11:23:30.394681909 +0000 -+++ src/kernel/audit.c 2020-03-11 11:46:41.484170922 +0000 -@@ -325,6 +325,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -335,6 +341,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -354,6 +361,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -400,6 +412,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.1/gcc-static-local-var-6.patch b/test/integration/rhel-8.1/gcc-static-local-var-6.patch deleted file mode 100644 index b970dd8..0000000 --- a/test/integration/rhel-8.1/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src/net/ipv6/netfilter.c 2020-03-11 11:23:32.702734076 +0000 -+++ src/net/ipv6/netfilter.c 2020-03-11 11:31:22.397716246 +0000 -@@ -87,6 +87,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -100,6 +102,9 @@ static int nf_ip6_route(struct net *net, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.1/macro-callbacks.patch b/test/integration/rhel-8.1/macro-callbacks.patch deleted file mode 100644 index fd29ecf..0000000 --- a/test/integration/rhel-8.1/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src/drivers/input/joydev.c src/drivers/input/joydev.c ---- src/drivers/input/joydev.c 2020-03-11 11:23:07.890174500 +0000 -+++ src/drivers/input/joydev.c 2020-03-11 11:32:20.859119425 +0000 -@@ -1068,3 +1068,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src/drivers/input/misc/pcspkr.c 2020-03-11 11:23:07.962176120 +0000 -+++ src/drivers/input/misc/pcspkr.c 2020-03-11 11:32:20.859119425 +0000 -@@ -138,3 +138,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src/fs/aio.c src/fs/aio.c ---- src/fs/aio.c 2020-03-11 11:23:24.150540895 +0000 -+++ src/fs/aio.c 2020-03-11 11:32:20.859119425 +0000 -@@ -49,6 +49,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.1/macro-printk.patch.disabled b/test/integration/rhel-8.1/macro-printk.patch.disabled deleted file mode 100644 index 02926af..0000000 --- a/test/integration/rhel-8.1/macro-printk.patch.disabled +++ /dev/null @@ -1,148 +0,0 @@ -diff -Nupr src/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src/net/ipv4/fib_frontend.c 2020-03-11 11:23:32.622732267 +0000 -+++ src/net/ipv4/fib_frontend.c 2020-03-11 11:47:37.897564680 +0000 -@@ -777,6 +777,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -798,6 +799,7 @@ static int inet_rtm_newroute(struct sk_b - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src/net/ipv4/fib_semantics.c 2020-03-11 11:23:32.626732358 +0000 -+++ src/net/ipv4/fib_semantics.c 2020-03-11 11:47:37.897564680 +0000 -@@ -1025,6 +1025,7 @@ fib_convert_metrics(struct fib_info *fi, - fi->fib_metrics->metrics); - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1058,6 +1059,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1078,6 +1080,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1093,6 +1096,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1109,8 +1114,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1172,6 +1179,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1193,6 +1201,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1231,6 +1240,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1240,6 +1250,7 @@ struct fib_info *fib_create_info(struct - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1251,6 +1262,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1274,6 +1286,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1284,6 +1297,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src/net/ipv4/fib_trie.c 2020-03-11 11:23:32.626732358 +0000 -+++ src/net/ipv4/fib_trie.c 2020-03-11 11:47:37.897564680 +0000 -@@ -1121,6 +1121,7 @@ static bool fib_valid_key_len(u32 key, u - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1143,11 +1144,14 @@ int fib_table_insert(struct net *net, st - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.1/meminfo-init-FAIL.patch b/test/integration/rhel-8.1/meminfo-init-FAIL.patch deleted file mode 100644 index 2334a0e..0000000 --- a/test/integration/rhel-8.1/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src/fs/proc/meminfo.c 2020-03-11 11:23:26.882602572 +0000 -+++ src/fs/proc/meminfo.c 2020-03-11 11:34:17.189926874 +0000 -@@ -151,6 +151,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.1/meminfo-init2-FAIL.patch b/test/integration/rhel-8.1/meminfo-init2-FAIL.patch deleted file mode 100644 index 937667b..0000000 --- a/test/integration/rhel-8.1/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src/fs/proc/meminfo.c 2020-03-11 11:23:26.882602572 +0000 -+++ src/fs/proc/meminfo.c 2020-03-11 11:33:19.732537882 +0000 -@@ -40,6 +40,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long sreclaimable, sunreclaim; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -151,6 +152,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.1/meminfo-string-LOADED.test b/test/integration/rhel-8.1/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.1/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.1/meminfo-string.patch b/test/integration/rhel-8.1/meminfo-string.patch deleted file mode 100644 index e3e7509..0000000 --- a/test/integration/rhel-8.1/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src/fs/proc/meminfo.c 2020-03-11 11:23:26.882602572 +0000 -+++ src/fs/proc/meminfo.c 2020-03-11 11:35:15.879349884 +0000 -@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - - #ifdef CONFIG_MEMORY_FAILURE - seq_printf(m, "HardwareCorrupted: %5lu kB\n", diff --git a/test/integration/rhel-8.1/module-LOADED.test b/test/integration/rhel-8.1/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-8.1/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-8.1/module.patch b/test/integration/rhel-8.1/module.patch deleted file mode 100644 index 8bfb621..0000000 --- a/test/integration/rhel-8.1/module.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 08078d00ab1749a6f84148a00d8d26572af4ec97 Mon Sep 17 00:00:00 2001 -Message-Id: <08078d00ab1749a6f84148a00d8d26572af4ec97.1586900628.git.jpoimboe@redhat.com> -From: Josh Poimboeuf -Date: Tue, 14 Apr 2020 15:17:51 -0500 -Subject: [PATCH] kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf ---- - fs/nfsd/export.c | 30 ++++++++++++++++++++++++++++++ - net/netlink/af_netlink.c | 5 +++++ - 2 files changed, 35 insertions(+) - -diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c -index a1143f7c2201..253c15ad82b2 100644 ---- a/fs/nfsd/export.c -+++ b/fs/nfsd/export.c -@@ -1196,15 +1196,45 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, - } - } - -+#include -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); - struct cache_detail *cd = m->private; -+#ifdef CONFIG_X86_64 -+ unsigned long long sched_clock; -+ -+ alternative("ud2", "call yield", X86_FEATURE_ALWAYS); -+ alternative("call yield", "ud2", X86_FEATURE_IA64); -+ -+ sched_clock = paravirt_sched_clock(); -+ if (!jiffies) -+ printk("kpatch: sched_clock: %llu\n", sched_clock); -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&mcsafe_key)) -+ printk("kpatch: mcsafe_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif - - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c -index 44fa4ea5df76..dc36ec2901b8 100644 ---- a/net/netlink/af_netlink.c -+++ b/net/netlink/af_netlink.c -@@ -2809,4 +2809,9 @@ static int __init netlink_proto_init(void) - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); --- -2.21.1 - diff --git a/test/integration/rhel-8.1/multiple.test b/test/integration/rhel-8.1/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.1/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.1/new-function.patch b/test/integration/rhel-8.1/new-function.patch deleted file mode 100644 index 3e446df..0000000 --- a/test/integration/rhel-8.1/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src/drivers/tty/n_tty.c 2020-03-11 11:23:23.062516341 +0000 -+++ src/drivers/tty/n_tty.c 2020-03-11 11:37:13.226206161 +0000 -@@ -2296,7 +2296,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2383,6 +2383,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.1/new-globals.patch b/test/integration/rhel-8.1/new-globals.patch deleted file mode 100644 index 07aafec..0000000 --- a/test/integration/rhel-8.1/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src/fs/proc/cmdline.c 2020-03-11 11:23:26.878602482 +0000 -+++ src/fs/proc/cmdline.c 2020-03-11 11:38:10.295599825 +0000 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src/fs/proc/meminfo.c 2020-03-11 11:23:26.882602572 +0000 -+++ src/fs/proc/meminfo.c 2020-03-11 11:38:10.295599825 +0000 -@@ -20,6 +20,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -56,6 +58,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE); - sunreclaim = global_node_page_state(NR_SLAB_UNRECLAIMABLE); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.1/parainstructions-section.patch b/test/integration/rhel-8.1/parainstructions-section.patch deleted file mode 100644 index 1183f45..0000000 --- a/test/integration/rhel-8.1/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src/fs/proc/generic.c src/fs/proc/generic.c ---- src/fs/proc/generic.c 2020-03-11 11:23:26.878602482 +0000 -+++ src/fs/proc/generic.c 2020-03-11 11:39:07.677003695 +0000 -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.1/shadow-newpid-LOADED.test.disabled b/test/integration/rhel-8.1/shadow-newpid-LOADED.test.disabled deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.1/shadow-newpid-LOADED.test.disabled +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.1/shadow-newpid.patch.disabled b/test/integration/rhel-8.1/shadow-newpid.patch.disabled deleted file mode 100644 index f571dc4..0000000 --- a/test/integration/rhel-8.1/shadow-newpid.patch.disabled +++ /dev/null @@ -1,77 +0,0 @@ -Disabled due to https:/github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src/fs/proc/array.c src/fs/proc/array.c ---- src/fs/proc/array.c 2020-03-11 11:23:26.874602392 +0000 -+++ src/fs/proc/array.c 2020-03-11 11:48:34.514964309 +0000 -@@ -370,12 +370,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src/kernel/exit.c src/kernel/exit.c ---- src/kernel/exit.c 2020-03-11 11:23:30.434682812 +0000 -+++ src/kernel/exit.c 2020-03-11 11:48:34.514964309 +0000 -@@ -762,6 +762,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -868,6 +869,8 @@ void __noreturn do_exit(long code) - exit_thread(tsk); - exit_umh(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src/kernel/fork.c src/kernel/fork.c ---- src/kernel/fork.c 2020-03-11 11:23:30.438682903 +0000 -+++ src/kernel/fork.c 2020-03-11 11:48:34.514964309 +0000 -@@ -2210,6 +2210,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2222,6 +2223,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2248,6 +2251,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.1/smp-locks-section.patch b/test/integration/rhel-8.1/smp-locks-section.patch deleted file mode 100644 index f0794a1..0000000 --- a/test/integration/rhel-8.1/smp-locks-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src/drivers/tty/tty_buffer.c 2020-03-11 11:23:23.138518056 +0000 -+++ src/drivers/tty/tty_buffer.c 2020-03-11 11:40:04.174388205 +0000 -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.1/special-static.patch.disabled b/test/integration/rhel-8.1/special-static.patch.disabled deleted file mode 100644 index 992f8b9..0000000 --- a/test/integration/rhel-8.1/special-static.patch.disabled +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src/kernel/fork.c src/kernel/fork.c ---- src/kernel/fork.c 2020-03-11 11:23:30.438682903 +0000 -+++ src/kernel/fork.c 2020-03-11 11:41:01.567796732 +0000 -@@ -1524,10 +1524,18 @@ static void posix_cpu_timers_init_group( - static inline void posix_cpu_timers_init_group(struct signal_struct *sig) { } - #endif - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.1/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.1/symvers-disagreement-FAIL.patch deleted file mode 100644 index 9527641..0000000 --- a/test/integration/rhel-8.1/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,51 +0,0 @@ -From c63702554e54b992793fe3598ea8c8c415bef908 Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index 2ab316d85651..2ef19920f6ab 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -29,6 +29,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index 0a2b261a27c9..51a1868c9cea 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -685,6 +685,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-8.1/tracepoints-section.patch b/test/integration/rhel-8.1/tracepoints-section.patch deleted file mode 100644 index ab5e316..0000000 --- a/test/integration/rhel-8.1/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src/kernel/time/timer.c src/kernel/time/timer.c ---- src/kernel/time/timer.c 2020-03-11 11:23:30.542685253 +0000 -+++ src/kernel/time/timer.c 2020-03-11 11:41:58.129186658 +0000 -@@ -1692,6 +1692,9 @@ static __latent_entropy void run_timer_s - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.1/warn-detect-FAIL.patch b/test/integration/rhel-8.1/warn-detect-FAIL.patch deleted file mode 100644 index a00fe05..0000000 --- a/test/integration/rhel-8.1/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src/arch/x86/kvm/x86.c 2020-03-11 11:22:57.389938541 +0000 -+++ src/arch/x86/kvm/x86.c 2020-03-11 11:42:55.798605475 +0000 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.2/bug-table-section.patch b/test/integration/rhel-8.2/bug-table-section.patch deleted file mode 100644 index 5bc1e11..0000000 --- a/test/integration/rhel-8.2/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-05-12 11:14:36.220489794 -0400 -@@ -338,6 +338,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.2/cmdline-string-LOADED.test b/test/integration/rhel-8.2/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.2/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.2/cmdline-string.patch b/test/integration/rhel-8.2/cmdline-string.patch deleted file mode 100644 index 4838935..0000000 --- a/test/integration/rhel-8.2/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/cmdline.c 2020-05-12 11:14:40.110321212 -0400 -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.2/data-new-LOADED.test b/test/integration/rhel-8.2/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.2/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.2/data-new.patch b/test/integration/rhel-8.2/data-new.patch deleted file mode 100644 index 6978e52..0000000 --- a/test/integration/rhel-8.2/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/meminfo.c 2020-05-12 11:14:43.210186867 -0400 -@@ -31,6 +31,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -143,6 +145,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.2/data-read-mostly.patch.disabled b/test/integration/rhel-8.2/data-read-mostly.patch.disabled deleted file mode 100644 index 5b1c87a..0000000 --- a/test/integration/rhel-8.2/data-read-mostly.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -Disabled due to https:/github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2020-05-12 11:14:29.800768017 -0400 -+++ src/net/core/dev.c 2020-05-12 11:15:38.827776462 -0400 -@@ -4893,6 +4893,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.2/fixup-section.patch b/test/integration/rhel-8.2/fixup-section.patch deleted file mode 100644 index 6632001..0000000 --- a/test/integration/rhel-8.2/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2020-05-12 11:14:29.170795319 -0400 -+++ src/fs/readdir.c 2020-05-12 11:14:46.280053823 -0400 -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.2/gcc-constprop.patch b/test/integration/rhel-8.2/gcc-constprop.patch deleted file mode 100644 index 1a17df4..0000000 --- a/test/integration/rhel-8.2/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2020-05-12 11:14:29.670773651 -0400 -+++ src/kernel/time/timekeeping.c 2020-05-12 11:15:41.897643417 -0400 -@@ -1221,6 +1221,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.2/gcc-isra.patch b/test/integration/rhel-8.2/gcc-isra.patch deleted file mode 100644 index 073b60f..0000000 --- a/test/integration/rhel-8.2/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-05-12 11:14:49.359920345 -0400 -@@ -53,6 +53,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.2/gcc-mangled-3.patch b/test/integration/rhel-8.2/gcc-mangled-3.patch deleted file mode 100644 index 8d096e4..0000000 --- a/test/integration/rhel-8.2/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2020-05-12 11:14:32.110667908 -0400 -+++ src/mm/slub.c 2020-05-12 11:14:52.439786867 -0400 -@@ -5852,6 +5852,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.2/gcc-static-local-var-2.patch b/test/integration/rhel-8.2/gcc-static-local-var-2.patch deleted file mode 100644 index a735a1f..0000000 --- a/test/integration/rhel-8.2/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2020-05-12 11:14:32.110667908 -0400 -+++ src/mm/mmap.c 2020-05-12 11:14:55.529652955 -0400 -@@ -1679,6 +1679,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.2/gcc-static-local-var-3.patch b/test/integration/rhel-8.2/gcc-static-local-var-3.patch deleted file mode 100644 index 2b7af0f..0000000 --- a/test/integration/rhel-8.2/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c ---- src.orig/kernel/reboot.c 2020-05-12 11:14:29.670773651 -0400 -+++ src/kernel/reboot.c 2020-05-12 11:14:58.579520777 -0400 -@@ -393,8 +393,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.2/gcc-static-local-var-4.patch.disabled b/test/integration/rhel-8.2/gcc-static-local-var-4.patch.disabled deleted file mode 100644 index 783f598..0000000 --- a/test/integration/rhel-8.2/gcc-static-local-var-4.patch.disabled +++ /dev/null @@ -1,24 +0,0 @@ -Disabled due to https:/github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-05-12 11:14:29.130797053 -0400 -+++ src/fs/aio.c 2020-05-12 11:15:44.967510372 -0400 -@@ -251,11 +251,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.2/gcc-static-local-var-4.test.disabled b/test/integration/rhel-8.2/gcc-static-local-var-4.test.disabled deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.2/gcc-static-local-var-4.test.disabled +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.2/gcc-static-local-var-5.patch b/test/integration/rhel-8.2/gcc-static-local-var-5.patch deleted file mode 100644 index b6f492b..0000000 --- a/test/integration/rhel-8.2/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2020-05-12 11:24:26.314915742 -0400 -+++ src/kernel/audit.c 2020-05-12 11:24:37.024451603 -0400 -@@ -321,6 +321,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -331,6 +337,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -350,6 +357,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -396,6 +408,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.2/gcc-static-local-var-6.patch b/test/integration/rhel-8.2/gcc-static-local-var-6.patch deleted file mode 100644 index 378433e..0000000 --- a/test/integration/rhel-8.2/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2020-05-12 11:14:29.820767150 -0400 -+++ src/net/ipv6/netfilter.c 2020-05-12 11:15:01.659387299 -0400 -@@ -87,6 +87,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -100,6 +102,9 @@ static int nf_ip6_route(struct net *net, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.2/macro-callbacks.patch b/test/integration/rhel-8.2/macro-callbacks.patch deleted file mode 100644 index e2c7df9..0000000 --- a/test/integration/rhel-8.2/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2020-05-12 11:14:32.580647540 -0400 -+++ src/drivers/input/joydev.c 2020-05-12 11:15:04.909246454 -0400 -@@ -1084,3 +1084,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2020-05-12 11:14:32.590647107 -0400 -+++ src/drivers/input/misc/pcspkr.c 2020-05-12 11:15:04.909246454 -0400 -@@ -133,3 +133,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-05-12 11:14:29.130797053 -0400 -+++ src/fs/aio.c 2020-05-12 11:15:04.909246454 -0400 -@@ -49,6 +49,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.2/macro-printk.patch b/test/integration/rhel-8.2/macro-printk.patch deleted file mode 100644 index f2d2d4b..0000000 --- a/test/integration/rhel-8.2/macro-printk.patch +++ /dev/null @@ -1,148 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2020-05-12 11:14:29.710771918 -0400 -+++ src/net/ipv4/fib_frontend.c 2020-05-12 11:15:48.047376894 -0400 -@@ -789,6 +789,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -810,6 +811,7 @@ static int inet_rtm_newroute(struct sk_b - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2020-05-12 11:14:29.710771918 -0400 -+++ src/net/ipv4/fib_semantics.c 2020-05-12 11:15:48.047376894 -0400 -@@ -1025,6 +1025,7 @@ fib_convert_metrics(struct fib_info *fi, - fi->fib_metrics->metrics); - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1058,6 +1059,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1078,6 +1080,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1093,6 +1096,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1109,8 +1114,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1172,6 +1179,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1193,6 +1201,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1231,6 +1240,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1240,6 +1250,7 @@ struct fib_info *fib_create_info(struct - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1251,6 +1262,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1274,6 +1286,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1284,6 +1297,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2020-05-12 11:14:29.710771918 -0400 -+++ src/net/ipv4/fib_trie.c 2020-05-12 11:15:48.047376894 -0400 -@@ -1121,6 +1121,7 @@ static bool fib_valid_key_len(u32 key, u - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1143,11 +1144,14 @@ int fib_table_insert(struct net *net, st - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.2/meminfo-init-FAIL.patch b/test/integration/rhel-8.2/meminfo-init-FAIL.patch deleted file mode 100644 index 6f58adb..0000000 --- a/test/integration/rhel-8.2/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/meminfo.c 2020-05-12 11:15:13.848859021 -0400 -@@ -153,6 +153,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.2/meminfo-init2-FAIL.patch b/test/integration/rhel-8.2/meminfo-init2-FAIL.patch deleted file mode 100644 index 28ba5bc..0000000 --- a/test/integration/rhel-8.2/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/meminfo.c 2020-05-12 11:15:10.778992066 -0400 -@@ -41,6 +41,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long sreclaimable, sunreclaim; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -153,6 +154,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.2/meminfo-string-LOADED.test b/test/integration/rhel-8.2/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.2/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.2/meminfo-string.patch b/test/integration/rhel-8.2/meminfo-string.patch deleted file mode 100644 index 278e0e5..0000000 --- a/test/integration/rhel-8.2/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-05-12 11:24:25.954931343 -0400 -+++ src/fs/proc/meminfo.c 2020-05-12 11:24:33.774592448 -0400 -@@ -121,7 +121,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - show_val_kb(m, "Percpu: ", pcpu_nr_pages()); - - #ifdef CONFIG_MEMORY_FAILURE diff --git a/test/integration/rhel-8.2/module-LOADED.test b/test/integration/rhel-8.2/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-8.2/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-8.2/module.patch b/test/integration/rhel-8.2/module.patch deleted file mode 100644 index 5dcee19..0000000 --- a/test/integration/rhel-8.2/module.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 08078d00ab1749a6f84148a00d8d26572af4ec97 Mon Sep 17 00:00:00 2001 -Message-Id: <08078d00ab1749a6f84148a00d8d26572af4ec97.1586900628.git.jpoimboe@redhat.com> -From: Josh Poimboeuf -Date: Tue, 14 Apr 2020 15:17:51 -0500 -Subject: [PATCH] kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf ---- - fs/nfsd/export.c | 30 ++++++++++++++++++++++++++++++ - net/netlink/af_netlink.c | 5 +++++ - 2 files changed, 35 insertions(+) - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2020-05-12 11:14:29.230792719 -0400 -+++ src/fs/nfsd/export.c 2020-05-12 11:15:17.078719042 -0400 -@@ -1196,15 +1196,45 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); - struct cache_detail *cd = m->private; -+#ifdef CONFIG_X86_64 -+ unsigned long long sched_clock; -+ -+ alternative("ud2", "call yield", X86_FEATURE_ALWAYS); -+ alternative("call yield", "ud2", X86_FEATURE_IA64); -+ -+ sched_clock = paravirt_sched_clock(); -+ if (!jiffies) -+ printk("kpatch: sched_clock: %llu\n", sched_clock); -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&mcsafe_key)) -+ printk("kpatch: mcsafe_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif - - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2020-05-12 11:14:29.780768884 -0400 -+++ src/net/netlink/af_netlink.c 2020-05-12 11:15:17.078719042 -0400 -@@ -2788,4 +2788,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-8.2/multiple.test b/test/integration/rhel-8.2/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.2/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.2/new-function.patch b/test/integration/rhel-8.2/new-function.patch deleted file mode 100644 index 079065d..0000000 --- a/test/integration/rhel-8.2/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2020-05-12 11:14:32.770639306 -0400 -+++ src/drivers/tty/n_tty.c 2020-05-12 11:15:20.398575163 -0400 -@@ -2296,7 +2296,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2383,6 +2383,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.2/new-globals.patch b/test/integration/rhel-8.2/new-globals.patch deleted file mode 100644 index 1f75685..0000000 --- a/test/integration/rhel-8.2/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/cmdline.c 2020-05-12 11:15:23.488441252 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/meminfo.c 2020-05-12 11:15:23.488441252 -0400 -@@ -21,6 +21,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -57,6 +59,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE); - sunreclaim = global_node_page_state(NR_SLAB_UNRECLAIMABLE); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.2/parainstructions-section.patch b/test/integration/rhel-8.2/parainstructions-section.patch deleted file mode 100644 index 185bf97..0000000 --- a/test/integration/rhel-8.2/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/generic.c 2020-05-12 11:15:26.558308207 -0400 -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.2/shadow-newpid-LOADED.test.disabled b/test/integration/rhel-8.2/shadow-newpid-LOADED.test.disabled deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.2/shadow-newpid-LOADED.test.disabled +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.2/shadow-newpid.patch.disabled b/test/integration/rhel-8.2/shadow-newpid.patch.disabled deleted file mode 100644 index 18ae4c5..0000000 --- a/test/integration/rhel-8.2/shadow-newpid.patch.disabled +++ /dev/null @@ -1,77 +0,0 @@ -Disabled due to https:/github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2020-05-12 11:14:29.250791853 -0400 -+++ src/fs/proc/array.c 2020-05-12 11:15:51.127243416 -0400 -@@ -370,12 +370,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2020-05-12 11:14:29.670773651 -0400 -+++ src/kernel/exit.c 2020-05-12 11:15:51.127243416 -0400 -@@ -762,6 +762,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -868,6 +869,8 @@ void __noreturn do_exit(long code) - exit_thread(tsk); - exit_umh(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-05-12 11:14:29.670773651 -0400 -+++ src/kernel/fork.c 2020-05-12 11:15:51.127243416 -0400 -@@ -2206,6 +2206,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2218,6 +2219,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2244,6 +2247,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.2/smp-locks-section.patch b/test/integration/rhel-8.2/smp-locks-section.patch deleted file mode 100644 index 562be3e..0000000 --- a/test/integration/rhel-8.2/smp-locks-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2020-05-12 11:14:32.780638873 -0400 -+++ src/drivers/tty/tty_buffer.c 2020-05-12 11:15:29.618175596 -0400 -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.2/special-static.patch.disabled b/test/integration/rhel-8.2/special-static.patch.disabled deleted file mode 100644 index a58cbbc..0000000 --- a/test/integration/rhel-8.2/special-static.patch.disabled +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-05-12 11:14:29.670773651 -0400 -+++ src/kernel/fork.c 2020-05-12 11:15:54.197110372 -0400 -@@ -1523,10 +1523,18 @@ static void posix_cpu_timers_init_group( - static inline void posix_cpu_timers_init_group(struct signal_struct *sig) { } - #endif - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.2/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.2/symvers-disagreement-FAIL.patch deleted file mode 100644 index 798d21f..0000000 --- a/test/integration/rhel-8.2/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index 26bae20f0553..506ebbf0a210 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -30,6 +30,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index f74e6bda1788..86f7d453549c 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -685,6 +685,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-8.2/tracepoints-section.patch b/test/integration/rhel-8.2/tracepoints-section.patch deleted file mode 100644 index a15d065..0000000 --- a/test/integration/rhel-8.2/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c ---- src.orig/kernel/time/timer.c 2020-05-12 11:14:29.670773651 -0400 -+++ src/kernel/time/timer.c 2020-05-12 11:15:32.688042552 -0400 -@@ -1696,6 +1696,9 @@ static __latent_entropy void run_timer_s - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.2/warn-detect-FAIL.patch b/test/integration/rhel-8.2/warn-detect-FAIL.patch deleted file mode 100644 index 5686019..0000000 --- a/test/integration/rhel-8.2/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2020-05-12 11:14:30.610732914 -0400 -+++ src/arch/x86/kvm/x86.c 2020-05-12 11:15:35.767909073 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.3/bug-table-section.patch b/test/integration/rhel-8.3/bug-table-section.patch deleted file mode 100644 index cc2cca0..0000000 --- a/test/integration/rhel-8.3/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-03-17 01:12:55.155895808 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-03-17 01:12:59.269209033 -0400 -@@ -338,6 +338,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.3/cmdline-string-LOADED.test b/test/integration/rhel-8.3/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.3/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.3/cmdline-string.patch b/test/integration/rhel-8.3/cmdline-string.patch deleted file mode 100644 index 06117f7..0000000 --- a/test/integration/rhel-8.3/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-03-17 01:12:55.154895731 -0400 -+++ src/fs/proc/cmdline.c 2020-03-17 01:13:02.339442827 -0400 -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.3/data-new-LOADED.test b/test/integration/rhel-8.3/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.3/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.3/data-new.patch b/test/integration/rhel-8.3/data-new.patch deleted file mode 100644 index 773c6c0..0000000 --- a/test/integration/rhel-8.3/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-17 01:12:55.155895808 -0400 -+++ src/fs/proc/meminfo.c 2020-03-17 01:13:05.297668094 -0400 -@@ -31,6 +31,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -143,6 +145,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.3/data-read-mostly.patch.disabled b/test/integration/rhel-8.3/data-read-mostly.patch.disabled deleted file mode 100644 index 9ad7022..0000000 --- a/test/integration/rhel-8.3/data-read-mostly.patch.disabled +++ /dev/null @@ -1,13 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2020-03-17 01:12:55.619931143 -0400 -+++ src/net/core/dev.c 2020-03-17 01:13:57.999681305 -0400 -@@ -4893,6 +4893,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.3/fixup-section.patch b/test/integration/rhel-8.3/fixup-section.patch deleted file mode 100644 index 845d27d..0000000 --- a/test/integration/rhel-8.3/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2020-03-17 01:12:55.087890628 -0400 -+++ src/fs/readdir.c 2020-03-17 01:13:08.214890238 -0400 -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.3/gcc-constprop.patch b/test/integration/rhel-8.3/gcc-constprop.patch deleted file mode 100644 index 1524b3f..0000000 --- a/test/integration/rhel-8.3/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2020-03-17 01:12:55.498921929 -0400 -+++ src/kernel/time/timekeeping.c 2020-03-17 01:14:00.935904896 -0400 -@@ -1221,6 +1221,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.3/gcc-isra.patch b/test/integration/rhel-8.3/gcc-isra.patch deleted file mode 100644 index cabe41b..0000000 --- a/test/integration/rhel-8.3/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2020-03-17 01:12:55.155895808 -0400 -+++ src/fs/proc/proc_sysctl.c 2020-03-17 01:13:11.117111239 -0400 -@@ -53,6 +53,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.3/gcc-mangled-3.patch b/test/integration/rhel-8.3/gcc-mangled-3.patch deleted file mode 100644 index 4b53f1c..0000000 --- a/test/integration/rhel-8.3/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2020-03-17 01:12:57.341062206 -0400 -+++ src/mm/slub.c 2020-03-17 01:13:14.023332546 -0400 -@@ -5852,6 +5852,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.3/gcc-static-local-var-2.patch b/test/integration/rhel-8.3/gcc-static-local-var-2.patch deleted file mode 100644 index 98a883e..0000000 --- a/test/integration/rhel-8.3/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2020-03-17 01:12:57.337061902 -0400 -+++ src/mm/mmap.c 2020-03-17 01:13:16.949555374 -0400 -@@ -1679,6 +1679,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.3/gcc-static-local-var-3.patch b/test/integration/rhel-8.3/gcc-static-local-var-3.patch deleted file mode 100644 index aa93ab8..0000000 --- a/test/integration/rhel-8.3/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c ---- src.orig/kernel/reboot.c 2020-03-17 01:12:55.495921700 -0400 -+++ src/kernel/reboot.c 2020-03-17 01:13:19.875778203 -0400 -@@ -393,8 +393,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.3/gcc-static-local-var-4.patch.disabled b/test/integration/rhel-8.3/gcc-static-local-var-4.patch.disabled deleted file mode 100644 index 1b4f072..0000000 --- a/test/integration/rhel-8.3/gcc-static-local-var-4.patch.disabled +++ /dev/null @@ -1,24 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-03-17 01:12:55.092891009 -0400 -+++ src/fs/aio.c 2020-03-17 01:14:03.844126354 -0400 -@@ -251,11 +251,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.3/gcc-static-local-var-4.test.disabled b/test/integration/rhel-8.3/gcc-static-local-var-4.test.disabled deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.3/gcc-static-local-var-4.test.disabled +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.3/gcc-static-local-var-5.patch b/test/integration/rhel-8.3/gcc-static-local-var-5.patch deleted file mode 100644 index 23be980..0000000 --- a/test/integration/rhel-8.3/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2020-03-17 13:21:09.547745268 -0400 -+++ src/kernel/audit.c 2020-03-17 13:57:21.709885683 -0400 -@@ -321,6 +321,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -331,6 +337,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -350,6 +357,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -396,6 +408,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.3/gcc-static-local-var-6.patch b/test/integration/rhel-8.3/gcc-static-local-var-6.patch deleted file mode 100644 index 7c418df..0000000 --- a/test/integration/rhel-8.3/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2020-10-21 11:19:40.261740227 -0400 -+++ src/net/ipv6/netfilter.c 2020-10-21 11:21:09.055020262 -0400 -@@ -86,6 +86,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -99,6 +101,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.3/macro-callbacks.patch b/test/integration/rhel-8.3/macro-callbacks.patch deleted file mode 100644 index ff41d17..0000000 --- a/test/integration/rhel-8.3/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2020-03-17 01:12:57.827099217 -0400 -+++ src/drivers/input/joydev.c 2020-03-17 01:13:25.725223634 -0400 -@@ -1084,3 +1084,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2020-03-17 01:12:57.831099522 -0400 -+++ src/drivers/input/misc/pcspkr.c 2020-03-17 01:13:25.725223634 -0400 -@@ -133,3 +133,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2020-03-17 01:12:55.092891009 -0400 -+++ src/fs/aio.c 2020-03-17 01:13:25.726223710 -0400 -@@ -49,6 +49,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.3/macro-printk.patch b/test/integration/rhel-8.3/macro-printk.patch deleted file mode 100644 index 1713578..0000000 --- a/test/integration/rhel-8.3/macro-printk.patch +++ /dev/null @@ -1,148 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2020-03-17 01:12:55.534924670 -0400 -+++ src/net/ipv4/fib_frontend.c 2020-03-17 01:14:06.756348118 -0400 -@@ -789,6 +789,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -810,6 +811,7 @@ static int inet_rtm_newroute(struct sk_b - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2020-03-17 01:12:55.534924670 -0400 -+++ src/net/ipv4/fib_semantics.c 2020-03-17 01:14:06.756348118 -0400 -@@ -1025,6 +1025,7 @@ fib_convert_metrics(struct fib_info *fi, - fi->fib_metrics->metrics); - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1058,6 +1059,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1078,6 +1080,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1093,6 +1096,8 @@ struct fib_info *fib_create_info(struct - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1109,8 +1114,10 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1172,6 +1179,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1193,6 +1201,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1231,6 +1240,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1240,6 +1250,7 @@ struct fib_info *fib_create_info(struct - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1251,6 +1262,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1274,6 +1286,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1284,6 +1297,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2020-03-17 01:12:55.541925203 -0400 -+++ src/net/ipv4/fib_trie.c 2020-03-17 01:14:06.756348118 -0400 -@@ -1121,6 +1121,7 @@ static bool fib_valid_key_len(u32 key, u - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1143,11 +1144,14 @@ int fib_table_insert(struct net *net, st - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.3/meminfo-init-FAIL.patch b/test/integration/rhel-8.3/meminfo-init-FAIL.patch deleted file mode 100644 index 8f4bf4a..0000000 --- a/test/integration/rhel-8.3/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-17 01:12:55.155895808 -0400 -+++ src/fs/proc/meminfo.c 2020-03-17 01:13:31.599670967 -0400 -@@ -153,6 +153,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.3/meminfo-init2-FAIL.patch b/test/integration/rhel-8.3/meminfo-init2-FAIL.patch deleted file mode 100644 index 8cc8748..0000000 --- a/test/integration/rhel-8.3/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-17 01:12:55.155895808 -0400 -+++ src/fs/proc/meminfo.c 2020-03-17 01:13:28.655446767 -0400 -@@ -41,6 +41,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long sreclaimable, sunreclaim; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -153,6 +154,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.3/meminfo-string-LOADED.test b/test/integration/rhel-8.3/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.3/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.3/meminfo-string.patch b/test/integration/rhel-8.3/meminfo-string.patch deleted file mode 100644 index 79c22de..0000000 --- a/test/integration/rhel-8.3/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-17 13:21:08.363654606 -0400 -+++ src/fs/proc/meminfo.c 2020-03-17 13:22:47.153218616 -0400 -@@ -121,7 +121,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - show_val_kb(m, "Percpu: ", pcpu_nr_pages()); - - #ifdef CONFIG_MEMORY_FAILURE diff --git a/test/integration/rhel-8.3/module-LOADED.test b/test/integration/rhel-8.3/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-8.3/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-8.3/module.patch b/test/integration/rhel-8.3/module.patch deleted file mode 100644 index 5dcee19..0000000 --- a/test/integration/rhel-8.3/module.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 08078d00ab1749a6f84148a00d8d26572af4ec97 Mon Sep 17 00:00:00 2001 -Message-Id: <08078d00ab1749a6f84148a00d8d26572af4ec97.1586900628.git.jpoimboe@redhat.com> -From: Josh Poimboeuf -Date: Tue, 14 Apr 2020 15:17:51 -0500 -Subject: [PATCH] kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf ---- - fs/nfsd/export.c | 30 ++++++++++++++++++++++++++++++ - net/netlink/af_netlink.c | 5 +++++ - 2 files changed, 35 insertions(+) - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2020-05-12 11:14:29.230792719 -0400 -+++ src/fs/nfsd/export.c 2020-05-12 11:15:17.078719042 -0400 -@@ -1196,15 +1196,45 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); - struct cache_detail *cd = m->private; -+#ifdef CONFIG_X86_64 -+ unsigned long long sched_clock; -+ -+ alternative("ud2", "call yield", X86_FEATURE_ALWAYS); -+ alternative("call yield", "ud2", X86_FEATURE_IA64); -+ -+ sched_clock = paravirt_sched_clock(); -+ if (!jiffies) -+ printk("kpatch: sched_clock: %llu\n", sched_clock); -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&mcsafe_key)) -+ printk("kpatch: mcsafe_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif - - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2020-05-12 11:14:29.780768884 -0400 -+++ src/net/netlink/af_netlink.c 2020-05-12 11:15:17.078719042 -0400 -@@ -2788,4 +2788,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-8.3/multiple.test b/test/integration/rhel-8.3/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.3/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.3/new-function.patch b/test/integration/rhel-8.3/new-function.patch deleted file mode 100644 index dab2c63..0000000 --- a/test/integration/rhel-8.3/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2020-03-17 01:12:58.001112468 -0400 -+++ src/drivers/tty/n_tty.c 2020-03-17 01:13:37.546123784 -0400 -@@ -2296,7 +2296,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2383,6 +2383,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.3/new-globals.patch b/test/integration/rhel-8.3/new-globals.patch deleted file mode 100644 index 085d8be..0000000 --- a/test/integration/rhel-8.3/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2020-03-17 01:12:55.154895731 -0400 -+++ src/fs/proc/cmdline.c 2020-03-17 01:13:40.492348137 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2020-03-17 01:12:55.155895808 -0400 -+++ src/fs/proc/meminfo.c 2020-03-17 01:13:40.492348137 -0400 -@@ -21,6 +21,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -57,6 +59,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE); - sunreclaim = global_node_page_state(NR_SLAB_UNRECLAIMABLE); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.3/parainstructions-section.patch b/test/integration/rhel-8.3/parainstructions-section.patch deleted file mode 100644 index 5f03a97..0000000 --- a/test/integration/rhel-8.3/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2020-03-17 01:12:55.154895731 -0400 -+++ src/fs/proc/generic.c 2020-03-17 01:13:43.430571880 -0400 -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.3/shadow-newpid-LOADED.test.disabled b/test/integration/rhel-8.3/shadow-newpid-LOADED.test.disabled deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.3/shadow-newpid-LOADED.test.disabled +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.3/shadow-newpid.patch.disabled b/test/integration/rhel-8.3/shadow-newpid.patch.disabled deleted file mode 100644 index d737bfb..0000000 --- a/test/integration/rhel-8.3/shadow-newpid.patch.disabled +++ /dev/null @@ -1,77 +0,0 @@ -Disabled due to https://github.com/dynup/kpatch/issues/940 ---- -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2020-03-17 01:12:55.154895731 -0400 -+++ src/fs/proc/array.c 2020-03-17 01:14:09.668569881 -0400 -@@ -370,12 +370,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2020-03-17 01:12:55.490921320 -0400 -+++ src/kernel/exit.c 2020-03-17 01:14:09.668569881 -0400 -@@ -762,6 +762,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -868,6 +869,8 @@ void __noreturn do_exit(long code) - exit_thread(tsk); - exit_umh(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-03-17 01:12:55.500922081 -0400 -+++ src/kernel/fork.c 2020-03-17 01:14:09.668569881 -0400 -@@ -2206,6 +2206,7 @@ struct task_struct *fork_idle(int cpu) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2218,6 +2219,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2244,6 +2247,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.3/smp-locks-section.patch b/test/integration/rhel-8.3/smp-locks-section.patch deleted file mode 100644 index 664ec7e..0000000 --- a/test/integration/rhel-8.3/smp-locks-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2020-03-17 01:12:58.012113306 -0400 -+++ src/drivers/tty/tty_buffer.c 2020-03-17 01:13:46.342793643 -0400 -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.3/special-static.patch.disabled b/test/integration/rhel-8.3/special-static.patch.disabled deleted file mode 100644 index 695f0a1..0000000 --- a/test/integration/rhel-8.3/special-static.patch.disabled +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2020-03-17 01:12:55.500922081 -0400 -+++ src/kernel/fork.c 2020-03-17 01:13:49.230013502 -0400 -@@ -1523,10 +1523,18 @@ static void posix_cpu_timers_init_group( - static inline void posix_cpu_timers_init_group(struct signal_struct *sig) { } - #endif - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.3/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.3/symvers-disagreement-FAIL.patch deleted file mode 100644 index 798d21f..0000000 --- a/test/integration/rhel-8.3/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/base/core.c b/drivers/base/core.c -index 26bae20f0553..506ebbf0a210 100644 ---- a/drivers/base/core.c -+++ b/drivers/base/core.c -@@ -30,6 +30,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index f74e6bda1788..86f7d453549c 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -685,6 +685,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; --- -2.21.3 - diff --git a/test/integration/rhel-8.3/tracepoints-section.patch b/test/integration/rhel-8.3/tracepoints-section.patch deleted file mode 100644 index 8b77551..0000000 --- a/test/integration/rhel-8.3/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c ---- src.orig/kernel/time/timer.c 2020-03-17 01:12:55.499922005 -0400 -+++ src/kernel/time/timer.c 2020-03-17 01:13:52.157236408 -0400 -@@ -1696,6 +1696,9 @@ static __latent_entropy void run_timer_s - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.3/warn-detect-FAIL.patch b/test/integration/rhel-8.3/warn-detect-FAIL.patch deleted file mode 100644 index e9518a9..0000000 --- a/test/integration/rhel-8.3/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2020-03-17 01:12:56.596005471 -0400 -+++ src/arch/x86/kvm/x86.c 2020-03-17 01:13:55.095460151 -0400 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.4/bug-table-section.patch b/test/integration/rhel-8.4/bug-table-section.patch deleted file mode 100644 index f1e2af8..0000000 --- a/test/integration/rhel-8.4/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/proc_sysctl.c 2021-04-20 11:04:27.636102900 -0400 -@@ -338,6 +338,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.4/cmdline-string-LOADED.test b/test/integration/rhel-8.4/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.4/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.4/cmdline-string.patch b/test/integration/rhel-8.4/cmdline-string.patch deleted file mode 100644 index 0f01b59..0000000 --- a/test/integration/rhel-8.4/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/cmdline.c 2021-04-20 11:04:30.118109128 -0400 -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.4/data-new-LOADED.test b/test/integration/rhel-8.4/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.4/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.4/data-new.patch b/test/integration/rhel-8.4/data-new.patch deleted file mode 100644 index 23e1bdd..0000000 --- a/test/integration/rhel-8.4/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/meminfo.c 2021-04-20 11:04:32.584115315 -0400 -@@ -31,6 +31,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -146,6 +148,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.4/data-read-mostly.patch b/test/integration/rhel-8.4/data-read-mostly.patch deleted file mode 100644 index 482d997..0000000 --- a/test/integration/rhel-8.4/data-read-mostly.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2021-04-20 11:04:27.355102195 -0400 -+++ src/net/core/dev.c 2021-04-20 11:04:34.800120875 -0400 -@@ -5058,6 +5058,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.4/fixup-section.patch b/test/integration/rhel-8.4/fixup-section.patch deleted file mode 100644 index 6321af8..0000000 --- a/test/integration/rhel-8.4/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2021-04-20 11:04:26.675100489 -0400 -+++ src/fs/readdir.c 2021-04-20 11:04:36.984126354 -0400 -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.4/gcc-constprop.patch b/test/integration/rhel-8.4/gcc-constprop.patch deleted file mode 100644 index dd62372..0000000 --- a/test/integration/rhel-8.4/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2021-04-20 11:04:27.325102120 -0400 -+++ src/kernel/time/timekeeping.c 2021-04-20 11:04:39.253132047 -0400 -@@ -1231,6 +1231,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.4/gcc-isra.patch b/test/integration/rhel-8.4/gcc-isra.patch deleted file mode 100644 index 51fd423..0000000 --- a/test/integration/rhel-8.4/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/proc_sysctl.c 2021-04-20 11:04:41.824138498 -0400 -@@ -53,6 +53,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.4/gcc-mangled-3.patch b/test/integration/rhel-8.4/gcc-mangled-3.patch deleted file mode 100644 index 699eb1a..0000000 --- a/test/integration/rhel-8.4/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2021-04-20 11:04:27.343102165 -0400 -+++ src/mm/slub.c 2021-04-20 11:04:44.205144472 -0400 -@@ -5749,6 +5749,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.4/gcc-static-local-var-2.patch b/test/integration/rhel-8.4/gcc-static-local-var-2.patch deleted file mode 100644 index f847008..0000000 --- a/test/integration/rhel-8.4/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2021-04-20 11:04:27.341102160 -0400 -+++ src/mm/mmap.c 2021-04-20 11:04:46.880151184 -0400 -@@ -1690,6 +1690,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.4/gcc-static-local-var-3.patch b/test/integration/rhel-8.4/gcc-static-local-var-3.patch deleted file mode 100644 index 8b9ec4f..0000000 --- a/test/integration/rhel-8.4/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c ---- src.orig/kernel/reboot.c 2021-04-20 11:04:27.316102097 -0400 -+++ src/kernel/reboot.c 2021-04-20 11:04:49.155156892 -0400 -@@ -393,8 +393,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.4/gcc-static-local-var-4.patch b/test/integration/rhel-8.4/gcc-static-local-var-4.patch deleted file mode 100644 index cdef516..0000000 --- a/test/integration/rhel-8.4/gcc-static-local-var-4.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2021-04-20 11:04:26.671100479 -0400 -+++ src/fs/aio.c 2021-04-20 11:04:51.420162575 -0400 -@@ -248,11 +248,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - --static void put_aio_ring_file(struct kioctx *ctx) -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ -+__always_inline static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.4/gcc-static-local-var-4.test b/test/integration/rhel-8.4/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.4/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.4/gcc-static-local-var-5.patch b/test/integration/rhel-8.4/gcc-static-local-var-5.patch deleted file mode 100644 index 1ba0205..0000000 --- a/test/integration/rhel-8.4/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2021-04-20 11:04:27.312102087 -0400 -+++ src/kernel/audit.c 2021-04-20 11:04:53.691168273 -0400 -@@ -327,6 +327,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -337,6 +343,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -356,6 +363,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -402,6 +414,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.4/gcc-static-local-var-6.patch b/test/integration/rhel-8.4/gcc-static-local-var-6.patch deleted file mode 100644 index 9163e02..0000000 --- a/test/integration/rhel-8.4/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2021-04-20 11:04:27.369102230 -0400 -+++ src/net/ipv6/netfilter.c 2021-04-20 11:04:56.097174309 -0400 -@@ -86,6 +86,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -99,6 +101,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.4/macro-callbacks.patch b/test/integration/rhel-8.4/macro-callbacks.patch deleted file mode 100644 index 68033a3..0000000 --- a/test/integration/rhel-8.4/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2021-04-20 11:04:26.086099011 -0400 -+++ src/drivers/input/joydev.c 2021-04-20 11:04:58.399180085 -0400 -@@ -1084,3 +1084,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2021-04-20 11:04:26.090099021 -0400 -+++ src/drivers/input/misc/pcspkr.c 2021-04-20 11:04:58.399180085 -0400 -@@ -133,3 +133,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2021-04-20 11:04:26.671100479 -0400 -+++ src/fs/aio.c 2021-04-20 11:04:58.399180085 -0400 -@@ -49,6 +49,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.4/macro-printk.patch b/test/integration/rhel-8.4/macro-printk.patch deleted file mode 100644 index f5f9004..0000000 --- a/test/integration/rhel-8.4/macro-printk.patch +++ /dev/null @@ -1,149 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2021-04-20 11:04:27.363102215 -0400 -+++ src/net/ipv4/fib_frontend.c 2021-04-20 11:05:00.587185575 -0400 -@@ -790,6 +790,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -811,6 +812,7 @@ static int inet_rtm_newroute(struct sk_b - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2021-04-20 11:04:27.363102215 -0400 -+++ src/net/ipv4/fib_semantics.c 2021-04-20 11:05:00.588185577 -0400 -@@ -1023,6 +1023,7 @@ static bool fib_valid_prefsrc(struct fib - return true; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1056,6 +1057,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1076,6 +1078,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1089,6 +1092,8 @@ struct fib_info *fib_create_info(struct - } - - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1144,9 +1149,11 @@ struct fib_info *fib_create_info(struct - "LWT encap type not specified"); - goto err_inval; - } -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - err = lwtunnel_build_state(cfg->fc_encap_type, - cfg->fc_encap, AF_INET, cfg, - &lwtstate, extack); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1164,6 +1171,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1185,6 +1193,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1223,6 +1232,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1232,6 +1242,7 @@ struct fib_info *fib_create_info(struct - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1243,6 +1254,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1266,6 +1278,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1276,6 +1289,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2021-04-20 11:04:27.363102215 -0400 -+++ src/net/ipv4/fib_trie.c 2021-04-20 11:05:00.588185577 -0400 -@@ -1174,6 +1174,7 @@ static void fib_remove_alias(struct trie - struct key_vector *l, struct fib_alias *old); - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1195,11 +1196,14 @@ int fib_table_insert(struct net *net, st - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.4/meminfo-init-FAIL.patch b/test/integration/rhel-8.4/meminfo-init-FAIL.patch deleted file mode 100644 index abd02dc..0000000 --- a/test/integration/rhel-8.4/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/meminfo.c 2021-04-20 11:05:05.090196873 -0400 -@@ -156,6 +156,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.4/meminfo-init2-FAIL.patch b/test/integration/rhel-8.4/meminfo-init2-FAIL.patch deleted file mode 100644 index b261bab..0000000 --- a/test/integration/rhel-8.4/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/meminfo.c 2021-04-20 11:05:02.874191313 -0400 -@@ -41,6 +41,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long sreclaimable, sunreclaim; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -156,6 +157,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.4/meminfo-string-LOADED.test b/test/integration/rhel-8.4/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.4/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.4/meminfo-string.patch b/test/integration/rhel-8.4/meminfo-string.patch deleted file mode 100644 index d07429a..0000000 --- a/test/integration/rhel-8.4/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/meminfo.c 2021-04-20 11:05:07.263202325 -0400 -@@ -120,7 +120,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - show_val_kb(m, "Percpu: ", pcpu_nr_pages()); - - #ifdef CONFIG_MEMORY_FAILURE diff --git a/test/integration/rhel-8.4/module-LOADED.test b/test/integration/rhel-8.4/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-8.4/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-8.4/module.patch b/test/integration/rhel-8.4/module.patch deleted file mode 100644 index 812dba8..0000000 --- a/test/integration/rhel-8.4/module.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 08078d00ab1749a6f84148a00d8d26572af4ec97 Mon Sep 17 00:00:00 2001 -Message-Id: <08078d00ab1749a6f84148a00d8d26572af4ec97.1586900628.git.jpoimboe@redhat.com> -From: Josh Poimboeuf -Date: Tue, 14 Apr 2020 15:17:51 -0500 -Subject: [PATCH] kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf ---- - fs/nfsd/export.c | 30 ++++++++++++++++++++++++++++++ - net/netlink/af_netlink.c | 5 +++++ - 2 files changed, 35 insertions(+) - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2021-04-20 11:04:26.703100559 -0400 -+++ src/fs/nfsd/export.c 2021-04-20 11:05:09.399207684 -0400 -@@ -1221,15 +1221,45 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); - struct cache_detail *cd = m->private; -+#ifdef CONFIG_X86_64 -+ unsigned long long sched_clock; -+ -+ alternative("ud2", "call yield", X86_FEATURE_ALWAYS); -+ alternative("call yield", "ud2", X86_FEATURE_IA64); -+ -+ sched_clock = paravirt_sched_clock(); -+ if (!jiffies) -+ printk("kpatch: sched_clock: %llu\n", sched_clock); -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&mcsafe_key)) -+ printk("kpatch: mcsafe_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif - - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2021-04-20 11:04:27.385102270 -0400 -+++ src/net/netlink/af_netlink.c 2021-04-20 11:05:09.399207684 -0400 -@@ -2879,4 +2879,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-8.4/multiple.test b/test/integration/rhel-8.4/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.4/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.4/new-function.patch b/test/integration/rhel-8.4/new-function.patch deleted file mode 100644 index 35b222e..0000000 --- a/test/integration/rhel-8.4/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2021-04-20 11:04:26.603100308 -0400 -+++ src/drivers/tty/n_tty.c 2021-04-20 11:05:11.672213387 -0400 -@@ -2296,7 +2296,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2383,6 +2383,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.4/new-globals.patch b/test/integration/rhel-8.4/new-globals.patch deleted file mode 100644 index 1ab87c0..0000000 --- a/test/integration/rhel-8.4/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/cmdline.c 2021-04-20 11:05:13.847218845 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/meminfo.c 2021-04-20 11:05:13.847218845 -0400 -@@ -21,6 +21,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -57,6 +59,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.4/parainstructions-section.patch b/test/integration/rhel-8.4/parainstructions-section.patch deleted file mode 100644 index 843ee94..0000000 --- a/test/integration/rhel-8.4/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/generic.c 2021-04-20 11:05:16.189224721 -0400 -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.4/shadow-newpid-LOADED.test b/test/integration/rhel-8.4/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.4/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.4/shadow-newpid.patch b/test/integration/rhel-8.4/shadow-newpid.patch deleted file mode 100644 index 3292906..0000000 --- a/test/integration/rhel-8.4/shadow-newpid.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2021-04-20 11:04:26.717100594 -0400 -+++ src/fs/proc/array.c 2021-04-20 11:05:18.430230343 -0400 -@@ -370,12 +370,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2021-04-20 11:04:27.314102092 -0400 -+++ src/kernel/exit.c 2021-04-20 11:05:18.430230343 -0400 -@@ -701,6 +701,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -794,6 +795,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2021-04-20 11:04:27.315102095 -0400 -+++ src/kernel/fork.c 2021-04-20 11:05:18.431230346 -0400 -@@ -2222,6 +2222,7 @@ struct mm_struct *copy_init_mm(void) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2234,6 +2235,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2260,6 +2263,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.4/smp-locks-section.patch b/test/integration/rhel-8.4/smp-locks-section.patch deleted file mode 100644 index d6273a5..0000000 --- a/test/integration/rhel-8.4/smp-locks-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2021-04-20 11:04:26.609100323 -0400 -+++ src/drivers/tty/tty_buffer.c 2021-04-20 11:05:20.584235748 -0400 -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.4/special-static.patch b/test/integration/rhel-8.4/special-static.patch deleted file mode 100644 index 8c1e197..0000000 --- a/test/integration/rhel-8.4/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2021-04-20 11:04:27.315102095 -0400 -+++ src/kernel/fork.c 2021-04-20 11:05:23.010241835 -0400 -@@ -1554,10 +1554,18 @@ static void posix_cpu_timers_init_group( - posix_cputimers_group_init(pct, cpu_limit); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.4/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.4/symvers-disagreement-FAIL.patch deleted file mode 100644 index cd62d06..0000000 --- a/test/integration/rhel-8.4/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c ---- src.orig/drivers/base/core.c 2021-04-20 11:04:25.703098050 -0400 -+++ src/drivers/base/core.c 2021-04-20 11:05:25.287247548 -0400 -@@ -31,6 +31,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c ---- src.orig/drivers/usb/core/usb.c 2021-04-20 11:04:26.613100333 -0400 -+++ src/drivers/usb/core/usb.c 2021-04-20 11:05:25.287247548 -0400 -@@ -693,6 +693,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; diff --git a/test/integration/rhel-8.4/syscall-LOADED.test b/test/integration/rhel-8.4/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/rhel-8.4/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/rhel-8.4/syscall.patch b/test/integration/rhel-8.4/syscall.patch deleted file mode 100644 index 4679d01..0000000 --- a/test/integration/rhel-8.4/syscall.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff --git a/kernel/sys.c b/kernel/sys.c -index 871c0848f05c8..479bf8725d2e6 100644 ---- a/kernel/sys.c -+++ b/kernel/sys.c -@@ -1241,14 +1241,18 @@ static int override_release(char __user *release, size_t len) - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { -+ struct new_utsname tmp; - int errno = 0; - - down_read(&uts_sem); -- if (copy_to_user(name, utsname(), sizeof *name)) -- errno = -EFAULT; -+ memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); -+ if (copy_to_user(name, &tmp, sizeof(tmp))) -+ errno = -EFAULT; - - if (!errno && override_release(name->release, sizeof(name->release))) - errno = -EFAULT; diff --git a/test/integration/rhel-8.4/tracepoints-section.patch b/test/integration/rhel-8.4/tracepoints-section.patch deleted file mode 100644 index 5af1b46..0000000 --- a/test/integration/rhel-8.4/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c ---- src.orig/kernel/time/timer.c 2021-04-20 11:04:27.325102120 -0400 -+++ src/kernel/time/timer.c 2021-04-20 11:05:27.596253341 -0400 -@@ -1751,6 +1751,9 @@ static __latent_entropy void run_timer_s - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.4/warn-detect-FAIL.patch b/test/integration/rhel-8.4/warn-detect-FAIL.patch deleted file mode 100644 index 6c1e7ac..0000000 --- a/test/integration/rhel-8.4/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2021-04-20 11:04:27.273101989 -0400 -+++ src/arch/x86/kvm/x86.c 2021-04-20 11:05:29.870259047 -0400 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-only -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.6/bug-table-section.patch b/test/integration/rhel-8.6/bug-table-section.patch deleted file mode 100644 index 7d05c04..0000000 --- a/test/integration/rhel-8.6/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/proc_sysctl.c 2022-04-29 16:08:21.908782326 -0400 -@@ -338,6 +338,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.6/cmdline-string-LOADED.test b/test/integration/rhel-8.6/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.6/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.6/cmdline-string.patch b/test/integration/rhel-8.6/cmdline-string.patch deleted file mode 100644 index f547c87..0000000 --- a/test/integration/rhel-8.6/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-04-29 16:08:21.408780547 -0400 -+++ src/fs/proc/cmdline.c 2022-04-29 16:08:24.434791315 -0400 -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.6/data-new-LOADED.test b/test/integration/rhel-8.6/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.6/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.6/data-new.patch b/test/integration/rhel-8.6/data-new.patch deleted file mode 100644 index 2fd4b91..0000000 --- a/test/integration/rhel-8.6/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 16:08:26.826799828 -0400 -@@ -31,6 +31,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -150,6 +152,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.6/data-read-mostly.patch b/test/integration/rhel-8.6/data-read-mostly.patch deleted file mode 100644 index 6f9e324..0000000 --- a/test/integration/rhel-8.6/data-read-mostly.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2022-04-29 16:08:21.614781280 -0400 -+++ src/net/core/dev.c 2022-04-29 16:08:29.184808219 -0400 -@@ -5278,6 +5278,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.6/fixup-section.patch b/test/integration/rhel-8.6/fixup-section.patch deleted file mode 100644 index efcbfc2..0000000 --- a/test/integration/rhel-8.6/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2022-04-29 16:08:21.360780376 -0400 -+++ src/fs/readdir.c 2022-04-29 16:08:31.537816593 -0400 -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.6/gcc-constprop.patch b/test/integration/rhel-8.6/gcc-constprop.patch deleted file mode 100644 index d923fbb..0000000 --- a/test/integration/rhel-8.6/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2022-04-29 16:08:21.581781162 -0400 -+++ src/kernel/time/timekeeping.c 2022-04-29 16:08:33.934825123 -0400 -@@ -1231,6 +1231,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.6/gcc-isra.patch b/test/integration/rhel-8.6/gcc-isra.patch deleted file mode 100644 index c873c3b..0000000 --- a/test/integration/rhel-8.6/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/proc_sysctl.c 2022-04-29 16:08:36.314833593 -0400 -@@ -53,6 +53,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.6/gcc-mangled-3.patch b/test/integration/rhel-8.6/gcc-mangled-3.patch deleted file mode 100644 index 19d54e1..0000000 --- a/test/integration/rhel-8.6/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2022-04-29 16:08:21.601781233 -0400 -+++ src/mm/slub.c 2022-04-29 16:08:38.713842130 -0400 -@@ -6107,6 +6107,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.6/gcc-static-local-var-2.patch b/test/integration/rhel-8.6/gcc-static-local-var-2.patch deleted file mode 100644 index a796431..0000000 --- a/test/integration/rhel-8.6/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2022-04-29 16:08:21.599781226 -0400 -+++ src/mm/mmap.c 2022-04-29 16:08:41.140850766 -0400 -@@ -1714,6 +1714,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.6/gcc-static-local-var-3.patch b/test/integration/rhel-8.6/gcc-static-local-var-3.patch deleted file mode 100644 index 286975e..0000000 --- a/test/integration/rhel-8.6/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c ---- src.orig/kernel/reboot.c 2022-04-29 16:08:21.578781152 -0400 -+++ src/kernel/reboot.c 2022-04-29 16:08:43.524859249 -0400 -@@ -393,8 +393,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.6/gcc-static-local-var-4.patch b/test/integration/rhel-8.6/gcc-static-local-var-4.patch deleted file mode 100644 index ad95d02..0000000 --- a/test/integration/rhel-8.6/gcc-static-local-var-4.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-04-29 16:08:21.357780365 -0400 -+++ src/fs/aio.c 2022-04-29 16:08:45.936867833 -0400 -@@ -247,11 +247,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - --static void put_aio_ring_file(struct kioctx *ctx) -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ -+__always_inline static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.6/gcc-static-local-var-4.test b/test/integration/rhel-8.6/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.6/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.6/gcc-static-local-var-5.patch b/test/integration/rhel-8.6/gcc-static-local-var-5.patch deleted file mode 100644 index 44ee755..0000000 --- a/test/integration/rhel-8.6/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2022-04-29 16:08:21.568781116 -0400 -+++ src/kernel/audit.c 2022-04-29 16:08:48.347876413 -0400 -@@ -327,6 +327,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -337,6 +343,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -356,6 +363,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -402,6 +414,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.6/gcc-static-local-var-6.patch b/test/integration/rhel-8.6/gcc-static-local-var-6.patch deleted file mode 100644 index 14c79a5..0000000 --- a/test/integration/rhel-8.6/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2022-04-29 16:08:21.627781326 -0400 -+++ src/net/ipv6/netfilter.c 2022-04-29 16:08:50.811885181 -0400 -@@ -86,6 +86,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -99,6 +101,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.6/macro-callbacks.patch b/test/integration/rhel-8.6/macro-callbacks.patch deleted file mode 100644 index 24a2579..0000000 --- a/test/integration/rhel-8.6/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2022-04-29 16:08:20.747778194 -0400 -+++ src/drivers/input/joydev.c 2022-04-29 16:08:53.228893783 -0400 -@@ -1087,3 +1087,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2022-04-29 16:08:20.752778212 -0400 -+++ src/drivers/input/misc/pcspkr.c 2022-04-29 16:08:53.229893786 -0400 -@@ -133,3 +133,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-04-29 16:08:21.357780365 -0400 -+++ src/fs/aio.c 2022-04-29 16:08:53.229893786 -0400 -@@ -48,6 +48,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.6/macro-printk.patch b/test/integration/rhel-8.6/macro-printk.patch deleted file mode 100644 index 74bd4a9..0000000 --- a/test/integration/rhel-8.6/macro-printk.patch +++ /dev/null @@ -1,149 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2022-04-29 16:08:21.621781305 -0400 -+++ src/net/ipv4/fib_frontend.c 2022-04-29 16:08:55.676902494 -0400 -@@ -792,6 +792,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -813,6 +814,7 @@ static int inet_rtm_newroute(struct sk_b - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2022-04-29 16:08:21.621781305 -0400 -+++ src/net/ipv4/fib_semantics.c 2022-04-29 16:08:55.677902498 -0400 -@@ -1022,6 +1022,7 @@ static bool fib_valid_prefsrc(struct fib - return true; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1055,6 +1056,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1075,6 +1077,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1088,6 +1091,8 @@ struct fib_info *fib_create_info(struct - } - - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1143,9 +1148,11 @@ struct fib_info *fib_create_info(struct - "LWT encap type not specified"); - goto err_inval; - } -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - err = lwtunnel_build_state(cfg->fc_encap_type, - cfg->fc_encap, AF_INET, cfg, - &lwtstate, extack); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1163,6 +1170,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1184,6 +1192,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1222,6 +1231,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1231,6 +1241,7 @@ struct fib_info *fib_create_info(struct - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1242,6 +1253,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1265,6 +1277,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1275,6 +1288,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2022-04-29 16:08:21.621781305 -0400 -+++ src/net/ipv4/fib_trie.c 2022-04-29 16:08:55.677902498 -0400 -@@ -1174,6 +1174,7 @@ static void fib_remove_alias(struct trie - struct key_vector *l, struct fib_alias *old); - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1195,11 +1196,14 @@ int fib_table_insert(struct net *net, st - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.6/meminfo-init-FAIL.patch b/test/integration/rhel-8.6/meminfo-init-FAIL.patch deleted file mode 100644 index 5105bed..0000000 --- a/test/integration/rhel-8.6/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 16:09:00.653920206 -0400 -@@ -160,6 +160,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.6/meminfo-init2-FAIL.patch b/test/integration/rhel-8.6/meminfo-init2-FAIL.patch deleted file mode 100644 index 913d67a..0000000 --- a/test/integration/rhel-8.6/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 16:08:58.219911544 -0400 -@@ -41,6 +41,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long sreclaimable, sunreclaim; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -160,6 +161,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.6/meminfo-string-LOADED.test b/test/integration/rhel-8.6/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.6/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.6/meminfo-string.patch b/test/integration/rhel-8.6/meminfo-string.patch deleted file mode 100644 index 6992c27..0000000 --- a/test/integration/rhel-8.6/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 16:09:03.079928840 -0400 -@@ -124,7 +124,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - show_val_kb(m, "Percpu: ", pcpu_nr_pages()); - - #ifdef CONFIG_MEMORY_FAILURE diff --git a/test/integration/rhel-8.6/module-LOADED.test b/test/integration/rhel-8.6/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-8.6/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-8.6/module.patch b/test/integration/rhel-8.6/module.patch deleted file mode 100644 index 4818ee0..0000000 --- a/test/integration/rhel-8.6/module.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 08078d00ab1749a6f84148a00d8d26572af4ec97 Mon Sep 17 00:00:00 2001 -Message-Id: <08078d00ab1749a6f84148a00d8d26572af4ec97.1586900628.git.jpoimboe@redhat.com> -From: Josh Poimboeuf -Date: Tue, 14 Apr 2020 15:17:51 -0500 -Subject: [PATCH] kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf ---- - fs/nfsd/export.c | 30 ++++++++++++++++++++++++++++++ - net/netlink/af_netlink.c | 5 +++++ - 2 files changed, 35 insertions(+) - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2022-04-29 16:08:21.394780497 -0400 -+++ src/fs/nfsd/export.c 2022-04-29 16:09:05.551937637 -0400 -@@ -1228,15 +1228,45 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); - struct cache_detail *cd = m->private; -+#ifdef CONFIG_X86_64 -+ unsigned long long sched_clock; -+ -+ alternative("ud2", "call yield", X86_FEATURE_ALWAYS); -+ alternative("call yield", "ud2", X86_FEATURE_IA64); -+ -+ sched_clock = paravirt_sched_clock(); -+ if (!jiffies) -+ printk("kpatch: sched_clock: %llu\n", sched_clock); -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&mcsafe_key)) -+ printk("kpatch: mcsafe_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif - - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2022-04-29 16:08:21.644781386 -0400 -+++ src/net/netlink/af_netlink.c 2022-04-29 16:09:05.551937637 -0400 -@@ -2887,4 +2887,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-8.6/multiple.test b/test/integration/rhel-8.6/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.6/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.6/new-function.patch b/test/integration/rhel-8.6/new-function.patch deleted file mode 100644 index 146ca31..0000000 --- a/test/integration/rhel-8.6/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2022-04-29 16:08:21.286780112 -0400 -+++ src/drivers/tty/n_tty.c 2022-04-29 16:09:07.953946185 -0400 -@@ -2298,7 +2298,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2385,6 +2385,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.6/new-globals.patch b/test/integration/rhel-8.6/new-globals.patch deleted file mode 100644 index 6b70151..0000000 --- a/test/integration/rhel-8.6/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-04-29 16:08:21.408780547 -0400 -+++ src/fs/proc/cmdline.c 2022-04-29 16:09:10.382954829 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 16:09:10.382954829 -0400 -@@ -21,6 +21,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -57,6 +59,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.6/parainstructions-section.patch b/test/integration/rhel-8.6/parainstructions-section.patch deleted file mode 100644 index ada24c0..0000000 --- a/test/integration/rhel-8.6/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2022-04-29 16:08:21.409780550 -0400 -+++ src/fs/proc/generic.c 2022-04-29 16:09:12.837963565 -0400 -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.6/shadow-newpid-LOADED.test b/test/integration/rhel-8.6/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.6/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.6/shadow-newpid.patch b/test/integration/rhel-8.6/shadow-newpid.patch deleted file mode 100644 index 50d8adf..0000000 --- a/test/integration/rhel-8.6/shadow-newpid.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2022-04-29 16:08:21.408780547 -0400 -+++ src/fs/proc/array.c 2022-04-29 16:09:15.255972171 -0400 -@@ -372,12 +372,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2022-04-29 16:08:21.572781130 -0400 -+++ src/kernel/exit.c 2022-04-29 16:09:15.256972174 -0400 -@@ -703,6 +703,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -803,6 +804,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-04-29 16:08:21.572781130 -0400 -+++ src/kernel/fork.c 2022-04-29 16:09:15.256972174 -0400 -@@ -2364,6 +2364,7 @@ struct mm_struct *copy_init_mm(void) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2376,6 +2377,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2402,6 +2405,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.6/smp-locks-section.patch b/test/integration/rhel-8.6/smp-locks-section.patch deleted file mode 100644 index 8c6272d..0000000 --- a/test/integration/rhel-8.6/smp-locks-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2022-04-29 16:08:21.287780116 -0400 -+++ src/drivers/tty/tty_buffer.c 2022-04-29 16:09:17.674980779 -0400 -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.6/special-static.patch b/test/integration/rhel-8.6/special-static.patch deleted file mode 100644 index ba6e75a..0000000 --- a/test/integration/rhel-8.6/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-04-29 16:08:21.572781130 -0400 -+++ src/kernel/fork.c 2022-04-29 16:09:20.112989455 -0400 -@@ -1579,10 +1579,18 @@ static void posix_cpu_timers_init_group( - posix_cputimers_group_init(pct, cpu_limit); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.6/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.6/symvers-disagreement-FAIL.patch deleted file mode 100644 index 04b7567..0000000 --- a/test/integration/rhel-8.6/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c ---- src.orig/drivers/base/core.c 2022-04-29 16:08:20.289776564 -0400 -+++ src/drivers/base/core.c 2022-04-29 16:09:22.510997989 -0400 -@@ -33,6 +33,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c ---- src.orig/drivers/usb/core/usb.c 2022-04-29 16:08:21.297780151 -0400 -+++ src/drivers/usb/core/usb.c 2022-04-29 16:09:22.510997989 -0400 -@@ -739,6 +739,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; diff --git a/test/integration/rhel-8.6/syscall-LOADED.test b/test/integration/rhel-8.6/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/rhel-8.6/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/rhel-8.6/syscall.patch b/test/integration/rhel-8.6/syscall.patch deleted file mode 100644 index 1494888..0000000 --- a/test/integration/rhel-8.6/syscall.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2022-04-29 16:10:59.577343400 -0400 -+++ src/kernel/sys.c 2022-04-29 16:10:59.917344609 -0400 -@@ -1241,14 +1241,18 @@ static int override_release(char __user - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { -+ struct new_utsname tmp; - int errno = 0; - - down_read(&uts_sem); -- if (copy_to_user(name, utsname(), sizeof *name)) -- errno = -EFAULT; -+ memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); -+ if (copy_to_user(name, &tmp, sizeof(tmp))) -+ errno = -EFAULT; - - if (!errno && override_release(name->release, sizeof(name->release))) - errno = -EFAULT; diff --git a/test/integration/rhel-8.6/tracepoints-section.patch b/test/integration/rhel-8.6/tracepoints-section.patch deleted file mode 100644 index 9d60262..0000000 --- a/test/integration/rhel-8.6/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c ---- src.orig/kernel/time/timer.c 2022-04-29 16:08:21.581781162 -0400 -+++ src/kernel/time/timer.c 2022-04-29 16:09:24.914006540 -0400 -@@ -1747,6 +1747,9 @@ static __latent_entropy void run_timer_s - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.6/warn-detect-FAIL.patch b/test/integration/rhel-8.6/warn-detect-FAIL.patch deleted file mode 100644 index 2245584..0000000 --- a/test/integration/rhel-8.6/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2022-04-29 16:08:20.241776394 -0400 -+++ src/arch/x86/kvm/x86.c 2022-04-29 16:09:27.340015174 -0400 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-only -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-8.7/bug-table-section.patch b/test/integration/rhel-8.7/bug-table-section.patch deleted file mode 100644 index 0f76565..0000000 --- a/test/integration/rhel-8.7/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/proc_sysctl.c 2022-10-24 15:41:09.326752698 -0400 -@@ -338,6 +338,8 @@ static void start_unregistering(struct c - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/rhel-8.7/cmdline-string-LOADED.test b/test/integration/rhel-8.7/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/rhel-8.7/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/rhel-8.7/cmdline-string.patch b/test/integration/rhel-8.7/cmdline-string.patch deleted file mode 100644 index 6dd6101..0000000 --- a/test/integration/rhel-8.7/cmdline-string.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-10-24 15:41:08.858760066 -0400 -+++ src/fs/proc/cmdline.c 2022-10-24 15:41:11.698715352 -0400 -@@ -6,8 +6,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_puts(m, saved_command_line); -- seq_putc(m, '\n'); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/rhel-8.7/data-new-LOADED.test b/test/integration/rhel-8.7/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-8.7/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-8.7/data-new.patch b/test/integration/rhel-8.7/data-new.patch deleted file mode 100644 index dc6b4b1..0000000 --- a/test/integration/rhel-8.7/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:41:13.982679391 -0400 -@@ -31,6 +31,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -150,6 +152,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-8.7/data-read-mostly.patch b/test/integration/rhel-8.7/data-read-mostly.patch deleted file mode 100644 index 972711b..0000000 --- a/test/integration/rhel-8.7/data-read-mostly.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2022-10-24 15:41:09.054756980 -0400 -+++ src/net/core/dev.c 2022-10-24 15:41:16.731636110 -0400 -@@ -5360,6 +5360,7 @@ skip_classify: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/rhel-8.7/fixup-section.patch b/test/integration/rhel-8.7/fixup-section.patch deleted file mode 100644 index ce7e2c4..0000000 --- a/test/integration/rhel-8.7/fixup-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c ---- src.orig/fs/readdir.c 2022-10-24 15:41:08.815760743 -0400 -+++ src/fs/readdir.c 2022-10-24 15:41:19.018600102 -0400 -@@ -189,6 +189,7 @@ static int filldir(struct dir_context *c - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/rhel-8.7/gcc-constprop.patch b/test/integration/rhel-8.7/gcc-constprop.patch deleted file mode 100644 index fba2be8..0000000 --- a/test/integration/rhel-8.7/gcc-constprop.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2022-10-24 15:41:09.024757453 -0400 -+++ src/kernel/time/timekeeping.c 2022-10-24 15:41:21.308564048 -0400 -@@ -1231,6 +1231,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/rhel-8.7/gcc-isra.patch b/test/integration/rhel-8.7/gcc-isra.patch deleted file mode 100644 index dfd70f6..0000000 --- a/test/integration/rhel-8.7/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/proc_sysctl.c 2022-10-24 15:41:23.590528119 -0400 -@@ -53,6 +53,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/rhel-8.7/gcc-mangled-3.patch b/test/integration/rhel-8.7/gcc-mangled-3.patch deleted file mode 100644 index 724253a..0000000 --- a/test/integration/rhel-8.7/gcc-mangled-3.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2022-10-24 15:41:09.041757185 -0400 -+++ src/mm/slub.c 2022-10-24 15:41:26.180487340 -0400 -@@ -6086,6 +6086,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/rhel-8.7/gcc-static-local-var-2.patch b/test/integration/rhel-8.7/gcc-static-local-var-2.patch deleted file mode 100644 index b38d284..0000000 --- a/test/integration/rhel-8.7/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2022-10-24 15:41:09.040757201 -0400 -+++ src/mm/mmap.c 2022-10-24 15:41:28.615449003 -0400 -@@ -1714,6 +1714,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, vm_flags, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/rhel-8.7/gcc-static-local-var-3.patch b/test/integration/rhel-8.7/gcc-static-local-var-3.patch deleted file mode 100644 index b66df8c..0000000 --- a/test/integration/rhel-8.7/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c ---- src.orig/kernel/reboot.c 2022-10-24 15:41:09.013757626 -0400 -+++ src/kernel/reboot.c 2022-10-24 15:41:30.924412649 -0400 -@@ -393,8 +393,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/rhel-8.7/gcc-static-local-var-4.patch b/test/integration/rhel-8.7/gcc-static-local-var-4.patch deleted file mode 100644 index 33e29e1..0000000 --- a/test/integration/rhel-8.7/gcc-static-local-var-4.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-10-24 15:41:08.813760775 -0400 -+++ src/fs/aio.c 2022-10-24 15:41:33.247376074 -0400 -@@ -247,11 +247,18 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - --static void put_aio_ring_file(struct kioctx *ctx) -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ -+__always_inline static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; - struct address_space *i_mapping; - -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(file_inode(aio_ring_file), 0); - diff --git a/test/integration/rhel-8.7/gcc-static-local-var-4.test b/test/integration/rhel-8.7/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/rhel-8.7/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/rhel-8.7/gcc-static-local-var-5.patch b/test/integration/rhel-8.7/gcc-static-local-var-5.patch deleted file mode 100644 index fa461e7..0000000 --- a/test/integration/rhel-8.7/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2022-10-24 15:41:09.011757657 -0400 -+++ src/kernel/audit.c 2022-10-24 15:41:35.790336036 -0400 -@@ -327,6 +327,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -337,6 +343,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -356,6 +363,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -402,6 +414,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(audit_context(), GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/rhel-8.7/gcc-static-local-var-6.patch b/test/integration/rhel-8.7/gcc-static-local-var-6.patch deleted file mode 100644 index 649d954..0000000 --- a/test/integration/rhel-8.7/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2022-10-24 15:41:09.065756807 -0400 -+++ src/net/ipv6/netfilter.c 2022-10-24 15:41:38.279296848 -0400 -@@ -86,6 +86,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -99,6 +101,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-8.7/macro-callbacks.patch b/test/integration/rhel-8.7/macro-callbacks.patch deleted file mode 100644 index e7147a8..0000000 --- a/test/integration/rhel-8.7/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2022-10-24 15:41:08.259769497 -0400 -+++ src/drivers/input/joydev.c 2022-10-24 15:41:40.583260573 -0400 -@@ -1087,3 +1087,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2022-10-24 15:41:08.263769434 -0400 -+++ src/drivers/input/misc/pcspkr.c 2022-10-24 15:41:40.583260573 -0400 -@@ -133,3 +133,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-10-24 15:41:08.813760775 -0400 -+++ src/fs/aio.c 2022-10-24 15:41:40.584260557 -0400 -@@ -48,6 +48,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-8.7/macro-printk.patch b/test/integration/rhel-8.7/macro-printk.patch deleted file mode 100644 index a567cd6..0000000 --- a/test/integration/rhel-8.7/macro-printk.patch +++ /dev/null @@ -1,149 +0,0 @@ -diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c ---- src.orig/net/ipv4/fib_frontend.c 2022-10-24 15:41:09.060756886 -0400 -+++ src/net/ipv4/fib_frontend.c 2022-10-24 15:41:42.891224235 -0400 -@@ -793,6 +793,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, - struct netlink_ext_ack *extack) - { -@@ -814,6 +815,7 @@ static int inet_rtm_newroute(struct sk_b - err = fib_table_insert(net, tb, &cfg, extack); - if (!err && cfg.fc_type == RTN_LOCAL) - net->ipv4.fib_has_custom_local_routes = true; -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -diff -Nupr src.orig/net/ipv4/fib_semantics.c src/net/ipv4/fib_semantics.c ---- src.orig/net/ipv4/fib_semantics.c 2022-10-24 15:41:09.060756886 -0400 -+++ src/net/ipv4/fib_semantics.c 2022-10-24 15:41:42.893224203 -0400 -@@ -1025,6 +1025,7 @@ static bool fib_valid_prefsrc(struct fib - return true; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg, - struct netlink_ext_ack *extack) - { -@@ -1058,6 +1059,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1078,6 +1080,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1091,6 +1094,8 @@ struct fib_info *fib_create_info(struct - } - - fib_info_cnt++; -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); -+ - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; -@@ -1146,9 +1151,11 @@ struct fib_info *fib_create_info(struct - "LWT encap type not specified"); - goto err_inval; - } -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - err = lwtunnel_build_state(cfg->fc_encap_type, - cfg->fc_encap, AF_INET, cfg, - &lwtstate, extack); -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); - if (err) - goto failure; - -@@ -1166,6 +1173,7 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) { -@@ -1187,6 +1195,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) { - NL_SET_ERR_MSG(extack, "Invalid scope"); -@@ -1225,6 +1234,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) { - NL_SET_ERR_MSG(extack, "Invalid prefsrc address"); -@@ -1234,6 +1244,7 @@ struct fib_info *fib_create_info(struct - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1245,6 +1256,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - refcount_set(&fi->fib_clntref, 1); -@@ -1268,6 +1280,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1278,6 +1291,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -diff -Nupr src.orig/net/ipv4/fib_trie.c src/net/ipv4/fib_trie.c ---- src.orig/net/ipv4/fib_trie.c 2022-10-24 15:41:09.060756886 -0400 -+++ src/net/ipv4/fib_trie.c 2022-10-24 15:41:42.894224187 -0400 -@@ -1174,6 +1174,7 @@ static void fib_remove_alias(struct trie - struct key_vector *l, struct fib_alias *old); - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg, struct netlink_ext_ack *extack) - { -@@ -1195,11 +1196,14 @@ int fib_table_insert(struct net *net, st - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg, extack); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/rhel-8.7/meminfo-init-FAIL.patch b/test/integration/rhel-8.7/meminfo-init-FAIL.patch deleted file mode 100644 index caec2bd..0000000 --- a/test/integration/rhel-8.7/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:41:47.914145150 -0400 -@@ -160,6 +160,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.7/meminfo-init2-FAIL.patch b/test/integration/rhel-8.7/meminfo-init2-FAIL.patch deleted file mode 100644 index 334d966..0000000 --- a/test/integration/rhel-8.7/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:41:45.332185802 -0400 -@@ -41,6 +41,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long sreclaimable, sunreclaim; - int lru; - -+ printk("a\n"); - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); -@@ -160,6 +161,7 @@ static int meminfo_proc_show(struct seq_ - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create_single("meminfo", 0, NULL, meminfo_proc_show); - return 0; - } diff --git a/test/integration/rhel-8.7/meminfo-string-LOADED.test b/test/integration/rhel-8.7/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/rhel-8.7/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/rhel-8.7/meminfo-string.patch b/test/integration/rhel-8.7/meminfo-string.patch deleted file mode 100644 index d6d8a76..0000000 --- a/test/integration/rhel-8.7/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:41:50.371106466 -0400 -@@ -124,7 +124,7 @@ static int meminfo_proc_show(struct seq_ - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); -- show_val_kb(m, "VmallocChunk: ", 0ul); -+ show_val_kb(m, "VMALLOCCHUNK: ", 0ul); - show_val_kb(m, "Percpu: ", pcpu_nr_pages()); - - #ifdef CONFIG_MEMORY_FAILURE diff --git a/test/integration/rhel-8.7/module-LOADED.test b/test/integration/rhel-8.7/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-8.7/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-8.7/module.patch b/test/integration/rhel-8.7/module.patch deleted file mode 100644 index 365f836..0000000 --- a/test/integration/rhel-8.7/module.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 08078d00ab1749a6f84148a00d8d26572af4ec97 Mon Sep 17 00:00:00 2001 -Message-Id: <08078d00ab1749a6f84148a00d8d26572af4ec97.1586900628.git.jpoimboe@redhat.com> -From: Josh Poimboeuf -Date: Tue, 14 Apr 2020 15:17:51 -0500 -Subject: [PATCH] kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf ---- - fs/nfsd/export.c | 30 ++++++++++++++++++++++++++++++ - net/netlink/af_netlink.c | 5 +++++ - 2 files changed, 35 insertions(+) - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2022-10-24 15:41:08.846760255 -0400 -+++ src/fs/nfsd/export.c 2022-10-24 15:41:52.672070238 -0400 -@@ -1228,15 +1228,45 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; - struct svc_export *exp = container_of(cp, struct svc_export, h); - struct cache_detail *cd = m->private; -+#ifdef CONFIG_X86_64 -+ unsigned long long sched_clock; -+ -+ alternative("ud2", "call yield", X86_FEATURE_ALWAYS); -+ alternative("call yield", "ud2", X86_FEATURE_IA64); -+ -+ sched_clock = paravirt_sched_clock(); -+ if (!jiffies) -+ printk("kpatch: sched_clock: %llu\n", sched_clock); -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&mcsafe_key)) -+ printk("kpatch: mcsafe_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif - - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2022-10-24 15:41:09.080756571 -0400 -+++ src/net/netlink/af_netlink.c 2022-10-24 15:41:52.672070238 -0400 -@@ -2887,4 +2887,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-8.7/multiple.test b/test/integration/rhel-8.7/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-8.7/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-8.7/new-function.patch b/test/integration/rhel-8.7/new-function.patch deleted file mode 100644 index a1ddb12..0000000 --- a/test/integration/rhel-8.7/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2022-10-24 15:41:08.744761861 -0400 -+++ src/drivers/tty/n_tty.c 2022-10-24 15:41:55.055032719 -0400 -@@ -2298,7 +2298,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2385,6 +2385,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-8.7/new-globals.patch b/test/integration/rhel-8.7/new-globals.patch deleted file mode 100644 index 261fabd..0000000 --- a/test/integration/rhel-8.7/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-10-24 15:41:08.858760066 -0400 -+++ src/fs/proc/cmdline.c 2022-10-24 15:41:57.672991500 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:41:57.672991500 -0400 -@@ -21,6 +21,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -57,6 +59,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-8.7/parainstructions-section.patch b/test/integration/rhel-8.7/parainstructions-section.patch deleted file mode 100644 index 5cc08b2..0000000 --- a/test/integration/rhel-8.7/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2022-10-24 15:41:08.859760050 -0400 -+++ src/fs/proc/generic.c 2022-10-24 15:42:00.072953713 -0400 -@@ -205,6 +205,7 @@ int proc_alloc_inum(unsigned int *inum) - { - int i; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - i = ida_simple_get(&proc_inum_ida, 0, UINT_MAX - PROC_DYNAMIC_FIRST + 1, - GFP_KERNEL); - if (i < 0) diff --git a/test/integration/rhel-8.7/shadow-newpid-LOADED.test b/test/integration/rhel-8.7/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-8.7/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-8.7/shadow-newpid.patch b/test/integration/rhel-8.7/shadow-newpid.patch deleted file mode 100644 index 00b8cee..0000000 --- a/test/integration/rhel-8.7/shadow-newpid.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2022-10-24 15:41:08.858760066 -0400 -+++ src/fs/proc/array.c 2022-10-24 15:42:02.398917091 -0400 -@@ -372,12 +372,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2022-10-24 15:41:09.012757642 -0400 -+++ src/kernel/exit.c 2022-10-24 15:42:02.399917076 -0400 -@@ -704,6 +704,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -804,6 +805,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-10-24 15:41:09.012757642 -0400 -+++ src/kernel/fork.c 2022-10-24 15:42:02.399917076 -0400 -@@ -2408,6 +2408,7 @@ struct mm_struct *copy_init_mm(void) - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -+#include - long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, -@@ -2420,6 +2421,8 @@ long _do_fork(unsigned long clone_flags, - struct task_struct *p; - int trace = 0; - long nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * Determine whether and which event to report to ptracer. When -@@ -2446,6 +2449,11 @@ long _do_fork(unsigned long clone_flags, - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-8.7/smp-locks-section.patch b/test/integration/rhel-8.7/smp-locks-section.patch deleted file mode 100644 index af46ca9..0000000 --- a/test/integration/rhel-8.7/smp-locks-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2022-10-24 15:41:08.745761845 -0400 -+++ src/drivers/tty/tty_buffer.c 2022-10-24 15:42:04.971876581 -0400 -@@ -256,6 +256,9 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); -+ - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/rhel-8.7/special-static.patch b/test/integration/rhel-8.7/special-static.patch deleted file mode 100644 index 98d2173..0000000 --- a/test/integration/rhel-8.7/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-10-24 15:41:09.012757642 -0400 -+++ src/kernel/fork.c 2022-10-24 15:42:08.093827427 -0400 -@@ -1586,10 +1586,18 @@ static void posix_cpu_timers_init_group( - posix_cputimers_group_init(pct, cpu_limit); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-8.7/symvers-disagreement-FAIL.patch b/test/integration/rhel-8.7/symvers-disagreement-FAIL.patch deleted file mode 100644 index a20d613..0000000 --- a/test/integration/rhel-8.7/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c ---- src.orig/drivers/base/core.c 2022-10-24 15:41:07.830776251 -0400 -+++ src/drivers/base/core.c 2022-10-24 15:42:11.128779642 -0400 -@@ -33,6 +33,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c ---- src.orig/drivers/usb/core/usb.c 2022-10-24 15:41:08.756761672 -0400 -+++ src/drivers/usb/core/usb.c 2022-10-24 15:42:11.129779626 -0400 -@@ -739,6 +739,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; diff --git a/test/integration/rhel-8.7/syscall-LOADED.test b/test/integration/rhel-8.7/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/rhel-8.7/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/rhel-8.7/syscall.patch b/test/integration/rhel-8.7/syscall.patch deleted file mode 100644 index ebacc1a..0000000 --- a/test/integration/rhel-8.7/syscall.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2022-10-24 15:41:09.013757626 -0400 -+++ src/kernel/sys.c 2022-10-24 15:42:13.974734833 -0400 -@@ -1241,14 +1241,18 @@ static int override_release(char __user - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { -+ struct new_utsname tmp; - int errno = 0; - - down_read(&uts_sem); -- if (copy_to_user(name, utsname(), sizeof *name)) -- errno = -EFAULT; -+ memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); -+ if (copy_to_user(name, &tmp, sizeof(tmp))) -+ errno = -EFAULT; - - if (!errno && override_release(name->release, sizeof(name->release))) - errno = -EFAULT; diff --git a/test/integration/rhel-8.7/tracepoints-section.patch b/test/integration/rhel-8.7/tracepoints-section.patch deleted file mode 100644 index 382c8cb..0000000 --- a/test/integration/rhel-8.7/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c ---- src.orig/kernel/time/timer.c 2022-10-24 15:41:09.024757453 -0400 -+++ src/kernel/time/timer.c 2022-10-24 15:42:17.054686340 -0400 -@@ -1747,6 +1747,9 @@ static __latent_entropy void run_timer_s - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON)) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); diff --git a/test/integration/rhel-8.7/warn-detect-FAIL.patch b/test/integration/rhel-8.7/warn-detect-FAIL.patch deleted file mode 100644 index 5273a2e..0000000 --- a/test/integration/rhel-8.7/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2022-10-24 15:41:07.784776976 -0400 -+++ src/arch/x86/kvm/x86.c 2022-10-24 15:42:19.845642398 -0400 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-only -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-9.0/data-new-LOADED.test b/test/integration/rhel-9.0/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-9.0/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-9.0/data-new.patch b/test/integration/rhel-9.0/data-new.patch deleted file mode 100644 index 6b94642..0000000 --- a/test/integration/rhel-9.0/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 15:52:13.399335763 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 15:52:20.014359304 -0400 -@@ -29,6 +29,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -145,6 +147,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-9.0/gcc-static-local-var-6.patch b/test/integration/rhel-9.0/gcc-static-local-var-6.patch deleted file mode 100644 index dbd9f34..0000000 --- a/test/integration/rhel-9.0/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2022-04-29 15:52:13.640336621 -0400 -+++ src/net/ipv6/netfilter.c 2022-04-29 15:52:45.295449272 -0400 -@@ -91,6 +91,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -104,6 +106,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-9.0/macro-callbacks.patch b/test/integration/rhel-9.0/macro-callbacks.patch deleted file mode 100644 index ab018c3..0000000 --- a/test/integration/rhel-9.0/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2022-04-29 15:52:12.634333041 -0400 -+++ src/drivers/input/joydev.c 2022-04-29 15:52:48.073459158 -0400 -@@ -1086,3 +1086,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2022-04-29 15:52:12.640333062 -0400 -+++ src/drivers/input/misc/pcspkr.c 2022-04-29 15:52:48.073459158 -0400 -@@ -134,3 +134,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-04-29 15:52:13.345335571 -0400 -+++ src/fs/aio.c 2022-04-29 15:52:48.073459158 -0400 -@@ -50,6 +50,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-9.0/module-LOADED.test b/test/integration/rhel-9.0/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-9.0/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-9.0/module.patch b/test/integration/rhel-9.0/module.patch deleted file mode 100644 index 7dcd332..0000000 --- a/test/integration/rhel-9.0/module.patch +++ /dev/null @@ -1,79 +0,0 @@ -kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2022-04-29 15:52:13.385335713 -0400 -+++ src/fs/nfsd/export.c 2022-04-29 15:53:02.037508852 -0400 -@@ -1294,6 +1294,10 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ -+__attribute__((optimize("-fno-optimize-sibling-calls"))) - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1301,12 +1305,36 @@ static int e_show(struct seq_file *m, vo - struct cache_detail *cd = m->private; - bool export_stats = is_export_stats_file(m); - -+#ifdef CONFIG_X86_64 -+ alternative("ud2", "call single_task_running", X86_FEATURE_ALWAYS); -+ alternative("call single_task_running", "ud2", X86_FEATURE_IA64); -+ -+ slow_down_io(); /* paravirt call */ -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&memcg_kmem_enabled_key)) -+ printk("kpatch: memcg_kmem_enabled_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif -+ - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - if (export_stats) - seq_puts(m, "# Path Client Start-time\n#\tStats\n"); - else - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2022-04-29 15:52:13.657336681 -0400 -+++ src/net/netlink/af_netlink.c 2022-04-29 15:53:02.038508855 -0400 -@@ -2908,4 +2908,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-9.0/multiple.test b/test/integration/rhel-9.0/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-9.0/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-9.0/new-function.patch b/test/integration/rhel-9.0/new-function.patch deleted file mode 100644 index 3e6cadd..0000000 --- a/test/integration/rhel-9.0/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2022-04-29 15:52:13.274335318 -0400 -+++ src/drivers/tty/n_tty.c 2022-04-29 15:53:04.777518603 -0400 -@@ -2253,7 +2253,7 @@ more_to_be_read: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2340,6 +2340,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-9.0/new-globals.patch b/test/integration/rhel-9.0/new-globals.patch deleted file mode 100644 index a296821..0000000 --- a/test/integration/rhel-9.0/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-04-29 15:52:13.399335763 -0400 -+++ src/fs/proc/cmdline.c 2022-04-29 15:53:07.589528610 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-04-29 15:52:13.399335763 -0400 -+++ src/fs/proc/meminfo.c 2022-04-29 15:53:07.589528610 -0400 -@@ -19,6 +19,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -55,6 +57,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-9.0/shadow-newpid-LOADED.test b/test/integration/rhel-9.0/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-9.0/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-9.0/shadow-newpid.patch b/test/integration/rhel-9.0/shadow-newpid.patch deleted file mode 100644 index c020e28..0000000 --- a/test/integration/rhel-9.0/shadow-newpid.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2022-04-29 15:52:13.399335763 -0400 -+++ src/fs/proc/array.c 2022-04-29 15:53:13.252548763 -0400 -@@ -402,12 +402,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2022-04-29 15:52:13.577336397 -0400 -+++ src/kernel/exit.c 2022-04-29 15:53:13.252548763 -0400 -@@ -725,6 +725,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -826,6 +827,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-04-29 15:52:13.577336397 -0400 -+++ src/kernel/fork.c 2022-04-29 15:53:13.252548763 -0400 -@@ -2540,6 +2540,7 @@ struct task_struct *create_io_thread(int - * - * args->exit_signal is expected to be checked for sanity by the caller. - */ -+#include - pid_t kernel_clone(struct kernel_clone_args *args) - { - u64 clone_flags = args->flags; -@@ -2548,6 +2549,8 @@ pid_t kernel_clone(struct kernel_clone_a - struct task_struct *p; - int trace = 0; - pid_t nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * For legacy clone() calls, CLONE_PIDFD uses the parent_tid argument -@@ -2587,6 +2590,11 @@ pid_t kernel_clone(struct kernel_clone_a - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-9.0/special-static.patch b/test/integration/rhel-9.0/special-static.patch deleted file mode 100644 index 79d333f..0000000 --- a/test/integration/rhel-9.0/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-04-29 15:52:13.577336397 -0400 -+++ src/kernel/fork.c 2022-04-29 15:53:18.857568709 -0400 -@@ -1635,10 +1635,18 @@ static void posix_cpu_timers_init_group( - posix_cputimers_group_init(pct, cpu_limit); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-9.0/symvers-disagreement-FAIL.patch b/test/integration/rhel-9.0/symvers-disagreement-FAIL.patch deleted file mode 100644 index 0c91065..0000000 --- a/test/integration/rhel-9.0/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c ---- src.orig/drivers/base/core.c 2022-04-29 15:52:12.115331194 -0400 -+++ src/drivers/base/core.c 2022-04-29 15:53:21.690578791 -0400 -@@ -34,6 +34,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c ---- src.orig/drivers/usb/core/usb.c 2022-04-29 15:52:13.286335361 -0400 -+++ src/drivers/usb/core/usb.c 2022-04-29 15:53:21.690578791 -0400 -@@ -739,6 +739,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; diff --git a/test/integration/rhel-9.0/syscall-LOADED.test b/test/integration/rhel-9.0/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/rhel-9.0/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/rhel-9.0/syscall.patch b/test/integration/rhel-9.0/syscall.patch deleted file mode 100644 index 623f2d9..0000000 --- a/test/integration/rhel-9.0/syscall.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2022-04-29 15:56:57.808347857 -0400 -+++ src/kernel/sys.c 2022-04-29 15:56:58.373349868 -0400 -@@ -1268,13 +1268,15 @@ static int override_release(char __user - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { - struct new_utsname tmp; - - down_read(&uts_sem); - memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); - if (copy_to_user(name, &tmp, sizeof(tmp))) - return -EFAULT; - diff --git a/test/integration/rhel-9.0/warn-detect-FAIL.patch b/test/integration/rhel-9.0/warn-detect-FAIL.patch deleted file mode 100644 index dc5a470..0000000 --- a/test/integration/rhel-9.0/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2022-04-29 15:52:12.045330945 -0400 -+++ src/arch/x86/kvm/x86.c 2022-04-29 15:53:27.283598695 -0400 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-only -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/rhel-9.1/data-new-LOADED.test b/test/integration/rhel-9.1/data-new-LOADED.test deleted file mode 100755 index 9f25744..0000000 --- a/test/integration/rhel-9.1/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/rhel-9.1/data-new.patch b/test/integration/rhel-9.1/data-new.patch deleted file mode 100644 index 87de0d5..0000000 --- a/test/integration/rhel-9.1/data-new.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:23:41.612216689 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:23:43.689184284 -0400 -@@ -29,6 +29,8 @@ static void show_val_kb(struct seq_file - seq_write(m, " kB\n", 4); - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -145,6 +147,7 @@ static int meminfo_proc_show(struct seq_ - show_val_kb(m, "CmaFree: ", - global_zone_page_state(NR_FREE_CMA_PAGES)); - #endif -+ seq_printf(m, "kpatch: %d\n", foo); - - hugetlb_report_meminfo(m); - diff --git a/test/integration/rhel-9.1/gcc-static-local-var-6.patch b/test/integration/rhel-9.1/gcc-static-local-var-6.patch deleted file mode 100644 index 2f1e377..0000000 --- a/test/integration/rhel-9.1/gcc-static-local-var-6.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c ---- src.orig/net/ipv6/netfilter.c 2022-10-24 15:23:43.095193552 -0400 -+++ src/net/ipv6/netfilter.c 2022-10-24 15:23:46.981132923 -0400 -@@ -91,6 +91,8 @@ static int nf_ip6_reroute(struct sk_buff - return 0; - } - -+#include "kpatch-macros.h" -+ - int __nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -104,6 +106,9 @@ int __nf_ip6_route(struct net *net, stru - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/rhel-9.1/macro-callbacks.patch b/test/integration/rhel-9.1/macro-callbacks.patch deleted file mode 100644 index 15fc88f..0000000 --- a/test/integration/rhel-9.1/macro-callbacks.patch +++ /dev/null @@ -1,155 +0,0 @@ -diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.orig/drivers/input/joydev.c 2022-10-24 15:23:42.163208093 -0400 -+++ src/drivers/input/joydev.c 2022-10-24 15:23:49.687090705 -0400 -@@ -1096,3 +1096,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.orig/drivers/input/misc/pcspkr.c 2022-10-24 15:23:42.167208030 -0400 -+++ src/drivers/input/misc/pcspkr.c 2022-10-24 15:23:49.687090705 -0400 -@@ -134,3 +134,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2022-10-24 15:23:41.558217532 -0400 -+++ src/fs/aio.c 2022-10-24 15:23:49.688090689 -0400 -@@ -50,6 +50,50 @@ - - #define KIOCB_KEY 0 - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/rhel-9.1/module-LOADED.test b/test/integration/rhel-9.1/module-LOADED.test deleted file mode 100755 index 72bb852..0000000 --- a/test/integration/rhel-9.1/module-LOADED.test +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -set -o errexit - -sudo modprobe nfsd -sleep 5 -grep -q kpatch /proc/fs/nfs/exports - -# TODO: This will trigger a printk on newer kernels which have the .klp.arch -# removal. Don't actually do the grep until running on a newer kernel. -echo "file fs/nfsd/export.c +p" > /sys/kernel/debug/dynamic_debug/control -cat /proc/fs/nfs/exports > /dev/null -# dmesg | grep -q "kpatch: pr_debug" diff --git a/test/integration/rhel-9.1/module.patch b/test/integration/rhel-9.1/module.patch deleted file mode 100644 index 6c646ac..0000000 --- a/test/integration/rhel-9.1/module.patch +++ /dev/null @@ -1,79 +0,0 @@ -kpatch module integration test - -This tests several things related to the patching of modules: - -- 'kpatch_string' tests the referencing of a symbol which is outside the - .o, but inside the patch module. - -- alternatives patching (.altinstructions) - -- paravirt patching (.parainstructions) - -- jump labels (5.8+ kernels only) -- including dynamic printk - -Signed-off-by: Josh Poimboeuf - -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2022-10-24 15:23:41.598216907 -0400 -+++ src/fs/nfsd/export.c 2022-10-24 15:23:52.404048315 -0400 -@@ -1294,6 +1294,10 @@ static void exp_flags(struct seq_file *m - } - } - -+#include -+extern char *kpatch_string(void); -+ -+__attribute__((optimize("-fno-optimize-sibling-calls"))) - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1301,12 +1305,36 @@ static int e_show(struct seq_file *m, vo - struct cache_detail *cd = m->private; - bool export_stats = is_export_stats_file(m); - -+#ifdef CONFIG_X86_64 -+ alternative("ud2", "call single_task_running", X86_FEATURE_ALWAYS); -+ alternative("call single_task_running", "ud2", X86_FEATURE_IA64); -+ -+ slow_down_io(); /* paravirt call */ -+#endif -+ -+ pr_debug("kpatch: pr_debug() test\n"); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) -+{ -+ static DEFINE_STATIC_KEY_TRUE(kpatch_key); -+ -+ if (static_branch_unlikely(&memcg_kmem_enabled_key)) -+ printk("kpatch: memcg_kmem_enabled_key\n"); -+ -+ BUG_ON(!static_branch_likely(&kpatch_key)); -+ static_branch_disable(&kpatch_key); -+ BUG_ON(static_branch_likely(&kpatch_key)); -+ static_branch_enable(&kpatch_key); -+} -+#endif -+ - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - if (export_stats) - seq_puts(m, "# Path Client Start-time\n#\tStats\n"); - else - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2022-10-24 15:23:43.112193286 -0400 -+++ src/net/netlink/af_netlink.c 2022-10-24 15:23:52.405048299 -0400 -@@ -2906,4 +2906,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/rhel-9.1/multiple.test b/test/integration/rhel-9.1/multiple.test deleted file mode 100755 index 7e4b352..0000000 --- a/test/integration/rhel-9.1/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(meminfo-string-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/rhel-9.1/new-function.patch b/test/integration/rhel-9.1/new-function.patch deleted file mode 100644 index 063a85b..0000000 --- a/test/integration/rhel-9.1/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2022-10-24 15:23:42.711199543 -0400 -+++ src/drivers/tty/n_tty.c 2022-10-24 15:23:55.216004443 -0400 -@@ -2253,7 +2253,7 @@ more_to_be_read: - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2340,6 +2340,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/rhel-9.1/new-globals.patch b/test/integration/rhel-9.1/new-globals.patch deleted file mode 100644 index 304bc6f..0000000 --- a/test/integration/rhel-9.1/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2022-10-24 15:23:41.612216689 -0400 -+++ src/fs/proc/cmdline.c 2022-10-24 15:23:58.224957497 -0400 -@@ -17,3 +17,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2022-10-24 15:23:41.612216689 -0400 -+++ src/fs/proc/meminfo.c 2022-10-24 15:23:58.224957497 -0400 -@@ -19,6 +19,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -55,6 +57,7 @@ static int meminfo_proc_show(struct seq_ - sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B); - sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B); - -+ kpatch_print_message(); - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); diff --git a/test/integration/rhel-9.1/shadow-newpid-LOADED.test b/test/integration/rhel-9.1/shadow-newpid-LOADED.test deleted file mode 100755 index c07d112..0000000 --- a/test/integration/rhel-9.1/shadow-newpid-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep -q newpid: /proc/$$/status diff --git a/test/integration/rhel-9.1/shadow-newpid.patch b/test/integration/rhel-9.1/shadow-newpid.patch deleted file mode 100644 index 132c69e..0000000 --- a/test/integration/rhel-9.1/shadow-newpid.patch +++ /dev/null @@ -1,75 +0,0 @@ -diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c ---- src.orig/fs/proc/array.c 2022-10-24 15:23:41.612216689 -0400 -+++ src/fs/proc/array.c 2022-10-24 15:24:00.901915731 -0400 -@@ -402,12 +402,19 @@ static inline void task_seccomp(struct s - seq_putc(m, '\n'); - } - -+#include - static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) - { -+ int *newpid; -+ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -+ -+ newpid = klp_shadow_get(p, 0); -+ if (newpid) -+ seq_printf(m, "newpid:\t%d\n", *newpid); - } - - static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c ---- src.orig/kernel/exit.c 2022-10-24 15:23:43.026194628 -0400 -+++ src/kernel/exit.c 2022-10-24 15:24:00.901915731 -0400 -@@ -725,6 +725,7 @@ static void check_stack_usage(void) - static inline void check_stack_usage(void) {} - #endif - -+#include - void __noreturn do_exit(long code) - { - struct task_struct *tsk = current; -@@ -826,6 +827,8 @@ void __noreturn do_exit(long code) - exit_task_work(tsk); - exit_thread(tsk); - -+ klp_shadow_free(tsk, 0, NULL); -+ - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-10-24 15:23:43.026194628 -0400 -+++ src/kernel/fork.c 2022-10-24 15:24:00.901915731 -0400 -@@ -2594,6 +2594,7 @@ struct task_struct *create_io_thread(int - * - * args->exit_signal is expected to be checked for sanity by the caller. - */ -+#include - pid_t kernel_clone(struct kernel_clone_args *args) - { - u64 clone_flags = args->flags; -@@ -2602,6 +2603,8 @@ pid_t kernel_clone(struct kernel_clone_a - struct task_struct *p; - int trace = 0; - pid_t nr; -+ int *newpid; -+ static int ctr = 0; - - /* - * For legacy clone() calls, CLONE_PIDFD uses the parent_tid argument -@@ -2641,6 +2644,11 @@ pid_t kernel_clone(struct kernel_clone_a - if (IS_ERR(p)) - return PTR_ERR(p); - -+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL, -+ NULL, NULL); -+ if (newpid) -+ *newpid = ctr++; -+ - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. diff --git a/test/integration/rhel-9.1/special-static.patch b/test/integration/rhel-9.1/special-static.patch deleted file mode 100644 index 67fedfc..0000000 --- a/test/integration/rhel-9.1/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2022-10-24 15:23:43.026194628 -0400 -+++ src/kernel/fork.c 2022-10-24 15:24:03.603873575 -0400 -@@ -1676,10 +1676,18 @@ static void posix_cpu_timers_init_group( - posix_cputimers_group_init(pct, cpu_limit); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/rhel-9.1/symvers-disagreement-FAIL.patch b/test/integration/rhel-9.1/symvers-disagreement-FAIL.patch deleted file mode 100644 index 70cc44f..0000000 --- a/test/integration/rhel-9.1/symvers-disagreement-FAIL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001 -From: Julien Thierry -Date: Wed, 6 May 2020 14:30:57 +0100 -Subject: [PATCH] Symbol version change - -This change causes: -1) Some exported symbols in drivers/base/core.c to see their CRCs - change. -2) Changes usb_get_dev() referencing a get_device() whose CRC has - changed, causing the symbol and the new CRC to be included in the - __version section of the final module. - -This makes the final module unloadable for the target kernel. - -See "Exported symbol versioning" of the patch author guide for more -detail. - ---- - drivers/base/core.c | 2 ++ - drivers/usb/core/usb.c | 2 ++ - 2 files changed, 4 insertions(+) - -diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c ---- src.orig/drivers/base/core.c 2022-10-24 15:23:41.659215956 -0400 -+++ src/drivers/base/core.c 2022-10-24 15:24:06.690825412 -0400 -@@ -34,6 +34,8 @@ - #include "base.h" - #include "power/power.h" - -+#include -+ - #ifdef CONFIG_SYSFS_DEPRECATED - #ifdef CONFIG_SYSFS_DEPRECATED_V2 - long sysfs_deprecated = 1; -diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c ---- src.orig/drivers/usb/core/usb.c 2022-10-24 15:23:42.721199387 -0400 -+++ src/drivers/usb/core/usb.c 2022-10-24 15:24:06.691825397 -0400 -@@ -697,6 +697,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); - */ - struct usb_device *usb_get_dev(struct usb_device *dev) - { -+ barrier(); -+ - if (dev) - get_device(&dev->dev); - return dev; diff --git a/test/integration/rhel-9.1/syscall-LOADED.test b/test/integration/rhel-9.1/syscall-LOADED.test deleted file mode 100755 index 3a2fd88..0000000 --- a/test/integration/rhel-9.1/syscall-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -uname -s | grep -q kpatch diff --git a/test/integration/rhel-9.1/syscall.patch b/test/integration/rhel-9.1/syscall.patch deleted file mode 100644 index d37e74c..0000000 --- a/test/integration/rhel-9.1/syscall.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c ---- src.orig/kernel/sys.c 2022-10-24 15:23:43.028194597 -0400 -+++ src/kernel/sys.c 2022-10-24 15:24:09.387783334 -0400 -@@ -1277,13 +1277,15 @@ static int override_release(char __user - return ret; - } - --SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -+#include "kpatch-syscall.h" -+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) - { - struct new_utsname tmp; - - down_read(&uts_sem); - memcpy(&tmp, utsname(), sizeof(tmp)); - up_read(&uts_sem); -+ strcat(tmp.sysname, ".kpatch"); - if (copy_to_user(name, &tmp, sizeof(tmp))) - return -EFAULT; - diff --git a/test/integration/rhel-9.1/warn-detect-FAIL.patch b/test/integration/rhel-9.1/warn-detect-FAIL.patch deleted file mode 100644 index edcf7be..0000000 --- a/test/integration/rhel-9.1/warn-detect-FAIL.patch +++ /dev/null @@ -1,9 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2022-10-24 15:23:41.539217828 -0400 -+++ src/arch/x86/kvm/x86.c 2022-10-24 15:24:12.085741241 -0400 -@@ -1,4 +1,5 @@ - // SPDX-License-Identifier: GPL-2.0-only -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/test-vagrant b/test/integration/test-vagrant deleted file mode 100755 index 22a93cd..0000000 --- a/test/integration/test-vagrant +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -SCRIPTDIR=$(readlink -f "$(dirname "$(type -p "${0}")")") -ROOTDIR=$(readlink -f "${SCRIPTDIR}/../..") -SLOWTEST=0 - -# shellcheck disable=SC1090 -source "${ROOTDIR}/test/integration/lib.sh" - -usage() -{ - echo "usage: $(basename "${0}") [options]" >&2 - echo "-h, --help This message" >&2 - echo "-s, --slow Run all of the tests" >&2 -} - -options="$(getopt -o hs -l "help,slow" -- "$@")" || "getopt failed" - -eval set -- "${options}" - -while [[ $# -gt 0 ]]; do - case "$1" in - -s|--slow) - SLOWTEST=1 - ;; - -h|--help) - usage - exit 0 - ;; - esac - shift -done - -declare -a distros=("fedora27" "centos7") - -ret=0 -for distro in "${distros[@]}"; do - kpatch_integration_tests_vagrant_distro "${distro}" "${ROOTDIR}/test/integration/vm-integration-run" "${SLOWTEST}" - rc=$? - ret=$((ret + rc)) -done -exit ${ret} diff --git a/test/integration/ubuntu-16.04/README b/test/integration/ubuntu-16.04/README deleted file mode 100644 index beab02d..0000000 --- a/test/integration/ubuntu-16.04/README +++ /dev/null @@ -1 +0,0 @@ -4.4.0-53-generic diff --git a/test/integration/ubuntu-16.04/bug-table-section.patch b/test/integration/ubuntu-16.04/bug-table-section.patch deleted file mode 100644 index 097a99b..0000000 --- a/test/integration/ubuntu-16.04/bug-table-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/proc_sysctl.c 2016-12-15 19:56:00.204000000 +0000 -@@ -301,6 +301,8 @@ void sysctl_head_put(struct ctl_table_he - - static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) - { -+ if (jiffies == 0) -+ printk("kpatch-test: testing __bug_table section changes\n"); - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) diff --git a/test/integration/ubuntu-16.04/cmdline-string-LOADED.test b/test/integration/ubuntu-16.04/cmdline-string-LOADED.test deleted file mode 100755 index a8e0a08..0000000 --- a/test/integration/ubuntu-16.04/cmdline-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep kpatch=1 /proc/cmdline diff --git a/test/integration/ubuntu-16.04/cmdline-string.patch b/test/integration/ubuntu-16.04/cmdline-string.patch deleted file mode 100644 index d8ca275..0000000 --- a/test/integration/ubuntu-16.04/cmdline-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/cmdline.c 2016-12-15 19:56:12.848000000 +0000 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - diff --git a/test/integration/ubuntu-16.04/data-new-LOADED.test b/test/integration/ubuntu-16.04/data-new-LOADED.test deleted file mode 100755 index 598b6bb..0000000 --- a/test/integration/ubuntu-16.04/data-new-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep "kpatch: 5" /proc/meminfo diff --git a/test/integration/ubuntu-16.04/data-new.patch b/test/integration/ubuntu-16.04/data-new.patch deleted file mode 100644 index 1b107c1..0000000 --- a/test/integration/ubuntu-16.04/data-new.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/meminfo.c 2016-12-15 19:56:17.076000000 +0000 -@@ -23,6 +23,8 @@ void __attribute__((weak)) arch_report_m - { - } - -+static int foo = 5; -+ - static int meminfo_proc_show(struct seq_file *m, void *v) - { - struct sysinfo i; -@@ -110,6 +112,7 @@ static int meminfo_proc_show(struct seq_ - "CmaTotal: %8lu kB\n" - "CmaFree: %8lu kB\n" - #endif -+ "kpatch: %d" - , - K(i.totalram), - K(i.freeram), -@@ -169,6 +172,7 @@ static int meminfo_proc_show(struct seq_ - , K(totalcma_pages) - , K(global_page_state(NR_FREE_CMA_PAGES)) - #endif -+ ,foo - ); - - hugetlb_report_meminfo(m); diff --git a/test/integration/ubuntu-16.04/data-read-mostly.patch b/test/integration/ubuntu-16.04/data-read-mostly.patch deleted file mode 100644 index d8b1ceb..0000000 --- a/test/integration/ubuntu-16.04/data-read-mostly.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c ---- src.orig/net/core/dev.c 2016-12-15 19:55:39.848000000 +0000 -+++ src/net/core/dev.c 2016-12-15 19:56:21.344000000 +0000 -@@ -3926,6 +3926,7 @@ ncls: - case RX_HANDLER_PASS: - break; - default: -+ printk("BUG!\n"); - BUG(); - } - } diff --git a/test/integration/ubuntu-16.04/fixup-section.patch b/test/integration/ubuntu-16.04/fixup-section.patch deleted file mode 100644 index c818b08..0000000 --- a/test/integration/ubuntu-16.04/fixup-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/fs/readdir.c b/fs/readdir.c -index ced679179cac..7fb338324582 100644 ---- a/fs/readdir.c -+++ b/fs/readdir.c -@@ -173,6 +173,7 @@ static int filldir(struct dir_context *ctx, const char *name, int namlen, - goto efault; - } - dirent = buf->current_dir; -+ asm("nop"); - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) diff --git a/test/integration/ubuntu-16.04/gcc-constprop.patch b/test/integration/ubuntu-16.04/gcc-constprop.patch deleted file mode 100644 index fbdf2e9..0000000 --- a/test/integration/ubuntu-16.04/gcc-constprop.patch +++ /dev/null @@ -1,16 +0,0 @@ -ensure timekeeping_forward_now.constprop.8 and -timekeeping_forward_now.constprop.9 are correlated. - -diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c ---- src.orig/kernel/time/timekeeping.c 2016-12-15 19:56:00.136000000 +0000 -+++ src/kernel/time/timekeeping.c 2016-12-15 19:56:30.496000000 +0000 -@@ -1148,6 +1148,9 @@ void do_gettimeofday(struct timeval *tv) - { - struct timespec64 now; - -+ if (!tv) -+ return; -+ - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; diff --git a/test/integration/ubuntu-16.04/gcc-isra.patch b/test/integration/ubuntu-16.04/gcc-isra.patch deleted file mode 100644 index 979fb9b..0000000 --- a/test/integration/ubuntu-16.04/gcc-isra.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c ---- src.orig/fs/proc/proc_sysctl.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/proc_sysctl.c 2016-12-15 19:56:34.800000000 +0000 -@@ -46,6 +46,7 @@ void proc_sys_poll_notify(struct ctl_tab - if (!poll) - return; - -+ printk("kpatch-test: testing gcc .isra function name mangling\n"); - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); - } diff --git a/test/integration/ubuntu-16.04/gcc-mangled-3.patch.disabled b/test/integration/ubuntu-16.04/gcc-mangled-3.patch.disabled deleted file mode 100644 index a72b19b..0000000 --- a/test/integration/ubuntu-16.04/gcc-mangled-3.patch.disabled +++ /dev/null @@ -1,19 +0,0 @@ -ensure that __cmpxchg_double_slab.isra.45 and -__cmpxchg_double_slab.isra.45.part.46 aren't correlated. - -Disabled: __flush_cpu_slab() is present in vmlinux.symtab but is optimized -out during kpatch builds - -diff -Nupr src.orig/mm/slub.c src/mm/slub.c ---- src.orig/mm/slub.c 2016-12-15 19:55:38.988000000 +0000 -+++ src/mm/slub.c 2016-12-15 19:56:39.068000000 +0000 -@@ -5531,6 +5531,9 @@ void get_slabinfo(struct kmem_cache *s, - int node; - struct kmem_cache_node *n; - -+ if (!jiffies) -+ printk("slabinfo\n"); -+ - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var-2.patch b/test/integration/ubuntu-16.04/gcc-static-local-var-2.patch deleted file mode 100644 index a9ca12b..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var-2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c ---- src.orig/mm/mmap.c 2016-12-15 19:55:38.992000000 +0000 -+++ src/mm/mmap.c 2016-12-15 19:56:43.684000000 +0000 -@@ -1547,6 +1548,9 @@ unsigned long mmap_region(struct file *f - struct rb_node **rb_link, *rb_parent; - unsigned long charged = 0; - -+ if (!jiffies) -+ printk("kpatch mmap foo\n"); -+ - /* Check against address space limit. */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) { - unsigned long nr_pages; diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var-3.patch b/test/integration/ubuntu-16.04/gcc-static-local-var-3.patch deleted file mode 100644 index 270e3d3..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var-3.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c ---- src.orig/kernel/reboot.c 2016-12-15 19:56:00.196000000 +0000 -+++ src/kernel/reboot.c 2016-12-15 19:56:48.264000000 +0000 -@@ -366,8 +366,15 @@ SYSCALL_DEFINE4(reboot, int, magic1, int - return ret; - } - -+void kpatch_bar(void) -+{ -+ if (!jiffies) -+ printk("kpatch_foo\n"); -+} -+ - static void deferred_cad(struct work_struct *dummy) - { -+ kpatch_bar(); - kernel_restart(NULL); - } - diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var-4.patch b/test/integration/ubuntu-16.04/gcc-static-local-var-4.patch deleted file mode 100644 index 48fa8c4..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var-4.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff -Nupr src.orig/fs/aio.c src/fs/aio.c ---- src.orig/fs/aio.c 2016-12-15 19:55:38.992000000 +0000 -+++ src/fs/aio.c 2016-12-15 19:56:52.588000000 +0000 -@@ -271,9 +271,16 @@ static int __init aio_setup(void) - } - __initcall(aio_setup); - -+void kpatch_aio_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch aio foo\n"); -+} -+ - static void put_aio_ring_file(struct kioctx *ctx) - { - struct file *aio_ring_file = ctx->aio_ring_file; -+ kpatch_aio_foo(); - if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); - diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var-4.test b/test/integration/ubuntu-16.04/gcc-static-local-var-4.test deleted file mode 100755 index e085f93..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var-4.test +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -o pipefail -if ! $(eu-readelf --wide --symbols test-gcc-static-local-var-4.ko | awk '$NF == "free_ioctx" { exit 1 }'); then - exit 1 -else - exit 0 -fi diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var-5.patch b/test/integration/ubuntu-16.04/gcc-static-local-var-5.patch deleted file mode 100644 index 2463454..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var-5.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c ---- src.orig/kernel/audit.c 2016-12-15 19:56:00.196000000 +0000 -+++ src/kernel/audit.c 2016-12-15 19:56:56.868000000 +0000 -@@ -213,6 +213,12 @@ void audit_panic(const char *message) - } - } - -+void kpatch_audit_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch audit foo\n"); -+} -+ - static inline int audit_rate_check(void) - { - static unsigned long last_check = 0; -@@ -223,6 +229,7 @@ static inline int audit_rate_check(void) - unsigned long elapsed; - int retval = 0; - -+ kpatch_audit_foo(); - if (!audit_rate_limit) return 1; - - spin_lock_irqsave(&lock, flags); -@@ -242,6 +249,11 @@ static inline int audit_rate_check(void) - return retval; - } - -+noinline void kpatch_audit_check(void) -+{ -+ audit_rate_check(); -+} -+ - /** - * audit_log_lost - conditionally log lost audit message event - * @message: the message stating reason for lost audit message -@@ -288,6 +300,8 @@ static int audit_log_config_change(char - struct audit_buffer *ab; - int rc = 0; - -+ kpatch_audit_check(); -+ - ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE); - if (unlikely(!ab)) - return rc; diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var-6.patch b/test/integration/ubuntu-16.04/gcc-static-local-var-6.patch deleted file mode 100644 index 20aff19..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var-6.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c -index 39970e2..85e750d 100644 ---- a/net/ipv6/netfilter.c -+++ b/net/ipv6/netfilter.c -@@ -108,6 +108,8 @@ static int nf_ip6_reroute(struct net *net, struct sk_buff *skb, - return 0; - } - -+#include "kpatch-macros.h" -+ - static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict) - { -@@ -121,6 +123,9 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, - struct dst_entry *result; - int err; - -+ if (!jiffies) -+ printk("kpatch nf_ip6_route foo\n"); -+ - result = ip6_route_output(net, sk, &fl->u.ip6); - err = result->error; - if (err) diff --git a/test/integration/ubuntu-16.04/gcc-static-local-var.patch b/test/integration/ubuntu-16.04/gcc-static-local-var.patch deleted file mode 100644 index fa1ee7c..0000000 --- a/test/integration/ubuntu-16.04/gcc-static-local-var.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/arch/x86/kernel/ldt.c src/arch/x86/kernel/ldt.c ---- src.orig/arch/x86/kernel/ldt.c 2016-12-15 19:55:57.560000000 +0000 -+++ src/arch/x86/kernel/ldt.c 2016-12-15 19:57:01.124000000 +0000 -@@ -99,6 +99,12 @@ static void free_ldt_struct(struct ldt_s - kfree(ldt); - } - -+void hi_there(void) -+{ -+ if (!jiffies) -+ printk("hi there\n"); -+} -+ - /* - * we do not have to muck with descriptors here, that is - * done in switch_mm() as needed. -@@ -109,6 +115,8 @@ int init_new_context(struct task_struct - struct mm_struct *old_mm; - int retval = 0; - -+ hi_there(); -+ - mutex_init(&mm->context.lock); - old_mm = current->mm; - if (!old_mm) { diff --git a/test/integration/ubuntu-16.04/macro-callbacks.patch b/test/integration/ubuntu-16.04/macro-callbacks.patch deleted file mode 100644 index 569cc7c..0000000 --- a/test/integration/ubuntu-16.04/macro-callbacks.patch +++ /dev/null @@ -1,163 +0,0 @@ -kpatch/livepatch callback test patch: - - vmlinux - pcspkr (mod) - joydev (mod) - -Note: update joydev's pre-patch callback to return -ENODEV to test failure path - -diff -Nupr src.old/drivers/input/joydev.c src/drivers/input/joydev.c ---- src.old/drivers/input/joydev.c 2017-09-03 16:56:17.000000000 -0400 -+++ src/drivers/input/joydev.c 2018-03-22 16:32:40.963082354 -0400 -@@ -1010,3 +1010,47 @@ static void __exit joydev_exit(void) - - module_init(joydev_init); - module_exit(joydev_exit); -+ -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; /* return -ENODEV; */ -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.old/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c ---- src.old/drivers/input/misc/pcspkr.c 2018-03-22 16:29:27.716082354 -0400 -+++ src/drivers/input/misc/pcspkr.c 2018-03-22 16:32:40.963082354 -0400 -@@ -132,3 +132,46 @@ static struct platform_driver pcspkr_pla - }; - module_platform_driver(pcspkr_platform_driver); - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -diff -Nupr src.old/fs/aio.c src/fs/aio.c ---- src.old/fs/aio.c 2017-09-03 16:56:17.000000000 -0400 -+++ src/fs/aio.c 2018-03-22 16:32:40.962082354 -0400 -@@ -46,6 +46,50 @@ - - #include "internal.h" - -+#include -+#include "kpatch-macros.h" -+ -+static const char *const module_state[] = { -+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state", -+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init", -+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away", -+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up", -+}; -+ -+static void callback_info(const char *callback, patch_object *obj) -+{ -+ if (obj->mod) -+ pr_info("%s: %s -> %s\n", callback, obj->mod->name, -+ module_state[obj->mod->state]); -+ else -+ pr_info("%s: vmlinux\n", callback); -+} -+ -+static int pre_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+ return 0; -+} -+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback); -+ -+static void post_patch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_PATCH_CALLBACK(post_patch_callback); -+ -+static void pre_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback); -+ -+static void post_unpatch_callback(patch_object *obj) -+{ -+ callback_info(__func__, obj); -+} -+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback); -+ - #define AIO_RING_MAGIC 0xa10a10a1 - #define AIO_RING_COMPAT_FEATURES 1 - #define AIO_RING_INCOMPAT_FEATURES 0 diff --git a/test/integration/ubuntu-16.04/macro-printk.patch b/test/integration/ubuntu-16.04/macro-printk.patch deleted file mode 100644 index e0eb7d4..0000000 --- a/test/integration/ubuntu-16.04/macro-printk.patch +++ /dev/null @@ -1,148 +0,0 @@ -Index: src/net/ipv4/fib_frontend.c -=================================================================== ---- src.orig/net/ipv4/fib_frontend.c -+++ src/net/ipv4/fib_frontend.c -@@ -728,6 +728,7 @@ errout: - return err; - } - -+#include "kpatch-macros.h" - static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) - { - struct net *net = sock_net(skb->sk); -@@ -746,6 +747,7 @@ static int inet_rtm_newroute(struct sk_b - } - - err = fib_table_insert(tb, &cfg); -+ KPATCH_PRINTK("[inet_rtm_newroute]: err is %d\n", err); - errout: - return err; - } -Index: src/net/ipv4/fib_semantics.c -=================================================================== ---- src.orig/net/ipv4/fib_semantics.c -+++ src/net/ipv4/fib_semantics.c -@@ -998,6 +998,7 @@ fib_convert_metrics(struct fib_info *fi, - return 0; - } - -+#include "kpatch-macros.h" - struct fib_info *fib_create_info(struct fib_config *cfg) - { - int err; -@@ -1025,6 +1026,7 @@ struct fib_info *fib_create_info(struct - #endif - - err = -ENOBUFS; -+ KPATCH_PRINTK("[fib_create_info]: create error err is %d\n",err); - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; -@@ -1045,6 +1047,7 @@ struct fib_info *fib_create_info(struct - if (!fib_info_hash_size) - goto failure; - } -+ KPATCH_PRINTK("[fib_create_info]: 2 create error err is %d\n",err); - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) -@@ -1059,6 +1062,7 @@ struct fib_info *fib_create_info(struct - } else { - fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; - } -+ KPATCH_PRINTK("[fib_create_info]: 3 create error err is %d\n",err); - fib_info_cnt++; - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; -@@ -1075,6 +1079,7 @@ struct fib_info *fib_create_info(struct - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 4 create error err is %d\n",err); - - err = fib_convert_metrics(fi, cfg); - if (err) -@@ -1127,6 +1132,8 @@ struct fib_info *fib_create_info(struct - nh->nh_weight = 1; - #endif - } -+ KPATCH_PRINTK("[fib_create_info]: 5 create error err is %d\n",err); -+ KPATCH_PRINTK("[fib_create_info]: 6 create error err is %d\n",err); - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) -@@ -1144,6 +1151,7 @@ struct fib_info *fib_create_info(struct - goto err_inval; - } - } -+ KPATCH_PRINTK("[fib_create_info]: 7 create error err is %d\n",err); - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; -@@ -1172,6 +1180,7 @@ struct fib_info *fib_create_info(struct - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } -+ KPATCH_PRINTK("[fib_create_info]: 8 create error err is %d\n",err); - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) - goto err_inval; -@@ -1180,6 +1189,7 @@ struct fib_info *fib_create_info(struct - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) -+ KPATCH_PRINTK("[fib_create_info]: 9 create error err is %d\n",err); - - fib_rebalance(fi); - -@@ -1191,6 +1201,7 @@ link_it: - ofi->fib_treeref++; - return ofi; - } -+ KPATCH_PRINTK("[fib_create_info]: 10 create error err is %d\n",err); - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); -@@ -1214,6 +1225,7 @@ link_it: - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); -+ KPATCH_PRINTK("[fib_create_info]: 11 create error err is %d\n",err); - return fi; - - err_inval: -@@ -1224,6 +1236,7 @@ failure: - fi->fib_dead = 1; - free_fib_info(fi); - } -+ KPATCH_PRINTK("[fib_create_info]: 12 create error err is %d\n",err); - - return ERR_PTR(err); - } -Index: src/net/ipv4/fib_trie.c -=================================================================== ---- src.orig/net/ipv4/fib_trie.c -+++ src/net/ipv4/fib_trie.c -@@ -1078,6 +1078,7 @@ static int fib_insert_alias(struct trie - } - - /* Caller must hold RTNL. */ -+#include "kpatch-macros.h" - int fib_table_insert(struct fib_table *tb, struct fib_config *cfg) - { - struct trie *t = (struct trie *)tb->tb_data; -@@ -1101,11 +1102,14 @@ int fib_table_insert(struct fib_table *t - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - -+ KPATCH_PRINTK("[fib_table_insert]: start\n"); - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); -+ KPATCH_PRINTK("[fib_table_insert]: create error err is %d\n",err); - goto err; - } -+ KPATCH_PRINTK("[fib_table_insert]: cross\n"); - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, diff --git a/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled b/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled deleted file mode 100755 index e2b647d..0000000 --- a/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo && grep kpatch=1 /proc/cmdline diff --git a/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW.patch.disabled b/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW.patch.disabled deleted file mode 100644 index 664b9b3..0000000 --- a/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW.patch.disabled +++ /dev/null @@ -1,42 +0,0 @@ -Disabled: -kpatch-build currently fails with "invalid ancestor" error. This happens -with at least drivers/gpu/drm/i2c/adv7511.o and drivers/hwmon/htu21.o -files. The problem is their .ko counterparts are never built for some -reason, This looks like a kernel bug since in both cases there are files -with same name but in different paths that have .ko module built. ---- -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/cmdline.c 2016-12-15 19:57:13.988000000 +0000 -@@ -5,7 +5,7 @@ - - static int cmdline_proc_show(struct seq_file *m, void *v) - { -- seq_printf(m, "%s\n", saved_command_line); -+ seq_printf(m, "%s kpatch=1\n", saved_command_line); - return 0; - } - -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/meminfo.c 2016-12-15 19:57:13.988000000 +0000 -@@ -99,7 +99,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" - #endif -diff -Nupr src.orig/include/linux/kernel.h src/include/linux/kernel.h ---- src.orig/include/linux/kernel.h 2016-12-15 19:55:56.996000000 +0000 -+++ src/include/linux/kernel.h 2016-12-15 19:57:13.992000000 +0000 -@@ -2,6 +2,7 @@ - #define _LINUX_KERNEL_H - - -+ - #include - #include - #include diff --git a/test/integration/ubuntu-16.04/meminfo-init-FAIL.patch b/test/integration/ubuntu-16.04/meminfo-init-FAIL.patch deleted file mode 100644 index c7a2cdd..0000000 --- a/test/integration/ubuntu-16.04/meminfo-init-FAIL.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/meminfo.c 2016-12-15 19:57:22.564000000 +0000 -@@ -193,6 +193,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/ubuntu-16.04/meminfo-init2-FAIL.patch b/test/integration/ubuntu-16.04/meminfo-init2-FAIL.patch deleted file mode 100644 index 8763fc0..0000000 --- a/test/integration/ubuntu-16.04/meminfo-init2-FAIL.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/meminfo.c 2016-12-15 19:57:18.240000000 +0000 -@@ -32,6 +32,7 @@ static int meminfo_proc_show(struct seq_ - unsigned long pages[NR_LRU_LISTS]; - int lru; - -+ printk("a\n"); - /* - * display in kilobytes. - */ -@@ -193,6 +194,7 @@ static const struct file_operations memi - - static int __init proc_meminfo_init(void) - { -+ printk("a\n"); - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; - } diff --git a/test/integration/ubuntu-16.04/meminfo-string-LOADED.test b/test/integration/ubuntu-16.04/meminfo-string-LOADED.test deleted file mode 100755 index 10dc20b..0000000 --- a/test/integration/ubuntu-16.04/meminfo-string-LOADED.test +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -grep VMALLOCCHUNK /proc/meminfo diff --git a/test/integration/ubuntu-16.04/meminfo-string.patch b/test/integration/ubuntu-16.04/meminfo-string.patch deleted file mode 100644 index 3dd2731..0000000 --- a/test/integration/ubuntu-16.04/meminfo-string.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/meminfo.c 2016-12-15 19:57:26.828000000 +0000 -@@ -99,7 +99,7 @@ static int meminfo_proc_show(struct seq_ - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" -- "VmallocChunk: %8lu kB\n" -+ "VMALLOCCHUNK: %8lu kB\n" - #ifdef CONFIG_MEMORY_FAILURE - "HardwareCorrupted: %5lu kB\n" - #endif diff --git a/test/integration/ubuntu-16.04/module-call-external.patch.disable b/test/integration/ubuntu-16.04/module-call-external.patch.disable deleted file mode 100644 index b9f51a7..0000000 --- a/test/integration/ubuntu-16.04/module-call-external.patch.disable +++ /dev/null @@ -1,38 +0,0 @@ -Disabled: -Original build includes "kzalloc" in af_netlink.c's symbol list, this -does not happen during kpatch build so create-diff-object fails with -find_local_syms. ---- -diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c ---- src.orig/fs/nfsd/export.c 2016-12-15 19:55:39.012000000 +0000 -+++ src/fs/nfsd/export.c 2016-12-15 19:57:31.068000000 +0000 -@@ -1183,6 +1183,8 @@ static void exp_flags(struct seq_file *m - } - } - -+extern char *kpatch_string(void); -+ - static int e_show(struct seq_file *m, void *p) - { - struct cache_head *cp = p; -@@ -1192,6 +1194,7 @@ static int e_show(struct seq_file *m, vo - if (p == SEQ_START_TOKEN) { - seq_puts(m, "# Version 1.1\n"); - seq_puts(m, "# Path Client(Flags) # IPs\n"); -+ seq_puts(m, kpatch_string()); - return 0; - } - -diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c ---- src.orig/net/netlink/af_netlink.c 2016-12-15 19:55:39.772000000 +0000 -+++ src/net/netlink/af_netlink.c 2016-12-15 19:57:31.072000000 +0000 -@@ -3353,4 +3353,9 @@ panic: - panic("netlink_init: Cannot allocate nl_table\n"); - } - -+char *kpatch_string(void) -+{ -+ return "# kpatch\n"; -+} -+ - core_initcall(netlink_proto_init); diff --git a/test/integration/ubuntu-16.04/module-kvm-fixup.patch b/test/integration/ubuntu-16.04/module-kvm-fixup.patch deleted file mode 100644 index d1130fd..0000000 --- a/test/integration/ubuntu-16.04/module-kvm-fixup.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/vmx.c src/arch/x86/kvm/vmx.c ---- src.orig/arch/x86/kvm/vmx.c 2016-12-15 19:55:57.436000000 +0000 -+++ src/arch/x86/kvm/vmx.c 2016-12-15 19:57:35.344000000 +0000 -@@ -10574,6 +10574,8 @@ static int vmx_check_intercept(struct kv - struct x86_instruction_info *info, - enum x86_intercept_stage stage) - { -+ if (!jiffies) -+ printk("kpatch vmx_check_intercept\n"); - return X86EMUL_CONTINUE; - } - diff --git a/test/integration/ubuntu-16.04/multiple.test b/test/integration/ubuntu-16.04/multiple.test deleted file mode 100755 index 70a3df3..0000000 --- a/test/integration/ubuntu-16.04/multiple.test +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" - -declare -a blacklist=(data-new-LOADED.test meminfo-cmdline-rebuild-SLOW-LOADED.test) - -source ${SCRIPTDIR}/../common/multiple.template diff --git a/test/integration/ubuntu-16.04/new-function.patch b/test/integration/ubuntu-16.04/new-function.patch deleted file mode 100644 index 1f36531..0000000 --- a/test/integration/ubuntu-16.04/new-function.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c ---- src.orig/drivers/tty/n_tty.c 2016-12-15 19:55:54.840000000 +0000 -+++ src/drivers/tty/n_tty.c 2016-12-15 19:57:43.856000000 +0000 -@@ -2328,7 +2328,7 @@ static ssize_t n_tty_read(struct tty_str - * lock themselves) - */ - --static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) - { - const unsigned char *b = buf; -@@ -2415,6 +2415,12 @@ break_out: - return (b - buf) ? b - buf : retval; - } - -+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, -+ const unsigned char *buf, size_t nr) -+{ -+ return kpatch_n_tty_write(tty, file, buf, nr); -+} -+ - /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device diff --git a/test/integration/ubuntu-16.04/new-globals.patch b/test/integration/ubuntu-16.04/new-globals.patch deleted file mode 100644 index 0beef3e..0000000 --- a/test/integration/ubuntu-16.04/new-globals.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c ---- src.orig/fs/proc/cmdline.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/cmdline.c 2016-12-15 19:57:48.084000000 +0000 -@@ -27,3 +27,10 @@ static int __init proc_cmdline_init(void - return 0; - } - fs_initcall(proc_cmdline_init); -+ -+#include -+void kpatch_print_message(void) -+{ -+ if (!jiffies) -+ printk("hello there!\n"); -+} -diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c ---- src.orig/fs/proc/meminfo.c 2016-12-15 19:55:39.084000000 +0000 -+++ src/fs/proc/meminfo.c 2016-12-15 19:57:48.084000000 +0000 -@@ -19,6 +19,8 @@ - #include - #include "internal.h" - -+void kpatch_print_message(void); -+ - void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) - { - } -@@ -53,6 +55,7 @@ static int meminfo_proc_show(struct seq_ - /* - * Tagged format, for easy grepping and expansion. - */ -+ kpatch_print_message(); - seq_printf(m, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" diff --git a/test/integration/ubuntu-16.04/parainstructions-section.patch b/test/integration/ubuntu-16.04/parainstructions-section.patch deleted file mode 100644 index 2fd39c3..0000000 --- a/test/integration/ubuntu-16.04/parainstructions-section.patch +++ /dev/null @@ -1,11 +0,0 @@ -diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c ---- src.orig/fs/proc/generic.c 2016-12-15 19:55:39.076000000 +0000 -+++ src/fs/proc/generic.c 2016-12-15 19:57:52.340000000 +0000 -@@ -195,6 +195,7 @@ int proc_alloc_inum(unsigned int *inum) - unsigned int i; - int error; - -+ printk("kpatch-test: testing change to .parainstructions section\n"); - retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; diff --git a/test/integration/ubuntu-16.04/replace-section-references.patch b/test/integration/ubuntu-16.04/replace-section-references.patch deleted file mode 100644 index 7fc29db..0000000 --- a/test/integration/ubuntu-16.04/replace-section-references.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2016-12-15 19:55:57.436000000 +0000 -+++ src/arch/x86/kvm/x86.c 2016-12-15 19:57:56.596000000 +0000 -@@ -230,6 +230,8 @@ static void shared_msr_update(unsigned s - - void kvm_define_shared_msr(unsigned slot, u32 msr) - { -+ if (!jiffies) -+ printk("kpatch kvm define shared msr\n"); - BUG_ON(slot >= KVM_NR_SHARED_MSRS); - shared_msrs_global.msrs[slot] = msr; - if (slot >= shared_msrs_global.nr) diff --git a/test/integration/ubuntu-16.04/smp-locks-section.patch b/test/integration/ubuntu-16.04/smp-locks-section.patch deleted file mode 100644 index 9d5a4e8..0000000 --- a/test/integration/ubuntu-16.04/smp-locks-section.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c ---- src.orig/drivers/tty/tty_buffer.c 2016-12-15 19:55:54.840000000 +0000 -+++ src/drivers/tty/tty_buffer.c 2016-12-15 19:58:05.088000000 +0000 -@@ -255,6 +255,8 @@ static int __tty_buffer_request_room(str - struct tty_buffer *b, *n; - int left, change; - -+ if (!size) -+ printk("kpatch-test: testing .smp_locks section changes\n"); - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; diff --git a/test/integration/ubuntu-16.04/special-static-2.patch b/test/integration/ubuntu-16.04/special-static-2.patch deleted file mode 100644 index fef67f4..0000000 --- a/test/integration/ubuntu-16.04/special-static-2.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2016-12-15 19:55:57.436000000 +0000 -+++ src/arch/x86/kvm/x86.c 2016-12-15 19:58:09.352000000 +0000 -@@ -2026,12 +2026,20 @@ static void record_steal_time(struct kvm - &vcpu->arch.st.steal, sizeof(struct kvm_steal_time)); - } - -+void kpatch_kvm_x86_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch kvm x86 foo\n"); -+} -+ - int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) - { - bool pr = false; - u32 msr = msr_info->index; - u64 data = msr_info->data; - -+ kpatch_kvm_x86_foo(); -+ - switch (msr) { - case MSR_AMD64_NB_CFG: - case MSR_IA32_UCODE_REV: diff --git a/test/integration/ubuntu-16.04/special-static.patch b/test/integration/ubuntu-16.04/special-static.patch deleted file mode 100644 index 7d96d57..0000000 --- a/test/integration/ubuntu-16.04/special-static.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c ---- src.orig/kernel/fork.c 2016-12-15 19:56:00.184000000 +0000 -+++ src/kernel/fork.c 2016-12-15 19:58:13.588000000 +0000 -@@ -1143,10 +1143,18 @@ static void posix_cpu_timers_init_group( - INIT_LIST_HEAD(&sig->cpu_timers[2]); - } - -+void kpatch_foo(void) -+{ -+ if (!jiffies) -+ printk("kpatch copy signal\n"); -+} -+ - static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) - { - struct signal_struct *sig; - -+ kpatch_foo(); -+ - if (clone_flags & CLONE_THREAD) - return 0; - diff --git a/test/integration/ubuntu-16.04/tracepoints-section.patch b/test/integration/ubuntu-16.04/tracepoints-section.patch deleted file mode 100644 index cea83e6..0000000 --- a/test/integration/ubuntu-16.04/tracepoints-section.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c ---- src.orig/kernel/time/timer.c 2016-01-10 23:01:32.000000000 +0000 -+++ src/kernel/time/timer.c 2016-12-15 20:27:00.368000000 +0000 -@@ -1433,6 +1433,9 @@ static void run_timer_softirq(struct sof - { - struct tvec_base *base = this_cpu_ptr(&tvec_bases); - -+ if (!base) -+ printk("kpatch-test: testing __tracepoints section changes\n"); -+ - if (time_after_eq(jiffies, base->timer_jiffies)) - __run_timers(base); - } diff --git a/test/integration/ubuntu-16.04/warn-detect-FAIL.patch b/test/integration/ubuntu-16.04/warn-detect-FAIL.patch deleted file mode 100644 index a78ca9d..0000000 --- a/test/integration/ubuntu-16.04/warn-detect-FAIL.patch +++ /dev/null @@ -1,8 +0,0 @@ -diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c ---- src.orig/arch/x86/kvm/x86.c 2016-12-15 19:55:57.436000000 +0000 -+++ src/arch/x86/kvm/x86.c 2016-12-15 19:58:17.844000000 +0000 -@@ -1,3 +1,4 @@ -+ - /* - * Kernel-based Virtual Machine driver for Linux - * diff --git a/test/integration/vm-integration-run b/test/integration/vm-integration-run deleted file mode 100755 index d5cb560..0000000 --- a/test/integration/vm-integration-run +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -KPATCH_SLOW=0 -KPATCH_GIT=${KPATCH_GIT:-https://github.com/dynup/kpatch.git} -KPATCH_REV=${KPATCH_REV:-HEAD} -LOGDIR="/vagrant/logs" - -usage() -{ - echo "usage: $(basename "${0}") [options]" >&2 - echo "-h, --help This message" >&2 - echo "-s, --slow Run all of the tests" >&2 - echo "-g, --git Git url to clone from" >&2 - echo "-r, --revision Revision to use (HEAD by default)" >&2 -} - -options="$(getopt -o "shg:r:" -l "slow,help,git:,revision:" -- "$@")" || "getopt failed" - -eval set -- "${options}" - -while [[ $# -gt 0 ]]; do - case "$1" in - -s|--slow) - KPATCH_SLOW=1 - shift - ;; - -g|--git) - KPATCH_GIT="${2}" - shift 2 - ;; - -r|--revision) - KPATCH_REV="${2}" - shift 2 - ;; - -h|--help) - usage - exit 0 - ;; - --) - shift - break - ;; - esac -done - -git clone "${KPATCH_GIT}" || exit 1 - -cd kpatch || exit 1 - -git fetch origin +refs/pull/*:refs/pull/* -git reset --hard "${KPATCH_REV}" || exit 1 - -# shellcheck disable=SC1091 -source test/integration/lib.sh - -kpatch_dependencies -kpatch_separate_disk_cache /dev/vdb /mnt/build -kpatch_set_ccache_max_size 10G - -# Check if we have predownloaded sources and move them to ~/.kpatch dir which -# is a symlink to a dir on a separate (bigger) volume, suitable for building. -if [[ -d "${HOME}/src" && -f "${HOME}/src/version" ]]; then - cp "${HOME}/src/version" "${HOME}/.kpatch/" - mv "${HOME}/src" "${HOME}/.kpatch/" -fi - -# shellcheck disable=SC1091 -source /etc/os-release - -if [[ "${NAME}" == "Fedora" ]] && [[ "${VERSION_ID}" -lt 30 ]]; then - export BUILDMOD=yes -fi - -if [ ${KPATCH_SLOW} -eq 1 ]; then - make integration-slow 2>&1 -else - make integration-quick 2>&1 -fi - -rc=${PIPESTATUS[0]} -rm -rf "${LOGDIR}" -mkdir -p "${LOGDIR}" -cp ./test/integration/*.log "${LOGDIR}" - -exit "${rc}" diff --git a/test/test-functions.sh b/test/test-functions.sh deleted file mode 100644 index 96fa9a7..0000000 --- a/test/test-functions.sh +++ /dev/null @@ -1,12 +0,0 @@ -FILE=$1 - -assert_num_funcs() { - local num_funcs=$(nm $FILE | grep -i " t " | wc -l) - - if [[ $num_funcs != $1 ]]; then - echo "$FILE: assertion failed: file has $num_funcs funcs, expected $1" 1>&2 - exit 1 - fi - - return 0 -} diff --git a/test/unit/Makefile b/test/unit/Makefile deleted file mode 100644 index e3ed7d7..0000000 --- a/test/unit/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -ARCHES ?= aarch64 ppc64le x86_64 - -.PHONY: all clean submodule-check - -all: $(addsuffix -test,$(ARCHES)) -clean: $(addsuffix -clean,$(ARCHES)) - -submodule-check: - @cd $(shell git rev-parse --show-toplevel) && \ - git diff-index --quiet HEAD test/unit/objs || \ - echo -e "\nWARNING: unit tests are out of date - run \"git submodule update\"\n" - -%-test: Makefile.include submodule-check - $(MAKE) -C objs/$* - -%-clean: Makefile.include - if [ -d objs/$* ]; then $(MAKE) -C objs/$* clean; fi diff --git a/test/unit/Makefile.include b/test/unit/Makefile.include deleted file mode 100644 index e971743..0000000 --- a/test/unit/Makefile.include +++ /dev/null @@ -1,73 +0,0 @@ -EXT_ORIG ?= ORIG.o -EXT_PATCHED ?= PATCHED.o -EXT_FAIL ?= PATCHED.FAIL.o -EXT_TEST ?= test -EXT_OUTPUT ?= OUTPUT.o -EXT_TEST_OUTPUT ?= test.out -EXT_SYMTAB ?= symtab -EXT_SYMVERS ?= symvers -EXT_ENV ?= env -TNAME = $(@:.$(EXT_OUTPUT)=) - -ifndef VERBOSE -MUTE_PASS := >/dev/null -MUTE_FAIL := >/dev/null 2>&1 -.SILENT: $(TARGETS) $(TEST_TARGETS) -endif - -SRC_PATH ?= $(realpath ../../../../) -CDO ?= $(SRC_PATH)/kpatch-build/create-diff-object -TEST_LIBRARY ?= $(SRC_PATH)/test/test-functions.sh - -TEST_ENV = KPATCH_TEST_LIBRARY=$(TEST_LIBRARY) - -TARGETS = $(patsubst %.$(EXT_ORIG),%.$(EXT_OUTPUT),$(wildcard *.$(EXT_ORIG))) -TEST_TARGETS = $(patsubst %.$(EXT_TEST),%.$(EXT_TEST_OUTPUT),$(wildcard *.$(EXT_TEST))) - -SYMVERS_FILE = $(if $(wildcard $(TNAME).$(EXT_SYMVERS)),$(TNAME).$(EXT_SYMVERS),/dev/null) - -define check_stripped = - $(if $(shell readelf --debug-dump $(1)), - $(error $(1) is not properly stripped, use 'strip --strip-debug --keep-file-symbols --remove-section=.eh_frame $(1)' to fix this), - ) -endef - -define check_all = - $(if $(findstring NOSTRIP,$(1)), , $(call check_stripped,$(1))) -endef - -.DELETE_ON_ERROR: %.$(EXT_OUTPUT) - -all: $(TARGETS) $(TEST_TARGETS) - -clean: - rm -f *.$(EXT_TEST_OUTPUT) *.$(EXT_OUTPUT) - -%.$(EXT_SYMTAB): - readelf -s --wide $(patsubst %.$(EXT_SYMTAB),%.$(EXT_ORIG),$(@)) | \ - sed -r 's/\s+\[: 8\]//' >$@ - -%.$(EXT_TEST_OUTPUT): %.$(EXT_OUTPUT) %.$(EXT_TEST) $(TEST_LIBRARY) - @echo "TEST $(@:.$(EXT_TEST_OUTPUT)=)" - $(TEST_ENV) bash $(@:.$(EXT_TEST_OUTPUT)=.$(EXT_TEST)) $< -# Don't rely on script creating this - @touch $@ - -%.$(EXT_OUTPUT): %.$(EXT_ORIG) %.$(EXT_PATCHED) %.$(EXT_SYMTAB) $(CDO) - @echo "BUILD $(TNAME)" - $(call check_all,$(TNAME).$(EXT_ORIG)) - $(call check_all,$(TNAME).$(EXT_PATCHED)) - $(CDO_ENV) $(shell cat $(TNAME).$(EXT_ENV) 2>/dev/null) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_PATCHED) \ - vmlinux $(TNAME).$(EXT_SYMTAB) $(SYMVERS_FILE) \ - test_$(TNAME) $@ $(MUTE_PASS) - -%.$(EXT_OUTPUT): %.$(EXT_ORIG) %.$(EXT_FAIL) %.$(EXT_SYMTAB) $(CDO) - @echo "BUILD $(TNAME)-FAIL" - $(call check_all,$(TNAME).$(EXT_ORIG)) - $(call check_all,$(TNAME).$(EXT_FAIL)) - ! $(CDO_ENV) $(shell cat $(TNAME).$(EXT_ENV) 2>/dev/null) $(CDO) $(TNAME).$(EXT_ORIG) $(TNAME).$(EXT_FAIL) \ - vmlinux $(TNAME).$(EXT_SYMTAB) $(SYMVERS_FILE) \ - test_$(TNAME) $@ $(MUTE_FAIL) -# Expecting to fail, thus create output file manually so we won't rerun the -# test without clean - @touch $@ diff --git a/v0.9.9.tar.gz b/v0.9.9.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..adb11597b4d1df5fe2852ca5d13ed3b50d031872 GIT binary patch literal 3282944 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 z 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 literal 0 HcmV?d00001 -- Gitee