derp/derpserver,cmd/derper: don't mutate cert provider's shared tls.Certificate (#20478)
ModifyTLSConfigToAddMetaCert (and its inline copy in cmd/derper) appended the DERP meta cert directly to the *tls.Certificate returned by the underlying GetCertificate. autocert returns a certificate sharing a cached chain slice (and, on the TLS-ALPN token path, the same pointer) across concurrent handshakes, so the in-place append was a data race and could grow the served chain unboundedly. Return a shallow copy with the meta cert appended to a fresh backing array instead, and have cmd/derper reuse ModifyTLSConfigToAddMetaCert rather than duplicating the wrapper. Fixes #20352 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
This commit is contained in:
@@ -719,7 +719,9 @@ func (s *Server) initMetacert() {
|
||||
func (s *Server) MetaCert() []byte { return s.metaCert }
|
||||
|
||||
// ModifyTLSConfigToAddMetaCert modifies c.GetCertificate to make
|
||||
// it append s.MetaCert to the returned certificates.
|
||||
// it append s.MetaCert to the returned certificates. The certificate
|
||||
// returned by the underlying GetCertificate is not mutated; a copy
|
||||
// with the meta cert appended is returned instead.
|
||||
//
|
||||
// It panics if c or c.GetCertificate is nil.
|
||||
func (s *Server) ModifyTLSConfigToAddMetaCert(c *tls.Config) {
|
||||
@@ -732,8 +734,19 @@ func (s *Server) ModifyTLSConfigToAddMetaCert(c *tls.Config) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert.Certificate = append(cert.Certificate, s.MetaCert())
|
||||
return cert, nil
|
||||
if cert == nil {
|
||||
// Underlying GetCertificate returned (nil, nil) to signal
|
||||
// fallback to Config.Certificates et al. Pass that through.
|
||||
return nil, nil
|
||||
}
|
||||
// Don't mutate the *tls.Certificate pointed to by cert: the
|
||||
// underlying GetCertificate implementation may return a shared
|
||||
// cached value. Return a shallow copy with the meta cert
|
||||
// appended to a freshly allocated chain slice.
|
||||
certCopy := *cert
|
||||
chain := cert.Certificate
|
||||
certCopy.Certificate = append(chain[:len(chain):len(chain)], s.MetaCert())
|
||||
return &certCopy, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user