pax_global_header00006660000000000000000000000064147437465740014537gustar00rootroot0000000000000052 comment=903dfe2b644ec41d9b4bc50344fdadf9664e948f kpatch-0.9.10/000077500000000000000000000000001474374657400131005ustar00rootroot00000000000000kpatch-0.9.10/.github/000077500000000000000000000000001474374657400144405ustar00rootroot00000000000000kpatch-0.9.10/.github/workflows/000077500000000000000000000000001474374657400164755ustar00rootroot00000000000000kpatch-0.9.10/.github/workflows/stale.yml000066400000000000000000000021231474374657400203260ustar00rootroot00000000000000name: close inactive issues on: schedule: - cron: "0 10 * * *" jobs: close-issues: runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: actions/stale@v5 with: days-before-issue-stale: 30 days-before-issue-close: 7 stale-issue-label: "stale" stale-issue-message: "This issue has been open for 30 days with no activity and no assignee. It will be closed in 7 days unless a comment is added." close-issue-message: "This issue was closed because it was inactive for 7 days after being marked stale." days-before-pr-stale: 60 days-before-pr-close: 7 stale-pr-label: "stale" stale-pr-message: "This PR has been open for 60 days with no activity and no assignee. It will be closed in 7 days unless a comment is added." close-pr-message: "This PR was closed because it was inactive for 7 days after being marked stale." exempt-all-assignees: true ascending: true repo-token: ${{ secrets.GITHUB_TOKEN }} kpatch-0.9.10/.github/workflows/unit.yml000066400000000000000000000011331474374657400201750ustar00rootroot00000000000000name: build and unit tests on: [push, pull_request] jobs: build: strategy: matrix: cflags: [ "", "-O2", "-O3" ] runs-on: ubuntu-latest env: CFLAGS: ${{ matrix.cflags }} steps: - uses: actions/checkout@v3 - name: dependencies run: sudo apt-get install -y libelf-dev linux-headers-$(uname -r) shellcheck elfutils - name: make run: make - name: submodule update run: git submodule update --init - name: make unit run: make unit - name: make check run: make check - name: install run: sudo make install kpatch-0.9.10/.gitignore000066400000000000000000000004111474374657400150640ustar00rootroot00000000000000*.o *.o.cmd *.o.d *.ko *.ko.cmd *.mod.c *.swp *.swo *.d *.so .tmp_versions Module.symvers kmod/core/.cache.mk kpatch-build/lookup kpatch-build/create-diff-object kpatch-build/create-klp-module kpatch-build/create-kpatch-module man/kpatch.1.gz man/kpatch-build.1.gz kpatch-0.9.10/.gitmodules000066400000000000000000000001561474374657400152570ustar00rootroot00000000000000[submodule "test/unit/objs"] path = test/unit/objs url = https://github.com/dynup/kpatch-unit-test-objs.git kpatch-0.9.10/.travis.yml000066400000000000000000000005161474374657400152130ustar00rootroot00000000000000language: c before_install: - sudo apt-get -qq update - sudo apt-get install -y libelf-dev linux-headers-$(uname -r) shellcheck elfutils jobs: include: - name: "Default" - name: "-O2" env: CFLAGS="-O2" - name: "-O3" env: CFLAGS="-O3" script: - make - make unit - make check - sudo make install kpatch-0.9.10/COPYING000066400000000000000000000432541474374657400141430ustar00rootroot00000000000000 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. kpatch-0.9.10/Makefile000066400000000000000000000062411474374657400145430ustar00rootroot00000000000000include 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 kpatch-0.9.10/Makefile.inc000066400000000000000000000010431474374657400153060ustar00rootroot00000000000000SHELL = /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 kpatch-0.9.10/README.md000066400000000000000000000313661474374657400143700ustar00rootroot00000000000000kpatch: dynamic kernel patching =============================== kpatch is a Linux dynamic kernel patching infrastructure 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, for users to log off, or for scheduled reboot windows. It gives more control over uptime without sacrificing security or stability. **WARNING: Use with caution! Kernel crashes, spontaneous reboots, and data loss may occur!** Here's a video of kpatch in action: [![kpatch video](https://img.youtube.com/vi/juyQ5TsJRTA/0.jpg)](https://www.youtube.com/watch?v=juyQ5TsJRTA) And a few more: - https://www.youtube.com/watch?v=rN0sFjrJQfU - https://www.youtube.com/watch?v=Mftc80KyjA4 Table of contents ================= - [Supported Architectures](#supported-architectures) - [Installation](#installation) - [Quick start](#quick-start) - [Patch Author Guide](#patch-author-guide) - [How it works](#how-it-works) - [kpatch-build](#kpatch-build) - [Limitations](#limitations) - [Frequently Asked Questions](#frequently-asked-questions) - [Get involved](#get-involved) - [License](#license) Supported Architectures ----------------------- - [x] x86-64 - [x] ppc64le - [ ] arm64 - [x] s390 [upstream prerequisites](doc/s390-upstream-prerequisites.md) Installation ------------ See [INSTALL.md](doc/INSTALL.md). Quick start ----------- > NOTE: While kpatch is designed to work with any recent Linux kernel on any distribution, `kpatch-build` has specifically been tested and confirmed to work on Fedora and RHEL. It has also been known to work on Oracle Linux, Ubuntu, Debian, and Gentoo. First, make a source code patch against the kernel tree using diff, git, or quilt. As a contrived example, let's patch /proc/meminfo to show VmallocChunk in ALL CAPS so we can see it better: $ cat meminfo-string.patch Index: src/fs/proc/meminfo.c =================================================================== --- src.orig/fs/proc/meminfo.c +++ src/fs/proc/meminfo.c @@ -95,7 +95,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 Build the patch module: $ kpatch-build meminfo-string.patch Using cache at /home/jpoimboe/.kpatch/3.13.10-200.fc20.x86_64/src Testing patch file checking file fs/proc/meminfo.c Building original kernel Building patched kernel Detecting changed objects Rebuilding changed objects Extracting new and modified ELF sections meminfo.o: changed function: meminfo_proc_show Building patch module: livepatch-meminfo-string.ko SUCCESS That outputs a patch module named `kpatch-meminfo-string.ko` in the current directory. Now apply it to the running kernel: $ sudo kpatch load kpatch-meminfo-string.ko loading patch module: livepatch-meminfo-string.ko Done! The kernel is now patched. $ grep -i chunk /proc/meminfo VMALLOCCHUNK: 34359337092 kB Patch author guide ------------------ Unfortunately, live patching isn't always as easy as the previous example, and can have some major pitfalls if you're not careful. To learn more about how to properly create live patches, see the [Patch Author Guide](doc/patch-author-guide.md). How it works ------------ kpatch works at a function granularity: old functions are replaced with new ones. It has three main components: - **kpatch-build**: a collection of tools which convert a source diff patch to a patch module. They work by compiling the kernel both with and without the source patch, comparing the binaries, and generating a patch module which includes new binary versions of the functions to be replaced. - **patch module**: a kernel livepatch module (.ko file) which includes the replacement functions and metadata about the original functions. Upon loading, it registers itself with the kernel livepatch infrastructure (CONFIG\_LIVEPATCH) which does the patching. - **kpatch utility:** a command-line tool which allows a user to manage a collection of patch modules. One or more patch modules may be configured to load at boot time, so that a system can remain patched even after a reboot into the same version of the kernel. ### kpatch-build The "kpatch-build" command converts a source-level diff patch file to a kernel patch module. Most of its work is performed by the kpatch-build script which uses a utility named `create-diff-object` to compare changed objects. The primary steps in kpatch-build are: - Build the unstripped vmlinux for the kernel - Patch the source tree - Rebuild vmlinux and monitor which objects are being rebuilt. These are the "changed objects". - Recompile each changed object with `-ffunction-sections -fdata-sections`, resulting in the changed patched objects - Unpatch the source tree - Recompile each changed object with `-ffunction-sections -fdata-sections`, resulting in the changed original objects - For every changed object, use `create-diff-object` to do the following: * Analyze each original/patched object pair for patchability * Add `.kpatch.funcs` and `.rela.kpatch.funcs` sections to the output object. The kpatch core module uses this to determine the list of functions that need to be redirected using ftrace. * Add `.kpatch.dynrelas` and `.rela.kpatch.dynrelas` sections to the output object. This will be used to resolve references to non-included local and non-exported global symbols. These relocations will be resolved by the kpatch core module. * Generate the resulting output object containing the new and modified sections - Link all the output objects into a cumulative object - Generate the patch module Limitations ----------- - NOTE: Many of these limitations can be worked around with creative solutions. For more details, see the [Patch Author Guide](doc/patch-author-guide.md). - Patches which modify init functions (annotated with `__init`) are not supported. kpatch-build will return an error if the patch attempts to do so. - Patches which modify statically allocated data are not directly supported. kpatch-build will detect that and return an error. This limitation can be overcome by using callbacks or shadow variables, as described in the [Patch Author Guide](doc/patch-author-guide.md). - Patches which change the way a function interacts with dynamically allocated data might be safe, or might not. It isn't possible for kpatch-build to verify the safety of this kind of patch. It's up to the user to understand what the patch does, whether the new functions interact with dynamically allocated data in a different way than the old functions did, and whether it would be safe to atomically apply such a patch to a running kernel. - Patches which modify functions in vdso are not supported. These run in user-space and ftrace can't hook them. - Patches which modify functions that are missing a `fentry` call are not supported. This includes any `lib-y` targets that are archived into a `lib.a` library for later linking (for example, `lib/string.o`). - Some incompatibilities currently exist between kpatch and usage of ftrace and kprobes. See the Frequently Asked Questions section for more details. Frequently Asked Questions -------------------------- **Q. Isn't this just a virus/rootkit injection framework?** kpatch uses kernel modules to replace code. It requires the `CAP_SYS_MODULE` capability. If you already have that capability, then you already have the ability to arbitrarily modify the kernel, with or without kpatch. **Q. How can I detect if somebody has patched the kernel?** If a patch is currently applied, you can see it in `/sys/kernel/livepatch`. Also, if a patch has been previously applied, the `TAINT_LIVEPATCH` flag is set. To test for these flags, `cat /proc/sys/kernel/tainted` and check to see if the value of `TAINT_LIVEPATCH` (32768) has been OR'ed in. Note that the `TAINT_OOT_MODULE` flag (4096) will also be set, since the patch module is built outside the Linux kernel source tree. If your patch module is unsigned, the `TAINT_UNSIGNED_MODULE` flag (8192) will also be set. **Q. Will it destabilize my system?** No, as long as the patch is created carefully. See the Limitations section above and the [Patch Author Guide](doc/patch-author-guide.md). **Q. Why not use something like kexec instead?** If you want to avoid a hardware reboot, but are ok with restarting processes or using CRIU, kexec is a good alternative. **Q. If an application can't handle a reboot, it's designed wrong.** That's a good poi... [system reboots] **Q. What kernels are supported?** kpatch needs gcc >= 4.8 and Linux >= 4.0. **Q. Is it possible to remove a patch?** Yes. Just run `kpatch unload` which will disable and unload the patch module and restore the function to its original state. **Q. Can you apply multiple patches?** Yes, but to prevent any unexpected interactions between multiple patch modules, it's recommended that patch upgrades are cumulative, so that each patch is a superset of the previous patch. This can be achieved by combining the new patch with the previous patch using `combinediff` before running `kpatch-build`. It's also recommended to use livepatch atomic "replace" mode, which is the default. **Q. Why did kpatch-build detect a changed function that wasn't touched by the source patch?** There could be a variety of reasons for this, such as: - The patch changed an inline function. - The compiler decided to inline a changed function, resulting in the outer function getting recompiled. This is common in the case where the inner function is static and is only called once. - A bug in kpatch-build's detection of `__LINE__` macro usage. **Q. Are patching of kernel modules supported?** - Yes. **Q. Can you patch out-of-tree modules?** Yes! There's a few requirements, and the feature is still in its infancy. 1. You need to use the `--oot-module` flag to specify the version of the module that's currently running on the machine. 2. `--oot-module-src` has to be passed with a directory containing the same version of code as the running module, all set up and ready to build with a `make` command. For example, some modules need `autogen.sh` and `./configure` to have been run with the appropriate flags to match the currently-running module. 3. If the `Module.symvers` file for the out-of-tree module doesn't appear in the root of the provided source directory, a symlink needs to be created in that directory that points to its actual location. 4. Usually you'll need to pass the `--target` flag as well, to specify the proper `make` target names. 5. This has only been tested for a single out-of-tree module per patch, and not for out-of-tree modules with dependencies on other out-of-tree modules built separately. ***Sample invocation*** `kpatch-build --oot-module-src ~/test/ --target default --oot-module /lib/modules/$(uname -r)/extra/test.ko test.patch` **Q. What is needed to support a new architecture?** Porting an architecture can be done in three phases: 1. In the kernel, add `CONFIG_HAVE_LIVEPATCH` support. For some arches this might be as simple as enabling `CONFIG_DYNAMIC_FTRACE_WITH REGS`. With this support you can do basic live patches like those in samples/livepatch. Livepatch functionality is limited and extra care must be taken to avoid certain pitfalls. 2. Add kpatch-build (create-diff-object) support. This makes it easier to build patches, and avoids some of the pitfalls. For example, https://github.com/dynup/kpatch/pull/1203 added s390x support. 3. Add `CONFIG_HAVE_RELIABLE_STACKTRACE` and (if needed) objtool support in the kernel. This avoids more pitfalls and enables full livepatch functionality. Get involved ------------ Contributions are very welcome. Feel free to open issues or PRs on github. For big PRs, it's a good idea to discuss them first in github issues/discussions before you write a lot of code. License ------- kpatch is under the GPLv2 license. 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. kpatch-0.9.10/contrib/000077500000000000000000000000001474374657400145405ustar00rootroot00000000000000kpatch-0.9.10/contrib/Makefile000066400000000000000000000006211474374657400161770ustar00rootroot00000000000000include ../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: kpatch-0.9.10/contrib/kpatch.conf000066400000000000000000000013221474374657400166570ustar00rootroot00000000000000# 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 kpatch-0.9.10/contrib/kpatch.service000066400000000000000000000004121474374657400173710ustar00rootroot00000000000000[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 kpatch-0.9.10/contrib/kpatch.spec000066400000000000000000000321401474374657400166660ustar00rootroot00000000000000# 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.10 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 * Mon Jan 20 2025 Joe Lawrence - 0.9.10 - Support for Amazon Linux, Anolis OS, and OpenCloudOS distros - Fix cleanup when kpatch is installed in read-only location - Added RHEL-8.9, 9.3, 8.10, 9.4, and 9.5 integration tests - Added AL2023 integration tests - Support for __patchable_function_entries sections * Thu Jul 27 2023 Joe Lawrence - 0.9.9 - Support for gcc-13 - Support for Linux 6.2 - Support for UBSAN kernels - Fix handling of PowerPC cpu features - Added RHEL-8.8 and 9.2 integration tests * Wed Mar 8 2023 Joe Lawrence - 0.9.8 - Clang fix ups from Pete Swain - Support for gcc-12 - Support for Linux 5.19 - Added RHEL-8.7 and 9.1 integration tests - Fixed __UNIQUE_ID() variable correlation - Improved handling of unsupported static calls * Wed Sep 14 2022 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 2022 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 2021 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 2021 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 2021 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 * Sun 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. * Tue 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 kpatch-0.9.10/doc/000077500000000000000000000000001474374657400136455ustar00rootroot00000000000000kpatch-0.9.10/doc/INSTALL.md000066400000000000000000000217271474374657400153060ustar00rootroot00000000000000Installation ============ Table of contents ================= - [Prerequisites](#prerequisites) - [Fedora, RHEL, CentOS](#fedora-rhel-centos) - [Oracle Linux 7](#oracle-linux-7) - [Ubuntu](#ubuntu) - [Debian 9 (Stretch)](#debian-9-stretch) - [Debian 8 (Jessie)](#debian-8-jessie) - [Debian 7 (Lenny)](#debian-7-lenny) - [Gentoo](#gentoo) - [OpenEuler](#openeuler) - [Build](#build) - [Install](#install) Prerequisites ------------- Before starting, see [Supported Architectures](../README.md#supported-architectures) and check if your device's architecture is supported. ### Fedora, RHEL, CentOS *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Install the dependencies for compiling kpatch and running kpatch-build: ```bash # Will request root privileges make dependencies ``` ### Oracle Linux 7 *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Install the dependencies for compiling kpatch: ```bash UNAME=$(uname -r) sudo yum install gcc kernel-devel-${UNAME%.*} elfutils elfutils-devel ``` Install the dependencies for the "kpatch-build" command: ```bash sudo yum install pesign yum-utils zlib-devel \ binutils-devel newt-devel python-devel perl-ExtUtils-Embed \ audit-libs numactl-devel pciutils-devel bison patchutils # enable ol7_optional_latest repo sudo yum-config-manager --enable ol7_optional_latest sudo yum-builddep kernel-${UNAME%.*} # manually install kernel debuginfo packages rpm -ivh https://oss.oracle.com/ol7/debuginfo/kernel-debuginfo-$(uname -r).rpm rpm -ivh https://oss.oracle.com/ol7/debuginfo/kernel-debuginfo-common-x86_64-$(uname -r).rpm # optional, but highly recommended - enable EPEL 7 sudo yum install ccache ccache --max-size=5G ``` ### Ubuntu *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Install the dependencies for compiling kpatch and running kpatch-build ```bash # required on ppc64le # e.g., on Ubuntu 18.04 for gcc-7.3 apt-get install gcc-7-plugin-dev # Will request root privileges make dependencies ``` ### Debian 9 (Stretch) Since Stretch the stock kernel can be used without changes, however the version of kpatch in Stretch is too old so you still need to build it manually. Follow the instructions for Debian Jessie (next section) but skip building a custom kernel/rebooting. ### Debian 8 (Jessie) *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Install the dependencies for compiling kpatch: apt-get install make gcc libelf-dev build-essential Install and prepare the kernel sources: ```bash apt-get install linux-source-$(uname -r) cd /usr/src && tar xvf linux-source-$(uname -r).tar.xz && ln -s linux-source-$(uname -r) linux && cd linux cp /boot/config-$(uname -r) .config for OPTION in CONFIG_KALLSYMS_ALL CONFIG_FUNCTION_TRACER ; do sed -i "s/# $OPTION is not set/$OPTION=y/g" .config ; done sed -i "s/^SUBLEVEL.*/SUBLEVEL =/" Makefile make -j`getconf _NPROCESSORS_CONF` deb-pkg KDEB_PKGVERSION=$(uname -r).9-1 ``` Install the kernel packages and reboot dpkg -i /usr/src/*.deb reboot Install the dependencies for the "kpatch-build" command: apt-get install dpkg-dev apt-get build-dep linux # required on ppc64le # e.g., on stretch for gcc-6.3 apt-get install gcc-6-plugin-dev # optional, but highly recommended apt-get install ccache ccache --max-size=5G ### Debian 7 (Lenny) *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Add backports repositories: ```bash echo "deb http://http.debian.net/debian wheezy-backports main" > /etc/apt/sources.list.d/wheezy-backports.list echo "deb http://packages.incloudus.com backports-incloudus main" > /etc/apt/sources.list.d/incloudus.list wget http://packages.incloudus.com/incloudus/incloudus.pub -O- | apt-key add - aptitude update ``` Install the linux kernel, symbols and gcc 4.9: aptitude install -t wheezy-backports -y initramfs-tools aptitude install -y gcc gcc-4.9 g++-4.9 linux-image-3.14 linux-image-3.14-dbg Configure gcc 4.9 as the default gcc compiler: update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 20 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 50 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.7 20 update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 50 Install kpatch and these dependencies: aptitude install kpatch Configure ccache (installed by kpatch package): ccache --max-size=5G ### Gentoo *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Install Kpatch and Kpatch dependencies: ```bash emerge --ask sys-kernel/kpatch ``` Install ccache (optional): ```bash emerge --ask dev-util/ccache ``` Configure ccache: ```bash ccache --max-size=5G ``` ### OpenEuler *ATTENTION: openEuler maintains its own version of kpatch which work with its own kernel. You can check this [link](https://gitee.com/src-openeuler/kpatch) to see its documents. This document describes how to run mainline kpatch in openEuler.* *NOTE: You'll need about 15GB of free disk space for the kpatch-build cache in `~/.kpatch` and for ccache.* Install the dependencies for compiling kpatch and running kpatch-build: ```bash # Will request root privileges make dependencies ``` #### Before running kpatch-build, two more things need to be checked: ------- 1. Ensure current kernel compiled with *CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY* set openEuler has two strategies to apply kernel live patches and it is decided at compile time. When CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY set, openEuler uses its own strategy. When CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY set, openEuler uses the conventional strategy. Only one config option can take effect at the same time. A [chinese blog](https://www.modb.pro/db/232858) written by the openEuler official describes their modifications for kernel livepatch. The main difference is CONFIG_LIVEPATCH_STOP_MACHINE_CONSISTENCY will disable the usage of ftrace handler in livepatch, they believe it will be faster. Check whether your current kernel compiled with *CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY* ```bash grep "CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY" /boot/config-$(uname -r) ``` If you see any output, it means your kernel satisfies, you can go directly to check step 2. If not, then you need to recompile your current kernel with CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY set. You can reference the following steps to recompile the kernel if needed 1. download source code of the current kernel ```bash # set working directories TEMPDIR=~/.tmp mkdir -p $TEMPDIR mkdir -p $TEMPDIR/buildroot # download kernel source rpm package yumdownloader --source --destdir "$TEMPDIR" kernel-$(uname -r) # obtain source code from package rpm -D "_topdir $TEMPDIR/buildroot" -ivh $TEMPDIR/kernel-*.src.rpm rpmbuild -D "_topdir $TEMPDIR/buildroot" -bp --nodeps --target=$(uname -m) $TEMPDIR/buildroot/SPECS/kernel.spec # check source code and copy config file cd $TEMPDIR/buildroot/BUILD/kernel-*/linux-*[sS]ource cp /boot/config-$(uname -r) .config ``` 2. set CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY ```bash make menuconfig ``` select order -> Processor type and features -> Enable Livepatch -> Kernel Live Patching -> live patching method choose > based on ftrace After this step, you shoud see CONFIG_LIVEPATCH_PER_TASK_CONSISTENCY in .config file 3. recompile kernel and install it to your running environment. Just to remind, after installing the recompiled kernel, the config file should also be updated. 2. Ensure */update/source* is in the rpm repo lists openEuler releases its source rpm package of the kernel in two places. One is /source and it is included in rpm repo lists by default. One is /update/source and it may not be included it in some release versions. ```bash grep "/update/source" /etc/yum.repos.d/openEuler.repo ``` If you can't see any output, add it to the end of /etc/yum.repos.d/openEuler.repo For example, if you use openEuler 21.09, you will add something like: ``` [update-source] name=update-source baseurl=https://repo.openeuler.org/openEuler-21.09/update/source/ enabled=1 gpgcheck=0 ``` *baseurl* is releated with your release version, be careful please! Goto [openEuler repo](https://repo.openeuler.org/), find your own suitable baseurl. Build ----- Compile kpatch: make Install ------- OPTIONAL: Install kpatch to `/usr/local`: sudo make install Alternatively, the kpatch and kpatch-build scripts can be run directly from the git tree. kpatch-0.9.10/doc/patch-author-guide.md000066400000000000000000001121001474374657400176540ustar00rootroot00000000000000kpatch Patch Author Guide ========================= Because kpatch-build is relatively easy to use, it can be easy to assume that a successful patch module build means that the patch is safe to apply. But in fact that's a very dangerous assumption. There are many pitfalls that can be encountered when creating a live patch. This document attempts to guide the patch creation process. It's a work in progress. If you find it useful, please contribute! Table of contents ================= - [Patch analysis](#patch-analysis) - [kpatch vs livepatch vs kGraft](#kpatch-vs-livepatch-vs-kgraft) - [Patch upgrades](#patch-upgrades) - [Data structure changes](#data-structure-changes) - [Data semantic changes](#data-semantic-changes) - [Init code changes](#init-code-changes) - [Header file changes](#header-file-changes) - [Dealing with unexpected changed functions](#dealing-with-unexpected-changed-functions) - [Removing references to static local variables](#removing-references-to-static-local-variables) - [Code removal](#code-removal) - [Once macros](#once-macros) - [inline implies notrace](#inline-implies-notrace) - [Jump labels and static calls](#jump-labels-and-static-calls) - [Sibling calls](#sibling-calls) - [Exported symbol versioning](#exported-symbol-versioning) - [System calls](#system-calls) Patch analysis -------------- kpatch provides _some_ guarantees, but it does not guarantee that all patches are safe to apply. Every patch must also be analyzed in-depth by a human. The most important point here cannot be stressed enough. Here comes the bold: **Do not blindly apply patches. There is no substitute for human analysis and reasoning on a per-patch basis. All patches must be thoroughly analyzed by a human kernel expert who completely understands the patch and the affected code and how they relate to the live patching environment.** kpatch vs livepatch vs kGraft ----------------------------- This document assumes that the kpatch-build tool is being used to create livepatch kernel modules. Other live patching systems may have different consistency models, their own guarantees, and other subtle differences. The guidance in this document applies **only** to kpatch-build generated livepatches. Patch upgrades -------------- Due to potential unexpected interactions between patches, it's highly recommended that when patching a system which has already been patched, the second patch should be a cumulative upgrade which is a superset of the first patch. Since upstream kernel 5.1, livepatch supports a "replace" flag to help the management of cumulative patches. With the flag set, the kernel will load the cumulative patch and unload all existing patches in one transition. kpatch-build enables the replace flag by default. If replace behavior is not desired, the user can disable it with -R|--non-replace. Data structure changes ---------------------- kpatch patches functions, not data. If the original patch involves a change to a data structure, the patch will require some rework, as changes to data structures are not allowed by default. Usually you have to get creative. There are several possible ways to handle this: ### Change the code which uses the data structure Sometimes, instead of changing the data structure itself, you can change the code which uses it. For example, consider this [patch](http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=54a20552e1eae07aa240fa370a0293e006b5faed). which has the following hunk: ```diff @@ -3270,6 +3277,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, + [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception, [SVM_EXIT_INTR] = intr_interception, [SVM_EXIT_NMI] = nmi_interception, [SVM_EXIT_SMI] = nop_on_interception, ``` `svm_exit_handlers[]` is an array of function pointers. The patch adds a `ac_interception` function pointer to the array at index `[SVM_EXIT_EXCP_BASE + AC_VECTOR]`. That change is incompatible with kpatch. Looking at the source file, we can see that this function pointer is only accessed by a single function, `handle_exit()`: ```c if (exit_code >= ARRAY_SIZE(svm_exit_handlers) || !svm_exit_handlers[exit_code]) { WARN_ONCE(1, "svm: unexpected exit reason 0x%x\n", exit_code); kvm_queue_exception(vcpu, UD_VECTOR); return 1; } return svm_exit_handlers[exit_code](svm); ``` So an easy solution here is to just change the code to manually check for the new case before looking in the data structure: ```diff @@ -3580,6 +3580,9 @@ static int handle_exit(struct kvm_vcpu *vcpu) return 1; } + if (exit_code == SVM_EXIT_EXCP_BASE + AC_VECTOR) + return ac_interception(svm); + return svm_exit_handlers[exit_code](svm); } ``` Not only is this an easy solution, it's also safer than touching data since `svm_exit_handlers[]` may be in use by tasks that haven't been patched yet. ### Use a kpatch callback macro Kpatch supports the kernel's livepatch [(Un)patching callbacks](https://github.com/torvalds/linux/blob/master/Documentation/livepatch/callbacks.rst). The kernel API requires callback registration through `struct klp_callbacks`, but to do so through kpatch-build, `kpatch-macros.h` defines the following: * `KPATCH_PRE_PATCH_CALLBACK` - executed before patching * `KPATCH_POST_PATCH_CALLBACK` - executed after patching * `KPATCH_PRE_UNPATCH_CALLBACK` - executed before unpatching, complements the post-patch callback. * `KPATCH_POST_UNPATCH_CALLBACK` - executed after unpatching, complements the pre-patch callback. A pre-patch callback routine has the following signature: ```c static int callback(patch_object *obj) { } KPATCH_PRE_PATCH_CALLBACK(callback); ``` and any non-zero return status indicates failure to the kernel. For more information on pre-patch callback failure, see the **Pre-patch return status** section below. Post-patch, pre-unpatch, and post-unpatch callback routines all share the following signature: ```c static void callback(patch_object *obj) { } KPATCH_POST_PATCH_CALLBACK(callback); /* or */ KPATCH_PRE_UNPATCH_CALLBACK(callback); /* or */ KPATCH_POST_UNPATCH_CALLBACK(callback); ``` Generally pre-patch callbacks are paired with post-unpatch callbacks, meaning that anything the former allocates or sets up should be torn down by the former callback. Likewise for post-patch and pre-unpatch callbacks. #### Pre-patch return status If kpatch is currently patching already loaded objects (vmlinux always by definition as well as any currently loaded kernel modules), a non-zero pre-patch callback status stops the current patch in progress. The kpatch-module is rejected, completely reverted, and unloaded. If an already loaded kpatch is patching an incoming kernel module, then a failing pre-patch callback will result in the kernel module loader rejecting the new module. In both cases, if a pre-patch callback fails, none of its other associated callbacks will be executed. #### Callback context * For patches to vmlinux or already loaded kernel modules, callback functions will be run around the livepatch transitions in the `klp_enable_patch()` callchain. This is executed automatically on kpatch module init. * For patches to kernel modules which haven't been loaded yet, a module-notifier will execute callbacks when the module is loaded into the `MODULE_STATE_COMING` state. The pre and post-patch callbacks are called before any module_init code. Example: a kpatch fix for CVE-2016-5696 could utilize the `KPATCH_PRE_PATCH_CALLBACK` and `KPATCH_POST_UNPATCH_CALLBACK` macros to modify variable `sysctl_tcp_challenge_ack_limit` in-place: ```diff +#include "kpatch-macros.h" + +static bool kpatch_write = false; +static int kpatch_pre_patch_tcp_send_challenge_ack(patch_object *obj) +{ + if (sysctl_tcp_challenge_ack_limit == 100) { + sysctl_tcp_challenge_ack_limit = 1000; + kpatch_write = true; + } + return 0; +} static void kpatch_post_unpatch_tcp_send_challenge_ack(patch_object *obj) +{ + if (kpatch_write && sysctl_tcp_challenge_ack_limit == 1000) + sysctl_tcp_challenge_ack_limit = 100; +} +KPATCH_PRE_PATCH_CALLBACK(kpatch_pre_patch_tcp_send_challenge_ack); +KPATCH_POST_UNPATCH_CALLBACK(kpatch_post_unpatch_tcp_send_challenge_ack); ``` Don't forget to protect access to data as needed. Spinlocks and mutexes / sleeping locks **may be used** (this is a change of behavior from when kpatch relied on the kpatch.ko support module and `stop_machine()` context.) Be careful when upgrading. If patch A has a pre/post-patch callback which writes to X, and then you load patch B which is a superset of A, in some cases you may want to prevent patch B from writing to X, if A is already loaded. ### Use a shadow variable If you need to add a field to an existing data structure, or even many existing data structures, you can use the kernel's [Shadow Variable](https://www.kernel.org/doc/html/latest/livepatch/shadow-vars.html) API. Example: The `shadow-newpid.patch` integration test employs shadow variables to add a rolling counter to the new `struct task_struct` instances. A simplified version is presented here. A shadow PID variable is allocated in `do_fork()`: it is associated with the current `struct task_struct *p` value, given an ID of `KPATCH_SHADOW_NEWPID`, sized accordingly, and allocated as per `GFP_KERNEL` flag rules. Note that the shadow variable association is global -- hence it is best to provide unique ID enumerations per kpatch as needed. `klp_shadow_alloc()` returns a pointer to the shadow variable, so we can dereference and make assignments as usual. In this patch chunk, the shadow `newpid` is allocated then assigned to a rolling `ctr` counter value: ```patch diff --git a/kernel/fork.c b/kernel/fork.c index 9bff3b28c357..18374fd35bd9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1751,6 +1751,8 @@ struct task_struct *fork_idle(int cpu) return task; } +#include +#define KPATCH_SHADOW_NEWPID 0 /* * Ok, this is the main fork-routine. * @@ -1794,6 +1796,14 @@ 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, KPATCH_SHADOW_NEWPID, + sizeof(*newpid), GFP_KERNEL, + NULL, NULL); + if (newpid) + *newpid = ctr++; trace_sched_process_fork(current, p); ``` A shadow variable may be accessed via `klp_shadow_get()`. Here the patch modifies `task_context_switch_counts()` to fetch the shadow variable associated with the current `struct task_struct *p` object and a `KPATCH_SHADOW_NEWPID ID`. As in the previous patch chunk, the shadow variable pointer may be accessed as an ordinary pointer type: ```patch diff --git a/fs/proc/array.c b/fs/proc/array.c index 39684c79e8e2..fe0259d057a3 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -394,13 +394,19 @@ static inline void task_seccomp(struct seq_file *m, struct task_struct *p) seq_putc(m, '\n'); } +#include +#define KPATCH_SHADOW_NEWPID 0 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, KPATCH_SHADOW_NEWPID); + if (newpid) + seq_printf(m, "newpid:\t%d\n", *newpid); } static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) ``` A shadow variable is freed by calling `klp_shadow_free()` and providing the object / enum ID combination. Once freed, the shadow variable is no longer safe to access: ```patch diff --git a/kernel/exit.c b/kernel/exit.c index 148a7842928d..44b6fe61e912 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -791,6 +791,8 @@ static void check_stack_usage(void) static inline void check_stack_usage(void) {} #endif +#include +#define KPATCH_SHADOW_NEWPID 0 void do_exit(long code) { struct task_struct *tsk = current; @@ -888,6 +890,8 @@ void do_exit(long code) check_stack_usage(); exit_thread(); + klp_shadow_free(tsk, KPATCH_SHADOW_NEWPID, NULL); + /* * Flush inherited counters to the parent - before the parent * gets woken up by child-exit notifications. ``` Notes: * `klp_shadow_alloc()` and `klp_shadow_get_or_alloc()` initialize only shadow variable metadata. They allocate variable storage via `kmalloc` with the `gfp_t` flags given, but otherwise leave the area untouched. Initialization of a shadow variable is the responsibility of the caller. * As soon as `klp_shadow_alloc()` or `klp_shadow_get_or_alloc()` create a shadow variable, its presence will be reported by `klp_shadow_get()`. Care should be taken to avoid any potential race conditions between a kernel thread that allocates a shadow variable and concurrent threads that may attempt to use it. * Patches may need to call `klp_shadow_free_all()` from a post-unpatch handler to safely cleanup any shadow variables of a particular ID. From post-unpatch context, unloading kpatch module code (aside from .exit) should be completely inactive. As long as these shadow variables were only accessed by the unloaded kpatch, they are be safe to release. Data semantic changes --------------------- Part of the stable-tree [backport](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/fs/aio.c?h=linux-3.10.y&id=6745cb91b5ec93a1b34221279863926fba43d0d7) to fix CVE-2014-0206 changed the reference count semantic of `struct kioctx.reqs_active`. Associating a shadow variable to new instances of this structure can be used by patched code to handle both new (post-patch) and existing (pre-patch) instances. (Note: this example is trimmed to highlight this use-case. Boilerplate code is also required to allocate/free a shadow variable with enum ID `KPATCH_SHADOW_REQS_ACTIVE_V2` whenever a new `struct kioctx` is created/released. No values are ever assigned to the shadow variable.) ```patch diff --git a/fs/aio.c b/fs/aio.c index ebd06fd0de89..6a33b73c9107 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -280,6 +280,8 @@ static void free_ioctx_rcu(struct rcu_head *head) * and ctx->users has dropped to 0, so we know no more kiocbs can be submitted - * now it's safe to cancel any that need to be. */ +#include +#define KPATCH_SHADOW_REQS_ACTIVE_V2 1 static void free_ioctx(struct kioctx *ctx) { struct aio_ring *ring; ``` Shadow variable existence can be verified before applying the *new* data semantic of the associated object: ```diff @@ -678,6 +681,8 @@ void aio_complete(struct kiocb *iocb, long res, long res2) put_rq: /* everything turned out well, dispose of the aiocb. */ aio_put_req(iocb); + if (klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2)) + atomic_dec(&ctx->reqs_active); /* * We have to order our ring_info tail store above and test ``` Likewise, shadow variable non-existence can be tested to continue applying the *old* data semantic: ```diff @@ -310,7 +312,8 @@ static void free_ioctx(struct kioctx *ctx) avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head; - atomic_sub(avail, &ctx->reqs_active); + if (!klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2)) + atomic_sub(avail, &ctx->reqs_active); head += avail; head %= ctx->nr_events; } @@ -757,6 +762,8 @@ static long aio_read_events_ring(struct kioctx *ctx, pr_debug("%li h%u t%u\n", ret, head, ctx->tail); atomic_sub(ret, &ctx->reqs_active); + if (!klp_shadow_get(ctx, KPATCH_SHADOW_REQS_ACTIVE_V2)) + atomic_sub(ret, &ctx->reqs_active); out: mutex_unlock(&ctx->ring_lock); ``` The previous example can be extended to use shadow variable storage to handle locking semantic changes. Consider the [upstream fix](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1d147bfa64293b2723c4fec50922168658e613ba) for CVE-2014-2706, which added a `ps_lock` to `struct sta_info` to protect critical sections throughout `net/mac80211/sta_info.c`. When allocating a new `struct sta_info`, allocate a corresponding shadow variable large enough to hold a `spinlock_t` instance, then initialize the spinlock: ```patch diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index decd30c1e290..758533dda4d8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -287,6 +287,8 @@ static int sta_prepare_rate_control(struct ieee80211_local *local, return 0; } +#include +#define KPATCH_SHADOW_PS_LOCK 2 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, const u8 *addr, gfp_t gfp) { @@ -295,6 +297,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, struct timespec uptime; struct ieee80211_tx_latency_bin_ranges *tx_latency; int i; + spinlock_t *ps_lock; sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); if (!sta) @@ -330,6 +333,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); spin_lock_init(&sta->lock); + ps_lock = klp_shadow_alloc(sta, KPATCH_SHADOW_PS_LOCK, + sizeof(*ps_lock), gfp, NULL, NULL); + if (ps_lock) + spin_lock_init(ps_lock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); ``` Patched code can reference the shadow variable associated with a given `struct sta_info` to determine and apply the correct locking semantic for that instance: ```patch diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 97a02d3f7d87..0edb0ed8dc60 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -459,12 +459,15 @@ static int ieee80211_use_mfp(__le16 fc, struct sta_info *sta, return 1; } +#include +#define KPATCH_SHADOW_PS_LOCK 2 static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_local *local = tx->local; + spinlock_t *ps_lock; if (unlikely(!sta)) return TX_CONTINUE; @@ -478,6 +481,23 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta->sta.addr, sta->sta.aid, ac); if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); + + /* sync with ieee80211_sta_ps_deliver_wakeup */ + ps_lock = klp_shadow_get(sta, KPATCH_SHADOW_PS_LOCK); + if (ps_lock) { + spin_lock(ps_lock); + /* + * STA woke up the meantime and all the frames on ps_tx_buf have + * been queued to pending queue. No reordering can happen, go + * ahead and Tx the packet. + */ + if (!test_sta_flag(sta, WLAN_STA_PS_STA) && + !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { + spin_unlock(ps_lock); + return TX_CONTINUE; + } + } + if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); ps_dbg(tx->sdata, ``` Init code changes ----------------- Any code which runs in an `__init` function or during module or device initialization is problematic, as it may have already run before the patch was applied. The patch may require a pre-patch callback which detects whether such init code has run, and which rewrites or changes the original initialization to force it into the desired state. Some changes involving hardware init are inherently incompatible with live patching. Header file changes ------------------- When changing header files, be extra careful. If data is being changed, you probably need to modify the patch. See "Data struct changes" above. If a function prototype is being changed, make sure it's not an exported function. Otherwise it could break out-of-tree modules. One way to workaround this is to define an entirely new copy of the function (with updated code) and patch in-tree callers to invoke it rather than the deprecated version. Many header file changes result in a complete rebuild of the kernel tree, which makes kpatch-build have to compare every .o file in the kernel. It slows the build down a lot, and can even fail to build if kpatch-build has any bugs lurking. If it's a trivial header file change, like adding a macro, it's advisable to just move that macro into the .c file where it's needed to avoid changing the header file at all. Dealing with unexpected changed functions ----------------------------------------- In general, it's best to patch as minimally as possible. If kpatch-build is reporting some unexpected function changes, it's always a good idea to try to figure out why it thinks they changed. In many cases you can change the source patch so that they no longer change. Some examples: * If a changed function was inlined, then the callers which inlined the function will also change. In this case there's nothing you can do to prevent the extra changes. * If a changed function was originally inlined, but turned into a callable function after patching, consider adding `__always_inline` to the function definition. Likewise, if a function is only inlined after patching, consider using `noinline` to prevent the compiler from doing so. * If your patch adds a call to a function where the original version of the function's ELF symbol has a .constprop or .isra suffix, and the corresponding patched function doesn't, that means the patch caused gcc to no longer perform an interprocedural optimization, which affects the function and all its callers. If you want to prevent this from happening, copy/paste the function with a new name and call the new function from your patch. * Moving around source code lines can introduce unique instructions if any `__LINE__` preprocessor macros are in use. This can be mitigated by adding any new functions to the bottom of source files, using newline whitespace to maintain original line counts, etc. A more exact fix can be employed by modifying the source code that invokes `__LINE__` and hard-coding the original line number in place. This occurred in issue #1124 for example. Removing references to static local variables --------------------------------------------- Removing references to static locals will fail to patch unless extra steps are taken. Static locals are basically global variables because they outlive the function's scope. They need to be correlated so that the new function will use the old static local. That way patching the function doesn't inadvertently reset the variable to zero; instead the variable keeps its old value. To work around this limitation one needs to retain the reference to the static local. This might be as simple as adding the variable back in the patched function in a non-functional way and ensuring the compiler doesn't optimize it away. Code removal ------------ Some fixes may replace or completely remove functions and references to them. Remember that kpatch modules can only add new functions and redirect existing functions, so "removed" functions will continue to exist in kernel address space as effectively dead code. That means this patch (source code removal of `cmdline_proc_show`): ```patch diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2016-11-30 19:39:49.317737234 +0000 +++ src/fs/proc/cmdline.c 2016-11-30 19:39:52.696737234 +0000 @@ -3,15 +3,15 @@ #include #include -static int cmdline_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%s\n", saved_command_line); - return 0; -} +static int cmdline_proc_show_v2(struct seq_file *m, void *v) +{ + seq_printf(m, "%s kpatch\n", saved_command_line); + return 0; +} static int cmdline_proc_open(struct inode *inode, struct file *file) { - return single_open(file, cmdline_proc_show, NULL); + return single_open(file, cmdline_proc_show_v2, NULL); } static const struct file_operations cmdline_proc_fops = { ``` will generate an equivalent kpatch module to this patch (dead `cmdline_proc_show` left in source): ```patch diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2016-11-30 19:39:49.317737234 +0000 +++ src/fs/proc/cmdline.c 2016-11-30 19:39:52.696737234 +0000 @@ -9,9 +9,15 @@ static int cmdline_proc_show(struct seq_ return 0; } +static int cmdline_proc_show_v2(struct seq_file *m, void *v) +{ + seq_printf(m, "%s kpatch\n", saved_command_line); + return 0; +} + static int cmdline_proc_open(struct inode *inode, struct file *file) { - return single_open(file, cmdline_proc_show, NULL); + return single_open(file, cmdline_proc_show_v2, NULL); } static const struct file_operations cmdline_proc_fops = { ``` In both versions, `kpatch-build` will determine that only `cmdline_proc_open` has changed and that `cmdline_proc_show_v2` is a new function. In some patching cases it might be necessary to completely remove the original function to avoid the compiler complaining about a defined, but unused function. This will depend on symbol scope and kernel build options. "Once" macros ------------- When adding a call to `printk_once()`, `pr_warn_once()`, or any other "once" variation of `printk()`, you'll get the following eror: ``` ERROR: vmx.o: 1 unsupported section change(s) vmx.o: WARNING: unable to correlate static local variable __print_once.60588 used by vmx_update_pi_irte, assuming variable is new vmx.o: changed function: vmx_update_pi_irte vmx.o: data section .data..read_mostly selected for inclusion /usr/lib/kpatch/create-diff-object: unreconcilable difference ``` This error occurs because the `printk_once()` adds a static local variable to the `.data..read_mostly` section. kpatch-build strict disallows any changes to that section, because in some cases a change to this section indicates a bug. To work around this issue, you'll need to manually implement your own "once" logic which doesn't store the static variable in the `.data..read_mostly` section. For example, a `pr_warn_once()` can be replaced with: ```c static bool print_once; ... if (!print_once) { print_once = true; pr_warn("..."); } ``` inline implies notrace ---------------------- The linux kernel defines its own version of "inline" in include/linux/compiler_types.h which includes "notrace" as well: ```c #if !defined(CONFIG_OPTIMIZE_INLINING) #define inline inline __attribute__((__always_inline__)) __gnu_inline \ __inline_maybe_unused notrace #else #define inline inline __gnu_inline \ __inline_maybe_unused notrace #endif ``` With the implicit "notrace", use of "inline" in patch sources may lead to kpatch-build errors like the following: 1. `__tcp_mtu_to_mss()` is marked as inline: ```c net/ipv4/tcp_output.c: /* Calculate MSS not accounting any TCP options. */ static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu) { ``` 2. the compiler decides not to inline it and keeps it in its own function-section. Then kpatch-build notices that it doesn't have an fentry/mcount call: ```console % kpatch-build ... tcp_output.o: function __tcp_mtu_to_mss has no fentry/mcount call, unable to patch ``` 3. a peek at the generated code: ```c Disassembly of section .text.__tcp_mtu_to_mss: 0000000000000000 <__tcp_mtu_to_mss>: 0: 48 8b 87 60 05 00 00 mov 0x560(%rdi),%rax 7: 0f b7 50 30 movzwl 0x30(%rax),%edx b: 0f b7 40 32 movzwl 0x32(%rax),%eax f: 29 d6 sub %edx,%esi 11: 83 ee 14 sub $0x14,%esi ... ``` This could be a little confusing since one might have expected to see changes to all of `__tcp_mtu_to_mss()` callers (ie, it was inlined as requested). In this case, a simple workaround is to specify `__tcp_mtu_to_mss()` as `__always_inline` to force the compiler to do so. Jump labels and static calls ---------------------------- ### Late module patching vs special section relocations Jump labels and static calls can be problematic due to "late module patching", which is a feature (design flaw?) in upstream livepatch. When a livepatch module patches another module, unfortunately the livepatch module doesn't have an official module dependency on the patched module. That means the patched module doesn't even have to be loaded when the livepatch module gets loaded. In that case the patched module gets patched on demand whenever it might get loaded in the future. It also gets unpatched on demand whenever it gets unloaded. Loading (and patching) the module at some point after loading the livepatch module is called "late module patching". In order to support this (mis?)feature, all relocations in the livepatch module which reference module symbols must be converted to "klp relocations", which get resolved at patching time. In all modules (livepatch and otherwise), jump labels and static calls rely on special sections which trigger jump-label/static-call code patching when a module gets loaded. But unfortunately those special sections have relocations which need to get resolved, so there's an ordering issue. When a (livepatch) module gets loaded, first its relocations are resolved, then its special section handling (and code patching) is done. The problem is, for klp relocations, if they reference another module's symbols, and that module isn't loaded, they're not yet defined. So if a `.static_call_sites` entry tries to reference its corresponding `struct static_call_key`, but that key lives in another module which is not yet loaded, the key reference won't be resolved, and so `mod->static_call_sites` will be corrupted when `static_call_module_notify()` runs when the livepatch module first loads. ### Jump labels With pre-5.8 kernels, kpatch-build will error out if it encounters any jump labels: ``` oom_kill.o: Found a jump label at out_of_memory()+0x10a, using key cpusets_enabled_key. Jump labels aren't supported with this kernel. Use static_key_enabled() instead. ``` With Linux 5.8+, klp relocation handling is integrated with the module relocation code, so jump labels in patched functions are supported when the static key was originally defined in the kernel proper (vmlinux). However, if the static key lives in a module, jump labels are _not_ supported in patched code, due to the ordering issue described above. If the jump label is a tracepoint, kpatch-build will silently remove the tracepoint. Otherwise, there will be an error: ``` vmx.o: Found a jump label at vmx_hardware_enable.cold()+0x23, using key enable_evmcs, which is defined in a module. Use static_key_enabled() instead. ``` When you get one of the above errors, the fix is to remove the jump label usage in the patched function, replacing it with a regular C conditional. This can be done by replacing any usages of `static_branch_likely()`, `static_branch_unlikely()`, `static_key_true()`, and `static_key_false()` with `static_key_enabled()` in the patch file. ### Static calls Similarly, static calls are not supported when the corresponding static call key was originally defined in a module. If such a static call is part of a tracepoint, kpatch-build will silently remove it. Otherwise, there will be an error: ``` cpuid.o: Found a static call at kvm_set_cpuid.cold()+0x32c, using key __SCK__kvm_x86_vcpu_after_set_cpuid, which is defined in a module. Use KPATCH_STATIC_CALL() instead. ``` To fix this error, simply replace such static calls with regular indirect branches (or retpolines, if applicable) by adding `#include "kpatch-macros.h"` to the patch source and replacing usages of `static_call()` with `KPATCH_STATIC_CALL()`. Sibling calls ------------- GCC may generate sibling calls that are incompatible with kpatch, resulting in an error like: `ERROR("Found an unsupported sibling call at foo()+0x123. Add __attribute__((optimize("-fno-optimize-sibling-calls"))) to foo() definition."` For example, if function A() calls function B() at the end of A() and both return similar data-types, GCC may deem them "sibling calls" and apply a tail call optimization in which A() restores the stack to is callee state before setting up B()'s arguments and jumping to B(). This may be an issue for kpatches on PowerPC which modify only A() or B() and the function call crosses a kernel module boundary: the sibling call optimization has changed expected calling conventions and (un)patched code may not be similarly modified. Commit [8b952bd77130](https://github.com/dynup/kpatch/commit/8b952bd77130) ("create-diff-object/ppc64le: Don't allow sibling calls") contains an excellent example and description of this problem with annotated disassembly. Adding `__attribute__((optimize("-fno-optimize-sibling-calls")))` instructs GCC to turn off the optimization for the given function. Exported symbol versioning -------------------------- ### Background `CONFIG_MODVERSIONS` enables an ABI check between exported kernel symbols and modules referencing those symbols, enforced on module load. When building the kernel, preprocessor output from `gcc -E` for each source file is passed to scripts/genksyms. The genksyms script recursively expands each exported symbol to its basic types. A hash is generated for each symbol as it traverses back up the symbol tree. The end result is a CRC for each exported function in the Module.symvers file and embedded in the vmlinux kernel object itself. A similar checksumming is performed when building modules: referenced exported symbol CRCs are stored in the module’s `__versions` section (you can also find these in plain-text intermediate \*.mod.c files.) When the kernel loads a module, the symbol CRCs found in its `__versions` are compared to those of the kernel, if the two do not match, the kernel will refuse to load it: ``` : disagrees about version of symbol : Unknown symbol (err -22) ``` ### Kpatch detection After building the original and patched sources, kpatch-build compares the newly calculated Module.symvers against the original. Discrepancies are reported: ``` ERROR: Version disagreement for symbol ``` These reports should be addressed to ensure that the resulting kpatch module can be loaded. #### False positives It is rare, but possible for a kpatch to introduce inadvertent symbol CRC changes that are not true ABI changes. The following conditions must occur: 1. The kpatch must modify the definition of an exported symbol. For example, introducing a new header file may further define an opaque data type: Before the kpatch, compilation unit U from the original kernel build only knew about a `struct S` declaration (not its complete type). At the same time, U contains function F, which has an interface that references S. If the kpatch adds a header file to U that now fully defines `struct S { int a, b, c; }`, its symbol type graph changes, CRCs generated for F are updated, but its ABI remains consistent. 2. The kpatch must introduce either a change or reference to F such that it is included in the resulting kpatch module. This will force a `__version` entry based on the new CRC. Note: if a kpatch doesn't change or reference F such that it is **not** included in the resulting kpatch module, the new CRC value won't be added to the module's `__version` table. However, if a future accumulative patch does add a new change or reference to F, the new CRC will become a problem. #### Avoidance Kpatches should introduce new `#include` directives sparingly. Whenever possible, extract the required definitions from header filers into kpatched compilation units directly. If additional header files or symbol definitions cannot be avoided, consider surrounding the offending include/definitions in an `#ifndef __GENKSYMS__` macro. The genksyms script will skip over those blocks when performing its CRC calculations. ### But what about a real ABI change? If a kpatch introduces a true ABI change, each of calling functions would consequently need to be updated in the kpatch module. For unexported functions, this may be handled safely if the kpatch does indeed update all callers. However, since motivation behind `CONFIG_MODVERSIONS` is to provide basic ABI verification between the kernel and modules for **exported** functions, kpatch cannot safely change this ABI without worrying about breaking other out-of-tree drivers. Those drivers have been built against the reference kernel's original set of CRCs and expect the original ABI. To track down specifically what caused a symbol CRC change, tools like [kabi-dw](https://github.com/skozina/kabi-dw) can be employed to produce a detailed symbol definition report. For a kpatch-build, kabi-dw can be modified to operate on .o object files (not just .ko and vmlinux files) and the `$CACHEDIR/tmp/{orig, patched}` directories compared. System calls ------------ 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'. This problem can be worked around by adding `#include "kpatch-syscall.h"` and replacing the use of the `SYSCALL_DEFINE1` (or similar) macro with the `KPATCH_` prefixed version. kpatch-0.9.10/doc/s390-upstream-prerequisites.md000066400000000000000000000027771474374657400214420ustar00rootroot00000000000000### s390 backporting **Prerequisite gcc patches (all backported to releases/gcc-11 branch):** - gcc-mirror/gcc@a1c1b7a IBM Z: Define NO_PROFILE_COUNTERS - gcc-mirror/gcc@0990d93 IBM Z: Use @PLT symbols for local functions in 64-bit mode - gcc-mirror/gcc@935b522 S/390: New option -mpic-data-is-text-relative - gcc-mirror/gcc@8753b13 IBM Z: fix section type conflict with -mindirect-branch-table **Prerequisite kernel patches:** **v5.19:** - 69505e3d9a39 bug: Use normal relative pointers in 'struct bug_entry' **v5.18:** - 602bf1687e6f s390/nospec: align and size extern thunks - 1d2ad084800e s390/nospec: add an option to use thunk-extern - eed38cd2f46f s390/nospec: generate single register thunks if possible - 2268169c14e5 s390: remove unused expoline to BC instructions - f0003a9e4c18 s390/entry: remove unused expoline thunk - ded466e18066 s390/unwind: fix fgraph return address recovery **v5.16:** - torvalds/linux@f6ac18f sched: Improve try_invoke_on_locked_down_task() - torvalds/linux@9b3c4ab sched,rcu: Rework try_invoke_on_locked_down_task() - torvalds/linux@00619f7 sched,livepatch: Use task_call_func() - torvalds/linux@8850cb6 sched: Simplify wake_up_*idle*() - torvalds/linux@5de62ea sched,livepatch: Use wake_up_if_idle() - torvalds/linux@96611c2 sched: Improve wake_up_all_idle_cpus() take #2 **v5.15** - torvalds/linux@de5012b s390/ftrace: implement hotpatching - torvalds/linux@67ccddf ftrace: Introduce ftrace_need_init_nop() **v5.14:** - torvalds/linux@7561c14 s390/vdso: add .got.plt in vdso linker script kpatch-0.9.10/examples/000077500000000000000000000000001474374657400147165ustar00rootroot00000000000000kpatch-0.9.10/examples/cmdline-string.patch000066400000000000000000000006141474374657400206570ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/examples/proc-version.patch000066400000000000000000000014661474374657400203740ustar00rootroot00000000000000From 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 kpatch-0.9.10/examples/tcp_cubic-better-follow-cubic-curve-converted.patch000066400000000000000000000071761474374657400266640ustar00rootroot00000000000000The 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); kpatch-0.9.10/examples/tcp_cubic-better-follow-cubic-curve-original.patch000066400000000000000000000033011474374657400264610ustar00rootroot00000000000000This 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", kpatch-0.9.10/kmod/000077500000000000000000000000001474374657400140325ustar00rootroot00000000000000kpatch-0.9.10/kmod/Makefile000066400000000000000000000012031474374657400154660ustar00rootroot00000000000000include ../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 kpatch-0.9.10/kmod/core/000077500000000000000000000000001474374657400147625ustar00rootroot00000000000000kpatch-0.9.10/kmod/core/Makefile000066400000000000000000000012121474374657400164160ustar00rootroot00000000000000# 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 kpatch-0.9.10/kmod/core/core.c000066400000000000000000001013241474374657400160570ustar00rootroot00000000000000/* * 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"); kpatch-0.9.10/kmod/core/kpatch.h000066400000000000000000000047331474374657400164140ustar00rootroot00000000000000/* * 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_ */ kpatch-0.9.10/kmod/core/shadow.c000066400000000000000000000105051474374657400164140ustar00rootroot00000000000000/* * 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); kpatch-0.9.10/kmod/patch/000077500000000000000000000000001474374657400151315ustar00rootroot00000000000000kpatch-0.9.10/kmod/patch/Makefile000066400000000000000000000012551474374657400165740ustar00rootroot00000000000000KPATCH_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 clean: $(RM) -Rf .*.o.cmd .*.ko.cmd .tmp_versions $(BUILDABLE_OBJS) *.ko *.mod.c \ Module.symvers kpatch-0.9.10/kmod/patch/kpatch-macros.h000066400000000000000000000123311474374657400200360ustar00rootroot00000000000000#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__); \ }) /* * KPATCH_STATIC_CALL macro * * Replace usages of static_call() with this macro, when create-diff-object * recommends it due to the original static call key living in a module. * * This converts the static call to a regular indirect call. */ #define KPATCH_STATIC_CALL(name) \ ((typeof(STATIC_CALL_TRAMP(name))*)(STATIC_CALL_KEY(name).func)) #endif /* __KPATCH_MACROS_H_ */ kpatch-0.9.10/kmod/patch/kpatch-patch-hook.c000066400000000000000000000256351474374657400206150ustar00rootroot00000000000000/* * 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"); kpatch-0.9.10/kmod/patch/kpatch-patch.h000066400000000000000000000030661474374657400176560ustar00rootroot00000000000000/* * 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_ */ kpatch-0.9.10/kmod/patch/kpatch-syscall.h000066400000000000000000000267651474374657400202440ustar00rootroot00000000000000#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. Since the * kpatch versions do not provide SYSCALL_METADATA, specifically entries in the * __syscalls_metadata and _ftrace_events sections, provide dummy values in * these sections and instruct kpatch-build to ignore changes to them. * * To patch a syscall, just replace the use of the SYSCALL_DEFINE1 (or similar) * macro with the "KPATCH_" prefixed version. */ #define KPATCH_SYSCALL_METADATA(sname) \ static struct syscall_metadata __used \ __section("__syscalls_metadata") \ *__p_syscall_meta_##sname = NULL; \ KPATCH_IGNORE_SECTION("__syscalls_metadata"); \ \ static struct trace_event_call __used \ __section("_ftrace_events") \ *__event_enter_##sname = NULL; \ 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_SYSCALL_METADATA(sname); \ __KPATCH_SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #ifdef CONFIG_X86_64 /* arch/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) # if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) # define KPATCH_SYSCALL_WRAPPERS_V2 # else # define KPATCH_SYSCALL_WRAPPERS_V1 # endif # if defined(RHEL_RELEASE_CODE) # if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9, 6) # define KPATCH_SYSCALL_WRAPPERS_V2 # else # define KPATCH_SYSCALL_WRAPPERS_V1 # endif # endif /* arch/s390/include/asm/syscall_wrapper.h versions */ #if defined(KPATCH_SYSCALL_WRAPPERS_V1) #if defined(CONFIG_COMPAT) #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; \ } #else #define __KPATCH_S390_SYS_STUBx(x, name, ...) #endif /* CONFIG_COMPAT */ #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__)) # else /* KPATCH_SYSCALL_WRAPPERS_V2 */ #if defined(CONFIG_COMPAT) #define __KPATCH_S390_SYS_STUBx(x, name, ...) \ long __s390_sys##name(struct pt_regs *regs); \ ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO); \ static inline long ___se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__)); \ long __s390_sys##name(struct pt_regs *regs) \ { \ return ___se_sys##name(SC_S390_REGS_TO_ARGS(x, __VA_ARGS__)); \ } \ static inline long ___se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__)) \ { \ __MAP(x, __SC_TEST, __VA_ARGS__); \ return __kpatch_do_sys##name(__MAP(x, __SC_COMPAT_CAST, __VA_ARGS__)); \ } #else #define __KPATCH_S390_SYS_STUBx(x, name, ...) #endif /* CONFIG_COMPAT */ #define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ long __s390x_sys##name(struct pt_regs *regs); \ ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \ static inline long __se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__)); \ static inline long __kpatch_do_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)); \ __KPATCH_S390_SYS_STUBx(x, name, __VA_ARGS__); \ long __s390x_sys##name(struct pt_regs *regs) \ { \ return __se_sys##name(SC_S390_REGS_TO_ARGS(x, __VA_ARGS__)); \ } \ static inline long __se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__)) \ { \ __MAP(x, __SC_TEST, __VA_ARGS__); \ return __kpatch_do_sys##name(__MAP(x, __SC_CAST, __VA_ARGS__)); \ } \ static inline long __kpatch_do_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) #endif /* KPATCH_SYSCALL_WRAPPERS_V2 */ #elif defined(CONFIG_PPC64) /* arch/powerpc/include/asm/syscall_wrapper.h versions */ # if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0) # define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ long sys##name(const struct pt_regs *regs); \ ALLOW_ERROR_INJECTION(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__));\ __attribute__((optimize("-fno-optimize-sibling-calls"))) \ long sys##name(const struct pt_regs *regs) \ { \ return __se_sys##name(SC_POWERPC_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 /* LINUX_VERSION_CODE */ #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_ */ kpatch-0.9.10/kmod/patch/kpatch.h000077700000000000000000000000001474374657400213352../core/kpatch.hustar00rootroot00000000000000kpatch-0.9.10/kmod/patch/kpatch.lds.S000066400000000000000000000030211474374657400173040ustar00rootroot00000000000000__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); } } kpatch-0.9.10/kmod/patch/livepatch-patch-hook.c000066400000000000000000000412361474374657400213150ustar00rootroot00000000000000/* * 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"); kpatch-0.9.10/kmod/patch/patch-hook.c000066400000000000000000000016071474374657400173360ustar00rootroot00000000000000/* * 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) #include "livepatch-patch-hook.c" #else #include "kpatch-patch-hook.c" #endif kpatch-0.9.10/kpatch-build/000077500000000000000000000000001474374657400154475ustar00rootroot00000000000000kpatch-0.9.10/kpatch-build/Makefile000066400000000000000000000030761474374657400171150ustar00rootroot00000000000000include ../Makefile.inc CFLAGS += -std=gnu11 -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 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 -std=gnu11 -Wconversion, $(CFLAGS)) PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \ -Igcc-plugins -fPIC -fno-rtti -O2 -Wall endif ifeq ($(filter $(ARCH),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} kpatch-0.9.10/kpatch-build/create-diff-object.c000066400000000000000000003530251474374657400212400ustar00rootroot00000000000000/* * 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__); \ errx(EXIT_STATUS_DIFF_FATAL, "unreconcilable difference"); \ }) char *childobj; enum subsection { SUBSECTION_NORMAL, SUBSECTION_HOT, SUBSECTION_UNLIKELY }; enum loglevel loglevel = NORMAL; bool KLP_ARCH; int jump_label_errors, static_call_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 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); } /* * 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; uint64_t expected_offset; list_for_each_entry(sym, &kelf->symbols, list) { if (is_bundleable(sym)) { if (sym->pfx) expected_offset = sym->pfx->sym.st_size; else if (is_gcc6_localentry_bundled_sym(kelf, sym)) expected_offset = 8; else expected_offset = 0; if (sym->sym.st_value != expected_offset) { ERROR("symbol %s at offset %lu within section %s, expected %lu", sym->name, sym->sym.st_value, sym->sec->name, expected_offset); } 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 and patchable_function_entries * sections, we rebuild regardless */ if (!strcmp(sec->name, ".rela__mcount_loc") || !strcmp(sec->name, "__mcount_loc") || !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; } /* * 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_ubsan_sec(sec_orig->name)) 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 list_head *symlist_orig, struct list_head *symlist_patched) { struct symbol *sym_orig, *sym_patched; list_for_each_entry(sym_orig, symlist_orig, list) { if (sym_orig->twin) continue; list_for_each_entry(sym_patched, symlist_patched, list) { if (kpatch_mangled_strcmp(sym_orig->name, sym_patched->name) || sym_orig->type != sym_patched->type || sym_patched->twin) continue; if (is_ubsan_sec(sym_orig->name)) 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; /* 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->symbols, &kelf_patched->symbols); } 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; /* * UBSAN data will be taken wholesale, no need to * replace section symbols. */ if (is_ubsan_sec(rela->sym->name)) 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") || !strncmp(rela->sym->name, "__ftr_alt_", 10)) 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->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) { /* * 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 has no fentry/mcount call, 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 klp relocation. */ 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/klp_relocs 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) klp relocations 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->pfx) kpatch_include_symbol(sym->pfx); } 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 || sym->is_pfx) 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 call_sites_group_size(struct kpatch_elf *kelf, int offset) { return 4; } 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 relocations 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 bool static_call_sites_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; 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 == 1) key = rela; i++; } } if (i != 2 || !key || !code) ERROR("BUG: .static_call_sites has an unexpected format"); if (!strncmp(key->sym->name, "__SCK__tp_func_", 15)) tracepoint = true; /* * Static calls are only supported in the case where the corresponding * static call key lives in vmlinux (see explanation in * jump_table_group_filter). */ if (lookup_symbol(lookup, key->sym, &symbol) && strcmp(symbol.objname, "vmlinux")) { /* The key lives in a module -- not supported */ /* Inert tracepoints are harmless */ if (tracepoint) return false; /* * This will be upgraded to an error after all static call * errors have been reported. */ log_normal("Found a static call at %s()+0x%lx, using key %s, which is defined in a module. Use KPATCH_STATIC_CALL() instead.\n", code->sym->name, code->addend, key->sym->name); static_call_errors++; return false; } /* The key lives in vmlinux or the patch module itself */ return true; } static struct special_section special_sections[] = { { .name = "__bug_table", .arch = X86_64 | PPC64 | S390, .group_size = bug_table_group_size, }, { .name = ".fixup", .arch = X86_64 | PPC64 | S390, .group_size = fixup_group_size, }, { .name = "__ex_table", /* must come after .fixup */ .arch = X86_64 | PPC64 | S390, .group_size = ex_table_group_size, }, { .name = "__jump_table", .arch = X86_64 | PPC64 | S390, .group_size = jump_table_group_size, .group_filter = jump_table_group_filter, }, { .name = ".printk_index", .arch = 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 = X86_64 | S390, .group_size = altinstructions_group_size, }, { .name = ".static_call_sites", .arch = X86_64, .group_size = static_call_sites_group_size, .group_filter = static_call_sites_group_filter, }, { .name = ".call_sites", .arch = X86_64, .group_size = 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 (static_call_errors) ERROR("Found %d unsupported static call(s) in the patched code. Use KPATCH_STATIC_CALL() instead.", static_call_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; if (kelf->arch == X86_64) { if (!strcmp(sec->name, ".rela__patchable_function_entries") || !strcmp(sec->name, "__patchable_function_entries")) 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", 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_klp_reloc(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 klp relocations. */ 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 klp relocations, 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 klp relocation, 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 klp relocations. 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 klp relocation 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 klp relocation * 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 * klp relocation 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 klp relocation 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 relocations to klp * relocations. * * 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 * klp relocation 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_klp_reloc' here in the first pass * because the .toc section's 'need_klp_reloc' values * are dependent on all the other sections. Otherwise, * if we did this analysis in the second pass, we'd * have to convert .toc klp relocations at the very end. * * Specifically, this is needed for the powerpc * internal symbol function pointer check which is done * via .toc indirection in need_klp_reloc(). */ if (need_klp_reloc(kelf, table, relasec, rela)) toc_rela(rela)->need_klp_reloc = true; } } /* 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_klp_reloc) { 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 klp relocation 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", 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; } } } } /* * Create links between text sections and their corresponding * __patchable_function_entries sections (as there may be multiple pfe * sections). */ static void kpatch_set_pfe_link(struct kpatch_elf *kelf) { struct section* sec; struct rela *rela; if (!kelf->has_pfe) return; list_for_each_entry(sec, &kelf->sections, list) { if (strcmp(sec->name, "__patchable_function_entries")) continue; if (!sec->rela) continue; list_for_each_entry(rela, &sec->rela->relas, list) rela->sym->pfe = sec; } } /* * 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_create_ftrace_callsite_sections(struct kpatch_elf *kelf, bool has_pfe) { int nr, index; struct section *sec = NULL; struct symbol *sym, *rela_sym; struct rela *rela; void **funcs; unsigned long insn_offset = 0; unsigned int rela_offset; nr = 0; list_for_each_entry(sym, &kelf->symbols, list) if (sym->type == STT_FUNC && sym->status != SAME && sym->has_func_profiling) nr++; if (has_pfe) /* * Create separate __patchable_function_entries sections * for each function in the following loop. */ kelf->has_pfe = true; else /* * Create a single __mcount_loc section pair for all * functions. */ sec = create_section_pair(kelf, "__mcount_loc", sizeof(void*), nr); /* populate sections */ index = 0; list_for_each_entry(sym, &kelf->symbols, list) { if (sym->type != STT_FUNC || sym->status == SAME) continue; if (!sym->has_func_profiling) { log_debug("function %s has no ftrace callsite, no __patchable_function_entries/mcount record is needed\n", sym->name); continue; } switch(kelf->arch) { case PPC64: { unsigned char *insn; if (kelf->has_pfe) { insn_offset = sym->sym.st_value + PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other); insn = sym->sec->data->d_buf + insn_offset; /* verify nops */ if (insn[0] != 0x00 || insn[1] != 0x00 || insn[2] != 0x00 || insn[3] != 0x60 || insn[4] != 0x00 || insn[5] != 0x00 || insn[6] != 0x00 || insn[7] != 0x60) ERROR("%s: unexpected instruction in patch section of function\n", sym->name); } else { 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 (kelf->has_pfe) { /* * Allocate a dedicated __patchable_function_entries for this function: * - its .sh_link will be updated by kpatch_reindex_elements() * - its lone rela is based on the section symbol */ sec = create_section_pair(kelf, "__patchable_function_entries", sizeof(void *), 1); sec->sh.sh_flags |= SHF_WRITE | SHF_ALLOC | SHF_LINK_ORDER; rela_sym = sym->sec->secsym; rela_offset = 0; rela_sym->pfe = sec; } else { /* * mcount relas are based on the function symbol and saved in a * single aggregate __mcount_loc section */ rela_sym = sym; rela_offset = (unsigned int) (index * sizeof(*funcs)); } ALLOC_LINK(rela, &sec->rela->relas); rela->sym = rela_sym; rela->type = absolute_rela_type(kelf); rela->addend = insn_offset - rela->sym->sym.st_value; rela->offset = rela_offset; 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 * klp relocations 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; int sibling_call_errors = 0; 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; log_normal("Found an unsupported sibling call at %s()+0x%lx. Add __attribute__((optimize(\"-fno-optimize-sibling-calls\"))) to %s() definition.\n", sym->name, sym->sym.st_value + offset, sym->name); sibling_call_errors++; } } if (sibling_call_errors) ERROR("Found %d unsupported sibling call(s) in the patched code.", sibling_call_errors); } static bool kpatch_symbol_has_pfe_entry(struct kpatch_elf *kelf, struct symbol *sym) { struct section *sec; struct rela *rela; if (!kelf->has_pfe) return false; list_for_each_entry(sec, &kelf->sections, list) { if (strcmp(sec->name, "__patchable_function_entries")) continue; if (!sec->rela) continue; list_for_each_entry(rela, &sec->rela->relas, list) { if (rela->sym->sec && sym->sec == rela->sym->sec && rela->sym->pfe == sec) { return true; } } } return false; } /* 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->is_pfx || !sym->sec) continue; switch(kelf->arch) { case PPC64: if (kpatch_symbol_has_pfe_entry(kelf, sym)) { sym->has_func_profiling = 1; } else if (sym->sec->rela) { 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) { 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: /* 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"); } } } 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 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; bool has_pfe = false; 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); kpatch_set_pfe_link(kelf_orig); kpatch_set_pfe_link(kelf_patched); if (kelf_patched->has_pfe) has_pfe = true; 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); /* * 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 klp relocation 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_create_ftrace_callsite_sections(kelf_out, has_pfe); /* * 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; } kpatch-0.9.10/kpatch-build/create-klp-module.c000066400000000000000000000346151474374657400211360ustar00rootroot00000000000000/* * 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.rela section"); /* Add the klp relocation 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; } kpatch-0.9.10/kpatch-build/create-kpatch-module.c000066400000000000000000000170451474374657400216200ustar00rootroot00000000000000/* * 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; } kpatch-0.9.10/kpatch-build/gcc-plugins/000077500000000000000000000000001474374657400176625ustar00rootroot00000000000000kpatch-0.9.10/kpatch-build/gcc-plugins/gcc-common.h000066400000000000000000000572521474374657400220700ustar00rootroot00000000000000#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.h" #include "gimple-expr.h" #include "gimple-iterator.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-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 kpatch-0.9.10/kpatch-build/gcc-plugins/gcc-generate-rtl-pass.h000066400000000000000000000101021474374657400241140ustar00rootroot00000000000000/* 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 */ kpatch-0.9.10/kpatch-build/gcc-plugins/ppc64le-plugin.c000066400000000000000000000051161474374657400226020ustar00rootroot00000000000000#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; } kpatch-0.9.10/kpatch-build/insn/000077500000000000000000000000001474374657400164165ustar00rootroot00000000000000kpatch-0.9.10/kpatch-build/insn/asm/000077500000000000000000000000001474374657400171765ustar00rootroot00000000000000kpatch-0.9.10/kpatch-build/insn/asm/inat.h000066400000000000000000000137641474374657400203150ustar00rootroot00000000000000#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 kpatch-0.9.10/kpatch-build/insn/asm/inat_types.h000066400000000000000000000017651474374657400215370ustar00rootroot00000000000000#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 kpatch-0.9.10/kpatch-build/insn/asm/insn.h000066400000000000000000000135371474374657400203270ustar00rootroot00000000000000#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 */ kpatch-0.9.10/kpatch-build/insn/inat-tables.c000066400000000000000000001172231474374657400207730ustar00rootroot00000000000000/* 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, }; kpatch-0.9.10/kpatch-build/insn/inat.c000066400000000000000000000051021474374657400175130ustar00rootroot00000000000000/* * 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]; } kpatch-0.9.10/kpatch-build/insn/insn.c000066400000000000000000000345471474374657400175460ustar00rootroot00000000000000/* * 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); } kpatch-0.9.10/kpatch-build/kpatch-build000077500000000000000000001364231474374657400177550ustar00rootroot00000000000000#!/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 VERSION=0.9.9 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=1 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" declare -rA SUPPORTED_DEB_DISTROS=( ["debian"]="Debian OS" ["ubuntu"]="Ubuntu OS") declare -rA SUPPORTED_RPM_DISTROS=( ["opencloudos"]="OpenCloudOS" ["anolis"]="Anolis OS" ["centos"]="CentOS" ["fedora"]="Fedora" ["openEuler"]="OpenEuler" ["ol"]="Oracle" ["photon"]="Photon OS" ["rhel"]="RHEL" ["amzn"]="Amazon Linux") 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 --strip=1 "$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) } # List of kernel tree files that kpatch-build backed up to # $KERNEL_BACKUPDIR before modification declare -a BACKUP_KERNEL_FILES KERNEL_BACKUPDIR="$TEMPDIR/kernel-backup" # Save a kernel file (i.e. "scripts/Makefile.modfinal") backup_kernel_file() { local kernel_path="$1" if [[ ! -e "$KERNEL_SRCDIR/$kernel_path" ]]; then die "Kernel path not found: $KERNEL_SRCDIR/$kernel_path" fi mkdir --parents "$KERNEL_BACKUPDIR/$(dirname "$kernel_path")" || die cp --force "$KERNEL_SRCDIR/$kernel_path" "$KERNEL_BACKUPDIR/$kernel_path" || die BACKUP_KERNEL_FILES+=("$kernel_path") } # Restore all kernel files backed up by backup_kernel_file() restore_kernel_files() { for kernel_path in "${BACKUP_KERNEL_FILES[@]}"; do if ! mv --force "$KERNEL_BACKUPDIR/$kernel_path" "$KERNEL_SRCDIR/$kernel_path"; then warn "Couldn't restore kernel path: $kernel_path" fi done } cleanup() { rm -f "$BUILDDIR/.scmversion" remove_patches restore_kernel_files [[ "$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 } 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:.*' } 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")" kgccver="$(gcc_version_from_file "$target")" 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 case "$ARCH" in "x86_64") check[a]=true # alt_instr kernel_version_gte 5.10.0 && check[s]=true # static_call_site [[ -n "$CONFIG_PARAVIRT" ]] && ! kernel_version_gte 6.8.0 && 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 } is_supported_deb_distro(){ [[ -n "$1" ]] && [[ -n "${SUPPORTED_DEB_DISTROS[$1]:-}" ]] } is_supported_rpm_distro(){ [[ -n "$1" ]] && [[ -n "${SUPPORTED_RPM_DISTROS[$1]:-}" ]] } print_supported_distro(){ if is_supported_deb_distro "$DISTRO"; then echo "${SUPPORTED_DEB_DISTROS[$DISTRO]} distribution detected" elif is_supported_rpm_distro "$DISTRO"; then echo "${SUPPORTED_RPM_DISTROS[$DISTRO]} distribution detected" else echo "$DISTRO is not supported" fi } 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 echo " --version Version of kpatch-build" } if ! command -v gawk &> /dev/null; then die "gawk not installed" fi 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,version" -- "$@")" || 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 ;; --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 ;; --version) echo "Version : $VERSION" exit 0 ;; *) [[ "$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 [[ ! -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 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" ]]; then die "Unable to determine the kernel version from vmlinux" fi ARCHVERSION="$VMLINUX_VER" 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 # Don't check external file. # shellcheck disable=SC1090 if [[ -z "$USERSRCDIR" ]] && [[ -f "$RELEASE_FILE" ]]; then source "$RELEASE_FILE" DISTRO="$ID" fi KVER="${ARCHVERSION%%-*}" if [[ "$ARCHVERSION" =~ - ]]; then # handle flavor extension on Photon ex) -rt, -esx if [[ "$DISTRO" = photon ]]; then KREL="${ARCHVERSION#*-}" # strip rt patchset version if present # remove trailing -flavor and starting -rt### patchset KREL="${KREL%-*}" KREL="${KREL#*-}" PH_TAG="${ARCHVERSION##*.}" PH_FLAVOR="${PH_TAG##*-}" PH_TAG="${PH_TAG%%-*}" # if no flavor, these will be the same [[ "$PH_FLAVOR" = "$PH_TAG" ]] && PH_FLAVOR="" else KREL="${ARCHVERSION##*-}" fi KREL="${KREL%.*}" fi [[ "$ARCHVERSION" =~ .el7a. ]] && ALT="-alt" [[ -z "$TARGETS" ]] && TARGETS="vmlinux modules" if is_supported_rpm_distro "$DISTRO"; 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 is_supported_deb_distro "$DISTRO"; 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 backup_kernel_file "vmlinux" VMLINUX="$KERNEL_BACKUPDIR/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 is_supported_rpm_distro "$DISTRO"; then print_supported_distro "$DISTRO" 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 elif [[ "$DISTRO" = photon ]]; then if [[ -n "$PH_FLAVOR" ]]; then SRC_RPM_NAME="linux-$PH_FLAVOR-$KVER-$KREL.$PH_TAG.src.rpm" else SRC_RPM_NAME="linux-${ARCHVERSION}.src.rpm" fi PHOTON_VERSION="${PH_TAG//[^0-9]/}".0 wget -P "$TEMPDIR" "https://packages.vmware.com/photon/$PHOTON_VERSION/photon_srpms_${PHOTON_VERSION}_${ARCH}/$SRC_RPM_NAME" 2>&1 | logger || die SRCRPM="$TEMPDIR/$SRC_RPM_NAME" 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 if [ -z "$SRCRPM" ]; then SRCRPM="$TEMPDIR/kernel$ALT-$KVER-$KREL.src.rpm" fi fi echo "Unpacking kernel source" if [[ "$DISTRO" = photon ]]; then [[ -n "$PH_FLAVOR" ]] && SPECNAME="linux-$PH_FLAVOR.spec" || SPECNAME="linux.spec" else SPECNAME="kernel$ALT.spec" fi rpm -D "_topdir $RPMTOPDIR" -ivh "$SRCRPM" 2>&1 | logger || die # Define dist tag to handle rpmbuild of the linux src rpm in Photon if [[ "$DISTRO" = photon ]] && [ "$(rpm -E %dist)" = "%dist" ]; then sed -i "1s/^/%define dist .$PH_TAG/" "$RPMTOPDIR"/SPECS/"$SPECNAME" fi rpmbuild -D "_topdir $RPMTOPDIR" -bp --nodeps "--target=$(uname -m)" "$RPMTOPDIR"/SPECS/"$SPECNAME" 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 elif [[ "$DISTRO" = opencloudos ]]; then mv "$RPMTOPDIR"/BUILD/kernel-*/kernel-* "$KERNEL_SRCDIR" 2>&1 | logger || die elif [[ "$DISTRO" = photon ]]; then # Photon has some files that are copied over during the build section of the spec file (instead of prep) # These change occasionally, so check they exist before copying ls "$RPMTOPDIR"/BUILD/fips*canister* &> /dev/null && ( cp -rT "$RPMTOPDIR"/BUILD/fips*canister* "$RPMTOPDIR"/BUILD/linux-"$KVER"/crypto | logger || die ) [[ -f "$RPMTOPDIR"/SOURCES/fips_canister-kallsyms ]] && ( cp "$RPMTOPDIR"/SOURCES/fips_canister-kallsyms rpmbuild/BUILD/linux-"$KVER"/crypto | logger || die ) if [[ -z "$CONFIGFILE" ]]; then # Photon has multiple config files per src rpm sometimes, and naming is not consistent. # So do our best to find the right one by parsing the spec file SRC_CFG=$(rpmspec -P -D "_topdir $RPMTOPDIR" "$RPMTOPDIR"/SPECS/"$SPECNAME" | awk '/^cp .*\/SOURCES\/config.* \.config$/{print $2}') [[ -z "$SRC_CFG" ]] && die "Failed to locate kernel config file" SRC_CFG="${SRC_CFG##*/}" cp "$RPMTOPDIR"/SOURCES/"$SRC_CFG" "$RPMTOPDIR"/BUILD/linux-"$KVER" | logger || die fi mv "$RPMTOPDIR"/BUILD/linux-"$KVER" "$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" == *-* ]] && [[ ! "$DISTRO" = photon ]]; then sed -i "s/^EXTRAVERSION.*/EXTRAVERSION = -${ARCHVERSION##*-}/" "$KERNEL_SRCDIR/Makefile" || die fi echo "$ARCHVERSION" > "$VERSIONFILE" || die if [[ "$DISTRO" = openEuler ]] || [[ "$DISTRO" = opencloudos ]]; then [[ -z "$CONFIGFILE" ]] && CONFIGFILE="/boot/config-${ARCHVERSION}" elif [[ "$DISTRO" = photon ]]; then [[ -z "$CONFIGFILE" ]] && CONFIGFILE="$KERNEL_SRCDIR/$SRC_CFG" # modify config file here to get the right vermagic, as Photon does not always listen to localversion file if [[ -z "$PH_FLAVOR" ]]; then sed -i s/^CONFIG_LOCALVERSION=\".*\"/CONFIG_LOCALVERSION=\"-"$KREL"."$PH_TAG"\"/g "$CONFIGFILE" || die else sed -i s/^CONFIG_LOCALVERSION=\".*\"/CONFIG_LOCALVERSION=\"-"$KREL"."$PH_TAG"-"$PH_FLAVOR"\"/g "$CONFIGFILE" || die fi else [[ -z "$CONFIGFILE" ]] && CONFIGFILE="$KERNEL_SRCDIR/configs/kernel$ALT-$KVER-$ARCH.config" fi (cd "$KERNEL_SRCDIR" && make mrproper 2>&1 | logger) || die elif is_supported_deb_distro "$DISTRO"; then print_supported_distro "$DISTRO" 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 # When the kernel source is in a git repo, applying the patch (plus the # Makefile sed hacks we do) can cause it to be built with "+" or "dirty" # appended to the kernel version string (VERMAGIC_STRING), even if the original # kernel was not dirty. That can complicate both the build (create-diff-object # false positive changes) and the patch module link (module version mismatch # load failures). Before making any changes to the source: # # For pre-v6.3 kernels: # Run `./scripts/setlocalversion --save-scmversion`. # # For v6.3+ kernels: # Replace the original setlocalversion with a friendlier one which just echo's # the original version. if [[ -n "$USERSRCDIR" && -e "$KERNEL_SRCDIR/.git" ]]; then cd "$KERNEL_SRCDIR" || die if ! ./scripts/setlocalversion --save-scmversion &>/dev/null; then backup_kernel_file "scripts/setlocalversion" LOCALVERSION="$(make --no-print-directory kernelversion)" LOCALVERSION="$(KERNELVERSION="$LOCALVERSION" ./scripts/setlocalversion)" [[ -n "$LOCALVERSION" ]] || die "setlocalversion failed" echo "echo $LOCALVERSION" > scripts/setlocalversion fi 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 if [[ -n "$CONFIG_LIVEPATCH" ]] && (kernel_is_rhel || kernel_version_gte 4.9.0); then 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 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" [[ -n "$CONFIG_X86_KERNEL_IBT" ]] && die "kernel option 'CONFIG_X86_KERNEL_IBT' 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 backup_kernel_file "scripts/link-vmlinux.sh" 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 backup_kernel_file "scripts/Makefile.modfinal" sed -i 's/CONFIG_DEBUG_INFO_BTF_MODULES/DISABLED_FOR_KPATCH_BUILD/g' "$KERNEL_SRCDIR"/scripts/Makefile.modfinal || die fi fi # CONFIG_LD_ORPHAN_WARN_LEVEL="error" will fail kernel builds with # --ffunction-sections with lots of "ld: error: unplaced orphan section" # errors. Temporarily demote to "warn"ings in the kernel Makefile. if [[ "$CONFIG_LD_ORPHAN_WARN_LEVEL" == "error" ]]; then backup_kernel_file "Makefile" sed -i 's/--orphan-handling=[$](CONFIG_LD_ORPHAN_WARN_LEVEL)/--orphan-handling="warn"/g' "$KERNEL_SRCDIR/Makefile" || die 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 preserves mode and the files might have been read-only. This would # interfere with cleanup later, so ensure the $TEMPDIR is read/write. cp -LR "$DATADIR/patch" "$TEMPDIR" || die chmod -R u+rw "$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" ! kernel_version_gte 6.10.0 && ARCH_KCFLAGS+=" -fPIE" 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 fi save_env echo "Building original source" 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 # 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 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 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" kpatch-0.9.10/kpatch-build/kpatch-cc000077500000000000000000000037131474374657400172360ustar00rootroot00000000000000#!/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/*|\ drivers/firmware/efi/libstub/*|\ init/version.o|\ init/version-timestamp.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[@]}" kpatch-0.9.10/kpatch-build/kpatch-elf.c000077500000000000000000000711061474374657400176410ustar00rootroot00000000000000/* * 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_section_by_name(struct list_head *list, const char *name) { struct section *sec; list_for_each_entry(sec, list, list) if (!strcmp(sec->name, name)) return sec; return NULL; } 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 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 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 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"); } /* * Some x86 kernels have NOP function padding [1] for which objtool [2] * adds ELF function symbols with prefix "__pfx_" to indicate the start * of a function, inclusive of NOP-padding. Find the prefix symbols and * link them to their corresponding function symbols at an expected * offset. * * A few examples: * * Value Size Type Bind Vis Ndx Name * (fork.o, simple case) * 0000000000000000 0 SECTION LOCAL DEFAULT 31 .text.get_task_mm * 0000000000000000 16 FUNC GLOBAL DEFAULT 31 __pfx_get_task_mm * 0000000000000010 91 FUNC GLOBAL DEFAULT 31 get_task_mm * * (fork.o, multiple function aliases) * 0000000000000000 0 SECTION LOCAL DEFAULT 190 .text.__do_sys_fork * 0000000000000000 16 FUNC GLOBAL DEFAULT 190 __pfx___x64_sys_fork * 0000000000000010 49 FUNC LOCAL DEFAULT 190 __do_sys_fork * 0000000000000010 49 FUNC GLOBAL DEFAULT 190 __ia32_sys_fork * 0000000000000010 49 FUNC GLOBAL DEFAULT 190 __x64_sys_fork * * (fork.o multiple functions in one section) * 0000000000000000 0 SECTION LOCAL DEFAULT 59 .init.text * 0000000000000000 16 FUNC LOCAL DEFAULT 59 __pfx_coredump_filter_setup * 0000000000000010 40 FUNC LOCAL DEFAULT 59 coredump_filter_setup * 0000000000000038 16 FUNC WEAK DEFAULT 59 __pfx_arch_task_cache_init * 0000000000000048 10 FUNC WEAK DEFAULT 59 arch_task_cache_init * 0000000000000052 16 FUNC GLOBAL DEFAULT 59 __pfx_fork_init * 0000000000000062 357 FUNC GLOBAL DEFAULT 59 fork_init * 00000000000001c7 16 FUNC GLOBAL DEFAULT 59 __pfx_fork_idle * 00000000000001d7 214 FUNC GLOBAL DEFAULT 59 fork_idle * 00000000000002ad 16 FUNC GLOBAL DEFAULT 59 __pfx_mm_cache_init * 00000000000002bd 72 FUNC GLOBAL DEFAULT 59 mm_cache_init * 0000000000000305 16 FUNC GLOBAL DEFAULT 59 __pfx_proc_caches_init * 0000000000000315 192 FUNC GLOBAL DEFAULT 59 proc_caches_init * * (fork.o, function without nop padding / __pfx_ symbol) * 0000000000000000 0 SECTION LOCAL DEFAULT 99 .text.unlikely.__mmdrop * 0000000000000000 48 FUNC LOCAL DEFAULT 99 __mmdrop.cold * * (kpatch-build generated tmp.ko, multple functions in one section, no __pfx_ symbols) * 0000000000000000 0 SECTION LOCAL DEFAULT 10 .text.unlikely.callback_info.isra.0 * 0000000000000010 65 FUNC LOCAL DEFAULT 10 callback_info.isra.0 * 0000000000000061 54 FUNC LOCAL DEFAULT 10 callback_info.isra.0 * 00000000000000a7 54 FUNC LOCAL DEFAULT 10 callback_info.isra.0 * * CONFIG_CFI_CLANG uses something very similar, except the symbol is created * by the compiler and its prefix is "__cfi_". * * [1] bea75b33895f ("x86/Kconfig: Introduce function padding") * [2] 9f2899fe36a6 ("objtool: Add option to generate prefix symbols") */ static void kpatch_link_prefixed_functions(struct kpatch_elf *kelf) { struct symbol *func, *pfx; bool found; if (kelf->arch != X86_64) return; list_for_each_entry(pfx, &kelf->symbols, list) { if (!pfx->name || pfx->type != STT_FUNC) continue; if (strncmp(pfx->name, "__pfx_", 6) && strncmp(pfx->name, "__cfi_", 6)) continue; found = false; list_for_each_entry(func, &kelf->symbols, list) { if (func->type == STT_FUNC && func->sec == pfx->sec && func->sym.st_value == pfx->sym.st_value + pfx->sym.st_size) { /* * If a func has aliases, it's possible for * multiple functions to have the same 'pfx'. */ pfx->is_pfx = true; func->pfx = pfx; found = true; } } if (!found) ERROR("missing func for %s", pfx->name); } } 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"); } kpatch_link_prefixed_functions(kelf); } 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_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); } /* * x86_64's pfe sections are only a side effect * CONFIG_CALL_PADDING building with * -fpatchable-function-entry=16,16, * These sections aren't used by ftrace on this arch, so do not * bother reading/writing them for x86_64. */ if (kelf->arch != X86_64) if (find_section_by_name(&kelf->sections, "__patchable_function_entries")) kelf->has_pfe = true; 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); if (sec->secsym && sec->secsym->pfe) printf(", pfe-> [%d]", (sec->secsym->pfe) == NULL ? -1 : (int)sec->secsym->pfe->index); } 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(", profiling: %d", sym->has_func_profiling); } 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; } bool is_ubsan_sec(const char *name) { if (!strncmp(name, ".data.rel.local..Lubsan_data", 28) || !strncmp(name, ".data..Lubsan_type", 18) || !strncmp(name, ".Lubsan_data", 12) || !strncmp(name, ".data..Lubsan_data", 18) || !strncmp(name, ".rela.data..Lubsan_data", 23) || !strncmp(name, ".rela.data.rel.local..Lubsan_data", 33)) return true; else return false; } 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; relasec->sh.sh_flags = SHF_INFO_LINK; /* 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->pfe) sym->pfe->sh.sh_link = 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; ehout.e_flags = eh.e_flags; 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); } kpatch-0.9.10/kpatch-build/kpatch-elf.h000066400000000000000000000115661474374657400176470ustar00rootroot00000000000000/* * 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; }; }; }; enum symbol_strip { SYMBOL_DEFAULT, SYMBOL_USED, SYMBOL_STRIP, }; struct symbol { struct list_head list; struct symbol *twin; struct symbol *parent; struct symbol *pfx; 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; bool is_pfx; struct section *pfe; }; struct rela { struct list_head list; GElf_Rela rela; struct symbol *sym; unsigned int type; unsigned int offset; long addend; char *string; bool need_klp_reloc; }; struct string { struct list_head list; char *name; }; enum architecture { PPC64 = 0x1 << 0, X86_64 = 0x1 << 1, S390 = 0x1 << 2, }; 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; bool has_pfe; }; /******************* * 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 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); bool is_ubsan_sec(const char *name); 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_ */ kpatch-0.9.10/kpatch-build/kpatch-intermediate.h000066400000000000000000000025641474374657400215510ustar00rootroot00000000000000/* * 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_ */ kpatch-0.9.10/kpatch-build/kpatch.h000066400000000000000000000003051474374657400170700ustar00rootroot00000000000000#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_ */ kpatch-0.9.10/kpatch-build/list.h000066400000000000000000000150331474374657400165750ustar00rootroot00000000000000/* * 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) __builtin_offsetof(TYPE, 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_ */ kpatch-0.9.10/kpatch-build/log.h000066400000000000000000000011751474374657400164050ustar00rootroot00000000000000#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, ...) \ errx(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_ */ kpatch-0.9.10/kpatch-build/lookup.c000066400000000000000000000334411474374657400171310ustar00rootroot00000000000000/* * 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) || is_ubsan_sec(name)) 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 bool file_has_locals(struct symbol *file_sym, struct list_head *sym_list) { struct symbol *sym = file_sym; list_for_each_entry_continue(sym, sym_list, list) { if (sym->type == STT_FILE) break; if (sym->type != STB_LOCAL) continue; if (maybe_discarded_sym(sym->name)) continue; if (sym->type == STT_FUNC || sym->type == STT_OBJECT) return true; } return false; } 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 (!file_has_locals(file_sym, sym_list)) { /* * If the file doesn't have local symbols, any empty * match will do. Skip the duplicate check. */ break; } } 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); } kpatch-0.9.10/kpatch-build/lookup.h000066400000000000000000000010241474374657400171260ustar00rootroot00000000000000#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_ */ kpatch-0.9.10/kpatch/000077500000000000000000000000001474374657400143525ustar00rootroot00000000000000kpatch-0.9.10/kpatch/Makefile000066400000000000000000000002211474374657400160050ustar00rootroot00000000000000include ../Makefile.inc all: install: all $(INSTALL) -d $(SBINDIR) $(INSTALL) kpatch $(SBINDIR) uninstall: $(RM) $(SBINDIR)/kpatch clean: kpatch-0.9.10/kpatch/kpatch000077500000000000000000000402121474374657400155510ustar00rootroot00000000000000#!/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.10" 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" 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 kpatch-0.9.10/man/000077500000000000000000000000001474374657400136535ustar00rootroot00000000000000kpatch-0.9.10/man/Makefile000066400000000000000000000006371474374657400153210ustar00rootroot00000000000000include ../Makefile.inc all: kpatch.1.gz kpatch-build.1.gz kpatch.1.gz: kpatch.1 gzip -n -c -9 $< > $@ kpatch-build.1.gz: kpatch-build.1 gzip -n -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 kpatch-0.9.10/man/kpatch-build.1000066400000000000000000000036711474374657400163130ustar00rootroot00000000000000.\" 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 kpatch-0.9.10/man/kpatch.1000066400000000000000000000027221474374657400152120ustar00rootroot00000000000000.\" 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 kpatch-0.9.10/test/000077500000000000000000000000001474374657400140575ustar00rootroot00000000000000kpatch-0.9.10/test/difftree.sh000077500000000000000000000053241474374657400162120ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/000077500000000000000000000000001474374657400164025ustar00rootroot00000000000000kpatch-0.9.10/test/integration/.gitignore000066400000000000000000000000301474374657400203630ustar00rootroot00000000000000test.log COMBINED.patch kpatch-0.9.10/test/integration/Makefile000066400000000000000000000023301474374657400200400ustar00rootroot00000000000000include /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" kpatch-0.9.10/test/integration/amzn-2023/000077500000000000000000000000001474374657400177335ustar00rootroot00000000000000kpatch-0.9.10/test/integration/amzn-2023/data-new-LOADED.test000077500000000000000000000000641474374657400232650ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/amzn-2023/data-new.patch000066400000000000000000000011551474374657400224560ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-01-12 11:20:07.184710563 -0500 +++ src/fs/proc/meminfo.c 2023-01-12 11:20:08.166716386 -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; @@ -154,6 +156,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); kpatch-0.9.10/test/integration/amzn-2023/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400250140ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2023-01-12 11:20:07.630713207 -0500 +++ src/net/ipv6/netfilter.c 2023-01-12 11:20:29.874845095 -0500 @@ -96,6 +96,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) { @@ -109,6 +111,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) kpatch-0.9.10/test/integration/amzn-2023/macro-callbacks.patch000066400000000000000000000107731474374657400240020ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2023-01-12 11:20:06.597707083 -0500 +++ src/drivers/input/joydev.c 2023-01-12 11:20:38.032893465 -0500 @@ -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 2023-01-12 11:20:06.578706970 -0500 +++ src/drivers/input/misc/pcspkr.c 2023-01-12 11:20:38.032893465 -0500 @@ -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 2023-01-12 11:20:07.273711091 -0500 +++ src/fs/aio.c 2023-01-12 11:20:38.033893471 -0500 @@ -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 kpatch-0.9.10/test/integration/amzn-2023/module-LOADED.test000077500000000000000000000003151474374657400230510ustar00rootroot00000000000000#!/bin/bash set -o errexit sudo modprobe xfs sleep 5 echo "file fs/xfs/xfs_stats.c +p" > /sys/kernel/debug/dynamic_debug/control grep -q kpatch /sys/fs/xfs/stats/stats dmesg | grep -q "kpatch: pr_debug" kpatch-0.9.10/test/integration/amzn-2023/module.patch000066400000000000000000000040351474374657400222430ustar00rootroot00000000000000kpatch 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 --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c index 90a77cd3ebad..f65df90ae8e1 100644 --- a/fs/xfs/xfs_stats.c +++ b/fs/xfs/xfs_stats.c @@ -16,6 +16,8 @@ static int counter_val(struct xfsstats __percpu *stats, int idx) return val; } +extern char *kpatch_string(void); + int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { int i, j; @@ -85,6 +87,34 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) 0); #endif + /* Reference a symbol outside the .o yet inside the patch module: */ + len += scnprintf(buf + len, PATH_MAX-len, "%s\n", kpatch_string()); + +#ifdef CONFIG_X86_64 + /* Test alternatives patching: */ + alternative("ud2", "nop", X86_FEATURE_ALWAYS); + alternative("nop", "ud2", X86_FEATURE_IA64); + + /* Test paravirt patching: */ + slow_down_io(); /* paravirt call */ +#endif + + /* Test pr_debug: */ + pr_debug("kpatch: pr_debug() test\n"); + +{ + /* Test static branches: */ + 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); +} + return len; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c64277659753..05b753c2ec84 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2980,4 +2980,9 @@ static int __init netlink_proto_init(void) panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "kpatch"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/amzn-2023/multiple.test000077500000000000000000000002451474374657400224730ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/amzn-2023/new-function.patch000066400000000000000000000016561474374657400234000ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2023-01-12 11:20:06.978709342 -0500 +++ src/drivers/tty/n_tty.c 2023-01-12 11:20:54.149989024 -0500 @@ -2315,7 +2315,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; @@ -2402,6 +2402,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 kpatch-0.9.10/test/integration/amzn-2023/new-globals.patch000066400000000000000000000021761474374657400231740ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-01-12 11:20:07.184710563 -0500 +++ src/fs/proc/cmdline.c 2023-01-12 11:21:02.411038005 -0500 @@ -21,3 +21,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 2023-01-12 11:20:07.184710563 -0500 +++ src/fs/proc/meminfo.c 2023-01-12 11:21:02.411038005 -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); kpatch-0.9.10/test/integration/amzn-2023/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400243360ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/amzn-2023/shadow-newpid.patch000066400000000000000000000045731474374657400235360ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2023-01-12 11:20:07.182710551 -0500 +++ src/fs/proc/array.c 2023-01-12 11:21:10.821087869 -0500 @@ -397,12 +397,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 2023-01-12 11:20:05.408700033 -0500 +++ src/kernel/exit.c 2023-01-12 11:21:10.822087875 -0500 @@ -802,6 +802,7 @@ static void synchronize_group_exit(struc spin_unlock_irq(&sighand->siglock); } +#include void __noreturn do_exit(long code) { struct task_struct *tsk = current; @@ -867,6 +868,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 2023-01-12 11:20:05.408700033 -0500 +++ src/kernel/fork.c 2023-01-12 11:21:10.824087886 -0500 @@ -2637,6 +2637,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; @@ -2645,6 +2646,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 @@ -2684,6 +2687,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. kpatch-0.9.10/test/integration/amzn-2023/special-static.patch000066400000000000000000000010441474374657400236600ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2023-01-12 11:20:05.408700033 -0500 +++ src/kernel/fork.c 2023-01-12 11:21:19.186137466 -0500 @@ -1700,10 +1700,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; kpatch-0.9.10/test/integration/amzn-2023/symvers-disagreement-FAIL.patch000066400000000000000000000027411474374657400256460ustar00rootroot00000000000000From 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 2023-01-12 11:20:06.403705933 -0500 +++ src/drivers/base/core.c 2023-01-12 11:21:27.466186559 -0500 @@ -36,6 +36,8 @@ #include "physical_location.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 2023-01-12 11:20:06.490706448 -0500 +++ src/drivers/usb/core/usb.c 2023-01-12 11:21:27.468186571 -0500 @@ -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; kpatch-0.9.10/test/integration/amzn-2023/syscall-LOADED.test000077500000000000000000000000471474374657400232400ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/amzn-2023/syscall.patch000066400000000000000000000011631474374657400224270ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2023-01-12 11:20:05.406700021 -0500 +++ src/kernel/sys.c 2023-01-12 11:21:35.782235867 -0500 @@ -1285,13 +1285,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; kpatch-0.9.10/test/integration/amzn-2023/warn-detect-FAIL.patch000066400000000000000000000004671474374657400237110ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2023-01-12 11:20:04.716695930 -0500 +++ src/arch/x86/kvm/x86.c 2023-01-12 11:21:44.162285556 -0500 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/centos-7000077700000000000000000000000001474374657400212252rhel-7.8/ustar00rootroot00000000000000kpatch-0.9.10/test/integration/centos-8000077700000000000000000000000001474374657400211422rhel-8.2ustar00rootroot00000000000000kpatch-0.9.10/test/integration/common/000077500000000000000000000000001474374657400176725ustar00rootroot00000000000000kpatch-0.9.10/test/integration/common/multiple.template000077500000000000000000000032501474374657400232650ustar00rootroot00000000000000SCRIPTDIR="$(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 kpatch-0.9.10/test/integration/fedora-27/000077500000000000000000000000001474374657400200705ustar00rootroot00000000000000kpatch-0.9.10/test/integration/fedora-27/README000066400000000000000000000000271474374657400207470ustar00rootroot000000000000004.13.9-300.fc27.x86_64 kpatch-0.9.10/test/integration/fedora-27/data-new-LOADED.test000077500000000000000000000000541474374657400234210ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/fedora-27/data-new.patch000066400000000000000000000011401474374657400226050ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/fedora-27/gcc-static-local-var-6.patch000066400000000000000000000011731474374657400251550ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/fedora-27/macro-callbacks.patch000066400000000000000000000112271474374657400241320ustar00rootroot00000000000000kpatch/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 kpatch-0.9.10/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled000077500000000000000000000001141474374657400307350ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo && grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/fedora-27/meminfo-cmdline-rebuild-SLOW.patch.disabled000066400000000000000000000022621474374657400301320ustar00rootroot00000000000000Disabled 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 kpatch-0.9.10/test/integration/fedora-27/module-call-external.patch000066400000000000000000000017501474374657400251320ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/fedora-27/module-shadow.patch.disabled000066400000000000000000000016361474374657400254350ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/fedora-27/multiple.test000077500000000000000000000002631474374657400226300ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-cmdline-rebuild-SLOW-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/fedora-27/new-function.patch000066400000000000000000000015211474374657400235240ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/fedora-27/new-globals.patch000066400000000000000000000020311474374657400233170ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/fedora-27/remote-setup000077500000000000000000000033271474374657400224540ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/fedora-27/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400244730ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/fedora-27/shadow-newpid.patch.disabled000066400000000000000000000045101474374657400254300ustar00rootroot00000000000000Index: 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. kpatch-0.9.10/test/integration/fedora-27/warn-detect-FAIL.patch000066400000000000000000000003301474374657400240330ustar00rootroot00000000000000diff --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. * kpatch-0.9.10/test/integration/kpatch-test000077500000000000000000000226271474374657400205700ustar00rootroot00000000000000#!/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="kpatch-test timestamp: $(date --rfc-3339=ns)" echo "$SAVED_DMESG" > /dev/kmsg } # new dmesg entries since our saved entry new_dmesg() { if ! dmesg --notime | 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 kpatch-0.9.10/test/integration/lib.sh000066400000000000000000000215401474374657400175060ustar00rootroot00000000000000#!/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_photon_dependencies() { local flavor flavor=$(uname -r | cut -d "-" -f 3) if [[ $(uname -r | cut -d "-" -f 2) == "rt" ]]; then flavor="rt" fi tdnf install -y kmod bash rpm-build coreutils util-linux sed findutils \ elfutils-devel systemd-rpm-macros build-essential wget if [[ -z "$flavor" ]]; then tdnf install -y linux-debuginfo else tdnf install -y linux-"$flavor"-debuginfo fi } kpatch_opencloudos_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 dnf-utils \ rpm-build dnf-plugins-core python3-devel openssl-devel ncurses-devel elfutils-libelf-devel sudo yum install -y "kernel-debuginfo-${kernel_version%.*}"\ "kernel-devel-${kernel_version%.*}" sudo yum-builddep -y "kernel-${kernel_version}*" } kpatch_anolis_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-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}" } kpatch-0.9.10/test/integration/linux-5.10.11/000077500000000000000000000000001474374657400203425ustar00rootroot00000000000000kpatch-0.9.10/test/integration/linux-5.10.11/data-new-LOADED.test000077500000000000000000000000541474374657400236730ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/linux-5.10.11/data-new.patch000066400000000000000000000012361474374657400230650ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/linux-5.10.11/gcc-static-local-var-6.patch000066400000000000000000000012621474374657400254260ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/linux-5.10.11/macro-callbacks.patch000066400000000000000000000112341474374657400244020ustar00rootroot00000000000000kpatch/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 kpatch-0.9.10/test/integration/linux-5.10.11/module-call-external.patch000066400000000000000000000017751474374657400254130ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/linux-5.10.11/multiple.test000077500000000000000000000002631474374657400231020ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-cmdline-rebuild-SLOW-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/linux-5.10.11/new-function.patch000066400000000000000000000016601474374657400240020ustar00rootroot00000000000000diff --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 kpatch-0.9.10/test/integration/linux-5.10.11/new-globals.patch000066400000000000000000000021761474374657400236030ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/linux-5.10.11/syscall-LOADED.test000077500000000000000000000000471474374657400236470ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/linux-5.10.11/syscall.patch000066400000000000000000000011271474374657400230360ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/linux-5.10.11/warn-detect-FAIL.patch000066400000000000000000000005361474374657400243150ustar00rootroot00000000000000diff -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. * kpatch-0.9.10/test/integration/linux-5.18.0/000077500000000000000000000000001474374657400202705ustar00rootroot00000000000000kpatch-0.9.10/test/integration/linux-5.18.0/data-new-LOADED.test000077500000000000000000000000641474374657400236220ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/linux-5.18.0/data-new.patch000066400000000000000000000011551474374657400230130ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/linux-5.18.0/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400253510ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/linux-5.18.0/macro-callbacks.patch000066400000000000000000000107731474374657400243370ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/linux-5.18.0/module-LOADED.test000077500000000000000000000006061474374657400234110ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/linux-5.18.0/module.patch000066400000000000000000000044051474374657400226010ustar00rootroot00000000000000kpatch 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); kpatch-0.9.10/test/integration/linux-5.18.0/multiple.test000077500000000000000000000002451474374657400230300ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/linux-5.18.0/new-function.patch000066400000000000000000000016611474374657400237310ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/linux-5.18.0/new-globals.patch000066400000000000000000000021761474374657400235310ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/linux-5.18.0/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400246730ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/linux-5.18.0/shadow-newpid.patch000066400000000000000000000046041474374657400240660ustar00rootroot00000000000000diff -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. kpatch-0.9.10/test/integration/linux-5.18.0/special-static.patch000066400000000000000000000010441474374657400242150ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/linux-5.18.0/symvers-disagreement-FAIL.patch000066400000000000000000000027241474374657400262040ustar00rootroot00000000000000From 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; kpatch-0.9.10/test/integration/linux-5.18.0/syscall-LOADED.test000077500000000000000000000000471474374657400235750ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/linux-5.18.0/syscall.patch000066400000000000000000000011631474374657400227640ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/linux-5.18.0/warn-detect-FAIL.patch000066400000000000000000000004671474374657400242460ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/linux-6.2.0/000077500000000000000000000000001474374657400202025ustar00rootroot00000000000000kpatch-0.9.10/test/integration/linux-6.2.0/data-new-LOADED.test000077500000000000000000000000641474374657400235340ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/linux-6.2.0/data-new.patch000066400000000000000000000011551474374657400227250ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-01-12 11:20:07.184710563 -0500 +++ src/fs/proc/meminfo.c 2023-01-12 11:20:08.166716386 -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; @@ -154,6 +156,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); kpatch-0.9.10/test/integration/linux-6.2.0/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400252630ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2023-01-12 11:20:07.630713207 -0500 +++ src/net/ipv6/netfilter.c 2023-01-12 11:20:29.874845095 -0500 @@ -96,6 +96,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) { @@ -109,6 +111,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) kpatch-0.9.10/test/integration/linux-6.2.0/macro-callbacks.patch000066400000000000000000000107731474374657400242510ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2023-01-12 11:20:06.597707083 -0500 +++ src/drivers/input/joydev.c 2023-01-12 11:20:38.032893465 -0500 @@ -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 2023-01-12 11:20:06.578706970 -0500 +++ src/drivers/input/misc/pcspkr.c 2023-01-12 11:20:38.032893465 -0500 @@ -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 2023-01-12 11:20:07.273711091 -0500 +++ src/fs/aio.c 2023-01-12 11:20:38.033893471 -0500 @@ -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 kpatch-0.9.10/test/integration/linux-6.2.0/module-LOADED.test000077500000000000000000000003151474374657400233200ustar00rootroot00000000000000#!/bin/bash set -o errexit sudo modprobe xfs sleep 5 echo "file fs/xfs/xfs_stats.c +p" > /sys/kernel/debug/dynamic_debug/control grep -q kpatch /sys/fs/xfs/stats/stats dmesg | grep -q "kpatch: pr_debug" kpatch-0.9.10/test/integration/linux-6.2.0/module.patch000066400000000000000000000040351474374657400225120ustar00rootroot00000000000000kpatch 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 --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c index 90a77cd3ebad..f65df90ae8e1 100644 --- a/fs/xfs/xfs_stats.c +++ b/fs/xfs/xfs_stats.c @@ -16,6 +16,8 @@ static int counter_val(struct xfsstats __percpu *stats, int idx) return val; } +extern char *kpatch_string(void); + int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { int i, j; @@ -85,6 +87,34 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) 0); #endif + /* Reference a symbol outside the .o yet inside the patch module: */ + len += scnprintf(buf + len, PATH_MAX-len, "%s\n", kpatch_string()); + +#ifdef CONFIG_X86_64 + /* Test alternatives patching: */ + alternative("ud2", "nop", X86_FEATURE_ALWAYS); + alternative("nop", "ud2", X86_FEATURE_IA64); + + /* Test paravirt patching: */ + slow_down_io(); /* paravirt call */ +#endif + + /* Test pr_debug: */ + pr_debug("kpatch: pr_debug() test\n"); + +{ + /* Test static branches: */ + 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); +} + return len; } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c64277659753..05b753c2ec84 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2980,4 +2980,9 @@ static int __init netlink_proto_init(void) panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "kpatch"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/linux-6.2.0/multiple.test000077500000000000000000000002451474374657400227420ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/linux-6.2.0/new-function.patch000066400000000000000000000016611474374657400236430ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2023-01-12 11:20:06.978709342 -0500 +++ src/drivers/tty/n_tty.c 2023-01-12 11:20:54.149989024 -0500 @@ -2315,7 +2315,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; @@ -2402,6 +2402,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 kpatch-0.9.10/test/integration/linux-6.2.0/new-globals.patch000066400000000000000000000021761474374657400234430ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-01-12 11:20:07.184710563 -0500 +++ src/fs/proc/cmdline.c 2023-01-12 11:21:02.411038005 -0500 @@ -21,3 +21,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 2023-01-12 11:20:07.184710563 -0500 +++ src/fs/proc/meminfo.c 2023-01-12 11:21:02.411038005 -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); kpatch-0.9.10/test/integration/linux-6.2.0/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400246050ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/linux-6.2.0/shadow-newpid.patch000066400000000000000000000045731474374657400240050ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2023-01-12 11:20:07.182710551 -0500 +++ src/fs/proc/array.c 2023-01-12 11:21:10.821087869 -0500 @@ -397,12 +397,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 2023-01-12 11:20:05.408700033 -0500 +++ src/kernel/exit.c 2023-01-12 11:21:10.822087875 -0500 @@ -802,6 +802,7 @@ static void synchronize_group_exit(struc spin_unlock_irq(&sighand->siglock); } +#include void __noreturn do_exit(long code) { struct task_struct *tsk = current; @@ -867,6 +868,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 2023-01-12 11:20:05.408700033 -0500 +++ src/kernel/fork.c 2023-01-12 11:21:10.824087886 -0500 @@ -2637,6 +2637,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; @@ -2645,6 +2646,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 @@ -2684,6 +2687,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. kpatch-0.9.10/test/integration/linux-6.2.0/special-static.patch000066400000000000000000000010441474374657400241270ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2023-01-12 11:20:05.408700033 -0500 +++ src/kernel/fork.c 2023-01-12 11:21:19.186137466 -0500 @@ -1700,10 +1700,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; kpatch-0.9.10/test/integration/linux-6.2.0/symvers-disagreement-FAIL.patch000066400000000000000000000027411474374657400261150ustar00rootroot00000000000000From 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 2023-01-12 11:20:06.403705933 -0500 +++ src/drivers/base/core.c 2023-01-12 11:21:27.466186559 -0500 @@ -36,6 +36,8 @@ #include "physical_location.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 2023-01-12 11:20:06.490706448 -0500 +++ src/drivers/usb/core/usb.c 2023-01-12 11:21:27.468186571 -0500 @@ -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; kpatch-0.9.10/test/integration/linux-6.2.0/syscall-LOADED.test000077500000000000000000000000471474374657400235070ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/linux-6.2.0/syscall.patch000066400000000000000000000011631474374657400226760ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2023-01-12 11:20:05.406700021 -0500 +++ src/kernel/sys.c 2023-01-12 11:21:35.782235867 -0500 @@ -1285,13 +1285,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; kpatch-0.9.10/test/integration/linux-6.2.0/warn-detect-FAIL.patch000066400000000000000000000004671474374657400241600ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2023-01-12 11:20:04.716695930 -0500 +++ src/arch/x86/kvm/x86.c 2023-01-12 11:21:44.162285556 -0500 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rebase-patches000077500000000000000000000024731474374657400212240ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-7.4/000077500000000000000000000000001474374657400176425ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-7.4/bug-table-section.patch000066400000000000000000000007711474374657400241740ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-7.4/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244070ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-7.4/cmdline-string.patch000066400000000000000000000006011474374657400235770ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.4/data-new-LOADED.test000077500000000000000000000000541474374657400231730ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.4/data-new.patch000066400000000000000000000013501474374657400223620ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.4/data-read-mostly.patch.disabled000066400000000000000000000004471474374657400256050ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-7.4/fixup-section.patch000066400000000000000000000006001474374657400234540ustar00rootroot00000000000000diff --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)) kpatch-0.9.10/test/integration/rhel-7.4/gcc-constprop.patch000066400000000000000000000006471474374657400234530ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/gcc-isra.patch000066400000000000000000000006541474374657400223600ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.4/gcc-mangled-3.patch000066400000000000000000000006041474374657400231640ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400247210ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var-3.patch000066400000000000000000000006511474374657400247240ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var-4.patch000066400000000000000000000010051474374657400247170ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246070ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var-5.patch000066400000000000000000000021571474374657400247310ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var-6.patch000066400000000000000000000011521474374657400247240ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/rhel-7.4/gcc-static-local-var.patch000066400000000000000000000012151474374657400245610ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/macro-callbacks.patch000066400000000000000000000107661474374657400237130ustar00rootroot00000000000000kpatch/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); kpatch-0.9.10/test/integration/rhel-7.4/macro-printk.patch000066400000000000000000000111141474374657400232670ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/meminfo-init-FAIL.patch000066400000000000000000000006011474374657400237640ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.4/meminfo-init2-FAIL.patch000066400000000000000000000010421474374657400240460ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.4/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244320ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.4/meminfo-string.patch000066400000000000000000000007331474374657400236240ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.4/module-call-external.patch000066400000000000000000000017501474374657400247040ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.4/module-kvm-fixup.patch000066400000000000000000000006711474374657400241000ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.4/module-shadow.patch000066400000000000000000000016361474374657400234410ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/multiple.test000077500000000000000000000002451474374657400224020ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-7.4/new-function.patch000066400000000000000000000014651474374657400233050ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.4/new-globals.patch000066400000000000000000000017551474374657400231050ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.4/parainstructions-section.patch000066400000000000000000000006551474374657400257430ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/replace-section-references.patch000066400000000000000000000007461474374657400260660ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-7.4/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242450ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-7.4/shadow-newpid.patch000066400000000000000000000041361474374657400234400ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.4/smp-locks-section.patch000066400000000000000000000011061474374657400242330ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/special-static-2.patch000066400000000000000000000012251474374657400237270ustar00rootroot00000000000000diff -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: kpatch-0.9.10/test/integration/rhel-7.4/special-static.patch000066400000000000000000000010351474374657400235670ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.4/tracepoints-section.patch000066400000000000000000000007141474374657400246620ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.4/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236110ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-7.5/000077500000000000000000000000001474374657400176435ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-7.5/bug-table-section.patch000066400000000000000000000007711474374657400241750ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-7.5/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244100ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-7.5/cmdline-string.patch000066400000000000000000000006011474374657400236000ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.5/data-new-LOADED.test000077500000000000000000000000541474374657400231740ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.5/data-new.patch000066400000000000000000000013501474374657400223630ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.5/data-read-mostly.patch.disabled000066400000000000000000000004471474374657400256060ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-7.5/fixup-section.patch000066400000000000000000000006001474374657400234550ustar00rootroot00000000000000diff --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)) kpatch-0.9.10/test/integration/rhel-7.5/gcc-constprop.patch000066400000000000000000000006471474374657400234540ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/gcc-isra.patch000066400000000000000000000006541474374657400223610ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.5/gcc-mangled-3.patch000066400000000000000000000006041474374657400231650ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400247220ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var-3.patch000066400000000000000000000006511474374657400247250ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var-4.patch000066400000000000000000000010051474374657400247200ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246100ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var-5.patch000066400000000000000000000021571474374657400247320ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var-6.patch000066400000000000000000000011521474374657400247250ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/rhel-7.5/gcc-static-local-var.patch000066400000000000000000000012151474374657400245620ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/macro-callbacks.patch000066400000000000000000000107661474374657400237140ustar00rootroot00000000000000kpatch/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); kpatch-0.9.10/test/integration/rhel-7.5/macro-printk.patch000066400000000000000000000111141474374657400232700ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/meminfo-init-FAIL.patch000066400000000000000000000006011474374657400237650ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.5/meminfo-init2-FAIL.patch000066400000000000000000000010421474374657400240470ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.5/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244330ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.5/meminfo-string.patch000066400000000000000000000007331474374657400236250ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.5/module-call-external.patch000066400000000000000000000017501474374657400247050ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.5/module-kvm-fixup.patch000066400000000000000000000006711474374657400241010ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.5/module-shadow.patch.disabled000066400000000000000000000015531474374657400252060ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.5/multiple.test000077500000000000000000000002451474374657400224030ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-7.5/new-function.patch000066400000000000000000000015561474374657400233070ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.5/new-globals.patch000066400000000000000000000017551474374657400231060ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.5/parainstructions-section.patch000066400000000000000000000006551474374657400257440ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/replace-section-references.patch000066400000000000000000000007461474374657400260670ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-7.5/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242460ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-7.5/shadow-newpid.patch000066400000000000000000000040261474374657400234370ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.5/smp-locks-section.patch000066400000000000000000000011061474374657400242340ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/special-static-2.patch000066400000000000000000000012251474374657400237300ustar00rootroot00000000000000diff -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: kpatch-0.9.10/test/integration/rhel-7.5/special-static.patch000066400000000000000000000010351474374657400235700ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.5/tracepoints-section.patch000066400000000000000000000007141474374657400246630ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.5/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236120ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-7.6/000077500000000000000000000000001474374657400176445ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-7.6/bug-table-section.patch000066400000000000000000000007551474374657400242000ustar00rootroot00000000000000Index: 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)) kpatch-0.9.10/test/integration/rhel-7.6/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244110ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-7.6/cmdline-string.patch000066400000000000000000000006011474374657400236010ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.6/data-new-LOADED.test000077500000000000000000000000541474374657400231750ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.6/data-new.patch000066400000000000000000000013221474374657400223630ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.6/data-read-mostly.patch.disabled000066400000000000000000000004531474374657400256040ustar00rootroot00000000000000Index: 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(); } } kpatch-0.9.10/test/integration/rhel-7.6/fixup-section.patch000066400000000000000000000006001474374657400234560ustar00rootroot00000000000000diff --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)) kpatch-0.9.10/test/integration/rhel-7.6/gcc-constprop.patch.disabled000066400000000000000000000006471474374657400252230ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.6/gcc-isra.patch000066400000000000000000000006401474374657400223550ustar00rootroot00000000000000Index: 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); } kpatch-0.9.10/test/integration/rhel-7.6/gcc-mangled-3.patch000066400000000000000000000006041474374657400231660ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.6/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400247230ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.6/gcc-static-local-var-3.patch000066400000000000000000000006461474374657400247320ustar00rootroot00000000000000Index: 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); } kpatch-0.9.10/test/integration/rhel-7.6/gcc-static-local-var-4.patch000066400000000000000000000010061474374657400247220ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.6/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246110ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-7.6/gcc-static-local-var-5.patch000066400000000000000000000021571474374657400247330ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.6/gcc-static-local-var-6.patch000066400000000000000000000011521474374657400247260ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/rhel-7.6/macro-callbacks.patch000066400000000000000000000107661474374657400237150ustar00rootroot00000000000000kpatch/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); kpatch-0.9.10/test/integration/rhel-7.6/macro-printk.patch000066400000000000000000000111151474374657400232720ustar00rootroot00000000000000Index: 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, kpatch-0.9.10/test/integration/rhel-7.6/meminfo-init-FAIL.patch000066400000000000000000000005711474374657400237740ustar00rootroot00000000000000Index: 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; } kpatch-0.9.10/test/integration/rhel-7.6/meminfo-init2-FAIL.patch000066400000000000000000000010321474374657400240470ustar00rootroot00000000000000Index: 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; } kpatch-0.9.10/test/integration/rhel-7.6/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244340ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.6/meminfo-string.patch000066400000000000000000000007331474374657400236260ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.6/module-call-external.patch000066400000000000000000000021601474374657400247020ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-7.6/multiple.test000077500000000000000000000002451474374657400224040ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-7.6/new-function.patch000066400000000000000000000015441474374657400233050ustar00rootroot00000000000000Index: 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 kpatch-0.9.10/test/integration/rhel-7.6/new-globals.patch000066400000000000000000000017551474374657400231070ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.6/parainstructions-section.patch000066400000000000000000000006551474374657400257450ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.6/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242470ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-7.6/shadow-newpid.patch000066400000000000000000000040111474374657400234320ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-7.6/smp-locks-section.patch000066400000000000000000000011061474374657400242350ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.6/special-static.patch000066400000000000000000000010311474374657400235650ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.6/symvers-disagreement-FAIL.patch000066400000000000000000000025701474374657400255570ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-7.6/tracepoints-section.patch000066400000000000000000000007071474374657400246660ustar00rootroot00000000000000Index: 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); } kpatch-0.9.10/test/integration/rhel-7.6/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236130ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-7.7/000077500000000000000000000000001474374657400176455ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-7.7/bug-table-section.patch000066400000000000000000000007331474374657400241750ustar00rootroot00000000000000Index: 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)) kpatch-0.9.10/test/integration/rhel-7.7/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244120ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-7.7/cmdline-string.patch000066400000000000000000000005471474374657400236130ustar00rootroot00000000000000Index: 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; } kpatch-0.9.10/test/integration/rhel-7.7/data-new-LOADED.test000077500000000000000000000000541474374657400231760ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.7/data-new.patch000066400000000000000000000013001474374657400223600ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.7/data-read-mostly.patch.disabled000066400000000000000000000004311474374657400256010ustar00rootroot00000000000000Index: 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(); } } kpatch-0.9.10/test/integration/rhel-7.7/fixup-section.patch000066400000000000000000000005671474374657400234730ustar00rootroot00000000000000Index: 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)) kpatch-0.9.10/test/integration/rhel-7.7/gcc-constprop.patch.disabled000066400000000000000000000006471474374657400252240ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.7/gcc-isra.patch000066400000000000000000000006161474374657400223610ustar00rootroot00000000000000Index: 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); } kpatch-0.9.10/test/integration/rhel-7.7/gcc-mangled-3.patch000066400000000000000000000005621474374657400231720ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.7/gcc-static-local-var-2.patch000066400000000000000000000006701474374657400247270ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.7/gcc-static-local-var-3.patch000066400000000000000000000006241474374657400247270ustar00rootroot00000000000000Index: 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); } kpatch-0.9.10/test/integration/rhel-7.7/gcc-static-local-var-4.patch000066400000000000000000000007641474374657400247350ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.7/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246120ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-7.7/gcc-static-local-var-5.patch000066400000000000000000000021301474374657400247230ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.7/gcc-static-local-var-6.patch000066400000000000000000000011641474374657400247320ustar00rootroot00000000000000Index: 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) kpatch-0.9.10/test/integration/rhel-7.7/macro-callbacks.patch000066400000000000000000000111451474374657400237060ustar00rootroot00000000000000kpatch/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); kpatch-0.9.10/test/integration/rhel-7.7/macro-printk.patch000066400000000000000000000110311474374657400232700ustar00rootroot00000000000000Index: 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, kpatch-0.9.10/test/integration/rhel-7.7/meminfo-init-FAIL.patch000066400000000000000000000005471474374657400240000ustar00rootroot00000000000000Index: 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; } kpatch-0.9.10/test/integration/rhel-7.7/meminfo-init2-FAIL.patch000066400000000000000000000010101474374657400240440ustar00rootroot00000000000000Index: 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; } kpatch-0.9.10/test/integration/rhel-7.7/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244350ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.7/meminfo-string.patch000066400000000000000000000007011474374657400236220ustar00rootroot00000000000000Index: 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 kpatch-0.9.10/test/integration/rhel-7.7/module-call-external.patch000066400000000000000000000021601474374657400247030ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-7.7/multiple.test000077500000000000000000000002451474374657400224050ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-7.7/new-function.patch000066400000000000000000000015221474374657400233020ustar00rootroot00000000000000Index: 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 kpatch-0.9.10/test/integration/rhel-7.7/new-globals.patch000066400000000000000000000016711474374657400231050ustar00rootroot00000000000000Index: 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" kpatch-0.9.10/test/integration/rhel-7.7/parainstructions-section.patch000066400000000000000000000006231474374657400257410ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.7/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242500ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-7.7/shadow-newpid.patch000066400000000000000000000040711474374657400234410ustar00rootroot00000000000000Index: 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); kpatch-0.9.10/test/integration/rhel-7.7/smp-locks-section.patch000066400000000000000000000010451474374657400242400ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.7/special-static.patch000066400000000000000000000010071474374657400235710ustar00rootroot00000000000000Index: 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; kpatch-0.9.10/test/integration/rhel-7.7/symvers-disagreement-FAIL.patch000066400000000000000000000025701474374657400255600ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-7.7/tracepoints-section.patch000066400000000000000000000006651474374657400246720ustar00rootroot00000000000000Index: 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); } kpatch-0.9.10/test/integration/rhel-7.7/warn-detect-FAIL.patch000066400000000000000000000003621474374657400236150ustar00rootroot00000000000000Index: 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 * kpatch-0.9.10/test/integration/rhel-7.8/000077500000000000000000000000001474374657400176465ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-7.8/bug-table-section.patch000066400000000000000000000007711474374657400242000ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-7.8/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244130ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-7.8/cmdline-string.patch000066400000000000000000000006011474374657400236030ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.8/data-new-LOADED.test000077500000000000000000000000541474374657400231770ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.8/data-new.patch000066400000000000000000000013321474374657400223660ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.8/data-read-mostly.patch.disabled000066400000000000000000000004601474374657400256040ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-7.8/fixup-section.patch000066400000000000000000000006141474374657400234650ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-7.8/gcc-constprop.patch.disabled000066400000000000000000000006471474374657400252250ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.8/gcc-isra.patch000066400000000000000000000006541474374657400223640ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.8/gcc-mangled-3.patch000066400000000000000000000006041474374657400231700ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.8/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400247250ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.8/gcc-static-local-var-3.patch000066400000000000000000000006511474374657400247300ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.8/gcc-static-local-var-4.patch000066400000000000000000000010051474374657400247230ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.8/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246130ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-7.8/gcc-static-local-var-5.patch000066400000000000000000000021571474374657400247350ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.8/gcc-static-local-var-6.patch000066400000000000000000000012211474374657400247250ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-7.8/macro-callbacks.patch000066400000000000000000000112711474374657400237070ustar00rootroot00000000000000kpatch/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 kpatch-0.9.10/test/integration/rhel-7.8/macro-printk.patch000066400000000000000000000111661474374657400233020ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-7.8/meminfo-init-FAIL.patch000066400000000000000000000006011474374657400237700ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.8/meminfo-init2-FAIL.patch000066400000000000000000000010421474374657400240520ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.8/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244360ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.8/meminfo-string.patch000066400000000000000000000011341474374657400236240ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.8/module-call-external.patch000066400000000000000000000022711474374657400247070ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.8/multiple.test000077500000000000000000000002451474374657400224060ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-7.8/new-function.patch000066400000000000000000000015561474374657400233120ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.8/new-globals.patch000066400000000000000000000017551474374657400231110ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.8/parainstructions-section.patch000066400000000000000000000006551474374657400257470ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.8/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242510ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-7.8/shadow-newpid.patch000066400000000000000000000041751474374657400234470ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.8/smp-locks-section.patch000066400000000000000000000011061474374657400242370ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.8/special-static.patch000066400000000000000000000010351474374657400235730ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.8/symvers-disagreement-FAIL.patch000066400000000000000000000024621474374657400255610ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-7.8/tracepoints-section.patch000066400000000000000000000007141474374657400246660ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.8/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236150ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-7.9/000077500000000000000000000000001474374657400176475ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-7.9/bug-table-section.patch000066400000000000000000000007711474374657400242010ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-7.9/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244140ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-7.9/cmdline-string.patch000066400000000000000000000006011474374657400236040ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.9/data-new-LOADED.test000077500000000000000000000000541474374657400232000ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.9/data-new.patch000066400000000000000000000013321474374657400223670ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.9/data-read-mostly.patch.disabled000066400000000000000000000004601474374657400256050ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-7.9/fixup-section.patch000066400000000000000000000006141474374657400234660ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-7.9/gcc-constprop.patch000066400000000000000000000006471474374657400234600ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.9/gcc-isra.patch000066400000000000000000000006541474374657400223650ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.9/gcc-mangled-3.patch000066400000000000000000000006041474374657400231710ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.9/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400247260ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.9/gcc-static-local-var-3.patch000066400000000000000000000006511474374657400247310ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.9/gcc-static-local-var-4.patch000066400000000000000000000010051474374657400247240ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.9/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246140ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-7.9/gcc-static-local-var-5.patch000066400000000000000000000021571474374657400247360ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.9/gcc-static-local-var-6.patch000066400000000000000000000012211474374657400247260ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-7.9/macro-callbacks.patch000066400000000000000000000112711474374657400237100ustar00rootroot00000000000000kpatch/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 kpatch-0.9.10/test/integration/rhel-7.9/macro-printk.patch000066400000000000000000000111661474374657400233030ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-7.9/meminfo-init-FAIL.patch000066400000000000000000000006011474374657400237710ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.9/meminfo-init2-FAIL.patch000066400000000000000000000010421474374657400240530ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-7.9/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244370ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-7.9/meminfo-string.patch000066400000000000000000000007641474374657400236350ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.9/module-call-external.patch000066400000000000000000000022711474374657400247100ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.9/multiple.test000077500000000000000000000002451474374657400224070ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-7.9/new-function.patch000066400000000000000000000015561474374657400233130ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-7.9/new-globals.patch000066400000000000000000000017551474374657400231120ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/rhel-7.9/parainstructions-section.patch000066400000000000000000000006551474374657400257500ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.9/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242520ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-7.9/shadow-newpid.patch000066400000000000000000000041751474374657400234500ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-7.9/smp-locks-section.patch000066400000000000000000000011061474374657400242400ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.9/special-static.patch000066400000000000000000000010351474374657400235740ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-7.9/symvers-disagreement-FAIL.patch000066400000000000000000000024621474374657400255620ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-7.9/syscall-LOADED.test000077500000000000000000000000471474374657400231540ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-7.9/syscall.patch000066400000000000000000000014161474374657400223440ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-7.9/tracepoints-section.patch000066400000000000000000000007141474374657400246670ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-7.9/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236160ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.0/000077500000000000000000000000001474374657400176375ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.0/README000066400000000000000000000000161474374657400205140ustar00rootroot000000000000004.18.0-80.el8 kpatch-0.9.10/test/integration/rhel-8.0/bug-table-section.patch000066400000000000000000000007201474374657400241630ustar00rootroot00000000000000diff --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)) kpatch-0.9.10/test/integration/rhel-8.0/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244040ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.0/cmdline-string.patch000066400000000000000000000005201474374657400235740ustar00rootroot00000000000000diff --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; } kpatch-0.9.10/test/integration/rhel-8.0/data-new-LOADED.test000077500000000000000000000000641474374657400231710ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.0/data-new.patch000066400000000000000000000011501474374657400223550ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-8.0/data-read-mostly.patch.disabled000066400000000000000000000005561474374657400256030ustar00rootroot00000000000000Disabled 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(); } } kpatch-0.9.10/test/integration/rhel-8.0/fixup-section.patch000066400000000000000000000005611474374657400234570ustar00rootroot00000000000000diff --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)) kpatch-0.9.10/test/integration/rhel-8.0/gcc-constprop.patch.disabled000066400000000000000000000005551474374657400252140ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-8.0/gcc-isra.patch000066400000000000000000000005761474374657400223600ustar00rootroot00000000000000diff --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); } kpatch-0.9.10/test/integration/rhel-8.0/gcc-mangled-3.patch000066400000000000000000000005661474374657400231700ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-8.0/gcc-static-local-var-2.patch000066400000000000000000000006601474374657400247200ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-8.0/gcc-static-local-var-3.patch000066400000000000000000000005541474374657400247230ustar00rootroot00000000000000diff --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); } kpatch-0.9.10/test/integration/rhel-8.0/gcc-static-local-var-4.patch.disabled000066400000000000000000000010611474374657400264640ustar00rootroot00000000000000Disabled 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); kpatch-0.9.10/test/integration/rhel-8.0/gcc-static-local-var-4.test.disabled000077500000000000000000000002451474374657400263520ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.0/gcc-static-local-var-5.patch000066400000000000000000000021251474374657400247210ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-8.0/gcc-static-local-var-6.patch000066400000000000000000000011571474374657400247260ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/rhel-8.0/macro-callbacks.patch000066400000000000000000000105271474374657400237030ustar00rootroot00000000000000diff --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 kpatch-0.9.10/test/integration/rhel-8.0/macro-printk.patch.disabled000066400000000000000000000122501474374657400250340ustar00rootroot00000000000000diff --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, kpatch-0.9.10/test/integration/rhel-8.0/meminfo-init-FAIL.patch000066400000000000000000000005341474374657400237660ustar00rootroot00000000000000diff --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; } kpatch-0.9.10/test/integration/rhel-8.0/meminfo-init2-FAIL.patch000066400000000000000000000011161474374657400240450ustar00rootroot00000000000000diff --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; } kpatch-0.9.10/test/integration/rhel-8.0/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244270ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.0/meminfo-string.patch000066400000000000000000000007701474374657400236220ustar00rootroot00000000000000diff --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", kpatch-0.9.10/test/integration/rhel-8.0/module-call-external.patch000066400000000000000000000016571474374657400247070ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-8.0/multiple.test000077500000000000000000000002451474374657400223770ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.0/new-function.patch000066400000000000000000000016611474374657400233000ustar00rootroot00000000000000diff --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 kpatch-0.9.10/test/integration/rhel-8.0/new-globals.patch000066400000000000000000000016631474374657400231000ustar00rootroot00000000000000diff --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); kpatch-0.9.10/test/integration/rhel-8.0/parainstructions-section.patch000066400000000000000000000005771474374657400257430ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/rhel-8.0/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242420ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.0/shadow-newpid.patch.disabled000066400000000000000000000045471474374657400252110ustar00rootroot00000000000000Disabled 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. kpatch-0.9.10/test/integration/rhel-8.0/smp-locks-section.patch000066400000000000000000000007131474374657400242330ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-8.0/special-static.patch000066400000000000000000000010501474374657400235610ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-8.0/symvers-disagreement-FAIL.patch000066400000000000000000000025741474374657400255560ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-8.0/tracepoints-section.patch000066400000000000000000000007651474374657400246650ustar00rootroot00000000000000diff --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])); kpatch-0.9.10/test/integration/rhel-8.0/warn-detect-FAIL.patch000066400000000000000000000003211474374657400236020ustar00rootroot00000000000000diff --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 * kpatch-0.9.10/test/integration/rhel-8.1/000077500000000000000000000000001474374657400176405ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.1/bug-table-section.patch000066400000000000000000000007571474374657400241760ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.1/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244050ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.1/cmdline-string.patch000066400000000000000000000006021474374657400235760ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.1/data-new-LOADED.test000077500000000000000000000000641474374657400231720ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.1/data-new.patch000066400000000000000000000011431474374657400223600ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.1/data-read-mostly.patch.disabled000066400000000000000000000005441474374657400256010ustar00rootroot00000000000000Disabled 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(); } } kpatch-0.9.10/test/integration/rhel-8.1/fixup-section.patch000066400000000000000000000006021474374657400234540ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.1/gcc-constprop.patch.disabled000066400000000000000000000006371474374657400252160ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.1/gcc-isra.patch000066400000000000000000000006421474374657400223530ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.1/gcc-mangled-3.patch000066400000000000000000000006201474374657400231600ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.1/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400247170ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.1/gcc-static-local-var-3.patch000066400000000000000000000006531474374657400247240ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.1/gcc-static-local-var-4.patch.disabled000066400000000000000000000011421474374657400264650ustar00rootroot00000000000000Disabled 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); kpatch-0.9.10/test/integration/rhel-8.1/gcc-static-local-var-4.test.disabled000077500000000000000000000002451474374657400263530ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.1/gcc-static-local-var-5.patch000066400000000000000000000021451474374657400247240ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.1/gcc-static-local-var-6.patch000066400000000000000000000012051474374657400247210ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.1/macro-callbacks.patch000066400000000000000000000107351474374657400237050ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.1/macro-printk.patch.disabled000066400000000000000000000115541474374657400250430ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-8.1/meminfo-init-FAIL.patch000066400000000000000000000005751474374657400237740ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.1/meminfo-init2-FAIL.patch000066400000000000000000000011431474374657400240460ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.1/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244300ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.1/meminfo-string.patch000066400000000000000000000010311474374657400236120ustar00rootroot00000000000000diff -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", kpatch-0.9.10/test/integration/rhel-8.1/module-LOADED.test000077500000000000000000000006061474374657400227610ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.1/module.patch000066400000000000000000000047531474374657400221570ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-8.1/multiple.test000077500000000000000000000002451474374657400224000ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.1/new-function.patch000066400000000000000000000016141474374657400232770ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.1/new-globals.patch000066400000000000000000000021351474374657400230740ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.1/parainstructions-section.patch000066400000000000000000000006611474374657400257360ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.1/shadow-newpid-LOADED.test.disabled000077500000000000000000000000551474374657400260110ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.1/shadow-newpid.patch.disabled000066400000000000000000000047241474374657400252070ustar00rootroot00000000000000Disabled 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. kpatch-0.9.10/test/integration/rhel-8.1/smp-locks-section.patch000066400000000000000000000007351474374657400242400ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.1/special-static.patch.disabled000066400000000000000000000011001474374657400253240ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.1/symvers-disagreement-FAIL.patch000066400000000000000000000025741474374657400255570ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-8.1/tracepoints-section.patch000066400000000000000000000010071474374657400246540ustar00rootroot00000000000000diff -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])); kpatch-0.9.10/test/integration/rhel-8.1/warn-detect-FAIL.patch000066400000000000000000000004031474374657400236040ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.10/000077500000000000000000000000001474374657400177205ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.10/bug-table-section.patch000066400000000000000000000007711474374657400242520ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c --- src.orig/fs/proc/proc_sysctl.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/proc_sysctl.c 2024-04-18 14:12:03.887374205 -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)) kpatch-0.9.10/test/integration/rhel-8.10/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244650ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.10/cmdline-string.patch000066400000000000000000000006141474374657400236610ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/cmdline.c 2024-04-18 14:12:10.803359173 -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; } kpatch-0.9.10/test/integration/rhel-8.10/data-new-LOADED.test000077500000000000000000000000641474374657400232520ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.10/data-new.patch000066400000000000000000000011551474374657400224430ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 14:12:13.626353038 -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); kpatch-0.9.10/test/integration/rhel-8.10/data-read-mostly.patch000066400000000000000000000004601474374657400241100ustar00rootroot00000000000000diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c --- src.orig/net/core/dev.c 2024-04-18 14:12:03.639374744 -0400 +++ src/net/core/dev.c 2024-04-18 14:12:15.656348626 -0400 @@ -5469,6 +5469,7 @@ skip_classify: case RX_HANDLER_PASS: break; default: + printk("BUG!\n"); BUG(); } } kpatch-0.9.10/test/integration/rhel-8.10/fixup-section.patch000066400000000000000000000006141474374657400235370ustar00rootroot00000000000000diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c --- src.orig/fs/readdir.c 2024-04-18 14:12:03.462375128 -0400 +++ src/fs/readdir.c 2024-04-18 14:12:17.665344260 -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)) kpatch-0.9.10/test/integration/rhel-8.10/gcc-constprop.patch000066400000000000000000000006511474374657400235240ustar00rootroot00000000000000diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c --- src.orig/kernel/time/timekeeping.c 2024-04-18 14:12:03.614374798 -0400 +++ src/kernel/time/timekeeping.c 2024-04-18 14:12:19.675339891 -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; kpatch-0.9.10/test/integration/rhel-8.10/gcc-isra.patch000066400000000000000000000006541474374657400224360ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c --- src.orig/fs/proc/proc_sysctl.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/proc_sysctl.c 2024-04-18 14:12:21.710335469 -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); } kpatch-0.9.10/test/integration/rhel-8.10/gcc-mangled-3.patch000066400000000000000000000006321474374657400232430ustar00rootroot00000000000000diff -Nupr src.orig/mm/slub.c src/mm/slub.c --- src.orig/mm/slub.c 2024-04-18 14:12:03.629374765 -0400 +++ src/mm/slub.c 2024-04-18 14:12:23.903330702 -0400 @@ -6192,6 +6192,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); kpatch-0.9.10/test/integration/rhel-8.10/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400250020ustar00rootroot00000000000000diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c --- src.orig/mm/mmap.c 2024-04-18 14:12:03.628374767 -0400 +++ src/mm/mmap.c 2024-04-18 14:12:25.958326236 -0400 @@ -1691,6 +1691,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; kpatch-0.9.10/test/integration/rhel-8.10/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400250070ustar00rootroot00000000000000diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c --- src.orig/kernel/reboot.c 2024-04-18 14:12:03.612374802 -0400 +++ src/kernel/reboot.c 2024-04-18 14:12:27.985321831 -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); } kpatch-0.9.10/test/integration/rhel-8.10/gcc-static-local-var-4.patch000066400000000000000000000011611474374657400250000ustar00rootroot00000000000000diff -Nupr src.orig/fs/aio.c src/fs/aio.c --- src.orig/fs/aio.c 2024-04-18 14:12:03.428375202 -0400 +++ src/fs/aio.c 2024-04-18 14:12:30.010317430 -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); kpatch-0.9.10/test/integration/rhel-8.10/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246650ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.10/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400250040ustar00rootroot00000000000000diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c --- src.orig/kernel/audit.c 2024-04-18 14:12:03.604374820 -0400 +++ src/kernel/audit.c 2024-04-18 14:12:32.055312985 -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; kpatch-0.9.10/test/integration/rhel-8.10/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400250010ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2024-04-18 14:12:03.648374724 -0400 +++ src/net/ipv6/netfilter.c 2024-04-18 14:12:34.140308454 -0400 @@ -93,6 +93,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) { @@ -106,6 +108,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) kpatch-0.9.10/test/integration/rhel-8.10/macro-callbacks.patch000066400000000000000000000107731474374657400237670ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2024-04-18 14:12:03.003376126 -0400 +++ src/drivers/input/joydev.c 2024-04-18 14:12:36.165304053 -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 2024-04-18 14:12:03.007376117 -0400 +++ src/drivers/input/misc/pcspkr.c 2024-04-18 14:12:36.166304050 -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 2024-04-18 14:12:03.428375202 -0400 +++ src/fs/aio.c 2024-04-18 14:12:36.166304050 -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 kpatch-0.9.10/test/integration/rhel-8.10/macro-printk.patch000066400000000000000000000116731474374657400233570ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c --- src.orig/net/ipv4/fib_frontend.c 2024-04-18 14:12:03.644374733 -0400 +++ src/net/ipv4/fib_frontend.c 2024-04-18 14:12:38.274299469 -0400 @@ -798,6 +798,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) { @@ -819,6 +820,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 2024-04-18 14:12:03.644374733 -0400 +++ src/net/ipv4/fib_semantics.c 2024-04-18 14:12:38.275299467 -0400 @@ -1028,6 +1028,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) { @@ -1061,6 +1062,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; @@ -1081,6 +1083,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) @@ -1094,6 +1097,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; @@ -1149,9 +1154,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; @@ -1169,6 +1176,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) { @@ -1190,6 +1198,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"); @@ -1228,6 +1237,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"); @@ -1237,6 +1247,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); @@ -1248,6 +1259,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); @@ -1271,6 +1283,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: @@ -1281,6 +1294,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 2024-04-18 14:12:03.644374733 -0400 +++ src/net/ipv4/fib_trie.c 2024-04-18 14:12:38.275299467 -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, kpatch-0.9.10/test/integration/rhel-8.10/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400240500ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 14:12:42.540290197 -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; } kpatch-0.9.10/test/integration/rhel-8.10/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400241310ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 14:12:40.414294818 -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; } kpatch-0.9.10/test/integration/rhel-8.10/meminfo-string-LOADED.test000077500000000000000000000000551474374657400245100ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.10/meminfo-string.patch000066400000000000000000000010711474374657400236760ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 14:12:44.665285579 -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: ", vmalloc_nr_pages()); - show_val_kb(m, "VmallocChunk: ", 0ul); + show_val_kb(m, "VMALLOCCHUNK: ", 0ul); show_val_kb(m, "Percpu: ", pcpu_nr_pages()); #ifdef CONFIG_MEMORY_FAILURE kpatch-0.9.10/test/integration/rhel-8.10/module-LOADED.test000077500000000000000000000005441474374657400230420ustar00rootroot00000000000000#!/bin/bash set -o errexit sudo modprobe xfs sleep 5 grep -q kpatch /sys/fs/xfs/stats/stats # 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/xfs/xfs_stats.c +p" > /sys/kernel/debug/dynamic_debug/control # dmesg | grep -q "kpatch: pr_debug" kpatch-0.9.10/test/integration/rhel-8.10/module.patch000066400000000000000000000032301474374657400222240ustar00rootroot00000000000000diff -Nupr src.orig/fs/xfs/xfs_stats.c src/fs/xfs/xfs_stats.c --- src.orig/fs/xfs/xfs_stats.c 2024-04-18 14:12:03.471375109 -0400 +++ src/fs/xfs/xfs_stats.c 2024-04-18 14:12:46.797280945 -0400 @@ -16,6 +16,8 @@ static int counter_val(struct xfsstats _ return val; } +extern char *kpatch_string(void); + int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { int i, j; @@ -85,6 +87,34 @@ int xfs_stats_format(struct xfsstats __p 0); #endif + /* Reference a symbol outside the .o yet inside the patch module: */ + len += scnprintf(buf + len, PATH_MAX-len, "%s\n", kpatch_string()); + +#ifdef CONFIG_X86_64 + /* Test alternatives patching: */ + alternative("ud2", "nop", X86_FEATURE_ALWAYS); + alternative("nop", "ud2", X86_FEATURE_IA64); + + /* Test paravirt patching: */ + slow_down_io(); /* paravirt call */ +#endif + + /* Test pr_debug: */ + pr_debug("kpatch: pr_debug() test\n"); + +{ + /* Test static branches: */ + 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); +} + return len; } diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c --- src.orig/net/netlink/af_netlink.c 2024-04-18 14:12:03.660374698 -0400 +++ src/net/netlink/af_netlink.c 2024-04-18 14:12:46.798280943 -0400 @@ -2888,4 +2888,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "kpatch"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-8.10/multiple.test000077500000000000000000000002451474374657400224600ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.10/new-function.patch000066400000000000000000000016261474374657400233620ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2024-04-18 14:12:03.376375315 -0400 +++ src/drivers/tty/n_tty.c 2024-04-18 14:12:48.938276292 -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 kpatch-0.9.10/test/integration/rhel-8.10/new-globals.patch000066400000000000000000000022011474374657400231460ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/cmdline.c 2024-04-18 14:12:51.049271704 -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 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 14:12:51.049271704 -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); kpatch-0.9.10/test/integration/rhel-8.10/parainstructions-section.patch000066400000000000000000000006731474374657400260210ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c --- src.orig/fs/proc/generic.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/generic.c 2024-04-18 14:12:53.192267047 -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) kpatch-0.9.10/test/integration/rhel-8.10/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400243230ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.10/shadow-newpid.patch000066400000000000000000000046701474374657400235210ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2024-04-18 14:12:03.460375133 -0400 +++ src/fs/proc/array.c 2024-04-18 14:12:55.335262389 -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 2024-04-18 14:12:03.608374811 -0400 +++ src/kernel/exit.c 2024-04-18 14:12:55.335262389 -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 2024-04-18 14:12:03.608374811 -0400 +++ src/kernel/fork.c 2024-04-18 14:12:55.336262387 -0400 @@ -2475,6 +2475,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, @@ -2487,6 +2488,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 @@ -2513,6 +2516,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. kpatch-0.9.10/test/integration/rhel-8.10/smp-locks-section.patch000066400000000000000000000007471474374657400243230ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c --- src.orig/drivers/tty/tty_buffer.c 2024-04-18 14:12:03.380375306 -0400 +++ src/drivers/tty/tty_buffer.c 2024-04-18 14:12:57.481257725 -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; kpatch-0.9.10/test/integration/rhel-8.10/special-static.patch000066400000000000000000000010441474374657400236450ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2024-04-18 14:12:03.608374811 -0400 +++ src/kernel/fork.c 2024-04-18 14:12:59.608253102 -0400 @@ -1661,10 +1661,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; kpatch-0.9.10/test/integration/rhel-8.10/symvers-disagreement-FAIL.patch000066400000000000000000000014361474374657400256330ustar00rootroot00000000000000diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c --- src.orig/drivers/base/core.c 2024-04-18 14:12:02.743376691 -0400 +++ src/drivers/base/core.c 2024-04-18 14:13:01.732248486 -0400 @@ -34,6 +34,8 @@ #include "physical_location.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 2024-04-18 14:12:03.383375300 -0400 +++ src/drivers/usb/core/usb.c 2024-04-18 14:13:01.733248484 -0400 @@ -769,6 +769,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; kpatch-0.9.10/test/integration/rhel-8.10/syscall-LOADED.test000077500000000000000000000000471474374657400232250ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-8.10/syscall.patch000066400000000000000000000014501474374657400224130ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2024-04-18 14:12:03.613374800 -0400 +++ src/kernel/sys.c 2024-04-18 14:13:03.847243889 -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; kpatch-0.9.10/test/integration/rhel-8.10/tracepoints-section.patch000066400000000000000000000010211474374657400247300ustar00rootroot00000000000000diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c --- src.orig/kernel/time/timer.c 2024-04-18 14:12:03.614374798 -0400 +++ src/kernel/time/timer.c 2024-04-18 14:13:05.967239282 -0400 @@ -1988,6 +1988,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])); kpatch-0.9.10/test/integration/rhel-8.10/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236760ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2024-04-18 14:12:02.707376769 -0400 +++ src/arch/x86/kvm/x86.c 2024-04-18 14:13:08.122234598 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rhel-8.2/000077500000000000000000000000001474374657400176415ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.2/bug-table-section.patch000066400000000000000000000007711474374657400241730ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.2/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244060ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.2/cmdline-string.patch000066400000000000000000000006141474374657400236020ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.2/data-new-LOADED.test000077500000000000000000000000641474374657400231730ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.2/data-new.patch000066400000000000000000000011551474374657400223640ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.2/data-read-mostly.patch.disabled000066400000000000000000000005561474374657400256050ustar00rootroot00000000000000Disabled 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(); } } kpatch-0.9.10/test/integration/rhel-8.2/fixup-section.patch000066400000000000000000000006141474374657400234600ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.2/gcc-constprop.patch000066400000000000000000000006511474374657400234450ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.2/gcc-isra.patch000066400000000000000000000006541474374657400223570ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.2/gcc-mangled-3.patch000066400000000000000000000006321474374657400231640ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.2/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247230ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.2/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247300ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.2/gcc-static-local-var-4.patch.disabled000066400000000000000000000011541474374657400264710ustar00rootroot00000000000000Disabled 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); kpatch-0.9.10/test/integration/rhel-8.2/gcc-static-local-var-4.test.disabled000077500000000000000000000002451474374657400263540ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.2/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247250ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.2/gcc-static-local-var-6.patch000066400000000000000000000012171474374657400247250ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.2/macro-callbacks.patch000066400000000000000000000107731474374657400237100ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.2/macro-printk.patch000066400000000000000000000116121474374657400232710ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-8.2/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400237710ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.2/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240520ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.2/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244310ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.2/meminfo-string.patch000066400000000000000000000010521474374657400236160ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.2/module-LOADED.test000077500000000000000000000006061474374657400227620ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.2/module.patch000066400000000000000000000050121474374657400221450ustar00rootroot00000000000000From 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); kpatch-0.9.10/test/integration/rhel-8.2/multiple.test000077500000000000000000000002451474374657400224010ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.2/new-function.patch000066400000000000000000000016261474374657400233030ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.2/new-globals.patch000066400000000000000000000021611474374657400230740ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.2/parainstructions-section.patch000066400000000000000000000006731474374657400257420ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.2/shadow-newpid-LOADED.test.disabled000077500000000000000000000000551474374657400260120ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.2/shadow-newpid.patch.disabled000066400000000000000000000047621474374657400252120ustar00rootroot00000000000000Disabled 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. kpatch-0.9.10/test/integration/rhel-8.2/smp-locks-section.patch000066400000000000000000000007471474374657400242440ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.2/special-static.patch.disabled000066400000000000000000000011121474374657400253300ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.2/symvers-disagreement-FAIL.patch000066400000000000000000000025741474374657400255600ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-8.2/tracepoints-section.patch000066400000000000000000000010211474374657400246510ustar00rootroot00000000000000diff -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])); kpatch-0.9.10/test/integration/rhel-8.2/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236100ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.3/000077500000000000000000000000001474374657400176425ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.3/bug-table-section.patch000066400000000000000000000007711474374657400241740ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.3/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244070ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.3/cmdline-string.patch000066400000000000000000000006141474374657400236030ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.3/data-new-LOADED.test000077500000000000000000000000641474374657400231740ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.3/data-new.patch000066400000000000000000000011551474374657400223650ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.3/data-read-mostly.patch.disabled000066400000000000000000000005571474374657400256070ustar00rootroot00000000000000Disabled 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(); } } kpatch-0.9.10/test/integration/rhel-8.3/fixup-section.patch000066400000000000000000000006141474374657400234610ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.3/gcc-constprop.patch000066400000000000000000000006511474374657400234460ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.3/gcc-isra.patch000066400000000000000000000006541474374657400223600ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.3/gcc-mangled-3.patch000066400000000000000000000006321474374657400231650ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.3/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247240ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.3/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247310ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.3/gcc-static-local-var-4.patch.disabled000066400000000000000000000011551474374657400264730ustar00rootroot00000000000000Disabled 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); kpatch-0.9.10/test/integration/rhel-8.3/gcc-static-local-var-4.test.disabled000077500000000000000000000002451474374657400263550ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.3/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247260ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.3/gcc-static-local-var-6.patch000066400000000000000000000012131474374657400247220ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.3/macro-callbacks.patch000066400000000000000000000107731474374657400237110ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.3/macro-printk.patch000066400000000000000000000116121474374657400232720ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-8.3/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400237720ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.3/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240530ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.3/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244320ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.3/meminfo-string.patch000066400000000000000000000010521474374657400236170ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.3/module-LOADED.test000077500000000000000000000006061474374657400227630ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.3/module.patch000066400000000000000000000050121474374657400221460ustar00rootroot00000000000000From 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); kpatch-0.9.10/test/integration/rhel-8.3/multiple.test000077500000000000000000000002451474374657400224020ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.3/new-function.patch000066400000000000000000000016261474374657400233040ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.3/new-globals.patch000066400000000000000000000021611474374657400230750ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.3/parainstructions-section.patch000066400000000000000000000006731474374657400257430ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.3/shadow-newpid-LOADED.test.disabled000077500000000000000000000000551474374657400260130ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.3/shadow-newpid.patch.disabled000066400000000000000000000047631474374657400252140ustar00rootroot00000000000000Disabled 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. kpatch-0.9.10/test/integration/rhel-8.3/smp-locks-section.patch000066400000000000000000000007471474374657400242450ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.3/special-static.patch.disabled000066400000000000000000000011121474374657400253310ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.3/symvers-disagreement-FAIL.patch000066400000000000000000000025741474374657400255610ustar00rootroot00000000000000From 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 kpatch-0.9.10/test/integration/rhel-8.3/tracepoints-section.patch000066400000000000000000000010211474374657400246520ustar00rootroot00000000000000diff -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])); kpatch-0.9.10/test/integration/rhel-8.3/warn-detect-FAIL.patch000066400000000000000000000004151474374657400236110ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.4/000077500000000000000000000000001474374657400176435ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.4/bug-table-section.patch000066400000000000000000000007711474374657400241750ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.4/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244100ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.4/cmdline-string.patch000066400000000000000000000006141474374657400236040ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.4/data-new-LOADED.test000077500000000000000000000000641474374657400231750ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.4/data-new.patch000066400000000000000000000011551474374657400223660ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.4/data-read-mostly.patch000066400000000000000000000004601474374657400240330ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-8.4/fixup-section.patch000066400000000000000000000006141474374657400234620ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.4/gcc-constprop.patch000066400000000000000000000006511474374657400234470ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.4/gcc-isra.patch000066400000000000000000000006541474374657400223610ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.4/gcc-mangled-3.patch000066400000000000000000000006321474374657400231660ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.4/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247250ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.4/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247320ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.4/gcc-static-local-var-4.patch000066400000000000000000000011611474374657400247230ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.4/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246100ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.4/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247270ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.4/gcc-static-local-var-6.patch000066400000000000000000000012131474374657400247230ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.4/macro-callbacks.patch000066400000000000000000000107731474374657400237120ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.4/macro-printk.patch000066400000000000000000000116731474374657400233020ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-8.4/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400237730ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.4/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240540ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.4/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244330ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.4/meminfo-string.patch000066400000000000000000000010521474374657400236200ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.4/module-LOADED.test000077500000000000000000000006061474374657400227640ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.4/module.patch000066400000000000000000000050121474374657400221470ustar00rootroot00000000000000From 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); kpatch-0.9.10/test/integration/rhel-8.4/multiple.test000077500000000000000000000002451474374657400224030ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.4/new-function.patch000066400000000000000000000016261474374657400233050ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.4/new-globals.patch000066400000000000000000000022011474374657400230710ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.4/parainstructions-section.patch000066400000000000000000000006731474374657400257440ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.4/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242460ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.4/shadow-newpid.patch000066400000000000000000000046701474374657400234440ustar00rootroot00000000000000diff -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. kpatch-0.9.10/test/integration/rhel-8.4/smp-locks-section.patch000066400000000000000000000007471474374657400242460ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.4/special-static.patch000066400000000000000000000010441474374657400235700ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.4/symvers-disagreement-FAIL.patch000066400000000000000000000027241474374657400255570ustar00rootroot00000000000000From 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; kpatch-0.9.10/test/integration/rhel-8.4/syscall-LOADED.test000077500000000000000000000000471474374657400231500ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-8.4/syscall.patch000066400000000000000000000014161474374657400223400ustar00rootroot00000000000000diff --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; kpatch-0.9.10/test/integration/rhel-8.4/tracepoints-section.patch000066400000000000000000000010211474374657400246530ustar00rootroot00000000000000diff -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])); kpatch-0.9.10/test/integration/rhel-8.4/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236210ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.6/000077500000000000000000000000001474374657400176455ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.6/bug-table-section.patch000066400000000000000000000007711474374657400241770ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.6/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244120ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.6/cmdline-string.patch000066400000000000000000000006141474374657400236060ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.6/data-new-LOADED.test000077500000000000000000000000641474374657400231770ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.6/data-new.patch000066400000000000000000000011551474374657400223700ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.6/data-read-mostly.patch000066400000000000000000000004601474374657400240350ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-8.6/fixup-section.patch000066400000000000000000000006141474374657400234640ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.6/gcc-constprop.patch000066400000000000000000000006511474374657400234510ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.6/gcc-isra.patch000066400000000000000000000006541474374657400223630ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.6/gcc-mangled-3.patch000066400000000000000000000006321474374657400231700ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.6/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247270ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.6/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247340ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.6/gcc-static-local-var-4.patch000066400000000000000000000011611474374657400247250ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.6/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246120ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.6/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247310ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.6/gcc-static-local-var-6.patch000066400000000000000000000012131474374657400247250ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.6/macro-callbacks.patch000066400000000000000000000107731474374657400237140ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.6/macro-printk.patch000066400000000000000000000116731474374657400233040ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-8.6/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400237750ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.6/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240560ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.6/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244350ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.6/meminfo-string.patch000066400000000000000000000010521474374657400236220ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.6/module-LOADED.test000077500000000000000000000006061474374657400227660ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.6/module.patch000066400000000000000000000050121474374657400221510ustar00rootroot00000000000000From 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); kpatch-0.9.10/test/integration/rhel-8.6/multiple.test000077500000000000000000000002451474374657400224050ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.6/new-function.patch000066400000000000000000000016261474374657400233070ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.6/new-globals.patch000066400000000000000000000022011474374657400230730ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.6/parainstructions-section.patch000066400000000000000000000006731474374657400257460ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.6/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242500ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.6/shadow-newpid.patch000066400000000000000000000046701474374657400234460ustar00rootroot00000000000000diff -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. kpatch-0.9.10/test/integration/rhel-8.6/smp-locks-section.patch000066400000000000000000000007471474374657400242500ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.6/special-static.patch000066400000000000000000000010441474374657400235720ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.6/symvers-disagreement-FAIL.patch000066400000000000000000000027241474374657400255610ustar00rootroot00000000000000From 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; kpatch-0.9.10/test/integration/rhel-8.6/syscall-LOADED.test000077500000000000000000000000471474374657400231520ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-8.6/syscall.patch000066400000000000000000000014501474374657400223400ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.6/tracepoints-section.patch000066400000000000000000000010211474374657400246550ustar00rootroot00000000000000diff -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])); kpatch-0.9.10/test/integration/rhel-8.6/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236230ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.7/000077500000000000000000000000001474374657400176465ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.7/bug-table-section.patch000066400000000000000000000007711474374657400242000ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.7/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244130ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.7/cmdline-string.patch000066400000000000000000000006141474374657400236070ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.7/data-new-LOADED.test000077500000000000000000000000641474374657400232000ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.7/data-new.patch000066400000000000000000000011551474374657400223710ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.7/data-read-mostly.patch000066400000000000000000000004601474374657400240360ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/rhel-8.7/fixup-section.patch000066400000000000000000000006141474374657400234650ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/rhel-8.7/gcc-constprop.patch000066400000000000000000000006511474374657400234520ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.7/gcc-isra.patch000066400000000000000000000006541474374657400223640ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.7/gcc-mangled-3.patch000066400000000000000000000006321474374657400231710ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.7/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247300ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.7/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247350ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/rhel-8.7/gcc-static-local-var-4.patch000066400000000000000000000011611474374657400247260ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.7/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246130ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.7/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247320ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.7/gcc-static-local-var-6.patch000066400000000000000000000012131474374657400247260ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.7/macro-callbacks.patch000066400000000000000000000107731474374657400237150ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.7/macro-printk.patch000066400000000000000000000116731474374657400233050ustar00rootroot00000000000000diff -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, kpatch-0.9.10/test/integration/rhel-8.7/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400237760ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.7/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240570ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/rhel-8.7/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244360ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.7/meminfo-string.patch000066400000000000000000000010521474374657400236230ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.7/module-LOADED.test000077500000000000000000000006061474374657400227670ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.7/module.patch000066400000000000000000000050121474374657400221520ustar00rootroot00000000000000From 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); kpatch-0.9.10/test/integration/rhel-8.7/multiple.test000077500000000000000000000002451474374657400224060ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.7/new-function.patch000066400000000000000000000016261474374657400233100ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-8.7/new-globals.patch000066400000000000000000000022011474374657400230740ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-8.7/parainstructions-section.patch000066400000000000000000000006731474374657400257470ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-8.7/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242510ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.7/shadow-newpid.patch000066400000000000000000000046701474374657400234470ustar00rootroot00000000000000diff -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. kpatch-0.9.10/test/integration/rhel-8.7/smp-locks-section.patch000066400000000000000000000007471474374657400242510ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.7/special-static.patch000066400000000000000000000010441474374657400235730ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.7/symvers-disagreement-FAIL.patch000066400000000000000000000027241474374657400255620ustar00rootroot00000000000000From 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; kpatch-0.9.10/test/integration/rhel-8.7/syscall-LOADED.test000077500000000000000000000000471474374657400231530ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-8.7/syscall.patch000066400000000000000000000014501474374657400223410ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-8.7/tracepoints-section.patch000066400000000000000000000010211474374657400246560ustar00rootroot00000000000000diff -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])); kpatch-0.9.10/test/integration/rhel-8.7/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236240ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-8.8/000077500000000000000000000000001474374657400176475ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.8/bug-table-section.patch000066400000000000000000000007711474374657400242010ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c --- src.orig/fs/proc/proc_sysctl.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/proc_sysctl.c 2023-04-24 14:22:43.962961760 -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)) kpatch-0.9.10/test/integration/rhel-8.8/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244140ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.8/cmdline-string.patch000066400000000000000000000006141474374657400236100ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/cmdline.c 2023-04-24 14:22:55.620002018 -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; } kpatch-0.9.10/test/integration/rhel-8.8/data-new-LOADED.test000077500000000000000000000000641474374657400232010ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.8/data-new.patch000066400000000000000000000011551474374657400223720ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:22:58.461011829 -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); kpatch-0.9.10/test/integration/rhel-8.8/data-read-mostly.patch000066400000000000000000000004601474374657400240370ustar00rootroot00000000000000diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c --- src.orig/net/core/dev.c 2023-04-24 14:22:43.578960434 -0400 +++ src/net/core/dev.c 2023-04-24 14:23:01.282021571 -0400 @@ -5440,6 +5440,7 @@ skip_classify: case RX_HANDLER_PASS: break; default: + printk("BUG!\n"); BUG(); } } kpatch-0.9.10/test/integration/rhel-8.8/fixup-section.patch000066400000000000000000000006141474374657400234660ustar00rootroot00000000000000diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c --- src.orig/fs/readdir.c 2023-04-24 14:22:43.304959488 -0400 +++ src/fs/readdir.c 2023-04-24 14:23:04.101031307 -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)) kpatch-0.9.10/test/integration/rhel-8.8/gcc-constprop.patch000066400000000000000000000006511474374657400234530ustar00rootroot00000000000000diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c --- src.orig/kernel/time/timekeeping.c 2023-04-24 14:22:43.539960299 -0400 +++ src/kernel/time/timekeeping.c 2023-04-24 14:23:06.906040994 -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; kpatch-0.9.10/test/integration/rhel-8.8/gcc-isra.patch000066400000000000000000000006541474374657400223650ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c --- src.orig/fs/proc/proc_sysctl.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/proc_sysctl.c 2023-04-24 14:23:09.715050695 -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); } kpatch-0.9.10/test/integration/rhel-8.8/gcc-mangled-3.patch000066400000000000000000000006321474374657400231720ustar00rootroot00000000000000diff -Nupr src.orig/mm/slub.c src/mm/slub.c --- src.orig/mm/slub.c 2023-04-24 14:22:43.563960382 -0400 +++ src/mm/slub.c 2023-04-24 14:23:12.536060437 -0400 @@ -6085,6 +6085,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); kpatch-0.9.10/test/integration/rhel-8.8/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247310ustar00rootroot00000000000000diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c --- src.orig/mm/mmap.c 2023-04-24 14:22:43.562960379 -0400 +++ src/mm/mmap.c 2023-04-24 14:23:15.352070162 -0400 @@ -1701,6 +1701,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; kpatch-0.9.10/test/integration/rhel-8.8/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247360ustar00rootroot00000000000000diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c --- src.orig/kernel/reboot.c 2023-04-24 14:22:43.536960289 -0400 +++ src/kernel/reboot.c 2023-04-24 14:23:18.171079898 -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); } kpatch-0.9.10/test/integration/rhel-8.8/gcc-static-local-var-4.patch000066400000000000000000000011611474374657400247270ustar00rootroot00000000000000diff -Nupr src.orig/fs/aio.c src/fs/aio.c --- src.orig/fs/aio.c 2023-04-24 14:22:43.250959301 -0400 +++ src/fs/aio.c 2023-04-24 14:23:21.002089674 -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); kpatch-0.9.10/test/integration/rhel-8.8/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246140ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.8/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247330ustar00rootroot00000000000000diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c --- src.orig/kernel/audit.c 2023-04-24 14:22:43.524960248 -0400 +++ src/kernel/audit.c 2023-04-24 14:23:23.810099372 -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; kpatch-0.9.10/test/integration/rhel-8.8/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247300ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2023-04-24 14:22:43.593960486 -0400 +++ src/net/ipv6/netfilter.c 2023-04-24 14:23:26.640109145 -0400 @@ -93,6 +93,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) { @@ -106,6 +108,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) kpatch-0.9.10/test/integration/rhel-8.8/macro-callbacks.patch000066400000000000000000000107731474374657400237160ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2023-04-24 14:22:42.562956925 -0400 +++ src/drivers/input/joydev.c 2023-04-24 14:23:29.479118950 -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 2023-04-24 14:22:42.568956946 -0400 +++ src/drivers/input/misc/pcspkr.c 2023-04-24 14:23:29.479118950 -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 2023-04-24 14:22:43.250959301 -0400 +++ src/fs/aio.c 2023-04-24 14:23:29.480118953 -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 kpatch-0.9.10/test/integration/rhel-8.8/macro-printk.patch000066400000000000000000000116731474374657400233060ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c --- src.orig/net/ipv4/fib_frontend.c 2023-04-24 14:22:43.587960465 -0400 +++ src/net/ipv4/fib_frontend.c 2023-04-24 14:23:32.327128785 -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 2023-04-24 14:22:43.587960465 -0400 +++ src/net/ipv4/fib_semantics.c 2023-04-24 14:23:32.328128789 -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 2023-04-24 14:22:43.587960465 -0400 +++ src/net/ipv4/fib_trie.c 2023-04-24 14:23:32.328128789 -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, kpatch-0.9.10/test/integration/rhel-8.8/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400237770ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:23:38.093148698 -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; } kpatch-0.9.10/test/integration/rhel-8.8/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240600ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:23:35.189138669 -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; } kpatch-0.9.10/test/integration/rhel-8.8/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244370ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.8/meminfo-string.patch000066400000000000000000000010711474374657400236250ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:23:40.970158634 -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: ", vmalloc_nr_pages()); - show_val_kb(m, "VmallocChunk: ", 0ul); + show_val_kb(m, "VMALLOCCHUNK: ", 0ul); show_val_kb(m, "Percpu: ", pcpu_nr_pages()); #ifdef CONFIG_MEMORY_FAILURE kpatch-0.9.10/test/integration/rhel-8.8/module-LOADED.test000077500000000000000000000006061474374657400227700ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-8.8/module.patch000066400000000000000000000050121474374657400221530ustar00rootroot00000000000000From 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 2023-04-24 14:22:43.286959426 -0400 +++ src/fs/nfsd/export.c 2023-04-24 14:23:43.847168570 -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 2023-04-24 14:22:43.612960551 -0400 +++ src/net/netlink/af_netlink.c 2023-04-24 14:23:43.848168573 -0400 @@ -2886,4 +2886,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "# kpatch\n"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-8.8/multiple.test000077500000000000000000000002451474374657400224070ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.8/new-function.patch000066400000000000000000000016261474374657400233110ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2023-04-24 14:22:43.167959015 -0400 +++ src/drivers/tty/n_tty.c 2023-04-24 14:23:46.713178467 -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 kpatch-0.9.10/test/integration/rhel-8.8/new-globals.patch000066400000000000000000000022011474374657400230750ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/cmdline.c 2023-04-24 14:23:49.566188320 -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 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:23:49.566188320 -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); kpatch-0.9.10/test/integration/rhel-8.8/parainstructions-section.patch000066400000000000000000000006731474374657400257500ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c --- src.orig/fs/proc/generic.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/generic.c 2023-04-24 14:23:52.460198315 -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) kpatch-0.9.10/test/integration/rhel-8.8/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242520ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.8/shadow-newpid.patch000066400000000000000000000046701474374657400234500ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2023-04-24 14:22:43.301959477 -0400 +++ src/fs/proc/array.c 2023-04-24 14:23:55.318208185 -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 2023-04-24 14:22:43.529960265 -0400 +++ src/kernel/exit.c 2023-04-24 14:23:55.319208188 -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 2023-04-24 14:22:43.529960265 -0400 +++ src/kernel/fork.c 2023-04-24 14:23:55.319208188 -0400 @@ -2399,6 +2399,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, @@ -2411,6 +2412,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 @@ -2437,6 +2440,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. kpatch-0.9.10/test/integration/rhel-8.8/smp-locks-section.patch000066400000000000000000000007471474374657400242520ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c --- src.orig/drivers/tty/tty_buffer.c 2023-04-24 14:22:43.173959035 -0400 +++ src/drivers/tty/tty_buffer.c 2023-04-24 14:23:58.206218158 -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; kpatch-0.9.10/test/integration/rhel-8.8/special-static.patch000066400000000000000000000010441474374657400235740ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2023-04-24 14:22:43.529960265 -0400 +++ src/kernel/fork.c 2023-04-24 14:24:01.089228115 -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; kpatch-0.9.10/test/integration/rhel-8.8/symvers-disagreement-FAIL.patch000066400000000000000000000027411474374657400255620ustar00rootroot00000000000000From 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 2023-04-24 14:22:42.148955496 -0400 +++ src/drivers/base/core.c 2023-04-24 14:24:04.162238727 -0400 @@ -34,6 +34,8 @@ #include "physical_location.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 2023-04-24 14:22:43.178959053 -0400 +++ src/drivers/usb/core/usb.c 2023-04-24 14:24:04.163238731 -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; kpatch-0.9.10/test/integration/rhel-8.8/syscall-LOADED.test000077500000000000000000000000471474374657400231540ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-8.8/syscall.patch000066400000000000000000000014501474374657400223420ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2023-04-24 14:22:43.538960296 -0400 +++ src/kernel/sys.c 2023-04-24 14:24:07.027248622 -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; kpatch-0.9.10/test/integration/rhel-8.8/tracepoints-section.patch000066400000000000000000000010211474374657400246570ustar00rootroot00000000000000diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c --- src.orig/kernel/time/timer.c 2023-04-24 14:22:43.539960299 -0400 +++ src/kernel/time/timer.c 2023-04-24 14:24:09.953258727 -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])); kpatch-0.9.10/test/integration/rhel-8.8/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236250ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2023-04-24 14:22:42.090955295 -0400 +++ src/arch/x86/kvm/x86.c 2023-04-24 14:24:12.817268617 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rhel-8.9/000077500000000000000000000000001474374657400176505ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-8.9/bug-table-section.patch000066400000000000000000000007711474374657400242020ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c --- src.orig/fs/proc/proc_sysctl.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/proc_sysctl.c 2023-05-18 13:26:13.738170286 -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)) kpatch-0.9.10/test/integration/rhel-8.9/cmdline-string-LOADED.test000077500000000000000000000000511474374657400244150ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/rhel-8.9/cmdline-string.patch000066400000000000000000000006141474374657400236110ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/cmdline.c 2023-05-18 13:26:20.040162860 -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; } kpatch-0.9.10/test/integration/rhel-8.9/data-new-LOADED.test000077500000000000000000000000641474374657400232020ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.9/data-new.patch000066400000000000000000000011551474374657400223730ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/meminfo.c 2023-05-18 13:26:27.035154617 -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); kpatch-0.9.10/test/integration/rhel-8.9/data-read-mostly.patch000066400000000000000000000004601474374657400240400ustar00rootroot00000000000000diff -Nupr src.orig/net/core/dev.c src/net/core/dev.c --- src.orig/net/core/dev.c 2023-05-18 13:26:13.486170583 -0400 +++ src/net/core/dev.c 2023-05-18 13:26:31.948148828 -0400 @@ -5440,6 +5440,7 @@ skip_classify: case RX_HANDLER_PASS: break; default: + printk("BUG!\n"); BUG(); } } kpatch-0.9.10/test/integration/rhel-8.9/fixup-section.patch000066400000000000000000000006141474374657400234670ustar00rootroot00000000000000diff -Nupr src.orig/fs/readdir.c src/fs/readdir.c --- src.orig/fs/readdir.c 2023-05-18 13:26:13.306170795 -0400 +++ src/fs/readdir.c 2023-05-18 13:26:37.497142290 -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)) kpatch-0.9.10/test/integration/rhel-8.9/gcc-constprop.patch000066400000000000000000000006511474374657400234540ustar00rootroot00000000000000diff -Nupr src.orig/kernel/time/timekeeping.c src/kernel/time/timekeeping.c --- src.orig/kernel/time/timekeeping.c 2023-05-18 13:26:13.459170615 -0400 +++ src/kernel/time/timekeeping.c 2023-05-18 13:26:42.511136382 -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; kpatch-0.9.10/test/integration/rhel-8.9/gcc-isra.patch000066400000000000000000000006541474374657400223660ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/proc_sysctl.c src/fs/proc/proc_sysctl.c --- src.orig/fs/proc/proc_sysctl.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/proc_sysctl.c 2023-05-18 13:26:48.145129743 -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); } kpatch-0.9.10/test/integration/rhel-8.9/gcc-mangled-3.patch000066400000000000000000000006321474374657400231730ustar00rootroot00000000000000diff -Nupr src.orig/mm/slub.c src/mm/slub.c --- src.orig/mm/slub.c 2023-05-18 13:26:13.476170595 -0400 +++ src/mm/slub.c 2023-05-18 13:26:51.355125960 -0400 @@ -6085,6 +6085,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); kpatch-0.9.10/test/integration/rhel-8.9/gcc-static-local-var-2.patch000066400000000000000000000007241474374657400247320ustar00rootroot00000000000000diff -Nupr src.orig/mm/mmap.c src/mm/mmap.c --- src.orig/mm/mmap.c 2023-05-18 13:26:13.475170596 -0400 +++ src/mm/mmap.c 2023-05-18 13:26:54.612122123 -0400 @@ -1691,6 +1691,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; kpatch-0.9.10/test/integration/rhel-8.9/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400247370ustar00rootroot00000000000000diff -Nupr src.orig/kernel/reboot.c src/kernel/reboot.c --- src.orig/kernel/reboot.c 2023-05-18 13:26:13.457170617 -0400 +++ src/kernel/reboot.c 2023-05-18 13:26:57.125119162 -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); } kpatch-0.9.10/test/integration/rhel-8.9/gcc-static-local-var-4.patch000066400000000000000000000011611474374657400247300ustar00rootroot00000000000000diff -Nupr src.orig/fs/aio.c src/fs/aio.c --- src.orig/fs/aio.c 2023-05-18 13:26:13.270170838 -0400 +++ src/fs/aio.c 2023-05-18 13:26:59.650116186 -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); kpatch-0.9.10/test/integration/rhel-8.9/gcc-static-local-var-4.test000077500000000000000000000002451474374657400246150ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/rhel-8.9/gcc-static-local-var-5.patch000066400000000000000000000021721474374657400247340ustar00rootroot00000000000000diff -Nupr src.orig/kernel/audit.c src/kernel/audit.c --- src.orig/kernel/audit.c 2023-05-18 13:26:13.449170627 -0400 +++ src/kernel/audit.c 2023-05-18 13:27:02.109113288 -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; kpatch-0.9.10/test/integration/rhel-8.9/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247310ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2023-05-18 13:26:13.496170571 -0400 +++ src/net/ipv6/netfilter.c 2023-05-18 13:27:04.595110359 -0400 @@ -93,6 +93,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) { @@ -106,6 +108,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) kpatch-0.9.10/test/integration/rhel-8.9/macro-callbacks.patch000066400000000000000000000107731474374657400237170ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2023-05-18 13:26:12.823171364 -0400 +++ src/drivers/input/joydev.c 2023-05-18 13:27:06.913107628 -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 2023-05-18 13:26:12.827171360 -0400 +++ src/drivers/input/misc/pcspkr.c 2023-05-18 13:27:06.913107628 -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 2023-05-18 13:26:13.270170838 -0400 +++ src/fs/aio.c 2023-05-18 13:27:06.913107628 -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 kpatch-0.9.10/test/integration/rhel-8.9/macro-printk.patch000066400000000000000000000116731474374657400233070ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv4/fib_frontend.c src/net/ipv4/fib_frontend.c --- src.orig/net/ipv4/fib_frontend.c 2023-05-18 13:26:13.492170576 -0400 +++ src/net/ipv4/fib_frontend.c 2023-05-18 13:27:09.416104679 -0400 @@ -798,6 +798,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) { @@ -819,6 +820,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 2023-05-18 13:26:13.492170576 -0400 +++ src/net/ipv4/fib_semantics.c 2023-05-18 13:27:09.417104677 -0400 @@ -1026,6 +1026,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) { @@ -1059,6 +1060,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; @@ -1079,6 +1081,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) @@ -1092,6 +1095,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; @@ -1147,9 +1152,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; @@ -1167,6 +1174,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) { @@ -1188,6 +1196,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"); @@ -1226,6 +1235,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"); @@ -1235,6 +1245,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); @@ -1246,6 +1257,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); @@ -1269,6 +1281,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: @@ -1279,6 +1292,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 2023-05-18 13:26:13.492170576 -0400 +++ src/net/ipv4/fib_trie.c 2023-05-18 13:27:09.417104677 -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, kpatch-0.9.10/test/integration/rhel-8.9/meminfo-init-FAIL.patch000066400000000000000000000006071474374657400240000ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/meminfo.c 2023-05-18 13:27:14.460098735 -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; } kpatch-0.9.10/test/integration/rhel-8.9/meminfo-init2-FAIL.patch000066400000000000000000000011551474374657400240610ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/meminfo.c 2023-05-18 13:27:11.926101721 -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; } kpatch-0.9.10/test/integration/rhel-8.9/meminfo-string-LOADED.test000077500000000000000000000000551474374657400244400ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/rhel-8.9/meminfo-string.patch000066400000000000000000000010711474374657400236260ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/meminfo.c 2023-05-18 13:27:16.879095885 -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: ", vmalloc_nr_pages()); - show_val_kb(m, "VmallocChunk: ", 0ul); + show_val_kb(m, "VMALLOCCHUNK: ", 0ul); show_val_kb(m, "Percpu: ", pcpu_nr_pages()); #ifdef CONFIG_MEMORY_FAILURE kpatch-0.9.10/test/integration/rhel-8.9/module-LOADED.test000077500000000000000000000005441474374657400227720ustar00rootroot00000000000000#!/bin/bash set -o errexit sudo modprobe xfs sleep 5 grep -q kpatch /sys/fs/xfs/stats/stats # 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/xfs/xfs_stats.c +p" > /sys/kernel/debug/dynamic_debug/control # dmesg | grep -q "kpatch: pr_debug" kpatch-0.9.10/test/integration/rhel-8.9/module.patch000066400000000000000000000040551474374657400221620ustar00rootroot00000000000000kpatch 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/xfs/xfs_stats.c src/fs/xfs/xfs_stats.c --- src.orig/fs/xfs/xfs_stats.c 2023-05-18 13:26:13.315170784 -0400 +++ src/fs/xfs/xfs_stats.c 2023-05-18 13:27:19.233093111 -0400 @@ -16,6 +16,8 @@ static int counter_val(struct xfsstats _ return val; } +extern char *kpatch_string(void); + int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) { int i, j; @@ -85,6 +87,34 @@ int xfs_stats_format(struct xfsstats __p 0); #endif + /* Reference a symbol outside the .o yet inside the patch module: */ + len += scnprintf(buf + len, PATH_MAX-len, "%s\n", kpatch_string()); + +#ifdef CONFIG_X86_64 + /* Test alternatives patching: */ + alternative("ud2", "nop", X86_FEATURE_ALWAYS); + alternative("nop", "ud2", X86_FEATURE_IA64); + + /* Test paravirt patching: */ + slow_down_io(); /* paravirt call */ +#endif + + /* Test pr_debug: */ + pr_debug("kpatch: pr_debug() test\n"); + +{ + /* Test static branches: */ + 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); +} + return len; } diff -Nupr src.orig/net/netlink/af_netlink.c src/net/netlink/af_netlink.c --- src.orig/net/netlink/af_netlink.c 2023-05-18 13:26:13.508170557 -0400 +++ src/net/netlink/af_netlink.c 2023-05-18 13:27:19.233093111 -0400 @@ -2886,4 +2886,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "kpatch"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-8.9/multiple.test000077500000000000000000000002451474374657400224100ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-8.9/new-function.patch000066400000000000000000000016261474374657400233120ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2023-05-18 13:26:13.216170901 -0400 +++ src/drivers/tty/n_tty.c 2023-05-18 13:27:21.591090332 -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 kpatch-0.9.10/test/integration/rhel-8.9/new-globals.patch000066400000000000000000000022011474374657400230760ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/cmdline.c 2023-05-18 13:27:23.780087752 -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 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/meminfo.c 2023-05-18 13:27:23.780087752 -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); kpatch-0.9.10/test/integration/rhel-8.9/parainstructions-section.patch000066400000000000000000000006731474374657400257510ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/generic.c src/fs/proc/generic.c --- src.orig/fs/proc/generic.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/generic.c 2023-05-18 13:27:25.966085176 -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) kpatch-0.9.10/test/integration/rhel-8.9/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242530ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-8.9/shadow-newpid.patch000066400000000000000000000046701474374657400234510ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2023-05-18 13:26:13.304170797 -0400 +++ src/fs/proc/array.c 2023-05-18 13:27:28.151082601 -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 2023-05-18 13:26:13.453170622 -0400 +++ src/kernel/exit.c 2023-05-18 13:27:28.151082601 -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 2023-05-18 13:26:13.453170622 -0400 +++ src/kernel/fork.c 2023-05-18 13:27:28.152082600 -0400 @@ -2401,6 +2401,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, @@ -2413,6 +2414,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 @@ -2439,6 +2442,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. kpatch-0.9.10/test/integration/rhel-8.9/smp-locks-section.patch000066400000000000000000000007471474374657400242530ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/tty_buffer.c src/drivers/tty/tty_buffer.c --- src.orig/drivers/tty/tty_buffer.c 2023-05-18 13:26:13.220170896 -0400 +++ src/drivers/tty/tty_buffer.c 2023-05-18 13:27:30.347080014 -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; kpatch-0.9.10/test/integration/rhel-8.9/special-static.patch000066400000000000000000000010441474374657400235750ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2023-05-18 13:26:13.453170622 -0400 +++ src/kernel/fork.c 2023-05-18 13:27:32.559077407 -0400 @@ -1588,10 +1588,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; kpatch-0.9.10/test/integration/rhel-8.9/symvers-disagreement-FAIL.patch000066400000000000000000000027411474374657400255630ustar00rootroot00000000000000From 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 2023-05-18 13:26:12.556171679 -0400 +++ src/drivers/base/core.c 2023-05-18 13:27:34.750074826 -0400 @@ -34,6 +34,8 @@ #include "physical_location.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 2023-05-18 13:26:13.223170893 -0400 +++ src/drivers/usb/core/usb.c 2023-05-18 13:27:34.751074825 -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; kpatch-0.9.10/test/integration/rhel-8.9/syscall-LOADED.test000077500000000000000000000000471474374657400231550ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-8.9/syscall.patch000066400000000000000000000014501474374657400223430ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2023-05-18 13:26:13.458170616 -0400 +++ src/kernel/sys.c 2023-05-18 13:27:36.949072235 -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; kpatch-0.9.10/test/integration/rhel-8.9/tracepoints-section.patch000066400000000000000000000010211474374657400246600ustar00rootroot00000000000000diff -Nupr src.orig/kernel/time/timer.c src/kernel/time/timer.c --- src.orig/kernel/time/timer.c 2023-05-18 13:26:13.459170615 -0400 +++ src/kernel/time/timer.c 2023-05-18 13:27:39.140069653 -0400 @@ -1986,6 +1986,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])); kpatch-0.9.10/test/integration/rhel-8.9/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236260ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2023-05-18 13:26:12.518171724 -0400 +++ src/arch/x86/kvm/x86.c 2023-05-18 13:27:41.361067036 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rhel-9.0/000077500000000000000000000000001474374657400176405ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-9.0/data-new-LOADED.test000077500000000000000000000000641474374657400231720ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-9.0/data-new.patch000066400000000000000000000011551474374657400223630ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-9.0/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247210ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-9.0/macro-callbacks.patch000066400000000000000000000107731474374657400237070ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-9.0/module-LOADED.test000077500000000000000000000006061474374657400227610ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-9.0/module.patch000066400000000000000000000044051474374657400221510ustar00rootroot00000000000000kpatch 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); kpatch-0.9.10/test/integration/rhel-9.0/multiple.test000077500000000000000000000002451474374657400224000ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-9.0/new-function.patch000066400000000000000000000015761474374657400233060ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-9.0/new-globals.patch000066400000000000000000000021761474374657400231010ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-9.0/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242430ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-9.0/shadow-newpid.patch000066400000000000000000000046041474374657400234360ustar00rootroot00000000000000diff -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. kpatch-0.9.10/test/integration/rhel-9.0/special-static.patch000066400000000000000000000010441474374657400235650ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-9.0/symvers-disagreement-FAIL.patch000066400000000000000000000027241474374657400255540ustar00rootroot00000000000000From 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; kpatch-0.9.10/test/integration/rhel-9.0/syscall-LOADED.test000077500000000000000000000000471474374657400231450ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-9.0/syscall.patch000066400000000000000000000011631474374657400223340ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-9.0/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236160ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-9.1/000077500000000000000000000000001474374657400176415ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-9.1/data-new-LOADED.test000077500000000000000000000000641474374657400231730ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-9.1/data-new.patch000066400000000000000000000011551474374657400223640ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-9.1/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247220ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/rhel-9.1/macro-callbacks.patch000066400000000000000000000107731474374657400237100ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-9.1/module-LOADED.test000077500000000000000000000006061474374657400227620ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-9.1/module.patch000066400000000000000000000044051474374657400221520ustar00rootroot00000000000000kpatch 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); kpatch-0.9.10/test/integration/rhel-9.1/multiple.test000077500000000000000000000002451474374657400224010ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-9.1/new-function.patch000066400000000000000000000015761474374657400233070ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/rhel-9.1/new-globals.patch000066400000000000000000000021761474374657400231020ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/rhel-9.1/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242440ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-9.1/shadow-newpid.patch000066400000000000000000000046041474374657400234370ustar00rootroot00000000000000diff -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. kpatch-0.9.10/test/integration/rhel-9.1/special-static.patch000066400000000000000000000010441474374657400235660ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-9.1/symvers-disagreement-FAIL.patch000066400000000000000000000027241474374657400255550ustar00rootroot00000000000000From 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; kpatch-0.9.10/test/integration/rhel-9.1/syscall-LOADED.test000077500000000000000000000000471474374657400231460ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-9.1/syscall.patch000066400000000000000000000011631474374657400223350ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/rhel-9.1/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236170ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/rhel-9.2/000077500000000000000000000000001474374657400176425ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-9.2/data-new-LOADED.test000077500000000000000000000000641474374657400231740ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-9.2/data-new.patch000066400000000000000000000011551474374657400223650ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-04-24 14:12:17.584987707 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:12:19.026986134 -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; @@ -152,6 +154,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); kpatch-0.9.10/test/integration/rhel-9.2/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247230ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2023-04-24 14:12:18.012987240 -0400 +++ src/net/ipv6/netfilter.c 2023-04-24 14:12:31.238972810 -0400 @@ -96,6 +96,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) { @@ -109,6 +111,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) kpatch-0.9.10/test/integration/rhel-9.2/macro-callbacks.patch000066400000000000000000000107731474374657400237110ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2023-04-24 14:12:16.758988609 -0400 +++ src/drivers/input/joydev.c 2023-04-24 14:12:34.749968980 -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 2023-04-24 14:12:16.765988601 -0400 +++ src/drivers/input/misc/pcspkr.c 2023-04-24 14:12:34.750968979 -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 2023-04-24 14:12:17.529987767 -0400 +++ src/fs/aio.c 2023-04-24 14:12:34.750968979 -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 kpatch-0.9.10/test/integration/rhel-9.2/module-LOADED.test000077500000000000000000000006061474374657400227630ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-9.2/module.patch000066400000000000000000000044051474374657400221530ustar00rootroot00000000000000kpatch 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 2023-04-24 14:12:17.568987725 -0400 +++ src/fs/nfsd/export.c 2023-04-24 14:12:38.260965149 -0400 @@ -1300,6 +1300,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; @@ -1307,12 +1311,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 2023-04-24 14:12:18.032987218 -0400 +++ src/net/netlink/af_netlink.c 2023-04-24 14:12:38.261965148 -0400 @@ -2905,4 +2905,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "# kpatch\n"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-9.2/multiple.test000077500000000000000000000002451474374657400224020ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-9.2/new-function.patch000066400000000000000000000015761474374657400233100ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2023-04-24 14:12:17.443987861 -0400 +++ src/drivers/tty/n_tty.c 2023-04-24 14:12:41.744961348 -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 kpatch-0.9.10/test/integration/rhel-9.2/new-globals.patch000066400000000000000000000021761474374657400231030ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-04-24 14:12:17.583987708 -0400 +++ src/fs/proc/cmdline.c 2023-04-24 14:12:45.242957531 -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 2023-04-24 14:12:17.584987707 -0400 +++ src/fs/proc/meminfo.c 2023-04-24 14:12:45.242957531 -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); kpatch-0.9.10/test/integration/rhel-9.2/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242450ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-9.2/shadow-newpid.patch000066400000000000000000000046041474374657400234400ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2023-04-24 14:12:17.583987708 -0400 +++ src/fs/proc/array.c 2023-04-24 14:12:48.737953718 -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 2023-04-24 14:12:17.941987318 -0400 +++ src/kernel/exit.c 2023-04-24 14:12:48.738953717 -0400 @@ -732,6 +732,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 2023-04-24 14:12:17.941987318 -0400 +++ src/kernel/fork.c 2023-04-24 14:12:48.739953716 -0400 @@ -2604,6 +2604,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; @@ -2612,6 +2613,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 @@ -2651,6 +2654,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. kpatch-0.9.10/test/integration/rhel-9.2/special-static.patch000066400000000000000000000010441474374657400235670ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2023-04-24 14:12:17.941987318 -0400 +++ src/kernel/fork.c 2023-04-24 14:12:52.352949774 -0400 @@ -1679,10 +1679,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; kpatch-0.9.10/test/integration/rhel-9.2/symvers-disagreement-FAIL.patch000066400000000000000000000027411474374657400255550ustar00rootroot00000000000000From 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 2023-04-24 14:12:16.287989122 -0400 +++ src/drivers/base/core.c 2023-04-24 14:12:55.891945913 -0400 @@ -35,6 +35,8 @@ #include "physical_location.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 2023-04-24 14:12:17.457987846 -0400 +++ src/drivers/usb/core/usb.c 2023-04-24 14:12:55.892945912 -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; kpatch-0.9.10/test/integration/rhel-9.2/syscall-LOADED.test000077500000000000000000000000471474374657400231470ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-9.2/syscall.patch000066400000000000000000000011631474374657400223360ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2023-04-24 14:12:17.950987308 -0400 +++ src/kernel/sys.c 2023-04-24 14:12:59.421942062 -0400 @@ -1284,13 +1284,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; kpatch-0.9.10/test/integration/rhel-9.2/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236200ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2023-04-24 14:12:16.228989187 -0400 +++ src/arch/x86/kvm/x86.c 2023-04-24 14:13:02.912938253 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rhel-9.3/000077500000000000000000000000001474374657400176435ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-9.3/data-new-LOADED.test000077500000000000000000000000641474374657400231750ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-9.3/data-new.patch000066400000000000000000000011551474374657400223660ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2023-07-14 10:41:06.284435188 -0400 +++ src/fs/proc/meminfo.c 2023-07-14 10:41:07.271433247 -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; @@ -154,6 +156,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); kpatch-0.9.10/test/integration/rhel-9.3/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247240ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2023-07-14 10:41:06.614434539 -0400 +++ src/net/ipv6/netfilter.c 2023-07-14 10:41:15.328417401 -0400 @@ -96,6 +96,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) { @@ -109,6 +111,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) kpatch-0.9.10/test/integration/rhel-9.3/macro-callbacks.patch000066400000000000000000000107731474374657400237120ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2023-07-14 10:41:05.666436404 -0400 +++ src/drivers/input/joydev.c 2023-07-14 10:41:18.589410987 -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 2023-07-14 10:41:05.671436394 -0400 +++ src/drivers/input/misc/pcspkr.c 2023-07-14 10:41:18.590410985 -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 2023-07-14 10:41:06.243435269 -0400 +++ src/fs/aio.c 2023-07-14 10:41:18.591410983 -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 kpatch-0.9.10/test/integration/rhel-9.3/module-LOADED.test000077500000000000000000000006061474374657400227640ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-9.3/module.patch000066400000000000000000000044051474374657400221540ustar00rootroot00000000000000kpatch 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 2023-07-14 10:41:06.272435212 -0400 +++ src/fs/nfsd/export.c 2023-07-14 10:41:21.273405708 -0400 @@ -1299,6 +1299,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; @@ -1306,12 +1310,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 2023-07-14 10:41:06.629434510 -0400 +++ src/net/netlink/af_netlink.c 2023-07-14 10:41:21.273405708 -0400 @@ -2942,4 +2942,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "# kpatch\n"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-9.3/multiple.test000077500000000000000000000002451474374657400224030ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-9.3/new-function.patch000066400000000000000000000015761474374657400233110ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2023-07-14 10:41:06.178435397 -0400 +++ src/drivers/tty/n_tty.c 2023-07-14 10:41:23.942400459 -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 kpatch-0.9.10/test/integration/rhel-9.3/new-globals.patch000066400000000000000000000021761474374657400231040ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2023-07-14 10:41:06.283435190 -0400 +++ src/fs/proc/cmdline.c 2023-07-14 10:41:26.683395067 -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 2023-07-14 10:41:06.284435188 -0400 +++ src/fs/proc/meminfo.c 2023-07-14 10:41:26.683395067 -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); kpatch-0.9.10/test/integration/rhel-9.3/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242460ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-9.3/shadow-newpid.patch000066400000000000000000000046041474374657400234410ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2023-07-14 10:41:06.283435190 -0400 +++ src/fs/proc/array.c 2023-07-14 10:41:29.489389549 -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 2023-07-14 10:41:06.560434645 -0400 +++ src/kernel/exit.c 2023-07-14 10:41:29.490389546 -0400 @@ -732,6 +732,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 2023-07-14 10:41:06.560434645 -0400 +++ src/kernel/fork.c 2023-07-14 10:41:29.491389545 -0400 @@ -2601,6 +2601,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; @@ -2609,6 +2610,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 @@ -2648,6 +2651,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. kpatch-0.9.10/test/integration/rhel-9.3/special-static.patch000066400000000000000000000010441474374657400235700ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2023-07-14 10:41:06.560434645 -0400 +++ src/kernel/fork.c 2023-07-14 10:41:32.174384268 -0400 @@ -1675,10 +1675,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; kpatch-0.9.10/test/integration/rhel-9.3/symvers-disagreement-FAIL.patch000066400000000000000000000027411474374657400255560ustar00rootroot00000000000000From 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 2023-07-14 10:41:05.314437096 -0400 +++ src/drivers/base/core.c 2023-07-14 10:41:34.809379085 -0400 @@ -35,6 +35,8 @@ #include "physical_location.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 2023-07-14 10:41:06.189435375 -0400 +++ src/drivers/usb/core/usb.c 2023-07-14 10:41:34.810379083 -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; kpatch-0.9.10/test/integration/rhel-9.3/syscall-LOADED.test000077500000000000000000000000471474374657400231500ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-9.3/syscall.patch000066400000000000000000000011631474374657400223370ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2023-07-14 10:41:06.567434632 -0400 +++ src/kernel/sys.c 2023-07-14 10:41:37.436373918 -0400 @@ -1284,13 +1284,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; kpatch-0.9.10/test/integration/rhel-9.3/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236210ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2023-07-14 10:41:05.270437183 -0400 +++ src/arch/x86/kvm/x86.c 2023-07-14 10:41:40.078368722 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rhel-9.4/000077500000000000000000000000001474374657400176445ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-9.4/data-new-LOADED.test000077500000000000000000000000641474374657400231760ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-9.4/data-new.patch000066400000000000000000000012241474374657400223640ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2024-04-18 11:19:38.154638374 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 11:19:39.092636204 -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; @@ -154,6 +156,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); #ifdef CONFIG_UNACCEPTED_MEMORY show_val_kb(m, "Unaccepted: ", kpatch-0.9.10/test/integration/rhel-9.4/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247250ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2024-04-18 11:19:38.428637740 -0400 +++ src/net/ipv6/netfilter.c 2024-04-18 11:19:46.066620071 -0400 @@ -96,6 +96,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) { @@ -109,6 +111,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) kpatch-0.9.10/test/integration/rhel-9.4/macro-callbacks.patch000066400000000000000000000107731474374657400237130ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2024-04-18 11:19:37.635639575 -0400 +++ src/drivers/input/joydev.c 2024-04-18 11:19:48.560614301 -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 2024-04-18 11:19:37.639639566 -0400 +++ src/drivers/input/misc/pcspkr.c 2024-04-18 11:19:48.561614299 -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 2024-04-18 11:19:38.122638448 -0400 +++ src/fs/aio.c 2024-04-18 11:19:48.561614299 -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 kpatch-0.9.10/test/integration/rhel-9.4/module-LOADED.test000077500000000000000000000006061474374657400227650ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-9.4/module.patch000066400000000000000000000035601474374657400221560ustar00rootroot00000000000000diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c --- src.orig/fs/nfsd/export.c 2024-04-18 11:19:38.144638397 -0400 +++ src/fs/nfsd/export.c 2024-04-18 11:19:51.106608412 -0400 @@ -1342,6 +1342,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; @@ -1349,12 +1353,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 2024-04-18 11:19:38.442637708 -0400 +++ src/net/netlink/af_netlink.c 2024-04-18 11:19:51.107608409 -0400 @@ -2944,4 +2944,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "# kpatch\n"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-9.4/multiple.test000077500000000000000000000002451474374657400224040ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-9.4/new-function.patch000066400000000000000000000015761474374657400233120ustar00rootroot00000000000000diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c --- src.orig/drivers/tty/n_tty.c 2024-04-18 11:19:38.071638566 -0400 +++ src/drivers/tty/n_tty.c 2024-04-18 11:19:53.617602603 -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 kpatch-0.9.10/test/integration/rhel-9.4/new-globals.patch000066400000000000000000000021761474374657400231050ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2024-04-18 11:19:38.153638377 -0400 +++ src/fs/proc/cmdline.c 2024-04-18 11:19:56.139596769 -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 2024-04-18 11:19:38.154638374 -0400 +++ src/fs/proc/meminfo.c 2024-04-18 11:19:56.140596766 -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); kpatch-0.9.10/test/integration/rhel-9.4/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242470ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-9.4/shadow-newpid.patch000066400000000000000000000046041474374657400234420ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2024-04-18 11:19:38.153638377 -0400 +++ src/fs/proc/array.c 2024-04-18 11:19:58.692590862 -0400 @@ -403,12 +403,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 2024-04-18 11:19:38.381637849 -0400 +++ src/kernel/exit.c 2024-04-18 11:19:58.692590862 -0400 @@ -734,6 +734,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; @@ -797,6 +798,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 2024-04-18 11:19:38.381637849 -0400 +++ src/kernel/fork.c 2024-04-18 11:19:58.693590860 -0400 @@ -2639,6 +2639,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; @@ -2647,6 +2648,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 @@ -2686,6 +2689,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. kpatch-0.9.10/test/integration/rhel-9.4/special-static.patch000066400000000000000000000010441474374657400235710ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2024-04-18 11:19:38.381637849 -0400 +++ src/kernel/fork.c 2024-04-18 11:20:01.214585028 -0400 @@ -1711,10 +1711,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; kpatch-0.9.10/test/integration/rhel-9.4/syscall-LOADED.test000077500000000000000000000000471474374657400231510ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-9.4/syscall.patch000066400000000000000000000011631474374657400223400ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2024-04-18 11:19:38.387637835 -0400 +++ src/kernel/sys.c 2024-04-18 11:20:03.760579138 -0400 @@ -1284,13 +1284,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; kpatch-0.9.10/test/integration/rhel-9.4/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236220ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2024-04-18 11:19:37.300640350 -0400 +++ src/arch/x86/kvm/x86.c 2024-04-18 11:20:06.339573172 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/rhel-9.5/000077500000000000000000000000001474374657400176455ustar00rootroot00000000000000kpatch-0.9.10/test/integration/rhel-9.5/data-new-LOADED.test000077500000000000000000000000641474374657400231770ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/rhel-9.5/data-new.patch000066400000000000000000000012241474374657400223650ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c --- src.orig/fs/proc/meminfo.c 2024-10-30 13:11:05.778615433 -0400 +++ src/fs/proc/meminfo.c 2024-10-30 13:11:06.647613918 -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; @@ -168,6 +170,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); #ifdef CONFIG_UNACCEPTED_MEMORY show_val_kb(m, "Unaccepted: ", kpatch-0.9.10/test/integration/rhel-9.5/gcc-static-local-var-6.patch000066400000000000000000000012141474374657400247260ustar00rootroot00000000000000diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c --- src.orig/net/ipv6/netfilter.c 2024-10-30 13:11:06.032614990 -0400 +++ src/net/ipv6/netfilter.c 2024-10-30 13:11:15.536598418 -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) kpatch-0.9.10/test/integration/rhel-9.5/macro-callbacks.patch000066400000000000000000000107731474374657400237140ustar00rootroot00000000000000diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c --- src.orig/drivers/input/joydev.c 2024-10-30 13:11:05.315616240 -0400 +++ src/drivers/input/joydev.c 2024-10-30 13:11:17.882594327 -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 2024-10-30 13:11:05.319616233 -0400 +++ src/drivers/input/misc/pcspkr.c 2024-10-30 13:11:17.882594327 -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 2024-10-30 13:11:05.749615483 -0400 +++ src/fs/aio.c 2024-10-30 13:11:17.882594327 -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 kpatch-0.9.10/test/integration/rhel-9.5/module-LOADED.test000077500000000000000000000006061474374657400227660ustar00rootroot00000000000000#!/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" kpatch-0.9.10/test/integration/rhel-9.5/module.patch000066400000000000000000000035561474374657400221640ustar00rootroot00000000000000diff -Nupr src.orig/fs/nfsd/export.c src/fs/nfsd/export.c --- src.orig/fs/nfsd/export.c 2024-10-30 13:11:05.769615449 -0400 +++ src/fs/nfsd/export.c 2024-10-30 13:11:20.262590177 -0400 @@ -1356,6 +1356,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; @@ -1363,12 +1367,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_online_key)) + printk("kpatch: memcg_kmem_online_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 2024-10-30 13:11:06.044614969 -0400 +++ src/net/netlink/af_netlink.c 2024-10-30 13:11:20.263590176 -0400 @@ -2936,4 +2936,9 @@ panic: panic("netlink_init: Cannot allocate nl_table\n"); } +char *kpatch_string(void) +{ + return "# kpatch\n"; +} + core_initcall(netlink_proto_init); kpatch-0.9.10/test/integration/rhel-9.5/multiple.test000077500000000000000000000002451474374657400224050ustar00rootroot00000000000000#!/bin/bash SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))" declare -a blacklist=(meminfo-string-LOADED.test) source ${SCRIPTDIR}/../common/multiple.template kpatch-0.9.10/test/integration/rhel-9.5/new-globals.patch000066400000000000000000000021761474374657400231060ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c --- src.orig/fs/proc/cmdline.c 2024-10-30 13:11:05.778615433 -0400 +++ src/fs/proc/cmdline.c 2024-10-30 13:11:22.659585998 -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 2024-10-30 13:11:05.778615433 -0400 +++ src/fs/proc/meminfo.c 2024-10-30 13:11:22.659585998 -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); kpatch-0.9.10/test/integration/rhel-9.5/shadow-newpid-LOADED.test000077500000000000000000000000551474374657400242500ustar00rootroot00000000000000#!/bin/bash grep -q newpid: /proc/$$/status kpatch-0.9.10/test/integration/rhel-9.5/shadow-newpid.patch000066400000000000000000000046041474374657400234430ustar00rootroot00000000000000diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c --- src.orig/fs/proc/array.c 2024-10-30 13:11:05.778615433 -0400 +++ src/fs/proc/array.c 2024-10-30 13:11:25.054581822 -0400 @@ -403,12 +403,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 2024-10-30 13:11:05.990615064 -0400 +++ src/kernel/exit.c 2024-10-30 13:11:25.055581820 -0400 @@ -767,6 +767,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; @@ -830,6 +831,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 2024-10-30 13:11:05.990615064 -0400 +++ src/kernel/fork.c 2024-10-30 13:11:25.055581820 -0400 @@ -2721,6 +2721,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; @@ -2729,6 +2730,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 @@ -2768,6 +2771,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. kpatch-0.9.10/test/integration/rhel-9.5/special-static.patch000066400000000000000000000010441474374657400235720ustar00rootroot00000000000000diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c --- src.orig/kernel/fork.c 2024-10-30 13:11:05.990615064 -0400 +++ src/kernel/fork.c 2024-10-30 13:11:27.473577604 -0400 @@ -1790,10 +1790,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; kpatch-0.9.10/test/integration/rhel-9.5/syscall-LOADED.test000077500000000000000000000000471474374657400231520ustar00rootroot00000000000000#!/bin/bash uname -s | grep -q kpatch kpatch-0.9.10/test/integration/rhel-9.5/syscall.patch000066400000000000000000000011631474374657400223410ustar00rootroot00000000000000diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c --- src.orig/kernel/sys.c 2024-10-30 13:11:05.995615055 -0400 +++ src/kernel/sys.c 2024-10-30 13:11:29.968573254 -0400 @@ -1285,13 +1285,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; kpatch-0.9.10/test/integration/rhel-9.5/warn-detect-FAIL.patch000066400000000000000000000004671474374657400236230ustar00rootroot00000000000000diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c --- src.orig/arch/x86/kvm/x86.c 2024-10-30 13:11:04.987616812 -0400 +++ src/arch/x86/kvm/x86.c 2024-10-30 13:11:32.482568870 -0400 @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only + /* * Kernel-based Virtual Machine driver for Linux * kpatch-0.9.10/test/integration/test-vagrant000077500000000000000000000014461474374657400207540ustar00rootroot00000000000000#!/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} kpatch-0.9.10/test/integration/ubuntu-16.04/000077500000000000000000000000001474374657400203725ustar00rootroot00000000000000kpatch-0.9.10/test/integration/ubuntu-16.04/README000066400000000000000000000000211474374657400212430ustar00rootroot000000000000004.4.0-53-generic kpatch-0.9.10/test/integration/ubuntu-16.04/bug-table-section.patch000066400000000000000000000007711474374657400247240ustar00rootroot00000000000000diff -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)) kpatch-0.9.10/test/integration/ubuntu-16.04/cmdline-string-LOADED.test000077500000000000000000000000511474374657400251370ustar00rootroot00000000000000#!/bin/bash grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/ubuntu-16.04/cmdline-string.patch000066400000000000000000000006011474374657400243270ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/ubuntu-16.04/data-new-LOADED.test000077500000000000000000000000541474374657400237230ustar00rootroot00000000000000#!/bin/bash grep "kpatch: 5" /proc/meminfo kpatch-0.9.10/test/integration/ubuntu-16.04/data-new.patch000066400000000000000000000013321474374657400231120ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/ubuntu-16.04/data-read-mostly.patch000066400000000000000000000004471474374657400245670ustar00rootroot00000000000000diff -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(); } } kpatch-0.9.10/test/integration/ubuntu-16.04/fixup-section.patch000066400000000000000000000005731474374657400242150ustar00rootroot00000000000000diff --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)) kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-constprop.patch000066400000000000000000000010151474374657400241710ustar00rootroot00000000000000ensure 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; kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-isra.patch000066400000000000000000000006541474374657400231100ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-mangled-3.patch.disabled000066400000000000000000000011471474374657400254650ustar00rootroot00000000000000ensure 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); kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var-2.patch000066400000000000000000000007121474374657400254510ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var-3.patch000066400000000000000000000006651474374657400254610ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var-4.patch000066400000000000000000000010051474374657400254470ustar00rootroot00000000000000diff -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); kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var-4.test000077500000000000000000000002451474374657400253370ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var-5.patch000066400000000000000000000021571474374657400254610ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var-6.patch000066400000000000000000000011731474374657400254570ustar00rootroot00000000000000diff --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) kpatch-0.9.10/test/integration/ubuntu-16.04/gcc-static-local-var.patch000066400000000000000000000012111474374657400253050ustar00rootroot00000000000000diff -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) { kpatch-0.9.10/test/integration/ubuntu-16.04/macro-callbacks.patch000066400000000000000000000112271474374657400244340ustar00rootroot00000000000000kpatch/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 kpatch-0.9.10/test/integration/ubuntu-16.04/macro-printk.patch000066400000000000000000000107771474374657400240350ustar00rootroot00000000000000Index: 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, kpatch-0.9.10/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW-LOADED.test.disabled000077500000000000000000000001141474374657400312370ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo && grep kpatch=1 /proc/cmdline kpatch-0.9.10/test/integration/ubuntu-16.04/meminfo-cmdline-rebuild-SLOW.patch.disabled000066400000000000000000000030261474374657400304330ustar00rootroot00000000000000Disabled: 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 kpatch-0.9.10/test/integration/ubuntu-16.04/meminfo-init-FAIL.patch000066400000000000000000000006011474374657400245140ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/ubuntu-16.04/meminfo-init2-FAIL.patch000066400000000000000000000010421474374657400245760ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/ubuntu-16.04/meminfo-string-LOADED.test000077500000000000000000000000551474374657400251620ustar00rootroot00000000000000#!/bin/bash grep VMALLOCCHUNK /proc/meminfo kpatch-0.9.10/test/integration/ubuntu-16.04/meminfo-string.patch000066400000000000000000000007331474374657400243540ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/ubuntu-16.04/module-call-external.patch.disable000066400000000000000000000022221474374657400270310ustar00rootroot00000000000000Disabled: 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); kpatch-0.9.10/test/integration/ubuntu-16.04/module-kvm-fixup.patch000066400000000000000000000006711474374657400246300ustar00rootroot00000000000000diff -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; } kpatch-0.9.10/test/integration/ubuntu-16.04/multiple.test000077500000000000000000000003101474374657400231230ustar00rootroot00000000000000#!/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 kpatch-0.9.10/test/integration/ubuntu-16.04/new-function.patch000066400000000000000000000015211474374657400240260ustar00rootroot00000000000000diff -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 kpatch-0.9.10/test/integration/ubuntu-16.04/new-globals.patch000066400000000000000000000017551474374657400236350ustar00rootroot00000000000000diff -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" kpatch-0.9.10/test/integration/ubuntu-16.04/parainstructions-section.patch000066400000000000000000000006551474374657400264730ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/ubuntu-16.04/replace-section-references.patch000066400000000000000000000007461474374657400266160ustar00rootroot00000000000000diff -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) kpatch-0.9.10/test/integration/ubuntu-16.04/smp-locks-section.patch000066400000000000000000000007451474374657400247730ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/ubuntu-16.04/special-static-2.patch000066400000000000000000000012251474374657400244570ustar00rootroot00000000000000diff -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: kpatch-0.9.10/test/integration/ubuntu-16.04/special-static.patch000066400000000000000000000010351474374657400243170ustar00rootroot00000000000000diff -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; kpatch-0.9.10/test/integration/ubuntu-16.04/tracepoints-section.patch000066400000000000000000000007361474374657400254160ustar00rootroot00000000000000diff -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); } kpatch-0.9.10/test/integration/ubuntu-16.04/warn-detect-FAIL.patch000066400000000000000000000004151474374657400243410ustar00rootroot00000000000000diff -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 * kpatch-0.9.10/test/integration/vm-integration-run000077500000000000000000000034401474374657400220760ustar00rootroot00000000000000#!/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}" kpatch-0.9.10/test/test-functions.sh000066400000000000000000000003351474374657400174010ustar00rootroot00000000000000FILE=$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 } kpatch-0.9.10/test/unit/000077500000000000000000000000001474374657400150365ustar00rootroot00000000000000kpatch-0.9.10/test/unit/Makefile000066400000000000000000000007331474374657400165010ustar00rootroot00000000000000ARCHES ?= 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 kpatch-0.9.10/test/unit/Makefile.include000066400000000000000000000046701474374657400201270ustar00rootroot00000000000000EXT_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 $@ kpatch-0.9.10/test/unit/objs/000077500000000000000000000000001474374657400157735ustar00rootroot00000000000000