Add today's security advisories 25/13925/4
authorBenjamin Kaduk <kaduk@mit.edu>
Tue, 22 Oct 2019 22:59:10 +0000 (15:59 -0700)
committerBenjamin Kaduk <kaduk@mit.edu>
Tue, 22 Oct 2019 23:18:54 +0000 (19:18 -0400)
OPENAFS-SA-2019-001, OPENAFS-SA-2019-002, and OPENAFS-SA-2019-003.
Add the signed advisory texts, patches, and appropriate notes
on the main security page.

Also fix the table entry for OPENAFS-SA-2018-003 at the bottom of the
page.

Change-Id: I006ded6b437c4820b5171c83f0f396d32f6f9349
Reviewed-on: https://gerrit.openafs.org/13925
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
Tested-by: Benjamin Kaduk <kaduk@mit.edu>

13 files changed:
security/OPENAFS-SA-2019-001.txt [new file with mode: 0644]
security/OPENAFS-SA-2019-002.txt [new file with mode: 0644]
security/OPENAFS-SA-2019-003.txt [new file with mode: 0644]
security/index.html
security/openafs-sa-2019-001-master.patch [new file with mode: 0644]
security/openafs-sa-2019-001-stable16.patch [new file with mode: 0644]
security/openafs-sa-2019-001-stable18.patch [new file with mode: 0644]
security/openafs-sa-2019-002-master.patch [new file with mode: 0644]
security/openafs-sa-2019-002-stable16.patch [new file with mode: 0644]
security/openafs-sa-2019-002-stable18.patch [new file with mode: 0644]
security/openafs-sa-2019-003-master.patch [new file with mode: 0644]
security/openafs-sa-2019-003-stable16.patch [new file with mode: 0644]
security/openafs-sa-2019-003-stable18.patch [new file with mode: 0644]

