neděle 22. října 2017

How to recompile Fedora kernel with the custom patch

I has been asked how to recompile Fedora kernel with the custom patch, so here is the tutorial:

At first install the needed packages:

# dnf install fedpkg dnf-plugins-core

Install build requirements for the kernel package:

# dnf builddep kernel

Clone the kernel dist-git module for the desired Fedora version, i.e. if you want to recompile the kernel for the Fedora 26, add the '-b f26' or respective version (--anonymous is used for the anonymous checkout, i.e. read only checkout):

$ fedpkg co --anonymous -b f26 kernel

Change the working directory to the cloned dist-git module:

$ cd kernel

Copy the desired patch (e.g. my.patch) to the working directory:

$ cp DIR/my.patch .

Make sure your my.patch has been generated by the 'git format-patch' if not, you need to manually add the header containing lines From:, Subject:, so proceed the following step just only if such header is not presented in your patch (of course edit the strings as needed):

$ echo "From: Joe Hacker <joe.hacker@hacker.org>" > header
$ echo "Subject: My patch" >> header
$ echo >> header
$ cat header my.patch > patch
$ mv patch my.patch

Edit the kernel.spec, locate the string '# END OF PATCH DEFINITIONS', and add the following string just before it:

Patch9999: my.patch

where make sure that the number 9999 is not used by any previous Patch keyword. If it's already used, keep increasing the number until you will find the highest unused number and use it with your patch. Save the spec file.

Recompile the kernel:

$ fedpkg local

Install/re-install the newly builds kernel RPMs from the ARCH directory, i.e. if you compiled the kernel for the x86_64, the ARCH directory is x86_64.

Reverted patch

