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