From e59644b720aed4b9ec9d3818b483f97376fb31ed Mon Sep 17 00:00:00 2001 From: Sargun Dhillon Date: Sun, 1 Apr 2018 08:42:08 +0000 Subject: [PATCH 1/8] security: remove security_settime security_settime was a wrapper around security_settime64. There are no more users of it. Therefore it can be removed. It was removed in: commit 4eb1bca17933 ("time: Use do_settimeofday64() internally") Signed-off-by: Sargun Dhillon Signed-off-by: James Morris --- include/linux/security.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index 3f5fd988ee87..5111fe8159ce 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -222,12 +222,6 @@ int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); int security_settime64(const struct timespec64 *ts, const struct timezone *tz); -static inline int security_settime(const struct timespec *ts, const struct timezone *tz) -{ - struct timespec64 ts64 = timespec_to_timespec64(*ts); - - return security_settime64(&ts64, tz); -} int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm); @@ -509,14 +503,6 @@ static inline int security_settime64(const struct timespec64 *ts, return cap_settime(ts, tz); } -static inline int security_settime(const struct timespec *ts, - const struct timezone *tz) -{ - struct timespec64 ts64 = timespec_to_timespec64(*ts); - - return cap_settime(&ts64, tz); -} - static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages)); From aae7cfcbb733cf16f3bc9cbb650673b94d5df75f Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 4 May 2018 16:28:19 +0200 Subject: [PATCH 2/8] security: add hook for socketpair() Right now the LSM labels for socketpairs are always uninitialized, since there is no security hook for the socketpair() syscall. This patch adds the required hooks so LSMs can properly label socketpairs. This allows SO_PEERSEC to return useful information on those sockets. Note that the behavior of socketpair() can be emulated by creating a listener socket, connecting to it, and then discarding the initial listener socket. With this workaround, SO_PEERSEC would return the caller's security context. However, with socketpair(), the uninitialized context is returned unconditionally. This is unexpected and makes socketpair() less useful in situations where the security context is crucial to the application. With the new socketpair-hook this disparity can be solved by making socketpair() return the expected security context. Acked-by: Serge Hallyn Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann Signed-off-by: James Morris --- include/linux/lsm_hooks.h | 7 +++++++ include/linux/security.h | 7 +++++++ security/security.c | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9d0b286f3dba..8f1131c8dd54 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -757,6 +757,11 @@ * @type contains the requested communications type. * @protocol contains the requested protocol. * @kern set to 1 if a kernel socket. + * @socket_socketpair: + * Check permissions before creating a fresh pair of sockets. + * @socka contains the first socket structure. + * @sockb contains the second socket structure. + * Return 0 if permission is granted and the connection was established. * @socket_bind: * Check permission before socket protocol layer bind operation is * performed and the socket @sock is bound to the address specified in the @@ -1656,6 +1661,7 @@ union security_list_options { int (*socket_create)(int family, int type, int protocol, int kern); int (*socket_post_create)(struct socket *sock, int family, int type, int protocol, int kern); + int (*socket_socketpair)(struct socket *socka, struct socket *sockb); int (*socket_bind)(struct socket *sock, struct sockaddr *address, int addrlen); int (*socket_connect)(struct socket *sock, struct sockaddr *address, @@ -1922,6 +1928,7 @@ struct security_hook_heads { struct hlist_head unix_may_send; struct hlist_head socket_create; struct hlist_head socket_post_create; + struct hlist_head socket_socketpair; struct hlist_head socket_bind; struct hlist_head socket_connect; struct hlist_head socket_listen; diff --git a/include/linux/security.h b/include/linux/security.h index ecb06e1357dd..63030c85ee19 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1177,6 +1177,7 @@ int security_unix_may_send(struct socket *sock, struct socket *other); int security_socket_create(int family, int type, int protocol, int kern); int security_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern); +int security_socket_socketpair(struct socket *socka, struct socket *sockb); int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen); int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen); int security_socket_listen(struct socket *sock, int backlog); @@ -1248,6 +1249,12 @@ static inline int security_socket_post_create(struct socket *sock, return 0; } +static inline int security_socket_socketpair(struct socket *socka, + struct socket *sockb) +{ + return 0; +} + static inline int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) diff --git a/security/security.c b/security/security.c index 7bc2fde023a7..68f46d849abe 100644 --- a/security/security.c +++ b/security/security.c @@ -1358,6 +1358,12 @@ int security_socket_post_create(struct socket *sock, int family, protocol, kern); } +int security_socket_socketpair(struct socket *socka, struct socket *sockb) +{ + return call_int_hook(socket_socketpair, 0, socka, sockb); +} +EXPORT_SYMBOL(security_socket_socketpair); + int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { return call_int_hook(socket_bind, 0, sock, address, addrlen); From d47cd9450d3b1fcf6ce7c7022f442a69a7b7322e Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 4 May 2018 16:28:20 +0200 Subject: [PATCH 3/8] net: hook socketpair() into LSM Use the newly created LSM-hook for socketpair(). The default hook return-value is 0, so behavior stays the same unless LSMs start using this hook. Acked-by: Serge Hallyn Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann Acked-by: David S. Miller Signed-off-by: James Morris --- net/socket.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/socket.c b/net/socket.c index f10f1d947c78..667a7b397134 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1420,6 +1420,13 @@ int __sys_socketpair(int family, int type, int protocol, int __user *usockvec) goto out; } + err = security_socket_socketpair(sock1, sock2); + if (unlikely(err)) { + sock_release(sock2); + sock_release(sock1); + goto out; + } + err = sock1->ops->socketpair(sock1, sock2); if (unlikely(err < 0)) { sock_release(sock2); From 0b811db2cb2aabc910e53d34ebb95a15997c33e7 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 4 May 2018 16:28:21 +0200 Subject: [PATCH 4/8] selinux: provide socketpair callback Make sure to implement the new socketpair callback so the SO_PEERSEC call on socketpair(2)s will return correct information. Acked-by: Serge Hallyn Acked-by: Stephen Smalley Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann Signed-off-by: James Morris --- security/selinux/hooks.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4cafe6a19167..02ebd1585eaf 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4569,6 +4569,18 @@ static int selinux_socket_post_create(struct socket *sock, int family, return err; } +static int selinux_socket_socketpair(struct socket *socka, + struct socket *sockb) +{ + struct sk_security_struct *sksec_a = socka->sk->sk_security; + struct sk_security_struct *sksec_b = sockb->sk->sk_security; + + sksec_a->peer_sid = sksec_b->sid; + sksec_b->peer_sid = sksec_a->sid; + + return 0; +} + /* Range of port numbers used to automatically bind. Need to determine whether we should perform a name_bind permission check between the socket and the port number. */ @@ -6999,6 +7011,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(socket_create, selinux_socket_create), LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create), + LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair), LSM_HOOK_INIT(socket_bind, selinux_socket_bind), LSM_HOOK_INIT(socket_connect, selinux_socket_connect), LSM_HOOK_INIT(socket_listen, selinux_socket_listen), From 5859cdf55063943192f316b3d6c673fd6fcbee46 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Fri, 4 May 2018 16:28:22 +0200 Subject: [PATCH 5/8] smack: provide socketpair callback Make sure to implement the new socketpair callback so the SO_PEERSEC call on socketpair(2)s will return correct information. Signed-off-by: Tom Gundersen Signed-off-by: David Herrmann Signed-off-by: James Morris --- security/smack/smack_lsm.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 0b414836bebd..dcb976f98df2 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2842,6 +2842,27 @@ static int smack_socket_post_create(struct socket *sock, int family, return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); } +/** + * smack_socket_socketpair - create socket pair + * @socka: one socket + * @sockb: another socket + * + * Cross reference the peer labels for SO_PEERSEC + * + * Returns 0 on success, and error code otherwise + */ +static int smack_socket_socketpair(struct socket *socka, + struct socket *sockb) +{ + struct socket_smack *asp = socka->sk->sk_security; + struct socket_smack *bsp = sockb->sk->sk_security; + + asp->smk_packet = bsp->smk_out; + bsp->smk_packet = asp->smk_out; + + return 0; +} + #ifdef SMACK_IPV6_PORT_LABELING /** * smack_socket_bind - record port binding information. @@ -4724,6 +4745,7 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), + LSM_HOOK_INIT(socket_socketpair, smack_socket_socketpair), #ifdef SMACK_IPV6_PORT_LABELING LSM_HOOK_INIT(socket_bind, smack_socket_bind), #endif From a964f395614af195cf5c5caa84a9c487b86d5ba5 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Tue, 24 Apr 2018 14:26:37 -0600 Subject: [PATCH 6/8] big key: get rid of stack array allocation We're interested in getting rid of all of the stack allocated arrays in the kernel [1]. This patch simply hardcodes the iv length to match that of the hardcoded cipher. [1]: https://lkml.org/lkml/2018/3/7/621 v2: hardcode the length of the nonce to be the GCM AES IV length, and do a sanity check in init(), Eric Biggers v3: * remember to free big_key_aead when sanity check fails * define a constant for big key IV size so it can be changed along side the algorithm in the code Signed-off-by: Tycho Andersen Reviewed-by: Kees Cook CC: David Howells CC: James Morris CC: "Serge E. Hallyn" CC: Jason A. Donenfeld CC: Eric Biggers Signed-off-by: James Morris --- security/keys/big_key.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 933623784ccd..2806e70d7f8f 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -22,6 +22,7 @@ #include #include #include +#include struct big_key_buf { unsigned int nr_pages; @@ -85,6 +86,7 @@ struct key_type key_type_big_key = { * Crypto names for big_key data authenticated encryption */ static const char big_key_alg_name[] = "gcm(aes)"; +#define BIG_KEY_IV_SIZE GCM_AES_IV_SIZE /* * Crypto algorithms for big_key data authenticated encryption @@ -109,7 +111,7 @@ static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t dat * an .update function, so there's no chance we'll wind up reusing the * key to encrypt updated data. Simply put: one key, one encryption. */ - u8 zero_nonce[crypto_aead_ivsize(big_key_aead)]; + u8 zero_nonce[BIG_KEY_IV_SIZE]; aead_req = aead_request_alloc(big_key_aead, GFP_KERNEL); if (!aead_req) @@ -425,6 +427,13 @@ static int __init big_key_init(void) pr_err("Can't alloc crypto: %d\n", ret); return ret; } + + if (unlikely(crypto_aead_ivsize(big_key_aead) != BIG_KEY_IV_SIZE)) { + WARN(1, "big key algorithm changed?"); + ret = -EINVAL; + goto free_aead; + } + ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE); if (ret < 0) { pr_err("Can't set crypto auth tag len: %d\n", ret); From 383203eff718d7397ffc68ac6c3ed644d3017fc7 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Tue, 24 Apr 2018 14:26:38 -0600 Subject: [PATCH 7/8] dh key: get rid of stack allocated array We're interested in getting rid of all of the stack allocated arrays in the kernel: https://lkml.org/lkml/2018/3/7/621 This particular vla is used as a temporary output buffer in case there is too much hash output for the destination buffer. Instead, let's just allocate a buffer that's big enough initially, but only copy back to userspace the amount that was originally asked for. v2: allocate enough in the original output buffer vs creating a temporary output buffer Signed-off-by: Tycho Andersen Reviewed-by: Kees Cook CC: David Howells CC: James Morris CC: "Serge E. Hallyn" CC: Eric Biggers Signed-off-by: James Morris --- security/keys/dh.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/security/keys/dh.c b/security/keys/dh.c index d1ea9f325f94..9fecaea6c298 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -183,24 +183,13 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, goto err; } - if (dlen < h) { - u8 tmpbuffer[h]; + err = crypto_shash_final(desc, dst); + if (err) + goto err; - err = crypto_shash_final(desc, tmpbuffer); - if (err) - goto err; - memcpy(dst, tmpbuffer, dlen); - memzero_explicit(tmpbuffer, h); - return 0; - } else { - err = crypto_shash_final(desc, dst); - if (err) - goto err; - - dlen -= h; - dst += h; - counter = cpu_to_be32(be32_to_cpu(counter) + 1); - } + dlen -= h; + dst += h; + counter = cpu_to_be32(be32_to_cpu(counter) + 1); } return 0; @@ -216,14 +205,16 @@ static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, { uint8_t *outbuf = NULL; int ret; + size_t outbuf_len = round_up(buflen, + crypto_shash_digestsize(sdesc->shash.tfm)); - outbuf = kmalloc(buflen, GFP_KERNEL); + outbuf = kmalloc(outbuf_len, GFP_KERNEL); if (!outbuf) { ret = -ENOMEM; goto err; } - ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen, lzero); + ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len, lzero); if (ret) goto err; From 890e2abe1028c39e5399101a2c277219cd637aaa Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Tue, 24 Apr 2018 14:26:39 -0600 Subject: [PATCH 8/8] dh key: get rid of stack allocated array for zeroes We're interested in getting rid of all of the stack allocated arrays in the kernel: https://lkml.org/lkml/2018/3/7/621 This case is interesting, since we really just need an array of bytes that are zero. The loop already ensures that if the array isn't exactly the right size that enough zero bytes will be copied in. So, instead of choosing this value to be the size of the hash, let's just choose it to be 32, since that is a common size, is not too big, and will not result in too many extra iterations of the loop. v2: split out from other patch, just hardcode array size instead of dynamically allocating something the right size v3: fix typo of 256 -> 32 Signed-off-by: Tycho Andersen Reviewed-by: Kees Cook CC: David Howells CC: James Morris CC: "Serge E. Hallyn" CC: Eric Biggers Signed-off-by: James Morris --- security/keys/dh.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/keys/dh.c b/security/keys/dh.c index 9fecaea6c298..f7403821db7f 100644 --- a/security/keys/dh.c +++ b/security/keys/dh.c @@ -162,8 +162,8 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, goto err; if (zlen && h) { - u8 tmpbuffer[h]; - size_t chunk = min_t(size_t, zlen, h); + u8 tmpbuffer[32]; + size_t chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); memset(tmpbuffer, 0, chunk); do { @@ -173,7 +173,7 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, goto err; zlen -= chunk; - chunk = min_t(size_t, zlen, h); + chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); } while (zlen); }