syzkaller
syzkaller copied to clipboard
sys/linux: add IMA/EVM interfaces
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"
Codecov Report
Merging #1970 (8dbc698) into master (c7c2067) will decrease coverage by
0.1%. The diff coverage isn/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: |
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.
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
The descriptions themselves look good to me. Though I don't understand any of these interface.
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.
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.
How hard is it to do? What what does it involve?
- 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
- 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
- At this step it's possible to write to evm file, e.g. "echo 1 > /sys/kernel/security/integrity/evm/evm"
How hard is it to do? What what does it involve?
- 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
- 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
- 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.
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.
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.
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
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)
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).
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