tcell_agent 1.1.12 → 2.2.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 (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