response-202005.tex (11355B)
1 \documentclass[11pt]{article} 2 \oddsidemargin=0in \evensidemargin=0in 3 \textwidth=6.2in \textheight=8.7in 4 %\topmargin=-0.2in 5 6 \usepackage[ansinew]{inputenc} 7 \usepackage{makeidx,amsmath,amssymb,exscale,multicol,epsfig,graphics} 8 9 \begin{document} 10 \pagestyle{headings} 11 \title{Preliminary response to the \\ GNU Taler security audit in Q2/Q3 2020} 12 \author{Christian Grothoff \and Florian Dold} 13 14 \maketitle 15 16 \section{Abstract} 17 18 This is the response to the source code audit report CodeBlau 19 created for GNU Taler in Q2/Q3 2020. 20 21 \section{Management Summary} 22 23 We thank CodeBlau for their detailed report and thorough analysis. We are 24 particularly impressed that they reported issues against components that were 25 not even in-scope, and also that they found an {\em interesting} new corner 26 case we had not previously considered. Finally, we also find several of their 27 architectural recommendations to strengthen security to be worthwhile, and 28 while some were already on our long-term roadmap, we will reprioritize our 29 roadmap given their recommendations. 30 31 Given our extensive discussions with CodeBlau, we also have the impression 32 that they really took the time to understand the system, and look forward 33 to working with CodeBlau as a competent auditor for GNU Taler in the future. 34 35 \section{Issues in the exchange} 36 37 We agree with the issues CodeBlau discovered and both parties believe that 38 they have all been addressed. 39 40 \section{Issues in the auditor} 41 42 We appreciate CodeBlau's extensive list of checks the Taler auditor performs, 43 which was previously not documented adequately by us. We agree that the 44 auditor still needs more comprehensive documentation. 45 46 As for issue \#6416, we agree with the analysis. However, the proposed fix 47 of making the primary key include the denomination would create other problems, 48 such as the exchange sometimes not having the denomination key (link, refund) 49 and the code in various places relying on the assumption of the coin's 50 public key being unique. Furthermore, allowing coin key re-use may validate 51 a terrible practice. We thus decided it is better to ``fail early'', and 52 modified the code to check that the coin public key is ``unique'' during 53 deposit, refresh and recoup and ensured that the exchange returns a proof 54 of non-uniqueness in case of a violation. The test suite was extended to 55 cover the corner case. 56 57 \section{Issues in GNUnet} 58 59 We agree with the issues CodeBlau discovered and both parties believe that 60 they have all been addressed. 61 62 \section{General remarks on the code} 63 64 We understand that writing the code in another programming language may make 65 certain checks for the auditor less work to implement. However, our choice of C 66 is based on the advantages that make it superior to contemporary languages for 67 our use case: relatively low complexity of the language (compared to C++); 68 availability of mature compilers, static and dynamic analysis tools; 69 predictable performance; access to stable and battle-tested libraries; and 70 future-proofness due to portability to older systems as well as new platforms. 71 72 We believe creating a parallel implementation in other languages would provide 73 advantages, especially with respect to avoiding ``the implementation is the 74 specification''-style issues. However, given limited resources will not make 75 this a priority. 76 77 We disagree that all modern software development has embraced the idea that 78 memory errors are to be handled in ways other than terminating or restarting 79 the process. Many programming languages (Erlang, Java) hardly offer any other 80 means of handling out-of-memory situations than to terminate the process. We 81 also insist that Taler {\em does} handle out-of-memory as it does have code 82 that terminates the process (we do {\em not} simply ignore the return value 83 from {\tt malloc()} or other allocation functions!). We simply consider that 84 terminating the process (which is run by a hypervisor that will restart the 85 service) is the correct way to handle out-of-memory situations. We also have 86 limits in place that should prevent attackers from causing large amounts of 87 memory to be consumed, and also have code to automatically preemptively 88 restart the process to guard against memory exhaustion from memory 89 fragmentation. Finally, a common problem with abrupt termination may be 90 corrupted files. However, the code mostly only reads from files and limits 91 writing to the Postgres database. Hence, there is no possibility of corrupt 92 files being left behind even in the case of abnormal termination. 93 94 95 \section{More specs and documentation code} 96 97 We agree with the recommendation that the documentation should be improved, 98 and will try to improve it along the lines recommended by CodeBlau. 99 100 \section{Protocol change: API for uniformly distributed seeds} 101 102 We agree with the suggestion, have made the necessary changes, and both 103 parties believe that the suggestion has been implemented. 104 105 \section{Reduce code complexity} 106 107 \subsection{Reduce global variables} 108 109 While we do not disagree with the general goal to have few global variables, 110 we also believe that there are cases where global variables make sense. 111 112 We have already tried to minimize the scope of variables. The remaining few 113 global variables are largely ``read-only'' configuration data. The report does 114 not point out specific instances that would be particularly beneficial to 115 eliminate. As we continue to work on the code, we will of course evaluate 116 whether the removal of a particular global variable would make the code 117 cleaner. 118 119 Also, we want to point out that all global variables we introduce 120 in the exchange are indicated with a prefix {\tt TEH\_} in the code, so they 121 are easy to identify as such. 122 123 \subsection{Callbacks, type pruning} 124 125 We understand that higher order functions in C can be confusing, but this 126 is also a common pattern to enable code re-use and asynchronous execution 127 which is essential for network applications. We do not believe that we 128 use callbacks {\em excessively}. Rewriting the code in another language 129 may indeed make this part easier to understand, alas would have other 130 disadvantages as pointed out previously. 131 132 \subsection{Initializing structs with memset} 133 134 Using {\tt memset()} first prevents compiler (or valgrind) warnings about 135 using uninitialized memory, possibly hiding bugs. We also do use struct 136 initialization in many cases. 137 138 The GNUnet-wrappers are generally designed to be ``safer'' or ``stricter'' 139 variants of the corresponding libc functions, and not merely ``the same''. 140 Hence we do not believe that renaming {\tt GNUNET\_malloc} is indicated. 141 142 The argument that {\tt memset()}ing first makes the code inherently more 143 obvious also seems fallacious, as it would commonly result in dead stores, 144 which can confuse developers and produce false-positive warnings from static 145 analysis tools. 146 147 \subsection{NULL pointer handling} 148 149 The problem with the ``goto fail'' style error handling is that it rarely 150 results in specific error handling where diagnostics are created that are 151 specific to the error. Using this style of programming encourages developers 152 to create simplistic error handling, which can result in inappropriate error 153 handling logic and also makes it harder to attribute errors to the specific 154 cause. 155 156 However, we have no prohibition on using this style of error handling either: 157 if it is appropriate, develpers should make a case-by-case decision as to how 158 to best handle a specific error. 159 160 We have made some first changes to how {\tt GNUNET\_free()} works in response 161 to the report, and will discuss further changes with the GNUnet development 162 team. 163 164 \subsection{Hidden security assumptions} 165 166 We disagree that the assumptions stated are ``hidden'', as (1) the Taler code 167 has its own checks to warrant that the requirements of the {\tt 168 GNUNET\_malloc()} API are satisfied (so enforcement is not limited to the 169 abstraction layer), and (2) the maximum allocation size limit is quite clearly 170 specified in the GNUnet documentation. Also, the GNUnet-functions are not 171 merely an abstraction layer for portability, but they provided extended 172 semantics that we rely upon. So it is not like it is possible to swap this 173 layer and expect anything to continue to work. 174 175 When we use the libjansson library, it is understood that it does not use 176 the GNUnet operations, and the code is careful about this distinction. 177 178 \subsection{Get rid of boolean function arguments} 179 180 We agree that this can make the code more readable, and have in some places 181 already changed the code in this way. 182 183 \section{Structural Recommendation} 184 185 \subsection{Least privilege} 186 187 It is wrong to say that GNU Taler has ``no work done'' on privilege separation. 188 For example, the {\tt taler-exchange-dbinit} tool is the only tool that requires 189 CREATE, ALTER and DROP rights on database tables, thus enusring that the ``main'' 190 process does not need these rights. 191 192 We also already had the {\tt taler-exchange-keyup} tool responsible for 193 initializing keys. In response to the audit, we already changed the GNUnet API 194 to make sure that tools do not create keys as a side-effect of trying to read 195 non-existent key files. 196 197 We agree with the recommendation on further privilege separation for access 198 to cryptographic keys, and intend to implement this in the near future. 199 200 \subsection{File system access} 201 202 The auditor helpers actually only read from the file system, only the LaTeX 203 invocation to compile the final report to PDF inherently needs write 204 access. We do not predict that we will retool LaTeX. Also, the file system 205 access is completely uncritical, as the auditor by design runs on a system 206 that is separate from the production exchange system. 207 208 Because that system will not have {\em any} crypto keys (not even the one of 209 the auditor!), CodeBlau is wrong to assume that reading from or writing to the 210 file system represents a security threat. 211 212 We have started to better document the operational requirements on running the 213 auditor. 214 215 \subsection{Avoid dlopen} 216 217 Taler actually uses {\tt ltdlopen()} from GNU libtool, which provides 218 compiler flags to convert the dynamic linkage into static linkage. For 219 development, dynamic linkage has many advantages. 220 221 We plan to test and document how to build GNU Taler with only static 222 linkage, and will recommend this style of deployment for the Taler 223 exchange for production. 224 225 \subsection{Reduce reliance on PostgreSQL} 226 227 CodeBlau's suggestion to use an append-only transaction logging service in 228 addition to the PostgreSQL database is a reasonable suggestion for a 229 production-grade deployment of GNU Taler, as it would allow partial disaster 230 recovery even in the presence of an attacker that has gained write access to 231 the exchange's database. 232 233 We are currently still investigating whether the transaction logging should be 234 implemented directly by the exchange service, or via the database's extensible 235 replication mechanism. Any implementation of such an append-only logging 236 mechanism must be carefully designed to ensure it does not negatively impact 237 the exchange's availability and does not interfere with serializability of 238 database transactions. As such we believe that transaction logging can only be 239 provided on a best-effort basis. Fortunately, even a best-effort append-only 240 transaction log would serve to limit the financial damage incurred by the 241 exchange in an active database compromise scenario. 242 243 \end{document}