Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull security system updates from James Morris:

 - incorporate new socketpair() hook into LSM and wire up the SELinux
   and Smack modules. From David Herrmann:

     "The idea is to allow SO_PEERSEC to be called on AF_UNIX sockets
      created via socketpair(2), and return the same information as if
      you emulated socketpair(2) via a temporary listener socket.

      Right now SO_PEERSEC will return the unlabeled credentials for a
      socketpair, rather than the actual credentials of the creating
      process."

 - remove the unused security_settime LSM hook (Sargun Dhillon).

 - remove some stack allocated arrays from the keys code (Tycho
   Andersen)

* 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  dh key: get rid of stack allocated array for zeroes
  dh key: get rid of stack allocated array
  big key: get rid of stack array allocation
  smack: provide socketpair callback
  selinux: provide socketpair callback
  net: hook socketpair() into LSM
  security: add hook for socketpair()
  security: remove security_settime
This commit is contained in:
Linus Torvalds 2018-06-06 16:15:56 -07:00
commit 10b1eb7d8c
8 changed files with 85 additions and 37 deletions

View File

@ -757,6 +757,11 @@
* @type contains the requested communications type. * @type contains the requested communications type.
* @protocol contains the requested protocol. * @protocol contains the requested protocol.
* @kern set to 1 if a kernel socket. * @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: * @socket_bind:
* Check permission before socket protocol layer bind operation is * Check permission before socket protocol layer bind operation is
* performed and the socket @sock is bound to the address specified in the * 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_create)(int family, int type, int protocol, int kern);
int (*socket_post_create)(struct socket *sock, int family, int type, int (*socket_post_create)(struct socket *sock, int family, int type,
int protocol, int kern); int protocol, int kern);
int (*socket_socketpair)(struct socket *socka, struct socket *sockb);
int (*socket_bind)(struct socket *sock, struct sockaddr *address, int (*socket_bind)(struct socket *sock, struct sockaddr *address,
int addrlen); int addrlen);
int (*socket_connect)(struct socket *sock, struct sockaddr *address, 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 unix_may_send;
struct hlist_head socket_create; struct hlist_head socket_create;
struct hlist_head socket_post_create; struct hlist_head socket_post_create;
struct hlist_head socket_socketpair;
struct hlist_head socket_bind; struct hlist_head socket_bind;
struct hlist_head socket_connect; struct hlist_head socket_connect;
struct hlist_head socket_listen; struct hlist_head socket_listen;

View File

@ -220,12 +220,6 @@ int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry); int security_quota_on(struct dentry *dentry);
int security_syslog(int type); int security_syslog(int type);
int security_settime64(const struct timespec64 *ts, const struct timezone *tz); 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_vm_enough_memory_mm(struct mm_struct *mm, long pages);
int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_set_creds(struct linux_binprm *bprm);
int security_bprm_check(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm);
@ -508,14 +502,6 @@ static inline int security_settime64(const struct timespec64 *ts,
return cap_settime(ts, tz); 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) 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)); return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages));
@ -1191,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_create(int family, int type, int protocol, int kern);
int security_socket_post_create(struct socket *sock, int family, int security_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern); 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_bind(struct socket *sock, struct sockaddr *address, int addrlen);
int security_socket_connect(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); int security_socket_listen(struct socket *sock, int backlog);
@ -1262,6 +1249,12 @@ static inline int security_socket_post_create(struct socket *sock,
return 0; 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, static inline int security_socket_bind(struct socket *sock,
struct sockaddr *address, struct sockaddr *address,
int addrlen) int addrlen)

View File

