1 //--------------------------------------------------------------------------
2 // Copyright (C) 2015-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // user_session.cc author Russ Combs <rucombs@cisco.com>
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "user_session.h"
25
26 #include "detection/detection_engine.h"
27 #include "detection/rules.h"
28 #include "main/analyzer.h"
29 #include "main/snort_debug.h"
30 #include "memory/memory_cap.h"
31 #include "profiler/profiler_defs.h"
32 #include "protocols/packet.h"
33 #include "utils/util.h"
34
35 #include "stream_user.h"
36 #include "user_module.h"
37
38 using namespace snort;
39
40 THREAD_LOCAL ProfileStats user_perf_stats;
41
42 // we always get exactly one copy of user data in order
43 // maintain "seg"list of user data stream
44 // allocate bucket size to substantially improve performance
45 // run user data through paf
46
47 //-------------------------------------------------------------------------
48 // segment stuff
49 //-------------------------------------------------------------------------
50
51 #define OVERHEAD 32
52 #define PAGE_SZ 4096
53 #define BUCKET (PAGE_SZ - OVERHEAD)
54
init(const uint8_t * p,unsigned n)55 UserSegment* UserSegment::init(const uint8_t* p, unsigned n)
56 {
57 unsigned bucket = (n > BUCKET) ? n : BUCKET;
58 unsigned size = sizeof(UserSegment) + bucket -1;
59
60 UserSegment* us = (UserSegment*)snort_alloc(size);
61
62 us->size = size;
63 us->len = 0;
64 us->offset = 0;
65 us->used = 0;
66 us->copy(p, n);
67
68 return us;
69 }
70
term(UserSegment * us)71 void UserSegment::term(UserSegment* us)
72 {
73 snort_free(us);
74 }
75
avail()76 unsigned UserSegment::avail()
77 {
78 unsigned size = offset + len;
79 return (BUCKET > size) ? BUCKET - size : 0;
80 }
81
copy(const uint8_t * p,unsigned n)82 void UserSegment::copy(const uint8_t* p, unsigned n)
83 {
84 memcpy(data+offset+len, p, n);
85 len += n;
86 }
87
shift(unsigned n)88 void UserSegment::shift(unsigned n)
89 {
90 assert(len >= n);
91 offset += n;
92 len -= n;
93 }
94
get_len()95 unsigned UserSegment::get_len()
96 { return len; }
97
get_data()98 uint8_t* UserSegment::get_data()
99 { return data + offset; }
100
unused()101 bool UserSegment::unused()
102 { return used < offset + len; }
103
use(unsigned n)104 void UserSegment::use(unsigned n)
105 {
106 used += n;
107 if ( used > offset + len )
108 used = offset + len;
109 }
110
reset()111 void UserSegment::reset()
112 { used = offset; }
113
get_unused_len()114 unsigned UserSegment::get_unused_len()
115 { return (offset + len > used) ? offset + len - used : 0; }
116
get_unused_data()117 uint8_t* UserSegment::get_unused_data()
118 { return data + used; }
119
120 //-------------------------------------------------------------------------
121 // tracker stuff
122 //-------------------------------------------------------------------------
123
UserTracker()124 UserTracker::UserTracker()
125 { init(); }
126
~UserTracker()127 UserTracker::~UserTracker()
128 { term(); }
129
init()130 void UserTracker::init()
131 {
132 paf_clear(&paf_state);
133 splitter = nullptr;
134 total = 0;
135 }
136
term()137 void UserTracker::term()
138 {
139 if ( splitter )
140 {
141 delete splitter;
142 splitter = nullptr;
143 }
144
145 for ( auto* p : seg_list )
146 snort_free(p);
147
148 seg_list.clear();
149 }
150
detect(const Packet * p,const StreamBuffer & sb,uint32_t flags,Packet * up)151 void UserTracker::detect(
152 const Packet* p, const StreamBuffer& sb, uint32_t flags, Packet* up)
153 {
154 up->pkth = p->pkth;
155 up->ptrs = p->ptrs;
156 up->flow = p->flow;
157 up->data = sb.data;
158 up->dsize = sb.length;
159
160 up->proto_bits = p->proto_bits;
161 up->pseudo_type = PSEUDO_PKT_USER;
162
163 up->packet_flags = flags | PKT_REBUILT_STREAM | PKT_PSEUDO;
164 up->packet_flags |= (p->packet_flags & (PKT_FROM_CLIENT|PKT_FROM_SERVER));
165 up->packet_flags |= (p->packet_flags & (PKT_STREAM_EST|PKT_STREAM_UNEST_UNI));
166
167 debug_logf(stream_user_trace, up, "detect[%d]\n", up->dsize);
168 Analyzer::get_local_analyzer()->inspect_rebuilt(up);
169 }
170
scan(Packet * p,uint32_t & flags)171 int UserTracker::scan(Packet* p, uint32_t& flags)
172 {
173 if ( seg_list.empty() )
174 return -1;
175
176 std::list<UserSegment*>::iterator it;
177
178 for ( it = seg_list.begin(); it != seg_list.end(); ++it)
179 {
180 UserSegment* us = *it;
181
182 if ( !us->unused() )
183 continue;
184
185 flags = p->packet_flags & (PKT_FROM_CLIENT|PKT_FROM_SERVER);
186 unsigned len = us->get_unused_len();
187 debug_logf(stream_user_trace, p, "scan[%d]\n", len);
188
189 int32_t flush_amt = paf_check(
190 splitter, &paf_state, p, us->get_unused_data(), len,
191 total, paf_state.seq, &flags);
192
193 if ( flush_amt >= 0 )
194 {
195 us->use(flush_amt);
196
197 if ( !splitter->is_paf() && total > (unsigned)flush_amt )
198 {
199 paf_jump(&paf_state, total - flush_amt);
200 return total;
201 }
202 return flush_amt;
203 }
204 us->use(len);
205 }
206 return -1;
207 }
208
flush(Packet * p,unsigned flush_amt,uint32_t flags)209 void UserTracker::flush(Packet* p, unsigned flush_amt, uint32_t flags)
210 {
211 unsigned bytes_flushed = 0;
212 debug_logf(stream_user_trace, p, "flush[%d]\n", flush_amt);
213 uint32_t rflags = flags & ~PKT_PDU_TAIL;
214 Packet* up = DetectionEngine::set_next_packet(p);
215
216 while ( !seg_list.empty() and bytes_flushed < flush_amt )
217 {
218 UserSegment* us = seg_list.front();
219 const uint8_t* data = us->get_data();
220 unsigned len = us->get_len();
221 unsigned bytes_copied = 0;
222
223 if ( len + bytes_flushed > flush_amt )
224 len = flush_amt - bytes_flushed;
225
226 if ( len + bytes_flushed == flush_amt )
227 {
228 rflags |= (flags & PKT_PDU_TAIL);
229 len = flush_amt;
230 }
231
232 debug_logf(stream_user_trace, p, "reassemble[%d]\n", len);
233 StreamBuffer sb = splitter->reassemble(
234 p->flow, flush_amt, bytes_flushed, data, len, rflags, bytes_copied);
235
236 bytes_flushed += bytes_copied;
237 total -= bytes_copied;
238
239 rflags &= ~PKT_PDU_HEAD;
240
241 if ( sb.data )
242 detect(p, sb, flags, up);
243
244 if ( bytes_copied == us->get_len() )
245 {
246 seg_list.pop_front();
247 UserSegment::term(us);
248 }
249 else
250 {
251 us->shift(bytes_copied);
252 }
253 }
254 }
255
process(Packet * p)256 void UserTracker::process(Packet* p)
257 {
258 uint32_t flags = 0;
259 int flush_amt = scan(p, flags);
260
261 while ( flush_amt >= 0 )
262 {
263 unsigned amt = (unsigned)flush_amt;
264 assert(total >= amt);
265
266 flush(p, amt, flags);
267
268 if ( total )
269 flush_amt = scan(p, flags);
270 else
271 break;
272 }
273 }
274
add_data(Packet * p)275 void UserTracker::add_data(Packet* p)
276 {
277 debug_logf(stream_user_trace, p, "add[%d]\n", p->dsize);
278 unsigned avail = 0;
279
280 if ( !seg_list.empty() )
281 {
282 UserSegment* us = seg_list.back();
283 avail = us->avail();
284
285 if ( avail )
286 {
287 if ( avail > p->dsize )
288 avail = p->dsize;
289 us->copy(p->data, avail);
290 }
291 }
292
293 if ( avail < p->dsize )
294 {
295 UserSegment* us = UserSegment::init(p->data+avail, p->dsize-avail);
296 seg_list.emplace_back(us);
297 }
298 total += p->dsize;
299 process(p);
300 }
301
302 //-------------------------------------------------------------------------
303 // private user session methods
304 // may need additional refactoring
305 //-------------------------------------------------------------------------
306
start(Packet * p,Flow * f)307 void UserSession::start(Packet* p, Flow* f)
308 {
309 Inspector* ins = f->gadget;
310
311 if ( !ins )
312 ins = f->clouseau;
313
314 if ( ins )
315 {
316 set_splitter(true, ins->get_splitter(true));
317 set_splitter(false, ins->get_splitter(false));
318 }
319 else
320 {
321 set_splitter(true, new AtomSplitter(true));
322 set_splitter(false, new AtomSplitter(false));
323 }
324
325 {
326 f->pkt_type = p->type();
327 f->ip_proto = (uint8_t)p->get_ip_proto_next();
328
329 if (f->ssn_state.session_flags & SSNFLAG_RESET)
330 f->ssn_state.session_flags &= ~SSNFLAG_RESET;
331
332 if ( (f->ssn_state.session_flags & SSNFLAG_CLIENT_SWAP) &&
333 !(f->ssn_state.session_flags & SSNFLAG_CLIENT_SWAPPED) )
334 {
335 f->swap_roles();
336
337 if ( !f->two_way_traffic() )
338 {
339 if ( f->ssn_state.session_flags & SSNFLAG_SEEN_CLIENT )
340 {
341 f->ssn_state.session_flags ^= SSNFLAG_SEEN_CLIENT;
342 f->ssn_state.session_flags |= SSNFLAG_SEEN_SERVER;
343 }
344 else if ( f->ssn_state.session_flags & SSNFLAG_SEEN_SERVER )
345 {
346 f->ssn_state.session_flags ^= SSNFLAG_SEEN_SERVER;
347 f->ssn_state.session_flags |= SSNFLAG_SEEN_CLIENT;
348 }
349 }
350 f->ssn_state.session_flags |= SSNFLAG_CLIENT_SWAPPED;
351 }
352 #if 0
353 // FIXIT-M implement stream_user perf stats
354 //f->set_expire(p, dstPolicy->session_timeout);
355
356 // add user flavor to perf stats?
357 AddStreamSession(
358 &sfBase, f->session_state & STREAM_STATE_MIDSTREAM ? SSNFLAG_MIDSTREAM : 0);
359
360 StreamUpdatePerfBaseState(&sfBase, tmp->flow, TCP_STATE_SYN_SENT);
361
362 EventInternal(SESSION_EVENT_SETUP);
363 #endif
364 }
365 }
366
end(Packet *,Flow *)367 void UserSession::end(Packet*, Flow*)
368 {
369 delete client.splitter;
370 delete server.splitter;
371
372 client.splitter = nullptr;
373 server.splitter = nullptr;
374 }
375
update(Packet * p,Flow * f)376 void UserSession::update(Packet* p, Flow* f)
377 {
378 if ( p->ptrs.sp and p->ptrs.dp )
379 p->packet_flags |= PKT_STREAM_EST;
380 else
381 p->packet_flags |= PKT_STREAM_UNEST_UNI;
382
383 if ( !(f->ssn_state.session_flags & SSNFLAG_ESTABLISHED) )
384 {
385 if ( p->is_from_client() )
386 f->ssn_state.session_flags |= SSNFLAG_SEEN_CLIENT;
387 else
388 f->ssn_state.session_flags |= SSNFLAG_SEEN_SERVER;
389
390 if ( (f->ssn_state.session_flags & SSNFLAG_SEEN_CLIENT) &&
391 (f->ssn_state.session_flags & SSNFLAG_SEEN_SERVER) )
392 {
393 f->ssn_state.session_flags |= SSNFLAG_ESTABLISHED;
394
395 f->set_ttl(p, false);
396 }
397 }
398
399 f->set_expire(p, f->default_session_timeout);
400 }
401
restart(Packet * p)402 void UserSession::restart(Packet* p)
403 {
404 bool c2s = p->is_from_client();
405 UserTracker& ut = c2s ? server : client;
406 std::list<UserSegment*>::iterator it;
407 ut.total = 0;
408
409 for ( it = ut.seg_list.begin(); it != ut.seg_list.end(); ++it)
410 {
411 (*it)->reset();
412 ut.total += (*it)->get_len();
413 }
414
415 paf_reset(&ut.paf_state);
416 ut.process(p);
417 }
418
419 //-------------------------------------------------------------------------
420 // UserSession methods
421 //-------------------------------------------------------------------------
422
UserSession(Flow * f)423 UserSession::UserSession(Flow* f) : Session(f)
424 { }
425
~UserSession()426 UserSession::~UserSession()
427 { }
428
setup(Packet *)429 bool UserSession::setup(Packet*)
430 {
431 client.init();
432 server.init();
433
434 StreamUserConfig* pc = get_user_cfg(flow->ssn_server);
435 flow->set_default_session_timeout(pc->session_timeout, false);
436
437 if ( flow->ssn_state.ignore_direction != SSN_DIR_NONE )
438 return false;
439 return true;
440 }
441
clear()442 void UserSession::clear()
443 {
444 client.term();
445 server.term();
446 }
447
set_splitter(bool c2s,StreamSplitter * ss)448 void UserSession::set_splitter(bool c2s, StreamSplitter* ss)
449 {
450 UserTracker& ut = c2s ? server : client;
451
452 if ( ut.splitter )
453 delete ut.splitter;
454
455 ut.splitter = ss;
456
457 if ( ss )
458 paf_setup(&ut.paf_state);
459 }
460
get_splitter(bool c2s)461 StreamSplitter* UserSession::get_splitter(bool c2s)
462 {
463 const UserTracker& ut = c2s ? server : client;
464 return ut.splitter;
465 }
466
process(Packet * p)467 int UserSession::process(Packet* p)
468 {
469 Profile profile(user_perf_stats);
470
471 if ( Stream::expired_flow(flow, p) )
472 {
473 flow->restart();
474 // FIXIT-M count user session timeouts here
475
476 #ifdef ENABLE_EXPECTED_USER
477 if ( Stream::expected_flow(flow, p))
478 return 0;
479 #endif
480 }
481
482 flow->set_direction(p);
483
484 if ( Stream::blocked_flow(p) || Stream::ignored_flow(flow, p) )
485 return 0;
486
487 update(p, flow);
488
489 UserTracker& ut = p->is_from_client() ? server : client;
490
491 if ( !ut.splitter or p->ptrs.decode_flags & DECODE_SOF )
492 start(p, flow);
493
494 if ( p->data && p->dsize )
495 ut.add_data(p);
496
497 if ( p->ptrs.decode_flags & DECODE_EOF )
498 end(p, flow);
499
500 return 0;
501 }
502
503 //-------------------------------------------------------------------------
504 // UserSession methods
505 // FIXIT-M these are TBD after tcp is updated
506 // some will be deleted, some refactored, some implemented
507 //-------------------------------------------------------------------------
508
add_alert(Packet *,uint32_t,uint32_t)509 bool UserSession::add_alert(Packet*, uint32_t /*gid*/, uint32_t /*sid*/) { return true; }
check_alerted(Packet *,uint32_t,uint32_t)510 bool UserSession::check_alerted(Packet*, uint32_t /*gid*/, uint32_t /*sid*/) { return false; }
511
update_alert(Packet *,uint32_t,uint32_t,uint32_t,uint32_t)512 int UserSession::update_alert(
513 Packet*, uint32_t /*gid*/, uint32_t /*sid*/,
514 uint32_t /*event_id*/, uint32_t /*event_second*/)
515 { return 0; }
516
get_reassembly_direction()517 uint8_t UserSession::get_reassembly_direction()
518 { return SSN_DIR_NONE; }
519
520