In case you have upstream kernel patch you need to revert (let's say upstream.patch, do the previous steps up-to the installation of the my.patch, then unpack the kernel sources:

$ fedpkg prep

Make the reverted patch of the upstream.patch (replace the DIR in commands below by directory where you store your patches):

$ pushd kernel-*/linux-*
$ git commit -am Flush
$ cp DIR/upstream.patch .
$ patch -p1 -R < upstream.patch
$ git commit -am "Upstream reverted patch"
$ git format-patch --stdout HEAD~1 > DIR/upstream-reverted.patch
$ popd

Then install the upstream-reverted.patch instead of the my.patch and proceed with the compilation as described above.

23 komentářů:

  1. Thanks for writing this! First, typo on the word "bellow". Then my question is from this step:
    "patch -p1 -R my-patch.patch"
    I'm not clear on what "my-patch.patch" should be if I'm just reverting a committed patch. In this instance we are referring to https://marc.info/?l=linux-kernel&m=150703479427738&w=2.

    I believe the contents of "my-patch-reverted.patch" should just be:
    ---
    fs/cifs/smb2pdu.c | 17 ++++++++++++-----
    1 file changed, 12 insertions(+), 5 deletions(-)

    --- a/fs/cifs/smb2pdu.c
    +++ b/fs/cifs/smb2pdu.c
    @@ -644,15 +644,22 @@ int smb3_validate_negotiate(const unsign

    /*
    * validation ioctl must be signed, so no point sending this if we
    - * can not sign it. We could eventually change this to selectively
    + * can not sign it (ie are not known user). Even if signing is not
    + * required (enabled but not negotiated), in those cases we selectively
    * sign just this, the first and only signed request on a connection.
    - * This is good enough for now since a user who wants better security
    - * would also enable signing on the mount. Having validation of
    - * negotiate info for signed connections helps reduce attack vectors
    + * Having validation of negotiate info helps reduce attack vectors.
    */
    - if (tcon->ses->server->sign == false)
    + if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
    return 0; /* validation requires signing */

    + if (tcon->ses->user_name == NULL) {
    + cifs_dbg(FYI, "Can't validate negotiate: null user mount\n");
    + return 0; /* validation requires signing */
    + }
    +
    + if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
    + cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
    +
    vneg_inbuf.Capabilities =
    cpu_to_le32(tcon->ses->server->vals->req_capabilities);
    memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid,

    So is there an extra step here? I guess my question really is, with regards to this patch, what should the contents of "my-patch.patch" be?

    OdpovědětVymazat
    Odpovědi
    1. Regarding 'bellow' - damn google :)

      I updated the text, hope it's more clear now.
      What you posted above is upstream.patch, do upstream-reverted.patch from it and proceed.

      Vymazat
    2. I.e. regarding the bugzilla, it's the patch what introduced the problem, so you need to revert it.

      Vymazat
    3. Ah right I have to create the reverted patch.

      However when I run the patch -p1 -R upstream.patch it just "hangs" and does nothing and I have to ctl-c.

      Can I just manually change the file /kernel/kernel-4.13.fc26/linux-4.13.9-200.fc26.x86_64/smb2pdu.c and undo the changes from the patch and run 'fedpkg local'?

      Unfortunately I'm getting this error: "+ /usr/lib/rpm/debugedit -b /root/kernel -d /usr/src/debug -i arch/x86/entry/vdso/vdso64.so.dbg
      Dest dir longer than base dir is not supported
      + /usr/lib/rpm/debugedit -b /root/kernel -d /usr/src/"

      Vymazat
    4. Again typo, it should be:
      patch -p1 -R < upstream.patch

      Of course, you can create the inverted version manually, IMHO just i.e. replace +/-

      Regarding the error maybe you are too deep in the directory structure, try to do it e.g. directly under the /var/tmp directory.

      Vymazat
  2. I'm doing it under /root. Does 'fedpkg local' need to be run in the /root/kernel directory?

    OdpovědětVymazat
  3. Hm stil errors with "RPM build errors:
    Could not execute local: rpmbuild --define '_sourcedir /root/kernel' --define '_specdir /root/kernel' --define '_builddir /root/kernel' --define '_srcrpmdir /root/kernel' --define '_rpmdir /root/kernel' --define 'dist .fc26' --define 'fedora 26' --eval '%undefine rhel' --define 'fc26 1' -ba /root/kernel/kernel.spec | tee .build-4.13.9-200.fc26.log"

    OdpovědětVymazat
    Odpovědi
    1. Hmm, does you patch cleanly apply?

      Try:
      $ fedpkg prep
      And see whether it cleanly applies.

      Vymazat
    2. It exits with a 0. I wanted to try to just patch the file manually. I skipped the patch command steps.

      Vymazat
    3. Could you post the whole log somewhere? Do you have rpmbuild installed (package rpmb-build)?

      Vymazat
  4. Yep: Package rpm-build-4.13.0.1-7.fc26.x86_64 is already installed, skipping. See https://pastebin.com/DP2rhz0b for the fedpkg prep results

    OdpovědětVymazat
    Odpovědi
    1. Are you able to recompile the kernel without patching? Could you post the whole 'fedpkg local' output?

      Vymazat
    2. See https://pastebin.com/QCz3UFE3 it errors with:
      + /usr/lib/rpm/debugedit -b /root/kernel -d /usr/src/debug -i arch/x86/entry/vdso/vdso64.so.dbg
      Dest dir longer than base dir is not supported
      + /usr/lib/rpm/debugedit -b /root/kernel -d /usr/src/debug -i arch/x86/entry/vdso/vdso32.so.dbg
      Dest dir longer than base dir is not supported

      Vymazat
    3. It seems like error from the debugedit utility, I have never encountered it :)

      Are you building it under root? If yes, please retry as regular user.

      In case of building a package through rpmbuild, define _topdir in ~/.rpmmacros to something longer than /usr/src/debug, e.g.:

      %_topdir %(echo $HOME)/rpmbuild_usr_src_debug

      There is KB article about it:
      https://access.redhat.com/solutions/1426113

      Vymazat
    4. I guess it should be fixed in f27 and should work there without workarounds, if not feel free to reopen:
      https://bugzilla.redhat.com/show_bug.cgi?id=757089

      Vymazat
    5. Interesting there was not .rpmmacros files so I created it with the contents you wrote.

      It looks like it's getting further but it's hanging at this:
      Success: decoded and checked 2582275 instructions
      arch/x86/tools/insn_sanity: Success: decoded and checked 1000000 random instructions with 0 errors (seed:0xfd0ef663)
      + make -s ARCH=x86_64 V=1 -j4 modules

      Vymazat
    6. I cannot see any error here. The modules compilation make take some time. Also you may try setting environment variables MAKEOPTS to -j1 by:
      export MAKEOPTS=-j1
      The compilation will take cca. 2-3 times longer, but it will consume less resources.

      Vymazat
    7. I retried all the instructions above on the cleanly provisioned Fedora 26 machine, including addition of the reverted SMB patch, so far, so good. If it goes OK, I will provide you the packages cca. 3 hours later.

      Vymazat
    8. I tried again with the MAKEOPTS env variable but fedpkg local just hangs at Success: decoded and checked 2582275 instructions
      arch/x86/tools/insn_sanity: Success: decoded and checked 1000000 random instructions with 0 errors (seed:0x5d5a6a5c)
      + make -s ARCH=x86_64 V=1 -j4 modules

      Vymazat
    9. Are you sure it hung? The distribution kernel compilation takes a lot of time (cca. 3+ hours and is silent most the time). You can check with the 'top' command whether it's utilizing CPU.

      I successfully compiled it on the cleanly provisioned machine according to above instructions (after cca. 3 hours). I had to re-run the compilation, because my first attempt failed on (no space left on the device :), i.e. it requires cca 18GB free disk space for the compilation :)

      I also did scratch build on the koji for you:
      https://koji.fedoraproject.org/koji/taskinfo?taskID=22687386

      You should be able to download the RPMs for your architecture (the i686 was still building in time of writing this). FYI the scratch build is automatically deleted after cca. 3 days.

      Vymazat
    10. Yes it seems my screensaver did indeed cause the ssh session which was in progress with the kernel compilation, to time out. I'm trying it again.

      I see your RPMs. Can you clarify for me the best way to install those? It it with rpm -ivh as indicated at https://fedoraproject.org/wiki/Building_a_custom_kernel/Source_RPM? Also, is there a way to check which RPMs are required to install?

      I got these warnings from your RPM:
      warning: user mockbuild does not exist - using root
      warning: group mockbuild does not exist - using root

      Vymazat
    11. Check which kernel packages you have installed by 'rpm -q NAME' for name for all packages from the build and then reinstall them by rpm -i

      Vymazat
  5. I was able to create the kernel RPMs. They installed and rebooted just fine. However I believe our issue is slightly different. It's not a Windows 10 host. It's a Drobo backup unit. So even though we specify version 1 for SMB we are still getting this error with autofs: kernel: No dialect specified on mount. Default has changed to a more secure dialect, SMB2.1 or later (e.g. SMB3), from CIFS (SMB1). To use the less secure SMB1 dialect to access old servers which do not support SMB3 (or SMB2.1) specify vers=1.0 on mount.
    Oct 31 09:48:45 me kernel: CIFS VFS: cifs_mount failed w/return code = -112

    OdpovědětVymazat