bpf.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. * Copyright (c) 2020, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package parameters
  20. import (
  21. "encoding/json"
  22. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  23. "golang.org/x/net/bpf"
  24. )
  25. // BPFProgramSpec specifies a BPF program. The Name field is informational and
  26. // may be used for logging. The Instructions field is a list of values which
  27. // map to golang.org/x/net/bpf.Instruction and which can be marshaled.
  28. type BPFProgramSpec struct {
  29. Name string
  30. Instructions []BPFInstructionSpec
  31. }
  32. // Validate validates a BPF program spec.
  33. func (s *BPFProgramSpec) Validate() error {
  34. if s.Name == "" {
  35. return errors.TraceNew("missing name")
  36. }
  37. if len(s.Instructions) < 1 {
  38. return errors.TraceNew("missing instructions")
  39. }
  40. _, err := s.Assemble()
  41. return errors.Trace(err)
  42. }
  43. // Assemble converts the Instructions to equivilent
  44. // golang.org/x/net/bpf.Instruction values and assembles these into raw
  45. // instructions suitable for attaching to a socket.
  46. func (s *BPFProgramSpec) Assemble() ([]bpf.RawInstruction, error) {
  47. if len(s.Instructions) == 0 {
  48. return nil, errors.TraceNew("empty program")
  49. }
  50. program := make([]bpf.Instruction, len(s.Instructions))
  51. for i, instructionSpec := range s.Instructions {
  52. instruction, err := instructionSpec.GetInstruction()
  53. if err != nil {
  54. return nil, errors.Trace(err)
  55. }
  56. program[i] = instruction
  57. }
  58. raw, err := bpf.Assemble(program)
  59. if err != nil {
  60. return nil, errors.Trace(err)
  61. }
  62. return raw, nil
  63. }
  64. // BPFInstructionSpec represents a golang.org/x/net/bpf.Instruction and can be
  65. // marshaled.
  66. type BPFInstructionSpec struct {
  67. Op string
  68. Args json.RawMessage
  69. }
  70. // GetInstruction coverts a BPFInstructionSpec to the equivilent
  71. // golang.org/x/net/bpf.Instruction.
  72. func (s *BPFInstructionSpec) GetInstruction() (bpf.Instruction, error) {
  73. switch s.Op {
  74. case "ALUOpConstant":
  75. var instruction bpf.ALUOpConstant
  76. err := json.Unmarshal(s.Args, &instruction)
  77. if err != nil {
  78. return nil, errors.Trace(err)
  79. }
  80. return instruction, nil
  81. case "ALUOpX":
  82. var instruction bpf.ALUOpX
  83. err := json.Unmarshal(s.Args, &instruction)
  84. if err != nil {
  85. return nil, errors.Trace(err)
  86. }
  87. return instruction, nil
  88. case "Jump":
  89. var instruction bpf.Jump
  90. err := json.Unmarshal(s.Args, &instruction)
  91. if err != nil {
  92. return nil, errors.Trace(err)
  93. }
  94. return instruction, nil
  95. case "JumpIf":
  96. var instruction bpf.JumpIf
  97. err := json.Unmarshal(s.Args, &instruction)
  98. if err != nil {
  99. return nil, errors.Trace(err)
  100. }
  101. return instruction, nil
  102. case "JumpIfX":
  103. var instruction bpf.JumpIfX
  104. err := json.Unmarshal(s.Args, &instruction)
  105. if err != nil {
  106. return nil, errors.Trace(err)
  107. }
  108. return instruction, nil
  109. case "LoadAbsolute":
  110. var instruction bpf.LoadAbsolute
  111. err := json.Unmarshal(s.Args, &instruction)
  112. if err != nil {
  113. return nil, errors.Trace(err)
  114. }
  115. return instruction, nil
  116. case "LoadConstant":
  117. var instruction bpf.LoadConstant
  118. err := json.Unmarshal(s.Args, &instruction)
  119. if err != nil {
  120. return nil, errors.Trace(err)
  121. }
  122. return instruction, nil
  123. case "LoadExtension":
  124. var instruction bpf.LoadExtension
  125. err := json.Unmarshal(s.Args, &instruction)
  126. if err != nil {
  127. return nil, errors.Trace(err)
  128. }
  129. return instruction, nil
  130. case "LoadIndirect":
  131. var instruction bpf.LoadIndirect
  132. err := json.Unmarshal(s.Args, &instruction)
  133. if err != nil {
  134. return nil, errors.Trace(err)
  135. }
  136. return instruction, nil
  137. case "LoadMemShift":
  138. var instruction bpf.LoadMemShift
  139. err := json.Unmarshal(s.Args, &instruction)
  140. if err != nil {
  141. return nil, errors.Trace(err)
  142. }
  143. return instruction, nil
  144. case "LoadScratch":
  145. var instruction bpf.LoadScratch
  146. err := json.Unmarshal(s.Args, &instruction)
  147. if err != nil {
  148. return nil, errors.Trace(err)
  149. }
  150. return instruction, nil
  151. case "NegateA":
  152. var instruction bpf.NegateA
  153. err := json.Unmarshal(s.Args, &instruction)
  154. if err != nil {
  155. return nil, errors.Trace(err)
  156. }
  157. return instruction, nil
  158. case "RetA":
  159. var instruction bpf.RetA
  160. err := json.Unmarshal(s.Args, &instruction)
  161. if err != nil {
  162. return nil, errors.Trace(err)
  163. }
  164. return instruction, nil
  165. case "RetConstant":
  166. var instruction bpf.RetConstant
  167. err := json.Unmarshal(s.Args, &instruction)
  168. if err != nil {
  169. return nil, errors.Trace(err)
  170. }
  171. return instruction, nil
  172. case "StoreScratch":
  173. var instruction bpf.StoreScratch
  174. err := json.Unmarshal(s.Args, &instruction)
  175. if err != nil {
  176. return nil, errors.Trace(err)
  177. }
  178. return instruction, nil
  179. case "TAX":
  180. var instruction bpf.TAX
  181. err := json.Unmarshal(s.Args, &instruction)
  182. if err != nil {
  183. return nil, errors.Trace(err)
  184. }
  185. return instruction, nil
  186. case "TXA":
  187. var instruction bpf.TXA
  188. err := json.Unmarshal(s.Args, &instruction)
  189. if err != nil {
  190. return nil, errors.Trace(err)
  191. }
  192. return instruction, nil
  193. }
  194. return nil, errors.Tracef("unknown bpf instruction: %s", s.Op)
  195. }