@ -1445,6 +1445,13 @@ int __sys_socketpair(int family, int type, int protocol, int __user *usockvec)
goto out; 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); err = sock1->ops->socketpair(sock1, sock2);
if (unlikely(err < 0)) { if (unlikely(err < 0)) {
sock_release(sock2); sock_release(sock2);

View File

@ -22,6 +22,7 @@
#include <keys/user-type.h> #include <keys/user-type.h>
#include <keys/big_key-type.h> #include <keys/big_key-type.h>
#include <crypto/aead.h> #include <crypto/aead.h>
#include <crypto/gcm.h>
struct big_key_buf { struct big_key_buf {
unsigned int nr_pages; unsigned int nr_pages;
@ -85,6 +86,7 @@ struct key_type key_type_big_key = {
* Crypto names for big_key data authenticated encryption * Crypto names for big_key data authenticated encryption
*/ */
static const char big_key_alg_name[] = "gcm(aes)"; 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 * 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 * 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. * 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); aead_req = aead_request_alloc(big_key_aead, GFP_KERNEL);
if (!aead_req) if (!aead_req)
@ -425,6 +427,13 @@ static int __init big_key_init(void)
pr_err("Can't alloc crypto: %d\n", ret); pr_err("Can't alloc crypto: %d\n", ret);
return 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); ret = crypto_aead_setauthsize(big_key_aead, ENC_AUTHTAG_SIZE);
if (ret < 0) { if (ret < 0) {
pr_err("Can't set crypto auth tag len: %d\n", ret); pr_err("Can't set crypto auth tag len: %d\n", ret);

View File

@ -162,8 +162,8 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
goto err; goto err;
if (zlen && h) { if (zlen && h) {
u8 tmpbuffer[h]; u8 tmpbuffer[32];
size_t chunk = min_t(size_t, zlen, h); size_t chunk = min_t(size_t, zlen, sizeof(tmpbuffer));
memset(tmpbuffer, 0, chunk); memset(tmpbuffer, 0, chunk);
do { do {
@ -173,7 +173,7 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
goto err; goto err;
zlen -= chunk; zlen -= chunk;
chunk = min_t(size_t, zlen, h); chunk = min_t(size_t, zlen, sizeof(tmpbuffer));
} while (zlen); } while (zlen);
} }
@ -183,24 +183,13 @@ static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
goto err; goto err;
} }
if (dlen < h) { err = crypto_shash_final(desc, dst);
u8 tmpbuffer[h]; if (err)
goto err;
err = crypto_shash_final(desc, tmpbuffer); dlen -= h;
if (err) dst += h;
goto err; counter = cpu_to_be32(be32_to_cpu(counter) + 1);
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);
}
} }
return 0; return 0;
@ -216,14 +205,16 @@ static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
{ {
uint8_t *outbuf = NULL; uint8_t *outbuf = NULL;
int ret; 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) { if (!outbuf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen, lzero); ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len, lzero);
if (ret) if (ret)
goto err; goto err;

View File

@ -1358,6 +1358,12 @@ int security_socket_post_create(struct socket *sock, int family,
protocol, kern); 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) int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{ {
return call_int_hook(socket_bind, 0, sock, address, addrlen); return call_int_hook(socket_bind, 0, sock, address, addrlen);

View File

@ -4580,6 +4580,18 @@ static int selinux_socket_post_create(struct socket *sock, int family,
return err; 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. /* Range of port numbers used to automatically bind.
Need to determine whether we should perform a name_bind Need to determine whether we should perform a name_bind
permission check between the socket and the port number. */ permission check between the socket and the port number. */
@ -7016,6 +7028,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(socket_create, selinux_socket_create), LSM_HOOK_INIT(socket_create, selinux_socket_create),
LSM_HOOK_INIT(socket_post_create, selinux_socket_post_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_bind, selinux_socket_bind),
LSM_HOOK_INIT(socket_connect, selinux_socket_connect), LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
LSM_HOOK_INIT(socket_listen, selinux_socket_listen), LSM_HOOK_INIT(socket_listen, selinux_socket_listen),

View File

@ -2842,6 +2842,27 @@ static int smack_socket_post_create(struct socket *sock, int family,
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); 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 #ifdef SMACK_IPV6_PORT_LABELING
/** /**
* smack_socket_bind - record port binding information. * 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(unix_may_send, smack_unix_may_send),
LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), LSM_HOOK_INIT(socket_post_create, smack_socket_post_create),
LSM_HOOK_INIT(socket_socketpair, smack_socket_socketpair),
#ifdef SMACK_IPV6_PORT_LABELING #ifdef SMACK_IPV6_PORT_LABELING
LSM_HOOK_INIT(socket_bind, smack_socket_bind), LSM_HOOK_INIT(socket_bind, smack_socket_bind),
#endif #endif