# lkrg

## honeymak

http://www.openwall.com/lkrg/

will this be supported in gentoo?

 :Embarassed: 

----------

## depontius

I am interested in this also.  I took just a moment to fiddle, though I haven't verified the signature yet.  The build fails, but I don't have time a the moment to look into it.

----------

## gengreen

I'm also following this since the 0.1, I tried today the 0.2, still not working:

```
4.17.1-gentoo-gnu
```

 *Quote:*   

> [   49.996195] p_lkrg: loading out-of-tree module taints kernel.
> 
> [   49.997088] [p_lkrg] Loading LKRG...
> 
> [   50.006038] [p_lkrg] Can't initialize exploit detection features! Exiting...

 

Hopefully next release will work

----------

## pi3

Hello,

Thanks for taking a look at LKRG.

Linux kernel 4.17.xx introduced some changes which broke LKRG (and not only LKRG). I'm aware about that and currently I'm working on patch which will introduce 4.17+ support.

Breakout kernel changes in kernel 4.17.xx is this one:

https://lists.gt.net/linux/kernel/2952784

and a bit more details can be found here:

https://webcache.googleusercontent.com/search?q=cache:pFP7YaBdcc0J:https://patchwork.kernel.org/patch/10327753/+&cd=1&hl=en&ct=clnk&gl=us

In short, they've changed the exported names for syscalls and introduces a big changes from the LKRG perspective. Currently, one syscall is generating up to 4 stubs, e.g. sys_waitid and compat_sys_waitid can be now:

810f2080 T         __x64_sys_waitid     # x64 64-bit-ptregs -> C stub

810f20b0 T        __ia32_sys_waitid     # ia32 32-bit-ptregs -> C stub[*]

810f2470 T __ia32_compat_sys_waitid     # ia32 32-bit-ptregs -> compat C stub

810f2490 T  __x32_compat_sys_waitid     # x32 64-bit-ptregs -> compat C stub

Real example from my machine for sys_execve():

ffffffffa1a9b9d0 T __ia32_compat_sys_execve

ffffffffa1a9ba90 T __ia32_sys_execve

ffffffffa1a9bb30 T __x32_compat_sys_execve

ffffffffa1a9bb80 T __x64_sys_execve

Until I publish a fix, you can use LKRG for any kernel up to 4.17.

For the future reference, if you would like to know why LKRG fails initialization you can try this simple scenario:

LKRG module has a parameter p_init_log_level which defines default log_level which is going to be used during initialization. You can read more about log_level option (and in general about communication channel) here:

https://openwall.info/wiki/p_lkrg/Examples#Communication-channel

In short it might be a number between 0-4 or 0-6 (if debugging compilation was used). If LKRG fails initialization I'm suggesting to use at least

number 4 for this parameter (e.g. # insmod p_lkrg.ko p_init_log_level=4). It will give more information about the root of the problem. If debug option is enabled number 5 and 6 is also available but you need to be carefully using it to not spam the kernel with too many logs.

Thanks,

Adam

----------

## pi3

I've just pushed a patch for LKRG to support 4.17+ kernels. You can get it from the official repo:

https://bitbucket.org/Adam_pi3/lkrg-main

Your help with testing it is highly appreciated  :Smile: 

Thanks,

Adam

----------

## qjim

Current version 343153fe5ba6 failing with following errors:

…

p_struct_wrap.h:28:14: error: inlining failed in call to always_inline ‘p_module_core’: function body not available

…

p_struct_wrap.h:30:21: error: inlining failed in call to always_inline ‘p_core_text_size’: function body not available

…

Only viable solution which I found, are these 3 steps:

1) mv src/modules/wrap/p_struct_wrap.c src/modules/wrap/p_struct_wrap.h

2) sed -i -e 's:^inline:static inline:' src/modules/wrap/p_struct_wrap.h -e '/#include/d'

3) sed -i -e '/src\/modules\/wrap\/p_struct_wrap.o/d' Makefile

optionally followed by: (used just for my comfort)

4) sed -i -e 's:P_KVER =:P_KVER ?=:' Makefile                                   # Useful when I'm compiling src for NOT RUNNING kernel

5) sed -i -e '/^all:/{n;s:^#::;n;s:^:#:;n;s:^:#:;n;s:^:#:;}' Makefile    # Unmasking make with CONFIG_DEBUG_SECTION_MISMATCH=y and masking rest of "all:" section

----------

## qjim

steps 1,2,3:

