@@ -186,10 +186,32 @@ func (manager) Start(ctx context.Context, bparams *bootapi.BootstrapParams) (_ *
186186 cmd .ExtraFiles = append (cmd .ExtraFiles , s .f )
187187 }
188188
189- cloneMntNs (ctx , cmd )
189+ userns := cloneMntNs (ctx , cmd )
190190
191- if err := cmd .Start (); err != nil {
192- return nil , err
191+ if startErr := cmd .Start (); startErr != nil {
192+ if ! userns {
193+ return nil , startErr
194+ }
195+ // clone(CLONE_NEWUSER) can fail for reasons not covered by the
196+ // proactive AppArmor check — e.g. seccomp filters, LSM policies,
197+ // or EACCES from the child's capability recomputation when
198+ // inherited socket fds cross the user namespace boundary after
199+ // exec. Retry without namespace isolation rather than failing
200+ // the container start.
201+ //
202+ // Note: we cannot log here — during "start" the logger output
203+ // goes to stderr which containerd captures as part of the
204+ // bootstrap response (CombinedOutput), corrupting the JSON.
205+ cmd , err = newCommand (ctx , id , bparams .ContainerdGrpcAddress , bparams .ContainerdTtrpcAddress , debug )
206+ if err != nil {
207+ return nil , err
208+ }
209+ for _ , s := range sockets {
210+ cmd .ExtraFiles = append (cmd .ExtraFiles , s .f )
211+ }
212+ if err := cmd .Start (); err != nil {
213+ return nil , fmt .Errorf ("retry without userns failed: %w (original error: %v)" , err , startErr )
214+ }
193215 }
194216
195217 defer func () {
0 commit comments