diff --git a/security/OPENAFS-SA-2019-001.txt b/security/OPENAFS-SA-2019-001.txt
new file mode 100644 (file)
index 0000000..12a17ec
--- /dev/null
@@ -0,0 +1,134 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA512
+
+OpenAFS Security Advisory 2019-001
+
+Topic: information leakage from uninitialized RPC output variables on error
+
+Issued: 22 October, 2019
+Affected: OpenAFS versions 1.0 through 1.6.23, and 1.8.0 through 1.8.4
+
+Generated RPC handler routines ran output variables through XDR encoding
+even when the call had failed and would shortly be aborted (and for
+which uninitialized output variables is common); any complete packets
+assembled in the process would be sent to the peer, leaking the contents
+of the uninitialized memory in question.
+
+SUMMARY
+=======
+
+AFS-3 RPCs use the XDR data encoding to represent input/output arguments,
+and OpenAFS uses an XDR en/decoder that is tightly integrated to the Rx
+protocol implementation.  The generated RPC handler code takes care of
+allocating storage/variables for the input/output variables and reading the
+input parameters from the network into local storage before calling the
+function that implements the RPC logic.  Similarly, after that function
+call, the generated code takes care of encoding the output parameters into
+Rx packets and sending them to the peer as necessary, then deallocating the
+storage it allocated and returning control flow to the caller.  However, in
+the case of an error return from the handler, the Rx layer will abort the
+current Rx call to direct the peer that the operation failed, and
+well-behaved peers will discard any information obtained as part of the
+aborted call.  Unfortunately, the generated code was going through the
+"encode output parameters" step even when the resulting data would not be of
+use to well-behaved peers, and in some cases the output parameters remained
+uninitialized in the case of error returns (on the assumption that since it
+was an error, the call would be aborted).  So for non-well-behaved peers, a
+large partially constructed response could include information from
+uninitialized memory in the RPC handler.
+
+IMPACT
+======
+
+RPCs that produce large responses are most at risk, and configurations that
+use small MTU values, since those increate the likelihood of one or more
+complete Rx packets being filled.  Leaving output variables uninitialized on
+error returns is a fairly common phenomenon, so many RPCs are expected to be
+at risk.  The amount and rate of data exposure is highly context-dependent,
+since the memory allocator behavior and other load on the system affect
+exactly what information is leaked from uninitialized memory.
+
+At present, no code paths in the cache manager are known to trigger this
+issue, but the risk has not been conclusively shown to be absent, so clients
+are listed as potentially affected as well.
+
+AFFECTED SOFTWARE
+=================
+
+All releases of OpenAFS prior to 1.6.24 are affected, as are OpenAFS
+1.8.0 through 1.8.4.
+
+FIXES
+=====
+
+The OpenAFS project recommends that administrators upgrade all machines
+to the 1.8.5 or 1.6.24 releases.  It is necessary to restart the server
+processes and cache manager in order for the fixes to take effect.
+
+DETAILS
+=======
+
+The AFS-3 protocol suite and OpenAFS extensions are run over the Rx RPC
+protocol.  A variant of Sun rpcgen, rxgen, is used to generate data
+en/decoding routines and client- and server-side stub functions from an
+interface description file.  In the RPC server, these stubs interface
+between the Rx network protocol layer and the implementation of the RPC
+server-side logic.  The server logic is written as a normal C function,
+taking input variables either as pointer-to-struct or scalar-by-value, and
+returning output variables via pointer arguments (allocating storage as
+appropriate).  The generated stub allocates storage on the stack for local
+variables to hold the input and ouput arguments of the RPC that are passed
+as arguments to the function implementing the server logic, and as discussed
+in OPENAFS-SA-2019-002, these local variables are only sometimes given an
+initial value; at other times they remain uninitialized and potentially
+refer to other content in the memory address space of the running process.
+
+Once the function implementing the server logic returns to the generated
+stub, the stub function uses the XDR encoder to pack the output variables
+from the local variables into an XDR bytestream.  The way in which the
+OpenAFS encoder works results in Rx packets being generated by the XDR
+encoder, and when a complete packet is assembled, it is sent to the peer
+according to the Rx congestion-control logic.  After all the output
+parameters have been encoded to the XDR bytestream, the generated stub frees
+any storage allocated, and then returns the result from the server logic.
+On success, this translates to completing any partially constructed Rx
+packet and sending the response code, but for error returns, any pending
+data is discarded and instead an Rx abort packet is sent for the Rx call
+over which the RPC is running.  The abort indicates to the client that the
+RPC has failed and the XDR stream is to be discarded.
+
+Unfortunately, the XDR-encode-and-send-packets step is not skipped in the
+case of error returns, even though the call will ultimately be aborted and
+well-behaved clients will discard the XDR bytestream, there is still an
+opportunity for Rx packets to be generated and sent.  When combined with the
+potential for uninitialized local variables to be included in the encoded
+stream, this results in a channel for the contents of uninitialized memory
+to be sent on the wire to a (potentially unauthenticated) peer.
+
+Vulnerabilities of this nature can be difficult to exploit, as there is not
+always context for *which* content from uninitialized memory is leaked to
+the caller, and that is in turn dependent on the allocation/deallocation
+patterns in the surrounding application and the other load patterns on the
+server.  However, there are worked examples in other software of attackers
+being able to massage allocator state and stack contents in order to
+exfiltrate specific information, so it should be assumed that such attacks
+are also possible here given a sufficiently dedicated attacker.
+
+ACKNOWLEDGMENTS
+===============
+
+Thanks to Andrew Deason for the detailed report and contributed patch.
+-----BEGIN PGP SIGNATURE-----
+
+iQG3BAEBCgAdFiEE2WGV4E2ARf9BYP0XKNmm82TrdRIFAl2vh/QACgkQKNmm82Tr
+dRJGMwwghX7qcmKA50FBq+Smhvqp1KggNnGXnt6t78opKm3uR3LfTrsDc4g4YZLG
+4H24JdbYoGfyoziTJtBMLW8KubFojrZfoqgDRXgcpx2TQE36X0kzgpH2grAxE5kA
+wBL6aic6FxEgkF9Xw+iwo34hGv79WPHEgB0lWlGqjRj94geVh7dWjYWeL0K7JnlS
+WdOpmIWMUr5aMIG5G34t/XrZvoVDOrBjBKXUXFHLpYCZS7XPrxWTCOzNwyS5WehQ
+uBtEIgPeYVL1c+8XLA94Lyyegc8lnvdNvEU3nP9nIQTJ4x79j3bQ/PhmKQCQPMeS
+3G/LKtzYTA5d2SmEQ5pfTUYCmG4ULjAdk2IT2nW20cwbWmuArzWlcCPkAH3itonO
+ToRpRcywjqa1Z9p0EWrwZyXKVwRt1t8areIraHiFQiuTpjecl4or4ioXggnNoeqa
+Ek+W/sV5sTVFZhLUlpx2VrpvahqUckc4deo/BjUzqMpPWSLZ9tgH/Qv4pCkxtD29
+lvMgEDkke90EOQ==
+=KqJn
+-----END PGP SIGNATURE-----
diff --git a/security/OPENAFS-SA-2019-002.txt b/security/OPENAFS-SA-2019-002.txt
new file mode 100644 (file)
index 0000000..8f526b7
--- /dev/null
@@ -0,0 +1,133 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA512
+
+OpenAFS Security Advisory 2019-002
+
+Topic: information leakage from uninitialized scalars
+
+Issued: 22 October, 2019
+Affected: OpenAFS versions 1.0 through 1.6.23, and 1.8.0 through 1.8.4
+
+Generated RPC handler routines only initialized local variables that would
+need to be freed, leaving uninitialized memory contents in RPC
+parameters of scalar type.  When combined with RPC implementations that
+also did not supply output values, this results in the contents of
+uninitialized memory being sent to the peer, even for successful RPCs.
+
+SUMMARY
+=======
+
+AFS-3 RPCs use the XDR data encoding to represent input/output arguments,
+and OpenAFS uses an XDR en/decoder that is tightly integrated to the Rx
+protocol implementation.  The generated RPC handler code takes care of
+allocating storage/variables for the input/output variables and reading the
+input parameters from the network into local storage before calling the
+function that implements the RPC logic.  Similarly, after that function
+call, the generated code takes care of encoding the output parameters into
+Rx packets and sending them to the peer as necessary, then deallocating the
+storage it allocated and returning control flow to the caller.  While
+the generated code is careful to initialize the local variables that
+might contain pointers to allocated memory (to ensure leak-free
+operation), scalar values (e.g., integers, flat structures) were not
+initialized.  Some RPC handlers in OpenAFS do not always write to all output
+variables, even in the case of a successful return, so the contents of these
+uninitialized variables would be encoded into the XDR stream and sent to the
+(potentially unauthenticated) peer.
+
+IMPACT
+======
+
+It is uncommon for the server-side implementation of an RPC to not write
+to its output variables on the success case, though multiple occurrences
+have been found during an incomplete survey, leaking between 4 and 8 bytes
+per call.  However, the actual amount and rate of data exposure is highly
+context-dependent, since the memory allocator behavior and other load on the
+system affect exactly what information is leaked from uninitialized memory.
+
+AFFECTED SOFTWARE
+=================
+
+All releases of OpenAFS prior to 1.6.24 are affected, as are OpenAFS
+1.8.0 through 1.8.4.
+
+FIXES
+=====
+
+The OpenAFS project recommends that administrators upgrade all machines
+to the 1.8.5 or 1.6.24 releases.  It is necessary to restart the server
+processes and cache manager in order for the fixes to take effect.
+
+DETAILS
+=======
+
+The AFS-3 protocol suite and OpenAFS extensions are run over the Rx RPC
+protocol.  A variant of Sun rpcgen, rxgen, is used to generate data
+en/decoding routines and client- and server-side stub functions from an
+interface description file.  In the RPC server, these stubs interface
+between the Rx network protocol layer and the implementation of the RPC
+server-side logic.  The server logic is written as a normal C function,
+taking input variables either as pointer-to-struct or scalar-by-value, and
+returning output variables via pointer arguments (allocating storage as
+appropriate).  The generated stub allocates storage on the stack for local
+variables to hold the input and ouput arguments of the RPC that are passed
+as arguments to the function implementing the server logic, but (as is
+common in code of this vintage) only initializes some of the variables
+to known values.  In particular, only the variables that will need to be
+passed to memory deallocation routines at the end of the function are
+initialized, to ensure that a garbage pointer is not passed to free().
+That leaves scalar types (integers, flat structures, etc.) with no
+explicit initialization, so references to them retrieve whatever
+happened to previously occupy that location in the program's address
+space.
+
+If an RPC implementation does not write to all its output variables (for
+example, if they correspond to some functionality that was not requested
+by the client or is disabled by configuration), then program execution
+will reach the end of the generated stub function without any value
+having been explicitly assigned to these (scalar) variables.  In
+particular, these uninitialized values are passed to the XDR encoder
+routine and  (as is common in code of this vintage) only initializes
+some of the variables to known values.  In particular, only the
+variables that will need to be passed to memory deallocation routines at
+the end of the function are initialized, to ensure that a garbage
+pointer is not passed to free().  That leaves scalar types (integers,
+flat structures, etc.) with no explicit initialization, so references to
+them retrieve whatever happened to previously occupy that location in
+the program's address space.  This includes when these variables are
+passed to the XDR encoder, so the uninitialized memory contents are
+encoded into the Rx stream and sent to the peer.
+
+Investigations surrounding this issue uncovered multiple RPCs known to leave
+output parameters uninitialized while returning success.  However, since the
+risk is systemic and best addressed with a systemic fix, no effort was made
+to perform a comprehensive search and enumerate the RPCs with the flaw.
+
+As with most avenues for information disclosure from uninitialized
+memory, vulnerabilities of this nature can be difficult to exploit, as
+there is not always context for *which* content from uninitialized
+memory is leaked to the caller, and that is in turn dependent on the
+allocation/deallocation patterns in the surrounding application and the
+other load patterns on the server.  However, there are worked examples
+in other software of attackers being able to massage allocator state and
+stack contents in order to exfiltrate specific information, so it should
+be assumed that such attacks are also possible here given a sufficiently
+dedicated attacker.
+
+ACKNOWLEDGMENTS
+===============
+
+Thanks to Andrew Deason for the detailed report and contributed patch.
+-----BEGIN PGP SIGNATURE-----
+
+iQG3BAEBCgAdFiEE2WGV4E2ARf9BYP0XKNmm82TrdRIFAl2vh/oACgkQKNmm82Tr
+dRLFwgweKkZFwtUAtZgpp8o96/yBTZ8iyuvDPYMN8LPobc/OqE6fxIdk8lwEQ696
+5F+N9nVXhwwVMqxP4PGw1qMVOyZFGwf3IXMMhgcZOQSepu6lwUeypRR/Ow0iFlI0
+XmeqI4F0PZGISpZlEc8HQ3/oASYWtMIatEs8vEWWpkrQLdYxKEZF2r9yMCdUwNwa
+QuqlEuORLa3aV4K7/c8JfWA3yi4GtYyoonZTeceS9s8MSHWgYtyH/0k3YQYsq57T
+vhJ+6MWG7WyNbbadJxngYACknaGtrk6Ifw2aIuKK1sUYKCqKvyO+BJXL68cBSupv
+rMG2+4RbKzmQXikQd3MxINTtu8ADhyqwQJi/UYHQXcHgyQJuIDKVu0W0PBJuKLQY
+u1JYB86ewsxOWazKIK1jbcMf15W6Jxhg6e1Wt5KrEFdoOinDgCnR7qWfPMxdLOQK
+UNxRX3T7wKZOFokU18dMX+TCKebb9fzxE0An/U5RsjtXWTodfi1Zo3A76KO1wFOn
+GCk+wKC+4tFeZg==
+=3pYF
+-----END PGP SIGNATURE-----
diff --git a/security/OPENAFS-SA-2019-003.txt b/security/OPENAFS-SA-2019-003.txt
new file mode 100644 (file)
index 0000000..804b041
--- /dev/null
@@ -0,0 +1,112 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA512
+
+OpenAFS Security Advisory 2019-003
+
+Topic: database server crash from unserialized data access
+
+Issued: 22 October, 2019
+Affected: OpenAFS versions 1.0 through 1.6.23, and 1.8.0 through 1.8.4
+
+Database servers in the SVOTE_Debug() RPC handler can encounter a
+segmentation fault and crash during certain circumstances, when running in
+parallel with the end of a write transaction on the database.
+
+SUMMARY
+=======
+
+The SVOTE_Debug() RPC handler used to implement the main udebug(1)
+functionality performs unlocked accesses to a global pointer variable,
+dereferencing it if the first access returns a non-NULL value.  Since the
+accesses are not serialized against writes, the value can change between
+accesses (e.g., to become NULL), with the attempted dereference generating a
+segmentation fault.
+
+IMPACT
+======
+
+The impact of this issue can be limited by the compiler and options used to
+compile the server code in question.  For example, gcc on some popular linux
+distributions is able to optimize the two memory accesses into a single
+load, so the value being dereferenced to check the type of the transaction
+will never be NULL.  (It might point into freed memory, but for the memory
+allocators in use on these linux systems, that memory is highly unlikely to
+have been unmapped in the intervening period, so the access would merely
+return bad data rather than crashing.)  Other compilers/architectures do not
+make this optimization, such as the Solaris cc, and the resulting binaries
+are impacted.
+
+Since the VOTE_Debug() RPC does not require authentication, a remote
+attacker can attempt to call the RPC repeatedly and overlap with the end of
+a write transaction; crashes have been observed simply by running udebug(1)
+in a tight loop.
+
+AFFECTED SOFTWARE
+=================
+
+All releases of OpenAFS prior to 1.6.24 are affected, as are OpenAFS
+1.8.0 through 1.8.4.
+
+Database server processes built against LWP (instead of pthreads) are
+not affected by this issue. Database server processes are built
+against LWP by default in 1.6 releases, but are built against pthreads by
+default in 1.8 releases.
+
+FIXES
+=====
+
+The OpenAFS project recommends that administrators upgrade all database servers
+to the 1.8.5 or 1.6.24 releases.  It is necessary to restart the database server
+processes in order for the fixes to take effect.
+
+Using a firewall to block or rate-limit VOTE_Debug() RPCs from untrusted
+sources may be an adequate workaround.
+
+DETAILS
+=======
+
+The udebug(1) utility is a debugging tool, and as such does not require
+authenticated access for the RPC calls it performs.  Most of its
+functionality comes from the VOTE_Debug() RPC, which was written to
+prioritize speed and avoiding disruption of normal database operation over
+correctness of output.  Accordingly, it accesses global state without
+adhering to the normal locking/serialization mechanisms for access to that
+state.  This means that the returned results can be incorrect or
+inconsistent, but that tradeoff was part of its original design.
+
+One of the pieces of information returned by SVOTE_Debug() is whether there
+is a current transaction on the database, and if so, whether it is a write
+transaction.  The current transaction is stored as a global pointer to a
+transaction structure (ubik_currentTrans), so whether or not there is an
+ongoing transaction is a question of whether ubik_currentTrans is non-NULL;
+the type of transaction (read vs. write) is stored in a field in the
+pointed-to structure.  However, we only ever create a transaction structure
+for ubik_currentTrans in the case of a write transaction, so checking the
+type stored in the transaction structure provides no value for this case!
+
+Because SVOTE_Debug() does not take any locks, it can run in parallel with a
+running transaction, and in particular, the end of that transaction.  This
+means that the value of ubik_currentTrans can change between accesses, and
+thus that the state determined by the first access ("there is a current
+transaction") can be invalid by the time of the second access (which
+dereferences the pointer).  In this case, an invalid pointer is
+dereferenced, leading to a segmentation fault and application crash.
+
+ACKNOWLEDGMENTS
+===============
+
+Thanks to Andrew Deason for the detailed report and contributed patch.
+-----BEGIN PGP SIGNATURE-----
+
+iQG3BAEBCgAdFiEE2WGV4E2ARf9BYP0XKNmm82TrdRIFAl2vjWsACgkQKNmm82Tr
+dRLTfgwg1/96x8b3WpwMg4YUwE/RmFJZpKiI7/lscPcLsH3Jn4Ru72jqN5vUa9dW
+6nCYLNqOeSPm0QDqQOz2bzle1HlcTYaCOoh446Y2kwGpBWicpyAm70SRkEiPgnVr
+UR0XmfqIw0s5h7S98VPJYWeyOE6eQiH2pdjHsyg5duwg09e/Rvw+XBR4L4VQPlvx
+JpK1Aa5V+1//n0egOhImFxFCMh6a9PBkuHsxjn9++f3TmM744qUbFM2SsW20OtTo
+IaC518yt9Eoeyw84MnKdTzRVa6gNFcRq7wp8ls9t8zY46Q3aDEAnipkOo+2OVy7e
+2cLAZ4t6vvRJKH1FBbA58DsNM+wDoiKJO0+3xYquRmIs0EbkOVpE99XNu7FUX7w2
+c0xCobqlozhbuJIluSV/XbyETvKvQHg7MtKPcDN8Hgf7e12UxgisfcD8uOjb1Toj
+bpx+Y6VX3Du/tW82lbZ5/1jXjiluDtAwDSHXLQbGO2JzAdtuSqiQNDpITXSUTwiH
+rzYCDiJT9PivIg==
+=s4yw
+-----END PGP SIGNATURE-----
index ef2ca2f..7a23335 100644 (file)
@@ -25,6 +25,95 @@ When sending sensitive information, we ask that you encrypt it
 with PGP.
 
 <hr>
