newrelic_security 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  3. data/.github/ISSUE_TEMPLATE/enhancement.md +27 -0
  4. data/.github/actions/simplecov-report/LICENSE +22 -0
  5. data/.github/actions/simplecov-report/README.md +36 -0
  6. data/.github/actions/simplecov-report/__tests__/.keep +0 -0
  7. data/.github/actions/simplecov-report/__tests__/main.test.ts +3 -0
  8. data/.github/actions/simplecov-report/action.yml +25 -0
  9. data/.github/actions/simplecov-report/dist/index.js +10238 -0
  10. data/.github/actions/simplecov-report/dummy_coverage/.last_run.json +5 -0
  11. data/.github/actions/simplecov-report/jest.config.js +11 -0
  12. data/.github/actions/simplecov-report/package.json +51 -0
  13. data/.github/actions/simplecov-report/src/main.ts +54 -0
  14. data/.github/actions/simplecov-report/src/report.ts +28 -0
  15. data/.github/actions/simplecov-report/tsconfig.json +12 -0
  16. data/.github/workflows/pr_ci.yml +77 -0
  17. data/.github/workflows/release.yml +51 -0
  18. data/.github/workflows/repolinter.yml +31 -0
  19. data/.github/workflows/rubocop.yml +17 -0
  20. data/.github/workflows/scripts/rubygems-authenticate.py +13 -0
  21. data/.github/workflows/scripts/rubygems-publish.rb +33 -0
  22. data/.gitignore +72 -0
  23. data/.rubocop.yml +9 -0
  24. data/.rubocop_todo.yml +1414 -0
  25. data/.simplecov +16 -0
  26. data/CHANGELOG.md +69 -0
  27. data/CONTRIBUTING.md +22 -0
  28. data/Gemfile +6 -0
  29. data/Gemfile_test +58 -0
  30. data/LICENSE +43 -0
  31. data/README.md +133 -0
  32. data/README_agent.md +44 -0
  33. data/Rakefile +28 -0
  34. data/THIRD_PARTY_NOTICES.md +36 -0
  35. data/lib/newrelic_security/agent/agent.rb +109 -0
  36. data/lib/newrelic_security/agent/configuration/default_source.rb +8 -0
  37. data/lib/newrelic_security/agent/configuration/environment_source.rb +8 -0
  38. data/lib/newrelic_security/agent/configuration/manager.rb +178 -0
  39. data/lib/newrelic_security/agent/configuration/manual_source.rb +8 -0
  40. data/lib/newrelic_security/agent/configuration/server_source.rb +8 -0
  41. data/lib/newrelic_security/agent/configuration/yaml_source.rb +8 -0
  42. data/lib/newrelic_security/agent/control/app_info.rb +132 -0
  43. data/lib/newrelic_security/agent/control/application_url_mappings.rb +66 -0
  44. data/lib/newrelic_security/agent/control/collector.rb +117 -0
  45. data/lib/newrelic_security/agent/control/control_command.rb +117 -0
  46. data/lib/newrelic_security/agent/control/critical_message.rb +58 -0
  47. data/lib/newrelic_security/agent/control/event.rb +149 -0
  48. data/lib/newrelic_security/agent/control/event_counter.rb +28 -0
  49. data/lib/newrelic_security/agent/control/event_processor.rb +134 -0
  50. data/lib/newrelic_security/agent/control/event_stats.rb +26 -0
  51. data/lib/newrelic_security/agent/control/event_subscriber.rb +28 -0
  52. data/lib/newrelic_security/agent/control/exit_event.rb +38 -0
  53. data/lib/newrelic_security/agent/control/fuzz_request.rb +18 -0
  54. data/lib/newrelic_security/agent/control/grpc_context.rb +57 -0
  55. data/lib/newrelic_security/agent/control/health_check.rb +136 -0
  56. data/lib/newrelic_security/agent/control/http_context.rb +73 -0
  57. data/lib/newrelic_security/agent/control/iast_client.rb +151 -0
  58. data/lib/newrelic_security/agent/control/iast_data_transfer_request.rb +32 -0
  59. data/lib/newrelic_security/agent/control/reflected_xss.rb +258 -0
  60. data/lib/newrelic_security/agent/control/websocket_client.rb +131 -0
  61. data/lib/newrelic_security/agent/logging/init_logger.rb +91 -0
  62. data/lib/newrelic_security/agent/logging/logger.rb +92 -0
  63. data/lib/newrelic_security/agent/logging/null_logger.rb +21 -0
  64. data/lib/newrelic_security/agent/resources/cert.pem +50 -0
  65. data/lib/newrelic_security/agent/utils/agent_utils.rb +219 -0
  66. data/lib/newrelic_security/agent.rb +57 -0
  67. data/lib/newrelic_security/constants.rb +67 -0
  68. data/lib/newrelic_security/instrumentation-security/active_record/mysql2_adapter/chain.rb +70 -0
  69. data/lib/newrelic_security/instrumentation-security/active_record/mysql2_adapter/instrumentation.rb +187 -0
  70. data/lib/newrelic_security/instrumentation-security/active_record/mysql2_adapter/prepend.rb +54 -0
  71. data/lib/newrelic_security/instrumentation-security/active_record/postgresql_adapter/chain.rb +60 -0
  72. data/lib/newrelic_security/instrumentation-security/active_record/postgresql_adapter/instrumentation.rb +143 -0
  73. data/lib/newrelic_security/instrumentation-security/active_record/postgresql_adapter/prepend.rb +48 -0
  74. data/lib/newrelic_security/instrumentation-security/active_record/sqlite3_adapter/chain.rb +72 -0
  75. data/lib/newrelic_security/instrumentation-security/active_record/sqlite3_adapter/instrumentation.rb +187 -0
  76. data/lib/newrelic_security/instrumentation-security/active_record/sqlite3_adapter/prepend.rb +54 -0
  77. data/lib/newrelic_security/instrumentation-security/async-http/chain.rb +21 -0
  78. data/lib/newrelic_security/instrumentation-security/async-http/instrumentation.rb +46 -0
  79. data/lib/newrelic_security/instrumentation-security/async-http/prepend.rb +16 -0
  80. data/lib/newrelic_security/instrumentation-security/curb/chain.rb +26 -0
  81. data/lib/newrelic_security/instrumentation-security/curb/instrumentation.rb +52 -0
  82. data/lib/newrelic_security/instrumentation-security/curb/prepend.rb +18 -0
  83. data/lib/newrelic_security/instrumentation-security/dir/chain.rb +42 -0
  84. data/lib/newrelic_security/instrumentation-security/dir/instrumentation.rb +102 -0
  85. data/lib/newrelic_security/instrumentation-security/dir/prepend.rb +28 -0
  86. data/lib/newrelic_security/instrumentation-security/ethon/chain.rb +53 -0
  87. data/lib/newrelic_security/instrumentation-security/ethon/instrumentation.rb +122 -0
  88. data/lib/newrelic_security/instrumentation-security/ethon/prepend.rb +39 -0
  89. data/lib/newrelic_security/instrumentation-security/excon/chain.rb +23 -0
  90. data/lib/newrelic_security/instrumentation-security/excon/instrumentation.rb +44 -0
  91. data/lib/newrelic_security/instrumentation-security/excon/prepend.rb +17 -0
  92. data/lib/newrelic_security/instrumentation-security/file/chain.rb +34 -0
  93. data/lib/newrelic_security/instrumentation-security/file/instrumentation.rb +62 -0
  94. data/lib/newrelic_security/instrumentation-security/file/prepend.rb +22 -0
  95. data/lib/newrelic_security/instrumentation-security/grape/chain.rb +42 -0
  96. data/lib/newrelic_security/instrumentation-security/grape/instrumentation.rb +56 -0
  97. data/lib/newrelic_security/instrumentation-security/grape/prepend.rb +30 -0
  98. data/lib/newrelic_security/instrumentation-security/grpc/client/chain.rb +47 -0
  99. data/lib/newrelic_security/instrumentation-security/grpc/client/instrumentation.rb +37 -0
  100. data/lib/newrelic_security/instrumentation-security/grpc/client/prepend.rb +36 -0
  101. data/lib/newrelic_security/instrumentation-security/grpc/server/chain.rb +62 -0
  102. data/lib/newrelic_security/instrumentation-security/grpc/server/instrumentation.rb +65 -0
  103. data/lib/newrelic_security/instrumentation-security/grpc/server/prepend.rb +46 -0
  104. data/lib/newrelic_security/instrumentation-security/httpclient/chain.rb +30 -0
  105. data/lib/newrelic_security/instrumentation-security/httpclient/instrumentation.rb +82 -0
  106. data/lib/newrelic_security/instrumentation-security/httpclient/prepend.rb +22 -0
  107. data/lib/newrelic_security/instrumentation-security/httprb/chain.rb +21 -0
  108. data/lib/newrelic_security/instrumentation-security/httprb/instrumentation.rb +44 -0
  109. data/lib/newrelic_security/instrumentation-security/httprb/prepend.rb +16 -0
  110. data/lib/newrelic_security/instrumentation-security/httpx/chain.rb +23 -0
  111. data/lib/newrelic_security/instrumentation-security/httpx/instrumentation.rb +51 -0
  112. data/lib/newrelic_security/instrumentation-security/httpx/prepend.rb +18 -0
  113. data/lib/newrelic_security/instrumentation-security/instrumentation_loader.rb +50 -0
  114. data/lib/newrelic_security/instrumentation-security/instrumentation_utils.rb +165 -0
  115. data/lib/newrelic_security/instrumentation-security/io/chain.rb +113 -0
  116. data/lib/newrelic_security/instrumentation-security/io/instrumentation.rb +300 -0
  117. data/lib/newrelic_security/instrumentation-security/io/prepend.rb +86 -0
  118. data/lib/newrelic_security/instrumentation-security/kernel/chain.rb +65 -0
  119. data/lib/newrelic_security/instrumentation-security/kernel/instrumentation.rb +167 -0
  120. data/lib/newrelic_security/instrumentation-security/kernel/prepend.rb +50 -0
  121. data/lib/newrelic_security/instrumentation-security/mongo/chain.rb +106 -0
  122. data/lib/newrelic_security/instrumentation-security/mongo/instrumentation.rb +273 -0
  123. data/lib/newrelic_security/instrumentation-security/mongo/prepend.rb +77 -0
  124. data/lib/newrelic_security/instrumentation-security/mysql2/chain.rb +53 -0
  125. data/lib/newrelic_security/instrumentation-security/mysql2/instrumentation.rb +84 -0
  126. data/lib/newrelic_security/instrumentation-security/mysql2/prepend.rb +37 -0
  127. data/lib/newrelic_security/instrumentation-security/net_http/chain.rb +21 -0
  128. data/lib/newrelic_security/instrumentation-security/net_http/instrumentation.rb +60 -0
  129. data/lib/newrelic_security/instrumentation-security/net_http/prepend.rb +16 -0
  130. data/lib/newrelic_security/instrumentation-security/net_ldap/chain.rb +21 -0
  131. data/lib/newrelic_security/instrumentation-security/net_ldap/instrumentation.rb +42 -0
  132. data/lib/newrelic_security/instrumentation-security/net_ldap/prepend.rb +16 -0
  133. data/lib/newrelic_security/instrumentation-security/nokogiri/chain.rb +46 -0
  134. data/lib/newrelic_security/instrumentation-security/nokogiri/instrumentation.rb +36 -0
  135. data/lib/newrelic_security/instrumentation-security/nokogiri/prepend.rb +31 -0
  136. data/lib/newrelic_security/instrumentation-security/padrino/chain.rb +26 -0
  137. data/lib/newrelic_security/instrumentation-security/padrino/instrumentation.rb +42 -0
  138. data/lib/newrelic_security/instrumentation-security/padrino/prepend.rb +20 -0
  139. data/lib/newrelic_security/instrumentation-security/patron/chain.rb +23 -0
  140. data/lib/newrelic_security/instrumentation-security/patron/instrumentation.rb +50 -0
  141. data/lib/newrelic_security/instrumentation-security/patron/prepend.rb +18 -0
  142. data/lib/newrelic_security/instrumentation-security/pg/chain.rb +49 -0
  143. data/lib/newrelic_security/instrumentation-security/pg/instrumentation.rb +102 -0
  144. data/lib/newrelic_security/instrumentation-security/pg/prepend.rb +36 -0
  145. data/lib/newrelic_security/instrumentation-security/pty/chain.rb +31 -0
  146. data/lib/newrelic_security/instrumentation-security/pty/instrumentation.rb +52 -0
  147. data/lib/newrelic_security/instrumentation-security/pty/prepend.rb +22 -0
  148. data/lib/newrelic_security/instrumentation-security/rails/chain.rb +46 -0
  149. data/lib/newrelic_security/instrumentation-security/rails/instrumentation.rb +67 -0
  150. data/lib/newrelic_security/instrumentation-security/rails/prepend.rb +33 -0
  151. data/lib/newrelic_security/instrumentation-security/roda/chain.rb +22 -0
  152. data/lib/newrelic_security/instrumentation-security/roda/instrumentation.rb +41 -0
  153. data/lib/newrelic_security/instrumentation-security/roda/prepend.rb +16 -0
  154. data/lib/newrelic_security/instrumentation-security/sinatra/chain.rb +29 -0
  155. data/lib/newrelic_security/instrumentation-security/sinatra/instrumentation.rb +49 -0
  156. data/lib/newrelic_security/instrumentation-security/sinatra/prepend.rb +21 -0
  157. data/lib/newrelic_security/instrumentation-security/sqlite3/chain.rb +79 -0
  158. data/lib/newrelic_security/instrumentation-security/sqlite3/instrumentation.rb +164 -0
  159. data/lib/newrelic_security/instrumentation-security/sqlite3/prepend.rb +56 -0
  160. data/lib/newrelic_security/newrelic-security-api/api.rb +72 -0
  161. data/lib/newrelic_security/version.rb +5 -0
  162. data/lib/newrelic_security/websocket-client-simple/client.rb +128 -0
  163. data/lib/newrelic_security/websocket-client-simple/event_emitter.rb +72 -0
  164. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/error.rb +129 -0
  165. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/exception_handler.rb +32 -0
  166. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/base.rb +62 -0
  167. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/data.rb +49 -0
  168. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/base.rb +41 -0
  169. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler03.rb +224 -0
  170. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler04.rb +18 -0
  171. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler05.rb +15 -0
  172. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler07.rb +78 -0
  173. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler/handler75.rb +78 -0
  174. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/handler.rb +15 -0
  175. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/incoming/client.rb +17 -0
  176. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/incoming/server.rb +17 -0
  177. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/incoming.rb +52 -0
  178. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/outgoing/client.rb +17 -0
  179. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/outgoing/server.rb +17 -0
  180. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame/outgoing.rb +35 -0
  181. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/frame.rb +11 -0
  182. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/base.rb +142 -0
  183. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/client.rb +130 -0
  184. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/base.rb +49 -0
  185. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client.rb +32 -0
  186. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client01.rb +20 -0
  187. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client04.rb +63 -0
  188. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client11.rb +22 -0
  189. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client75.rb +39 -0
  190. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/client76.rb +105 -0
  191. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server.rb +10 -0
  192. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server04.rb +56 -0
  193. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server75.rb +40 -0
  194. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler/server76.rb +75 -0
  195. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/handler.rb +21 -0
  196. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake/server.rb +179 -0
  197. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/handshake.rb +10 -0
  198. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/nice_inspect.rb +12 -0
  199. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket/version.rb +5 -0
  200. data/lib/newrelic_security/websocket-client-simple/websocket-ruby/lib/websocket.rb +50 -0
  201. data/lib/newrelic_security.rb +6 -0
  202. data/lib/tasks/all.rb +8 -0
  203. data/lib/tasks/coverage_report.rake +27 -0
  204. data/newrelic_security.gemspec +51 -0
  205. metadata +342 -0
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+ require 'set'
3
+ require 'uri'
4
+
5
+ module NewRelic::Security
6
+ module Instrumentation
7
+ module InstrumentationUtils
8
+ extend self
9
+
10
+ OPEN_MODES = ::Set.new(%W[r rb])
11
+ APP_INTEGRITY_MODES = ::Set.new(%W[w w+ a a+ ab at r+ wb wt write binwrite])
12
+ DOT_DOT_SLASH = '../'
13
+ TMP_CACHE = '/tmp/cache'
14
+ FILTERED_SQL = ['PRAGMA foreign_keys = ON', #sqlite
15
+ 'COMMIT', #mysql
16
+ 'BEGIN', #mysql
17
+ 'PRAGMA', #sqlite
18
+ 'begin deferred transaction', #sqlite
19
+ 'commit transaction', #sqlite
20
+ 'SHOW TIME ZONE', #pg
21
+ 'SET' #pg
22
+ ]
23
+
24
+ def sql_filter_events?(sql_query)
25
+ FILTERED_SQL.each do |unwanted_sql|
26
+ if sql_query.start_with?(unwanted_sql)
27
+ NewRelic::Security::Agent.logger.debug "Filtered invalid SQL '#{sql_query}'"
28
+ return true
29
+ end
30
+ end if sql_query
31
+ return false
32
+ end
33
+
34
+ def in_app_dir?(fname, abs_path)
35
+ app_dir = NewRelic::Security::Agent.config[:app_root]
36
+ if app_dir == nil
37
+ return false
38
+ end
39
+ if abs_path.start_with?(app_dir)
40
+ return true
41
+ end
42
+ return false
43
+ end
44
+
45
+ def in_gem_dir?(fname, abs_path)
46
+ gem_dir = ::Gem.dir
47
+ if gem_dir == nil
48
+ return false
49
+ end
50
+ if abs_path.start_with?(gem_dir)
51
+ return true
52
+ end
53
+ return false
54
+ end
55
+
56
+ def in_tmp_cache_dir?(fname, abs_path)
57
+ app_dir = NewRelic::Security::Agent.config[:app_root]
58
+ if app_dir == nil
59
+ return false
60
+ end
61
+ if abs_path.start_with?(app_dir + TMP_CACHE)
62
+ return true
63
+ end
64
+ return false
65
+ end
66
+
67
+ def notify_app_integrity_open?(fname, abs_path, fmode)
68
+ if fname == nil || fmode == nil
69
+ # we cannot do the app integrity
70
+ NewRelic::Security::Agent.logger.debug "Invalid Args of 'open', app integrity check cannot be enforced \r\n"
71
+ NewRelic::Security::Agent.logger.debug "File Name #{fname} fmode #{fmode}"
72
+ return false
73
+ end
74
+ #check whether the file path is in the App root directory
75
+ #check whether file exists for 'w','w+','a','a+' mode because file is created
76
+ #for these modes if it doesn't present.
77
+ #If file already exists , then no need to send the app integrity event to IC
78
+ if in_app_dir?(fname, abs_path) && !in_tmp_cache_dir?(fname, abs_path) && APP_INTEGRITY_MODES.include?(fmode)
79
+ return true
80
+ end
81
+ return false
82
+ end
83
+
84
+ def notify_app_integrity_delete?(fnames)
85
+ #delete api argument is an array of file names/name
86
+ #get the root directory
87
+ #check whether file present in the application root
88
+ #check whether the file exists, if not remove it from the args
89
+ if fnames == nil || fnames.empty?
90
+ NewRelic::Security::Agent.logger.debug "Invalid Args of 'delete', app integrity check cannot be enforced \r\n"
91
+ return false
92
+ end
93
+ NewRelic::Security::Agent.logger.debug "File Names #{fnames}"
94
+ fnames.each do |fname|
95
+ return true if in_app_dir?(fname, ::File.expand_path(fname)) && !in_tmp_cache_dir?(fname, ::File.expand_path(fname))
96
+ end
97
+ return false
98
+ end
99
+
100
+ def open_filter?(fname, abs_path, fmode)
101
+ if fname == nil || fmode == nil
102
+ NewRelic::Security::Agent.logger.debug "Invalid Args of 'open', filter cannot be enforced \r\n"
103
+ NewRelic::Security::Agent.logger.debug "File Name #{fname} fmode #{fmode}"
104
+ return false
105
+ end
106
+ if (in_app_dir?(fname, abs_path) || in_gem_dir?(fname, abs_path)) && OPEN_MODES.include?(fmode)
107
+ if !fname.include?(DOT_DOT_SLASH) #check for any path traversal
108
+ return true #filter it , if path is in app_dir and there is no "../" segment
109
+ end
110
+ end
111
+ return false
112
+ end
113
+
114
+ #for now ,any file read in the application directory event is filtered out.
115
+ def read_filter?(fname, abs_path)
116
+ if fname == nil
117
+ NewRelic::Security::Agent.logger.debug "Invalid Args of 'read', filter cannot be enforced \r\n"
118
+ NewRelic::Security::Agent.logger.debug "File Name #{fname} "
119
+ return false
120
+ end
121
+ if in_app_dir?(fname, abs_path) || in_gem_dir?(fname, abs_path)
122
+ if !fname.include?(DOT_DOT_SLASH) #check for any path traversal
123
+ return true #filter it , if path is in app_dir and there is no "../" segment
124
+ end
125
+ end
126
+ return false
127
+ end
128
+
129
+ def add_tracing_data(req, event)
130
+ req[NR_CSEC_TRACING_DATA] = "#{event.httpRequest[:headers][NR_CSEC_TRACING_DATA]}#{NewRelic::Security::Agent.config[:uuid]}/#{event.apiId}/#{event.id};"
131
+ req[NR_CSEC_FUZZ_REQUEST_ID] = event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID] if event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID]
132
+ end
133
+
134
+ def append_tracing_data(req, event)
135
+ req = [] if req.nil?
136
+ req.append([NR_CSEC_TRACING_DATA, "#{event.httpRequest[:headers][NR_CSEC_TRACING_DATA]}#{NewRelic::Security::Agent.config[:uuid]}/#{event.apiId}/#{event.id};"])
137
+ req.append([NR_CSEC_FUZZ_REQUEST_ID, event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID]]) if event.httpRequest[:headers][NR_CSEC_FUZZ_REQUEST_ID]
138
+ end
139
+
140
+ def parse_uri(uri_string)
141
+ ::URI.parse(uri_string)
142
+ rescue
143
+ return nil
144
+ end
145
+
146
+ def parse_typhoeus_request(request)
147
+ ob = {}
148
+ ob[:Method] = request.options[:method].nil? ? :get : request.options[:method]
149
+ ob[:URI] = request.base_url
150
+ ob[:Body] = request.options[:body]
151
+ ob[:Headers] = request.options[:headers]
152
+ uri_parsed = parse_uri(request.base_url)
153
+ if !uri_parsed.nil?
154
+ ob[:scheme] = uri_parsed.scheme
155
+ ob[:host] = uri_parsed.host
156
+ ob[:port] = uri_parsed.port
157
+ ob[:path] = uri_parsed.path
158
+ ob[:query] = uri_parsed.query
159
+ end
160
+ ob
161
+ end
162
+
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,113 @@
1
+ module NewRelic::Security
2
+ module Instrumentation
3
+ module IO
4
+ module Chain
5
+ def self.instrument!
6
+ ::IO.class_eval do
7
+ class << self
8
+ include NewRelic::Security::Instrumentation::IO
9
+
10
+ alias_method :open_without_security, :open
11
+
12
+ if RUBY_VERSION < '2.7.0'
13
+ def open(var1, var2 = "r", *var3, &var4)
14
+ return open_without_security(var1, var2, *var3, &var4) if var1.to_s.include?(LOG_FILE_NAME)
15
+ retval = nil
16
+ event = open_on_enter(var1, var2) { retval = open_without_security(var1, var2, *var3, &var4) }
17
+ open_on_exit(event) { return retval }
18
+ end
19
+ else
20
+ def open(*args, **kwargs, &block)
21
+ return open_without_security(*args, **kwargs, &block) if args[0].to_s.include?(LOG_FILE_NAME)
22
+ retval = nil
23
+ event = open_on_enter(*args) { retval = open_without_security(*args, **kwargs, &block) }
24
+ open_on_exit(event) { return retval }
25
+ end
26
+ end
27
+
28
+ alias_method :read_without_security, :read
29
+
30
+ def read(*var, **kwargs)
31
+ retval = nil
32
+ event = read_on_enter(*var) { retval = read_without_security(*var, **kwargs) }
33
+ read_on_exit(event, retval) { return retval }
34
+ end
35
+
36
+ alias_method :binread_without_security, :binread
37
+
38
+ def binread(*var)
39
+ retval = nil
40
+ event = binread_on_enter(*var) { retval = binread_without_security(*var) }
41
+ binread_on_exit(event, retval) { return retval }
42
+ end
43
+
44
+ alias_method :readlines_without_security, :readlines
45
+
46
+ def readlines(*var, **kwargs)
47
+ retval = nil
48
+ event = readlines_on_enter(*var) { retval = readlines_without_security(*var, **kwargs) }
49
+ readlines_on_exit(event, retval) { return retval }
50
+ end
51
+
52
+ alias_method :new_without_security, :new
53
+
54
+ if RUBY_VERSION < '2.7.0'
55
+ def new(*var)
56
+ retval = nil
57
+ event = new_on_enter(*var) { retval = new_without_security(*var) }
58
+ new_on_exit(event) { return retval }
59
+ end
60
+ else
61
+ def new(*var, **kwargs)
62
+ retval = nil
63
+ event = new_on_enter(*var) { retval = new_without_security(*var, **kwargs) }
64
+ new_on_exit(event) { return retval }
65
+ end
66
+ end
67
+
68
+ alias_method :sysopen_without_security, :sysopen
69
+
70
+ def sysopen(*var)
71
+ retval = nil
72
+ event = sysopen_on_enter(*var) { retval = sysopen_without_security(*var) }
73
+ sysopen_on_exit(event, retval, *var) { return retval }
74
+ end
75
+
76
+ alias_method :foreach_without_security, :foreach
77
+
78
+ def foreach(*var)
79
+ retval = nil
80
+ event = foreach_on_enter(*var) { retval = foreach_without_security(*var) }
81
+ foreach_on_exit(event, retval) { return retval }
82
+ end
83
+
84
+ alias_method :write_without_security, :write
85
+
86
+ def write(*var, **kwargs)
87
+ retval = nil
88
+ event = write_on_enter(*var, **kwargs) { retval = write_without_security(*var) }
89
+ write_on_exit(event, retval) { return retval }
90
+ end
91
+
92
+ alias_method :binwrite_without_security, :binwrite
93
+
94
+ def binwrite(*var)
95
+ retval = nil
96
+ event = binwrite_on_enter(*var) { retval = binwrite_without_security(*var) }
97
+ binwrite_on_exit(event, retval) { return retval }
98
+ end
99
+
100
+ alias_method :popen_without_security, :popen
101
+
102
+ def popen(*var)
103
+ retval = nil
104
+ event = popen_on_enter(*var) { retval = popen_without_security(*var) }
105
+ popen_on_exit(event) { return retval }
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,300 @@
1
+ require_relative 'prepend'
2
+ require_relative 'chain'
3
+
4
+ module NewRelic::Security
5
+ module Instrumentation
6
+ module IO
7
+
8
+ def open_on_enter(*args)
9
+ event = nil
10
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
11
+ fname = args[0].to_s
12
+ if args[0].is_a? Integer
13
+ fname = NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[args[0].object_id.to_s].to_s if NewRelic::Security::Agent::Control::HTTPContext.get_context && NewRelic::Security::Agent::Control::HTTPContext.get_context.cache.key?(args[0].object_id.to_s)
14
+ else
15
+ fname = ::File.path(args[0]) if args[0] #some times it is 'String' or 'Path' class
16
+ end
17
+ abs_path = ::File.expand_path(fname)
18
+ fmode = args[1]
19
+ event_category = NewRelic::Security::Instrumentation::InstrumentationUtils::OPEN_MODES.include?(fmode) ? READ : WRITE
20
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.notify_app_integrity_open?(fname, abs_path, fmode)
21
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_INTEGRITY, [fname], event_category)
22
+ else
23
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
24
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{fname} #{fmode}"
25
+ else
26
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], event_category)
27
+ end
28
+ end
29
+ rescue => exception
30
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
31
+ ensure
32
+ yield
33
+ return event
34
+ end
35
+
36
+ def open_on_exit(event)
37
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
38
+ NewRelic::Security::Agent::Utils.create_exit_event(event)
39
+ rescue => exception
40
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
41
+ ensure
42
+ yield
43
+ end
44
+
45
+ def new_on_enter(*var)
46
+ event = nil
47
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
48
+ fname = var[0].to_s
49
+ if var[0].is_a? Integer
50
+ fname = NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[var[0].object_id.to_s].to_s if NewRelic::Security::Agent::Control::HTTPContext.get_context && NewRelic::Security::Agent::Control::HTTPContext.get_context.cache.key?(var[0].object_id.to_s)
51
+ else
52
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
53
+ end
54
+ abs_path = ::File.expand_path(fname)
55
+ fmode = var[1] if var[1]
56
+ event_category = NewRelic::Security::Instrumentation::InstrumentationUtils::OPEN_MODES.include?(fmode) ? READ : WRITE
57
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.notify_app_integrity_open?(fname, abs_path, fmode)
58
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_INTEGRITY, [fname], event_category)
59
+ else
60
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
61
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{fname} #{fmode}"
62
+ else
63
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], event_category)
64
+ end
65
+ end
66
+ rescue => exception
67
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
68
+ ensure
69
+ yield
70
+ return event
71
+ end
72
+
73
+ def new_on_exit(event)
74
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
75
+ NewRelic::Security::Agent::Utils.create_exit_event(event)
76
+ rescue => exception
77
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
78
+ ensure
79
+ yield
80
+ end
81
+
82
+ def sysopen_on_enter(*var)
83
+ event = nil
84
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
85
+ rescue => exception
86
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
87
+ ensure
88
+ yield
89
+ return event
90
+ end
91
+
92
+ def sysopen_on_exit(event, retval, *var)
93
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
94
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
95
+ NewRelic::Security::Agent::Control::HTTPContext.get_context.cache[retval.object_id.to_s] = fname if NewRelic::Security::Agent::Control::HTTPContext.get_context
96
+ rescue => exception
97
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
98
+ ensure
99
+ yield
100
+ end
101
+
102
+ def read_on_enter(*var)
103
+ event = nil
104
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
105
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
106
+ abs_path = ::File.expand_path(fname)
107
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
108
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{var}"
109
+ else
110
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], READ)
111
+ end
112
+ rescue => exception
113
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
114
+ ensure
115
+ yield
116
+ return event
117
+ end
118
+
119
+ def read_on_exit(event, retval)
120
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
121
+ NewRelic::Security::Agent::Utils.create_exit_event(event) if retval.is_a?(String)
122
+ rescue => exception
123
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
124
+ ensure
125
+ yield
126
+ end
127
+
128
+ def binread_on_enter(*var)
129
+ event = nil
130
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
131
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
132
+ abs_path = ::File.expand_path(fname)
133
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
134
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{var}"
135
+ else
136
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], READ)
137
+ end
138
+ rescue => exception
139
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
140
+ ensure
141
+ yield
142
+ return event
143
+ end
144
+
145
+ def binread_on_exit(event, retval)
146
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
147
+ NewRelic::Security::Agent::Utils.create_exit_event(event) if retval.is_a?(String)
148
+ rescue => exception
149
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
150
+ ensure
151
+ yield
152
+ end
153
+
154
+ def readlines_on_enter(*var)
155
+ event = nil
156
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
157
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
158
+ abs_path = ::File.expand_path(fname)
159
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
160
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{var}"
161
+ else
162
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], READ)
163
+ end
164
+ rescue => exception
165
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
166
+ ensure
167
+ yield
168
+ return event
169
+ end
170
+
171
+ def readlines_on_exit(event, retval)
172
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
173
+ NewRelic::Security::Agent::Utils.create_exit_event(event) if retval.is_a?(Array)
174
+ rescue => exception
175
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
176
+ ensure
177
+ yield
178
+ end
179
+
180
+ def foreach_on_enter(*var)
181
+ event = nil
182
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
183
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
184
+ abs_path = ::File.expand_path(fname)
185
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
186
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{var}"
187
+ else
188
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], READ)
189
+ end
190
+ rescue => exception
191
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
192
+ ensure
193
+ yield
194
+ return event
195
+ end
196
+
197
+ def foreach_on_exit(event, retval)
198
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
199
+ NewRelic::Security::Agent::Utils.create_exit_event(event) if retval.is_a?(NilClass) || retval.is_a?(Enumerator)
200
+ rescue => exception
201
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
202
+ ensure
203
+ yield
204
+ end
205
+
206
+ def write_on_enter(*var, **kwargs)
207
+ event = nil
208
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
209
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
210
+ abs_path = ::File.expand_path(fname)
211
+ fmode = kwargs.has_key?(:mode) ? kwargs[:mode] : WRITE
212
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.notify_app_integrity_open?(fname, abs_path, fmode)
213
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_INTEGRITY, [fname], WRITE)
214
+ else
215
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
216
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{fname} #{fmode}"
217
+ else
218
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], WRITE)
219
+ end
220
+ end
221
+ rescue => exception
222
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
223
+ ensure
224
+ yield
225
+ return event
226
+ end
227
+
228
+ def write_on_exit(event, retval)
229
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
230
+ NewRelic::Security::Agent::Utils.create_exit_event(event) if retval.is_a?(Integer)
231
+ rescue => exception
232
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
233
+ ensure
234
+ yield
235
+ end
236
+
237
+ def binwrite_on_enter(*var)
238
+ event = nil
239
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
240
+ fname = ::File.path(var[0]) #some times it is 'String' or 'Path' class
241
+ abs_path = ::File.expand_path(fname)
242
+ fmode = BINWRITE
243
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.notify_app_integrity_open?(fname, abs_path, fmode)
244
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_INTEGRITY, [fname], WRITE)
245
+ else
246
+ if NewRelic::Security::Instrumentation::InstrumentationUtils.read_filter?(fname, abs_path)
247
+ NewRelic::Security::Agent.logger.debug "Filtered because File name exist in filtered list #{self.class}.#{__method__} Args:: #{fname} #{fmode}"
248
+ else
249
+ event = NewRelic::Security::Agent::Control::Collector.collect(FILE_OPERATION, [fname], WRITE)
250
+ end
251
+ end
252
+ rescue => exception
253
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
254
+ ensure
255
+ yield
256
+ return event
257
+ end
258
+
259
+ def binwrite_on_exit(event, retval)
260
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
261
+ NewRelic::Security::Agent::Utils.create_exit_event(event) if retval.is_a?(Integer)
262
+ rescue => exception
263
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
264
+ ensure
265
+ yield
266
+ end
267
+
268
+ def popen_on_enter(*var)
269
+ event = nil
270
+ NewRelic::Security::Agent.logger.debug "OnEnter : #{self.class}.#{__method__}"
271
+ ic_args = []
272
+ var.each { |arg|
273
+ if arg.is_a? String
274
+ ic_args << arg
275
+ elsif arg.is_a? Array
276
+ ic_args << arg.join(" ")
277
+ end
278
+ }
279
+ event = NewRelic::Security::Agent::Control::Collector.collect(SYSTEM_COMMAND, ic_args)
280
+ rescue => exception
281
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
282
+ ensure
283
+ yield
284
+ return event
285
+ end
286
+
287
+ def popen_on_exit(event)
288
+ NewRelic::Security::Agent.logger.debug "OnExit : #{self.class}.#{__method__}"
289
+ NewRelic::Security::Agent::Utils.create_exit_event(event)
290
+ rescue => exception
291
+ NewRelic::Security::Agent.logger.error "Exception in hook in #{self.class}.#{__method__}, #{exception.inspect}, #{exception.backtrace}"
292
+ ensure
293
+ yield
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ NewRelic::Security::Instrumentation::InstrumentationLoader.install_instrumentation(:io, ::IO.singleton_class, ::NewRelic::Security::Instrumentation::IO)
300
+
@@ -0,0 +1,86 @@
1
+ module NewRelic::Security
2
+ module Instrumentation
3
+ module IO
4
+ module Prepend
5
+ include NewRelic::Security::Instrumentation::IO
6
+ if RUBY_VERSION < '2.7.0'
7
+ def open(var1, var2 = "r", *var3, &var4)
8
+ return super if var1.to_s.include?(LOG_FILE_NAME)
9
+ retval = nil
10
+ event = open_on_enter(var1, var2) { retval = super }
11
+ open_on_exit(event) { return retval }
12
+ end
13
+ else
14
+ def open(*args, **kwargs, &block)
15
+ return super if args[0].to_s.include?(LOG_FILE_NAME)
16
+ retval = nil
17
+ event = open_on_enter(*args) { retval = super }
18
+ open_on_exit(event) { return retval }
19
+ end
20
+ end
21
+
22
+ def read(*var, **kwargs)
23
+ retval = nil
24
+ event = read_on_enter(*var) { retval = super }
25
+ read_on_exit(event, retval) { return retval }
26
+ end
27
+
28
+ def binread(*var)
29
+ retval = nil
30
+ event = binread_on_enter(*var) { retval = super }
31
+ binread_on_exit(event, retval) { return retval }
32
+ end
33
+
34
+ def readlines(*var, **kwargs)
35
+ retval = nil
36
+ event = readlines_on_enter(*var) { retval = super }
37
+ readlines_on_exit(event, retval) { return retval }
38
+ end
39
+
40
+ if RUBY_VERSION < '2.7.0'
41
+ def new(*var)
42
+ retval = nil
43
+ event = new_on_enter(*var) { retval = super }
44
+ new_on_exit(event) { return retval }
45
+ end
46
+ else
47
+ def new(*var, **kwargs)
48
+ retval = nil
49
+ event = new_on_enter(*var) { retval = super }
50
+ new_on_exit(event) { return retval }
51
+ end
52
+ end
53
+
54
+ def sysopen(*var)
55
+ retval = nil
56
+ event = sysopen_on_enter(*var) { retval = super }
57
+ sysopen_on_exit(event, retval, *var) { return retval }
58
+ end
59
+
60
+ def foreach(*var)
61
+ retval = nil
62
+ event = foreach_on_enter(*var) { retval = super }
63
+ foreach_on_exit(event, retval) { return retval }
64
+ end
65
+
66
+ def write(*var, **kwargs)
67
+ retval = nil
68
+ event = write_on_enter(*var, **kwargs) { retval = super }
69
+ write_on_exit(event, retval) { return retval }
70
+ end
71
+
72
+ def binwrite(*var)
73
+ retval = nil
74
+ event = binwrite_on_enter(*var) { retval = super }
75
+ binwrite_on_exit(event, retval) { return retval }
76
+ end
77
+
78
+ def popen(*var)
79
+ retval = nil
80
+ event = popen_on_enter(*var) { retval = super }
81
+ popen_on_exit(event) { return retval }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end