Line data Source code
1 : /* hwfeatures.c - Detect hardware features.
2 : * Copyright (C) 2007, 2011 Free Software Foundation, Inc.
3 : * Copyright (C) 2012 g10 Code GmbH
4 : *
5 : * This file is part of Libgcrypt.
6 : *
7 : * Libgcrypt is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU Lesser General Public License as
9 : * published by the Free Software Foundation; either version 2.1 of
10 : * the License, or (at your option) any later version.
11 : *
12 : * Libgcrypt is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU Lesser General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU Lesser General Public
18 : * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <stdio.h>
23 : #include <ctype.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <stdarg.h>
27 : #include <unistd.h>
28 : #ifdef HAVE_SYSLOG
29 : # include <syslog.h>
30 : #endif /*HAVE_SYSLOG*/
31 :
32 : #include "g10lib.h"
33 : #include "hwf-common.h"
34 :
35 : /* The name of a file used to globally disable selected features. */
36 : #define HWF_DENY_FILE "/etc/gcrypt/hwf.deny"
37 :
38 : /* A table to map hardware features to a string. */
39 : static struct
40 : {
41 : unsigned int flag;
42 : const char *desc;
43 : } hwflist[] =
44 : {
45 : { HWF_PADLOCK_RNG, "padlock-rng" },
46 : { HWF_PADLOCK_AES, "padlock-aes" },
47 : { HWF_PADLOCK_SHA, "padlock-sha" },
48 : { HWF_PADLOCK_MMUL, "padlock-mmul"},
49 : { HWF_INTEL_CPU, "intel-cpu" },
50 : { HWF_INTEL_FAST_SHLD, "intel-fast-shld" },
51 : { HWF_INTEL_BMI2, "intel-bmi2" },
52 : { HWF_INTEL_SSSE3, "intel-ssse3" },
53 : { HWF_INTEL_SSE4_1, "intel-sse4.1" },
54 : { HWF_INTEL_PCLMUL, "intel-pclmul" },
55 : { HWF_INTEL_AESNI, "intel-aesni" },
56 : { HWF_INTEL_RDRAND, "intel-rdrand" },
57 : { HWF_INTEL_AVX, "intel-avx" },
58 : { HWF_INTEL_AVX2, "intel-avx2" },
59 : { HWF_INTEL_FAST_VPGATHER, "intel-fast-vpgather" },
60 : { HWF_ARM_NEON, "arm-neon" },
61 : { HWF_ARM_AES, "arm-aes" },
62 : { HWF_ARM_SHA1, "arm-sha1" },
63 : { HWF_ARM_SHA2, "arm-sha2" },
64 : { HWF_ARM_PMULL, "arm-pmull" }
65 : };
66 :
67 : /* A bit vector with the hardware features which shall not be used.
68 : This variable must be set prior to any initialization. */
69 : static unsigned int disabled_hw_features;
70 :
71 : /* A bit vector describing the hardware features currently
72 : available. */
73 : static unsigned int hw_features;
74 :
75 : /* Convenience macros. */
76 : #define my_isascii(c) (!((c) & 0x80))
77 :
78 :
79 :
80 : /* Disable a feature by name. This function must be called *before*
81 : _gcry_detect_hw_features is called. */
82 : gpg_err_code_t
83 1 : _gcry_disable_hw_feature (const char *name)
84 : {
85 : int i;
86 : size_t n1, n2;
87 :
88 3 : while (name && *name)
89 : {
90 1 : n1 = strcspn (name, ":,");
91 1 : if (!n1)
92 : ;
93 1 : else if (n1 == 3 && !strncmp (name, "all", 3))
94 1 : disabled_hw_features = ~0;
95 : else
96 : {
97 0 : for (i=0; i < DIM (hwflist); i++)
98 : {
99 0 : n2 = strlen (hwflist[i].desc);
100 0 : if (n1 == n2 && !strncmp (hwflist[i].desc, name, n2))
101 : {
102 0 : disabled_hw_features |= hwflist[i].flag;
103 0 : break;
104 : }
105 : }
106 0 : if (!(i < DIM (hwflist)))
107 0 : return GPG_ERR_INV_NAME;
108 : }
109 1 : name += n1;
110 1 : if (*name)
111 0 : name++; /* Skip delimiter ':' or ','. */
112 : }
113 1 : return 0;
114 : }
115 :
116 :
117 : /* Return a bit vector describing the available hardware features.
118 : The HWF_ constants are used to test for them. */
119 : unsigned int
120 263475 : _gcry_get_hw_features (void)
121 : {
122 263475 : return hw_features;
123 : }
124 :
125 :
126 : /* Enumerate all features. The caller is expected to start with an
127 : IDX of 0 and then increment IDX until NULL is returned. */
128 : const char *
129 21 : _gcry_enum_hw_features (int idx, unsigned int *r_feature)
130 : {
131 21 : if (idx < 0 || idx >= DIM (hwflist))
132 1 : return NULL;
133 20 : if (r_feature)
134 20 : *r_feature = hwflist[idx].flag;
135 20 : return hwflist[idx].desc;
136 : }
137 :
138 :
139 : /* Read a file with features which shall not be used. The file is a
140 : simple text file where empty lines and lines with the first non
141 : white-space character being '#' are ignored. */
142 : static void
143 34 : parse_hwf_deny_file (void)
144 : {
145 34 : const char *fname = HWF_DENY_FILE;
146 : FILE *fp;
147 : char buffer[256];
148 : char *p, *pend;
149 34 : int lnr = 0;
150 :
151 34 : fp = fopen (fname, "r");
152 34 : if (!fp)
153 34 : return;
154 :
155 : for (;;)
156 : {
157 0 : if (!fgets (buffer, sizeof buffer, fp))
158 : {
159 0 : if (!feof (fp))
160 : {
161 : #ifdef HAVE_SYSLOG
162 0 : syslog (LOG_USER|LOG_WARNING,
163 : "Libgcrypt warning: error reading '%s', line %d",
164 : fname, lnr);
165 : #endif /*HAVE_SYSLOG*/
166 : }
167 0 : fclose (fp);
168 0 : return;
169 : }
170 0 : lnr++;
171 0 : for (p=buffer; my_isascii (*p) && isspace (*p); p++)
172 : ;
173 0 : pend = strchr (p, '\n');
174 0 : if (pend)
175 0 : *pend = 0;
176 0 : pend = p + (*p? (strlen (p)-1):0);
177 0 : for ( ;pend > p; pend--)
178 0 : if (my_isascii (*pend) && isspace (*pend))
179 0 : *pend = 0;
180 0 : if (!*p || *p == '#')
181 0 : continue;
182 :
183 0 : if (_gcry_disable_hw_feature (p) == GPG_ERR_INV_NAME)
184 : {
185 : #ifdef HAVE_SYSLOG
186 0 : syslog (LOG_USER|LOG_WARNING,
187 : "Libgcrypt warning: unknown feature in '%s', line %d",
188 : fname, lnr);
189 : #endif /*HAVE_SYSLOG*/
190 : }
191 : }
192 : }
193 :
194 :
195 : /* Detect the available hardware features. This function is called
196 : once right at startup and we assume that no other threads are
197 : running. */
198 : void
199 34 : _gcry_detect_hw_features (void)
200 : {
201 34 : hw_features = 0;
202 :
203 34 : if (fips_mode ())
204 0 : return; /* Hardware support is not to be evaluated. */
205 :
206 34 : parse_hwf_deny_file ();
207 :
208 : #if defined (HAVE_CPU_ARCH_X86)
209 : {
210 34 : hw_features = _gcry_hwf_detect_x86 ();
211 : }
212 : #endif /* HAVE_CPU_ARCH_X86 */
213 : #if defined (HAVE_CPU_ARCH_ARM)
214 : {
215 : hw_features = _gcry_hwf_detect_arm ();
216 : }
217 : #endif /* HAVE_CPU_ARCH_ARM */
218 :
219 34 : hw_features &= ~disabled_hw_features;
220 : }
|