+<a name="OPENAFS-SA-2019-003"></a>
+<h2>OPENAFS-SA-2019-003 - crash in database servers</h2>
+<table border=0>
+<tr><th align="left">Issued:</th><td>22-Oct-2019</td></tr>
+<tr><th align="left">Last Update:</th><td>22-Oct-2019</td></tr>
+<tr><th align="left">Severity:</th><td>Medium</td></tr>
+<tr><th align="left">Affected:</th><td>
+  OpenAFS server versions 1.0 through 1.6.23, 1.8.0 through 1.8.4 .</td></tr>
+<tr><th align="left">Patch:</th><td>
+  <a href="openafs-sa-2019-003-stable16.patch">
+  https://www.openafs.org/security/openafs-sa-2019-003-stable16.patch</a><br>
+</td><td>
+  <a href="openafs-sa-2019-003-stable18.patch">
+  https://www.openafs.org/security/openafs-sa-2019-003-stable18.patch</a><br>
+</td><td>
+  <a href="openafs-sa-2019-003-master.patch">
+  https://www.openafs.org/security/openafs-sa-2019-003-master.patch</a><br>
+</td></tr>
+<tr><th align="left">Full Text:</th><td>
+  <a href="OPENAFS-SA-2019-003.txt">
+  https://www.openafs.org/security/OPENAFS-SA-2019-003.txt</a>
+</td></tr>
+</table>
+<p>The ubik debugging RPCs prioritize being fast and non-disruptive to
+database operations over strict correctness, and do not adhere to the
+usual locking protocol for data access.  A data race could cause a NULL
+dereference if the second memory load was not optimized out by the
+compiler
+
+<a name="OPENAFS-SA-2019-002"></a>
+<h2>OPENAFS-SA-2019-002 - information leakage from uninitialized scalars</h2>
+<table border=0>
+<tr><th align="left">Issued:</th><td>22-Oct-2019</td></tr>
+<tr><th align="left">Last Update:</th><td>22-Oct-2019</td></tr>
+<tr><th align="left">Severity:</th><td>Low</td></tr>
+<tr><th align="left">Affected:</th><td>
+  OpenAFS client versions 1.0 through 1.6.23, 1.8.0 through 1.8.4 ;
+  OpenAFS server versions 1.0 through 1.6.23, 1.8.0 through 1.8.4 .</td></tr>
+<tr><th align="left">Patch:</th><td>
+  <a href="openafs-sa-2019-002-stable16.patch">
+  https://www.openafs.org/security/openafs-sa-2019-002-stable16.patch</a><br>
+</td><td>
+  <a href="openafs-sa-2019-002-stable18.patch">
+  https://www.openafs.org/security/openafs-sa-2019-002-stable18.patch</a><br>
+</td><td>
+  <a href="openafs-sa-2019-002-master.patch">
+  https://www.openafs.org/security/openafs-sa-2019-002-master.patch</a><br>
+</td></tr>
+<tr><th align="left">Full Text:</th><td>
+  <a href="OPENAFS-SA-2019-002.txt">
+  https://www.openafs.org/security/OPENAFS-SA-2019-002.txt</a>
+</td></tr>
+</table>
+<p>Generated RPC handler routines did not initialize output variables of
+scalar (fixed-length) type, since they did not require dedicated logic to
+free.  Such variables allocated on the stack could remain uninitialized
+in some cases (including those affected by OPENAFS-SA-2019-001), and the
+contents of uninitialized memory would be returned to the peer.
+
+<a name="OPENAFS-SA-2019-001"></a>
+<h2>OPENAFS-SA-2019-001 - information leakage in failed RPC output</h2>
+<table border=0>
+<tr><th align="left">Issued:</th><td>22-Oct-2019</td></tr>
+<tr><th align="left">Last Update:</th><td>22-Oct-2019</td></tr>
+<tr><th align="left">Severity:</th><td>Low</td></tr>
+<tr><th align="left">Affected:</th><td>
+  OpenAFS client versions 1.0 through 1.6.23, 1.8.0 through 1.8.4 ;
+  OpenAFS server versions 1.0 through 1.6.23, 1.8.0 through 1.8.4 .</td></tr>
+<tr><th align="left">Patch:</th><td>
+  <a href="openafs-sa-2019-001-stable16.patch">
+  https://www.openafs.org/security/openafs-sa-2019-001-stable16.patch</a><br>
+</td><td>
+  <a href="openafs-sa-2019-001-stable18.patch">
+  https://www.openafs.org/security/openafs-sa-2019-001-stable18.patch</a><br>
+</td><td>
+  <a href="openafs-sa-2019-001-master.patch">
+  https://www.openafs.org/security/openafs-sa-2019-001-master.patch</a><br>
+</td></tr>
+<tr><th align="left">Full Text:</th><td>
+  <a href="OPENAFS-SA-2019-001.txt">
+  https://www.openafs.org/security/OPENAFS-SA-2019-001.txt</a>
+</td></tr>
+</table>
+<p>Generated RPC handler routines ran output variables through XDR encoding
+even when the call had failed and would shortly be aborted (and for
+which uninitialized output variables is common); any complete packets
+assembled in the process would be sent to the peer, leaking the contents
+of the uninitialized memory in question.
+
 <a name="OPENAFS-SA-2018-003"></a>
 <h2>OPENAFS-SA-2018-003 - denial of service due to excess resource consumption</h2>
 <table border=0>
