brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · a2afd10 Raw
174 lines · c
1/*2 * Constant-time equality testing of memory regions.3 *4 * Authors:5 *6 *   James Yonan <james@openvpn.net>7 *   Daniel Borkmann <dborkman@redhat.com>8 *9 * This file is provided under a dual BSD/GPLv2 license.  When using or10 * redistributing this file, you may do so under either license.11 *12 * GPL LICENSE SUMMARY13 *14 * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.15 *16 * This program is free software; you can redistribute it and/or modify17 * it under the terms of version 2 of the GNU General Public License as18 * published by the Free Software Foundation.19 *20 * This program is distributed in the hope that it will be useful, but21 * WITHOUT ANY WARRANTY; without even the implied warranty of22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU23 * General Public License for more details.24 *25 * You should have received a copy of the GNU General Public License26 * along with this program; if not, write to the Free Software27 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.28 * The full GNU General Public License is included in this distribution29 * in the file called LICENSE.GPL.30 *31 * BSD LICENSE32 *33 * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved.34 *35 * Redistribution and use in source and binary forms, with or without36 * modification, are permitted provided that the following conditions37 * are met:38 *39 *   * Redistributions of source code must retain the above copyright40 *     notice, this list of conditions and the following disclaimer.41 *   * Redistributions in binary form must reproduce the above copyright42 *     notice, this list of conditions and the following disclaimer in43 *     the documentation and/or other materials provided with the44 *     distribution.45 *   * Neither the name of OpenVPN Technologies nor the names of its46 *     contributors may be used to endorse or promote products derived47 *     from this software without specific prior written permission.48 *49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.60 */61 62#include <linux/unaligned.h>63#include <crypto/algapi.h>64#include <linux/module.h>65 66/* Generic path for arbitrary size */67static inline unsigned long68__crypto_memneq_generic(const void *a, const void *b, size_t size)69{70	unsigned long neq = 0;71 72#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)73	while (size >= sizeof(unsigned long)) {74		neq |= get_unaligned((unsigned long *)a) ^75		       get_unaligned((unsigned long *)b);76		OPTIMIZER_HIDE_VAR(neq);77		a += sizeof(unsigned long);78		b += sizeof(unsigned long);79		size -= sizeof(unsigned long);80	}81#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */82	while (size > 0) {83		neq |= *(unsigned char *)a ^ *(unsigned char *)b;84		OPTIMIZER_HIDE_VAR(neq);85		a += 1;86		b += 1;87		size -= 1;88	}89	return neq;90}91 92/* Loop-free fast-path for frequently used 16-byte size */93static inline unsigned long __crypto_memneq_16(const void *a, const void *b)94{95	unsigned long neq = 0;96 97#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS98	if (sizeof(unsigned long) == 8) {99		neq |= get_unaligned((unsigned long *)a) ^100		       get_unaligned((unsigned long *)b);101		OPTIMIZER_HIDE_VAR(neq);102		neq |= get_unaligned((unsigned long *)(a + 8)) ^103		       get_unaligned((unsigned long *)(b + 8));104		OPTIMIZER_HIDE_VAR(neq);105	} else if (sizeof(unsigned int) == 4) {106		neq |= get_unaligned((unsigned int *)a) ^107		       get_unaligned((unsigned int *)b);108		OPTIMIZER_HIDE_VAR(neq);109		neq |= get_unaligned((unsigned int *)(a + 4)) ^110		       get_unaligned((unsigned int *)(b + 4));111		OPTIMIZER_HIDE_VAR(neq);112		neq |= get_unaligned((unsigned int *)(a + 8)) ^113		       get_unaligned((unsigned int *)(b + 8));114		OPTIMIZER_HIDE_VAR(neq);115		neq |= get_unaligned((unsigned int *)(a + 12)) ^116		       get_unaligned((unsigned int *)(b + 12));117		OPTIMIZER_HIDE_VAR(neq);118	} else119#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */120	{121		neq |= *(unsigned char *)(a)    ^ *(unsigned char *)(b);122		OPTIMIZER_HIDE_VAR(neq);123		neq |= *(unsigned char *)(a+1)  ^ *(unsigned char *)(b+1);124		OPTIMIZER_HIDE_VAR(neq);125		neq |= *(unsigned char *)(a+2)  ^ *(unsigned char *)(b+2);126		OPTIMIZER_HIDE_VAR(neq);127		neq |= *(unsigned char *)(a+3)  ^ *(unsigned char *)(b+3);128		OPTIMIZER_HIDE_VAR(neq);129		neq |= *(unsigned char *)(a+4)  ^ *(unsigned char *)(b+4);130		OPTIMIZER_HIDE_VAR(neq);131		neq |= *(unsigned char *)(a+5)  ^ *(unsigned char *)(b+5);132		OPTIMIZER_HIDE_VAR(neq);133		neq |= *(unsigned char *)(a+6)  ^ *(unsigned char *)(b+6);134		OPTIMIZER_HIDE_VAR(neq);135		neq |= *(unsigned char *)(a+7)  ^ *(unsigned char *)(b+7);136		OPTIMIZER_HIDE_VAR(neq);137		neq |= *(unsigned char *)(a+8)  ^ *(unsigned char *)(b+8);138		OPTIMIZER_HIDE_VAR(neq);139		neq |= *(unsigned char *)(a+9)  ^ *(unsigned char *)(b+9);140		OPTIMIZER_HIDE_VAR(neq);141		neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10);142		OPTIMIZER_HIDE_VAR(neq);143		neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11);144		OPTIMIZER_HIDE_VAR(neq);145		neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12);146		OPTIMIZER_HIDE_VAR(neq);147		neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13);148		OPTIMIZER_HIDE_VAR(neq);149		neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14);150		OPTIMIZER_HIDE_VAR(neq);151		neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15);152		OPTIMIZER_HIDE_VAR(neq);153	}154 155	return neq;156}157 158/* Compare two areas of memory without leaking timing information,159 * and with special optimizations for common sizes.  Users should160 * not call this function directly, but should instead use161 * crypto_memneq defined in crypto/algapi.h.162 */163noinline unsigned long __crypto_memneq(const void *a, const void *b,164				       size_t size)165{166	switch (size) {167	case 16:168		return __crypto_memneq_16(a, b);169	default:170		return __crypto_memneq_generic(a, b, size);171	}172}173EXPORT_SYMBOL(__crypto_memneq);174