diff --git a/virtcontainers/agent.go b/virtcontainers/agent.go index 7e68a3e6c3..f1d6f5b7c0 100644 --- a/virtcontainers/agent.go +++ b/virtcontainers/agent.go @@ -218,4 +218,7 @@ type agent interface { // getSharePath will return the agent 9pfs share mount path getSharePath(id string) string + + // reseedRNG will reseed the guest random number generator + reseedRNG(data []byte) error } diff --git a/virtcontainers/factory/factory.go b/virtcontainers/factory/factory.go index c2f8845aff..e1c125c9d0 100644 --- a/virtcontainers/factory/factory.go +++ b/virtcontainers/factory/factory.go @@ -151,6 +151,12 @@ func (f *factory) GetVM(config vc.VMConfig) (*vc.VM, error) { return nil, err } + // reseed RNG so that shared memory VMs do not generate same random numbers. + err = vm.ReseedRNG() + if err != nil { + return nil, err + } + online := false baseConfig := f.base.Config().HypervisorConfig if baseConfig.DefaultVCPUs < hypervisorConfig.DefaultVCPUs { diff --git a/virtcontainers/hyperstart_agent.go b/virtcontainers/hyperstart_agent.go index cd2f9a358c..521a58f4ae 100644 --- a/virtcontainers/hyperstart_agent.go +++ b/virtcontainers/hyperstart_agent.go @@ -884,3 +884,8 @@ func (h *hyper) resumeContainer(sandbox *Sandbox, c Container) error { func (h *hyper) cleanupSandbox(sandbox *Sandbox) error { return nil } + +func (h *hyper) reseedRNG(data []byte) error { + // hyperstart-agent does not support reseeding + return nil +} diff --git a/virtcontainers/hyperstart_agent_test.go b/virtcontainers/hyperstart_agent_test.go index ea986aaff0..d0c4ec43c5 100644 --- a/virtcontainers/hyperstart_agent_test.go +++ b/virtcontainers/hyperstart_agent_test.go @@ -198,3 +198,11 @@ func TestHyperConfigure(t *testing.T) { err = h.configure(m, id, dir, false, c) assert.Nil(err) } + +func TestHyperReseedAPI(t *testing.T) { + assert := assert.New(t) + + h := &hyper{} + err := h.reseedRNG([]byte{}) + assert.Nil(err) +} diff --git a/virtcontainers/kata_agent.go b/virtcontainers/kata_agent.go index 0ffbbc3798..b307bc73b8 100644 --- a/virtcontainers/kata_agent.go +++ b/virtcontainers/kata_agent.go @@ -1267,6 +1267,14 @@ func (k *kataAgent) closeProcessStdin(c *Container, ProcessID string) error { return err } +func (k *kataAgent) reseedRNG(data []byte) error { + _, err := k.sendReq(&grpc.ReseedRandomDevRequest{ + Data: data, + }) + + return err +} + type reqFunc func(context.Context, interface{}, ...golangGrpc.CallOption) (interface{}, error) func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) { @@ -1333,6 +1341,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) { k.reqHandlers["grpc.ResumeContainerRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) { return k.client.ResumeContainer(ctx, req.(*grpc.ResumeContainerRequest), opts...) } + k.reqHandlers["grpc.ReseedRandomDevRequest"] = func(ctx context.Context, req interface{}, opts ...golangGrpc.CallOption) (interface{}, error) { + return k.client.ReseedRandomDev(ctx, req.(*grpc.ReseedRandomDevRequest), opts...) + } } func (k *kataAgent) sendReq(request interface{}) (interface{}, error) { diff --git a/virtcontainers/kata_agent_test.go b/virtcontainers/kata_agent_test.go index 1b8b0d6864..75c8651c09 100644 --- a/virtcontainers/kata_agent_test.go +++ b/virtcontainers/kata_agent_test.go @@ -225,6 +225,10 @@ func (p *gRPCProxy) ResumeContainer(ctx context.Context, req *pb.ResumeContainer return emptyResp, nil } +func (p *gRPCProxy) ReseedRandomDev(ctx context.Context, req *pb.ReseedRandomDevRequest) (*gpb.Empty, error) { + return emptyResp, nil +} + func gRPCRegister(s *grpc.Server, srv interface{}) { switch g := srv.(type) { case *gRPCProxy: diff --git a/virtcontainers/noop_agent.go b/virtcontainers/noop_agent.go index f4fbb8c137..fe919ec587 100644 --- a/virtcontainers/noop_agent.go +++ b/virtcontainers/noop_agent.go @@ -160,3 +160,8 @@ func (n *noopAgent) getVMPath(id string) string { func (n *noopAgent) getSharePath(id string) string { return "" } + +// reseedRNG is the Noop agent RND reseeder. It does nothing. +func (n *noopAgent) reseedRNG(data []byte) error { + return nil +} diff --git a/virtcontainers/noop_agent_test.go b/virtcontainers/noop_agent_test.go index 7b30d425c1..847997b202 100644 --- a/virtcontainers/noop_agent_test.go +++ b/virtcontainers/noop_agent_test.go @@ -209,3 +209,11 @@ func TestNoopAgentProcessListContainer(t *testing.T) { t.Fatal(err) } } + +func TestNoopAgentReseedRNG(t *testing.T) { + n := &noopAgent{} + err := n.reseedRNG([]byte{}) + if err != nil { + t.Fatal("reseedRNG failed") + } +} diff --git a/virtcontainers/vm.go b/virtcontainers/vm.go index 09c07d9f1d..aa42d80062 100644 --- a/virtcontainers/vm.go +++ b/virtcontainers/vm.go @@ -191,6 +191,26 @@ func (v *VM) OnlineCPUMemory() error { return err } +// ReseedRNG adds random entropy to guest random number generator +// and reseeds it. +func (v *VM) ReseedRNG() error { + v.logger().Infof("reseed guest random number generator") + urandomDev := "/dev/urandom" + data := make([]byte, 512) + f, err := os.OpenFile(urandomDev, os.O_RDONLY, 0) + if err != nil { + v.logger().WithError(err).Warn("fail to open %s", urandomDev) + return err + } + defer f.Close() + if _, err = f.Read(data); err != nil { + v.logger().WithError(err).Warn("fail to read %s", urandomDev) + return err + } + + return v.agent.reseedRNG(data) +} + func (v *VM) assignSandbox(s *Sandbox) error { // add vm symlinks // - link vm socket from sandbox dir (/run/vc/vm/sbid/) to vm dir (/run/vc/vm/vmid/) diff --git a/virtcontainers/vm_test.go b/virtcontainers/vm_test.go index 3031fc023d..15c16f8bae 100644 --- a/virtcontainers/vm_test.go +++ b/virtcontainers/vm_test.go @@ -50,6 +50,8 @@ func TestNewVM(t *testing.T) { assert.Nil(err) err = vm.OnlineCPUMemory() assert.Nil(err) + err = vm.ReseedRNG() + assert.Nil(err) // template VM config.HypervisorConfig.BootFromTemplate = true