@@ -967,10 +1056,25 @@ for this vulnerability.
   <td><a href="#OPENAFS-SA-2018-002">information leakage from uninitialized RPC output variables</a></td>
 </tr>
 <tr>
-  <td>2018-002</td><td>11-Sep-2018</td><td>11-Sep-2018</td>
+  <td>2018-003</td><td>11-Sep-2018</td><td>11-Sep-2018</td>
   <td>Medium</td><td>1.0-1.6.22.4,1.8.0-1.8.1.1</td>
   <td><a href="#OPENAFS-SA-2018-003">denial of service due to excess resource consumption</a></td>
 </tr>
+<tr>
+  <td>2019-001</td><td>22-Oct-2019</td><td>22-Oct-2019</td>
+  <td>Low</td><td>1.0-1.6.23,1.8.0-1.8.4</td>
+  <td><a href="#OPENAFS-SA-2019-001">information leakage in failed RPC output</a></td>
+</tr>
+<tr>
+  <td>2019-002</td><td>22-Oct-2019</td><td>22-Oct-2019</td>
+  <td>Low</td><td>1.0-1.6.23,1.8.0-1.8.4</td>
+  <td><a href="#OPENAFS-SA-2019-002">information leakage from uninitialized scalars</a></td>
+</tr>
+<tr>
+  <td>2019-003</td><td>22-Oct-2019</td><td>22-Oct-2019</td>
+  <td>Medium</td><td>1.0-1.6.23,1.8.0-1.8.4</td>
+  <td><a href="#OPENAFS-SA-2019-003">crash in database servers</a></td>
+</tr>
 </table>
 
 
