random: Initialize variable as requested by valgrind
[libgcrypt.git] / src / hwfeatures.c
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_INTEL_RDTSC,         "intel-rdtsc" },
61     { HWF_INTEL_SHAEXT,        "intel-shaext" },
62     { HWF_ARM_NEON,            "arm-neon" },
63     { HWF_ARM_AES,             "arm-aes" },
64     { HWF_ARM_SHA1,            "arm-sha1" },
65     { HWF_ARM_SHA2,            "arm-sha2" },
66     { HWF_ARM_PMULL,           "arm-pmull" }
67   };
68
69 /* A bit vector with the hardware features which shall not be used.
70    This variable must be set prior to any initialization.  */
71 static unsigned int disabled_hw_features;
72
73 /* A bit vector describing the hardware features currently
74    available. */
75 static unsigned int hw_features;
76
77
78 \f
79 /* Disable a feature by name.  This function must be called *before*
80    _gcry_detect_hw_features is called.  */
81 gpg_err_code_t
82 _gcry_disable_hw_feature (const char *name)
83 {
84   int i;
85   size_t n1, n2;
86
87   while (name && *name)
88     {
89       n1 = strcspn (name, ":,");
90       if (!n1)
91         ;
92       else if (n1 == 3 && !strncmp (name, "all", 3))
93         disabled_hw_features = ~0;
94       else
95         {
96           for (i=0; i < DIM (hwflist); i++)
97             {
98               n2 = strlen (hwflist[i].desc);
99               if (n1 == n2 && !strncmp (hwflist[i].desc, name, n2))
100                 {
101                   disabled_hw_features |= hwflist[i].flag;
102                   break;
103                 }
104             }
105           if (!(i < DIM (hwflist)))
106             return GPG_ERR_INV_NAME;
107         }
108       name += n1;
109       if (*name)
110         name++; /* Skip delimiter ':' or ','.  */
111     }
112   return 0;
113 }
114
115
116 /* Return a bit vector describing the available hardware features.
117    The HWF_ constants are used to test for them. */
118 unsigned int
119 _gcry_get_hw_features (void)
120 {
121   return hw_features;
122 }
123
124
125 /* Enumerate all features.  The caller is expected to start with an
126    IDX of 0 and then increment IDX until NULL is returned.  */
127 const char *
128 _gcry_enum_hw_features (int idx, unsigned int *r_feature)
129 {
130   if (idx < 0 || idx >= DIM (hwflist))
131     return NULL;
132   if (r_feature)
133     *r_feature = hwflist[idx].flag;
134   return hwflist[idx].desc;
135 }
136
137
138 /* Read a file with features which shall not be used.  The file is a
139    simple text file where empty lines and lines with the first non
140    white-space character being '#' are ignored.  */
141 static void
142 parse_hwf_deny_file (void)
143 {
144   const char *fname = HWF_DENY_FILE;
145   FILE *fp;
146   char buffer[256];
147   char *p, *pend;
148   int lnr = 0;
149
150   fp = fopen (fname, "r");
151   if (!fp)
152     return;
153
154   for (;;)
155     {
156       if (!fgets (buffer, sizeof buffer, fp))
157         {
158           if (!feof (fp))
159             {
160 #ifdef HAVE_SYSLOG
161               syslog (LOG_USER|LOG_WARNING,
162                       "Libgcrypt warning: error reading '%s', line %d",
163                       fname, lnr);
164 #endif /*HAVE_SYSLOG*/
165             }
166           fclose (fp);
167           return;
168         }
169       lnr++;
170       for (p=buffer; my_isascii (*p) && isspace (*p); p++)
171         ;
172       pend = strchr (p, '\n');
173       if (pend)
174         *pend = 0;
175       pend = p + (*p? (strlen (p)-1):0);
176       for ( ;pend > p; pend--)
177         if (my_isascii (*pend) && isspace (*pend))
178           *pend = 0;
179       if (!*p || *p == '#')
180         continue;
181
182       if (_gcry_disable_hw_feature (p) == GPG_ERR_INV_NAME)
183         {
184 #ifdef HAVE_SYSLOG
185           syslog (LOG_USER|LOG_WARNING,
186                   "Libgcrypt warning: unknown feature in '%s', line %d",
187                   fname, lnr);
188 #endif /*HAVE_SYSLOG*/
189         }
190     }
191 }
192
193
194 /* Detect the available hardware features.  This function is called
195    once right at startup and we assume that no other threads are
196    running.  */
197 void
198 _gcry_detect_hw_features (void)
199 {
200   hw_features = 0;
201
202   if (fips_mode ())
203     return; /* Hardware support is not to be evaluated.  */
204
205   parse_hwf_deny_file ();
206
207 #if defined (HAVE_CPU_ARCH_X86)
208   {
209     hw_features = _gcry_hwf_detect_x86 ();
210   }
211 #endif /* HAVE_CPU_ARCH_X86 */
212 #if defined (HAVE_CPU_ARCH_ARM)
213   {
214     hw_features = _gcry_hwf_detect_arm ();
215   }
216 #endif /* HAVE_CPU_ARCH_ARM */
217
218   hw_features &= ~disabled_hw_features;
219 }