tcell_agent 1.1.12 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (169) hide show
  1. checksums.yaml +5 -5
  2. data/bin/tcell_agent +45 -137
  3. data/lib/tcell_agent.rb +12 -14
  4. data/lib/tcell_agent/agent.rb +108 -97
  5. data/lib/tcell_agent/agent/route_manager.rb +0 -16
  6. data/lib/tcell_agent/agent/static_agent.rb +9 -30
  7. data/lib/tcell_agent/config_initializer.rb +66 -0
  8. data/lib/tcell_agent/configuration.rb +69 -345
  9. data/lib/tcell_agent/hooks/login_fraud.rb +30 -33
  10. data/lib/tcell_agent/instrument_servers.rb +23 -0
  11. data/lib/tcell_agent/instrumentation.rb +12 -10
  12. data/lib/tcell_agent/instrumentation/cmdi.rb +29 -25
  13. data/lib/tcell_agent/instrumentation/lfi.rb +84 -0
  14. data/lib/tcell_agent/instrumentation/monkey_patches/file.rb +25 -0
  15. data/lib/tcell_agent/instrumentation/monkey_patches/io.rb +131 -0
  16. data/lib/tcell_agent/instrumentation/monkey_patches/kernel.rb +102 -0
  17. data/lib/tcell_agent/logger.rb +49 -114
  18. data/lib/tcell_agent/patches.rb +6 -7
  19. data/lib/tcell_agent/policies/appfirewall_policy.rb +26 -0
  20. data/lib/tcell_agent/policies/command_injection_policy.rb +28 -0
  21. data/lib/tcell_agent/policies/dataloss_policy.rb +44 -44
  22. data/lib/tcell_agent/policies/headers_policy.rb +25 -0
  23. data/lib/tcell_agent/policies/http_redirect_policy.rb +13 -79
  24. data/lib/tcell_agent/policies/js_agent_policy.rb +27 -0
  25. data/lib/tcell_agent/policies/local_file_access.rb +28 -0
  26. data/lib/tcell_agent/policies/login_policy.rb +43 -0
  27. data/lib/tcell_agent/policies/patches_policy.rb +27 -0
  28. data/lib/tcell_agent/policies/policies_manager.rb +68 -0
  29. data/lib/tcell_agent/policies/policy_polling.rb +58 -0
  30. data/lib/tcell_agent/policies/policy_types.rb +14 -0
  31. data/lib/tcell_agent/policies/system_enablements.rb +27 -0
  32. data/lib/tcell_agent/rails/auth/authlogic.rb +46 -75
  33. data/lib/tcell_agent/rails/auth/authlogic_helper.rb +20 -0
  34. data/lib/tcell_agent/rails/auth/devise.rb +100 -105
  35. data/lib/tcell_agent/rails/auth/devise_helper.rb +29 -0
  36. data/lib/tcell_agent/rails/auth/doorkeeper.rb +62 -76
  37. data/lib/tcell_agent/{userinfo.rb → rails/auth/userinfo.rb} +0 -0
  38. data/lib/tcell_agent/rails/csrf_exception.rb +2 -10
  39. data/lib/tcell_agent/rails/dlp.rb +35 -23
  40. data/lib/tcell_agent/rails/dlp_handler.rb +1 -2
  41. data/lib/tcell_agent/rails/js_agent_insert.rb +12 -13
  42. data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +4 -25
  43. data/lib/tcell_agent/rails/middleware/context_middleware.rb +2 -12
  44. data/lib/tcell_agent/rails/middleware/global_middleware.rb +1 -2
  45. data/lib/tcell_agent/rails/middleware/headers_middleware.rb +14 -34
  46. data/lib/tcell_agent/{rails.rb → rails/railties/tcell_agent_railties.rb} +11 -16
  47. data/lib/tcell_agent/rails/railties/tcell_agent_unicorn_railties.rb +8 -0
  48. data/lib/tcell_agent/rails/routes.rb +10 -12
  49. data/lib/tcell_agent/rails/routes/grape.rb +4 -14
  50. data/lib/tcell_agent/rails/routes/route_id.rb +3 -1
  51. data/lib/tcell_agent/rails/settings_reporter.rb +23 -36
  52. data/lib/tcell_agent/rails/tcell_body_proxy.rb +5 -4
  53. data/lib/tcell_agent/rust/agent_config.rb +60 -0
  54. data/lib/tcell_agent/rust/{libtcellagent-alpine-1.3.2.so → libtcellagent-5.0.2.dylib} +0 -0
  55. data/lib/tcell_agent/rust/{libtcellagent-1.3.2.so → libtcellagent-5.0.2.so} +0 -0
  56. data/lib/tcell_agent/rust/libtcellagent-alpine-5.0.2.so +0 -0
  57. data/lib/tcell_agent/rust/models.rb +6 -52
  58. data/lib/tcell_agent/rust/native_agent.rb +549 -0
  59. data/lib/tcell_agent/rust/native_agent_response.rb +42 -0
  60. data/lib/tcell_agent/rust/native_library.rb +69 -0
  61. data/lib/tcell_agent/rust/tcellagent-5.0.2.dll +0 -0
  62. data/lib/tcell_agent/sensor_events/agent_setting_event.rb +12 -0
  63. data/lib/tcell_agent/sensor_events/{app_config.rb → app_config_setting_event.rb} +0 -6
  64. data/lib/tcell_agent/sensor_events/dlp.rb +2 -6
  65. data/lib/tcell_agent/sensor_events/sensor.rb +0 -62
  66. data/lib/tcell_agent/sensor_events/server_agent.rb +13 -18
  67. data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +0 -108
  68. data/lib/tcell_agent/sensor_events/util/utils.rb +0 -2
  69. data/lib/tcell_agent/servers/passenger.rb +1 -28
  70. data/lib/tcell_agent/servers/puma.rb +3 -21
  71. data/lib/tcell_agent/servers/rails_server.rb +1 -2
  72. data/lib/tcell_agent/servers/thin.rb +2 -2
  73. data/lib/tcell_agent/servers/unicorn.rb +19 -80
  74. data/lib/tcell_agent/servers/webrick.rb +1 -2
  75. data/lib/tcell_agent/settings_reporter.rb +11 -90
  76. data/lib/tcell_agent/sinatra.rb +14 -16
  77. data/lib/tcell_agent/tcell_context.rb +40 -14
  78. data/lib/tcell_agent/utils/headers.rb +14 -0
  79. data/lib/tcell_agent/version.rb +1 -1
  80. data/spec/lib/tcell_agent/configuration_spec.rb +55 -346
  81. data/spec/lib/tcell_agent/hooks/login_fraud_spec.rb +46 -173
  82. data/spec/lib/tcell_agent/instrumentation/cmdi/io_cmdi_spec.rb +504 -0
  83. data/spec/lib/tcell_agent/instrumentation/cmdi/kernel_cmdi_spec.rb +435 -0
  84. data/spec/lib/tcell_agent/instrumentation/cmdi_spec.rb +201 -0
  85. data/spec/lib/tcell_agent/instrumentation/lfi/file_lfi_spec.rb +326 -0
  86. data/spec/lib/tcell_agent/instrumentation/lfi/io_lfi_spec.rb +562 -0
  87. data/spec/lib/tcell_agent/instrumentation/lfi/kernel_lfi_spec.rb +264 -0
  88. data/spec/lib/tcell_agent/instrumentation/lfi_spec.rb +150 -0
  89. data/spec/lib/tcell_agent/patches_spec.rb +25 -43
  90. data/spec/lib/tcell_agent/policies/appfirewall_policy_spec.rb +183 -0
  91. data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +57 -0
  92. data/spec/lib/tcell_agent/policies/command_injection_policy_spec.rb +84 -773
  93. data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +161 -0
  94. data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +9 -9
  95. data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +243 -198
  96. data/spec/lib/tcell_agent/policies/js_agent_policy_spec.rb +75 -0
  97. data/spec/lib/tcell_agent/policies/login_policy_spec.rb +165 -33
  98. data/spec/lib/tcell_agent/policies/patches_policy_spec.rb +84 -277
  99. data/spec/lib/tcell_agent/policies/policies_manager_spec.rb +104 -0
  100. data/spec/lib/tcell_agent/policies/policy_polling_spec.rb +6 -0
  101. data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +56 -0
  102. data/spec/lib/tcell_agent/rails/csrf_exception_spec.rb +9 -18
  103. data/spec/lib/tcell_agent/rails/js_agent_insert_spec.rb +13 -30
  104. data/spec/lib/tcell_agent/rails/logger_spec.rb +27 -7
  105. data/spec/lib/tcell_agent/rails/middleware/tcell_body_proxy_spec.rb +17 -12
  106. data/spec/lib/tcell_agent/rails/routes/routes_spec.rb +14 -14
  107. data/spec/lib/tcell_agent/rust/agent_config_spec.rb +27 -0
  108. data/spec/lib/tcell_agent/sensor_events/util/sanitizer_utilities_spec.rb +0 -35
  109. data/spec/lib/tcell_agent/settings_reporter_spec.rb +56 -155
  110. data/spec/spec_helper.rb +1 -1
  111. data/spec/support/builders.rb +103 -0
  112. data/spec/support/force_logger_mocking.rb +38 -0
  113. data/spec/support/resources/lfi_sample_file.txt +2 -0
  114. data/spec/support/static_agent_overrides.rb +0 -15
  115. metadata +72 -83
  116. data/lib/tcell_agent/agent/event_processor.rb +0 -326
  117. data/lib/tcell_agent/agent/fork_pipe_manager.rb +0 -113
  118. data/lib/tcell_agent/agent/policy_manager.rb +0 -219
  119. data/lib/tcell_agent/agent/policy_types.rb +0 -30
  120. data/lib/tcell_agent/api.rb +0 -91
  121. data/lib/tcell_agent/appsensor/injections_reporter.rb +0 -24
  122. data/lib/tcell_agent/authlogic.rb +0 -26
  123. data/lib/tcell_agent/config/child_process_events.rb +0 -8
  124. data/lib/tcell_agent/config/unknown_options.rb +0 -123
  125. data/lib/tcell_agent/devise.rb +0 -35
  126. data/lib/tcell_agent/instrumentation/cmdi/backtick.rb +0 -10
  127. data/lib/tcell_agent/instrumentation/cmdi/exec.rb +0 -14
  128. data/lib/tcell_agent/instrumentation/cmdi/popen.rb +0 -28
  129. data/lib/tcell_agent/instrumentation/cmdi/spawn.rb +0 -11
  130. data/lib/tcell_agent/instrumentation/cmdi/system.rb +0 -11
  131. data/lib/tcell_agent/policies/http_tx_policy.rb +0 -60
  132. data/lib/tcell_agent/policies/login_fraud_policy.rb +0 -45
  133. data/lib/tcell_agent/policies/rust_policies.rb +0 -110
  134. data/lib/tcell_agent/rails/on_start.rb +0 -41
  135. data/lib/tcell_agent/rust/libtcellagent-1.3.2.dylib +0 -0
  136. data/lib/tcell_agent/rust/tcellagent-1.3.2.dll +0 -0
  137. data/lib/tcell_agent/rust/whisperer.rb +0 -308
  138. data/lib/tcell_agent/sensor_events/appsensor_event.rb +0 -52
  139. data/lib/tcell_agent/sensor_events/appsensor_meta_event.rb +0 -45
  140. data/lib/tcell_agent/sensor_events/command_injection.rb +0 -75
  141. data/lib/tcell_agent/sensor_events/honeytokens.rb +0 -16
  142. data/lib/tcell_agent/sensor_events/login_fraud.rb +0 -60
  143. data/lib/tcell_agent/sensor_events/metrics.rb +0 -123
  144. data/lib/tcell_agent/sensor_events/patches.rb +0 -21
  145. data/lib/tcell_agent/start_background_thread.rb +0 -55
  146. data/lib/tcell_agent/system_info.rb +0 -11
  147. data/lib/tcell_agent/utils/io.rb +0 -38
  148. data/lib/tcell_agent/utils/passwords.rb +0 -28
  149. data/lib/tcell_agent/utils/queue_with_timeout.rb +0 -142
  150. data/spec/lib/tcell_agent/agent/fork_pipe_manager_spec.rb +0 -100
  151. data/spec/lib/tcell_agent/agent/policy_manager_spec.rb +0 -535
  152. data/spec/lib/tcell_agent/agent/static_agent_spec.rb +0 -133
  153. data/spec/lib/tcell_agent/api/api_spec.rb +0 -39
  154. data/spec/lib/tcell_agent/appsensor/injections_reporter_spec.rb +0 -187
  155. data/spec/lib/tcell_agent/cmdi_spec.rb +0 -736
  156. data/spec/lib/tcell_agent/config/unknown_options_spec.rb +0 -213
  157. data/spec/lib/tcell_agent/instrumentation_spec.rb +0 -225
  158. data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +0 -517
  159. data/spec/lib/tcell_agent/policies/http_tx_policy_spec.rb +0 -22
  160. data/spec/lib/tcell_agent/rails/middleware/appsensor_middleware_spec.rb +0 -293
  161. data/spec/lib/tcell_agent/rails/middleware/dlp_middleware_spec.rb +0 -198
  162. data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +0 -180
  163. data/spec/lib/tcell_agent/rails/middleware/redirect_middleware_spec.rb +0 -116
  164. data/spec/lib/tcell_agent/rust/models_spec.rb +0 -120
  165. data/spec/lib/tcell_agent/rust/whisperer_spec.rb +0 -704
  166. data/spec/lib/tcell_agent/sensor_events/appsensor_meta_event_spec.rb +0 -45
  167. data/spec/lib/tcell_agent/sensor_events/sessions_metric_spec.rb +0 -272
  168. data/spec/lib/tcell_agent/utils/bounded_queue_spec.rb +0 -52
  169. data/spec/lib/tcell_agent/utils/passwords_spec.rb +0 -143