diff --git a/security/openafs-sa-2019-001-master.patch b/security/openafs-sa-2019-001-master.patch
new file mode 100644 (file)
index 0000000..a957797
--- /dev/null
@@ -0,0 +1,81 @@
+commit ea276e83e37e5bd27285a3d639f2158639172786
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Wed Aug 7 20:50:47 2019 -0500
+
+    OPENAFS-SA-2019-001: Skip server OUT args on error
+    
+    Currently, part of our server-side RPC argument-handling code that's
+    generated from rxgen looks like this (for example):
+    
+        z_result = SRXAFS_BulkStatus(z_call, &FidsArray, &StatArray, &CBArray, &Sync);
+        z_xdrs->x_op = XDR_ENCODE;
+        if ((!xdr_AFSBulkStats(z_xdrs, &StatArray))
+             || (!xdr_AFSCBs(z_xdrs, &CBArray))
+             || (!xdr_AFSVolSync(z_xdrs, &Sync)))
+                z_result = RXGEN_SS_MARSHAL;
+    fail:
+        [...]
+        return z_result;
+    
+    When the server routine for implementing the RPC results a non-zero
+    value into z_result, the call will be aborted. However, before we
+    abort the call, we still call the xdr_* routines with XDR_ENCODE for
+    all of our output arguments. If the call has not already been aborted
+    for other reasons, we'll serialize the output argument data into the
+    Rx call. If we push more data than can fit in a single Rx packet for
+    the call, then we'll also send that data to the client. Many server
+    routines for implementing RPCs do not initialize the memory inside
+    their output arguments during certain errors, and so the memory may be
+    leaked to the peer.
+    
+    To avoid this, just jump to the 'fail' label when a nonzero 'z_result'
+    is returned. This means we skip sending the output argument data to
+    the peer, but we still free any argument data that needs freeing, and
+    record the stats for the call (if needed). This makes the above
+    example now look like this:
+    
+        z_result = SRXAFS_BulkStatus(z_call, &FidsArray, &StatArray, &CBArray, &Sync);
+        if (z_result)
+            goto fail;
+        z_xdrs->x_op = XDR_ENCODE;
+        if ((!xdr_AFSBulkStats(z_xdrs, &StatArray))
+             || (!xdr_AFSCBs(z_xdrs, &CBArray))
+             || (!xdr_AFSVolSync(z_xdrs, &Sync)))
+                z_result = RXGEN_SS_MARSHAL;
+    fail:
+        [...]
+        return z_result;
+    
+    Change-Id: I2bdea2e808bb215720492b0ba6ac1a88da61b954
+    Reviewed-on: https://gerrit.openafs.org/13913
+    Reviewed-by: Andrew Deason <adeason@sinenomine.net>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+
+diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c
+index 492bfb0853..4e1b6141d7 100644
+--- a/src/rxgen/rpc_parse.c
++++ b/src/rxgen/rpc_parse.c
+@@ -1301,7 +1301,12 @@ cs_ProcTail_setup(definition * defp, int split_flag)
+ static void
+ ss_Proc_CodeGeneration(definition * defp)
+ {
+-    defp->can_fail = 0;
++    extern char zflag;
++
++    if (zflag)
++      defp->can_fail = 0;
++    else
++      defp->can_fail = 1;
+     ss_ProcName_setup(defp);
+     if (!cflag) {
+       ss_ProcParams_setup(defp);
+@@ -1546,6 +1551,8 @@ ss_ProcCallRealProc_setup(definition * defp)
+     f_print(fout, ");\n");
+     if (zflag) {
+       f_print(fout, "\tif (z_result)\n\t\treturn z_result;\n");
++    } else {
++      f_print(fout, "\tif (z_result)\n\t\tgoto fail;\n");
+     }
+ }
diff --git a/security/openafs-sa-2019-001-stable16.patch b/security/openafs-sa-2019-001-stable16.patch
new file mode 100644 (file)
index 0000000..4e0f498
--- /dev/null
@@ -0,0 +1,91 @@
+commit 6e08c0368aa43fa9851556050f2e4bf4e59edaea
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Wed Aug 7 20:50:47 2019 -0500
+
+    OPENAFS-SA-2019-001: Skip server OUT args on error
+    
+    Currently, part of our server-side RPC argument-handling code that's
+    generated from rxgen looks like this (for example):
+    
+        z_result = SRXAFS_BulkStatus(z_call, &FidsArray, &StatArray, &CBArray, &Sync);
+        z_xdrs->x_op = XDR_ENCODE;
+        if ((!xdr_AFSBulkStats(z_xdrs, &StatArray))
+             || (!xdr_AFSCBs(z_xdrs, &CBArray))
+             || (!xdr_AFSVolSync(z_xdrs, &Sync)))
+                z_result = RXGEN_SS_MARSHAL;
+    fail:
+        [...]
+        return z_result;
+    
+    When the server routine for implementing the RPC results a non-zero
+    value into z_result, the call will be aborted. However, before we
+    abort the call, we still call the xdr_* routines with XDR_ENCODE for
+    all of our output arguments. If the call has not already been aborted
+    for other reasons, we'll serialize the output argument data into the
+    Rx call. If we push more data than can fit in a single Rx packet for
+    the call, then we'll also send that data to the client. Many server
+    routines for implementing RPCs do not initialize the memory inside
+    their output arguments during certain errors, and so the memory may be
+    leaked to the peer.
+    
+    To avoid this, just jump to the 'fail' label when a nonzero 'z_result'
+    is returned. This means we skip sending the output argument data to
+    the peer, but we still free any argument data that needs freeing, and
+    record the stats for the call (if needed). This makes the above
+    example now look like this:
+    
+        z_result = SRXAFS_BulkStatus(z_call, &FidsArray, &StatArray, &CBArray, &Sync);
+        if (z_result)
+            goto fail;
+        z_xdrs->x_op = XDR_ENCODE;
+        if ((!xdr_AFSBulkStats(z_xdrs, &StatArray))
+             || (!xdr_AFSCBs(z_xdrs, &CBArray))
+             || (!xdr_AFSVolSync(z_xdrs, &Sync)))
+                z_result = RXGEN_SS_MARSHAL;
+    fail:
+        [...]
+        return z_result;
+    
+    Reviewed-on: https://gerrit.openafs.org/13913
+    Reviewed-by: Andrew Deason <adeason@sinenomine.net>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit ea276e83e37e5bd27285a3d639f2158639172786)
+    
+    Reviewed-on: https://gerrit.openafs.org/13916
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit 5a3d1b62810fc8cc7b37a737b4f5f1912bc614f9)
+    
+    Change-Id: Ia54b06399b1f8a05a560ec7560580783d3e64b9d
+    Reviewed-on: https://gerrit.openafs.org/13921
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+
+diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c
+index 5a3f27d845..8ff57d0794 100644
+--- a/src/rxgen/rpc_parse.c
++++ b/src/rxgen/rpc_parse.c
+@@ -1369,8 +1369,12 @@ static void
+ ss_Proc_CodeGeneration(definition * defp)
+ {
+     int somefrees = 0;
++    extern char zflag;
+-    defp->can_fail = 0;
++    if (zflag)
++      defp->can_fail = 0;
++    else
++      defp->can_fail = 1;
+     ss_ProcName_setup(defp);
+     if (!cflag) {
+       ss_ProcParams_setup(defp, &somefrees);
+@@ -1610,6 +1614,8 @@ ss_ProcCallRealProc_setup(definition * defp)
+     f_print(fout, ");\n");
+     if (zflag) {
+       f_print(fout, "\tif (z_result)\n\t\treturn z_result;\n");
++    } else {
++      f_print(fout, "\tif (z_result)\n\t\tgoto fail;\n");
+     }
+ }
diff --git a/security/openafs-sa-2019-001-stable18.patch b/security/openafs-sa-2019-001-stable18.patch
new file mode 100644 (file)
index 0000000..576abdd
--- /dev/null
@@ -0,0 +1,86 @@
+commit 5a3d1b62810fc8cc7b37a737b4f5f1912bc614f9
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Wed Aug 7 20:50:47 2019 -0500
+
+    OPENAFS-SA-2019-001: Skip server OUT args on error
+    
+    Currently, part of our server-side RPC argument-handling code that's
+    generated from rxgen looks like this (for example):
+    
+        z_result = SRXAFS_BulkStatus(z_call, &FidsArray, &StatArray, &CBArray, &Sync);
+        z_xdrs->x_op = XDR_ENCODE;
+        if ((!xdr_AFSBulkStats(z_xdrs, &StatArray))
+             || (!xdr_AFSCBs(z_xdrs, &CBArray))
+             || (!xdr_AFSVolSync(z_xdrs, &Sync)))
+                z_result = RXGEN_SS_MARSHAL;
+    fail:
+        [...]
+        return z_result;
+    
+    When the server routine for implementing the RPC results a non-zero
+    value into z_result, the call will be aborted. However, before we
+    abort the call, we still call the xdr_* routines with XDR_ENCODE for
+    all of our output arguments. If the call has not already been aborted
+    for other reasons, we'll serialize the output argument data into the
+    Rx call. If we push more data than can fit in a single Rx packet for
+    the call, then we'll also send that data to the client. Many server
+    routines for implementing RPCs do not initialize the memory inside
+    their output arguments during certain errors, and so the memory may be
+    leaked to the peer.
+    
+    To avoid this, just jump to the 'fail' label when a nonzero 'z_result'
+    is returned. This means we skip sending the output argument data to
+    the peer, but we still free any argument data that needs freeing, and
+    record the stats for the call (if needed). This makes the above
+    example now look like this:
+    
+        z_result = SRXAFS_BulkStatus(z_call, &FidsArray, &StatArray, &CBArray, &Sync);
+        if (z_result)
+            goto fail;
+        z_xdrs->x_op = XDR_ENCODE;
+        if ((!xdr_AFSBulkStats(z_xdrs, &StatArray))
+             || (!xdr_AFSCBs(z_xdrs, &CBArray))
+             || (!xdr_AFSVolSync(z_xdrs, &Sync)))
+                z_result = RXGEN_SS_MARSHAL;
+    fail:
+        [...]
+        return z_result;
+    
+    Reviewed-on: https://gerrit.openafs.org/13913
+    Reviewed-by: Andrew Deason <adeason@sinenomine.net>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit ea276e83e37e5bd27285a3d639f2158639172786)
+    
+    Change-Id: I688cbf1a65903bf26a0db033687898f3fb5a54ea
+    Reviewed-on: https://gerrit.openafs.org/13916
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+
+diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c
+index f5d7c70338..032afe0313 100644
+--- a/src/rxgen/rpc_parse.c
++++ b/src/rxgen/rpc_parse.c
+@@ -1301,7 +1301,12 @@ cs_ProcTail_setup(definition * defp, int split_flag)
+ static void
+ ss_Proc_CodeGeneration(definition * defp)
+ {
+-    defp->can_fail = 0;
++    extern char zflag;
++
++    if (zflag)
++      defp->can_fail = 0;
++    else
++      defp->can_fail = 1;
+     ss_ProcName_setup(defp);
+     if (!cflag) {
+       ss_ProcParams_setup(defp);
+@@ -1546,6 +1551,8 @@ ss_ProcCallRealProc_setup(definition * defp)
+     f_print(fout, ");\n");
+     if (zflag) {
+       f_print(fout, "\tif (z_result)\n\t\treturn z_result;\n");
++    } else {
++      f_print(fout, "\tif (z_result)\n\t\tgoto fail;\n");
+     }
+ }
diff --git a/security/openafs-sa-2019-002-master.patch b/security/openafs-sa-2019-002-master.patch
new file mode 100644 (file)
index 0000000..0a5def8
--- /dev/null
@@ -0,0 +1,118 @@
+commit 93aee3cf40622993b95bd1af77080a31670c24bb
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Wed Aug 7 21:19:47 2019 -0500
+
+    OPENAFS-SA-2019-002: Zero all server RPC args
+    
+    Currently, our server-side RPC argument-handling code generated from
+    rxgen initializes complex arguments like so (for example, in
+    _RXAFS_BulkStatus):
+    
+        AFSCBFids FidsArray;
+        AFSBulkStats StatArray;
+        AFSCBs CBArray;
+        AFSVolSync Sync;
+    
+        FidsArray.AFSCBFids_val = 0;
+        FidsArray.AFSCBFids_len = 0;
+        CBArray.AFSCBs_val = 0;
+        CBArray.AFSCBs_len = 0;
+        StatArray.AFSBulkStats_val = 0;
+        StatArray.AFSBulkStats_len = 0;
+    
+    This is done for any input or output arguments, but only for types we
+    need to free afterwards (arrays, usually). We do not do this for
+    simple types, like single flat structs. In the above example, we do
+    this for the arrays FidsArray, StatArray, and CBArray, but 'Sync' is
+    not initialized to anything.
+    
+    If some server RPC handlers never set a value for an output argument,
+    this means we'll send uninitialized stack memory to our peer.
+    Currently this can happen in, for example,
+    MRXSTATS_RetrieveProcessRPCStats if 'rxi_monitor_processStats' is
+    unset (specifically, the 'clock_sec' and 'clock_usec' arguments are
+    never set when rx_enableProcessRPCStats() has not been called).
+    
+    To make sure we cannot send uninitialized data to our peer, change
+    rxgen to instead 'memset(&arg, 0, sizeof(arg));' for every single
+    parameter. Using memset in this way just makes this a little simpler
+    inside rxgen, since all we need to do this is the name of the
+    argument.
+    
+    With this commit, the rxgen-generated code for the above example now
+    looks like this:
+    
+        AFSCBFids FidsArray;
+        AFSBulkStats StatArray;
+        AFSCBs CBArray;
+        AFSVolSync Sync;
+    
+        memset(&FidsArray, 0, sizeof(FidsArray));
+        memset(&CBArray, 0, sizeof(CBArray));
+        memset(&StatArray, 0, sizeof(StatsArray));
+        memset(&Sync, 0, sizeof(Sync));
+    
+    Change-Id: Iedccc25e50ee32bd1144e652b951496cb7dde5d2
+    Reviewed-on: https://gerrit.openafs.org/13914
+    Reviewed-by: Andrew Deason <adeason@sinenomine.net>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+
+diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c
+index 4e1b6141d7..768e42f3ba 100644
+--- a/src/rxgen/rpc_parse.c
++++ b/src/rxgen/rpc_parse.c
+@@ -1435,8 +1435,6 @@ ss_ProcSpecial_setup(definition * defp)
+               if (streq(string, structname(plist->pl.param_type))) {
+                   plist->pl.string_name = spec->sdef.string_name;
+                   plist->pl.param_flag |= FREETHIS_PARAM;
+-                  fprintf(fout, "\n\t%s.%s = 0;", plist->pl.param_name,
+-                          spec->sdef.string_name);
+               }
+           }
+       }
+@@ -1451,22 +1449,13 @@ ss_ProcSpecial_setup(definition * defp)
+                   case REL_ARRAY:
+                       plist->pl.string_name = alloc(40);
+                       if (brief_flag) {
+-                          f_print(fout, "\n\t%s.val = 0;",
+-                                  plist->pl.param_name);
+-                          f_print(fout, "\n\t%s.len = 0;",
+-                                  plist->pl.param_name);
+                           s_print(plist->pl.string_name, "val");
+                       } else {
+-                          f_print(fout, "\n\t%s.%s_val = 0;",
+-                                  plist->pl.param_name, defp1->def_name);
+-                          f_print(fout, "\n\t%s.%s_len = 0;",
+-                                  plist->pl.param_name, defp1->def_name);
+                           s_print(plist->pl.string_name, "%s_val",
+                                   defp1->def_name);
+                       }
+                       break;
+                   case REL_POINTER:
+-                      f_print(fout, "\n\t%s = 0;", plist->pl.param_name);
+                       plist->pl.string_name = NULL;
+                       break;
+                   default:
+@@ -1482,13 +1471,19 @@ ss_ProcSpecial_setup(definition * defp)
+           if (plist->component_kind == DEF_PARAM) {
+               if (streq(defp1->def_name, structname(plist->pl.param_type))) {
+                   plist->pl.param_flag |= FREETHIS_PARAM;
+-                  fprintf(fout, "\n\tmemset(&%s, 0, sizeof(%s));",
+-                               plist->pl.param_name, defp1->def_name);
+               }
+           }
+       }
+     }
++    for (plist = defp->pc.plists; plist; plist = plist->next) {
++      if (plist->component_kind == DEF_PARAM) {
++          fprintf(fout, "\n\tmemset(&%s, 0, sizeof(%s));",
++                  plist->pl.param_name,
++                  plist->pl.param_name);
++      }
++    }
++
+     f_print(fout, "\n");
+ }
diff --git a/security/openafs-sa-2019-002-stable16.patch b/security/openafs-sa-2019-002-stable16.patch
new file mode 100644 (file)
index 0000000..fd59e53
--- /dev/null
@@ -0,0 +1,122 @@
+commit 2a7b4b891bec730a6c4f58e3b5976383e4c179c1
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Wed Aug 7 21:19:47 2019 -0500
+
+    OPENAFS-SA-2019-002: Zero all server RPC args
+    
+    Currently, our server-side RPC argument-handling code generated from
+    rxgen initializes complex arguments like so (for example, in
+    _RXAFS_BulkStatus):
+    
+        AFSCBFids FidsArray;
+        AFSBulkStats StatArray;
+        AFSCBs CBArray;
+        AFSVolSync Sync;
+    
+        FidsArray.AFSCBFids_val = 0;
+        FidsArray.AFSCBFids_len = 0;
+        CBArray.AFSCBs_val = 0;
+        CBArray.AFSCBs_len = 0;
+        StatArray.AFSBulkStats_val = 0;
+        StatArray.AFSBulkStats_len = 0;
+    
+    This is done for any input or output arguments, but only for types we
+    need to free afterwards (arrays, usually). We do not do this for
+    simple types, like single flat structs. In the above example, we do
+    this for the arrays FidsArray, StatArray, and CBArray, but 'Sync' is
+    not initialized to anything.
+    
+    If some server RPC handlers never set a value for an output argument,
+    this means we'll send uninitialized stack memory to our peer.
+    Currently this can happen in, for example,
+    MRXSTATS_RetrieveProcessRPCStats if 'rxi_monitor_processStats' is
+    unset (specifically, the 'clock_sec' and 'clock_usec' arguments are
+    never set when rx_enableProcessRPCStats() has not been called).
+    
+    To make sure we cannot send uninitialized data to our peer, change
+    rxgen to instead 'memset(&arg, 0, sizeof(arg));' for every single
+    parameter. Using memset in this way just makes this a little simpler
+    inside rxgen, since all we need to do this is the name of the
+    argument.
+    
+    With this commit, the rxgen-generated code for the above example now
+    looks like this:
+    
+        AFSCBFids FidsArray;
+        AFSBulkStats StatArray;
+        AFSCBs CBArray;
+        AFSVolSync Sync;
+    
+        memset(&FidsArray, 0, sizeof(FidsArray));
+        memset(&CBArray, 0, sizeof(CBArray));
+        memset(&StatArray, 0, sizeof(StatsArray));
+        memset(&Sync, 0, sizeof(Sync));
+    
+    Reviewed-on: https://gerrit.openafs.org/13914
+    Reviewed-by: Andrew Deason <adeason@sinenomine.net>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+    (cherry picked from commit 93aee3cf40622993b95bd1af77080a31670c24bb)
+    
+    Reviewed-on: https://gerrit.openafs.org/13917
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit fcaac44f845d18d6fd5d2f3685db11118d8f8626)
+    
+    Change-Id: Ic096570e9c894fb05d084ba451beabda3bb295e2
+    Reviewed-on: https://gerrit.openafs.org/13922
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+
+diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c
+index 8ff57d0794..e3731dfc8a 100644
+--- a/src/rxgen/rpc_parse.c
++++ b/src/rxgen/rpc_parse.c
+@@ -1508,8 +1508,6 @@ ss_ProcSpecial_setup(definition * defp, int *somefrees)
+                   plist->pl.string_name = spec->sdef.string_name;
+                   plist->pl.param_flag |= FREETHIS_PARAM;
+                   *somefrees = 1;
+-                  fprintf(fout, "\n\t%s.%s = 0;", plist->pl.param_name,
+-                          spec->sdef.string_name);
+               }
+           }
+       }
+@@ -1527,22 +1525,13 @@ ss_ProcSpecial_setup(definition * defp, int *somefrees)
+                   case REL_ARRAY:
+                       plist->pl.string_name = alloc(40);
+                       if (brief_flag) {
+-                          f_print(fout, "\n\t%s.val = 0;",
+-                                  plist->pl.param_name);
+-                          f_print(fout, "\n\t%s.len = 0;",
+-                                  plist->pl.param_name);
+                           s_print(plist->pl.string_name, "val");
+                       } else {
+-                          f_print(fout, "\n\t%s.%s_val = 0;",
+-                                  plist->pl.param_name, defp1->def_name);
+-                          f_print(fout, "\n\t%s.%s_len = 0;",
+-                                  plist->pl.param_name, defp1->def_name);
+                           s_print(plist->pl.string_name, "%s_val",
+                                   defp1->def_name);
+                       }
+                       break;
+                   case REL_POINTER:
+-                      f_print(fout, "\n\t%s = 0;", plist->pl.param_name);
+                       plist->pl.string_name = NULL;
+                       break;
+                   default:
+@@ -1552,6 +1541,15 @@ ss_ProcSpecial_setup(definition * defp, int *somefrees)
+           }
+       }
+     }
++
++    for (plist = defp->pc.plists; plist; plist = plist->next) {
++      if (plist->component_kind == DEF_PARAM) {
++          fprintf(fout, "\n\tmemset(&%s, 0, sizeof(%s));",
++                  plist->pl.param_name,
++                  plist->pl.param_name);
++      }
++    }
++
+     f_print(fout, "\n");
+ }
diff --git a/security/openafs-sa-2019-002-stable18.patch b/security/openafs-sa-2019-002-stable18.patch
new file mode 100644 (file)
index 0000000..2607277
--- /dev/null
@@ -0,0 +1,123 @@
+commit fcaac44f845d18d6fd5d2f3685db11118d8f8626
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Wed Aug 7 21:19:47 2019 -0500
+
+    OPENAFS-SA-2019-002: Zero all server RPC args
+    
+    Currently, our server-side RPC argument-handling code generated from
+    rxgen initializes complex arguments like so (for example, in
+    _RXAFS_BulkStatus):
+    
+        AFSCBFids FidsArray;
+        AFSBulkStats StatArray;
+        AFSCBs CBArray;
+        AFSVolSync Sync;
+    
+        FidsArray.AFSCBFids_val = 0;
+        FidsArray.AFSCBFids_len = 0;
+        CBArray.AFSCBs_val = 0;
+        CBArray.AFSCBs_len = 0;
+        StatArray.AFSBulkStats_val = 0;
+        StatArray.AFSBulkStats_len = 0;
+    
+    This is done for any input or output arguments, but only for types we
+    need to free afterwards (arrays, usually). We do not do this for
+    simple types, like single flat structs. In the above example, we do
+    this for the arrays FidsArray, StatArray, and CBArray, but 'Sync' is
+    not initialized to anything.
+    
+    If some server RPC handlers never set a value for an output argument,
+    this means we'll send uninitialized stack memory to our peer.
+    Currently this can happen in, for example,
+    MRXSTATS_RetrieveProcessRPCStats if 'rxi_monitor_processStats' is
+    unset (specifically, the 'clock_sec' and 'clock_usec' arguments are
+    never set when rx_enableProcessRPCStats() has not been called).
+    
+    To make sure we cannot send uninitialized data to our peer, change
+    rxgen to instead 'memset(&arg, 0, sizeof(arg));' for every single
+    parameter. Using memset in this way just makes this a little simpler
+    inside rxgen, since all we need to do this is the name of the
+    argument.
+    
+    With this commit, the rxgen-generated code for the above example now
+    looks like this:
+    
+        AFSCBFids FidsArray;
+        AFSBulkStats StatArray;
+        AFSCBs CBArray;
+        AFSVolSync Sync;
+    
+        memset(&FidsArray, 0, sizeof(FidsArray));
+        memset(&CBArray, 0, sizeof(CBArray));
+        memset(&StatArray, 0, sizeof(StatsArray));
+        memset(&Sync, 0, sizeof(Sync));
+    
+    Reviewed-on: https://gerrit.openafs.org/13914
+    Reviewed-by: Andrew Deason <adeason@sinenomine.net>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+    (cherry picked from commit 93aee3cf40622993b95bd1af77080a31670c24bb)
+    
+    Change-Id: I6e19aaea57e545455b65851d1bedade584e482f0
+    Reviewed-on: https://gerrit.openafs.org/13917
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+
+diff --git a/src/rxgen/rpc_parse.c b/src/rxgen/rpc_parse.c
+index 032afe0313..629e703504 100644
+--- a/src/rxgen/rpc_parse.c
++++ b/src/rxgen/rpc_parse.c
+@@ -1435,8 +1435,6 @@ ss_ProcSpecial_setup(definition * defp)
+               if (streq(string, structname(plist->pl.param_type))) {
+                   plist->pl.string_name = spec->sdef.string_name;
+                   plist->pl.param_flag |= FREETHIS_PARAM;
+-                  fprintf(fout, "\n\t%s.%s = 0;", plist->pl.param_name,
+-                          spec->sdef.string_name);
+               }
+           }
+       }
+@@ -1451,22 +1449,13 @@ ss_ProcSpecial_setup(definition * defp)
+                   case REL_ARRAY:
+                       plist->pl.string_name = alloc(40);
+                       if (brief_flag) {
+-                          f_print(fout, "\n\t%s.val = 0;",
+-                                  plist->pl.param_name);
+-                          f_print(fout, "\n\t%s.len = 0;",
+-                                  plist->pl.param_name);
+                           s_print(plist->pl.string_name, "val");
+                       } else {
+-                          f_print(fout, "\n\t%s.%s_val = 0;",
+-                                  plist->pl.param_name, defp1->def_name);
+-                          f_print(fout, "\n\t%s.%s_len = 0;",
+-                                  plist->pl.param_name, defp1->def_name);
+                           s_print(plist->pl.string_name, "%s_val",
+                                   defp1->def_name);
+                       }
+                       break;
+                   case REL_POINTER:
+-                      f_print(fout, "\n\t%s = 0;", plist->pl.param_name);
+                       plist->pl.string_name = NULL;
+                       break;
+                   default:
+@@ -1482,13 +1471,19 @@ ss_ProcSpecial_setup(definition * defp)
+           if (plist->component_kind == DEF_PARAM) {
+               if (streq(defp1->def_name, structname(plist->pl.param_type))) {
+                   plist->pl.param_flag |= FREETHIS_PARAM;
+-                  fprintf(fout, "\n\tmemset(&%s, 0, sizeof(%s));",
+-                               plist->pl.param_name, defp1->def_name);
+               }
+           }
+       }
+     }
++    for (plist = defp->pc.plists; plist; plist = plist->next) {
++      if (plist->component_kind == DEF_PARAM) {
++          fprintf(fout, "\n\tmemset(&%s, 0, sizeof(%s));",
++                  plist->pl.param_name,
++                  plist->pl.param_name);
++      }
++    }
++
+     f_print(fout, "\n");
+ }
diff --git a/security/openafs-sa-2019-003-master.patch b/security/openafs-sa-2019-003-master.patch
new file mode 100644 (file)
index 0000000..771587c
--- /dev/null
@@ -0,0 +1,64 @@
+commit 6ec46ba7773089e1549d27a0d345afeca65c9472
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Mon Sep 16 14:06:53 2019 -0500
+
+    OPENAFS-SA-2019-003: ubik: Avoid unlocked ubik_currentTrans deref
+    
+    Currently, SVOTE_Debug/SVOTE_DebugOld examine some ubik internal state
+    without any locks, because the speed of these functions is more
+    important than accuracy.
+    
+    However, one of the pieces of data we examine is ubik_currentTrans,
+    which we dereference to get ubik_currentTrans->type. ubik_currentTrans
+    could be set to NULL while this code is running, so there is a small
+    chance of this code causing a segfault, if SVOTE_Debug() is running
+    when the current transaction ends.
+    
+    We only ever initialize ubik_currentTrans as a write transation (via
+    SDISK_Begin), so this check is pointless anyway. Accordingly, skip the
+    type check, and always assume that any active transaction is a write
+    transaction.  This means we only ever access ubik_currentTrans once,
+    avoiding any risk of the value changing between accesses (and we no
+    longer need to dereference it, anyway).
+    
+    Note that, since ubik_currentTrans is not marked as 'volatile', some C
+    compilers, with certain options, can and do assume that its value will
+    not change between accesses, and thus only fetch the pointer value once.
+    This avoids the risk of NULL dereference (and thus, crash, if pointer
+    stores/loads are atomic), but the value pointed to by ubik_currentTrans->type
+    would be incorrect when the transaction ends during the execution of
+    SVOTE_Debug().
+    
+    Change-Id: Ia36c58e5906f5e8df59936f845ae11e886e8ec38
+    Reviewed-on: https://gerrit.openafs.org/13915
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+
+diff --git a/src/ubik/vote.c b/src/ubik/vote.c
+index 34f285dcd2..1ae7456435 100644
+--- a/src/ubik/vote.c
++++ b/src/ubik/vote.c
+@@ -444,10 +444,7 @@ SVOTE_Debug(struct rx_call * rxcall, struct ubik_debug * aparm)
+     if (ubik_currentTrans) {
+       aparm->currentTrans = 1;
+-      if (ubik_currentTrans->type == UBIK_WRITETRANS)
+-          aparm->writeTrans = 1;
+-      else
+-          aparm->writeTrans = 0;
++      aparm->writeTrans = 1;
+     } else {
+       aparm->currentTrans = 0;
+     }
+@@ -527,10 +524,7 @@ SVOTE_DebugOld(struct rx_call * rxcall,
+     if (ubik_currentTrans) {
+       aparm->currentTrans = 1;
+-      if (ubik_currentTrans->type == UBIK_WRITETRANS)
+-          aparm->writeTrans = 1;
+-      else
+-          aparm->writeTrans = 0;
++      aparm->writeTrans = 1;
+     } else {
+       aparm->currentTrans = 0;
+     }
diff --git a/security/openafs-sa-2019-003-stable16.patch b/security/openafs-sa-2019-003-stable16.patch
new file mode 100644 (file)
index 0000000..08f4562
--- /dev/null
@@ -0,0 +1,74 @@
+commit 3915886843a1d4b21bd2539e7e9d4057965a52dd
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Mon Sep 16 14:06:53 2019 -0500
+
+    OPENAFS-SA-2019-003: ubik: Avoid unlocked ubik_currentTrans deref
+    
+    Currently, SVOTE_Debug/SVOTE_DebugOld examine some ubik internal state
+    without any locks, because the speed of these functions is more
+    important than accuracy.
+    
+    However, one of the pieces of data we examine is ubik_currentTrans,
+    which we dereference to get ubik_currentTrans->type. ubik_currentTrans
+    could be set to NULL while this code is running, so there is a small
+    chance of this code causing a segfault, if SVOTE_Debug() is running
+    when the current transaction ends.
+    
+    We only ever initialize ubik_currentTrans as a write transation (via
+    SDISK_Begin), so this check is pointless anyway. Accordingly, skip the
+    type check, and always assume that any active transaction is a write
+    transaction.  This means we only ever access ubik_currentTrans once,
+    avoiding any risk of the value changing between accesses (and we no
+    longer need to dereference it, anyway).
+    
+    Note that, since ubik_currentTrans is not marked as 'volatile', some C
+    compilers, with certain options, can and do assume that its value will
+    not change between accesses, and thus only fetch the pointer value once.
+    This avoids the risk of NULL dereference (and thus, crash, if pointer
+    stores/loads are atomic), but the value pointed to by ubik_currentTrans->type
+    would be incorrect when the transaction ends during the execution of
+    SVOTE_Debug().
+    
+    Reviewed-on: https://gerrit.openafs.org/13915
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit 6ec46ba7773089e1549d27a0d345afeca65c9472)
+    
+    Reviewed-on: https://gerrit.openafs.org/13918
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit 213b9dc386ff89a14379313ee8ec09280f130a29)
+    
+    Change-Id: I0ddbc2309de09a629150a6b3825e1aa8bda8b910
+    Reviewed-on: https://gerrit.openafs.org/13923
+    Tested-by: BuildBot <buildbot@rampaginggeek.com>
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+
+diff --git a/src/ubik/vote.c b/src/ubik/vote.c
+index 5d75a80228..4d6ab44a20 100644
+--- a/src/ubik/vote.c
++++ b/src/ubik/vote.c
+@@ -447,10 +447,7 @@ SVOTE_Debug(struct rx_call * rxcall, struct ubik_debug * aparm)
+     if (ubik_currentTrans) {
+       aparm->currentTrans = 1;
+-      if (ubik_currentTrans->type == UBIK_WRITETRANS)
+-          aparm->writeTrans = 1;
+-      else
+-          aparm->writeTrans = 0;
++      aparm->writeTrans = 1;
+     } else {
+       aparm->currentTrans = 0;
+     }
+@@ -530,10 +527,7 @@ SVOTE_DebugOld(struct rx_call * rxcall,
+     if (ubik_currentTrans) {
+       aparm->currentTrans = 1;
+-      if (ubik_currentTrans->type == UBIK_WRITETRANS)
+-          aparm->writeTrans = 1;
+-      else
+-          aparm->writeTrans = 0;
++      aparm->writeTrans = 1;
+     } else {
+       aparm->currentTrans = 0;
+     }
diff --git a/security/openafs-sa-2019-003-stable18.patch b/security/openafs-sa-2019-003-stable18.patch
new file mode 100644 (file)
index 0000000..cf1ad17
--- /dev/null
@@ -0,0 +1,69 @@
+commit 213b9dc386ff89a14379313ee8ec09280f130a29
+Author: Andrew Deason <adeason@sinenomine.net>
+Date:   Mon Sep 16 14:06:53 2019 -0500
+
+    OPENAFS-SA-2019-003: ubik: Avoid unlocked ubik_currentTrans deref
+    
+    Currently, SVOTE_Debug/SVOTE_DebugOld examine some ubik internal state
+    without any locks, because the speed of these functions is more
+    important than accuracy.
+    
+    However, one of the pieces of data we examine is ubik_currentTrans,
+    which we dereference to get ubik_currentTrans->type. ubik_currentTrans
+    could be set to NULL while this code is running, so there is a small
+    chance of this code causing a segfault, if SVOTE_Debug() is running
+    when the current transaction ends.
+    
+    We only ever initialize ubik_currentTrans as a write transation (via
+    SDISK_Begin), so this check is pointless anyway. Accordingly, skip the
+    type check, and always assume that any active transaction is a write
+    transaction.  This means we only ever access ubik_currentTrans once,
+    avoiding any risk of the value changing between accesses (and we no
+    longer need to dereference it, anyway).
+    
+    Note that, since ubik_currentTrans is not marked as 'volatile', some C
+    compilers, with certain options, can and do assume that its value will
+    not change between accesses, and thus only fetch the pointer value once.
+    This avoids the risk of NULL dereference (and thus, crash, if pointer
+    stores/loads are atomic), but the value pointed to by ubik_currentTrans->type
+    would be incorrect when the transaction ends during the execution of
+    SVOTE_Debug().
+    
+    Reviewed-on: https://gerrit.openafs.org/13915
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+    (cherry picked from commit 6ec46ba7773089e1549d27a0d345afeca65c9472)
+    
+    Change-Id: I634ddb27e7a8dbe5c9d1dacdc83070efa470b50b
+    Reviewed-on: https://gerrit.openafs.org/13918
+    Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
+    Tested-by: Benjamin Kaduk <kaduk@mit.edu>
+
+diff --git a/src/ubik/vote.c b/src/ubik/vote.c
+index 87cfb3911e..3a8374e88f 100644
+--- a/src/ubik/vote.c
++++ b/src/ubik/vote.c
+@@ -441,10 +441,7 @@ SVOTE_Debug(struct rx_call * rxcall, struct ubik_debug * aparm)
+     if (ubik_currentTrans) {
+       aparm->currentTrans = 1;
+-      if (ubik_currentTrans->type == UBIK_WRITETRANS)
+-          aparm->writeTrans = 1;
+-      else
+-          aparm->writeTrans = 0;
++      aparm->writeTrans = 1;
+     } else {
+       aparm->currentTrans = 0;
+     }
+@@ -524,10 +521,7 @@ SVOTE_DebugOld(struct rx_call * rxcall,
+     if (ubik_currentTrans) {
+       aparm->currentTrans = 1;
+-      if (ubik_currentTrans->type == UBIK_WRITETRANS)
+-          aparm->writeTrans = 1;
+-      else
+-          aparm->writeTrans = 0;
++      aparm->writeTrans = 1;
+     } else {
+       aparm->currentTrans = 0;
+     }