@@ -15,10 +15,12 @@ import (
15
15
"syscall"
16
16
"time"
17
17
18
+ "github.com/containers/libpod/pkg/lookup"
18
19
"github.com/containers/libpod/pkg/rootless"
19
20
"github.com/containers/libpod/pkg/util"
20
21
"github.com/coreos/go-systemd/activation"
21
22
"github.com/cri-o/ocicni/pkg/ocicni"
23
+ "github.com/docker/docker/daemon/caps"
22
24
spec "github.com/opencontainers/runtime-spec/specs-go"
23
25
"github.com/opencontainers/selinux/go-selinux"
24
26
"github.com/opencontainers/selinux/go-selinux/label"
@@ -735,18 +737,23 @@ func (r *OCIRuntime) unpauseContainer(ctr *Container) error {
735
737
// TODO: Add --detach support
736
738
// TODO: Convert to use conmon
737
739
// TODO: add --pid-file and use that to generate exec session tracking
738
- func (r * OCIRuntime ) execContainer (c * Container , cmd , capAdd , env []string , tty bool , cwd , user , sessionID string ) (* exec.Cmd , error ) {
740
+ func (r * OCIRuntime ) execContainer (c * Container , cmd , env []string , tty bool , cwd , user , sessionID string , privileged bool ) (* exec.Cmd , string , error ) {
739
741
if len (cmd ) == 0 {
740
- return nil , errors .Wrapf (ErrInvalidArg , "must provide a command to execute" )
742
+ return nil , "" , errors .Wrapf (ErrInvalidArg , "must provide a command to execute" )
741
743
}
742
744
743
745
if sessionID == "" {
744
- return nil , errors .Wrapf (ErrEmptyID , "must provide a session ID for exec" )
746
+ return nil , "" , errors .Wrapf (ErrEmptyID , "must provide a session ID for exec" )
745
747
}
746
748
747
749
runtimeDir , err := util .GetRootlessRuntimeDir ()
748
750
if err != nil {
749
- return nil , err
751
+ return nil , "" , err
752
+ }
753
+
754
+ processFile , err := prepareProcessExec (c , cmd , env , tty , cwd , user , sessionID , privileged )
755
+ if err != nil {
756
+ return nil , "" , err
750
757
}
751
758
752
759
args := []string {}
@@ -756,34 +763,14 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
756
763
757
764
args = append (args , "exec" )
758
765
759
- if cwd != "" {
760
- args = append (args , "--cwd" , cwd )
761
- }
766
+ args = append (args , "--process" , processFile )
762
767
763
768
args = append (args , "--pid-file" , c .execPidPath (sessionID ))
764
769
765
- if tty {
766
- args = append (args , "--tty" )
767
- } else {
768
- args = append (args , "--tty=false" )
769
- }
770
-
771
- if user != "" {
772
- args = append (args , "--user" , user )
773
- }
774
-
775
770
if c .config .Spec .Process .NoNewPrivileges {
776
771
args = append (args , "--no-new-privs" )
777
772
}
778
773
779
- for _ , cap := range capAdd {
780
- args = append (args , "--cap" , cap )
781
- }
782
-
783
- for _ , envVar := range env {
784
- args = append (args , "--env" , envVar )
785
- }
786
-
787
774
// Append container ID and command
788
775
args = append (args , c .ID ())
789
776
args = append (args , cmd ... )
@@ -797,10 +784,10 @@ func (r *OCIRuntime) execContainer(c *Container, cmd, capAdd, env []string, tty
797
784
execCmd .Env = append (execCmd .Env , fmt .Sprintf ("XDG_RUNTIME_DIR=%s" , runtimeDir ))
798
785
799
786
if err := execCmd .Start (); err != nil {
800
- return nil , errors .Wrapf (err , "cannot start container %s" , c .ID ())
787
+ return nil , "" , errors .Wrapf (err , "cannot start container %s" , c .ID ())
801
788
}
802
789
803
- return execCmd , nil
790
+ return execCmd , processFile , nil
804
791
}
805
792
806
793
// execStopContainer stops all active exec sessions in a container
@@ -892,3 +879,110 @@ func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckp
892
879
args = append (args , ctr .ID ())
893
880
return utils .ExecCmdWithStdStreams (os .Stdin , os .Stdout , os .Stderr , nil , r .path , args ... )
894
881
}
882
+
883
+ // prepareProcessExec returns the path of the process.json used in runc exec -p.
884
+ // Returns path to the created exec process file. This will need to be removed
885
+ // by the caller when they're done, best effort.
886
+ func prepareProcessExec (c * Container , cmd , env []string , tty bool , cwd , user , sessionID string , privileged bool ) (string , error ) {
887
+ filename := filepath .Join (c .bundlePath (), fmt .Sprintf ("exec-process-%s" , sessionID ))
888
+ f , err := os .OpenFile (filename , os .O_CREATE | os .O_WRONLY , 0600 )
889
+ if err != nil {
890
+ return "" , err
891
+ }
892
+ defer f .Close ()
893
+
894
+ pspec := c .config .Spec .Process
895
+ pspec .SelinuxLabel = c .config .ProcessLabel
896
+ pspec .Args = cmd
897
+ // We need to default this to false else it will inherit terminal as true
898
+ // from the container.
899
+ pspec .Terminal = false
900
+ if tty {
901
+ pspec .Terminal = true
902
+ }
903
+ if len (env ) > 0 {
904
+ pspec .Env = append (pspec .Env , env ... )
905
+ }
906
+
907
+ if cwd != "" {
908
+ pspec .Cwd = cwd
909
+
910
+ }
911
+
912
+ var addGroups []string
913
+ var sgids []uint32
914
+
915
+ // if the user is empty, we should inherit the user that the container is currently running with
916
+ if user == "" {
917
+ user = c .config .User
918
+ addGroups = c .config .Groups
919
+ }
920
+
921
+ execUser , err := lookup .GetUserGroupInfo (c .state .Mountpoint , user , nil )
922
+ if err != nil {
923
+ return "" , err
924
+ }
925
+
926
+ if len (addGroups ) > 0 {
927
+ sgids , err = lookup .GetContainerGroups (addGroups , c .state .Mountpoint , nil )
928
+ if err != nil {
929
+ return "" , errors .Wrapf (err , "error looking up supplemental groups for container %s exec session %s" , c .ID (), sessionID )
930
+ }
931
+ }
932
+
933
+ // If user was set, look it up in the container to get a UID to use on
934
+ // the host
935
+ if user != "" || len (sgids ) > 0 {
936
+ if user != "" {
937
+ for _ , sgid := range execUser .Sgids {
938
+ sgids = append (sgids , uint32 (sgid ))
939
+ }
940
+ }
941
+ processUser := spec.User {
942
+ UID : uint32 (execUser .Uid ),
943
+ GID : uint32 (execUser .Gid ),
944
+ AdditionalGids : sgids ,
945
+ }
946
+
947
+ pspec .User = processUser
948
+ }
949
+
950
+ allCaps := caps .GetAllCapabilities ()
951
+ pspec .Capabilities .Effective = []string {}
952
+ if privileged {
953
+ pspec .Capabilities .Bounding = allCaps
954
+ } else {
955
+ pspec .Capabilities .Bounding = []string {}
956
+ }
957
+ pspec .Capabilities .Inheritable = pspec .Capabilities .Bounding
958
+ if execUser .Uid == 0 {
959
+ pspec .Capabilities .Effective = pspec .Capabilities .Bounding
960
+ pspec .Capabilities .Permitted = pspec .Capabilities .Bounding
961
+ pspec .Capabilities .Ambient = pspec .Capabilities .Bounding
962
+ } else {
963
+ pspec .Capabilities .Permitted = pspec .Capabilities .Effective
964
+ pspec .Capabilities .Ambient = pspec .Capabilities .Effective
965
+ }
966
+
967
+ hasHomeSet := false
968
+ for _ , s := range pspec .Env {
969
+ if strings .HasPrefix (s , "HOME=" ) {
970
+ hasHomeSet = true
971
+ break
972
+ }
973
+ }
974
+ if ! hasHomeSet {
975
+ pspec .Env = append (pspec .Env , fmt .Sprintf ("HOME=%s" , execUser .Home ))
976
+ }
977
+
978
+ processJSON , err := json .Marshal (pspec )
979
+ if err != nil {
980
+ return "" , err
981
+ }
982
+
983
+ if err := ioutil .WriteFile (filename , processJSON , 0644 ); err != nil {
984
+ return "" , err
985
+ }
986
+
987
+ return filename , nil
988
+ }
0 commit comments