mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
Merge branch 'android-3.10' of https://android.googlesource.com/kernel/common into linaro-android-3.10-lsk
* android-3.10: (60 commits) kbuild: make it possible to specify the module output dir xt_qtaguid: Use sk_callback_lock read locks before reading sk->sk_socket ipv6: clean up anycast when an interface is destroyed usb: gadget: check for accessory device before disconnecting HIDs staging: android: ashmem: add missing include usb: gadget: android: Save/restore ep0 completion function selinux: Remove obsolete selinux_audit_data initialization. selinux: make the netif cache namespace aware selinux: correctly label /proc inodes in use before the policy is loaded selinux: fix inode security list corruption selinux: put the mmap() DAC controls before the MAC controls selinux: reduce the number of calls to synchronize_net() when flushing caches [PATCH 5/5] pstore: selinux: add security in-core xattr support for pstore and debugfs SELinux: Update policy version to support constraints info [PATCH v4 4/5] pstore: add pmsg [PATCH 3/5] pstore: handle zero-sized prz in series [PATCH v2 2/5] pstore: remove superfluous memory size check [PATCH v4 1/5] pstore: use snprintf pstore: clarify clearing of _read_cnt in ramoops_context prctl: make PR_SET_TIMERSLACK_PID pid namespace aware ... Signed-off-by: Amit Pundir <amit.pundir@linaro.org> Conflicts: drivers/staging/android/Kconfig
This commit is contained in:
@@ -2221,6 +2221,13 @@ config NEON
|
||||
Say Y to include support code for NEON, the ARMv7 Advanced SIMD
|
||||
Extension.
|
||||
|
||||
config KERNEL_MODE_NEON
|
||||
bool "Support for NEON in kernel mode"
|
||||
default n
|
||||
depends on NEON
|
||||
help
|
||||
Say Y to include support for NEON in kernel mode.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Userspace binary formats"
|
||||
|
||||
1
arch/arm/crypto/.gitignore
vendored
Normal file
1
arch/arm/crypto/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
aesbs-core.S
|
||||
@@ -3,7 +3,21 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o
|
||||
obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o
|
||||
obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
|
||||
obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
|
||||
obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o
|
||||
|
||||
aes-arm-y := aes-armv4.o aes_glue.o
|
||||
sha1-arm-y := sha1-armv4-large.o sha1_glue.o
|
||||
aes-arm-y := aes-armv4.o aes_glue.o
|
||||
aes-arm-bs-y := aesbs-core.o aesbs-glue.o
|
||||
sha1-arm-y := sha1-armv4-large.o sha1_glue.o
|
||||
sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o
|
||||
sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o
|
||||
|
||||
quiet_cmd_perl = PERL $@
|
||||
cmd_perl = $(PERL) $(<) > $(@)
|
||||
|
||||
$(src)/aesbs-core.S_shipped: $(src)/bsaes-armv7.pl
|
||||
$(call cmd,perl)
|
||||
|
||||
.PRECIOUS: $(obj)/aesbs-core.S
|
||||
|
||||
@@ -148,7 +148,7 @@ AES_Te:
|
||||
@ const AES_KEY *key) {
|
||||
.align 5
|
||||
ENTRY(AES_encrypt)
|
||||
sub r3,pc,#8 @ AES_encrypt
|
||||
adr r3,AES_encrypt
|
||||
stmdb sp!,{r1,r4-r12,lr}
|
||||
mov r12,r0 @ inp
|
||||
mov r11,r2
|
||||
@@ -381,7 +381,7 @@ _armv4_AES_encrypt:
|
||||
.align 5
|
||||
ENTRY(private_AES_set_encrypt_key)
|
||||
_armv4_AES_set_encrypt_key:
|
||||
sub r3,pc,#8 @ AES_set_encrypt_key
|
||||
adr r3,_armv4_AES_set_encrypt_key
|
||||
teq r0,#0
|
||||
moveq r0,#-1
|
||||
beq .Labrt
|
||||
@@ -843,7 +843,7 @@ AES_Td:
|
||||
@ const AES_KEY *key) {
|
||||
.align 5
|
||||
ENTRY(AES_decrypt)
|
||||
sub r3,pc,#8 @ AES_decrypt
|
||||
adr r3,AES_decrypt
|
||||
stmdb sp!,{r1,r4-r12,lr}
|
||||
mov r12,r0 @ inp
|
||||
mov r11,r2
|
||||
|
||||
@@ -6,22 +6,12 @@
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/aes.h>
|
||||
|
||||
#define AES_MAXNR 14
|
||||
#include "aes_glue.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int rd_key[4 *(AES_MAXNR + 1)];
|
||||
int rounds;
|
||||
} AES_KEY;
|
||||
|
||||
struct AES_CTX {
|
||||
AES_KEY enc_key;
|
||||
AES_KEY dec_key;
|
||||
};
|
||||
|
||||
asmlinkage void AES_encrypt(const u8 *in, u8 *out, AES_KEY *ctx);
|
||||
asmlinkage void AES_decrypt(const u8 *in, u8 *out, AES_KEY *ctx);
|
||||
asmlinkage int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
|
||||
asmlinkage int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
|
||||
EXPORT_SYMBOL(AES_encrypt);
|
||||
EXPORT_SYMBOL(AES_decrypt);
|
||||
EXPORT_SYMBOL(private_AES_set_encrypt_key);
|
||||
EXPORT_SYMBOL(private_AES_set_decrypt_key);
|
||||
|
||||
static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
|
||||
{
|
||||
@@ -81,7 +71,7 @@ static struct crypto_alg aes_alg = {
|
||||
.cipher = {
|
||||
.cia_min_keysize = AES_MIN_KEY_SIZE,
|
||||
.cia_max_keysize = AES_MAX_KEY_SIZE,
|
||||
.cia_setkey = aes_set_key,
|
||||
.cia_setkey = aes_set_key,
|
||||
.cia_encrypt = aes_encrypt,
|
||||
.cia_decrypt = aes_decrypt
|
||||
}
|
||||
|
||||
19
arch/arm/crypto/aes_glue.h
Normal file
19
arch/arm/crypto/aes_glue.h
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
#define AES_MAXNR 14
|
||||
|
||||
struct AES_KEY {
|
||||
unsigned int rd_key[4 * (AES_MAXNR + 1)];
|
||||
int rounds;
|
||||
};
|
||||
|
||||
struct AES_CTX {
|
||||
struct AES_KEY enc_key;
|
||||
struct AES_KEY dec_key;
|
||||
};
|
||||
|
||||
asmlinkage void AES_encrypt(const u8 *in, u8 *out, struct AES_KEY *ctx);
|
||||
asmlinkage void AES_decrypt(const u8 *in, u8 *out, struct AES_KEY *ctx);
|
||||
asmlinkage int private_AES_set_decrypt_key(const unsigned char *userKey,
|
||||
const int bits, struct AES_KEY *key);
|
||||
asmlinkage int private_AES_set_encrypt_key(const unsigned char *userKey,
|
||||
const int bits, struct AES_KEY *key);
|
||||
2544
arch/arm/crypto/aesbs-core.S_shipped
Normal file
2544
arch/arm/crypto/aesbs-core.S_shipped
Normal file
File diff suppressed because it is too large
Load Diff
434
arch/arm/crypto/aesbs-glue.c
Normal file
434
arch/arm/crypto/aesbs-glue.c
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* linux/arch/arm/crypto/aesbs-glue.c - glue code for NEON bit sliced AES
|
||||
*
|
||||
* Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <asm/neon.h>
|
||||
#include <crypto/aes.h>
|
||||
#include <crypto/ablk_helper.h>
|
||||
#include <crypto/algapi.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "aes_glue.h"
|
||||
|
||||
#define BIT_SLICED_KEY_MAXSIZE (128 * (AES_MAXNR - 1) + 2 * AES_BLOCK_SIZE)
|
||||
|
||||
struct BS_KEY {
|
||||
struct AES_KEY rk;
|
||||
int converted;
|
||||
u8 __aligned(8) bs[BIT_SLICED_KEY_MAXSIZE];
|
||||
} __aligned(8);
|
||||
|
||||
asmlinkage void bsaes_enc_key_convert(u8 out[], struct AES_KEY const *in);
|
||||
asmlinkage void bsaes_dec_key_convert(u8 out[], struct AES_KEY const *in);
|
||||
|
||||
asmlinkage void bsaes_cbc_encrypt(u8 const in[], u8 out[], u32 bytes,
|
||||
struct BS_KEY *key, u8 iv[]);
|
||||
|
||||
asmlinkage void bsaes_ctr32_encrypt_blocks(u8 const in[], u8 out[], u32 blocks,
|
||||
struct BS_KEY *key, u8 const iv[]);
|
||||
|
||||
asmlinkage void bsaes_xts_encrypt(u8 const in[], u8 out[], u32 bytes,
|
||||
struct BS_KEY *key, u8 tweak[]);
|
||||
|
||||
asmlinkage void bsaes_xts_decrypt(u8 const in[], u8 out[], u32 bytes,
|
||||
struct BS_KEY *key, u8 tweak[]);
|
||||
|
||||
struct aesbs_cbc_ctx {
|
||||
struct AES_KEY enc;
|
||||
struct BS_KEY dec;
|
||||
};
|
||||
|
||||
struct aesbs_ctr_ctx {
|
||||
struct BS_KEY enc;
|
||||
};
|
||||
|
||||
struct aesbs_xts_ctx {
|
||||
struct BS_KEY enc;
|
||||
struct BS_KEY dec;
|
||||
struct AES_KEY twkey;
|
||||
};
|
||||
|
||||
static int aesbs_cbc_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
struct aesbs_cbc_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
int bits = key_len * 8;
|
||||
|
||||
if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc)) {
|
||||
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
||||
return -EINVAL;
|
||||
}
|
||||
ctx->dec.rk = ctx->enc;
|
||||
private_AES_set_decrypt_key(in_key, bits, &ctx->dec.rk);
|
||||
ctx->dec.converted = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aesbs_ctr_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
struct aesbs_ctr_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
int bits = key_len * 8;
|
||||
|
||||
if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc.rk)) {
|
||||
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
||||
return -EINVAL;
|
||||
}
|
||||
ctx->enc.converted = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aesbs_xts_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
struct aesbs_xts_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
int bits = key_len * 4;
|
||||
|
||||
if (private_AES_set_encrypt_key(in_key, bits, &ctx->enc.rk)) {
|
||||
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
|
||||
return -EINVAL;
|
||||
}
|
||||
ctx->dec.rk = ctx->enc.rk;
|
||||
private_AES_set_decrypt_key(in_key, bits, &ctx->dec.rk);
|
||||
private_AES_set_encrypt_key(in_key + key_len / 2, bits, &ctx->twkey);
|
||||
ctx->enc.converted = ctx->dec.converted = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aesbs_cbc_encrypt(struct blkcipher_desc *desc,
|
||||
struct scatterlist *dst,
|
||||
struct scatterlist *src, unsigned int nbytes)
|
||||
{
|
||||
struct aesbs_cbc_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
|
||||
struct blkcipher_walk walk;
|
||||
int err;
|
||||
|
||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||
err = blkcipher_walk_virt(desc, &walk);
|
||||
|
||||
while (walk.nbytes) {
|
||||
u32 blocks = walk.nbytes / AES_BLOCK_SIZE;
|
||||
u8 *src = walk.src.virt.addr;
|
||||
|
||||
if (walk.dst.virt.addr == walk.src.virt.addr) {
|
||||
u8 *iv = walk.iv;
|
||||
|
||||
do {
|
||||
crypto_xor(src, iv, AES_BLOCK_SIZE);
|
||||
AES_encrypt(src, src, &ctx->enc);
|
||||
iv = src;
|
||||
src += AES_BLOCK_SIZE;
|
||||
} while (--blocks);
|
||||
memcpy(walk.iv, iv, AES_BLOCK_SIZE);
|
||||
} else {
|
||||
u8 *dst = walk.dst.virt.addr;
|
||||
|
||||
do {
|
||||
crypto_xor(walk.iv, src, AES_BLOCK_SIZE);
|
||||
AES_encrypt(walk.iv, dst, &ctx->enc);
|
||||
memcpy(walk.iv, dst, AES_BLOCK_SIZE);
|
||||
src += AES_BLOCK_SIZE;
|
||||
dst += AES_BLOCK_SIZE;
|
||||
} while (--blocks);
|
||||
}
|
||||
err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int aesbs_cbc_decrypt(struct blkcipher_desc *desc,
|
||||
struct scatterlist *dst,
|
||||
struct scatterlist *src, unsigned int nbytes)
|
||||
{
|
||||
struct aesbs_cbc_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
|
||||
struct blkcipher_walk walk;
|
||||
int err;
|
||||
|
||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||
err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
|
||||
|
||||
while ((walk.nbytes / AES_BLOCK_SIZE) >= 8) {
|
||||
kernel_neon_begin();
|
||||
bsaes_cbc_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
|
||||
walk.nbytes, &ctx->dec, walk.iv);
|
||||
kernel_neon_end();
|
||||
err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
|
||||
}
|
||||
while (walk.nbytes) {
|
||||
u32 blocks = walk.nbytes / AES_BLOCK_SIZE;
|
||||
u8 *dst = walk.dst.virt.addr;
|
||||
u8 *src = walk.src.virt.addr;
|
||||
u8 bk[2][AES_BLOCK_SIZE];
|
||||
u8 *iv = walk.iv;
|
||||
|
||||
do {
|
||||
if (walk.dst.virt.addr == walk.src.virt.addr)
|
||||
memcpy(bk[blocks & 1], src, AES_BLOCK_SIZE);
|
||||
|
||||
AES_decrypt(src, dst, &ctx->dec.rk);
|
||||
crypto_xor(dst, iv, AES_BLOCK_SIZE);
|
||||
|
||||
if (walk.dst.virt.addr == walk.src.virt.addr)
|
||||
iv = bk[blocks & 1];
|
||||
else
|
||||
iv = src;
|
||||
|
||||
dst += AES_BLOCK_SIZE;
|
||||
src += AES_BLOCK_SIZE;
|
||||
} while (--blocks);
|
||||
err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void inc_be128_ctr(__be32 ctr[], u32 addend)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 3; i >= 0; i--, addend = 1) {
|
||||
u32 n = be32_to_cpu(ctr[i]) + addend;
|
||||
|
||||
ctr[i] = cpu_to_be32(n);
|
||||
if (n >= addend)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int aesbs_ctr_encrypt(struct blkcipher_desc *desc,
|
||||
struct scatterlist *dst, struct scatterlist *src,
|
||||
unsigned int nbytes)
|
||||
{
|
||||
struct aesbs_ctr_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
|
||||
struct blkcipher_walk walk;
|
||||
u32 blocks;
|
||||
int err;
|
||||
|
||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||
err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
|
||||
|
||||
while ((blocks = walk.nbytes / AES_BLOCK_SIZE)) {
|
||||
u32 tail = walk.nbytes % AES_BLOCK_SIZE;
|
||||
__be32 *ctr = (__be32 *)walk.iv;
|
||||
u32 headroom = UINT_MAX - be32_to_cpu(ctr[3]);
|
||||
|
||||
/* avoid 32 bit counter overflow in the NEON code */
|
||||
if (unlikely(headroom < blocks)) {
|
||||
blocks = headroom + 1;
|
||||
tail = walk.nbytes - blocks * AES_BLOCK_SIZE;
|
||||
}
|
||||
kernel_neon_begin();
|
||||
bsaes_ctr32_encrypt_blocks(walk.src.virt.addr,
|
||||
walk.dst.virt.addr, blocks,
|
||||
&ctx->enc, walk.iv);
|
||||
kernel_neon_end();
|
||||
inc_be128_ctr(ctr, blocks);
|
||||
|
||||
nbytes -= blocks * AES_BLOCK_SIZE;
|
||||
if (nbytes && nbytes == tail && nbytes <= AES_BLOCK_SIZE)
|
||||
break;
|
||||
|
||||
err = blkcipher_walk_done(desc, &walk, tail);
|
||||
}
|
||||
if (walk.nbytes) {
|
||||
u8 *tdst = walk.dst.virt.addr + blocks * AES_BLOCK_SIZE;
|
||||
u8 *tsrc = walk.src.virt.addr + blocks * AES_BLOCK_SIZE;
|
||||
u8 ks[AES_BLOCK_SIZE];
|
||||
|
||||
AES_encrypt(walk.iv, ks, &ctx->enc.rk);
|
||||
if (tdst != tsrc)
|
||||
memcpy(tdst, tsrc, nbytes);
|
||||
crypto_xor(tdst, ks, nbytes);
|
||||
err = blkcipher_walk_done(desc, &walk, 0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int aesbs_xts_encrypt(struct blkcipher_desc *desc,
|
||||
struct scatterlist *dst,
|
||||
struct scatterlist *src, unsigned int nbytes)
|
||||
{
|
||||
struct aesbs_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
|
||||
struct blkcipher_walk walk;
|
||||
int err;
|
||||
|
||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||
err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
|
||||
|
||||
/* generate the initial tweak */
|
||||
AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
|
||||
|
||||
while (walk.nbytes) {
|
||||
kernel_neon_begin();
|
||||
bsaes_xts_encrypt(walk.src.virt.addr, walk.dst.virt.addr,
|
||||
walk.nbytes, &ctx->enc, walk.iv);
|
||||
kernel_neon_end();
|
||||
err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int aesbs_xts_decrypt(struct blkcipher_desc *desc,
|
||||
struct scatterlist *dst,
|
||||
struct scatterlist *src, unsigned int nbytes)
|
||||
{
|
||||
struct aesbs_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
|
||||
struct blkcipher_walk walk;
|
||||
int err;
|
||||
|
||||
blkcipher_walk_init(&walk, dst, src, nbytes);
|
||||
err = blkcipher_walk_virt_block(desc, &walk, 8 * AES_BLOCK_SIZE);
|
||||
|
||||
/* generate the initial tweak */
|
||||
AES_encrypt(walk.iv, walk.iv, &ctx->twkey);
|
||||
|
||||
while (walk.nbytes) {
|
||||
kernel_neon_begin();
|
||||
bsaes_xts_decrypt(walk.src.virt.addr, walk.dst.virt.addr,
|
||||
walk.nbytes, &ctx->dec, walk.iv);
|
||||
kernel_neon_end();
|
||||
err = blkcipher_walk_done(desc, &walk, walk.nbytes % AES_BLOCK_SIZE);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct crypto_alg aesbs_algs[] = { {
|
||||
.cra_name = "__cbc-aes-neonbs",
|
||||
.cra_driver_name = "__driver-cbc-aes-neonbs",
|
||||
.cra_priority = 0,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
|
||||
.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.cra_ctxsize = sizeof(struct aesbs_cbc_ctx),
|
||||
.cra_alignmask = 7,
|
||||
.cra_type = &crypto_blkcipher_type,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_blkcipher = {
|
||||
.min_keysize = AES_MIN_KEY_SIZE,
|
||||
.max_keysize = AES_MAX_KEY_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.setkey = aesbs_cbc_set_key,
|
||||
.encrypt = aesbs_cbc_encrypt,
|
||||
.decrypt = aesbs_cbc_decrypt,
|
||||
},
|
||||
}, {
|
||||
.cra_name = "__ctr-aes-neonbs",
|
||||
.cra_driver_name = "__driver-ctr-aes-neonbs",
|
||||
.cra_priority = 0,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
|
||||
.cra_blocksize = 1,
|
||||
.cra_ctxsize = sizeof(struct aesbs_ctr_ctx),
|
||||
.cra_alignmask = 7,
|
||||
.cra_type = &crypto_blkcipher_type,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_blkcipher = {
|
||||
.min_keysize = AES_MIN_KEY_SIZE,
|
||||
.max_keysize = AES_MAX_KEY_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.setkey = aesbs_ctr_set_key,
|
||||
.encrypt = aesbs_ctr_encrypt,
|
||||
.decrypt = aesbs_ctr_encrypt,
|
||||
},
|
||||
}, {
|
||||
.cra_name = "__xts-aes-neonbs",
|
||||
.cra_driver_name = "__driver-xts-aes-neonbs",
|
||||
.cra_priority = 0,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
|
||||
.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.cra_ctxsize = sizeof(struct aesbs_xts_ctx),
|
||||
.cra_alignmask = 7,
|
||||
.cra_type = &crypto_blkcipher_type,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_blkcipher = {
|
||||
.min_keysize = 2 * AES_MIN_KEY_SIZE,
|
||||
.max_keysize = 2 * AES_MAX_KEY_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.setkey = aesbs_xts_set_key,
|
||||
.encrypt = aesbs_xts_encrypt,
|
||||
.decrypt = aesbs_xts_decrypt,
|
||||
},
|
||||
}, {
|
||||
.cra_name = "cbc(aes)",
|
||||
.cra_driver_name = "cbc-aes-neonbs",
|
||||
.cra_priority = 300,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
||||
.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.cra_ctxsize = sizeof(struct async_helper_ctx),
|
||||
.cra_alignmask = 7,
|
||||
.cra_type = &crypto_ablkcipher_type,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_init = ablk_init,
|
||||
.cra_exit = ablk_exit,
|
||||
.cra_ablkcipher = {
|
||||
.min_keysize = AES_MIN_KEY_SIZE,
|
||||
.max_keysize = AES_MAX_KEY_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.setkey = ablk_set_key,
|
||||
.encrypt = __ablk_encrypt,
|
||||
.decrypt = ablk_decrypt,
|
||||
}
|
||||
}, {
|
||||
.cra_name = "ctr(aes)",
|
||||
.cra_driver_name = "ctr-aes-neonbs",
|
||||
.cra_priority = 300,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
||||
.cra_blocksize = 1,
|
||||
.cra_ctxsize = sizeof(struct async_helper_ctx),
|
||||
.cra_alignmask = 7,
|
||||
.cra_type = &crypto_ablkcipher_type,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_init = ablk_init,
|
||||
.cra_exit = ablk_exit,
|
||||
.cra_ablkcipher = {
|
||||
.min_keysize = AES_MIN_KEY_SIZE,
|
||||
.max_keysize = AES_MAX_KEY_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.setkey = ablk_set_key,
|
||||
.encrypt = ablk_encrypt,
|
||||
.decrypt = ablk_decrypt,
|
||||
}
|
||||
}, {
|
||||
.cra_name = "xts(aes)",
|
||||
.cra_driver_name = "xts-aes-neonbs",
|
||||
.cra_priority = 300,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
|
||||
.cra_blocksize = AES_BLOCK_SIZE,
|
||||
.cra_ctxsize = sizeof(struct async_helper_ctx),
|
||||
.cra_alignmask = 7,
|
||||
.cra_type = &crypto_ablkcipher_type,
|
||||
.cra_module = THIS_MODULE,
|
||||
.cra_init = ablk_init,
|
||||
.cra_exit = ablk_exit,
|
||||
.cra_ablkcipher = {
|
||||
.min_keysize = 2 * AES_MIN_KEY_SIZE,
|
||||
.max_keysize = 2 * AES_MAX_KEY_SIZE,
|
||||
.ivsize = AES_BLOCK_SIZE,
|
||||
.setkey = ablk_set_key,
|
||||
.encrypt = ablk_encrypt,
|
||||
.decrypt = ablk_decrypt,
|
||||
}
|
||||
} };
|
||||
|
||||
static int __init aesbs_mod_init(void)
|
||||
{
|
||||
if (!cpu_has_neon())
|
||||
return -ENODEV;
|
||||
|
||||
return crypto_register_algs(aesbs_algs, ARRAY_SIZE(aesbs_algs));
|
||||
}
|
||||
|
||||
static void __exit aesbs_mod_exit(void)
|
||||
{
|
||||
crypto_unregister_algs(aesbs_algs, ARRAY_SIZE(aesbs_algs));
|
||||
}
|
||||
|
||||
module_init(aesbs_mod_init);
|
||||
module_exit(aesbs_mod_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Bit sliced AES in CBC/CTR/XTS modes using NEON");
|
||||
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
2467
arch/arm/crypto/bsaes-armv7.pl
Normal file
2467
arch/arm/crypto/bsaes-armv7.pl
Normal file
File diff suppressed because it is too large
Load Diff
634
arch/arm/crypto/sha1-armv7-neon.S
Normal file
634
arch/arm/crypto/sha1-armv7-neon.S
Normal file
@@ -0,0 +1,634 @@
|
||||
/* sha1-armv7-neon.S - ARM/NEON accelerated SHA-1 transform function
|
||||
*
|
||||
* Copyright © 2013-2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
|
||||
.syntax unified
|
||||
.code 32
|
||||
.fpu neon
|
||||
|
||||
.text
|
||||
|
||||
|
||||
/* Context structure */
|
||||
|
||||
#define state_h0 0
|
||||
#define state_h1 4
|
||||
#define state_h2 8
|
||||
#define state_h3 12
|
||||
#define state_h4 16
|
||||
|
||||
|
||||
/* Constants */
|
||||
|
||||
#define K1 0x5A827999
|
||||
#define K2 0x6ED9EBA1
|
||||
#define K3 0x8F1BBCDC
|
||||
#define K4 0xCA62C1D6
|
||||
.align 4
|
||||
.LK_VEC:
|
||||
.LK1: .long K1, K1, K1, K1
|
||||
.LK2: .long K2, K2, K2, K2
|
||||
.LK3: .long K3, K3, K3, K3
|
||||
.LK4: .long K4, K4, K4, K4
|
||||
|
||||
|
||||
/* Register macros */
|
||||
|
||||
#define RSTATE r0
|
||||
#define RDATA r1
|
||||
#define RNBLKS r2
|
||||
#define ROLDSTACK r3
|
||||
#define RWK lr
|
||||
|
||||
#define _a r4
|
||||
#define _b r5
|
||||
#define _c r6
|
||||
#define _d r7
|
||||
#define _e r8
|
||||
|
||||
#define RT0 r9
|
||||
#define RT1 r10
|
||||
#define RT2 r11
|
||||
#define RT3 r12
|
||||
|
||||
#define W0 q0
|
||||
#define W1 q1
|
||||
#define W2 q2
|
||||
#define W3 q3
|
||||
#define W4 q4
|
||||
#define W5 q5
|
||||
#define W6 q6
|
||||
#define W7 q7
|
||||
|
||||
#define tmp0 q8
|
||||
#define tmp1 q9
|
||||
#define tmp2 q10
|
||||
#define tmp3 q11
|
||||
|
||||
#define qK1 q12
|
||||
#define qK2 q13
|
||||
#define qK3 q14
|
||||
#define qK4 q15
|
||||
|
||||
|
||||
/* Round function macros. */
|
||||
|
||||
#define WK_offs(i) (((i) & 15) * 4)
|
||||
|
||||
#define _R_F1(a,b,c,d,e,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
ldr RT3, [sp, WK_offs(i)]; \
|
||||
pre1(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
bic RT0, d, b; \
|
||||
add e, e, a, ror #(32 - 5); \
|
||||
and RT1, c, b; \
|
||||
pre2(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
add RT0, RT0, RT3; \
|
||||
add e, e, RT1; \
|
||||
ror b, #(32 - 30); \
|
||||
pre3(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
add e, e, RT0;
|
||||
|
||||
#define _R_F2(a,b,c,d,e,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
ldr RT3, [sp, WK_offs(i)]; \
|
||||
pre1(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
eor RT0, d, b; \
|
||||
add e, e, a, ror #(32 - 5); \
|
||||
eor RT0, RT0, c; \
|
||||
pre2(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
add e, e, RT3; \
|
||||
ror b, #(32 - 30); \
|
||||
pre3(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
add e, e, RT0; \
|
||||
|
||||
#define _R_F3(a,b,c,d,e,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
ldr RT3, [sp, WK_offs(i)]; \
|
||||
pre1(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
eor RT0, b, c; \
|
||||
and RT1, b, c; \
|
||||
add e, e, a, ror #(32 - 5); \
|
||||
pre2(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
and RT0, RT0, d; \
|
||||
add RT1, RT1, RT3; \
|
||||
add e, e, RT0; \
|
||||
ror b, #(32 - 30); \
|
||||
pre3(i16,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28); \
|
||||
add e, e, RT1;
|
||||
|
||||
#define _R_F4(a,b,c,d,e,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
_R_F2(a,b,c,d,e,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28)
|
||||
|
||||
#define _R(a,b,c,d,e,f,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
_R_##f(a,b,c,d,e,i,pre1,pre2,pre3,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28)
|
||||
|
||||
#define R(a,b,c,d,e,f,i) \
|
||||
_R_##f(a,b,c,d,e,i,dummy,dummy,dummy,i16,\
|
||||
W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28)
|
||||
|
||||
#define dummy(...)
|
||||
|
||||
|
||||
/* Input expansion macros. */
|
||||
|
||||
/********* Precalc macros for rounds 0-15 *************************************/
|
||||
|
||||
#define W_PRECALC_00_15() \
|
||||
add RWK, sp, #(WK_offs(0)); \
|
||||
\
|
||||
vld1.32 {tmp0, tmp1}, [RDATA]!; \
|
||||
vrev32.8 W0, tmp0; /* big => little */ \
|
||||
vld1.32 {tmp2, tmp3}, [RDATA]!; \
|
||||
vadd.u32 tmp0, W0, curK; \
|
||||
vrev32.8 W7, tmp1; /* big => little */ \
|
||||
vrev32.8 W6, tmp2; /* big => little */ \
|
||||
vadd.u32 tmp1, W7, curK; \
|
||||
vrev32.8 W5, tmp3; /* big => little */ \
|
||||
vadd.u32 tmp2, W6, curK; \
|
||||
vst1.32 {tmp0, tmp1}, [RWK]!; \
|
||||
vadd.u32 tmp3, W5, curK; \
|
||||
vst1.32 {tmp2, tmp3}, [RWK]; \
|
||||
|
||||
#define WPRECALC_00_15_0(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vld1.32 {tmp0, tmp1}, [RDATA]!; \
|
||||
|
||||
#define WPRECALC_00_15_1(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
add RWK, sp, #(WK_offs(0)); \
|
||||
|
||||
#define WPRECALC_00_15_2(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vrev32.8 W0, tmp0; /* big => little */ \
|
||||
|
||||
#define WPRECALC_00_15_3(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vld1.32 {tmp2, tmp3}, [RDATA]!; \
|
||||
|
||||
#define WPRECALC_00_15_4(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vadd.u32 tmp0, W0, curK; \
|
||||
|
||||
#define WPRECALC_00_15_5(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vrev32.8 W7, tmp1; /* big => little */ \
|
||||
|
||||
#define WPRECALC_00_15_6(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vrev32.8 W6, tmp2; /* big => little */ \
|
||||
|
||||
#define WPRECALC_00_15_7(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vadd.u32 tmp1, W7, curK; \
|
||||
|
||||
#define WPRECALC_00_15_8(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vrev32.8 W5, tmp3; /* big => little */ \
|
||||
|
||||
#define WPRECALC_00_15_9(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vadd.u32 tmp2, W6, curK; \
|
||||
|
||||
#define WPRECALC_00_15_10(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vst1.32 {tmp0, tmp1}, [RWK]!; \
|
||||
|
||||
#define WPRECALC_00_15_11(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vadd.u32 tmp3, W5, curK; \
|
||||
|
||||
#define WPRECALC_00_15_12(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vst1.32 {tmp2, tmp3}, [RWK]; \
|
||||
|
||||
|
||||
/********* Precalc macros for rounds 16-31 ************************************/
|
||||
|
||||
#define WPRECALC_16_31_0(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor tmp0, tmp0; \
|
||||
vext.8 W, W_m16, W_m12, #8; \
|
||||
|
||||
#define WPRECALC_16_31_1(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
add RWK, sp, #(WK_offs(i)); \
|
||||
vext.8 tmp0, W_m04, tmp0, #4; \
|
||||
|
||||
#define WPRECALC_16_31_2(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor tmp0, tmp0, W_m16; \
|
||||
veor.32 W, W, W_m08; \
|
||||
|
||||
#define WPRECALC_16_31_3(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor tmp1, tmp1; \
|
||||
veor W, W, tmp0; \
|
||||
|
||||
#define WPRECALC_16_31_4(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vshl.u32 tmp0, W, #1; \
|
||||
|
||||
#define WPRECALC_16_31_5(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vext.8 tmp1, tmp1, W, #(16-12); \
|
||||
vshr.u32 W, W, #31; \
|
||||
|
||||
#define WPRECALC_16_31_6(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vorr tmp0, tmp0, W; \
|
||||
vshr.u32 W, tmp1, #30; \
|
||||
|
||||
#define WPRECALC_16_31_7(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vshl.u32 tmp1, tmp1, #2; \
|
||||
|
||||
#define WPRECALC_16_31_8(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor tmp0, tmp0, W; \
|
||||
|
||||
#define WPRECALC_16_31_9(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor W, tmp0, tmp1; \
|
||||
|
||||
#define WPRECALC_16_31_10(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vadd.u32 tmp0, W, curK; \
|
||||
|
||||
#define WPRECALC_16_31_11(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vst1.32 {tmp0}, [RWK];
|
||||
|
||||
|
||||
/********* Precalc macros for rounds 32-79 ************************************/
|
||||
|
||||
#define WPRECALC_32_79_0(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor W, W_m28; \
|
||||
|
||||
#define WPRECALC_32_79_1(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vext.8 tmp0, W_m08, W_m04, #8; \
|
||||
|
||||
#define WPRECALC_32_79_2(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor W, W_m16; \
|
||||
|
||||
#define WPRECALC_32_79_3(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
veor W, tmp0; \
|
||||
|
||||
#define WPRECALC_32_79_4(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
add RWK, sp, #(WK_offs(i&~3)); \
|
||||
|
||||
#define WPRECALC_32_79_5(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vshl.u32 tmp1, W, #2; \
|
||||
|
||||
#define WPRECALC_32_79_6(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vshr.u32 tmp0, W, #30; \
|
||||
|
||||
#define WPRECALC_32_79_7(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vorr W, tmp0, tmp1; \
|
||||
|
||||
#define WPRECALC_32_79_8(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vadd.u32 tmp0, W, curK; \
|
||||
|
||||
#define WPRECALC_32_79_9(i,W,W_m04,W_m08,W_m12,W_m16,W_m20,W_m24,W_m28) \
|
||||
vst1.32 {tmp0}, [RWK];
|
||||
|
||||
|
||||
/*
|
||||
* Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
|
||||
*
|
||||
* unsigned int
|
||||
* sha1_transform_neon (void *ctx, const unsigned char *data,
|
||||
* unsigned int nblks)
|
||||
*/
|
||||
.align 3
|
||||
ENTRY(sha1_transform_neon)
|
||||
/* input:
|
||||
* r0: ctx, CTX
|
||||
* r1: data (64*nblks bytes)
|
||||
* r2: nblks
|
||||
*/
|
||||
|
||||
cmp RNBLKS, #0;
|
||||
beq .Ldo_nothing;
|
||||
|
||||
push {r4-r12, lr};
|
||||
/*vpush {q4-q7};*/
|
||||
|
||||
adr RT3, .LK_VEC;
|
||||
|
||||
mov ROLDSTACK, sp;
|
||||
|
||||
/* Align stack. */
|
||||
sub RT0, sp, #(16*4);
|
||||
and RT0, #(~(16-1));
|
||||
mov sp, RT0;
|
||||
|
||||
vld1.32 {qK1-qK2}, [RT3]!; /* Load K1,K2 */
|
||||
|
||||
/* Get the values of the chaining variables. */
|
||||
ldm RSTATE, {_a-_e};
|
||||
|
||||
vld1.32 {qK3-qK4}, [RT3]; /* Load K3,K4 */
|
||||
|
||||
#undef curK
|
||||
#define curK qK1
|
||||
/* Precalc 0-15. */
|
||||
W_PRECALC_00_15();
|
||||
|
||||
.Loop:
|
||||
/* Transform 0-15 + Precalc 16-31. */
|
||||
_R( _a, _b, _c, _d, _e, F1, 0,
|
||||
WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 16,
|
||||
W4, W5, W6, W7, W0, _, _, _ );
|
||||
_R( _e, _a, _b, _c, _d, F1, 1,
|
||||
WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 16,
|
||||
W4, W5, W6, W7, W0, _, _, _ );
|
||||
_R( _d, _e, _a, _b, _c, F1, 2,
|
||||
WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 16,
|
||||
W4, W5, W6, W7, W0, _, _, _ );
|
||||
_R( _c, _d, _e, _a, _b, F1, 3,
|
||||
WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,16,
|
||||
W4, W5, W6, W7, W0, _, _, _ );
|
||||
|
||||
#undef curK
|
||||
#define curK qK2
|
||||
_R( _b, _c, _d, _e, _a, F1, 4,
|
||||
WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 20,
|
||||
W3, W4, W5, W6, W7, _, _, _ );
|
||||
_R( _a, _b, _c, _d, _e, F1, 5,
|
||||
WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 20,
|
||||
W3, W4, W5, W6, W7, _, _, _ );
|
||||
_R( _e, _a, _b, _c, _d, F1, 6,
|
||||
WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 20,
|
||||
W3, W4, W5, W6, W7, _, _, _ );
|
||||
_R( _d, _e, _a, _b, _c, F1, 7,
|
||||
WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,20,
|
||||
W3, W4, W5, W6, W7, _, _, _ );
|
||||
|
||||
_R( _c, _d, _e, _a, _b, F1, 8,
|
||||
WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 24,
|
||||
W2, W3, W4, W5, W6, _, _, _ );
|
||||
_R( _b, _c, _d, _e, _a, F1, 9,
|
||||
WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 24,
|
||||
W2, W3, W4, W5, W6, _, _, _ );
|
||||
_R( _a, _b, _c, _d, _e, F1, 10,
|
||||
WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 24,
|
||||
W2, W3, W4, W5, W6, _, _, _ );
|
||||
_R( _e, _a, _b, _c, _d, F1, 11,
|
||||
WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,24,
|
||||
W2, W3, W4, W5, W6, _, _, _ );
|
||||
|
||||
_R( _d, _e, _a, _b, _c, F1, 12,
|
||||
WPRECALC_16_31_0, WPRECALC_16_31_1, WPRECALC_16_31_2, 28,
|
||||
W1, W2, W3, W4, W5, _, _, _ );
|
||||
_R( _c, _d, _e, _a, _b, F1, 13,
|
||||
WPRECALC_16_31_3, WPRECALC_16_31_4, WPRECALC_16_31_5, 28,
|
||||
W1, W2, W3, W4, W5, _, _, _ );
|
||||
_R( _b, _c, _d, _e, _a, F1, 14,
|
||||
WPRECALC_16_31_6, WPRECALC_16_31_7, WPRECALC_16_31_8, 28,
|
||||
W1, W2, W3, W4, W5, _, _, _ );
|
||||
_R( _a, _b, _c, _d, _e, F1, 15,
|
||||
WPRECALC_16_31_9, WPRECALC_16_31_10,WPRECALC_16_31_11,28,
|
||||
W1, W2, W3, W4, W5, _, _, _ );
|
||||
|
||||
/* Transform 16-63 + Precalc 32-79. */
|
||||
_R( _e, _a, _b, _c, _d, F1, 16,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 32,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
_R( _d, _e, _a, _b, _c, F1, 17,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 32,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
_R( _c, _d, _e, _a, _b, F1, 18,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 32,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
_R( _b, _c, _d, _e, _a, F1, 19,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 32,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
|
||||
_R( _a, _b, _c, _d, _e, F2, 20,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 36,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
_R( _e, _a, _b, _c, _d, F2, 21,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 36,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
_R( _d, _e, _a, _b, _c, F2, 22,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 36,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
_R( _c, _d, _e, _a, _b, F2, 23,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 36,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
|
||||
#undef curK
|
||||
#define curK qK3
|
||||
_R( _b, _c, _d, _e, _a, F2, 24,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 40,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
_R( _a, _b, _c, _d, _e, F2, 25,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 40,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
_R( _e, _a, _b, _c, _d, F2, 26,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 40,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
_R( _d, _e, _a, _b, _c, F2, 27,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 40,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
|
||||
_R( _c, _d, _e, _a, _b, F2, 28,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 44,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
_R( _b, _c, _d, _e, _a, F2, 29,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 44,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
_R( _a, _b, _c, _d, _e, F2, 30,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 44,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
_R( _e, _a, _b, _c, _d, F2, 31,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 44,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
|
||||
_R( _d, _e, _a, _b, _c, F2, 32,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 48,
|
||||
W4, W5, W6, W7, W0, W1, W2, W3);
|
||||
_R( _c, _d, _e, _a, _b, F2, 33,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 48,
|
||||
W4, W5, W6, W7, W0, W1, W2, W3);
|
||||
_R( _b, _c, _d, _e, _a, F2, 34,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 48,
|
||||
W4, W5, W6, W7, W0, W1, W2, W3);
|
||||
_R( _a, _b, _c, _d, _e, F2, 35,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 48,
|
||||
W4, W5, W6, W7, W0, W1, W2, W3);
|
||||
|
||||
_R( _e, _a, _b, _c, _d, F2, 36,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 52,
|
||||
W3, W4, W5, W6, W7, W0, W1, W2);
|
||||
_R( _d, _e, _a, _b, _c, F2, 37,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 52,
|
||||
W3, W4, W5, W6, W7, W0, W1, W2);
|
||||
_R( _c, _d, _e, _a, _b, F2, 38,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 52,
|
||||
W3, W4, W5, W6, W7, W0, W1, W2);
|
||||
_R( _b, _c, _d, _e, _a, F2, 39,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 52,
|
||||
W3, W4, W5, W6, W7, W0, W1, W2);
|
||||
|
||||
_R( _a, _b, _c, _d, _e, F3, 40,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 56,
|
||||
W2, W3, W4, W5, W6, W7, W0, W1);
|
||||
_R( _e, _a, _b, _c, _d, F3, 41,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 56,
|
||||
W2, W3, W4, W5, W6, W7, W0, W1);
|
||||
_R( _d, _e, _a, _b, _c, F3, 42,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 56,
|
||||
W2, W3, W4, W5, W6, W7, W0, W1);
|
||||
_R( _c, _d, _e, _a, _b, F3, 43,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 56,
|
||||
W2, W3, W4, W5, W6, W7, W0, W1);
|
||||
|
||||
#undef curK
|
||||
#define curK qK4
|
||||
_R( _b, _c, _d, _e, _a, F3, 44,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 60,
|
||||
W1, W2, W3, W4, W5, W6, W7, W0);
|
||||
_R( _a, _b, _c, _d, _e, F3, 45,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 60,
|
||||
W1, W2, W3, W4, W5, W6, W7, W0);
|
||||
_R( _e, _a, _b, _c, _d, F3, 46,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 60,
|
||||
W1, W2, W3, W4, W5, W6, W7, W0);
|
||||
_R( _d, _e, _a, _b, _c, F3, 47,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 60,
|
||||
W1, W2, W3, W4, W5, W6, W7, W0);
|
||||
|
||||
_R( _c, _d, _e, _a, _b, F3, 48,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 64,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
_R( _b, _c, _d, _e, _a, F3, 49,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 64,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
_R( _a, _b, _c, _d, _e, F3, 50,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 64,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
_R( _e, _a, _b, _c, _d, F3, 51,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 64,
|
||||
W0, W1, W2, W3, W4, W5, W6, W7);
|
||||
|
||||
_R( _d, _e, _a, _b, _c, F3, 52,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 68,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
_R( _c, _d, _e, _a, _b, F3, 53,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 68,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
_R( _b, _c, _d, _e, _a, F3, 54,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 68,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
_R( _a, _b, _c, _d, _e, F3, 55,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 68,
|
||||
W7, W0, W1, W2, W3, W4, W5, W6);
|
||||
|
||||
_R( _e, _a, _b, _c, _d, F3, 56,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 72,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
_R( _d, _e, _a, _b, _c, F3, 57,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 72,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
_R( _c, _d, _e, _a, _b, F3, 58,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 72,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
_R( _b, _c, _d, _e, _a, F3, 59,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 72,
|
||||
W6, W7, W0, W1, W2, W3, W4, W5);
|
||||
|
||||
subs RNBLKS, #1;
|
||||
|
||||
_R( _a, _b, _c, _d, _e, F4, 60,
|
||||
WPRECALC_32_79_0, WPRECALC_32_79_1, WPRECALC_32_79_2, 76,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
_R( _e, _a, _b, _c, _d, F4, 61,
|
||||
WPRECALC_32_79_3, WPRECALC_32_79_4, WPRECALC_32_79_5, 76,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
_R( _d, _e, _a, _b, _c, F4, 62,
|
||||
WPRECALC_32_79_6, dummy, WPRECALC_32_79_7, 76,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
_R( _c, _d, _e, _a, _b, F4, 63,
|
||||
WPRECALC_32_79_8, dummy, WPRECALC_32_79_9, 76,
|
||||
W5, W6, W7, W0, W1, W2, W3, W4);
|
||||
|
||||
beq .Lend;
|
||||
|
||||
/* Transform 64-79 + Precalc 0-15 of next block. */
|
||||
#undef curK
|
||||
#define curK qK1
|
||||
_R( _b, _c, _d, _e, _a, F4, 64,
|
||||
WPRECALC_00_15_0, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _a, _b, _c, _d, _e, F4, 65,
|
||||
WPRECALC_00_15_1, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _e, _a, _b, _c, _d, F4, 66,
|
||||
WPRECALC_00_15_2, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _d, _e, _a, _b, _c, F4, 67,
|
||||
WPRECALC_00_15_3, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
|
||||
_R( _c, _d, _e, _a, _b, F4, 68,
|
||||
dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _b, _c, _d, _e, _a, F4, 69,
|
||||
dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _a, _b, _c, _d, _e, F4, 70,
|
||||
WPRECALC_00_15_4, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _e, _a, _b, _c, _d, F4, 71,
|
||||
WPRECALC_00_15_5, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
|
||||
_R( _d, _e, _a, _b, _c, F4, 72,
|
||||
dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _c, _d, _e, _a, _b, F4, 73,
|
||||
dummy, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _b, _c, _d, _e, _a, F4, 74,
|
||||
WPRECALC_00_15_6, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _a, _b, _c, _d, _e, F4, 75,
|
||||
WPRECALC_00_15_7, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
|
||||
_R( _e, _a, _b, _c, _d, F4, 76,
|
||||
WPRECALC_00_15_8, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _d, _e, _a, _b, _c, F4, 77,
|
||||
WPRECALC_00_15_9, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _c, _d, _e, _a, _b, F4, 78,
|
||||
WPRECALC_00_15_10, dummy, dummy, _, _, _, _, _, _, _, _, _ );
|
||||
_R( _b, _c, _d, _e, _a, F4, 79,
|
||||
WPRECALC_00_15_11, dummy, WPRECALC_00_15_12, _, _, _, _, _, _, _, _, _ );
|
||||
|
||||
/* Update the chaining variables. */
|
||||
ldm RSTATE, {RT0-RT3};
|
||||
add _a, RT0;
|
||||
ldr RT0, [RSTATE, #state_h4];
|
||||
add _b, RT1;
|
||||
add _c, RT2;
|
||||
add _d, RT3;
|
||||
add _e, RT0;
|
||||
stm RSTATE, {_a-_e};
|
||||
|
||||
b .Loop;
|
||||
|
||||
.Lend:
|
||||
/* Transform 64-79 */
|
||||
R( _b, _c, _d, _e, _a, F4, 64 );
|
||||
R( _a, _b, _c, _d, _e, F4, 65 );
|
||||
R( _e, _a, _b, _c, _d, F4, 66 );
|
||||
R( _d, _e, _a, _b, _c, F4, 67 );
|
||||
R( _c, _d, _e, _a, _b, F4, 68 );
|
||||
R( _b, _c, _d, _e, _a, F4, 69 );
|
||||
R( _a, _b, _c, _d, _e, F4, 70 );
|
||||
R( _e, _a, _b, _c, _d, F4, 71 );
|
||||
R( _d, _e, _a, _b, _c, F4, 72 );
|
||||
R( _c, _d, _e, _a, _b, F4, 73 );
|
||||
R( _b, _c, _d, _e, _a, F4, 74 );
|
||||
R( _a, _b, _c, _d, _e, F4, 75 );
|
||||
R( _e, _a, _b, _c, _d, F4, 76 );
|
||||
R( _d, _e, _a, _b, _c, F4, 77 );
|
||||
R( _c, _d, _e, _a, _b, F4, 78 );
|
||||
R( _b, _c, _d, _e, _a, F4, 79 );
|
||||
|
||||
mov sp, ROLDSTACK;
|
||||
|
||||
/* Update the chaining variables. */
|
||||
ldm RSTATE, {RT0-RT3};
|
||||
add _a, RT0;
|
||||
ldr RT0, [RSTATE, #state_h4];
|
||||
add _b, RT1;
|
||||
add _c, RT2;
|
||||
add _d, RT3;
|
||||
/*vpop {q4-q7};*/
|
||||
add _e, RT0;
|
||||
stm RSTATE, {_a-_e};
|
||||
|
||||
pop {r4-r12, pc};
|
||||
|
||||
.Ldo_nothing:
|
||||
bx lr
|
||||
ENDPROC(sha1_transform_neon)
|
||||
@@ -23,32 +23,27 @@
|
||||
#include <linux/types.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/crypto/sha1.h>
|
||||
|
||||
struct SHA1_CTX {
|
||||
uint32_t h0,h1,h2,h3,h4;
|
||||
u64 count;
|
||||
u8 data[SHA1_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
asmlinkage void sha1_block_data_order(struct SHA1_CTX *digest,
|
||||
asmlinkage void sha1_block_data_order(u32 *digest,
|
||||
const unsigned char *data, unsigned int rounds);
|
||||
|
||||
|
||||
static int sha1_init(struct shash_desc *desc)
|
||||
{
|
||||
struct SHA1_CTX *sctx = shash_desc_ctx(desc);
|
||||
memset(sctx, 0, sizeof(*sctx));
|
||||
sctx->h0 = SHA1_H0;
|
||||
sctx->h1 = SHA1_H1;
|
||||
sctx->h2 = SHA1_H2;
|
||||
sctx->h3 = SHA1_H3;
|
||||
sctx->h4 = SHA1_H4;
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
*sctx = (struct sha1_state){
|
||||
.state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __sha1_update(struct SHA1_CTX *sctx, const u8 *data,
|
||||
unsigned int len, unsigned int partial)
|
||||
static int __sha1_update(struct sha1_state *sctx, const u8 *data,
|
||||
unsigned int len, unsigned int partial)
|
||||
{
|
||||
unsigned int done = 0;
|
||||
|
||||
@@ -56,43 +51,44 @@ static int __sha1_update(struct SHA1_CTX *sctx, const u8 *data,
|
||||
|
||||
if (partial) {
|
||||
done = SHA1_BLOCK_SIZE - partial;
|
||||
memcpy(sctx->data + partial, data, done);
|
||||
sha1_block_data_order(sctx, sctx->data, 1);
|
||||
memcpy(sctx->buffer + partial, data, done);
|
||||
sha1_block_data_order(sctx->state, sctx->buffer, 1);
|
||||
}
|
||||
|
||||
if (len - done >= SHA1_BLOCK_SIZE) {
|
||||
const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE;
|
||||
sha1_block_data_order(sctx, data + done, rounds);
|
||||
sha1_block_data_order(sctx->state, data + done, rounds);
|
||||
done += rounds * SHA1_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy(sctx->data, data + done, len - done);
|
||||
memcpy(sctx->buffer, data + done, len - done);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int sha1_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
int sha1_update_arm(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
struct SHA1_CTX *sctx = shash_desc_ctx(desc);
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
|
||||
int res;
|
||||
|
||||
/* Handle the fast case right here */
|
||||
if (partial + len < SHA1_BLOCK_SIZE) {
|
||||
sctx->count += len;
|
||||
memcpy(sctx->data + partial, data, len);
|
||||
memcpy(sctx->buffer + partial, data, len);
|
||||
return 0;
|
||||
}
|
||||
res = __sha1_update(sctx, data, len, partial);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sha1_update_arm);
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
static int sha1_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
struct SHA1_CTX *sctx = shash_desc_ctx(desc);
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int i, index, padlen;
|
||||
__be32 *dst = (__be32 *)out;
|
||||
__be64 bits;
|
||||
@@ -106,7 +102,7 @@ static int sha1_final(struct shash_desc *desc, u8 *out)
|
||||
/* We need to fill a whole block for __sha1_update() */
|
||||
if (padlen <= 56) {
|
||||
sctx->count += padlen;
|
||||
memcpy(sctx->data + index, padding, padlen);
|
||||
memcpy(sctx->buffer + index, padding, padlen);
|
||||
} else {
|
||||
__sha1_update(sctx, padding, padlen, index);
|
||||
}
|
||||
@@ -114,7 +110,7 @@ static int sha1_final(struct shash_desc *desc, u8 *out)
|
||||
|
||||
/* Store state in digest */
|
||||
for (i = 0; i < 5; i++)
|
||||
dst[i] = cpu_to_be32(((u32 *)sctx)[i]);
|
||||
dst[i] = cpu_to_be32(sctx->state[i]);
|
||||
|
||||
/* Wipe context */
|
||||
memset(sctx, 0, sizeof(*sctx));
|
||||
@@ -124,7 +120,7 @@ static int sha1_final(struct shash_desc *desc, u8 *out)
|
||||
|
||||
static int sha1_export(struct shash_desc *desc, void *out)
|
||||
{
|
||||
struct SHA1_CTX *sctx = shash_desc_ctx(desc);
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
memcpy(out, sctx, sizeof(*sctx));
|
||||
return 0;
|
||||
}
|
||||
@@ -132,7 +128,7 @@ static int sha1_export(struct shash_desc *desc, void *out)
|
||||
|
||||
static int sha1_import(struct shash_desc *desc, const void *in)
|
||||
{
|
||||
struct SHA1_CTX *sctx = shash_desc_ctx(desc);
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
memcpy(sctx, in, sizeof(*sctx));
|
||||
return 0;
|
||||
}
|
||||
@@ -141,12 +137,12 @@ static int sha1_import(struct shash_desc *desc, const void *in)
|
||||
static struct shash_alg alg = {
|
||||
.digestsize = SHA1_DIGEST_SIZE,
|
||||
.init = sha1_init,
|
||||
.update = sha1_update,
|
||||
.update = sha1_update_arm,
|
||||
.final = sha1_final,
|
||||
.export = sha1_export,
|
||||
.import = sha1_import,
|
||||
.descsize = sizeof(struct SHA1_CTX),
|
||||
.statesize = sizeof(struct SHA1_CTX),
|
||||
.descsize = sizeof(struct sha1_state),
|
||||
.statesize = sizeof(struct sha1_state),
|
||||
.base = {
|
||||
.cra_name = "sha1",
|
||||
.cra_driver_name= "sha1-asm",
|
||||
|
||||
197
arch/arm/crypto/sha1_neon_glue.c
Normal file
197
arch/arm/crypto/sha1_neon_glue.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Glue code for the SHA1 Secure Hash Algorithm assembler implementation using
|
||||
* ARM NEON instructions.
|
||||
*
|
||||
* Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||
*
|
||||
* This file is based on sha1_generic.c and sha1_ssse3_glue.c:
|
||||
* Copyright (c) Alan Smithee.
|
||||
* Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
|
||||
* Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
|
||||
* Copyright (c) Mathias Krause <minipli@googlemail.com>
|
||||
* Copyright (c) Chandramouli Narayanan <mouli@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#include <linux/types.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/neon.h>
|
||||
#include <asm/simd.h>
|
||||
#include <asm/crypto/sha1.h>
|
||||
|
||||
|
||||
asmlinkage void sha1_transform_neon(void *state_h, const char *data,
|
||||
unsigned int rounds);
|
||||
|
||||
|
||||
static int sha1_neon_init(struct shash_desc *desc)
|
||||
{
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
*sctx = (struct sha1_state){
|
||||
.state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __sha1_neon_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len, unsigned int partial)
|
||||
{
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int done = 0;
|
||||
|
||||
sctx->count += len;
|
||||
|
||||
if (partial) {
|
||||
done = SHA1_BLOCK_SIZE - partial;
|
||||
memcpy(sctx->buffer + partial, data, done);
|
||||
sha1_transform_neon(sctx->state, sctx->buffer, 1);
|
||||
}
|
||||
|
||||
if (len - done >= SHA1_BLOCK_SIZE) {
|
||||
const unsigned int rounds = (len - done) / SHA1_BLOCK_SIZE;
|
||||
|
||||
sha1_transform_neon(sctx->state, data + done, rounds);
|
||||
done += rounds * SHA1_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy(sctx->buffer, data + done, len - done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha1_neon_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
|
||||
int res;
|
||||
|
||||
/* Handle the fast case right here */
|
||||
if (partial + len < SHA1_BLOCK_SIZE) {
|
||||
sctx->count += len;
|
||||
memcpy(sctx->buffer + partial, data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!may_use_simd()) {
|
||||
res = sha1_update_arm(desc, data, len);
|
||||
} else {
|
||||
kernel_neon_begin();
|
||||
res = __sha1_neon_update(desc, data, len, partial);
|
||||
kernel_neon_end();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
static int sha1_neon_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int i, index, padlen;
|
||||
__be32 *dst = (__be32 *)out;
|
||||
__be64 bits;
|
||||
static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, };
|
||||
|
||||
bits = cpu_to_be64(sctx->count << 3);
|
||||
|
||||
/* Pad out to 56 mod 64 and append length */
|
||||
index = sctx->count % SHA1_BLOCK_SIZE;
|
||||
padlen = (index < 56) ? (56 - index) : ((SHA1_BLOCK_SIZE+56) - index);
|
||||
if (!may_use_simd()) {
|
||||
sha1_update_arm(desc, padding, padlen);
|
||||
sha1_update_arm(desc, (const u8 *)&bits, sizeof(bits));
|
||||
} else {
|
||||
kernel_neon_begin();
|
||||
/* We need to fill a whole block for __sha1_neon_update() */
|
||||
if (padlen <= 56) {
|
||||
sctx->count += padlen;
|
||||
memcpy(sctx->buffer + index, padding, padlen);
|
||||
} else {
|
||||
__sha1_neon_update(desc, padding, padlen, index);
|
||||
}
|
||||
__sha1_neon_update(desc, (const u8 *)&bits, sizeof(bits), 56);
|
||||
kernel_neon_end();
|
||||
}
|
||||
|
||||
/* Store state in digest */
|
||||
for (i = 0; i < 5; i++)
|
||||
dst[i] = cpu_to_be32(sctx->state[i]);
|
||||
|
||||
/* Wipe context */
|
||||
memset(sctx, 0, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha1_neon_export(struct shash_desc *desc, void *out)
|
||||
{
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
memcpy(out, sctx, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha1_neon_import(struct shash_desc *desc, const void *in)
|
||||
{
|
||||
struct sha1_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
memcpy(sctx, in, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct shash_alg alg = {
|
||||
.digestsize = SHA1_DIGEST_SIZE,
|
||||
.init = sha1_neon_init,
|
||||
.update = sha1_neon_update,
|
||||
.final = sha1_neon_final,
|
||||
.export = sha1_neon_export,
|
||||
.import = sha1_neon_import,
|
||||
.descsize = sizeof(struct sha1_state),
|
||||
.statesize = sizeof(struct sha1_state),
|
||||
.base = {
|
||||
.cra_name = "sha1",
|
||||
.cra_driver_name = "sha1-neon",
|
||||
.cra_priority = 250,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA1_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init sha1_neon_mod_init(void)
|
||||
{
|
||||
if (!cpu_has_neon())
|
||||
return -ENODEV;
|
||||
|
||||
return crypto_register_shash(&alg);
|
||||
}
|
||||
|
||||
static void __exit sha1_neon_mod_fini(void)
|
||||
{
|
||||
crypto_unregister_shash(&alg);
|
||||
}
|
||||
|
||||
module_init(sha1_neon_mod_init);
|
||||
module_exit(sha1_neon_mod_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, NEON accelerated");
|
||||
MODULE_ALIAS("sha1");
|
||||
455
arch/arm/crypto/sha512-armv7-neon.S
Normal file
455
arch/arm/crypto/sha512-armv7-neon.S
Normal file
@@ -0,0 +1,455 @@
|
||||
/* sha512-armv7-neon.S - ARM/NEON assembly implementation of SHA-512 transform
|
||||
*
|
||||
* Copyright © 2013-2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
|
||||
|
||||
.syntax unified
|
||||
.code 32
|
||||
.fpu neon
|
||||
|
||||
.text
|
||||
|
||||
/* structure of SHA512_CONTEXT */
|
||||
#define hd_a 0
|
||||
#define hd_b ((hd_a) + 8)
|
||||
#define hd_c ((hd_b) + 8)
|
||||
#define hd_d ((hd_c) + 8)
|
||||
#define hd_e ((hd_d) + 8)
|
||||
#define hd_f ((hd_e) + 8)
|
||||
#define hd_g ((hd_f) + 8)
|
||||
|
||||
/* register macros */
|
||||
#define RK %r2
|
||||
|
||||
#define RA d0
|
||||
#define RB d1
|
||||
#define RC d2
|
||||
#define RD d3
|
||||
#define RE d4
|
||||
#define RF d5
|
||||
#define RG d6
|
||||
#define RH d7
|
||||
|
||||
#define RT0 d8
|
||||
#define RT1 d9
|
||||
#define RT2 d10
|
||||
#define RT3 d11
|
||||
#define RT4 d12
|
||||
#define RT5 d13
|
||||
#define RT6 d14
|
||||
#define RT7 d15
|
||||
|
||||
#define RT01q q4
|
||||
#define RT23q q5
|
||||
#define RT45q q6
|
||||
#define RT67q q7
|
||||
|
||||
#define RW0 d16
|
||||
#define RW1 d17
|
||||
#define RW2 d18
|
||||
#define RW3 d19
|
||||
#define RW4 d20
|
||||
#define RW5 d21
|
||||
#define RW6 d22
|
||||
#define RW7 d23
|
||||
#define RW8 d24
|
||||
#define RW9 d25
|
||||
#define RW10 d26
|
||||
#define RW11 d27
|
||||
#define RW12 d28
|
||||
#define RW13 d29
|
||||
#define RW14 d30
|
||||
#define RW15 d31
|
||||
|
||||
#define RW01q q8
|
||||
#define RW23q q9
|
||||
#define RW45q q10
|
||||
#define RW67q q11
|
||||
#define RW89q q12
|
||||
#define RW1011q q13
|
||||
#define RW1213q q14
|
||||
#define RW1415q q15
|
||||
|
||||
/***********************************************************************
|
||||
* ARM assembly implementation of sha512 transform
|
||||
***********************************************************************/
|
||||
#define rounds2_0_63(ra, rb, rc, rd, re, rf, rg, rh, rw0, rw1, rw01q, rw2, \
|
||||
rw23q, rw1415q, rw9, rw10, interleave_op, arg1) \
|
||||
/* t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; */ \
|
||||
vshr.u64 RT2, re, #14; \
|
||||
vshl.u64 RT3, re, #64 - 14; \
|
||||
interleave_op(arg1); \
|
||||
vshr.u64 RT4, re, #18; \
|
||||
vshl.u64 RT5, re, #64 - 18; \
|
||||
vld1.64 {RT0}, [RK]!; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, re, #41; \
|
||||
vshl.u64 RT5, re, #64 - 41; \
|
||||
vadd.u64 RT0, RT0, rw0; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vmov.64 RT7, re; \
|
||||
veor.64 RT1, RT2, RT3; \
|
||||
vbsl.64 RT7, rf, rg; \
|
||||
\
|
||||
vadd.u64 RT1, RT1, rh; \
|
||||
vshr.u64 RT2, ra, #28; \
|
||||
vshl.u64 RT3, ra, #64 - 28; \
|
||||
vadd.u64 RT1, RT1, RT0; \
|
||||
vshr.u64 RT4, ra, #34; \
|
||||
vshl.u64 RT5, ra, #64 - 34; \
|
||||
vadd.u64 RT1, RT1, RT7; \
|
||||
\
|
||||
/* h = Sum0 (a) + Maj (a, b, c); */ \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, ra, #39; \
|
||||
vshl.u64 RT5, ra, #64 - 39; \
|
||||
veor.64 RT0, ra, rb; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vbsl.64 RT0, rc, rb; \
|
||||
vadd.u64 rd, rd, RT1; /* d+=t1; */ \
|
||||
veor.64 rh, RT2, RT3; \
|
||||
\
|
||||
/* t1 = g + Sum1 (d) + Ch (d, e, f) + k[t] + w[t]; */ \
|
||||
vshr.u64 RT2, rd, #14; \
|
||||
vshl.u64 RT3, rd, #64 - 14; \
|
||||
vadd.u64 rh, rh, RT0; \
|
||||
vshr.u64 RT4, rd, #18; \
|
||||
vshl.u64 RT5, rd, #64 - 18; \
|
||||
vadd.u64 rh, rh, RT1; /* h+=t1; */ \
|
||||
vld1.64 {RT0}, [RK]!; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, rd, #41; \
|
||||
vshl.u64 RT5, rd, #64 - 41; \
|
||||
vadd.u64 RT0, RT0, rw1; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vmov.64 RT7, rd; \
|
||||
veor.64 RT1, RT2, RT3; \
|
||||
vbsl.64 RT7, re, rf; \
|
||||
\
|
||||
vadd.u64 RT1, RT1, rg; \
|
||||
vshr.u64 RT2, rh, #28; \
|
||||
vshl.u64 RT3, rh, #64 - 28; \
|
||||
vadd.u64 RT1, RT1, RT0; \
|
||||
vshr.u64 RT4, rh, #34; \
|
||||
vshl.u64 RT5, rh, #64 - 34; \
|
||||
vadd.u64 RT1, RT1, RT7; \
|
||||
\
|
||||
/* g = Sum0 (h) + Maj (h, a, b); */ \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, rh, #39; \
|
||||
vshl.u64 RT5, rh, #64 - 39; \
|
||||
veor.64 RT0, rh, ra; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vbsl.64 RT0, rb, ra; \
|
||||
vadd.u64 rc, rc, RT1; /* c+=t1; */ \
|
||||
veor.64 rg, RT2, RT3; \
|
||||
\
|
||||
/* w[0] += S1 (w[14]) + w[9] + S0 (w[1]); */ \
|
||||
/* w[1] += S1 (w[15]) + w[10] + S0 (w[2]); */ \
|
||||
\
|
||||
/**** S0(w[1:2]) */ \
|
||||
\
|
||||
/* w[0:1] += w[9:10] */ \
|
||||
/* RT23q = rw1:rw2 */ \
|
||||
vext.u64 RT23q, rw01q, rw23q, #1; \
|
||||
vadd.u64 rw0, rw9; \
|
||||
vadd.u64 rg, rg, RT0; \
|
||||
vadd.u64 rw1, rw10;\
|
||||
vadd.u64 rg, rg, RT1; /* g+=t1; */ \
|
||||
\
|
||||
vshr.u64 RT45q, RT23q, #1; \
|
||||
vshl.u64 RT67q, RT23q, #64 - 1; \
|
||||
vshr.u64 RT01q, RT23q, #8; \
|
||||
veor.u64 RT45q, RT45q, RT67q; \
|
||||
vshl.u64 RT67q, RT23q, #64 - 8; \
|
||||
veor.u64 RT45q, RT45q, RT01q; \
|
||||
vshr.u64 RT01q, RT23q, #7; \
|
||||
veor.u64 RT45q, RT45q, RT67q; \
|
||||
\
|
||||
/**** S1(w[14:15]) */ \
|
||||
vshr.u64 RT23q, rw1415q, #6; \
|
||||
veor.u64 RT01q, RT01q, RT45q; \
|
||||
vshr.u64 RT45q, rw1415q, #19; \
|
||||
vshl.u64 RT67q, rw1415q, #64 - 19; \
|
||||
veor.u64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT45q, rw1415q, #61; \
|
||||
veor.u64 RT23q, RT23q, RT67q; \
|
||||
vshl.u64 RT67q, rw1415q, #64 - 61; \
|
||||
veor.u64 RT23q, RT23q, RT45q; \
|
||||
vadd.u64 rw01q, RT01q; /* w[0:1] += S(w[1:2]) */ \
|
||||
veor.u64 RT01q, RT23q, RT67q;
|
||||
#define vadd_RT01q(rw01q) \
|
||||
/* w[0:1] += S(w[14:15]) */ \
|
||||
vadd.u64 rw01q, RT01q;
|
||||
|
||||
#define dummy(_) /*_*/
|
||||
|
||||
#define rounds2_64_79(ra, rb, rc, rd, re, rf, rg, rh, rw0, rw1, \
|
||||
interleave_op1, arg1, interleave_op2, arg2) \
|
||||
/* t1 = h + Sum1 (e) + Ch (e, f, g) + k[t] + w[t]; */ \
|
||||
vshr.u64 RT2, re, #14; \
|
||||
vshl.u64 RT3, re, #64 - 14; \
|
||||
interleave_op1(arg1); \
|
||||
vshr.u64 RT4, re, #18; \
|
||||
vshl.u64 RT5, re, #64 - 18; \
|
||||
interleave_op2(arg2); \
|
||||
vld1.64 {RT0}, [RK]!; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, re, #41; \
|
||||
vshl.u64 RT5, re, #64 - 41; \
|
||||
vadd.u64 RT0, RT0, rw0; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vmov.64 RT7, re; \
|
||||
veor.64 RT1, RT2, RT3; \
|
||||
vbsl.64 RT7, rf, rg; \
|
||||
\
|
||||
vadd.u64 RT1, RT1, rh; \
|
||||
vshr.u64 RT2, ra, #28; \
|
||||
vshl.u64 RT3, ra, #64 - 28; \
|
||||
vadd.u64 RT1, RT1, RT0; \
|
||||
vshr.u64 RT4, ra, #34; \
|
||||
vshl.u64 RT5, ra, #64 - 34; \
|
||||
vadd.u64 RT1, RT1, RT7; \
|
||||
\
|
||||
/* h = Sum0 (a) + Maj (a, b, c); */ \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, ra, #39; \
|
||||
vshl.u64 RT5, ra, #64 - 39; \
|
||||
veor.64 RT0, ra, rb; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vbsl.64 RT0, rc, rb; \
|
||||
vadd.u64 rd, rd, RT1; /* d+=t1; */ \
|
||||
veor.64 rh, RT2, RT3; \
|
||||
\
|
||||
/* t1 = g + Sum1 (d) + Ch (d, e, f) + k[t] + w[t]; */ \
|
||||
vshr.u64 RT2, rd, #14; \
|
||||
vshl.u64 RT3, rd, #64 - 14; \
|
||||
vadd.u64 rh, rh, RT0; \
|
||||
vshr.u64 RT4, rd, #18; \
|
||||
vshl.u64 RT5, rd, #64 - 18; \
|
||||
vadd.u64 rh, rh, RT1; /* h+=t1; */ \
|
||||
vld1.64 {RT0}, [RK]!; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, rd, #41; \
|
||||
vshl.u64 RT5, rd, #64 - 41; \
|
||||
vadd.u64 RT0, RT0, rw1; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vmov.64 RT7, rd; \
|
||||
veor.64 RT1, RT2, RT3; \
|
||||
vbsl.64 RT7, re, rf; \
|
||||
\
|
||||
vadd.u64 RT1, RT1, rg; \
|
||||
vshr.u64 RT2, rh, #28; \
|
||||
vshl.u64 RT3, rh, #64 - 28; \
|
||||
vadd.u64 RT1, RT1, RT0; \
|
||||
vshr.u64 RT4, rh, #34; \
|
||||
vshl.u64 RT5, rh, #64 - 34; \
|
||||
vadd.u64 RT1, RT1, RT7; \
|
||||
\
|
||||
/* g = Sum0 (h) + Maj (h, a, b); */ \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vshr.u64 RT4, rh, #39; \
|
||||
vshl.u64 RT5, rh, #64 - 39; \
|
||||
veor.64 RT0, rh, ra; \
|
||||
veor.64 RT23q, RT23q, RT45q; \
|
||||
vbsl.64 RT0, rb, ra; \
|
||||
vadd.u64 rc, rc, RT1; /* c+=t1; */ \
|
||||
veor.64 rg, RT2, RT3;
|
||||
#define vadd_rg_RT0(rg) \
|
||||
vadd.u64 rg, rg, RT0;
|
||||
#define vadd_rg_RT1(rg) \
|
||||
vadd.u64 rg, rg, RT1; /* g+=t1; */
|
||||
|
||||
.align 3
|
||||
ENTRY(sha512_transform_neon)
|
||||
/* Input:
|
||||
* %r0: SHA512_CONTEXT
|
||||
* %r1: data
|
||||
* %r2: u64 k[] constants
|
||||
* %r3: nblks
|
||||
*/
|
||||
push {%lr};
|
||||
|
||||
mov %lr, #0;
|
||||
|
||||
/* Load context to d0-d7 */
|
||||
vld1.64 {RA-RD}, [%r0]!;
|
||||
vld1.64 {RE-RH}, [%r0];
|
||||
sub %r0, #(4*8);
|
||||
|
||||
/* Load input to w[16], d16-d31 */
|
||||
/* NOTE: Assumes that on ARMv7 unaligned accesses are always allowed. */
|
||||
vld1.64 {RW0-RW3}, [%r1]!;
|
||||
vld1.64 {RW4-RW7}, [%r1]!;
|
||||
vld1.64 {RW8-RW11}, [%r1]!;
|
||||
vld1.64 {RW12-RW15}, [%r1]!;
|
||||
#ifdef __ARMEL__
|
||||
/* byteswap */
|
||||
vrev64.8 RW01q, RW01q;
|
||||
vrev64.8 RW23q, RW23q;
|
||||
vrev64.8 RW45q, RW45q;
|
||||
vrev64.8 RW67q, RW67q;
|
||||
vrev64.8 RW89q, RW89q;
|
||||
vrev64.8 RW1011q, RW1011q;
|
||||
vrev64.8 RW1213q, RW1213q;
|
||||
vrev64.8 RW1415q, RW1415q;
|
||||
#endif
|
||||
|
||||
/* EABI says that d8-d15 must be preserved by callee. */
|
||||
/*vpush {RT0-RT7};*/
|
||||
|
||||
.Loop:
|
||||
rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, RW01q, RW2,
|
||||
RW23q, RW1415q, RW9, RW10, dummy, _);
|
||||
b .Lenter_rounds;
|
||||
|
||||
.Loop_rounds:
|
||||
rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1, RW01q, RW2,
|
||||
RW23q, RW1415q, RW9, RW10, vadd_RT01q, RW1415q);
|
||||
.Lenter_rounds:
|
||||
rounds2_0_63(RG, RH, RA, RB, RC, RD, RE, RF, RW2, RW3, RW23q, RW4,
|
||||
RW45q, RW01q, RW11, RW12, vadd_RT01q, RW01q);
|
||||
rounds2_0_63(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5, RW45q, RW6,
|
||||
RW67q, RW23q, RW13, RW14, vadd_RT01q, RW23q);
|
||||
rounds2_0_63(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7, RW67q, RW8,
|
||||
RW89q, RW45q, RW15, RW0, vadd_RT01q, RW45q);
|
||||
rounds2_0_63(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9, RW89q, RW10,
|
||||
RW1011q, RW67q, RW1, RW2, vadd_RT01q, RW67q);
|
||||
rounds2_0_63(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11, RW1011q, RW12,
|
||||
RW1213q, RW89q, RW3, RW4, vadd_RT01q, RW89q);
|
||||
add %lr, #16;
|
||||
rounds2_0_63(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13, RW1213q, RW14,
|
||||
RW1415q, RW1011q, RW5, RW6, vadd_RT01q, RW1011q);
|
||||
cmp %lr, #64;
|
||||
rounds2_0_63(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15, RW1415q, RW0,
|
||||
RW01q, RW1213q, RW7, RW8, vadd_RT01q, RW1213q);
|
||||
bne .Loop_rounds;
|
||||
|
||||
subs %r3, #1;
|
||||
|
||||
rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW0, RW1,
|
||||
vadd_RT01q, RW1415q, dummy, _);
|
||||
rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW2, RW3,
|
||||
vadd_rg_RT0, RG, vadd_rg_RT1, RG);
|
||||
beq .Lhandle_tail;
|
||||
vld1.64 {RW0-RW3}, [%r1]!;
|
||||
rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5,
|
||||
vadd_rg_RT0, RE, vadd_rg_RT1, RE);
|
||||
rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7,
|
||||
vadd_rg_RT0, RC, vadd_rg_RT1, RC);
|
||||
#ifdef __ARMEL__
|
||||
vrev64.8 RW01q, RW01q;
|
||||
vrev64.8 RW23q, RW23q;
|
||||
#endif
|
||||
vld1.64 {RW4-RW7}, [%r1]!;
|
||||
rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9,
|
||||
vadd_rg_RT0, RA, vadd_rg_RT1, RA);
|
||||
rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11,
|
||||
vadd_rg_RT0, RG, vadd_rg_RT1, RG);
|
||||
#ifdef __ARMEL__
|
||||
vrev64.8 RW45q, RW45q;
|
||||
vrev64.8 RW67q, RW67q;
|
||||
#endif
|
||||
vld1.64 {RW8-RW11}, [%r1]!;
|
||||
rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13,
|
||||
vadd_rg_RT0, RE, vadd_rg_RT1, RE);
|
||||
rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15,
|
||||
vadd_rg_RT0, RC, vadd_rg_RT1, RC);
|
||||
#ifdef __ARMEL__
|
||||
vrev64.8 RW89q, RW89q;
|
||||
vrev64.8 RW1011q, RW1011q;
|
||||
#endif
|
||||
vld1.64 {RW12-RW15}, [%r1]!;
|
||||
vadd_rg_RT0(RA);
|
||||
vadd_rg_RT1(RA);
|
||||
|
||||
/* Load context */
|
||||
vld1.64 {RT0-RT3}, [%r0]!;
|
||||
vld1.64 {RT4-RT7}, [%r0];
|
||||
sub %r0, #(4*8);
|
||||
|
||||
#ifdef __ARMEL__
|
||||
vrev64.8 RW1213q, RW1213q;
|
||||
vrev64.8 RW1415q, RW1415q;
|
||||
#endif
|
||||
|
||||
vadd.u64 RA, RT0;
|
||||
vadd.u64 RB, RT1;
|
||||
vadd.u64 RC, RT2;
|
||||
vadd.u64 RD, RT3;
|
||||
vadd.u64 RE, RT4;
|
||||
vadd.u64 RF, RT5;
|
||||
vadd.u64 RG, RT6;
|
||||
vadd.u64 RH, RT7;
|
||||
|
||||
/* Store the first half of context */
|
||||
vst1.64 {RA-RD}, [%r0]!;
|
||||
sub RK, $(8*80);
|
||||
vst1.64 {RE-RH}, [%r0]; /* Store the last half of context */
|
||||
mov %lr, #0;
|
||||
sub %r0, #(4*8);
|
||||
|
||||
b .Loop;
|
||||
|
||||
.Lhandle_tail:
|
||||
rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW4, RW5,
|
||||
vadd_rg_RT0, RE, vadd_rg_RT1, RE);
|
||||
rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW6, RW7,
|
||||
vadd_rg_RT0, RC, vadd_rg_RT1, RC);
|
||||
rounds2_64_79(RA, RB, RC, RD, RE, RF, RG, RH, RW8, RW9,
|
||||
vadd_rg_RT0, RA, vadd_rg_RT1, RA);
|
||||
rounds2_64_79(RG, RH, RA, RB, RC, RD, RE, RF, RW10, RW11,
|
||||
vadd_rg_RT0, RG, vadd_rg_RT1, RG);
|
||||
rounds2_64_79(RE, RF, RG, RH, RA, RB, RC, RD, RW12, RW13,
|
||||
vadd_rg_RT0, RE, vadd_rg_RT1, RE);
|
||||
rounds2_64_79(RC, RD, RE, RF, RG, RH, RA, RB, RW14, RW15,
|
||||
vadd_rg_RT0, RC, vadd_rg_RT1, RC);
|
||||
|
||||
/* Load context to d16-d23 */
|
||||
vld1.64 {RW0-RW3}, [%r0]!;
|
||||
vadd_rg_RT0(RA);
|
||||
vld1.64 {RW4-RW7}, [%r0];
|
||||
vadd_rg_RT1(RA);
|
||||
sub %r0, #(4*8);
|
||||
|
||||
vadd.u64 RA, RW0;
|
||||
vadd.u64 RB, RW1;
|
||||
vadd.u64 RC, RW2;
|
||||
vadd.u64 RD, RW3;
|
||||
vadd.u64 RE, RW4;
|
||||
vadd.u64 RF, RW5;
|
||||
vadd.u64 RG, RW6;
|
||||
vadd.u64 RH, RW7;
|
||||
|
||||
/* Store the first half of context */
|
||||
vst1.64 {RA-RD}, [%r0]!;
|
||||
|
||||
/* Clear used registers */
|
||||
/* d16-d31 */
|
||||
veor.u64 RW01q, RW01q;
|
||||
veor.u64 RW23q, RW23q;
|
||||
veor.u64 RW45q, RW45q;
|
||||
veor.u64 RW67q, RW67q;
|
||||
vst1.64 {RE-RH}, [%r0]; /* Store the last half of context */
|
||||
veor.u64 RW89q, RW89q;
|
||||
veor.u64 RW1011q, RW1011q;
|
||||
veor.u64 RW1213q, RW1213q;
|
||||
veor.u64 RW1415q, RW1415q;
|
||||
/* d8-d15 */
|
||||
/*vpop {RT0-RT7};*/
|
||||
/* d0-d7 (q0-q3) */
|
||||
veor.u64 %q0, %q0;
|
||||
veor.u64 %q1, %q1;
|
||||
veor.u64 %q2, %q2;
|
||||
veor.u64 %q3, %q3;
|
||||
|
||||
pop {%pc};
|
||||
ENDPROC(sha512_transform_neon)
|
||||
305
arch/arm/crypto/sha512_neon_glue.c
Normal file
305
arch/arm/crypto/sha512_neon_glue.c
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Glue code for the SHA512 Secure Hash Algorithm assembly implementation
|
||||
* using NEON instructions.
|
||||
*
|
||||
* Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||
*
|
||||
* This file is based on sha512_ssse3_glue.c:
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
* Author: Tim Chen <tim.c.chen@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/simd.h>
|
||||
#include <asm/neon.h>
|
||||
|
||||
|
||||
static const u64 sha512_k[] = {
|
||||
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
|
||||
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
|
||||
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
|
||||
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
|
||||
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
|
||||
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
|
||||
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
|
||||
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
|
||||
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
|
||||
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
|
||||
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
|
||||
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
|
||||
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
|
||||
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
|
||||
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
|
||||
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
|
||||
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
|
||||
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
|
||||
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
|
||||
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
|
||||
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
|
||||
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
|
||||
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
|
||||
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
|
||||
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
|
||||
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
|
||||
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
|
||||
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
|
||||
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
|
||||
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
|
||||
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
|
||||
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
|
||||
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
|
||||
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
|
||||
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
|
||||
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
|
||||
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
|
||||
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
|
||||
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
||||
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
|
||||
};
|
||||
|
||||
|
||||
asmlinkage void sha512_transform_neon(u64 *digest, const void *data,
|
||||
const u64 k[], unsigned int num_blks);
|
||||
|
||||
|
||||
static int sha512_neon_init(struct shash_desc *desc)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
sctx->state[0] = SHA512_H0;
|
||||
sctx->state[1] = SHA512_H1;
|
||||
sctx->state[2] = SHA512_H2;
|
||||
sctx->state[3] = SHA512_H3;
|
||||
sctx->state[4] = SHA512_H4;
|
||||
sctx->state[5] = SHA512_H5;
|
||||
sctx->state[6] = SHA512_H6;
|
||||
sctx->state[7] = SHA512_H7;
|
||||
sctx->count[0] = sctx->count[1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __sha512_neon_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len, unsigned int partial)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int done = 0;
|
||||
|
||||
sctx->count[0] += len;
|
||||
if (sctx->count[0] < len)
|
||||
sctx->count[1]++;
|
||||
|
||||
if (partial) {
|
||||
done = SHA512_BLOCK_SIZE - partial;
|
||||
memcpy(sctx->buf + partial, data, done);
|
||||
sha512_transform_neon(sctx->state, sctx->buf, sha512_k, 1);
|
||||
}
|
||||
|
||||
if (len - done >= SHA512_BLOCK_SIZE) {
|
||||
const unsigned int rounds = (len - done) / SHA512_BLOCK_SIZE;
|
||||
|
||||
sha512_transform_neon(sctx->state, data + done, sha512_k,
|
||||
rounds);
|
||||
|
||||
done += rounds * SHA512_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy(sctx->buf, data + done, len - done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha512_neon_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
|
||||
int res;
|
||||
|
||||
/* Handle the fast case right here */
|
||||
if (partial + len < SHA512_BLOCK_SIZE) {
|
||||
sctx->count[0] += len;
|
||||
if (sctx->count[0] < len)
|
||||
sctx->count[1]++;
|
||||
memcpy(sctx->buf + partial, data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!may_use_simd()) {
|
||||
res = crypto_sha512_update(desc, data, len);
|
||||
} else {
|
||||
kernel_neon_begin();
|
||||
res = __sha512_neon_update(desc, data, len, partial);
|
||||
kernel_neon_end();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
static int sha512_neon_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int i, index, padlen;
|
||||
__be64 *dst = (__be64 *)out;
|
||||
__be64 bits[2];
|
||||
static const u8 padding[SHA512_BLOCK_SIZE] = { 0x80, };
|
||||
|
||||
/* save number of bits */
|
||||
bits[1] = cpu_to_be64(sctx->count[0] << 3);
|
||||
bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
|
||||
|
||||
/* Pad out to 112 mod 128 and append length */
|
||||
index = sctx->count[0] & 0x7f;
|
||||
padlen = (index < 112) ? (112 - index) : ((128+112) - index);
|
||||
|
||||
if (!may_use_simd()) {
|
||||
crypto_sha512_update(desc, padding, padlen);
|
||||
crypto_sha512_update(desc, (const u8 *)&bits, sizeof(bits));
|
||||
} else {
|
||||
kernel_neon_begin();
|
||||
/* We need to fill a whole block for __sha512_neon_update() */
|
||||
if (padlen <= 112) {
|
||||
sctx->count[0] += padlen;
|
||||
if (sctx->count[0] < padlen)
|
||||
sctx->count[1]++;
|
||||
memcpy(sctx->buf + index, padding, padlen);
|
||||
} else {
|
||||
__sha512_neon_update(desc, padding, padlen, index);
|
||||
}
|
||||
__sha512_neon_update(desc, (const u8 *)&bits,
|
||||
sizeof(bits), 112);
|
||||
kernel_neon_end();
|
||||
}
|
||||
|
||||
/* Store state in digest */
|
||||
for (i = 0; i < 8; i++)
|
||||
dst[i] = cpu_to_be64(sctx->state[i]);
|
||||
|
||||
/* Wipe context */
|
||||
memset(sctx, 0, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha512_neon_export(struct shash_desc *desc, void *out)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
memcpy(out, sctx, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha512_neon_import(struct shash_desc *desc, const void *in)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
memcpy(sctx, in, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha384_neon_init(struct shash_desc *desc)
|
||||
{
|
||||
struct sha512_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
sctx->state[0] = SHA384_H0;
|
||||
sctx->state[1] = SHA384_H1;
|
||||
sctx->state[2] = SHA384_H2;
|
||||
sctx->state[3] = SHA384_H3;
|
||||
sctx->state[4] = SHA384_H4;
|
||||
sctx->state[5] = SHA384_H5;
|
||||
sctx->state[6] = SHA384_H6;
|
||||
sctx->state[7] = SHA384_H7;
|
||||
|
||||
sctx->count[0] = sctx->count[1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha384_neon_final(struct shash_desc *desc, u8 *hash)
|
||||
{
|
||||
u8 D[SHA512_DIGEST_SIZE];
|
||||
|
||||
sha512_neon_final(desc, D);
|
||||
|
||||
memcpy(hash, D, SHA384_DIGEST_SIZE);
|
||||
memset(D, 0, SHA512_DIGEST_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct shash_alg algs[] = { {
|
||||
.digestsize = SHA512_DIGEST_SIZE,
|
||||
.init = sha512_neon_init,
|
||||
.update = sha512_neon_update,
|
||||
.final = sha512_neon_final,
|
||||
.export = sha512_neon_export,
|
||||
.import = sha512_neon_import,
|
||||
.descsize = sizeof(struct sha512_state),
|
||||
.statesize = sizeof(struct sha512_state),
|
||||
.base = {
|
||||
.cra_name = "sha512",
|
||||
.cra_driver_name = "sha512-neon",
|
||||
.cra_priority = 250,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA512_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
}, {
|
||||
.digestsize = SHA384_DIGEST_SIZE,
|
||||
.init = sha384_neon_init,
|
||||
.update = sha512_neon_update,
|
||||
.final = sha384_neon_final,
|
||||
.export = sha512_neon_export,
|
||||
.import = sha512_neon_import,
|
||||
.descsize = sizeof(struct sha512_state),
|
||||
.statesize = sizeof(struct sha512_state),
|
||||
.base = {
|
||||
.cra_name = "sha384",
|
||||
.cra_driver_name = "sha384-neon",
|
||||
.cra_priority = 250,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA384_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
} };
|
||||
|
||||
static int __init sha512_neon_mod_init(void)
|
||||
{
|
||||
if (!cpu_has_neon())
|
||||
return -ENODEV;
|
||||
|
||||
return crypto_register_shashes(algs, ARRAY_SIZE(algs));
|
||||
}
|
||||
|
||||
static void __exit sha512_neon_mod_fini(void)
|
||||
{
|
||||
crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
|
||||
}
|
||||
|
||||
module_init(sha512_neon_mod_init);
|
||||
module_exit(sha512_neon_mod_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SHA512 Secure Hash Algorithm, NEON accelerated");
|
||||
|
||||
MODULE_ALIAS("sha512");
|
||||
MODULE_ALIAS("sha384");
|
||||
@@ -24,6 +24,7 @@ generic-y += sembuf.h
|
||||
generic-y += serial.h
|
||||
generic-y += shmbuf.h
|
||||
generic-y += siginfo.h
|
||||
generic-y += simd.h
|
||||
generic-y += sizes.h
|
||||
generic-y += socket.h
|
||||
generic-y += sockios.h
|
||||
|
||||
10
arch/arm/include/asm/crypto/sha1.h
Normal file
10
arch/arm/include/asm/crypto/sha1.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef ASM_ARM_CRYPTO_SHA1_H
|
||||
#define ASM_ARM_CRYPTO_SHA1_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/sha.h>
|
||||
|
||||
extern int sha1_update_arm(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len);
|
||||
|
||||
#endif
|
||||
36
arch/arm/include/asm/neon.h
Normal file
36
arch/arm/include/asm/neon.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* linux/arch/arm/include/asm/neon.h
|
||||
*
|
||||
* Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#define cpu_has_neon() (!!(elf_hwcap & HWCAP_NEON))
|
||||
|
||||
#ifdef __ARM_NEON__
|
||||
|
||||
/*
|
||||
* If you are affected by the BUILD_BUG below, it probably means that you are
|
||||
* using NEON code /and/ calling the kernel_neon_begin() function from the same
|
||||
* compilation unit. To prevent issues that may arise from GCC reordering or
|
||||
* generating(1) NEON instructions outside of these begin/end functions, the
|
||||
* only supported way of using NEON code in the kernel is by isolating it in a
|
||||
* separate compilation unit, and calling it from another unit from inside a
|
||||
* kernel_neon_begin/kernel_neon_end pair.
|
||||
*
|
||||
* (1) Current GCC (4.7) might generate NEON instructions at O3 level if
|
||||
* -mpfu=neon is set.
|
||||
*/
|
||||
|
||||
#define kernel_neon_begin() \
|
||||
BUILD_BUG_ON_MSG(1, "kernel_neon_begin() called from NEON code")
|
||||
|
||||
#else
|
||||
void kernel_neon_begin(void);
|
||||
#endif
|
||||
void kernel_neon_end(void);
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/cp15.h>
|
||||
#include <asm/cputype.h>
|
||||
@@ -648,6 +649,52 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action,
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KERNEL_MODE_NEON
|
||||
|
||||
/*
|
||||
* Kernel-side NEON support functions
|
||||
*/
|
||||
void kernel_neon_begin(void)
|
||||
{
|
||||
struct thread_info *thread = current_thread_info();
|
||||
unsigned int cpu;
|
||||
u32 fpexc;
|
||||
|
||||
/*
|
||||
* Kernel mode NEON is only allowed outside of interrupt context
|
||||
* with preemption disabled. This will make sure that the kernel
|
||||
* mode NEON register contents never need to be preserved.
|
||||
*/
|
||||
BUG_ON(in_interrupt());
|
||||
cpu = get_cpu();
|
||||
|
||||
fpexc = fmrx(FPEXC) | FPEXC_EN;
|
||||
fmxr(FPEXC, fpexc);
|
||||
|
||||
/*
|
||||
* Save the userland NEON/VFP state. Under UP,
|
||||
* the owner could be a task other than 'current'
|
||||
*/
|
||||
if (vfp_state_in_hw(cpu, thread))
|
||||
vfp_save_state(&thread->vfpstate, fpexc);
|
||||
#ifndef CONFIG_SMP
|
||||
else if (vfp_current_hw_state[cpu] != NULL)
|
||||
vfp_save_state(vfp_current_hw_state[cpu], fpexc);
|
||||
#endif
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_neon_begin);
|
||||
|
||||
void kernel_neon_end(void)
|
||||
{
|
||||
/* Disable the NEON/VFP unit. */
|
||||
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
||||
put_cpu();
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_neon_end);
|
||||
|
||||
#endif /* CONFIG_KERNEL_MODE_NEON */
|
||||
|
||||
/*
|
||||
* VFP support code initialisation.
|
||||
*/
|
||||
@@ -731,4 +778,4 @@ static int __init vfp_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(vfp_init);
|
||||
core_initcall(vfp_init);
|
||||
|
||||
@@ -533,6 +533,17 @@ config CRYPTO_SHA1_PPC
|
||||
This is the powerpc hardware accelerated implementation of the
|
||||
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
|
||||
|
||||
config CRYPTO_SHA1_ARM_NEON
|
||||
tristate "SHA1 digest algorithm (ARM NEON)"
|
||||
depends on ARM && KERNEL_MODE_NEON && !CPU_BIG_ENDIAN
|
||||
select CRYPTO_SHA1_ARM
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_HASH
|
||||
help
|
||||
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented
|
||||
using optimized ARM NEON assembly, when NEON instructions are
|
||||
available.
|
||||
|
||||
config CRYPTO_SHA256
|
||||
tristate "SHA224 and SHA256 digest algorithm"
|
||||
select CRYPTO_HASH
|
||||
@@ -566,6 +577,21 @@ config CRYPTO_SHA512
|
||||
This code also includes SHA-384, a 384 bit hash with 192 bits
|
||||
of security against collision attacks.
|
||||
|
||||
config CRYPTO_SHA512_ARM_NEON
|
||||
tristate "SHA384 and SHA512 digest algorithm (ARM NEON)"
|
||||
depends on ARM && KERNEL_MODE_NEON && !CPU_BIG_ENDIAN
|
||||
select CRYPTO_SHA512
|
||||
select CRYPTO_HASH
|
||||
help
|
||||
SHA-512 secure hash standard (DFIPS 180-2) implemented
|
||||
using ARM NEON instructions, when available.
|
||||
|
||||
This version of SHA implements a 512 bit hash with 256 bits of
|
||||
security against collision attacks.
|
||||
|
||||
This code also includes SHA-384, a 384 bit hash with 192 bits
|
||||
of security against collision attacks.
|
||||
|
||||
config CRYPTO_SHA512_SPARC64
|
||||
tristate "SHA384 and SHA512 digest algorithm (SPARC64)"
|
||||
depends on SPARC64
|
||||
@@ -761,6 +787,22 @@ config CRYPTO_AES_ARM
|
||||
|
||||
See <http://csrc.nist.gov/encryption/aes/> for more information.
|
||||
|
||||
config CRYPTO_AES_ARM_BS
|
||||
tristate "Bit sliced AES using NEON instructions"
|
||||
depends on ARM && KERNEL_MODE_NEON
|
||||
select CRYPTO_ALGAPI
|
||||
select CRYPTO_AES_ARM
|
||||
select CRYPTO_ABLK_HELPER
|
||||
help
|
||||
Use a faster and more secure NEON based implementation of AES in CBC,
|
||||
CTR and XTS modes
|
||||
|
||||
Bit sliced AES gives around 45% speedup on Cortex-A15 for CTR mode
|
||||
and for XTS mode encryption, CBC and XTS mode decryption speedup is
|
||||
around 25%. (CBC encryption speed is not affected by this driver.)
|
||||
This implementation does not rely on any lookup tables so it is
|
||||
believed to be invulnerable to cache timing attacks.
|
||||
|
||||
config CRYPTO_ANUBIS
|
||||
tristate "Anubis cipher algorithm"
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -168,4 +168,6 @@ source "drivers/ipack/Kconfig"
|
||||
|
||||
source "drivers/reset/Kconfig"
|
||||
|
||||
source "drivers/android/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -153,3 +153,4 @@ obj-$(CONFIG_IIO) += iio/
|
||||
obj-$(CONFIG_VME_BUS) += vme/
|
||||
obj-$(CONFIG_IPACK_BUS) += ipack/
|
||||
obj-$(CONFIG_NTB) += ntb/
|
||||
obj-$(CONFIG_ANDROID) += android/
|
||||
|
||||
37
drivers/android/Kconfig
Normal file
37
drivers/android/Kconfig
Normal file
@@ -0,0 +1,37 @@
|
||||
menu "Android"
|
||||
|
||||
config ANDROID
|
||||
bool "Android Drivers"
|
||||
---help---
|
||||
Enable support for various drivers needed on the Android platform
|
||||
|
||||
if ANDROID
|
||||
|
||||
config ANDROID_BINDER_IPC
|
||||
bool "Android Binder IPC Driver"
|
||||
depends on MMU
|
||||
default n
|
||||
---help---
|
||||
Binder is used in Android for both communication between processes,
|
||||
and remote method invocation.
|
||||
|
||||
This means one Android process can call a method/routine in another
|
||||
Android process, using Binder to identify, invoke and pass arguments
|
||||
between said processes.
|
||||
|
||||
config ANDROID_BINDER_IPC_32BIT
|
||||
bool
|
||||
depends on !64BIT && ANDROID_BINDER_IPC
|
||||
default y
|
||||
---help---
|
||||
The Binder API has been changed to support both 32 and 64bit
|
||||
applications in a mixed environment.
|
||||
|
||||
Enable this to support an old 32-bit Android user-space (v4.4 and
|
||||
earlier).
|
||||
|
||||
Note that enabling this will break newer Android user-space.
|
||||
|
||||
endif # if ANDROID
|
||||
|
||||
endmenu
|
||||
3
drivers/android/Makefile
Normal file
3
drivers/android/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
ccflags-y += -I$(src) # needed for trace events
|
||||
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
|
||||
@@ -40,7 +40,11 @@
|
||||
#include <linux/pid_namespace.h>
|
||||
#include <linux/security.h>
|
||||
|
||||
#include "binder.h"
|
||||
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
|
||||
#define BINDER_IPC_32BIT 1
|
||||
#endif
|
||||
|
||||
#include <uapi/linux/android/binder.h>
|
||||
#include "binder_trace.h"
|
||||
|
||||
static DEFINE_RT_MUTEX(binder_main_lock);
|
||||
@@ -120,6 +124,7 @@ static int binder_set_stop_on_user_error(const char *val,
|
||||
struct kernel_param *kp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = param_set_int(val, kp);
|
||||
if (binder_stop_on_user_error < 2)
|
||||
wake_up(&binder_user_error_wait);
|
||||
@@ -196,6 +201,7 @@ static struct binder_transaction_log_entry *binder_transaction_log_add(
|
||||
struct binder_transaction_log *log)
|
||||
{
|
||||
struct binder_transaction_log_entry *e;
|
||||
|
||||
e = &log->entry[log->next];
|
||||
memset(e, 0, sizeof(*e));
|
||||
log->next++;
|
||||
@@ -434,6 +440,7 @@ static inline void binder_unlock(const char *tag)
|
||||
static void binder_set_nice(long nice)
|
||||
{
|
||||
long min_nice;
|
||||
|
||||
if (can_nice(current, nice)) {
|
||||
set_user_nice(current, nice);
|
||||
return;
|
||||
@@ -453,9 +460,8 @@ static size_t binder_buffer_size(struct binder_proc *proc,
|
||||
{
|
||||
if (list_is_last(&buffer->entry, &proc->buffers))
|
||||
return proc->buffer + proc->buffer_size - (void *)buffer->data;
|
||||
else
|
||||
return (size_t)list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry) - (size_t)buffer->data;
|
||||
return (size_t)list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry) - (size_t)buffer->data;
|
||||
}
|
||||
|
||||
static void binder_insert_free_buffer(struct binder_proc *proc,
|
||||
@@ -586,6 +592,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
|
||||
for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) {
|
||||
int ret;
|
||||
struct page **page_array_ptr;
|
||||
|
||||
page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
|
||||
|
||||
BUG_ON(*page);
|
||||
@@ -728,6 +735,7 @@ static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc,
|
||||
binder_insert_allocated_buffer(proc, buffer);
|
||||
if (buffer_size != size) {
|
||||
struct binder_buffer *new_buffer = (void *)buffer->data + size;
|
||||
|
||||
list_add(&new_buffer->entry, &buffer->entry);
|
||||
new_buffer->free = 1;
|
||||
binder_insert_free_buffer(proc, new_buffer);
|
||||
@@ -840,6 +848,7 @@ static void binder_free_buf(struct binder_proc *proc,
|
||||
if (!list_is_last(&buffer->entry, &proc->buffers)) {
|
||||
struct binder_buffer *next = list_entry(buffer->entry.next,
|
||||
struct binder_buffer, entry);
|
||||
|
||||
if (next->free) {
|
||||
rb_erase(&next->rb_node, &proc->free_buffers);
|
||||
binder_delete_free_buffer(proc, next);
|
||||
@@ -848,6 +857,7 @@ static void binder_free_buf(struct binder_proc *proc,
|
||||
if (proc->buffers.next != &buffer->entry) {
|
||||
struct binder_buffer *prev = list_entry(buffer->entry.prev,
|
||||
struct binder_buffer, entry);
|
||||
|
||||
if (prev->free) {
|
||||
binder_delete_free_buffer(proc, buffer);
|
||||
rb_erase(&prev->rb_node, &proc->free_buffers);
|
||||
@@ -1109,6 +1119,7 @@ static int binder_inc_ref(struct binder_ref *ref, int strong,
|
||||
struct list_head *target_list)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strong) {
|
||||
if (ref->strong == 0) {
|
||||
ret = binder_inc_node(ref->node, 1, 1, target_list);
|
||||
@@ -1140,6 +1151,7 @@ static int binder_dec_ref(struct binder_ref *ref, int strong)
|
||||
ref->strong--;
|
||||
if (ref->strong == 0) {
|
||||
int ret;
|
||||
|
||||
ret = binder_dec_node(ref->node, strong, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1179,6 +1191,8 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
uint32_t error_code)
|
||||
{
|
||||
struct binder_thread *target_thread;
|
||||
struct binder_transaction *next;
|
||||
|
||||
BUG_ON(t->flags & TF_ONE_WAY);
|
||||
while (1) {
|
||||
target_thread = t->from;
|
||||
@@ -1192,7 +1206,8 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
if (target_thread->return_error == BR_OK) {
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
"send failed reply for transaction %d to %d:%d\n",
|
||||
t->debug_id, target_thread->proc->pid,
|
||||
t->debug_id,
|
||||
target_thread->proc->pid,
|
||||
target_thread->pid);
|
||||
|
||||
binder_pop_transaction(target_thread, t);
|
||||
@@ -1205,24 +1220,23 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
target_thread->return_error);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
struct binder_transaction *next = t->from_parent;
|
||||
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
"send failed reply for transaction %d, target dead\n",
|
||||
t->debug_id);
|
||||
|
||||
binder_pop_transaction(target_thread, t);
|
||||
if (next == NULL) {
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread at root\n");
|
||||
return;
|
||||
}
|
||||
t = next;
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread -- retry %d\n",
|
||||
t->debug_id);
|
||||
}
|
||||
next = t->from_parent;
|
||||
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
"send failed reply for transaction %d, target dead\n",
|
||||
t->debug_id);
|
||||
|
||||
binder_pop_transaction(target_thread, t);
|
||||
if (next == NULL) {
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread at root\n");
|
||||
return;
|
||||
}
|
||||
t = next;
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"reply failed, no target thread -- retry %d\n",
|
||||
t->debug_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1249,6 +1263,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
||||
off_end = (void *)offp + buffer->offsets_size;
|
||||
for (; offp < off_end; offp++) {
|
||||
struct flat_binder_object *fp;
|
||||
|
||||
if (*offp > buffer->data_size - sizeof(*fp) ||
|
||||
buffer->data_size < sizeof(*fp) ||
|
||||
!IS_ALIGNED(*offp, sizeof(u32))) {
|
||||
@@ -1261,6 +1276,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
||||
case BINDER_TYPE_BINDER:
|
||||
case BINDER_TYPE_WEAK_BINDER: {
|
||||
struct binder_node *node = binder_get_node(proc, fp->binder);
|
||||
|
||||
if (node == NULL) {
|
||||
pr_err("transaction release %d bad node %016llx\n",
|
||||
debug_id, (u64)fp->binder);
|
||||
@@ -1274,6 +1290,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
|
||||
case BINDER_TYPE_HANDLE:
|
||||
case BINDER_TYPE_WEAK_HANDLE: {
|
||||
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
|
||||
|
||||
if (ref == NULL) {
|
||||
pr_err("transaction release %d bad handle %d\n",
|
||||
debug_id, fp->handle);
|
||||
@@ -1366,6 +1383,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
} else {
|
||||
if (tr->target.handle) {
|
||||
struct binder_ref *ref;
|
||||
|
||||
ref = binder_get_ref(proc, tr->target.handle);
|
||||
if (ref == NULL) {
|
||||
binder_user_error("%d:%d got transaction to invalid handle\n",
|
||||
@@ -1393,6 +1411,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
}
|
||||
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
|
||||
struct binder_transaction *tmp;
|
||||
|
||||
tmp = thread->transaction_stack;
|
||||
if (tmp->to_thread != thread) {
|
||||
binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n",
|
||||
@@ -1459,7 +1478,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->from = thread;
|
||||
else
|
||||
t->from = NULL;
|
||||
t->sender_euid = proc->tsk->cred->euid;
|
||||
t->sender_euid = task_euid(proc->tsk);
|
||||
t->to_proc = target_proc;
|
||||
t->to_thread = target_thread;
|
||||
t->code = tr->code;
|
||||
@@ -1509,6 +1528,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
off_min = 0;
|
||||
for (; offp < off_end; offp++) {
|
||||
struct flat_binder_object *fp;
|
||||
|
||||
if (*offp > t->buffer->data_size - sizeof(*fp) ||
|
||||
*offp < off_min ||
|
||||
t->buffer->data_size < sizeof(*fp) ||
|
||||
@@ -1528,6 +1548,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
case BINDER_TYPE_WEAK_BINDER: {
|
||||
struct binder_ref *ref;
|
||||
struct binder_node *node = binder_get_node(proc, fp->binder);
|
||||
|
||||
if (node == NULL) {
|
||||
node = binder_new_node(proc, fp->binder, fp->cookie);
|
||||
if (node == NULL) {
|
||||
@@ -1542,6 +1563,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
proc->pid, thread->pid,
|
||||
(u64)fp->binder, node->debug_id,
|
||||
(u64)fp->cookie, (u64)node->cookie);
|
||||
return_error = BR_FAILED_REPLY;
|
||||
goto err_binder_get_ref_for_node_failed;
|
||||
}
|
||||
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
|
||||
@@ -1570,6 +1592,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
case BINDER_TYPE_HANDLE:
|
||||
case BINDER_TYPE_WEAK_HANDLE: {
|
||||
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
|
||||
|
||||
if (ref == NULL) {
|
||||
binder_user_error("%d:%d got transaction with invalid handle, %d\n",
|
||||
proc->pid,
|
||||
@@ -1596,6 +1619,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
(u64)ref->node->ptr);
|
||||
} else {
|
||||
struct binder_ref *new_ref;
|
||||
|
||||
new_ref = binder_get_ref_for_node(target_proc, ref->node);
|
||||
if (new_ref == NULL) {
|
||||
return_error = BR_FAILED_REPLY;
|
||||
@@ -1720,6 +1744,7 @@ err_no_context_mgr_node:
|
||||
|
||||
{
|
||||
struct binder_transaction_log_entry *fe;
|
||||
|
||||
fe = binder_transaction_log_add(&binder_transaction_log_failed);
|
||||
*fe = *e;
|
||||
}
|
||||
@@ -1732,7 +1757,8 @@ err_no_context_mgr_node:
|
||||
thread->return_error = return_error;
|
||||
}
|
||||
|
||||
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
|
||||
static int binder_thread_write(struct binder_proc *proc,
|
||||
struct binder_thread *thread,
|
||||
binder_uintptr_t binder_buffer, size_t size,
|
||||
binder_size_t *consumed)
|
||||
{
|
||||
@@ -1888,7 +1914,8 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_FREE_BUFFER,
|
||||
"%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n",
|
||||
proc->pid, thread->pid, (u64)data_ptr, buffer->debug_id,
|
||||
proc->pid, thread->pid, (u64)data_ptr,
|
||||
buffer->debug_id,
|
||||
buffer->transaction ? "active" : "finished");
|
||||
|
||||
if (buffer->transaction) {
|
||||
@@ -2025,7 +2052,8 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
|
||||
if (death->cookie != cookie) {
|
||||
binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)death->cookie, (u64)cookie);
|
||||
(u64)death->cookie,
|
||||
(u64)cookie);
|
||||
break;
|
||||
}
|
||||
ref->death = NULL;
|
||||
@@ -2047,12 +2075,14 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
|
||||
struct binder_work *w;
|
||||
binder_uintptr_t cookie;
|
||||
struct binder_ref_death *death = NULL;
|
||||
|
||||
if (get_user(cookie, (binder_uintptr_t __user *)ptr))
|
||||
return -EFAULT;
|
||||
|
||||
ptr += sizeof(void *);
|
||||
list_for_each_entry(w, &proc->delivered_death, entry) {
|
||||
struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
|
||||
|
||||
if (tmp_death->cookie == cookie) {
|
||||
death = tmp_death;
|
||||
break;
|
||||
@@ -2060,7 +2090,8 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_DEAD_BINDER,
|
||||
"%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
|
||||
proc->pid, thread->pid, (u64)cookie, death);
|
||||
proc->pid, thread->pid, (u64)cookie,
|
||||
death);
|
||||
if (death == NULL) {
|
||||
binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n",
|
||||
proc->pid, thread->pid, (u64)cookie);
|
||||
@@ -2089,8 +2120,8 @@ int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void binder_stat_br(struct binder_proc *proc, struct binder_thread *thread,
|
||||
uint32_t cmd)
|
||||
static void binder_stat_br(struct binder_proc *proc,
|
||||
struct binder_thread *thread, uint32_t cmd)
|
||||
{
|
||||
trace_binder_return(cmd);
|
||||
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) {
|
||||
@@ -2200,12 +2231,16 @@ retry:
|
||||
struct binder_work *w;
|
||||
struct binder_transaction *t = NULL;
|
||||
|
||||
if (!list_empty(&thread->todo))
|
||||
w = list_first_entry(&thread->todo, struct binder_work, entry);
|
||||
else if (!list_empty(&proc->todo) && wait_for_proc_work)
|
||||
w = list_first_entry(&proc->todo, struct binder_work, entry);
|
||||
else {
|
||||
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */
|
||||
if (!list_empty(&thread->todo)) {
|
||||
w = list_first_entry(&thread->todo, struct binder_work,
|
||||
entry);
|
||||
} else if (!list_empty(&proc->todo) && wait_for_proc_work) {
|
||||
w = list_first_entry(&proc->todo, struct binder_work,
|
||||
entry);
|
||||
} else {
|
||||
/* no data added */
|
||||
if (ptr - buffer == 4 &&
|
||||
!(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
|
||||
goto retry;
|
||||
break;
|
||||
}
|
||||
@@ -2238,6 +2273,7 @@ retry:
|
||||
const char *cmd_name;
|
||||
int strong = node->internal_strong_refs || node->local_strong_refs;
|
||||
int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong;
|
||||
|
||||
if (weak && !node->has_weak_ref) {
|
||||
cmd = BR_INCREFS;
|
||||
cmd_name = "BR_INCREFS";
|
||||
@@ -2283,16 +2319,20 @@ retry:
|
||||
if (!weak && !strong) {
|
||||
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
|
||||
"%d:%d node %d u%016llx c%016llx deleted\n",
|
||||
proc->pid, thread->pid, node->debug_id,
|
||||
(u64)node->ptr, (u64)node->cookie);
|
||||
proc->pid, thread->pid,
|
||||
node->debug_id,
|
||||
(u64)node->ptr,
|
||||
(u64)node->cookie);
|
||||
rb_erase(&node->rb_node, &proc->nodes);
|
||||
kfree(node);
|
||||
binder_stats_deleted(BINDER_STAT_NODE);
|
||||
} else {
|
||||
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
|
||||
"%d:%d node %d u%016llx c%016llx state unchanged\n",
|
||||
proc->pid, thread->pid, node->debug_id,
|
||||
(u64)node->ptr, (u64)node->cookie);
|
||||
proc->pid, thread->pid,
|
||||
node->debug_id,
|
||||
(u64)node->ptr,
|
||||
(u64)node->cookie);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -2340,6 +2380,7 @@ retry:
|
||||
BUG_ON(t->buffer == NULL);
|
||||
if (t->buffer->target_node) {
|
||||
struct binder_node *target_node = t->buffer->target_node;
|
||||
|
||||
tr.target.ptr = target_node->ptr;
|
||||
tr.cookie = target_node->cookie;
|
||||
t->saved_priority = task_nice(current);
|
||||
@@ -2361,6 +2402,7 @@ retry:
|
||||
|
||||
if (t->from) {
|
||||
struct task_struct *sender = t->from->proc->tsk;
|
||||
|
||||
tr.sender_pid = task_tgid_nr_ns(sender,
|
||||
task_active_pid_ns(current));
|
||||
} else {
|
||||
@@ -2431,6 +2473,7 @@ done:
|
||||
static void binder_release_work(struct list_head *list)
|
||||
{
|
||||
struct binder_work *w;
|
||||
|
||||
while (!list_empty(list)) {
|
||||
w = list_first_entry(list, struct binder_work, entry);
|
||||
list_del_init(&w->entry);
|
||||
@@ -2585,6 +2628,109 @@ static unsigned int binder_poll(struct file *filp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int binder_ioctl_write_read(struct file *filp,
|
||||
unsigned int cmd, unsigned long arg,
|
||||
struct binder_thread *thread)
|
||||
{
|
||||
int ret = 0;
|
||||
struct binder_proc *proc = filp->private_data;
|
||||
unsigned int size = _IOC_SIZE(cmd);
|
||||
void __user *ubuf = (void __user *)arg;
|
||||
struct binder_write_read bwr;
|
||||
|
||||
if (size != sizeof(struct binder_write_read)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d write %lld at %016llx, read %lld at %016llx\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_size, (u64)bwr.write_buffer,
|
||||
(u64)bwr.read_size, (u64)bwr.read_buffer);
|
||||
|
||||
if (bwr.write_size > 0) {
|
||||
ret = binder_thread_write(proc, thread,
|
||||
bwr.write_buffer,
|
||||
bwr.write_size,
|
||||
&bwr.write_consumed);
|
||||
trace_binder_write_done(ret);
|
||||
if (ret < 0) {
|
||||
bwr.read_consumed = 0;
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (bwr.read_size > 0) {
|
||||
ret = binder_thread_read(proc, thread, bwr.read_buffer,
|
||||
bwr.read_size,
|
||||
&bwr.read_consumed,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
trace_binder_read_done(ret);
|
||||
if (!list_empty(&proc->todo))
|
||||
wake_up_interruptible(&proc->wait);
|
||||
if (ret < 0) {
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d wrote %lld of %lld, read return %lld of %lld\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_consumed, (u64)bwr.write_size,
|
||||
(u64)bwr.read_consumed, (u64)bwr.read_size);
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int binder_ioctl_set_ctx_mgr(struct file *filp)
|
||||
{
|
||||
int ret = 0;
|
||||
struct binder_proc *proc = filp->private_data;
|
||||
kuid_t curr_euid = current_euid();
|
||||
|
||||
if (binder_context_mgr_node != NULL) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
ret = security_binder_set_context_mgr(proc->tsk);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
if (uid_valid(binder_context_mgr_uid)) {
|
||||
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
|
||||
from_kuid(&init_user_ns, curr_euid),
|
||||
from_kuid(&init_user_ns,
|
||||
binder_context_mgr_uid));
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
binder_context_mgr_uid = curr_euid;
|
||||
}
|
||||
binder_context_mgr_node = binder_new_node(proc, 0, 0);
|
||||
if (binder_context_mgr_node == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
binder_context_mgr_node->local_weak_refs++;
|
||||
binder_context_mgr_node->local_strong_refs++;
|
||||
binder_context_mgr_node->has_strong_ref = 1;
|
||||
binder_context_mgr_node->has_weak_ref = 1;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
@@ -2593,7 +2739,8 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
unsigned int size = _IOC_SIZE(cmd);
|
||||
void __user *ubuf = (void __user *)arg;
|
||||
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n", proc->pid, current->pid, cmd, arg);*/
|
||||
/*pr_info("binder_ioctl: %d:%d %x %lx\n",
|
||||
proc->pid, current->pid, cmd, arg);*/
|
||||
|
||||
trace_binder_ioctl(cmd, arg);
|
||||
|
||||
@@ -2609,54 +2756,11 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case BINDER_WRITE_READ: {
|
||||
struct binder_write_read bwr;
|
||||
if (size != sizeof(struct binder_write_read)) {
|
||||
ret = -EINVAL;
|
||||
case BINDER_WRITE_READ:
|
||||
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d write %lld at %016llx, read %lld at %016llx\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_size, (u64)bwr.write_buffer,
|
||||
(u64)bwr.read_size, (u64)bwr.read_buffer);
|
||||
|
||||
if (bwr.write_size > 0) {
|
||||
ret = binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
|
||||
trace_binder_write_done(ret);
|
||||
if (ret < 0) {
|
||||
bwr.read_consumed = 0;
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (bwr.read_size > 0) {
|
||||
ret = binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
|
||||
trace_binder_read_done(ret);
|
||||
if (!list_empty(&proc->todo))
|
||||
wake_up_interruptible(&proc->wait);
|
||||
if (ret < 0) {
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
binder_debug(BINDER_DEBUG_READ_WRITE,
|
||||
"%d:%d wrote %lld of %lld, read return %lld of %lld\n",
|
||||
proc->pid, thread->pid,
|
||||
(u64)bwr.write_consumed, (u64)bwr.write_size,
|
||||
(u64)bwr.read_consumed, (u64)bwr.read_size);
|
||||
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BINDER_SET_MAX_THREADS:
|
||||
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
|
||||
ret = -EINVAL;
|
||||
@@ -2664,33 +2768,9 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
break;
|
||||
case BINDER_SET_CONTEXT_MGR:
|
||||
if (binder_context_mgr_node != NULL) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
|
||||
ret = -EBUSY;
|
||||
ret = binder_ioctl_set_ctx_mgr(filp);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
ret = security_binder_set_context_mgr(proc->tsk);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (uid_valid(binder_context_mgr_uid)) {
|
||||
if (!uid_eq(binder_context_mgr_uid, current->cred->euid)) {
|
||||
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
|
||||
from_kuid(&init_user_ns, current->cred->euid),
|
||||
from_kuid(&init_user_ns, binder_context_mgr_uid));
|
||||
ret = -EPERM;
|
||||
goto err;
|
||||
}
|
||||
} else
|
||||
binder_context_mgr_uid = current->cred->euid;
|
||||
binder_context_mgr_node = binder_new_node(proc, 0, 0);
|
||||
if (binder_context_mgr_node == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
binder_context_mgr_node->local_weak_refs++;
|
||||
binder_context_mgr_node->local_strong_refs++;
|
||||
binder_context_mgr_node->has_strong_ref = 1;
|
||||
binder_context_mgr_node->has_weak_ref = 1;
|
||||
break;
|
||||
case BINDER_THREAD_EXIT:
|
||||
binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
|
||||
@@ -2698,16 +2778,20 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
binder_free_thread(proc, thread);
|
||||
thread = NULL;
|
||||
break;
|
||||
case BINDER_VERSION:
|
||||
case BINDER_VERSION: {
|
||||
struct binder_version __user *ver = ubuf;
|
||||
|
||||
if (size != sizeof(struct binder_version)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
|
||||
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
|
||||
&ver->protocol_version)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
@@ -2728,6 +2812,7 @@ err_unlocked:
|
||||
static void binder_vma_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct binder_proc *proc = vma->vm_private_data;
|
||||
|
||||
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
|
||||
"%d open vm area %lx-%lx (%ld K) vma %lx pagep %lx\n",
|
||||
proc->pid, vma->vm_start, vma->vm_end,
|
||||
@@ -2738,6 +2823,7 @@ static void binder_vma_open(struct vm_area_struct *vma)
|
||||
static void binder_vma_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct binder_proc *proc = vma->vm_private_data;
|
||||
|
||||
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
|
||||
"%d close vm area %lx-%lx (%ld K) vma %lx pagep %lx\n",
|
||||
proc->pid, vma->vm_start, vma->vm_end,
|
||||
@@ -2748,9 +2834,15 @@ static void binder_vma_close(struct vm_area_struct *vma)
|
||||
binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
|
||||
}
|
||||
|
||||
static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct binder_vm_ops = {
|
||||
.open = binder_vma_open,
|
||||
.close = binder_vma_close,
|
||||
.fault = binder_vm_fault,
|
||||
};
|
||||
|
||||
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
@@ -2880,6 +2972,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
|
||||
|
||||
if (binder_debugfs_dir_entry_proc) {
|
||||
char strbuf[11];
|
||||
|
||||
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
|
||||
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,
|
||||
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
|
||||
@@ -2901,8 +2994,10 @@ static void binder_deferred_flush(struct binder_proc *proc)
|
||||
{
|
||||
struct rb_node *n;
|
||||
int wake_count = 0;
|
||||
|
||||
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) {
|
||||
struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node);
|
||||
|
||||
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
|
||||
if (thread->looper & BINDER_LOOPER_STATE_WAITING) {
|
||||
wake_up_interruptible(&thread->wait);
|
||||
@@ -2919,6 +3014,7 @@ static void binder_deferred_flush(struct binder_proc *proc)
|
||||
static int binder_release(struct inode *nodp, struct file *filp)
|
||||
{
|
||||
struct binder_proc *proc = filp->private_data;
|
||||
|
||||
debugfs_remove(proc->debugfs_entry);
|
||||
binder_defer_work(proc, BINDER_DEFERRED_RELEASE);
|
||||
|
||||
@@ -3080,6 +3176,7 @@ static void binder_deferred_func(struct work_struct *work)
|
||||
struct files_struct *files;
|
||||
|
||||
int defer;
|
||||
|
||||
do {
|
||||
binder_lock(__func__);
|
||||
mutex_lock(&binder_deferred_lock);
|
||||
@@ -8,25 +8,6 @@ config ANDROID
|
||||
|
||||
if ANDROID
|
||||
|
||||
config ANDROID_BINDER_IPC
|
||||
bool "Android Binder IPC Driver"
|
||||
default n
|
||||
---help---
|
||||
Binder is used in Android for both communication between processes,
|
||||
and remote method invocation.
|
||||
|
||||
This means one Android process can call a method/routine in another
|
||||
Android process, using Binder to identify, invoke and pass arguments
|
||||
between said processes.
|
||||
|
||||
config ANDROID_BINDER_IPC_32BIT
|
||||
bool
|
||||
default y
|
||||
depends on !64BIT && ANDROID_BINDER_IPC
|
||||
---help---
|
||||
Enable to support an old 32-bit Android user-space. Breaks the new
|
||||
Android user-space.
|
||||
|
||||
config ASHMEM
|
||||
bool "Enable the Anonymous Shared Memory Subsystem"
|
||||
default n
|
||||
|
||||
@@ -3,7 +3,6 @@ ccflags-y += -I$(src) # needed for trace events
|
||||
obj-y += ion/
|
||||
obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/
|
||||
|
||||
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
|
||||
obj-$(CONFIG_ASHMEM) += ashmem.o
|
||||
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
|
||||
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
|
||||
|
||||
@@ -326,6 +326,7 @@ static int alarm_release(struct inode *inode, struct file *file)
|
||||
if (file->private_data) {
|
||||
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
|
||||
uint32_t alarm_type_mask = 1U << i;
|
||||
|
||||
if (alarm_enabled & alarm_type_mask) {
|
||||
alarm_dbg(INFO,
|
||||
"%s: clear alarm, pending %d\n",
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google, Inc.
|
||||
*
|
||||
* Based on, but no longer compatible with, the original
|
||||
* OpenBinder.org binder driver interface, which is:
|
||||
*
|
||||
* Copyright (c) 2005 Palmsource, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_BINDER_H
|
||||
#define _LINUX_BINDER_H
|
||||
|
||||
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
|
||||
#define BINDER_IPC_32BIT 1
|
||||
#endif
|
||||
|
||||
#include "uapi/binder.h"
|
||||
|
||||
#endif /* _LINUX_BINDER_H */
|
||||
|
||||
@@ -407,6 +407,7 @@ static struct ion_handle *ion_handle_lookup(struct ion_client *client,
|
||||
|
||||
while (n) {
|
||||
struct ion_handle *entry = rb_entry(n, struct ion_handle, node);
|
||||
|
||||
if (buffer < entry->buffer)
|
||||
n = n->rb_left;
|
||||
else if (buffer > entry->buffer)
|
||||
@@ -719,9 +720,11 @@ static int ion_get_client_serial(const struct rb_root *root,
|
||||
{
|
||||
int serial = -1;
|
||||
struct rb_node *node;
|
||||
|
||||
for (node = rb_first(root); node; node = rb_next(node)) {
|
||||
struct ion_client *client = rb_entry(node, struct ion_client,
|
||||
node);
|
||||
|
||||
if (strcmp(client->name, name))
|
||||
continue;
|
||||
serial = max(serial, client->display_serial);
|
||||
@@ -1034,12 +1037,14 @@ static int ion_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
|
||||
static void ion_dma_buf_release(struct dma_buf *dmabuf)
|
||||
{
|
||||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
|
||||
ion_buffer_put(buffer);
|
||||
}
|
||||
|
||||
static void *ion_dma_buf_kmap(struct dma_buf *dmabuf, unsigned long offset)
|
||||
{
|
||||
struct ion_buffer *buffer = dmabuf->priv;
|
||||
|
||||
return buffer->vaddr + offset * PAGE_SIZE;
|
||||
}
|
||||
|
||||
@@ -1293,6 +1298,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
case ION_IOC_IMPORT:
|
||||
{
|
||||
struct ion_handle *handle;
|
||||
|
||||
handle = ion_import_dma_buf(client, data.fd.fd);
|
||||
if (IS_ERR(handle))
|
||||
ret = PTR_ERR(handle);
|
||||
@@ -1394,6 +1400,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused)
|
||||
struct ion_client *client = rb_entry(n, struct ion_client,
|
||||
node);
|
||||
size_t size = ion_debug_heap_total(client, heap->id);
|
||||
|
||||
if (!size)
|
||||
continue;
|
||||
if (client->task) {
|
||||
@@ -1518,6 +1525,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
|
||||
|
||||
if (!debug_file) {
|
||||
char buf[256], *path;
|
||||
|
||||
path = dentry_path(dev->heaps_debug_root, buf, 256);
|
||||
pr_err("Failed to create heap debugfs at %s/%s\n",
|
||||
path, heap->name);
|
||||
@@ -1533,6 +1541,7 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
|
||||
&debug_shrink_fops);
|
||||
if (!debug_file) {
|
||||
char buf[256], *path;
|
||||
|
||||
path = dentry_path(dev->heaps_debug_root, buf, 256);
|
||||
pr_err("Failed to create heap shrinker debugfs at %s/%s\n",
|
||||
path, debug_name);
|
||||
@@ -1608,6 +1617,7 @@ void __init ion_reserve(struct ion_platform_data *data)
|
||||
|
||||
if (data->heaps[i].base == 0) {
|
||||
phys_addr_t paddr;
|
||||
|
||||
paddr = memblock_alloc_base(data->heaps[i].size,
|
||||
data->heaps[i].align,
|
||||
MEMBLOCK_ALLOC_ANYWHERE);
|
||||
|
||||
@@ -48,6 +48,7 @@ void *ion_heap_map_kernel(struct ion_heap *heap,
|
||||
for_each_sg(table->sgl, sg, table->nents, i) {
|
||||
int npages_this_entry = PAGE_ALIGN(sg->length) / PAGE_SIZE;
|
||||
struct page *page = sg_page(sg);
|
||||
|
||||
BUG_ON(i >= npages);
|
||||
for (j = 0; j < npages_this_entry; j++)
|
||||
*(tmp++) = page++;
|
||||
@@ -105,6 +106,7 @@ int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
|
||||
static int ion_heap_clear_pages(struct page **pages, int num, pgprot_t pgprot)
|
||||
{
|
||||
void *addr = vm_map_ram(pages, num, -1, pgprot);
|
||||
|
||||
if (!addr)
|
||||
return -ENOMEM;
|
||||
memset(addr, 0, PAGE_SIZE * num);
|
||||
|
||||
@@ -179,6 +179,7 @@ struct ion_heap {
|
||||
spinlock_t free_lock;
|
||||
wait_queue_head_t waitqueue;
|
||||
struct task_struct *task;
|
||||
|
||||
int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
|
||||
};
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ static const int num_orders = ARRAY_SIZE(orders);
|
||||
static int order_to_index(unsigned int order)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_orders; i++)
|
||||
if (order == orders[i])
|
||||
return i;
|
||||
@@ -92,6 +93,7 @@ static void free_buffer_page(struct ion_system_heap *heap,
|
||||
|
||||
if (!cached && !(buffer->private_flags & ION_PRIV_FLAG_SHRINKER_FREE)) {
|
||||
struct ion_page_pool *pool = heap->pools[order_to_index(order)];
|
||||
|
||||
ion_page_pool_free(pool, page);
|
||||
} else {
|
||||
__free_pages(page, order);
|
||||
@@ -242,6 +244,7 @@ static int ion_system_heap_shrink(struct ion_heap *heap, gfp_t gfp_mask,
|
||||
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
struct ion_page_pool *pool = sys_heap->pools[i];
|
||||
|
||||
nr_total += ion_page_pool_shrink(pool, gfp_mask, nr_to_scan);
|
||||
}
|
||||
|
||||
@@ -267,8 +270,10 @@ static int ion_system_heap_debug_show(struct ion_heap *heap, struct seq_file *s,
|
||||
struct ion_system_heap,
|
||||
heap);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_orders; i++) {
|
||||
struct ion_page_pool *pool = sys_heap->pools[i];
|
||||
|
||||
seq_printf(s, "%d order %u highmem pages in pool = %lu total\n",
|
||||
pool->high_count, pool->order,
|
||||
(1 << pool->order) * PAGE_SIZE * pool->high_count);
|
||||
|
||||
@@ -108,6 +108,7 @@ static inline struct logger_log *file_get_log(struct file *file)
|
||||
{
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
struct logger_reader *reader = file->private_data;
|
||||
|
||||
return reader->log;
|
||||
} else
|
||||
return file->private_data;
|
||||
@@ -124,6 +125,7 @@ static struct logger_entry *get_entry_header(struct logger_log *log,
|
||||
size_t off, struct logger_entry *scratch)
|
||||
{
|
||||
size_t len = min(sizeof(struct logger_entry), log->size - off);
|
||||
|
||||
if (len != sizeof(struct logger_entry)) {
|
||||
memcpy(((void *) scratch), log->buffer + off, len);
|
||||
memcpy(((void *) scratch) + len, log->buffer,
|
||||
@@ -640,6 +642,7 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
|
||||
static long logger_set_version(struct logger_reader *reader, void __user *arg)
|
||||
{
|
||||
int version;
|
||||
|
||||
if (copy_from_user(&version, arg, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ static void sw_sync_pt_value_str(struct sync_pt *sync_pt,
|
||||
char *str, int size)
|
||||
{
|
||||
struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
|
||||
|
||||
snprintf(str, size, "%d", pt->value);
|
||||
}
|
||||
|
||||
@@ -156,6 +157,7 @@ static int sw_sync_open(struct inode *inode, struct file *file)
|
||||
static int sw_sync_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct sw_sync_timeline *obj = file->private_data;
|
||||
|
||||
sync_timeline_destroy(&obj->obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -384,6 +384,7 @@ static void sync_fence_detach_pts(struct sync_fence *fence)
|
||||
|
||||
list_for_each_safe(pos, n, &fence->pt_list_head) {
|
||||
struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
|
||||
|
||||
sync_timeline_remove_pt(pt);
|
||||
}
|
||||
}
|
||||
@@ -394,6 +395,7 @@ static void sync_fence_free_pts(struct sync_fence *fence)
|
||||
|
||||
list_for_each_safe(pos, n, &fence->pt_list_head) {
|
||||
struct sync_pt *pt = container_of(pos, struct sync_pt, pt_list);
|
||||
|
||||
sync_pt_free(pt);
|
||||
}
|
||||
}
|
||||
@@ -827,6 +829,7 @@ static long sync_fence_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct sync_fence *fence = file->private_data;
|
||||
|
||||
switch (cmd) {
|
||||
case SYNC_IOC_WAIT:
|
||||
return sync_fence_ioctl_wait(fence, arg);
|
||||
@@ -856,18 +859,21 @@ static const char *sync_status_str(int status)
|
||||
static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
|
||||
{
|
||||
int status = pt->status;
|
||||
|
||||
seq_printf(s, " %s%spt %s",
|
||||
fence ? pt->parent->name : "",
|
||||
fence ? "_" : "",
|
||||
sync_status_str(status));
|
||||
if (pt->status) {
|
||||
struct timeval tv = ktime_to_timeval(pt->timestamp);
|
||||
|
||||
seq_printf(s, "@%ld.%06ld", tv.tv_sec, tv.tv_usec);
|
||||
}
|
||||
|
||||
if (pt->parent->ops->timeline_value_str &&
|
||||
pt->parent->ops->pt_value_str) {
|
||||
char value[64];
|
||||
|
||||
pt->parent->ops->pt_value_str(pt, value, sizeof(value));
|
||||
seq_printf(s, ": %s", value);
|
||||
if (fence) {
|
||||
@@ -892,6 +898,7 @@ static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)
|
||||
|
||||
if (obj->ops->timeline_value_str) {
|
||||
char value[64];
|
||||
|
||||
obj->ops->timeline_value_str(obj, value, sizeof(value));
|
||||
seq_printf(s, ": %s", value);
|
||||
} else if (obj->ops->print_obj) {
|
||||
@@ -1001,6 +1008,7 @@ void sync_dump(void)
|
||||
for (i = 0; i < s.count; i += DUMP_CHUNK) {
|
||||
if ((s.count - i) > DUMP_CHUNK) {
|
||||
char c = s.buf[i + DUMP_CHUNK];
|
||||
|
||||
s.buf[i + DUMP_CHUNK] = 0;
|
||||
pr_cont("%s", s.buf + i);
|
||||
s.buf[i + DUMP_CHUNK] = c;
|
||||
|
||||
@@ -51,6 +51,7 @@ static int gpio_get_time(struct timed_output_dev *dev)
|
||||
if (hrtimer_active(&data->timer)) {
|
||||
ktime_t r = hrtimer_get_remaining(&data->timer);
|
||||
struct timeval t = ktime_to_timeval(r);
|
||||
|
||||
return t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#define _UAPI_LINUX_ASHMEM_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define ASHMEM_NAME_LEN 256
|
||||
|
||||
|
||||
@@ -90,6 +90,9 @@ struct android_dev {
|
||||
struct usb_composite_dev *cdev;
|
||||
struct device *dev;
|
||||
|
||||
void (*setup_complete)(struct usb_ep *ep,
|
||||
struct usb_request *req);
|
||||
|
||||
bool enabled;
|
||||
int disable_depth;
|
||||
struct mutex mutex;
|
||||
@@ -1312,6 +1315,9 @@ static int android_bind(struct usb_composite_dev *cdev)
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
int id, ret;
|
||||
|
||||
/* Save the default handler */
|
||||
dev->setup_complete = cdev->req->complete;
|
||||
|
||||
/*
|
||||
* Start disconnected. Userspace will connect the gadget once
|
||||
* it is done configuring the functions.
|
||||
@@ -1378,6 +1384,7 @@ android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
|
||||
|
||||
req->zero = 0;
|
||||
req->length = 0;
|
||||
req->complete = dev->setup_complete;
|
||||
gadget->ep0->driver_data = cdev;
|
||||
|
||||
list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
|
||||
|
||||
@@ -951,6 +951,10 @@ kill_all_hid_devices(struct acc_dev *dev)
|
||||
struct list_head *entry, *temp;
|
||||
unsigned long flags;
|
||||
|
||||
/* do nothing if usb accessory device doesn't exist */
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
list_for_each_safe(entry, temp, &dev->hid_list) {
|
||||
hid = list_entry(entry, struct acc_hid_dev, list);
|
||||
|
||||
@@ -19,6 +19,16 @@ config PSTORE_CONSOLE
|
||||
When the option is enabled, pstore will log all kernel
|
||||
messages, even if no oops or panic happened.
|
||||
|
||||
config PSTORE_PMSG
|
||||
bool "Log user space messages"
|
||||
depends on PSTORE
|
||||
help
|
||||
When the option is enabled, pstore will export a character
|
||||
interface /dev/pmsg0 to log user space messages. On reboot
|
||||
data can be retrieved from /sys/fs/pstore/pmsg-ramoops-[ID].
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config PSTORE_FTRACE
|
||||
bool "Persistent function tracer"
|
||||
depends on PSTORE
|
||||
|
||||
@@ -7,5 +7,7 @@ obj-y += pstore.o
|
||||
pstore-objs += inode.o platform.o
|
||||
obj-$(CONFIG_PSTORE_FTRACE) += ftrace.o
|
||||
|
||||
obj-$(CONFIG_PSTORE_PMSG) += pmsg.o
|
||||
|
||||
ramoops-objs += ram.o ram_core.o
|
||||
obj-$(CONFIG_PSTORE_RAM) += ramoops.o
|
||||
|
||||
@@ -313,22 +313,27 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int count,
|
||||
|
||||
switch (type) {
|
||||
case PSTORE_TYPE_DMESG:
|
||||
sprintf(name, "dmesg-%s-%lld", psname, id);
|
||||
scnprintf(name, sizeof(name), "dmesg-%s-%lld",
|
||||
psname, id);
|
||||
break;
|
||||
case PSTORE_TYPE_CONSOLE:
|
||||
sprintf(name, "console-%s", psname);
|
||||
scnprintf(name, sizeof(name), "console-%s", psname);
|
||||
break;
|
||||
case PSTORE_TYPE_FTRACE:
|
||||
sprintf(name, "ftrace-%s", psname);
|
||||
scnprintf(name, sizeof(name), "ftrace-%s", psname);
|
||||
break;
|
||||
case PSTORE_TYPE_MCE:
|
||||
sprintf(name, "mce-%s-%lld", psname, id);
|
||||
scnprintf(name, sizeof(name), "mce-%s-%lld", psname, id);
|
||||
break;
|
||||
case PSTORE_TYPE_PMSG:
|
||||
scnprintf(name, sizeof(name), "pmsg-%s-%lld", psname, id);
|
||||
break;
|
||||
case PSTORE_TYPE_UNKNOWN:
|
||||
sprintf(name, "unknown-%s-%lld", psname, id);
|
||||
scnprintf(name, sizeof(name), "unknown-%s-%lld", psname, id);
|
||||
break;
|
||||
default:
|
||||
sprintf(name, "type%d-%s-%lld", type, psname, id);
|
||||
scnprintf(name, sizeof(name), "type%d-%s-%lld",
|
||||
type, psname, id);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@ extern void pstore_register_ftrace(void);
|
||||
static inline void pstore_register_ftrace(void) {}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PSTORE_PMSG
|
||||
extern void pstore_register_pmsg(void);
|
||||
#else
|
||||
static inline void pstore_register_pmsg(void) {}
|
||||
#endif
|
||||
|
||||
extern struct pstore_info *psinfo;
|
||||
|
||||
extern void pstore_set_kmsg_bytes(int);
|
||||
|
||||
@@ -267,6 +267,7 @@ int pstore_register(struct pstore_info *psi)
|
||||
kmsg_dump_register(&pstore_dumper);
|
||||
pstore_register_console();
|
||||
pstore_register_ftrace();
|
||||
pstore_register_pmsg();
|
||||
|
||||
if (pstore_update_ms >= 0) {
|
||||
pstore_timer.expires = jiffies +
|
||||
|
||||
114
fs/pstore/pmsg.c
Normal file
114
fs/pstore/pmsg.c
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2014 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "internal.h"
|
||||
|
||||
static DEFINE_MUTEX(pmsg_lock);
|
||||
#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE)
|
||||
|
||||
static ssize_t write_pmsg(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
size_t i, buffer_size;
|
||||
char *buffer;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!access_ok(VERIFY_READ, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buffer_size = count;
|
||||
if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE)
|
||||
buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE;
|
||||
buffer = vmalloc(buffer_size);
|
||||
|
||||
mutex_lock(&pmsg_lock);
|
||||
for (i = 0; i < count; ) {
|
||||
size_t c = min(count - i, buffer_size);
|
||||
u64 id;
|
||||
long ret;
|
||||
|
||||
ret = __copy_from_user(buffer, buf + i, c);
|
||||
if (unlikely(ret != 0)) {
|
||||
mutex_unlock(&pmsg_lock);
|
||||
vfree(buffer);
|
||||
return -EFAULT;
|
||||
}
|
||||
psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, c,
|
||||
psinfo);
|
||||
|
||||
i += c;
|
||||
}
|
||||
|
||||
mutex_unlock(&pmsg_lock);
|
||||
vfree(buffer);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations pmsg_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = noop_llseek,
|
||||
.write = write_pmsg,
|
||||
};
|
||||
|
||||
static struct class *pmsg_class;
|
||||
static int pmsg_major;
|
||||
#define PMSG_NAME "pmsg"
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) PMSG_NAME ": " fmt
|
||||
|
||||
static char *pmsg_devnode(struct device *dev, umode_t *mode)
|
||||
{
|
||||
if (mode)
|
||||
*mode = 0220;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pstore_register_pmsg(void)
|
||||
{
|
||||
struct device *pmsg_device;
|
||||
|
||||
pmsg_major = register_chrdev(0, PMSG_NAME, &pmsg_fops);
|
||||
if (pmsg_major < 0) {
|
||||
pr_err("register_chrdev failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
pmsg_class = class_create(THIS_MODULE, PMSG_NAME);
|
||||
if (IS_ERR(pmsg_class)) {
|
||||
pr_err("device class file already in use\n");
|
||||
goto err_class;
|
||||
}
|
||||
pmsg_class->devnode = pmsg_devnode;
|
||||
|
||||
pmsg_device = device_create(pmsg_class, NULL, MKDEV(pmsg_major, 0),
|
||||
NULL, "%s%d", PMSG_NAME, 0);
|
||||
if (IS_ERR(pmsg_device)) {
|
||||
pr_err("failed to create device\n");
|
||||
goto err_device;
|
||||
}
|
||||
return;
|
||||
|
||||
err_device:
|
||||
class_destroy(pmsg_class);
|
||||
err_class:
|
||||
unregister_chrdev(pmsg_major, PMSG_NAME);
|
||||
err:
|
||||
return;
|
||||
}
|
||||
@@ -51,6 +51,10 @@ static ulong ramoops_ftrace_size = MIN_MEM_SIZE;
|
||||
module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400);
|
||||
MODULE_PARM_DESC(ftrace_size, "size of ftrace log");
|
||||
|
||||
static ulong ramoops_pmsg_size = MIN_MEM_SIZE;
|
||||
module_param_named(pmsg_size, ramoops_pmsg_size, ulong, 0400);
|
||||
MODULE_PARM_DESC(pmsg_size, "size of user space message log");
|
||||
|
||||
static ulong mem_address;
|
||||
module_param(mem_address, ulong, 0400);
|
||||
MODULE_PARM_DESC(mem_address,
|
||||
@@ -77,18 +81,22 @@ struct ramoops_context {
|
||||
struct persistent_ram_zone **przs;
|
||||
struct persistent_ram_zone *cprz;
|
||||
struct persistent_ram_zone *fprz;
|
||||
struct persistent_ram_zone *mprz;
|
||||
phys_addr_t phys_addr;
|
||||
unsigned long size;
|
||||
size_t record_size;
|
||||
size_t console_size;
|
||||
size_t ftrace_size;
|
||||
size_t pmsg_size;
|
||||
int dump_oops;
|
||||
struct persistent_ram_ecc_info ecc_info;
|
||||
unsigned int max_dump_cnt;
|
||||
unsigned int dump_write_cnt;
|
||||
/* _read_cnt need clear on ramoops_pstore_open */
|
||||
unsigned int dump_read_cnt;
|
||||
unsigned int console_read_cnt;
|
||||
unsigned int ftrace_read_cnt;
|
||||
unsigned int pmsg_read_cnt;
|
||||
struct pstore_info pstore;
|
||||
};
|
||||
|
||||
@@ -101,6 +109,8 @@ static int ramoops_pstore_open(struct pstore_info *psi)
|
||||
|
||||
cxt->dump_read_cnt = 0;
|
||||
cxt->console_read_cnt = 0;
|
||||
cxt->ftrace_read_cnt = 0;
|
||||
cxt->pmsg_read_cnt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -131,6 +141,12 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
|
||||
return prz;
|
||||
}
|
||||
|
||||
static bool prz_ok(struct persistent_ram_zone *prz)
|
||||
{
|
||||
return !!prz && !!(persistent_ram_old_size(prz) +
|
||||
persistent_ram_ecc_string(prz, NULL, 0));
|
||||
}
|
||||
|
||||
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
|
||||
int *count, struct timespec *time,
|
||||
char **buf, struct pstore_info *psi)
|
||||
@@ -143,13 +159,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
|
||||
prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
|
||||
cxt->max_dump_cnt, id, type,
|
||||
PSTORE_TYPE_DMESG, 1);
|
||||
if (!prz)
|
||||
if (!prz_ok(prz))
|
||||
prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
|
||||
1, id, type, PSTORE_TYPE_CONSOLE, 0);
|
||||
if (!prz)
|
||||
if (!prz_ok(prz))
|
||||
prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
|
||||
1, id, type, PSTORE_TYPE_FTRACE, 0);
|
||||
if (!prz)
|
||||
if (!prz_ok(prz))
|
||||
prz = ramoops_get_next_prz(&cxt->mprz, &cxt->pmsg_read_cnt,
|
||||
1, id, type, PSTORE_TYPE_PMSG, 0);
|
||||
if (!prz_ok(prz))
|
||||
return 0;
|
||||
|
||||
/* TODO(kees): Bogus time for the moment. */
|
||||
@@ -212,6 +231,11 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
|
||||
return -ENOMEM;
|
||||
persistent_ram_write(cxt->fprz, buf, size);
|
||||
return 0;
|
||||
} else if (type == PSTORE_TYPE_PMSG) {
|
||||
if (!cxt->mprz)
|
||||
return -ENOMEM;
|
||||
persistent_ram_write(cxt->mprz, buf, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type != PSTORE_TYPE_DMESG)
|
||||
@@ -269,6 +293,9 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
|
||||
case PSTORE_TYPE_FTRACE:
|
||||
prz = cxt->fprz;
|
||||
break;
|
||||
case PSTORE_TYPE_PMSG:
|
||||
prz = cxt->mprz;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -399,7 +426,7 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
goto fail_out;
|
||||
|
||||
if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
|
||||
!pdata->ftrace_size)) {
|
||||
!pdata->ftrace_size && !pdata->pmsg_size)) {
|
||||
pr_err("The memory size and the record/console size must be "
|
||||
"non-zero\n");
|
||||
goto fail_out;
|
||||
@@ -413,19 +440,22 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
pdata->console_size = rounddown_pow_of_two(pdata->console_size);
|
||||
if (!is_power_of_2(pdata->ftrace_size))
|
||||
pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
|
||||
if (pdata->pmsg_size && !is_power_of_2(pdata->pmsg_size))
|
||||
pdata->pmsg_size = rounddown_pow_of_two(pdata->pmsg_size);
|
||||
|
||||
cxt->dump_read_cnt = 0;
|
||||
cxt->size = pdata->mem_size;
|
||||
cxt->phys_addr = pdata->mem_address;
|
||||
cxt->record_size = pdata->record_size;
|
||||
cxt->console_size = pdata->console_size;
|
||||
cxt->ftrace_size = pdata->ftrace_size;
|
||||
cxt->pmsg_size = pdata->pmsg_size;
|
||||
cxt->dump_oops = pdata->dump_oops;
|
||||
cxt->ecc_info = pdata->ecc_info;
|
||||
|
||||
paddr = cxt->phys_addr;
|
||||
|
||||
dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size;
|
||||
dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size
|
||||
- cxt->pmsg_size;
|
||||
err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
|
||||
if (err)
|
||||
goto fail_out;
|
||||
@@ -440,13 +470,9 @@ static int ramoops_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto fail_init_fprz;
|
||||
|
||||
if (!cxt->przs && !cxt->cprz && !cxt->fprz) {
|
||||
pr_err("memory size too small, minimum is %zu\n",
|
||||
cxt->console_size + cxt->record_size +
|
||||
cxt->ftrace_size);
|
||||
err = -EINVAL;
|
||||
goto fail_cnt;
|
||||
}
|
||||
err = ramoops_init_prz(dev, cxt, &cxt->mprz, &paddr, cxt->pmsg_size, 0);
|
||||
if (err)
|
||||
goto fail_init_mprz;
|
||||
|
||||
cxt->pstore.data = cxt;
|
||||
/*
|
||||
@@ -492,7 +518,8 @@ fail_buf:
|
||||
fail_clear:
|
||||
cxt->pstore.bufsize = 0;
|
||||
cxt->max_dump_cnt = 0;
|
||||
fail_cnt:
|
||||
kfree(cxt->mprz);
|
||||
fail_init_mprz:
|
||||
kfree(cxt->fprz);
|
||||
fail_init_fprz:
|
||||
kfree(cxt->cprz);
|
||||
@@ -550,6 +577,7 @@ static void ramoops_register_dummy(void)
|
||||
dummy_data->record_size = record_size;
|
||||
dummy_data->console_size = ramoops_console_size;
|
||||
dummy_data->ftrace_size = ramoops_ftrace_size;
|
||||
dummy_data->pmsg_size = ramoops_pmsg_size;
|
||||
dummy_data->dump_oops = dump_oops;
|
||||
/*
|
||||
* For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
|
||||
|
||||
@@ -35,6 +35,7 @@ enum pstore_type_id {
|
||||
PSTORE_TYPE_MCE = 1,
|
||||
PSTORE_TYPE_CONSOLE = 2,
|
||||
PSTORE_TYPE_FTRACE = 3,
|
||||
PSTORE_TYPE_PMSG = 4, /* Backport: 7 in upstream 3.19.0-rc3 */
|
||||
PSTORE_TYPE_UNKNOWN = 255
|
||||
};
|
||||
|
||||
|
||||
@@ -81,6 +81,7 @@ struct ramoops_platform_data {
|
||||
unsigned long record_size;
|
||||
unsigned long console_size;
|
||||
unsigned long ftrace_size;
|
||||
unsigned long pmsg_size;
|
||||
int dump_oops;
|
||||
struct persistent_ram_ecc_info ecc_info;
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ struct wifi_platform_data {
|
||||
int (*set_carddetect)(int val);
|
||||
void *(*mem_prealloc)(int section, unsigned long size);
|
||||
int (*get_mac_addr)(unsigned char *buf);
|
||||
int (*get_wake_irq)(void);
|
||||
void *(*get_country_code)(char *ccode, u32 flags);
|
||||
};
|
||||
|
||||
|
||||
@@ -196,6 +196,7 @@ extern int ipv6_dev_ac_inc(struct net_device *dev, const struct in6_addr *addr);
|
||||
extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr);
|
||||
extern bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
|
||||
const struct in6_addr *addr);
|
||||
extern void ipv6_ac_destroy_dev(struct inet6_dev *idev);
|
||||
|
||||
|
||||
/* Device notifier */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# UAPI Header export list
|
||||
header-y += android/
|
||||
header-y += byteorder/
|
||||
header-y += can/
|
||||
header-y += caif/
|
||||
|
||||
2
include/uapi/linux/android/Kbuild
Normal file
2
include/uapi/linux/android/Kbuild
Normal file
@@ -0,0 +1,2 @@
|
||||
# UAPI Header export list
|
||||
header-y += binder.h
|
||||
@@ -131,8 +131,10 @@ struct binder_transaction_data {
|
||||
* identifying the target and contents of the transaction.
|
||||
*/
|
||||
union {
|
||||
__u32 handle; /* target descriptor of command transaction */
|
||||
binder_uintptr_t ptr; /* target descriptor of return transaction */
|
||||
/* target descriptor of command transaction */
|
||||
__u32 handle;
|
||||
/* target descriptor of return transaction */
|
||||
binder_uintptr_t ptr;
|
||||
} target;
|
||||
binder_uintptr_t cookie; /* target object cookie */
|
||||
__u32 code; /* transaction command */
|
||||
@@ -167,7 +169,7 @@ struct binder_ptr_cookie {
|
||||
struct binder_handle_cookie {
|
||||
__u32 handle;
|
||||
binder_uintptr_t cookie;
|
||||
} __attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct binder_pri_desc {
|
||||
__s32 priority;
|
||||
@@ -100,7 +100,6 @@ EXPORT_SYMBOL_GPL(resume_device_irqs);
|
||||
int check_wakeup_irqs(void)
|
||||
{
|
||||
struct irq_desc *desc;
|
||||
char suspend_abort[MAX_SUSPEND_ABORT_LEN];
|
||||
int irq;
|
||||
|
||||
for_each_irq_desc(irq, desc) {
|
||||
|
||||
40
kernel/sys.c
40
kernel/sys.c
@@ -2377,26 +2377,6 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
||||
else
|
||||
return -EINVAL;
|
||||
break;
|
||||
case PR_SET_TIMERSLACK_PID:
|
||||
if (current->pid != (pid_t)arg3 &&
|
||||
!capable(CAP_SYS_NICE))
|
||||
return -EPERM;
|
||||
rcu_read_lock();
|
||||
tsk = find_task_by_pid_ns((pid_t)arg3, &init_pid_ns);
|
||||
if (tsk == NULL) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
get_task_struct(tsk);
|
||||
rcu_read_unlock();
|
||||
if (arg2 <= 0)
|
||||
tsk->timer_slack_ns =
|
||||
tsk->default_timer_slack_ns;
|
||||
else
|
||||
tsk->timer_slack_ns = arg2;
|
||||
put_task_struct(tsk);
|
||||
error = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2416,6 +2396,26 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
|
||||
case PR_GET_TID_ADDRESS:
|
||||
error = prctl_get_tid_address(me, (int __user **)arg2);
|
||||
break;
|
||||
case PR_SET_TIMERSLACK_PID:
|
||||
if (task_pid_vnr(current) != (pid_t)arg3 &&
|
||||
!capable(CAP_SYS_NICE))
|
||||
return -EPERM;
|
||||
rcu_read_lock();
|
||||
tsk = find_task_by_vpid((pid_t)arg3);
|
||||
if (tsk == NULL) {
|
||||
rcu_read_unlock();
|
||||
return -EINVAL;
|
||||
}
|
||||
get_task_struct(tsk);
|
||||
rcu_read_unlock();
|
||||
if (arg2 <= 0)
|
||||
tsk->timer_slack_ns =
|
||||
tsk->default_timer_slack_ns;
|
||||
else
|
||||
tsk->timer_slack_ns = arg2;
|
||||
put_task_struct(tsk);
|
||||
error = 0;
|
||||
break;
|
||||
case PR_SET_CHILD_SUBREAPER:
|
||||
me->signal->is_child_subreaper = !!arg2;
|
||||
break;
|
||||
|
||||
@@ -3155,11 +3155,13 @@ static int addrconf_ifdown(struct net_device *dev, int how)
|
||||
|
||||
write_unlock_bh(&idev->lock);
|
||||
|
||||
/* Step 5: Discard multicast list */
|
||||
if (how)
|
||||
/* Step 5: Discard anycast and multicast list */
|
||||
if (how) {
|
||||
ipv6_ac_destroy_dev(idev);
|
||||
ipv6_mc_destroy_dev(idev);
|
||||
else
|
||||
} else {
|
||||
ipv6_mc_down(idev);
|
||||
}
|
||||
|
||||
idev->tstamp = jiffies;
|
||||
|
||||
|
||||
@@ -341,6 +341,27 @@ static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr)
|
||||
return __ipv6_dev_ac_dec(idev, addr);
|
||||
}
|
||||
|
||||
void ipv6_ac_destroy_dev(struct inet6_dev *idev)
|
||||
{
|
||||
struct ifacaddr6 *aca;
|
||||
|
||||
write_lock_bh(&idev->lock);
|
||||
while ((aca = idev->ac_list) != NULL) {
|
||||
idev->ac_list = aca->aca_next;
|
||||
write_unlock_bh(&idev->lock);
|
||||
|
||||
addrconf_leave_solict(idev, &aca->aca_addr);
|
||||
|
||||
dst_hold(&aca->aca_rt->dst);
|
||||
ip6_del_rt(aca->aca_rt);
|
||||
|
||||
aca_put(aca);
|
||||
|
||||
write_lock_bh(&idev->lock);
|
||||
}
|
||||
write_unlock_bh(&idev->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if the interface has this anycast address
|
||||
* called with rcu_read_lock()
|
||||
|
||||
@@ -1658,6 +1658,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
struct sock *sk;
|
||||
uid_t sock_uid;
|
||||
bool res;
|
||||
bool set_sk_callback_lock = false;
|
||||
|
||||
if (unlikely(module_passive))
|
||||
return (info->match ^ info->invert) == 0;
|
||||
@@ -1715,6 +1716,8 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
MT_DEBUG("qtaguid[%d]: sk=%p got_sock=%d fam=%d proto=%d\n",
|
||||
par->hooknum, sk, got_sock, par->family, ipx_proto(skb, par));
|
||||
if (sk != NULL) {
|
||||
set_sk_callback_lock = true;
|
||||
read_lock_bh(&sk->sk_callback_lock);
|
||||
MT_DEBUG("qtaguid[%d]: sk=%p->sk_socket=%p->file=%p\n",
|
||||
par->hooknum, sk, sk->sk_socket,
|
||||
sk->sk_socket ? sk->sk_socket->file : (void *)-1LL);
|
||||
@@ -1794,6 +1797,8 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
put_sock_ret_res:
|
||||
if (got_sock)
|
||||
xt_socket_put_sk(sk);
|
||||
if (set_sk_callback_lock)
|
||||
read_unlock_bh(&sk->sk_callback_lock);
|
||||
ret_res:
|
||||
MT_DEBUG("qtaguid[%d]: left %d\n", par->hooknum, res);
|
||||
return res;
|
||||
|
||||
@@ -24,7 +24,7 @@ quiet_cmd_modules_install = INSTALL $@
|
||||
INSTALL_MOD_DIR ?= extra
|
||||
ext-mod-dir = $(INSTALL_MOD_DIR)$(subst $(patsubst %/,%,$(KBUILD_EXTMOD)),,$(@D))
|
||||
|
||||
modinst_dir = $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
|
||||
modinst_dir ?= $(if $(KBUILD_EXTMOD),$(ext-mod-dir),kernel/$(@D))
|
||||
|
||||
$(modules):
|
||||
$(call cmd,modules_install,$(MODLIB)/$(modinst_dir))
|
||||
|
||||
@@ -146,6 +146,17 @@ static int selinux_secmark_enabled(void)
|
||||
return (atomic_read(&selinux_secmark_refcount) > 0);
|
||||
}
|
||||
|
||||
static int selinux_netcache_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netif_flush();
|
||||
sel_netnode_flush();
|
||||
sel_netport_flush();
|
||||
synchronize_net();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialise the security for the init task
|
||||
*/
|
||||
@@ -418,15 +429,11 @@ static int sb_finish_set_opts(struct super_block *sb)
|
||||
sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
|
||||
sbsec->flags &= ~SE_SBLABELSUPP;
|
||||
|
||||
/* Special handling for sysfs. Is genfs but also has setxattr handler*/
|
||||
if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
|
||||
sbsec->flags |= SE_SBLABELSUPP;
|
||||
|
||||
/*
|
||||
* Special handling for rootfs. Is genfs but supports
|
||||
* setting SELinux context on in-core inodes.
|
||||
*/
|
||||
if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
|
||||
/* Special handling. Is genfs but also has in-core setxattr handler*/
|
||||
if (!strcmp(sb->s_type->name, "sysfs") ||
|
||||
!strcmp(sb->s_type->name, "pstore") ||
|
||||
!strcmp(sb->s_type->name, "debugfs") ||
|
||||
!strcmp(sb->s_type->name, "rootfs"))
|
||||
sbsec->flags |= SE_SBLABELSUPP;
|
||||
|
||||
/* Initialize the root inode. */
|
||||
@@ -443,6 +450,7 @@ next_inode:
|
||||
list_entry(sbsec->isec_head.next,
|
||||
struct inode_security_struct, list);
|
||||
struct inode *inode = isec->inode;
|
||||
list_del_init(&isec->list);
|
||||
spin_unlock(&sbsec->isec_lock);
|
||||
inode = igrab(inode);
|
||||
if (inode) {
|
||||
@@ -451,7 +459,6 @@ next_inode:
|
||||
iput(inode);
|
||||
}
|
||||
spin_lock(&sbsec->isec_lock);
|
||||
list_del_init(&isec->list);
|
||||
goto next_inode;
|
||||
}
|
||||
spin_unlock(&sbsec->isec_lock);
|
||||
@@ -1367,15 +1374,33 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
|
||||
isec->sid = sbsec->sid;
|
||||
|
||||
if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
|
||||
if (opt_dentry) {
|
||||
isec->sclass = inode_mode_to_security_class(inode->i_mode);
|
||||
rc = selinux_proc_get_sid(opt_dentry,
|
||||
isec->sclass,
|
||||
&sid);
|
||||
if (rc)
|
||||
goto out_unlock;
|
||||
isec->sid = sid;
|
||||
}
|
||||
/* We must have a dentry to determine the label on
|
||||
* procfs inodes */
|
||||
if (opt_dentry)
|
||||
/* Called from d_instantiate or
|
||||
* d_splice_alias. */
|
||||
dentry = dget(opt_dentry);
|
||||
else
|
||||
/* Called from selinux_complete_init, try to
|
||||
* find a dentry. */
|
||||
dentry = d_find_alias(inode);
|
||||
/*
|
||||
* This can be hit on boot when a file is accessed
|
||||
* before the policy is loaded. When we load policy we
|
||||
* may find inodes that have no dentry on the
|
||||
* sbsec->isec_head list. No reason to complain as
|
||||
* these will get fixed up the next time we go through
|
||||
* inode_doinit() with a dentry, before these inodes
|
||||
* could be used again by userspace.
|
||||
*/
|
||||
if (!dentry)
|
||||
goto out_unlock;
|
||||
isec->sclass = inode_mode_to_security_class(inode->i_mode);
|
||||
rc = selinux_proc_get_sid(dentry, isec->sclass, &sid);
|
||||
dput(dentry);
|
||||
if (rc)
|
||||
goto out_unlock;
|
||||
isec->sid = sid;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1882,12 +1907,10 @@ static int selinux_binder_transfer_file(struct task_struct *from, struct task_st
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
struct inode_security_struct *isec = inode->i_security;
|
||||
struct common_audit_data ad;
|
||||
struct selinux_audit_data sad = {0,};
|
||||
int rc;
|
||||
|
||||
ad.type = LSM_AUDIT_DATA_PATH;
|
||||
ad.u.path = file->f_path;
|
||||
ad.selinux_audit_data = &sad;
|
||||
|
||||
if (sid != fsec->sid) {
|
||||
rc = avc_has_perm(sid, fsec->sid,
|
||||
@@ -3171,24 +3194,20 @@ error:
|
||||
|
||||
static int selinux_mmap_addr(unsigned long addr)
|
||||
{
|
||||
int rc = 0;
|
||||
u32 sid = current_sid();
|
||||
|
||||
/*
|
||||
* notice that we are intentionally putting the SELinux check before
|
||||
* the secondary cap_file_mmap check. This is such a likely attempt
|
||||
* at bad behaviour/exploit that we always want to get the AVC, even
|
||||
* if DAC would have also denied the operation.
|
||||
*/
|
||||
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
|
||||
rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
|
||||
MEMPROTECT__MMAP_ZERO, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
int rc;
|
||||
|
||||
/* do DAC check on address space usage */
|
||||
return cap_mmap_addr(addr);
|
||||
rc = cap_mmap_addr(addr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
|
||||
u32 sid = current_sid();
|
||||
rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
|
||||
MEMPROTECT__MMAP_ZERO, NULL);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int selinux_mmap_file(struct file *file, unsigned long reqprot,
|
||||
@@ -4179,15 +4198,15 @@ static int selinux_socket_unix_may_send(struct socket *sock,
|
||||
&ad);
|
||||
}
|
||||
|
||||
static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
|
||||
u32 peer_sid,
|
||||
static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
|
||||
char *addrp, u16 family, u32 peer_sid,
|
||||
struct common_audit_data *ad)
|
||||
{
|
||||
int err;
|
||||
u32 if_sid;
|
||||
u32 node_sid;
|
||||
|
||||
err = sel_netif_sid(ifindex, &if_sid);
|
||||
err = sel_netif_sid(ns, ifindex, &if_sid);
|
||||
if (err)
|
||||
return err;
|
||||
err = avc_has_perm(peer_sid, if_sid,
|
||||
@@ -4280,8 +4299,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
|
||||
if (err)
|
||||
return err;
|
||||
err = selinux_inet_sys_rcv_skb(skb->skb_iif, addrp, family,
|
||||
peer_sid, &ad);
|
||||
err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
|
||||
addrp, family, peer_sid, &ad);
|
||||
if (err) {
|
||||
selinux_netlbl_err(skb, err, 0);
|
||||
return err;
|
||||
@@ -4627,7 +4646,8 @@ out:
|
||||
|
||||
#ifdef CONFIG_NETFILTER
|
||||
|
||||
static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
|
||||
static unsigned int selinux_ip_forward(struct sk_buff *skb,
|
||||
const struct net_device *indev,
|
||||
u16 family)
|
||||
{
|
||||
int err;
|
||||
@@ -4653,14 +4673,14 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
|
||||
|
||||
ad.type = LSM_AUDIT_DATA_NET;
|
||||
ad.u.net = &net;
|
||||
ad.u.net->netif = ifindex;
|
||||
ad.u.net->netif = indev->ifindex;
|
||||
ad.u.net->family = family;
|
||||
if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
|
||||
return NF_DROP;
|
||||
|
||||
if (peerlbl_active) {
|
||||
err = selinux_inet_sys_rcv_skb(ifindex, addrp, family,
|
||||
peer_sid, &ad);
|
||||
err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
|
||||
addrp, family, peer_sid, &ad);
|
||||
if (err) {
|
||||
selinux_netlbl_err(skb, err, 1);
|
||||
return NF_DROP;
|
||||
@@ -4689,7 +4709,7 @@ static unsigned int selinux_ipv4_forward(unsigned int hooknum,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
return selinux_ip_forward(skb, in->ifindex, PF_INET);
|
||||
return selinux_ip_forward(skb, in, PF_INET);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
@@ -4699,7 +4719,7 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
return selinux_ip_forward(skb, in->ifindex, PF_INET6);
|
||||
return selinux_ip_forward(skb, in, PF_INET6);
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
|
||||
@@ -4767,11 +4787,13 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
||||
static unsigned int selinux_ip_postroute(struct sk_buff *skb,
|
||||
const struct net_device *outdev,
|
||||
u16 family)
|
||||
{
|
||||
u32 secmark_perm;
|
||||
u32 peer_sid;
|
||||
int ifindex = outdev->ifindex;
|
||||
struct sock *sk;
|
||||
struct common_audit_data ad;
|
||||
struct lsm_network_audit net = {0,};
|
||||
@@ -4836,7 +4858,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
||||
u32 if_sid;
|
||||
u32 node_sid;
|
||||
|
||||
if (sel_netif_sid(ifindex, &if_sid))
|
||||
if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
|
||||
return NF_DROP;
|
||||
if (avc_has_perm(peer_sid, if_sid,
|
||||
SECCLASS_NETIF, NETIF__EGRESS, &ad))
|
||||
@@ -4858,7 +4880,7 @@ static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
return selinux_ip_postroute(skb, out->ifindex, PF_INET);
|
||||
return selinux_ip_postroute(skb, out, PF_INET);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
@@ -4868,7 +4890,7 @@ static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
|
||||
return selinux_ip_postroute(skb, out, PF_INET6);
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
|
||||
@@ -5848,6 +5870,9 @@ static __init int selinux_init(void)
|
||||
if (register_security(&selinux_ops))
|
||||
panic("SELinux: Unable to register with kernel.\n");
|
||||
|
||||
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
|
||||
panic("SELinux: Unable to register AVC netcache callback\n");
|
||||
|
||||
if (selinux_enforcing)
|
||||
printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
|
||||
else
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
#ifndef _SELINUX_NETIF_H_
|
||||
#define _SELINUX_NETIF_H_
|
||||
|
||||
int sel_netif_sid(int ifindex, u32 *sid);
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
void sel_netif_flush(void);
|
||||
|
||||
int sel_netif_sid(struct net *ns, int ifindex, u32 *sid);
|
||||
|
||||
#endif /* _SELINUX_NETIF_H_ */
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#ifndef _SELINUX_NETNODE_H
|
||||
#define _SELINUX_NETNODE_H
|
||||
|
||||
void sel_netnode_flush(void);
|
||||
|
||||
int sel_netnode_sid(void *addr, u16 family, u32 *sid);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#ifndef _SELINUX_NETPORT_H
|
||||
#define _SELINUX_NETPORT_H
|
||||
|
||||
void sel_netport_flush(void);
|
||||
|
||||
int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include "flask.h"
|
||||
#include "avc.h"
|
||||
|
||||
@@ -78,6 +79,7 @@ struct ipc_security_struct {
|
||||
};
|
||||
|
||||
struct netif_security_struct {
|
||||
struct net *ns; /* network namespace */
|
||||
int ifindex; /* device index */
|
||||
u32 sid; /* SID for this interface */
|
||||
};
|
||||
|
||||
@@ -33,13 +33,14 @@
|
||||
#define POLICYDB_VERSION_ROLETRANS 26
|
||||
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
|
||||
#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
||||
#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
|
||||
|
||||
/* Range of policy versions we understand*/
|
||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||
#else
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES
|
||||
#endif
|
||||
|
||||
/* Mask for just the mount related flags */
|
||||
|
||||
@@ -45,6 +45,7 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
|
||||
|
||||
/**
|
||||
* sel_netif_hashfn - Hashing function for the interface table
|
||||
* @ns: the network namespace
|
||||
* @ifindex: the network interface
|
||||
*
|
||||
* Description:
|
||||
@@ -52,13 +53,14 @@ static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
|
||||
* bucket number for the given interface.
|
||||
*
|
||||
*/
|
||||
static inline u32 sel_netif_hashfn(int ifindex)
|
||||
static inline u32 sel_netif_hashfn(const struct net *ns, int ifindex)
|
||||
{
|
||||
return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
|
||||
return (((uintptr_t)ns + ifindex) & (SEL_NETIF_HASH_SIZE - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* sel_netif_find - Search for an interface record
|
||||
* @ns: the network namespace
|
||||
* @ifindex: the network interface
|
||||
*
|
||||
* Description:
|
||||
@@ -66,15 +68,15 @@ static inline u32 sel_netif_hashfn(int ifindex)
|
||||
* If an entry can not be found in the table return NULL.
|
||||
*
|
||||
*/
|
||||
static inline struct sel_netif *sel_netif_find(int ifindex)
|
||||
static inline struct sel_netif *sel_netif_find(const struct net *ns,
|
||||
int ifindex)
|
||||
{
|
||||
int idx = sel_netif_hashfn(ifindex);
|
||||
int idx = sel_netif_hashfn(ns, ifindex);
|
||||
struct sel_netif *netif;
|
||||
|
||||
list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
|
||||
/* all of the devices should normally fit in the hash, so we
|
||||
* optimize for that case */
|
||||
if (likely(netif->nsec.ifindex == ifindex))
|
||||
if (net_eq(netif->nsec.ns, ns) &&
|
||||
netif->nsec.ifindex == ifindex)
|
||||
return netif;
|
||||
|
||||
return NULL;
|
||||
@@ -96,7 +98,7 @@ static int sel_netif_insert(struct sel_netif *netif)
|
||||
if (sel_netif_total >= SEL_NETIF_HASH_MAX)
|
||||
return -ENOSPC;
|
||||
|
||||
idx = sel_netif_hashfn(netif->nsec.ifindex);
|
||||
idx = sel_netif_hashfn(netif->nsec.ns, netif->nsec.ifindex);
|
||||
list_add_rcu(&netif->list, &sel_netif_hash[idx]);
|
||||
sel_netif_total++;
|
||||
|
||||
@@ -120,6 +122,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
|
||||
|
||||
/**
|
||||
* sel_netif_sid_slow - Lookup the SID of a network interface using the policy
|
||||
* @ns: the network namespace
|
||||
* @ifindex: the network interface
|
||||
* @sid: interface SID
|
||||
*
|
||||
@@ -130,7 +133,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
static int sel_netif_sid_slow(int ifindex, u32 *sid)
|
||||
static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
|
||||
{
|
||||
int ret;
|
||||
struct sel_netif *netif;
|
||||
@@ -140,7 +143,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
|
||||
/* NOTE: we always use init's network namespace since we don't
|
||||
* currently support containers */
|
||||
|
||||
dev = dev_get_by_index(&init_net, ifindex);
|
||||
dev = dev_get_by_index(ns, ifindex);
|
||||
if (unlikely(dev == NULL)) {
|
||||
printk(KERN_WARNING
|
||||
"SELinux: failure in sel_netif_sid_slow(),"
|
||||
@@ -149,7 +152,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
|
||||
}
|
||||
|
||||
spin_lock_bh(&sel_netif_lock);
|
||||
netif = sel_netif_find(ifindex);
|
||||
netif = sel_netif_find(ns, ifindex);
|
||||
if (netif != NULL) {
|
||||
*sid = netif->nsec.sid;
|
||||
ret = 0;
|
||||
@@ -163,6 +166,7 @@ static int sel_netif_sid_slow(int ifindex, u32 *sid)
|
||||
ret = security_netif_sid(dev->name, &new->nsec.sid);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
new->nsec.ns = ns;
|
||||
new->nsec.ifindex = ifindex;
|
||||
ret = sel_netif_insert(new);
|
||||
if (ret != 0)
|
||||
@@ -184,6 +188,7 @@ out:
|
||||
|
||||
/**
|
||||
* sel_netif_sid - Lookup the SID of a network interface
|
||||
* @ns: the network namespace
|
||||
* @ifindex: the network interface
|
||||
* @sid: interface SID
|
||||
*
|
||||
@@ -195,12 +200,12 @@ out:
|
||||
* on failure.
|
||||
*
|
||||
*/
|
||||
int sel_netif_sid(int ifindex, u32 *sid)
|
||||
int sel_netif_sid(struct net *ns, int ifindex, u32 *sid)
|
||||
{
|
||||
struct sel_netif *netif;
|
||||
|
||||
rcu_read_lock();
|
||||
netif = sel_netif_find(ifindex);
|
||||
netif = sel_netif_find(ns, ifindex);
|
||||
if (likely(netif != NULL)) {
|
||||
*sid = netif->nsec.sid;
|
||||
rcu_read_unlock();
|
||||
@@ -208,11 +213,12 @@ int sel_netif_sid(int ifindex, u32 *sid)
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return sel_netif_sid_slow(ifindex, sid);
|
||||
return sel_netif_sid_slow(ns, ifindex, sid);
|
||||
}
|
||||
|
||||
/**
|
||||
* sel_netif_kill - Remove an entry from the network interface table
|
||||
* @ns: the network namespace
|
||||
* @ifindex: the network interface
|
||||
*
|
||||
* Description:
|
||||
@@ -220,13 +226,13 @@ int sel_netif_sid(int ifindex, u32 *sid)
|
||||
* table if it exists.
|
||||
*
|
||||
*/
|
||||
static void sel_netif_kill(int ifindex)
|
||||
static void sel_netif_kill(const struct net *ns, int ifindex)
|
||||
{
|
||||
struct sel_netif *netif;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_bh(&sel_netif_lock);
|
||||
netif = sel_netif_find(ifindex);
|
||||
netif = sel_netif_find(ns, ifindex);
|
||||
if (netif)
|
||||
sel_netif_destroy(netif);
|
||||
spin_unlock_bh(&sel_netif_lock);
|
||||
@@ -240,7 +246,7 @@ static void sel_netif_kill(int ifindex)
|
||||
* Remove all entries from the network interface table.
|
||||
*
|
||||
*/
|
||||
static void sel_netif_flush(void)
|
||||
void sel_netif_flush(void)
|
||||
{
|
||||
int idx;
|
||||
struct sel_netif *netif;
|
||||
@@ -252,25 +258,13 @@ static void sel_netif_flush(void)
|
||||
spin_unlock_bh(&sel_netif_lock);
|
||||
}
|
||||
|
||||
static int sel_netif_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netif_flush();
|
||||
synchronize_net();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct net_device *dev = ptr;
|
||||
|
||||
if (dev_net(dev) != &init_net)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (event == NETDEV_DOWN)
|
||||
sel_netif_kill(dev->ifindex);
|
||||
sel_netif_kill(dev_net(dev), dev->ifindex);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
@@ -291,10 +285,6 @@ static __init int sel_netif_init(void)
|
||||
|
||||
register_netdevice_notifier(&sel_netif_netdev_notifier);
|
||||
|
||||
err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (err)
|
||||
panic("avc_add_callback() failed, error %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,7 +281,7 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid)
|
||||
* Remove all entries from the network address table.
|
||||
*
|
||||
*/
|
||||
static void sel_netnode_flush(void)
|
||||
void sel_netnode_flush(void)
|
||||
{
|
||||
unsigned int idx;
|
||||
struct sel_netnode *node, *node_tmp;
|
||||
@@ -298,15 +298,6 @@ static void sel_netnode_flush(void)
|
||||
spin_unlock_bh(&sel_netnode_lock);
|
||||
}
|
||||
|
||||
static int sel_netnode_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netnode_flush();
|
||||
synchronize_net();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init int sel_netnode_init(void)
|
||||
{
|
||||
int iter;
|
||||
@@ -320,10 +311,6 @@ static __init int sel_netnode_init(void)
|
||||
sel_netnode_hash[iter].size = 0;
|
||||
}
|
||||
|
||||
ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (ret != 0)
|
||||
panic("avc_add_callback() failed, error %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -217,7 +217,7 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid)
|
||||
* Remove all entries from the network address table.
|
||||
*
|
||||
*/
|
||||
static void sel_netport_flush(void)
|
||||
void sel_netport_flush(void)
|
||||
{
|
||||
unsigned int idx;
|
||||
struct sel_netport *port, *port_tmp;
|
||||
@@ -234,15 +234,6 @@ static void sel_netport_flush(void)
|
||||
spin_unlock_bh(&sel_netport_lock);
|
||||
}
|
||||
|
||||
static int sel_netport_avc_callback(u32 event)
|
||||
{
|
||||
if (event == AVC_CALLBACK_RESET) {
|
||||
sel_netport_flush();
|
||||
synchronize_net();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init int sel_netport_init(void)
|
||||
{
|
||||
int iter;
|
||||
@@ -256,10 +247,6 @@ static __init int sel_netport_init(void)
|
||||
sel_netport_hash[iter].size = 0;
|
||||
}
|
||||
|
||||
ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET);
|
||||
if (ret != 0)
|
||||
panic("avc_add_callback() failed, error %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ struct constraint_expr {
|
||||
u32 op; /* operator */
|
||||
|
||||
struct ebitmap names; /* names */
|
||||
struct type_set *type_names;
|
||||
|
||||
struct constraint_expr *next; /* next expression */
|
||||
};
|
||||
|
||||
@@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = {
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
{
|
||||
.version = POLICYDB_VERSION_CONSTRAINT_NAMES,
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
||||
@@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void constraint_expr_destroy(struct constraint_expr *expr)
|
||||
{
|
||||
if (expr) {
|
||||
ebitmap_destroy(&expr->names);
|
||||
if (expr->type_names) {
|
||||
ebitmap_destroy(&expr->type_names->types);
|
||||
ebitmap_destroy(&expr->type_names->negset);
|
||||
kfree(expr->type_names);
|
||||
}
|
||||
kfree(expr);
|
||||
}
|
||||
}
|
||||
|
||||
static int cls_destroy(void *key, void *datum, void *p)
|
||||
{
|
||||
struct class_datum *cladatum;
|
||||
@@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p)
|
||||
while (constraint) {
|
||||
e = constraint->expr;
|
||||
while (e) {
|
||||
ebitmap_destroy(&e->names);
|
||||
etmp = e;
|
||||
e = e->next;
|
||||
kfree(etmp);
|
||||
constraint_expr_destroy(etmp);
|
||||
}
|
||||
ctemp = constraint;
|
||||
constraint = constraint->next;
|
||||
@@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p)
|
||||
while (constraint) {
|
||||
e = constraint->expr;
|
||||
while (e) {
|
||||
ebitmap_destroy(&e->names);
|
||||
etmp = e;
|
||||
e = e->next;
|
||||
kfree(etmp);
|
||||
constraint_expr_destroy(etmp);
|
||||
}
|
||||
ctemp = constraint;
|
||||
constraint = constraint->next;
|
||||
kfree(ctemp);
|
||||
}
|
||||
|
||||
kfree(cladatum->comkey);
|
||||
}
|
||||
kfree(datum);
|
||||
@@ -1156,8 +1171,34 @@ bad:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int read_cons_helper(struct constraint_node **nodep, int ncons,
|
||||
int allowxtarget, void *fp)
|
||||
static void type_set_init(struct type_set *t)
|
||||
{
|
||||
ebitmap_init(&t->types);
|
||||
ebitmap_init(&t->negset);
|
||||
}
|
||||
|
||||
static int type_set_read(struct type_set *t, void *fp)
|
||||
{
|
||||
__le32 buf[1];
|
||||
int rc;
|
||||
|
||||
if (ebitmap_read(&t->types, fp))
|
||||
return -EINVAL;
|
||||
if (ebitmap_read(&t->negset, fp))
|
||||
return -EINVAL;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
t->flags = le32_to_cpu(buf[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int read_cons_helper(struct policydb *p,
|
||||
struct constraint_node **nodep,
|
||||
int ncons, int allowxtarget, void *fp)
|
||||
{
|
||||
struct constraint_node *c, *lc;
|
||||
struct constraint_expr *e, *le;
|
||||
@@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
|
||||
rc = ebitmap_read(&e->names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >=
|
||||
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||
e->type_names = kzalloc(sizeof
|
||||
(*e->type_names),
|
||||
GFP_KERNEL);
|
||||
if (!e->type_names)
|
||||
return -ENOMEM;
|
||||
type_set_init(e->type_names);
|
||||
rc = type_set_read(e->type_names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
|
||||
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
|
||||
if (rc)
|
||||
goto bad;
|
||||
|
||||
@@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||
if (rc)
|
||||
goto bad;
|
||||
ncons = le32_to_cpu(buf[0]);
|
||||
rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
|
||||
rc = read_cons_helper(p, &cladatum->validatetrans,
|
||||
ncons, 1, fp);
|
||||
if (rc)
|
||||
goto bad;
|
||||
}
|
||||
@@ -2750,6 +2804,24 @@ static int common_write(void *vkey, void *datum, void *ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int type_set_write(struct type_set *t, void *fp)
|
||||
{
|
||||
int rc;
|
||||
__le32 buf[1];
|
||||
|
||||
if (ebitmap_write(&t->types, fp))
|
||||
return -EINVAL;
|
||||
if (ebitmap_write(&t->negset, fp))
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = cpu_to_le32(t->flags);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
||||
void *fp)
|
||||
{
|
||||
@@ -2781,6 +2853,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
||||
rc = ebitmap_write(&e->names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >=
|
||||
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||
rc = type_set_write(e->type_names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -153,6 +153,17 @@ struct cond_bool_datum {
|
||||
|
||||
struct cond_node;
|
||||
|
||||
/*
|
||||
* type set preserves data needed to determine constraint info from
|
||||
* policy source. This is not used by the kernel policy but allows
|
||||
* utilities such as audit2allow to determine constraint denials.
|
||||
*/
|
||||
struct type_set {
|
||||
struct ebitmap types;
|
||||
struct ebitmap negset;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* The configuration data includes security contexts for
|
||||
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
|
||||
|
||||
Reference in New Issue
Block a user