syzkaller icon indicating copy to clipboard operation
syzkaller copied to clipboard

sys/linux: add IMA/EVM interfaces

Open evdenis opened this issue 5 years ago • 14 comments

It's better to disable syscall write$evm. An attempt to write to "/sys/kernel/security/integrity/evm/evm" without additional vm setup highly likely will result in "lost connection to test machine" error due to -ENOKEY error. Recommended boot args for fuzzing: "ima_appraise=fix evm=fix"

evdenis avatar Jul 24 '20 17:07 evdenis

Codecov Report

Merging #1970 (8dbc698) into master (c7c2067) will decrease coverage by 0.1%. The diff coverage is n/a.

Impacted Files Coverage Δ
pkg/csource/csource.go 74.1% <0.0%> (-6.0%) :arrow_down:
prog/mutation.go 87.1% <0.0%> (-2.1%) :arrow_down:
prog/any.go 84.5% <0.0%> (ø)
prog/rand.go 90.7% <0.0%> (+0.4%) :arrow_up:
prog/rotation.go 96.6% <0.0%> (+1.7%) :arrow_up:

codecov[bot] avatar Jul 24 '20 18:07 codecov[bot]

An attempt to write to "/sys/kernel/security/integrity/evm/evm" without additional vm setup highly likely will result in "lost connection to test machine" error due to -ENOKEY error.

Will ENOKEY be returned for all subsequent filesystem operations? Or why will it result in "lost connection"?

What is the additional VM setup? Is it these "ima_appraise=fix evm=fix"? If it provokes "lost connection" by default all the time, it's not very good for syzbot and all other users out there. We try to make the default behavior without "special tuning by an expert required" sane. It won't scale for 1000 of kernel subsystems, nobody is an expert in 1000 kernel subsystems.

dvyukov avatar Jul 25 '20 07:07 dvyukov

Recommended boot args for fuzzing: "ima_appraise=fix evm=fix"

If it's recommended for all setups, please add it to: tools/create-gce-image.sh tools/create-image.sh

If it's "weakly recommended", but it not really necessary, then add it to (for syzbot): dashboard/config/upstream-*.cmdline

dvyukov avatar Jul 25 '20 07:07 dvyukov

The descriptions themselves look good to me. Though I don't understand any of these interface.

dvyukov avatar Jul 25 '20 07:07 dvyukov

Will ENOKEY be returned for all subsequent filesystem operations? Or why will it result in "lost connection"?

Yes, for all subsequent "write" filesystem operations.

What is the additional VM setup? Is it these "ima_appraise=fix evm=fix"?

No, one needs to generate and load crypto keys. Will it be better to just comment line?

# write$evm(fd fd_evm, buf ptr[in, fmt[dec, flags[evm_flags]]], count len[buf])

If it's "weakly recommended", but it not really necessary, then add it to (for syzbot): dashboard/config/upstream-*.cmdline

By default IMA/EVM is starting in off mode. Switching them to fix modes should cover mode kernel operations like checksum computations for files/metadata, xattr updates etc.

evdenis avatar Jul 25 '20 09:07 evdenis

No, one needs to generate and load crypto keys.

How hard is it to do? What what does it involve?

Will it be better to just comment line?

I think we need to disable the open call, otherwise syzkaller will find gazillion other ways of how to write to it. It can now be done by adding (disabled) attribute to open and write, this way they are still parsed and checked for correctness.

dvyukov avatar Jul 25 '20 09:07 dvyukov

How hard is it to do? What what does it involve?

  1. Generate keys in create-image.sh
$ dd if=/dev/urandom bs=1 count=32 status=none | keyctl padd user kmk-user @u
$ keyctl pipe `keyctl search @u user kmk-user` > /etc/keys/kmk-user.blob
$ keyctl add encrypted evm-key "new user:kmk-user 32" @u
$ keyctl pipe `keyctl search @u encrypted evm-key` > /etc/keys/evm-user.blob
  1. Update init scripts to load keys during boot with commands like:
keyctl show | grep -q kmk-user || keyctl add user kmk-user "`cat /etc/keys/kmk-user.blob`" @u > /dev/null
keyctl add encrypted evm-key "load `cat /etc/keys/evm-user.blob`" @u > /dev/null
ima_id=`keyctl newring _ima @u` && /usr/bin/evmctl import --rsa /etc/keys/rsa_public.pem $ima_id > /dev/null
evm_id=`keyctl newring _evm @u` && /usr/bin/evmctl import --rsa /etc/keys/rsa_public.pem $evm_id > /dev/null
  1. At this step it's possible to write to evm file, e.g. "echo 1 > /sys/kernel/security/integrity/evm/evm"

evdenis avatar Jul 25 '20 10:07 evdenis

How hard is it to do? What what does it involve?

  1. Generate keys in create-image.sh
$ dd if=/dev/urandom bs=1 count=32 status=none | keyctl padd user kmk-user @u
$ keyctl pipe `keyctl search @u user kmk-user` > /etc/keys/kmk-user.blob
$ keyctl add encrypted evm-key "new user:kmk-user 32" @u
$ keyctl pipe `keyctl search @u encrypted evm-key` > /etc/keys/evm-user.blob
  1. Update init scripts to load keys during boot with commands like:
keyctl show | grep -q kmk-user || keyctl add user kmk-user "`cat /etc/keys/kmk-user.blob`" @u > /dev/null
keyctl add encrypted evm-key "load `cat /etc/keys/evm-user.blob`" @u > /dev/null
ima_id=`keyctl newring _ima @u` && /usr/bin/evmctl import --rsa /etc/keys/rsa_public.pem $ima_id > /dev/null
evm_id=`keyctl newring _evm @u` && /usr/bin/evmctl import --rsa /etc/keys/rsa_public.pem $evm_id > /dev/null
  1. At this step it's possible to write to evm file, e.g. "echo 1 > /sys/kernel/security/integrity/evm/evm"

Thanks! Let's wait for @ebiggers, I think it's close to his area of expertise.

dvyukov avatar Jul 25 '20 10:07 dvyukov

Let's wait for @ebiggers, I think it's close to his area of expertise.

Not that close. I don't work on IMA or EVM.

ebiggers avatar Jul 27 '20 16:07 ebiggers

Let's wait for @ebiggers, I think it's close to his area of expertise.

Not that close. I don't work on IMA or EVM.

Ack. Thanks for the review.

I started reading: https://sourceforge.net/p/linux-ima/wiki/Home/ which seems to be the description of the setup needed. But I feel it will take me days to grasp it all, figure out the details and test changes needed to deploy this on syzbot. I filed #1977 for now.

Denis, is it possible to understand if writing to the file will cause all writes to fail or not (is the key has been setup or not)? If yes, then I think the best solution is to detect presence of the key here: https://github.com/google/syzkaller/blob/cb93dc6ac64225e09f44bac6c6cce1dae1b248b0/pkg/host/syscalls_linux.go#L24 where we check if we should enable/disable particular syscalls. Then we can leave it enabled and it will automatically work on any machines where they key is setup.

dvyukov avatar Jul 27 '20 16:07 dvyukov

How to reproduce ENOKEY error:

root@syzkaller:~# echo 2 > /sys/kernel/security/integrity/evm/evm
root@syzkaller:~# touch test.txt # should be new file
[  526.976855][ T5771] evm: HMAC key is not set
[  526.977892][ T5771] evm: init_desc failed
touch: cannot touch 'test.txt': Required key not available

evdenis avatar Jul 27 '20 22:07 evdenis

Denis, is it possible to understand if writing to the file will cause all writes to fail or not (is the key has been setup or not)? If yes, then I think the best solution is to detect presence of the key here: https://github.com/google/syzkaller/blob/cb93dc6ac64225e09f44bac6c6cce1dae1b248b0/pkg/host/syscalls_linux.go#L24 where we check if we should enable/disable particular syscalls. Then we can leave it enabled and it will automatically work on any machines where they key is setup.

I think we can check /proc/keys:

$ cat /proc/keys | grep evm
007c6d0c I--Q---     1 perm 3f010000     0     0 encrypted evm-key: 139
206619df I------     1 perm 1f0f0000     0     0 keyring   .evm: empty

String "encrypted evm-key" to detect the presence of hmac key which is requested in evm_init_key (https://github.com/torvalds/linux/blob/92ed301919932f777713b9172e525674157e983d/security/integrity/evm/evm_crypto.c#L357)

evdenis avatar Jul 27 '20 22:07 evdenis

How to reproduce ENOKEY error:

root@syzkaller:~# echo 2 > /sys/kernel/security/integrity/evm/evm
root@syzkaller:~# touch test.txt # should be new file
[  526.976855][ T5771] evm: HMAC key is not set
[  526.977892][ T5771] evm: init_desc failed
touch: cannot touch 'test.txt': Required key not available

2 is for "Enable digital signature validation" according to Documentation/ABI/testing/evm and I think that kernel should not accept the value without checking that hmac and digsig keys are loaded (pretty much as with 1).

evdenis avatar Jul 27 '20 23:07 evdenis

To check that at least one digsig key loaded to _evm keyring during boot we can check:

$ evm_id=`keyctl newring _evm @u`
$ evmctl import /etc/keys/pubkey_ima.pem $evm_id
$ cat /proc/keys | grep keyring | grep _evm
1e8e1965 I--Q---     1 perm 3f010000     0     0 keyring   _evm: 1

# no keys
$ keyctl newring _test @u
$ cat /proc/keys | grep keyring | grep _test
0a9b9f6a I--Q---     1 perm 3f010000     0     0 keyring   _test: empty

evmctl uses add_key syscall:

# keyring creation
add_key("keyring", "_test1", NULL, 0, KEY_SPEC_USER_KEYRING) = 458492488

# key import
openat(AT_FDCWD, "/etc/keys/pubkey_evm.pem", O_RDONLY) = 3
futex(0x7fdbfafee6c4, FUTEX_WAKE_PRIVATE, 2147483647) = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=272, ...}) = 0
read(3, "-----BEGIN PUBLIC KEY-----\nMIGfM"..., 4096) = 272
futex(0x7fdbfafee65c, FUTEX_WAKE_PRIVATE, 2147483647) = 0
close(3)                                = 0
add_key("user", "\4ZR0\376\177", "\1\0\0\0\0\0\2\4\0\276b\216\270|\233\366\4\247\275e\230rq\324,\32\347;T\220V\251"..., 142, 177971050) = 327167649

evdenis avatar Jul 27 '20 23:07 evdenis