```

diff -Nupr lkrg-0.4~/Makefile lkrg-0.4/Makefile

--- lkrg-0.4~/Makefile   2018-11-03 20:45:22.889400502 +0100

+++ lkrg-0.4/Makefile   2018-11-03 20:49:06.501418164 +0100

@@ -16,7 +16,6 @@ obj-m += p_lkrg.o

 p_lkrg-objs += src/modules/ksyms/p_resolve_ksym.o \

                src/modules/hashing/p_lkrg_fast_hash.o \

                src/modules/comm_channel/p_comm_channel.o \

-               src/modules/wrap/p_struct_wrap.o \

                src/modules/integrity_timer/p_integrity_timer.o \

                src/modules/kmod/p_kmod.o \

                src/modules/database/CPU.o \

diff -Nupr lkrg-0.4~/src/modules/wrap/p_struct_wrap.c lkrg-0.4/src/modules/wrap/p_struct_wrap.c

--- lkrg-0.4~/src/modules/wrap/p_struct_wrap.c   2018-01-14 21:15:47.000000000 +0100

+++ lkrg-0.4/src/modules/wrap/p_struct_wrap.c   1970-01-01 01:00:00.000000000 +0100

@@ -1,123 +0,0 @@

-/*

- * pi3's Linux kernel Runtime Guard

- *

- * Component:

- *  - Kernel's modules module wrapping access to some critical structures

- *

- * Notes:

- *  - Wrapping some of the critical structures in the system e.g.:

- *   -> k[g/u]id_t

- *   -> accesing 'struct module' structure

- *

- * Timeline:

- *  - Created: 11.IX.2017

- *

- * Author:

- *  - Adam 'pi3' Zabrocki (http://pi3.com.pl)

- *

- */

-

-#include "../../p_lkrg_main.h"

-

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)

-

-inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {

-   p_arg->val = p_val;

-}

-

-inline unsigned int p_get_uid(const kuid_t *p_from) {

-   return p_from->val;

-}

-

-inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {

-   p_arg->val = p_val;

-}

-

-inline unsigned int p_get_gid(const kgid_t *p_from) {

-   return p_from->val;

-}

-

-#else

-

-#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS

-

-inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {

-   p_arg->val = p_val;

-}

-

-inline unsigned int p_get_uid(const kuid_t *p_from) {

-   return p_from->val;

-}

-

-inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {

-   p_arg->val = p_val;

-}

-

-inline unsigned int p_get_gid(const kgid_t *p_from) {

-   return p_from->val;

-}

-

-#else

-

-inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {

-   *p_arg = p_val;

-}

-

-inline unsigned int p_get_uid(const kuid_t *p_from) {

-   return *p_from;

-}

-

-inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {

-   *p_arg = p_val;

-}

-

-inline unsigned int p_get_gid(const kgid_t *p_from) {

-   return *p_from;

-}

-

-#endif

-

-#endif

-

-

-

-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 6)

-

-

-inline void *p_module_core(struct module *p_mod) {

-   return p_mod->core_layout.base;

-}

-

-inline unsigned int p_core_size(struct module *p_mod) {

-   return p_mod->core_layout.size;

-}

-

-inline unsigned int p_core_text_size(struct module *p_mod) {

-   return p_mod->core_layout.text_size;

-}

-

-inline unsigned int p_init_text_size(struct module *p_mod) {

-   return p_mod->init_layout.text_size;

-}

-

-

-#else

-

-inline void *p_module_core(struct module *p_mod) {

-   return p_mod->module_core;

-}

-

-inline unsigned int p_init_text_size(struct module *p_mod) {

-   return p_mod->init_text_size;

-}

-

-inline unsigned int p_core_text_size(struct module *p_mod) {

-   return p_mod->core_text_size;

-}

-

-inline unsigned int p_core_size(struct module *p_mod) {

-   return p_mod->core_size;

-}

-

-

-#endif

diff -Nupr lkrg-0.4~/src/modules/wrap/p_struct_wrap.h lkrg-0.4/src/modules/wrap/p_struct_wrap.h

--- lkrg-0.4~/src/modules/wrap/p_struct_wrap.h   2018-01-14 21:15:47.000000000 +0100

+++ lkrg-0.4/src/modules/wrap/p_struct_wrap.h   2018-11-03 20:49:06.502418165 +0100

@@ -20,14 +20,40 @@

 #ifndef P_LKRG_WRAPPER_H

 #define P_LKRG_WRAPPER_H

 

-inline void p_set_uid(kuid_t *p_arg, unsigned int p_val);

-inline unsigned int p_get_uid(const kuid_t *p_from);

-inline void p_set_gid(kgid_t *p_arg, unsigned int p_val);

-inline unsigned int p_get_gid(const kgid_t *p_from);

-

-inline void *p_module_core(struct module *p_mod);

-inline unsigned int p_core_size(struct module *p_mod);

-inline unsigned int p_core_text_size(struct module *p_mod);

-inline unsigned int p_init_text_size(struct module *p_mod);

+static inline void p_set_uid(kuid_t *p_arg, unsigned int p_val) {

+   p_arg->val = p_val;

+}

+

+static inline unsigned int p_get_uid(const kuid_t *p_from) {

+   return p_from->val;

+}

+

+static inline void p_set_gid(kgid_t *p_arg, unsigned int p_val) {

+   p_arg->val = p_val;

+}

+

+static inline unsigned int p_get_gid(const kgid_t *p_from) {

+   return p_from->val;

+}

+

+

+

+static inline void *p_module_core(struct module *p_mod) {

+   return p_mod->core_layout.base;

+}

+

+static inline unsigned int p_core_size(struct module *p_mod) {

+   return p_mod->core_layout.size;

+}

+

+static inline unsigned int p_core_text_size(struct module *p_mod) {

+   return p_mod->core_layout.text_size;

+}

+

+static inline unsigned int p_init_text_size(struct module *p_mod) {

+   return p_mod->init_layout.text_size;

+}

+

+

 

 #endif

```

