sync.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package libcontainer
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "github.com/opencontainers/runc/libcontainer/utils"
  8. )
  9. type syncType string
  10. // Constants that are used for synchronisation between the parent and child
  11. // during container setup. They come in pairs (with procError being a generic
  12. // response which is followed by an &initError).
  13. //
  14. // [ child ] <-> [ parent ]
  15. //
  16. // procHooks --> [run hooks]
  17. // <-- procResume
  18. //
  19. // procReady --> [final setup]
  20. // <-- procRun
  21. //
  22. // procSeccomp --> [pick up seccomp fd with pidfd_getfd()]
  23. // <-- procSeccompDone
  24. const (
  25. procError syncType = "procError"
  26. procReady syncType = "procReady"
  27. procRun syncType = "procRun"
  28. procHooks syncType = "procHooks"
  29. procResume syncType = "procResume"
  30. procSeccomp syncType = "procSeccomp"
  31. procSeccompDone syncType = "procSeccompDone"
  32. )
  33. type syncT struct {
  34. Type syncType `json:"type"`
  35. Fd int `json:"fd"`
  36. }
  37. // initError is used to wrap errors for passing them via JSON,
  38. // as encoding/json can't unmarshal into error type.
  39. type initError struct {
  40. Message string `json:"message,omitempty"`
  41. }
  42. func (i initError) Error() string {
  43. return i.Message
  44. }
  45. // writeSync is used to write to a synchronisation pipe. An error is returned
  46. // if there was a problem writing the payload.
  47. func writeSync(pipe io.Writer, sync syncType) error {
  48. return writeSyncWithFd(pipe, sync, -1)
  49. }
  50. // writeSyncWithFd is used to write to a synchronisation pipe. An error is
  51. // returned if there was a problem writing the payload.
  52. func writeSyncWithFd(pipe io.Writer, sync syncType, fd int) error {
  53. if err := utils.WriteJSON(pipe, syncT{sync, fd}); err != nil {
  54. return fmt.Errorf("writing syncT %q: %w", string(sync), err)
  55. }
  56. return nil
  57. }
  58. // readSync is used to read from a synchronisation pipe. An error is returned
  59. // if we got an initError, the pipe was closed, or we got an unexpected flag.
  60. func readSync(pipe io.Reader, expected syncType) error {
  61. var procSync syncT
  62. if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
  63. if errors.Is(err, io.EOF) {
  64. return errors.New("parent closed synchronisation channel")
  65. }
  66. return fmt.Errorf("failed reading error from parent: %w", err)
  67. }
  68. if procSync.Type == procError {
  69. var ierr initError
  70. if err := json.NewDecoder(pipe).Decode(&ierr); err != nil {
  71. return fmt.Errorf("failed reading error from parent: %w", err)
  72. }
  73. return &ierr
  74. }
  75. if procSync.Type != expected {
  76. return errors.New("invalid synchronisation flag from parent")
  77. }
  78. return nil
  79. }
  80. // parseSync runs the given callback function on each syncT received from the
  81. // child. It will return once io.EOF is returned from the given pipe.
  82. func parseSync(pipe io.Reader, fn func(*syncT) error) error {
  83. dec := json.NewDecoder(pipe)
  84. for {
  85. var sync syncT
  86. if err := dec.Decode(&sync); err != nil {
  87. if errors.Is(err, io.EOF) {
  88. break
  89. }
  90. return err
  91. }
  92. // We handle this case outside fn for cleanliness reasons.
  93. var ierr *initError
  94. if sync.Type == procError {
  95. if err := dec.Decode(&ierr); err != nil && !errors.Is(err, io.EOF) {
  96. return fmt.Errorf("error decoding proc error from init: %w", err)
  97. }
  98. if ierr != nil {
  99. return ierr
  100. }
  101. // Programmer error.
  102. panic("No error following JSON procError payload.")
  103. }
  104. if err := fn(&sync); err != nil {
  105. return err
  106. }
  107. }
  108. return nil
  109. }