Skip to content

namespace.WithNamespace is not thread safe #3504

@darfux

Description

@darfux

Description
If there are multiple goroutines calling namespace.WithNamespace on a ctx that already had namespace, there will be a data race like:

WARNING: DATA RACE
Write at 0x00c00041a8c8 by goroutine 84:
  github.com/containerd/containerd/vendor/github.com/containerd/ttrpc.MD.Set()
      go/src/github.com/containerd/containerd/vendor/github.com/containerd/ttrpc/metadata.go:48 +0x1be
  github.com/containerd/containerd/namespaces.withTTRPCNamespaceHeader()
      go/src/github.com/containerd/containerd/namespaces/ttrpc.go:35 +0x1f2
  github.com/containerd/containerd/namespaces.WithNamespace()
      go/src/github.com/containerd/containerd/namespaces/context.go:41 +0x209

Maybe this is because withTTRPCNamespaceHeader sets the MD directly,

func withTTRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
md, ok := ttrpc.GetMetadata(ctx)
if !ok {
md = ttrpc.MD{}
}
md.Set(TTRPCHeader, namespace)

while withGRPCNamespaceHeader will take a copy of MD.
func withGRPCNamespaceHeader(ctx context.Context, namespace string) context.Context {
// also store on the grpc headers so it gets picked up by any clients that
// are using this.
nsheader := metadata.Pairs(GRPCHeader, namespace)
md, ok := metadata.FromOutgoingContext(ctx) // merge with outgoing context.
if !ok {
md = nsheader
} else {
// order ensures the latest is first in this list.
md = metadata.Join(nsheader, md)

So is it ok here? Or should we add metadata copy functions to ttrpc and use them in withTTRPCNamespaceHeader ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions