99 "fmt"
1010 "os"
1111 "path/filepath"
12- "strings"
1312 "time"
1413
1514 "github.com/Microsoft/hcsshim/hcn"
@@ -19,15 +18,12 @@ import (
1918 hcsschema "github.com/Microsoft/hcsshim/internal/hcs/schema2"
2019 "github.com/Microsoft/hcsshim/internal/log"
2120 "github.com/Microsoft/hcsshim/internal/oc"
22- "github.com/Microsoft/hcsshim/internal/oci"
2321 "github.com/Microsoft/hcsshim/internal/protocol/guestrequest"
2422 "github.com/Microsoft/hcsshim/internal/protocol/guestresource"
2523 "github.com/Microsoft/hcsshim/internal/windevice"
26- "github.com/Microsoft/hcsshim/pkg/annotations"
2724 "github.com/Microsoft/hcsshim/pkg/cimfs"
2825 "github.com/Microsoft/hcsshim/pkg/securitypolicy"
2926 "github.com/pkg/errors"
30- "golang.org/x/sys/windows"
3127)
3228
3329const (
@@ -89,11 +85,19 @@ func (b *Bridge) createContainer(req *request) (err error) {
8985 if err != nil {
9086 return fmt .Errorf ("CreateContainer operation is denied by policy: %w" , err )
9187 }
88+
89+ if err := b .hostState .SetupSecurityContextDir (ctx , & spec ); err != nil {
90+ return err
91+ }
92+ commandLine := len (spec .Process .Args ) > 0
9293 c := & Container {
93- id : containerID ,
94- spec : spec ,
95- processes : make (map [uint32 ]* containerProcess ),
94+ id : containerID ,
95+ spec : spec ,
96+ processes : make (map [uint32 ]* containerProcess ),
97+ commandLine : commandLine ,
98+ commandLineExec : false ,
9699 }
100+
97101 log .G (ctx ).Tracef ("Adding ContainerID: %v" , containerID )
98102 if err := b .hostState .AddContainer (req .ctx , containerID , c ); err != nil {
99103 log .G (ctx ).Tracef ("Container exists in the map." )
@@ -104,49 +108,6 @@ func (b *Bridge) createContainer(req *request) (err error) {
104108 b .hostState .RemoveContainer (ctx , containerID )
105109 }
106110 }(err )
107- // Write security policy, signed UVM reference and host AMD certificate to
108- // container's rootfs, so that application and sidecar containers can have
109- // access to it. The security policy is required by containers which need to
110- // extract init-time claims found in the security policy. The directory path
111- // containing the files is exposed via UVM_SECURITY_CONTEXT_DIR env var.
112- // It may be an error to have a security policy but not expose it to the
113- // container as in that case it can never be checked as correct by a verifier.
114- if oci .ParseAnnotationsBool (ctx , spec .Annotations , annotations .WCOWSecurityPolicyEnv , true ) {
115- encodedPolicy := b .hostState .securityPolicyEnforcer .EncodedSecurityPolicy ()
116- hostAMDCert := spec .Annotations [annotations .WCOWHostAMDCertificate ]
117- if len (encodedPolicy ) > 0 || len (hostAMDCert ) > 0 || len (b .hostState .uvmReferenceInfo ) > 0 {
118- // Use os.MkdirTemp to make sure that the directory is unique.
119- securityContextDir , err := os .MkdirTemp (spec .Root .Path , securitypolicy .SecurityContextDirTemplate )
120- if err != nil {
121- return fmt .Errorf ("failed to create security context directory: %w" , err )
122- }
123- // Make sure that files inside directory are readable
124- if err := os .Chmod (securityContextDir , 0755 ); err != nil {
125- return fmt .Errorf ("failed to chmod security context directory: %w" , err )
126- }
127-
128- if len (encodedPolicy ) > 0 {
129- if err := writeFileInDir (securityContextDir , securitypolicy .PolicyFilename , []byte (encodedPolicy ), 0777 ); err != nil {
130- return fmt .Errorf ("failed to write security policy: %w" , err )
131- }
132- }
133- if len (b .hostState .uvmReferenceInfo ) > 0 {
134- if err := writeFileInDir (securityContextDir , securitypolicy .ReferenceInfoFilename , []byte (b .hostState .uvmReferenceInfo ), 0777 ); err != nil {
135- return fmt .Errorf ("failed to write UVM reference info: %w" , err )
136- }
137- }
138-
139- if len (hostAMDCert ) > 0 {
140- if err := writeFileInDir (securityContextDir , securitypolicy .HostAMDCertFilename , []byte (hostAMDCert ), 0777 ); err != nil {
141- return fmt .Errorf ("failed to write host AMD certificate: %w" , err )
142- }
143- }
144-
145- containerCtxDir := fmt .Sprintf ("/%s" , filepath .Base (securityContextDir ))
146- secCtxEnv := fmt .Sprintf ("UVM_SECURITY_CONTEXT_DIR=%s" , containerCtxDir )
147- spec .Process .Env = append (spec .Process .Env , secCtxEnv )
148- }
149- }
150111
151112 // Strip the spec field
152113 hostedSystemBytes , err := json .Marshal (cwcowHostedSystem )
@@ -265,15 +226,6 @@ func (b *Bridge) shutdownForced(req *request) (err error) {
265226 return nil
266227}
267228
268- // escapeArgs makes a Windows-style escaped command line from a set of arguments.
269- func escapeArgs (args []string ) string {
270- escapedArgs := make ([]string , len (args ))
271- for i , a := range args {
272- escapedArgs [i ] = windows .EscapeArg (a )
273- }
274- return strings .Join (escapedArgs , " " )
275- }
276-
277229func (b * Bridge ) executeProcess (req * request ) (err error ) {
278230 _ , span := oc .StartSpan (req .ctx , "sidecar::executeProcess" )
279231 defer span .End ()
@@ -313,15 +265,19 @@ func (b *Bridge) executeProcess(req *request) (err error) {
313265 return fmt .Errorf ("failed to get created container: %w" , err )
314266 }
315267
316- // if this is an exec of Container command line, then it's already enforced
317- // during container creation, hence skip it here
318- containerCommandLine := escapeArgs (c .spec .Process .Args )
319- if processParams .CommandLine != containerCommandLine {
268+ c .processesMutex .Lock ()
269+ isCreateExec := c .commandLine && ! c .commandLineExec
270+ if isCreateExec {
271+ // if this is an exec of Container command line, then it's already enforced
272+ // during container creation, hence skip it here
273+ c .commandLineExec = true
320274
275+ }
276+ c .processesMutex .Unlock ()
277+ if ! isCreateExec {
321278 user := securitypolicy.IDName {
322279 Name : processParams .User ,
323280 }
324-
325281 log .G (req .ctx ).Tracef ("Enforcing policy on exec in container" )
326282 _ , _ , _ , err = b .hostState .securityPolicyEnforcer .
327283 EnforceExecInContainerPolicyV2 (
@@ -339,9 +295,10 @@ func (b *Bridge) executeProcess(req *request) (err error) {
339295 }
340296 headerID := req .header .ID
341297
342- // initiate process ID
298+ // initiate exec process response channel
299+ procRespCh := make (chan * prot.ContainerExecuteProcessResponse , 1 )
343300 b .pendingMu .Lock ()
344- b .pending [headerID ] = nil // nil means not yet received
301+ b .pending [headerID ] = procRespCh
345302 b .pendingMu .Unlock ()
346303
347304 defer func () {
@@ -354,13 +311,8 @@ func (b *Bridge) executeProcess(req *request) (err error) {
354311 b .forwardRequestToGcs (req )
355312
356313 // fetch the process ID from response
357- deadline := time .Now ().Add (5 * time .Second )
358- for time .Now ().Before (deadline ) {
359- log .G (req .ctx ).Tracef ("waiting for exec resp" )
360- b .pendingMu .Lock ()
361- resp := b .pending [headerID ]
362- b .pendingMu .Unlock ()
363-
314+ select {
315+ case resp := <- procRespCh :
364316 // capture the Process details, so that we can later enforce
365317 // on the allowed signals on the Process
366318 if resp != nil {
@@ -374,10 +326,11 @@ func (b *Bridge) executeProcess(req *request) (err error) {
374326 }
375327 return nil
376328 }
377- time .Sleep (10 * time .Millisecond ) // backoff
329+ // Channel closed or received nil, treat as error
330+ return errors .New ("received nil exec response" )
331+ case <- time .After (5 * time .Second ):
332+ return errors .New ("timed out waiting for exec response" )
378333 }
379-
380- return errors .Wrap (err , "timedout waiting for exec response" )
381334 }
382335 return nil
383336}
0 commit comments