Skip to content

Commit 8cd431d

Browse files
Merge pull request #151136 from cockroachdb/blathers/backport-release-25.3-151041
release-25.3: security: fix memory accounting issue in client certificate cache
2 parents 707f708 + 3092aed commit 8cd431d

File tree

4 files changed

+34
-7
lines changed

4 files changed

+34
-7
lines changed

pkg/security/certificate_manager.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"github.com/cockroachdb/cockroach/pkg/security/certnames"
1414
"github.com/cockroachdb/cockroach/pkg/security/clientcert"
1515
"github.com/cockroachdb/cockroach/pkg/security/username"
16+
"github.com/cockroachdb/cockroach/pkg/settings"
17+
"github.com/cockroachdb/cockroach/pkg/settings/cluster"
1618
"github.com/cockroachdb/cockroach/pkg/util/log"
1719
"github.com/cockroachdb/cockroach/pkg/util/log/eventpb"
1820
"github.com/cockroachdb/cockroach/pkg/util/log/severity"
@@ -196,15 +198,24 @@ func (cm *CertificateManager) RegisterSignalHandler(
196198
})
197199
}
198200

201+
var certCacheMemLimit = settings.RegisterByteSizeSetting(
202+
settings.ApplicationLevel,
203+
"security.client_cert.cache_memory_limit",
204+
"memory limit for the client certificate expiration cache",
205+
1<<29, // 512MiB
206+
)
207+
199208
// RegisterExpirationCache registers a cache for client certificate expiration.
200209
// It is called during server startup.
201210
func (cm *CertificateManager) RegisterExpirationCache(
202211
ctx context.Context,
203212
stopper *stop.Stopper,
204213
timeSrc timeutil.TimeSource,
205214
parentMon *mon.BytesMonitor,
215+
st *cluster.Settings,
206216
) error {
207-
m := mon.NewMonitorInheritWithLimit(mon.MakeName("client-expiration-caches"), 0 /* limit */, parentMon, true /* longLiving */)
217+
limit := certCacheMemLimit.Get(&st.SV)
218+
m := mon.NewMonitorInheritWithLimit(mon.MakeName("client-expiration-caches"), limit, parentMon, true /* longLiving */)
208219
acc := m.MakeConcurrentBoundAccount()
209220
m.StartNoReserved(ctx, parentMon)
210221

pkg/security/clientcert/cert_expiry_cache.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,19 @@ func (c *Cache) Upsert(ctx context.Context, user string, serial string, newExpir
9999
if _, ok := c.cache[user]; !ok {
100100
err := c.account.Grow(ctx, 2*GaugeSize)
101101
if err != nil {
102-
log.Ops.Warningf(ctx, "no memory available to cache cert expiry: %v", err)
102+
log.Warningf(ctx, "no memory available to cache cert expiry: %v", err)
103103
return
104104
}
105105
c.cache[user] = map[string]certInfo{}
106106
}
107107

108-
err := c.account.Grow(ctx, CertInfoSize)
109-
if err != nil {
110-
log.Warningf(ctx, "no memory available to cache cert expiry: %v", err)
111-
c.evictLocked(ctx, user, serial)
108+
// if the serial hasn't been seen, report it in the memory accounting.
109+
if _, ok := c.cache[user][serial]; !ok {
110+
err := c.account.Grow(ctx, CertInfoSize)
111+
if err != nil {
112+
log.Warningf(ctx, "no memory available to cache cert expiry: %v", err)
113+
return
114+
}
112115
}
113116

114117
// insert / update the certificate expiration time.

pkg/security/clientcert/cert_expiry_cache_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ func TestAllocationTracking(t *testing.T) {
313313
cache.Upsert(ctx, "user1", "serial2", 120)
314314
cache.Upsert(ctx, "user2", "serial3", 65)
315315
clock.Advance(time.Minute)
316+
require.Equal(t, (3*certInfoSize)+(4*gaugeSize), account.Used())
316317
cache.Purge(ctx)
317318
cache.Upsert(ctx, "user2", "serial4", 75)
318319
require.Equal(t, certInfoSize+(2*gaugeSize), account.Used())
@@ -324,9 +325,21 @@ func TestAllocationTracking(t *testing.T) {
324325
cache.Upsert(ctx, "user1", "serial2", 120)
325326
cache.Upsert(ctx, "user2", "serial3", 65)
326327
cache.Upsert(ctx, "user2", "serial4", 75)
328+
require.Equal(t, (4*certInfoSize)+(4*gaugeSize), account.Used())
327329
cache.Clear()
328330
require.Equal(t, int64(0), account.Used())
329331
})
332+
333+
t.Run("overwriting an existing certificate does not change the reported memory allocation", func(t *testing.T) {
334+
cache, account := newCacheAndAccount(ctx, clock, stopper)
335+
require.Equal(t, int64(0), account.Used())
336+
cache.Upsert(ctx, "user1", "serial1", 100)
337+
require.Equal(t, certInfoSize+(2*gaugeSize), account.Used())
338+
cache.Upsert(ctx, "user1", "serial1", 100)
339+
require.Equal(t, certInfoSize+(2*gaugeSize), account.Used())
340+
cache.Upsert(ctx, "user1", "serial1", 100)
341+
require.Equal(t, certInfoSize+(2*gaugeSize), account.Used())
342+
})
330343
}
331344

332345
func TestExpiration(t *testing.T) {

pkg/server/server_sql.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,7 @@ func newSQLServer(ctx context.Context, cfg sqlServerArgs) (*SQLServer, error) {
944944
return nil, errors.Wrap(err, "initializing certificate manager")
945945
}
946946
err = certMgr.RegisterExpirationCache(
947-
ctx, cfg.stopper, &timeutil.DefaultTimeSource{}, rootSQLMemoryMonitor,
947+
ctx, cfg.stopper, &timeutil.DefaultTimeSource{}, rootSQLMemoryMonitor, cfg.Settings,
948948
)
949949
if err != nil {
950950
return nil, errors.Wrap(err, "adding clientcert cache")

0 commit comments

Comments
 (0)