@@ -0,0 +1,326 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+
4
+ describe 'File' do
5
+ before(:all) do
6
+ native_agent = double('native_agent')
7
+ @local_files_policy = TCellAgent::Policies::LocalFileInclusion.new(
8
+ native_agent, {}
9
+ )
10
+ @system_enablements_policy = TCellAgent::Policies::SystemEnablements.new(
11
+ native_agent, {}
12
+ )
13
+ @filename = get_test_resource_path('lfi_sample_file.txt')
14
+ @file_contents = "This is line one.\nThis is line two.\n"
15
+ @new_file_name = '/tmp/' + SecureRandom.uuid
16
+ end
17
+
18
+ describe '.new' do
19
+ context 'empty path' do
20
+ it 'should raise an error' do
21
+ expect do
22
+ File.new
23
+ end.to raise_error(ArgumentError)
24
+ expect do
25
+ File.new(nil)
26
+ end.to raise_error(TypeError)
27
+ expect do
28
+ File.new('')
29
+ end.to raise_error(Errno::ENOENT)
30
+ end
31
+ end
32
+ context 'with a non-existent file' do
33
+ context 'with a directory not blocked for read/write' do
34
+ before(:each) do
35
+ expect(TCellAgent).to receive(:policy).with(
36
+ TCellAgent::PolicyTypes::LFI
37
+ ).and_return(@local_files_policy)
38
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
39
+ end
40
+ context 'with a filename and mode r' do
41
+ it 'should raise an ERRNO::ENOENT error' do
42
+ expect do
43
+ File.new(@new_file_name, 'r')
44
+ end.to raise_error(Errno::ENOENT)
45
+ end
46
+ end
47
+ context 'with a filename and mode w' do
48
+ it 'should create the file' do
49
+ File.new(@new_file_name, 'w')
50
+
51
+ expect(File.exist?(@new_file_name)).to be_truthy
52
+ File.delete(@new_file_name)
53
+ end
54
+ end
55
+ context 'with a filename and write mode and file permissions 644' do
56
+ it 'should create the file with the correct permissions' do
57
+ File.new(@new_file_name, 'w', 0o644)
58
+
59
+ expect(File.exist?(@new_file_name)).to be_truthy
60
+ expect(File.stat(@new_file_name).mode.to_s(8)[3..5]).to eq('644')
61
+ File.delete(@new_file_name)
62
+ end
63
+ end
64
+ context 'with a filename and write mode and file permissions 755' do
65
+ it 'should create the file with the correct permissions' do
66
+ File.new(@new_file_name, 'w', 0o755)
67
+
68
+ expect(File.exist?(@new_file_name)).to be_truthy
69
+ expect(File.stat(@new_file_name).mode.to_s(8)[3..5]).to eq('755')
70
+ File.delete(@new_file_name)
71
+ end
72
+ end
73
+ context 'with a filename and write mode and file permissions 777' do
74
+ it 'should create the file with permissions 755' do
75
+ File.new(@new_file_name, 'w', 0o777)
76
+
77
+ expect(File.exist?(@new_file_name)).to be_truthy
78
+ expect(File.stat(@new_file_name).mode.to_s(8)[3..5]).to eq('755')
79
+ File.delete(@new_file_name)
80
+ end
81
+ end
82
+ end
83
+ context 'with a filename blocked for read/write' do
84
+ before(:each) do
85
+ expect(TCellAgent).to receive(:policy).with(
86
+ TCellAgent::PolicyTypes::LFI
87
+ ).and_return(@local_files_policy)
88
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
89
+ end
90
+ context 'with a filename and write mode' do
91
+ it 'should raise an IOError' do
92
+ expect do
93
+ File.new(@new_file_name, 'w')
94
+ end.to raise_error(IOError)
95
+ end
96
+ end
97
+ context 'with a filename and write mode and file permissions 644' do
98
+ it 'should raise an IOError' do
99
+ expect do
100
+ File.new(@new_file_name, 'w', 644)
101
+ end.to raise_error(IOError)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ context 'with an existing file' do
107
+ context 'with a file not blocked for read/write' do
108
+ before(:each) do
109
+ expect(TCellAgent).to receive(:policy).with(
110
+ TCellAgent::PolicyTypes::LFI
111
+ ).and_return(@local_files_policy)
112
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
113
+ end
114
+ context 'with a filename' do
115
+ it 'should still be able to read the file' do
116
+ result = File.new(@filename).read
117
+ expect(result).to eq @file_contents
118
+ end
119
+ end
120
+ context 'with a filename and mode r' do
121
+ it 'should still be able to read the file' do
122
+ result = File.new(@filename, 'r').read
123
+ expect(result).to eq @file_contents
124
+ end
125
+ end
126
+ context 'with a filenname and mode w' do
127
+ it 'should still be able to write to a file' do
128
+ file = File.new('/dev/null', 'w')
129
+ expect(file.write('dummy message')).to eq 13
130
+ end
131
+ end
132
+ context 'with a filenname and mode a' do
133
+ it 'should still be able to write to a file' do
134
+ file = File.new('/dev/null', 'a')
135
+ expect(file.write('dummy message')).to eq 13
136
+ end
137
+ end
138
+ end
139
+ context 'with a file blocked for read/write' do
140
+ before(:each) do
141
+ expect(TCellAgent).to receive(:policy).with(
142
+ TCellAgent::PolicyTypes::LFI
143
+ ).and_return(@local_files_policy)
144
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
145
+ end
146
+ context 'with a filename' do
147
+ it 'should not be able to read the file' do
148
+ expect do
149
+ File.new(@filename)
150
+ end.to raise_error(IOError)
151
+ end
152
+ end
153
+ context 'with a filename and mode r' do
154
+ it 'should not be able to read the file' do
155
+ expect do
156
+ File.new(@filename, 'r')
157
+ end.to raise_error(IOError)
158
+ end
159
+ end
160
+ context 'with a filename and mode w' do
161
+ it 'should not be able to write to the file' do
162
+ expect do
163
+ File.new('/dev/null', 'w')
164
+ end.to raise_error(IOError)
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ describe '.open' do
172
+ context 'empty path' do
173
+ it 'should raise an error' do
174
+ expect do
175
+ File.open
176
+ end.to raise_error(ArgumentError)
177
+ expect do
178
+ File.open(nil)
179
+ end.to raise_error(TypeError)
180
+ expect do
181
+ File.open('')
182
+ end.to raise_error(Errno::ENOENT)
183
+ end
184
+ end
185
+ context 'with a non-existent file' do
186
+ before(:all) do
187
+ @new_file_name = '/tmp/' + SecureRandom.uuid
188
+ end
189
+ context 'with a directory not blocked for read/write' do
190
+ before(:each) do
191
+ expect(TCellAgent).to receive(:policy).with(
192
+ TCellAgent::PolicyTypes::LFI
193
+ ).and_return(@local_files_policy)
194
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
195
+ end
196
+ context 'with a filename and mode r' do
197
+ it 'should raise an ERRNO::ENOENT error' do
198
+ expect do
199
+ File.open(@new_file_name, 'r')
200
+ end.to raise_error(Errno::ENOENT)
201
+ end
202
+ end
203
+ context 'with a filename and mode w' do
204
+ it 'should create the file' do
205
+ File.open(@new_file_name, 'w')
206
+
207
+ expect(File.exist?(@new_file_name)).to be_truthy
208
+ File.delete(@new_file_name)
209
+ end
210
+ end
211
+ context 'with a filename and write mode and file permissions 644' do
212
+ it 'should create the file with the correct permissions' do
213
+ File.open(@new_file_name, 'w', 0o644)
214
+
215
+ expect(File.exist?(@new_file_name)).to be_truthy
216
+ expect(File.stat(@new_file_name).mode.to_s(8)[3..5]).to eq('644')
217
+ File.delete(@new_file_name)
218
+ end
219
+ end
220
+ context 'with a filename and write mode and file permissions 755' do
221
+ it 'should create the file with the correct permissions' do
222
+ File.open(@new_file_name, 'w', 0o755)
223
+
224
+ expect(File.exist?(@new_file_name)).to be_truthy
225
+ expect(File.stat(@new_file_name).mode.to_s(8)[3..5]).to eq('755')
226
+ File.delete(@new_file_name)
227
+ end
228
+ end
229
+ context 'with a filename and write mode and file permissions 777' do
230
+ it 'should create the file with permissions 755' do
231
+ File.open(@new_file_name, 'w', 0o777)
232
+
233
+ expect(File.exist?(@new_file_name)).to be_truthy
234
+ expect(File.stat(@new_file_name).mode.to_s(8)[3..5]).to eq('755')
235
+ File.delete(@new_file_name)
236
+ end
237
+ end
238
+ end
239
+ context 'with a filename blocked for read/write' do
240
+ before(:each) do
241
+ expect(TCellAgent).to receive(:policy).with(
242
+ TCellAgent::PolicyTypes::LFI
243
+ ).and_return(@local_files_policy)
244
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
245
+ end
246
+ context 'with a filename and write mode' do
247
+ it 'should raise an IOError' do
248
+ expect do
249
+ File.open(@new_file_name, 'w')
250
+ end.to raise_error(IOError)
251
+ end
252
+ end
253
+ context 'with a filename and write mode and file permissions 644' do
254
+ it 'should raise an IOError' do
255
+ expect do
256
+ File.open(@new_file_name, 'w', 644)
257
+ end.to raise_error(IOError)
258
+ end
259
+ end
260
+ end
261
+ end
262
+ context 'with an existing file' do
263
+ context 'with a file not blocked for read/write' do
264
+ before(:each) do
265
+ expect(TCellAgent).to receive(:policy).with(
266
+ TCellAgent::PolicyTypes::LFI
267
+ ).and_return(@local_files_policy)
268
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
269
+ end
270
+ context 'with a filename' do
271
+ it 'should still be able to read the file' do
272
+ result = File.open(@filename).read
273
+ expect(result).to eq @file_contents
274
+ end
275
+ end
276
+ context 'with a filename and mode r' do
277
+ it 'should still be able to read the file' do
278
+ result = File.open(@filename, 'r').read
279
+ expect(result).to eq @file_contents
280
+ end
281
+ end
282
+ context 'with a filenname and mode w' do
283
+ it 'should still be able to write to a file' do
284
+ file = File.open('/dev/null', 'w')
285
+ expect(file.write('dummy message')).to eq 13
286
+ end
287
+ end
288
+ context 'with a filenname and mode a' do
289
+ it 'should still be able to write to a file' do
290
+ file = File.open('/dev/null', 'a')
291
+ expect(file.write('dummy message')).to eq 13
292
+ end
293
+ end
294
+ end
295
+ context 'with a file blocked for read/write' do
296
+ before(:each) do
297
+ expect(TCellAgent).to receive(:policy).with(
298
+ TCellAgent::PolicyTypes::LFI
299
+ ).and_return(@local_files_policy)
300
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
301
+ end
302
+ context 'with a filename' do
303
+ it 'should not be able to read the file' do
304
+ expect do
305
+ File.open(@filename)
306
+ end.to raise_error(IOError)
307
+ end
308
+ end
309
+ context 'with a filename and mode r' do
310
+ it 'should not be able to read the file' do
311
+ expect do
312
+ File.open(@filename, 'r')
313
+ end.to raise_error(IOError)
314
+ end
315
+ end
316
+ context 'with a filename and mode w' do
317
+ it 'should not be able to write to the file' do
318
+ expect do
319
+ File.open('/dev/null', 'w')
320
+ end.to raise_error(IOError)
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
@@ -0,0 +1,562 @@
1
+ require 'spec_helper'
2
+ require 'securerandom'
3
+
4
+ describe 'IO' do
5
+ before do
6
+ native_agent = double('native_agent')
7
+ @local_files_policy = TCellAgent::Policies::LocalFileInclusion.new(
8
+ native_agent, {}
9
+ )
10
+ @cmdi_policy = TCellAgent::Policies::CommandInjectionPolicy.new(
11
+ native_agent, {}
12
+ )
13
+ end
14
+
15
+ before(:all) do
16
+ @filename = get_test_resource_path('lfi_sample_file.txt')
17
+ @file_contents = "This is line one.\nThis is line two.\n"
18
+ @file_length = @file_contents.length
19
+
20
+ @new_file_name = '/tmp/' + SecureRandom.uuid
21
+ @new_file_contents_offset = "This OFFSETe one.\nThis is line two.\n"
22
+ end
23
+
24
+ describe '.binread' do
25
+ context 'empty path' do
26
+ it 'should raise an error' do
27
+ expect do
28
+ IO.binread
29
+ end.to raise_error(ArgumentError)
30
+ expect do
31
+ IO.binread(nil)
32
+ end.to raise_error(TypeError)
33
+ expect do
34
+ IO.binread('')
35
+ end.to raise_error(Errno::ENOENT)
36
+ end
37
+ end
38
+ context 'with a file not blocked for read/write' do
39
+ before do |test|
40
+ unless test.metadata[:skip_before]
41
+ expect(TCellAgent).to receive(:policy).with(
42
+ TCellAgent::PolicyTypes::LFI
43
+ ).and_return(@local_files_policy)
44
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
45
+ expect(TCellAgent::Cmdi).not_to receive(:parse_command_from_open)
46
+ end
47
+ end
48
+
49
+ it 'should still be able to execute OS commands', :skip_before do
50
+ result = IO.binread('|echo test')
51
+ expect(result).to eq "test\n"
52
+ end
53
+ context 'with a filename' do
54
+ it 'should still be able to read file' do
55
+ result = IO.binread(@filename)
56
+ expect(result).to eq @file_contents
57
+ end
58
+ end
59
+ context 'with a filename and a length of 20' do
60
+ it 'should read 20 bytes of the file' do
61
+ result = IO.binread(@filename, 20)
62
+ expect(result).to eq @file_contents[0..19]
63
+ end
64
+ end
65
+ context 'with a filename and a length of 20 and an offset of 5' do
66
+ it 'should read 20 bytes starting from the 5th byte' do
67
+ result = IO.binread(@filename, 20, 5)
68
+ expect(result).to eq @file_contents[5..24]
69
+ end
70
+ end
71
+ end
72
+ context 'with a file blocked for read/write' do
73
+ before do |test|
74
+ unless test.metadata[:skip_before]
75
+ expect(TCellAgent).to receive(:policy).with(
76
+ TCellAgent::PolicyTypes::LFI
77
+ ).and_return(@local_files_policy)
78
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
79
+ expect(TCellAgent::Cmdi).not_to receive(:parse_command_from_open)
80
+ end
81
+ end
82
+
83
+ it 'should still be able to execute OS commands', :skip_before do
84
+ result = IO.binread('|echo test')
85
+ expect(result).to eq "test\n"
86
+ end
87
+ context 'with a filename' do
88
+ it 'should not be able to read the file' do
89
+ expect do
90
+ IO.binread(@filename)
91
+ end.to raise_error(IOError)
92
+ end
93
+ end
94
+ context 'with a filename and a length of 20' do
95
+ it 'should not be able to read the file' do
96
+ expect do
97
+ IO.binread(@filename, 20)
98
+ end.to raise_error(IOError)
99
+ end
100
+ end
101
+ context 'with a filename and a length of 20 and an offset of 5' do
102
+ it 'should not be able to read the file' do
103
+ expect do
104
+ IO.binread(@filename, 20, 5)
105
+ end.to raise_error(IOError)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '.binwrite' do
112
+ context 'empty path' do
113
+ it 'should raise an error' do
114
+ expect do
115
+ IO.binwrite
116
+ end.to raise_error(ArgumentError)
117
+ expect do
118
+ IO.binwrite(nil)
119
+ end.to raise_error(ArgumentError)
120
+ expect do
121
+ IO.binwrite('')
122
+ end.to raise_error(ArgumentError)
123
+ end
124
+ end
125
+ context 'with a file not blocked for read/write' do
126
+ before do
127
+ expect(TCellAgent).to receive(:policy).with(
128
+ TCellAgent::PolicyTypes::LFI
129
+ ).and_return(@local_files_policy)
130
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
131
+ end
132
+
133
+ context 'with a nonexistent filename and string' do
134
+ it 'should create the file' do
135
+ IO.binwrite(@new_file_name, '')
136
+ expect(File.exist?(@new_file_name)).to be_truthy
137
+ File.delete(@new_file_name)
138
+ end
139
+ it 'should write to the file' do
140
+ expect(IO.binwrite(@new_file_name, @file_contents)).to eq @file_length
141
+ File.delete(@new_file_name)
142
+ end
143
+ end
144
+ context 'with a nonexistent filename and string and offset' do
145
+ it 'should write to the file at the offset value 5' do
146
+ expect(TCellAgent).to receive(:policy).with(
147
+ TCellAgent::PolicyTypes::LFI
148
+ ).and_return(@local_files_policy, @local_files_policy)
149
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false, false)
150
+
151
+ IO.binwrite(@new_file_name, @file_contents)
152
+ IO.binwrite(@new_file_name, 'OFFSET', 5)
153
+ expect(IO.binread(@new_file_name)).to eq @new_file_contents_offset
154
+ File.delete(@new_file_name)
155
+ end
156
+ end
157
+ end
158
+ context 'with a file blocked for read or write' do
159
+ before do
160
+ expect(TCellAgent).to receive(:policy).with(
161
+ TCellAgent::PolicyTypes::LFI
162
+ ).and_return(@local_files_policy)
163
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
164
+ end
165
+
166
+ context 'with a nonexistent filename and a string' do
167
+ it 'should not be able to write to the file' do
168
+ expect do
169
+ IO.binwrite(@new_file_name, @file_contents)
170
+ end.to raise_error(IOError)
171
+ end
172
+ end
173
+ context 'with a nonexistent filename and a string and an offset' do
174
+ it 'should not be able to write to the file' do
175
+ expect do
176
+ IO.binwrite(@new_file_name, @file_contents)
177
+ end.to raise_error(IOError)
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ describe '.foreach' do
184
+ context 'empty path' do
185
+ it 'should raise an error' do
186
+ expect do
187
+ IO.foreach('') { pass }
188
+ end.to raise_error(Errno::ENOENT)
189
+ end
190
+ end
191
+ context 'with a file not blocked for read/write' do
192
+ before do
193
+ expect(TCellAgent).to receive(:policy).with(
194
+ TCellAgent::PolicyTypes::LFI
195
+ ).and_return(@local_files_policy)
196
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
197
+ end
198
+
199
+ context 'with a filename' do
200
+ it 'should be able to read the file' do
201
+ result = ''
202
+ IO.foreach(@filename) { |line| result << line }
203
+ expect(result).to eq @file_contents
204
+ end
205
+ end
206
+ context 'with a filename and a limit 16' do
207
+ it 'should split each line to a max length of 16' do
208
+ result = ''
209
+ IO.foreach(@filename, 16) { |line| result << line }
210
+ expect(result).to eq @file_contents
211
+ end
212
+ end
213
+ context 'with a filename and sep' do
214
+ # TODO: no documentation on how to use sep
215
+ end
216
+ context 'with a filename and sep and limit' do
217
+ # TODO: no documentation on how to use sep and limit
218
+ end
219
+ end
220
+ context 'with a file blocked for read or write' do
221
+ before do
222
+ expect(TCellAgent).to receive(:policy).with(
223
+ TCellAgent::PolicyTypes::LFI
224
+ ).and_return(@local_files_policy)
225
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
226
+ end
227
+
228
+ context 'with a filename' do
229
+ it 'should not be able to read the file' do
230
+ expect do
231
+ result = ''
232
+ IO.foreach(@filename) { |line| result << line }
233
+ expect(result).to eq @file_contents
234
+ end.to raise_error(IOError)
235
+ end
236
+ end
237
+ end
238
+ end
239
+
240
+ describe '.read' do
241
+ context 'empty path' do
242
+ it 'should raise an error' do
243
+ expect do
244
+ IO.read
245
+ end.to raise_error(ArgumentError)
246
+ expect do
247
+ IO.read('')
248
+ end.to raise_error(Errno::ENOENT)
249
+ end
250
+ end
251
+ context 'with a file not blocked for read/write' do
252
+ before do |test|
253
+ unless test.metadata[:skip_before]
254
+ expect(TCellAgent).to receive(:policy).with(
255
+ TCellAgent::PolicyTypes::LFI
256
+ ).and_return(@local_files_policy)
257
+
258
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
259
+ expect(TCellAgent::Cmdi).not_to receive(:parse_command_from_open)
260
+ end
261
+ end
262
+
263
+ it 'should still be able to execute OS commands', :skip_before do
264
+ result = IO.read('|echo test')
265
+ expect(result).to eq "test\n"
266
+ end
267
+ context 'with a filename' do
268
+ it 'should read the file' do
269
+ result = IO.read(@filename)
270
+ expect(result).to eq @file_contents
271
+ end
272
+ end
273
+ context 'with a filename and a length of 20' do
274
+ it 'should read 20 bytes of the file' do
275
+ result = IO.read(@filename, 20)
276
+ expect(result).to eq @file_contents[0..19]
277
+ end
278
+ end
279
+ context 'with a filename and a length of 20 and an offset of 5' do
280
+ it 'should read 20 bytes starting from the 5th byte' do
281
+ result = IO.read(@filename, 20, 5)
282
+ expect(result).to eq @file_contents[5..24]
283
+ end
284
+ end
285
+ end
286
+ context 'with a file blocked for read/write' do
287
+ before do |test|
288
+ unless test.metadata[:skip_before]
289
+ expect(TCellAgent).to receive(:policy).with(
290
+ TCellAgent::PolicyTypes::LFI
291
+ ).and_return(@local_files_policy)
292
+
293
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
294
+ expect(TCellAgent::Cmdi).not_to receive(:parse_command_from_open)
295
+ end
296
+ end
297
+
298
+ it 'should still be able to execute OS commands', :skip_before do
299
+ result = IO.read('|echo test')
300
+ expect(result).to eq "test\n"
301
+ end
302
+ context 'with a filename' do
303
+ it 'should not be able to read the file' do
304
+ expect do
305
+ IO.read(@filename)
306
+ end.to raise_error(IOError)
307
+ end
308
+ end
309
+ context 'with a filename and a length 20' do
310
+ it 'should not be able to read the file' do
311
+ expect do
312
+ IO.read(@filename, 20)
313
+ end.to raise_error(IOError)
314
+ end
315
+ end
316
+ context 'with a filename and a length and an offset 5' do
317
+ it 'should not be able to read the file' do
318
+ expect do
319
+ IO.read(@filename, 20, 5)
320
+ end.to raise_error(IOError)
321
+ end
322
+ end
323
+ end
324
+ end
325
+
326
+ describe '.readlines' do
327
+ context 'empty path' do
328
+ it 'should raise an error' do
329
+ expect do
330
+ IO.readlines
331
+ end.to raise_error(ArgumentError)
332
+ expect do
333
+ IO.readlines('')
334
+ end.to raise_error(Errno::ENOENT)
335
+ end
336
+ end
337
+ context 'with a file not blocked for read/write' do
338
+ before do |test|
339
+ unless test.metadata[:skip_before]
340
+ expect(TCellAgent).to receive(:policy).with(
341
+ TCellAgent::PolicyTypes::LFI
342
+ ).and_return(@local_files_policy)
343
+
344
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
345
+ expect(TCellAgent::Cmdi).not_to receive(:parse_command_from_open)
346
+ end
347
+ end
348
+
349
+ context 'with a filename' do
350
+ it 'should read the file' do
351
+ result = IO.readlines(@filename)
352
+ expect(result[0] + result[1]).to eq @file_contents
353
+ end
354
+ end
355
+ context 'with a filename and a limit 20' do
356
+ it 'should read 20 bytes of the file' do
357
+ exp_result = ['This ', 'is li', 'ne on', "e.\n", 'This ', 'is li', 'ne tw', "o.\n"]
358
+ result = IO.readlines(@filename, 5)
359
+ expect(result).to eq exp_result
360
+ end
361
+ end
362
+ context 'with a filename and a limit of 20 and sep' do
363
+ # TODO
364
+ end
365
+ end
366
+ context 'with a file blocked for read/write' do
367
+ before do |test|
368
+ unless test.metadata[:skip_before]
369
+ expect(TCellAgent).to receive(:policy).with(
370
+ TCellAgent::PolicyTypes::LFI
371
+ ).and_return(@local_files_policy)
372
+
373
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
374
+ expect(TCellAgent::Cmdi).not_to receive(:parse_command_from_open)
375
+ end
376
+ end
377
+
378
+ it 'should still be able to execute OS commands', :skip_before do
379
+ result = IO.readlines('|echo test')[0]
380
+ expect(result).to eq "test\n"
381
+ end
382
+ context 'with a filename' do
383
+ it 'should not be able to read the file' do
384
+ expect do
385
+ IO.readlines(@filename)
386
+ end.to raise_error(IOError)
387
+ end
388
+ end
389
+ end
390
+ end
391
+
392
+ describe '.sysopen' do
393
+ context 'empty path' do
394
+ it 'should raise an error' do
395
+ expect do
396
+ IO.sysopen
397
+ end.to raise_error(ArgumentError)
398
+ expect do
399
+ IO.sysopen(nil)
400
+ end.to raise_error(TypeError)
401
+ expect do
402
+ IO.sysopen('')
403
+ end.to raise_error(Errno::ENOENT)
404
+ end
405
+ end
406
+ context 'with a nonexistent file' do
407
+ context 'with mode r' do
408
+ it 'should raise an error' do
409
+ end
410
+ end
411
+ context 'with mode w' do
412
+ it 'should return an integer' do
413
+ end
414
+ end
415
+ end
416
+ context 'with a file not blocked for read/write' do
417
+ before do
418
+ expect(TCellAgent).to receive(:policy).with(
419
+ TCellAgent::PolicyTypes::LFI
420
+ ).and_return(@local_files_policy)
421
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
422
+ end
423
+
424
+ context 'with a filename' do
425
+ it 'should return an integer' do
426
+ fd = IO.sysopen(@filename)
427
+ expect(fd).to be_a(Integer)
428
+ end
429
+ it 'should open the file for read' do
430
+ fd = IO.sysopen(@filename)
431
+ expect(IO.new(fd).read).to eq @file_contents
432
+ end
433
+ end
434
+ context 'with a filename and mode w' do
435
+ it 'should return an integer' do
436
+ fd = IO.sysopen(@new_file_name, 'w')
437
+ expect(fd).to be_a(Integer)
438
+ end
439
+ it 'should open the file for write' do
440
+ fd = IO.sysopen(@new_file_name, 'w')
441
+ file = IO.new(fd, 'w')
442
+ file.puts @file_contents
443
+ file.rewind
444
+ end
445
+ end
446
+ end
447
+ context 'with a file blocked for read/write' do
448
+ before do
449
+ expect(TCellAgent).to receive(:policy).with(
450
+ TCellAgent::PolicyTypes::LFI
451
+ ).and_return(@local_files_policy)
452
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
453
+ end
454
+
455
+ context 'with a filename' do
456
+ it 'should not be able to open the file for read' do
457
+ expect do
458
+ IO.sysopen(@filename)
459
+ end.to raise_error(IOError)
460
+ end
461
+ end
462
+ context 'with a filename and mode' do
463
+ it 'should not be able to open the file for read' do
464
+ expect do
465
+ IO.sysopen(@filename, 'r')
466
+ end.to raise_error(IOError)
467
+ end
468
+ end
469
+ end
470
+ end
471
+
472
+ describe '.write' do
473
+ context 'empty path' do
474
+ it 'should raise an error' do
475
+ expect do
476
+ IO.write
477
+ end.to raise_error(ArgumentError)
478
+ expect do
479
+ IO.write(nil)
480
+ end.to raise_error(ArgumentError)
481
+ expect do
482
+ IO.write('')
483
+ end.to raise_error(ArgumentError)
484
+ end
485
+ end
486
+ context 'with a file not blocked for read/write' do
487
+ before do
488
+ expect(TCellAgent).to receive(:policy).with(
489
+ TCellAgent::PolicyTypes::LFI
490
+ ).and_return(@local_files_policy)
491
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
492
+ end
493
+
494
+ context 'with a filename that doe not exist' do
495
+ it 'should create the file' do
496
+ IO.write(@new_file_name, @file_contents)
497
+ expect(File.exist?(@new_file_name)).to be_truthy
498
+ File.delete(@new_file_name)
499
+ end
500
+ it 'should write to the file' do
501
+ expect(TCellAgent).to receive(:policy).with(
502
+ TCellAgent::PolicyTypes::LFI
503
+ ).and_return(@local_files_policy)
504
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
505
+
506
+ IO.write(@new_file_name, @file_contents)
507
+ expect(IO.read(@new_file_name)).to eq @file_contents
508
+ File.delete(@new_file_name)
509
+ end
510
+ end
511
+ context 'with a filename that does exist' do
512
+ it 'should overwrite the file' do
513
+ expect(TCellAgent).to receive(:policy).with(
514
+ TCellAgent::PolicyTypes::LFI
515
+ ).and_return(@local_files_policy)
516
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false)
517
+
518
+ IO.write(@new_file_name, @file_contents)
519
+ expect(IO.read(@new_file_name)).to eq @file_contents
520
+ File.delete(@new_file_name)
521
+ end
522
+ end
523
+ context 'with a filename that does exist and an offset 5' do
524
+ it 'should overwrite the file starting at the offset value' do
525
+ expect(TCellAgent).to receive(:policy).with(
526
+ TCellAgent::PolicyTypes::LFI
527
+ ).and_return(@local_files_policy, @local_files_policy)
528
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(false, false)
529
+
530
+ exp_results = @file_contents.dup
531
+ exp_results[1..6] = 'OFFSET'
532
+ IO.write(@new_file_name, @file_contents)
533
+ IO.write(@new_file_name, 'OFFSET', 1)
534
+ expect(IO.read(@new_file_name)).to eq exp_results
535
+ end
536
+ end
537
+ end
538
+ context 'with a file blocked for read/write' do
539
+ before do
540
+ expect(TCellAgent).to receive(:policy).with(
541
+ TCellAgent::PolicyTypes::LFI
542
+ ).and_return(@local_files_policy)
543
+ expect(@local_files_policy).to receive(:block_file_access?).and_return(true)
544
+ end
545
+
546
+ context 'with a filename that does not exist' do
547
+ it 'should not be able to write to the file' do
548
+ expect do
549
+ IO.write(@new_file_name, '')
550
+ end.to raise_error(IOError)
551
+ end
552
+ end
553
+ context 'with a filename that does exist' do
554
+ it 'should not be able to write to the file' do
555
+ expect do
556
+ IO.write(@filename, @file_contents)
557
+ end.to raise_error(IOError)
558
+ end
559
+ end
560
+ end
561
+ end
562
+ end