Compiling grsec kernel for Fedora 20

31 March 2014

Introduction

There is a lot of information online on how to roll your own kernel with the grsecurity patch. This is especially true for Gentoo or Debian. But to apply grsec to Fedora, there are some unexpected issues you might come across. The purpose of this post is to understand the classic merging problems and how to address them.

Disclaimer: By the time you read this post, the version numbers will be obsolete. There should be enough comments for you to adapt this method to any current version.

Step-by-step

First, let's install the necessary tools to build RPMS:

# yum install rpmdevtools yum-utils gcc-plugin-devel
$ rpmdev-setuptree

The last command will create a rpmbuild directory in your $HOME. If you'd rather use another path, you can put %_topdir %{getenv:HOME}/my_path in ~/.rpmmacros.

Then, we retrieve the current kernel SRPM, locally install it and install the building dependencies:

$ yumdownloader --source kernel
$ rpm -Uvh kernel-3.13.7-200.fc20.src.rpm
# yum-builddep kernel

Get the test patch from grsecurity and put it into the SOURCES directory:

$ wget http://grsecurity.net/test/grsecurity-3.0-3.13.7-201403281902.patch

and verify its signature (If it's your first time, you will have to import the signing key first):

$ gpg --verify grsecurity-3.0-3.13.7-201403281902.patch.sig 
gpg: Signature made Sat 29 Mar 2014 10:11:54 EST using RSA key ID 2525FE49
gpg: Good signature from "Bradley Spengler (spender) <spender@grsecurity.net>"

Now, let's add the grsec patch into our configuration. In the SPECS directory, modify kernel.spec. Change:

# % define buildid .local

to:

%define buildid .grsec

Before

# END OF PATCH DEFINITIONS

Add

Patch26000: grsecurity-3.0-3.13.7-201403281902.patch

Before

# END OF PATCH APPLICATIONS

Add

ApplyPatch grsecurity-3.0-3.13.7-201403281902.patch

Let's test the patching. The "bp" flag of rpmbuild is used to decompress and patch the sources:

$ rpmbuild -bp kernel.spec
[...]
Patch26000: grsecurity-3.0-3.13.7-201403281902.patch
+ case "$patch" in
+ patch -p1 -F1 -s
2 out of 4 hunks FAILED -- saving rejects to file arch/x86/kernel/ioport.c.rej
1 out of 1 hunk FAILED -- saving rejects to file arch/x86/vdso/Makefile.rej
1 out of 1 hunk FAILED -- saving rejects to file drivers/acpi/custom_method.c.rej
3 out of 3 hunks FAILED -- saving rejects to file drivers/platform/x86/asus-wmi.c.rej
1 out of 3 hunks FAILED -- saving rejects to file init/Kconfig.rej
Reversed (or previously applied) patch detected!  Assume -R? [n]

Failing at that point is completely normal. There are usually two types of failure: a patch is included inside both Fedora's default kernel and grsecurity or some functionalities are in conflict. To solve both, it is easy to find which patches is making the modification. In the SOURCES directory, use a grep on the file that failed merging, for instance:

$ grep -Rin ioport\.c .
./grsecurity-3.0-3.13.7-201403281902.patch.new:24823:diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
./grsecurity-3.0-3.13.7-201403281902.patch.new:24825:--- a/arch/x86/kernel/ioport.c
./grsecurity-3.0-3.13.7-201403281902.patch.new:24826:+++ b/arch/x86/kernel/ioport.c
./grsecurity-3.0-3.13.7-201403281902.patch:24823:diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
./grsecurity-3.0-3.13.7-201403281902.patch:24825:--- a/arch/x86/kernel/ioport.c
./grsecurity-3.0-3.13.7-201403281902.patch:24826:+++ b/arch/x86/kernel/ioport.c
./secure-modules.patch:198: arch/x86/kernel/ioport.c | 5 +++--
./secure-modules.patch:202:diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
./secure-modules.patch:204:--- a/arch/x86/kernel/ioport.c
./secure-modules.patch:205:+++ b/arch/x86/kernel/ioport.c

In this case we will remove the series of patches from Fedora regarding the UEFI Secure Boot. In kernel.spec, comment out:

# secure boot
#Patch1000: secure-modules.patch
#Patch1001: modsign-uefi.patch
#Patch1002: sb-hibernate.patch
#Patch1003: sysrq-secure-boot.patch

And

# secure boot
#ApplyPatch secure-modules.patch
#ApplyPatch modsign-uefi.patch
#ApplyPatch sb-hibernate.patch
#ApplyPatch sysrq-secure-boot.patch

Using the same procedure, you can comment out all the following patch which are already included in grsecurity:

#Patch25026: keyring-fix.patch
#Patch25031: net-fix-for-a-race-condition-in-the-inet-frag-code.patch
#Patch25041: ipv6-dont-set-DST_NOCOUNT-for-remotely-added-routes.patch
#Patch25045: netfilter-nf_conntrack_dccp-fix-skb_header_pointer-A.patch

#ApplyPatch keyring-fix.patch
#ApplyPatch net-fix-for-a-race-condition-in-the-inet-frag-code.patch
#ApplyPatch ipv6-dont-set-DST_NOCOUNT-for-remotely-added-routes.patch
#ApplyPatch netfilter-nf_conntrack_dccp-fix-skb_header_pointer-A.patch

Now some patches from Fedora may add more functionalities than grsecurity. For instance, to solve the vdso/Makefile error, it is easier to remove the grsec part (which adds compilation error in case some symbols are not resolved):

diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index fd14be1..e3c79c0 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -181,7 +181,7 @@ quiet_cmd_vdso = VDSO    $@
           -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \
     sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@'

-VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS = -fPIC -shared -Wl,--no-undefined $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
 GCOV_PROFILE := n

 #

The same applies for init/Kconfig, remove "if EXPERT" in the grsec patch:

diff --git a/init/Kconfig b/init/Kconfig
index 4e5d96a..93cd8a1 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1079,6 +1079,7 @@ endif # CGROUPS

 config CHECKPOINT_RESTORE
  bool "Checkpoint/restore support" if EXPERT
+ depends on !GRKERNSEC
  default n
  help
    Enables additional kernel features in a sake of checkpoint/restore.

By default, grsecurity patch also add a "-grsec" suffix to the kernel. This is already handled by the Fedora spec, so we can safely remove that:

diff --git a/localversion-grsec b/localversion-grsec
new file mode 100644
index 0000000..7cd6065
--- /dev/null
+++ b/localversion-grsec
@@ -0,0 +1 @@
+-grsec

If you run again the rpmbuild command the patching should now be successful. And the following error is now reached:

[...]
+ cat .newoptions
CONFIG_GRKERNSEC
+ exit 1
error: Bad exit status from /var/tmp/rpm-tmp.H6mU7j (%prep)

This means that you haven't configured the grsec options for your kernel. At this stage you should go to the BUILD directory and run a make (config|menuconfig|xconfig). Once you have made your selection, copy all the CONFIG_GRKERNSEC and CONFIG_PAX options into the file SOURCES/config-local. For instance, here is my config-local (Desktop + KVM Host).

By default, the kernel.spec will try to configure the kernel for every architecture, which causes some issues with your configuration. To avoid that, modify SPECS/kernel.spec:

# now run oldconfig over all the config files
for i in *.config

to

for i in *x86_64.config

Let's try to compile:

$ rpmbuild -bb --without debug --without debuginfo --without extra --without perf --without tools kernel.spec

We now reach the following compilation error:

drivers/input/serio/i8042.c:677:13: error: i8042_irq_being_tested causes a section type conflict with dmi_system_table
static bool i8042_irq_being_tested __initdata;

Back to kernel.spec to comment out these patches:

#Patch12016: disable-i8042-check-on-apple-mac.patch
#ApplyPatch disable-i8042-check-on-apple-mac.patch

And here is our final build:

$ rpmbuild -bb --without debug --without debuginfo --without extra --without perf --without tools kernel.spec

Time to install the generated kernel:

$ cd ~/rpmbuild/RPMS/x86_64
$ sudo yum install kernel-3.13.7-200.grsec.fc20.x86_64.rpm