Go 1.7.4 fixes multipart cleanup and certificate distrust
Two security fixes address distinct gaps between an API's apparent behavior and its implementation, closing upload files and respecting Darwin certificate trust settings.
A multipart upload can exhaust a server's file descriptors even when the parser has a memory limit. The limit moves file data onto disk, where temporary files require their own cleanup. Go 1.7.4 fixes a failure in that cleanup, alongside a separate failure to respect explicit certificate distrust on Darwin. The release history dates the release to December 1. The security announcement recommends updating to Go 1.7.4 or the accompanying Go 1.6.4 release.
I value Go's explicit handling of errors because operational policy should be visible in ordinary code. The multipart fix is a useful example of how much that policy includes. An unsuccessful copy still leaves a file that needs closing. Returning the copy error does not complete the operation's resource management.
A memory threshold creates another resource obligation
The announcement identifies Request.ParseMultipartForm as the HTTP entry point. Its maxMemory argument controls when file data moves into temporary files. A caller can supply that argument while still remaining exposed to the descriptor exhaustion problem. The threshold concerns storage decisions inside parsing, so treating it as a general limit on the cost of an upload gives it a meaning it does not have.
The Go 1.7.4 multipart implementation makes the transition concrete. For a file part, it reads into a buffer up to maxMemory+1. Reading beyond the remaining allowance tells the parser that the file needs disk storage. It creates a temporary file, then copies the buffered prefix and the remaining part into that file. This avoids losing the bytes already consumed while deciding where to store the upload.
The temporary file now has two relevant properties. It has a name that the parsed form can retain, and it has an open file descriptor used during the copy. Keeping the name does not require retaining the open descriptor. The implementation can close the file after copying and later reopen it through FileHeader.Open when the application reads the uploaded content.
Issue 17965 requests backporting the change that closes the file regardless of the copy's success. The issue links the failure to potential denial of service through exhausted server file descriptors. The release announcement confirms that an attacker could construct a multipart request that triggered this exhaustion. This makes an error path in a parser relevant to the availability of the server receiving the request.
Closing has its own error result
The corrected implementation calls file.Close immediately after io.Copy. If the copy succeeded, it retains any error from closing. If copying already failed, that earlier error remains the result. The code consequently performs both operations while giving the original data transfer failure precedence over a subsequent cleanup failure.
This ordering matters when reading the change. Moving Close onto the success path would leave the original resource leak. Overwriting the copy error with the result of Close would risk reporting success after a failed transfer. The fix instead makes closing unconditional and replaces the error only when there was no earlier error to preserve. Both properties are visible in a small block of ordinary control flow.
When that block finds an error, it removes the temporary file by name before returning. Closing the descriptor and removing the file are distinct operations in the implementation. On success, the parser records the name in the file header. On a later open, the file header calls os.Open for a disk-backed part. Those details explain why closing at the end of the copy does not prevent the application from accessing a successfully parsed upload.
The form also has a RemoveAll method for its associated temporary files. Its implementation walks the file headers and removes their recorded temporary paths. That is a separate responsibility from closing the descriptor used while constructing each file. Understanding both steps prevents a mistaken reading of the security fix as a change that simply deletes uploaded content before it can be used.
I prefer this kind of correction because the resource lifetime can be checked locally. The copy ends, the file closes, and the error handling decides whether its contents remain part of a successful form. The implementation does not require a reader to infer that a failed operation somehow released everything it acquired.
Presence in the Keychain did not imply trust
The certificate issue concerns Darwin's root certificate handling. According to issue 18141, a root certificate could be present in the user's Keychain and explicitly marked as untrusted, yet a Go program would still verify a connection using it. The problematic distinction was between a stored certificate and the user's trust decision about that certificate.
Loading roots without honoring those preferences changes the effective authentication policy. A user who explicitly distrusts a root expects connections relying on that root to fail verification. The reported behavior could accept such a connection. The release addresses that mismatch, and the announcement credits Xy Ziemba with identifying and reporting it.
This is a platform integration issue with a narrower scope than a general statement that certificate verification is broken. The announcement identifies Darwin and explicit distrust of a loaded root. It does not say that every certificate chain on every platform is accepted. Accurate scope matters because it identifies which assumption failed, the expectation that Go's use of the platform's certificate information includes the user's negative trust decisions.
The two fixes therefore involve different forms of state. Multipart parsing creates resources while processing untrusted input. Certificate verification consumes a policy decision already recorded by the user. Each implementation needs to preserve a property that the caller cannot establish just by invoking the high-level API. A memory argument cannot close a leaked descriptor, and a Keychain entry's presence cannot substitute for its trust settings.
The release announcement also includes a correction for source builders. The initial go1.7.4 tag pointed at the wrong commit and could report its version as go1.7.3. Chris Broadfoot states that the published download binaries were unaffected and supplies the corrected commit identifier. That distinction gives source builders a concrete explanation for an unexpected version result without casting doubt on the separately distributed binaries. Go 1.6.4 carries the same security fixes for users on that release line.