step 4:

```

diff -Nupr lkrg-0.4/Makefile~ lkrg-0.4/Makefile

--- lkrg-0.4/Makefile~   2018-11-03 20:04:39.187207485 +0100

+++ lkrg-0.4/Makefile   2018-11-03 20:04:45.219207961 +0100

@@ -9,7 +9,7 @@ export CFLAGS="$CFLAGS"

 

 P_OUTPUT = output

 P_PWD = $(shell pwd)

-P_KVER = $(shell uname -r)

+P_KVER ?= $(shell uname -r)

 P_KERNEL := /lib/modules/$(P_KVER)/build

 

 obj-m += p_lkrg.o

```

step 5:

```

diff -Nupr lkrg-0.4~/Makefile lkrg-0.4/Makefile

--- lkrg-0.4~/Makefile   2018-11-03 21:05:01.513493597 +0100

+++ lkrg-0.4/Makefile   2018-11-03 21:05:42.188496809 +0100

@@ -74,10 +74,10 @@ p_lkrg-objs += src/modules/ksyms/p_resol

 

 

 all:

-#   $(MAKE) -C $(P_KERNEL) M=$(P_PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y

-   $(MAKE) -C $(P_KERNEL) M=$(P_PWD) modules

-   mkdir -p $(P_OUTPUT)

-   cp $(P_PWD)/p_lkrg.ko $(P_OUTPUT)

+   $(MAKE) -C $(P_KERNEL) M=$(P_PWD) modules CONFIG_DEBUG_SECTION_MISMATCH=y

+#   $(MAKE) -C $(P_KERNEL) M=$(P_PWD) modules

+#   mkdir -p $(P_OUTPUT)

+#   cp $(P_PWD)/p_lkrg.ko $(P_OUTPUT)

 

 install:

    $(MAKE) -C $(P_KERNEL) M=$(P_PWD) modules_install

```

----------

## pi3

New version of LKRG (0.6) has been announced so you can try to verify if you have any issues with it.

https://www.openwall.com/lists/lkrg-users/2019/02/19/1

Thanks,

Adam

----------

## freke

Doesn't build for me:

```
ns ~/lkrg-0.6 # make

make -C /lib/modules/4.19.23-gentoo/build M=/root/lkrg-0.6 modules

make[1]: Entering directory '/usr/src/linux-4.19.23-gentoo'

  CC [M]  /root/lkrg-0.6/src/modules/ksyms/p_resolve_ksym.o

  CC [M]  /root/lkrg-0.6/src/modules/hashing/p_lkrg_fast_hash.o

...

...

  CC [M]  /root/lkrg-0.6/src/modules/exploit_detection/syscalls/pCFI/p_schedule/p_schedule.o

  CC [M]  /root/lkrg-0.6/src/modules/exploit_detection/p_exploit_detection.o

/root/lkrg-0.6/src/modules/exploit_detection/p_exploit_detection.c: In function ‘p_ed_enforce_pcfi’:

/root/lkrg-0.6/src/modules/exploit_detection/p_exploit_detection.c:873:23: error: storage size of ‘p_trace’ isn’t known

    struct stack_trace p_trace;

                       ^~~~~~~

/root/lkrg-0.6/src/modules/exploit_detection/p_exploit_detection.c:873:23: warning: unused variable ‘p_trace’ [-Wunused-variable]

make[2]: *** [scripts/Makefile.build:304: /root/lkrg-0.6/src/modules/exploit_detection/p_exploit_detection.o] Error 1

make[1]: *** [Makefile:1520: _module_/root/lkrg-0.6] Error 2

make[1]: Leaving directory '/usr/src/linux-4.19.23-gentoo'

make: *** [Makefile:82: all] Error 2

ns ~/lkrg-0.6 #

```

----------

## pi3

Hi,

Your kernel needs to be built with CONFIG_STACKTRACE otherwise this structure won't be visible:

https://elixir.bootlin.com/linux/latest/source/include/linux/stacktrace.h#L11

Can you confirm that you have this option? If yes can you give more details of what kernel do you have and how to repro that environment?

Thanks,

Adam

----------

## freke

Thanks - can't confirm that - I'll compile a new kernel when gcc8.3.0 is done - thanks  :Wink: 

--

Builds fine with CONFIG_STACKTRACE enabled  :Smile: 

----------

## depontius

I've been following this with some interest, and yesterday I successfully compiled it against my kernel.  However I have a bit of a problem, in that I require module signatures and throw away the key as part of my kernel build script, so no module not built with the kernel can ever be loaded.  In other words, I have to incorporate lkrg into my kernel build script and sign it before throwing away the key.

Just to double-check, I presume people on this thread are using lkrg now?  Any comments on its operation?

----------

## pi3

Hi,

It depends on the configuration and if your kernel supports and/or enforces module signature. Gentoo has pretty good wiki describing this topic here:

https://wiki.gentoo.org/wiki/Signed_kernel_module_support

About LKRG itself, I've recently fixed a very rare glitching problem in pCFI (it's a completely new feature where I didn't propagate a similar fix done a few releases ago in Exploit-Detection). I would strongly recommend LKRG code-base from the official bitbucket repo here:

https://bitbucket.org/Adam_pi3/lkrg-main

Thanks,

Adam

----------

## depontius

First, p_lkrg defines the symbol "hide_module", and as such, gives a false positive for the XOR DDos rootkit when checking with rkhunter.  I haven't yet looked to see if that can be bypassed, just notifying here.

Second, I got around the module signature by tweaking my kernel build script.  Now I build the kernel, then before throwing away the signing key, I build p_lkrt and sign it, too.  THEN I throw away the keys.  I've got lkrg running on one of my systems.  I've tried on a second, updated the kernel config, and it starts to load, then hangs.  I haven't gotten around to doing the diagnostic work yet to see what's wrong.

----------

## pi3

 *depontius wrote:*   

> First, p_lkrg defines the symbol "hide_module", and as such, gives a false positive for the XOR DDos rootkit when checking with rkhunter.  I haven't yet looked to see if that can be bypassed, just notifying here.

 

LKRG has functionality of hiding itself. It's part of a weak self-defense which will be extended in the future. If rkhunter classifies XOR DDos purely by fuzzy-matching exported symbols, the easiest way to bypass it is to change that names. This apply to the rookit itself too  :Wink: 

 *depontius wrote:*   

> Second, I got around the module signature by tweaking my kernel build script.  Now I build the kernel, then before throwing away the signing key, I build p_lkrt and sign it, too.  THEN I throw away the keys.

 

There is also a possibility of not using signed modules and then you can build and load any module without that security feature. If you do just some test it might be easier option for you.

 *depontius wrote:*   

> I've got lkrg running on one of my systems.  I've tried on a second, updated the kernel config, and it starts to load, then hangs.  I haven't gotten around to doing the diagnostic work yet to see what's wrong.

 

LKRG module has a parameter p_init_log_level which defines default log_level which is going to be used during initialization. You can read more about log_level option (and in general about communication channel) here: 

https://openwall.info/wiki/p_lkrg/Examples#Communication-channel

In short it might be a number between 0-4 or 0-6 (if debugging compilation was used). If LKRG fails initialization I'm suggesting to use at least number 4 for this parameter (e.g. # insmod p_lkrg.ko p_init_log_level=4). It will give more information about the root of the problem. If debug option is enabled number 5 and 6 is also available but you need to be carefully using it to not spam the kernel with too many logs.

----------

## pi3

Just wanted to give an updated that new LKRG was released (0.7) which includes tons of improvement. Among other there is also experimental support for ARM64 CPUs (AArch64). Full announcement can be read here:

https://www.openwall.com/lists/announce/2019/07/21/1

Additionally, latest bitbucket version of LKRG (https://bitbucket.org/Adam_pi3/lkrg-main) includes extra hardening for SMEP enforcement on each individual CPU-core (on x86/amd64 CPUs).

I'll be happy to hear any feedback and I encourage you to test.

Thanks,

Adam

----------

## depontius

I'd just like to add that 0.6 quit building somewhere during the 5.1 series, but 0.7 has been building cleanly against the 5.2 series, so far.

Thank you

----------

## pi3

It might be worth to mention that LKRG can save you by preventing and detecting Felix’s container escape (based on UMH). More information can be read here:

http://blog.pi3.com.pl/?p=663

Thanks,

Adam

----------

