1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 // Copyright (C) 2002-2013 Sourcefire, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License Version 2 as published
7 // by the Free Software Foundation.  You may not use, modify or distribute
8 // this program under any other version of the GNU General Public License.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //--------------------------------------------------------------------------
19 // cd_pgm.cc author Josh Rosenbaum <jrosenba@cisco.com>
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "codecs/codec_module.h"
26 #include "framework/codec.h"
27 
28 #include "checksum.h"
29 
30 using namespace snort;
31 
32 namespace
33 {
34 #define CD_PGM_NAME "pgm"
35 #define CD_PGM_HELP "support for pragmatic general multicast"
36 
37 static const RuleMap pgm_rules[] =
38 {
39     { DECODE_PGM_NAK_OVERFLOW, "PGM nak list overflow attempt" },
40     { 0, nullptr }
41 };
42 
43 class PgmModule : public BaseCodecModule
44 {
45 public:
PgmModule()46     PgmModule() : BaseCodecModule(CD_PGM_NAME, CD_PGM_HELP) { }
47 
get_rules() const48     const RuleMap* get_rules() const override
49     { return pgm_rules; }
50 };
51 
52 class PgmCodec : public Codec
53 {
54 public:
PgmCodec()55     PgmCodec() : Codec(CD_PGM_NAME) { }
56 
57     bool decode(const RawData&, CodecData&, DecodeData&) override;
58     void get_protocol_ids(std::vector<ProtocolId>&) override;
59 };
60 
61 static const int PGM_NAK_ERR = -1;
62 static const int PGM_NAK_OK = 0;
63 static const int PGM_NAK_VULN = 1;
64 
65 struct PGM_NAK_OPT
66 {
67     uint8_t type;     /* 02 = vuln */
68     uint8_t len;
69     uint8_t res[2];
70     uint32_t seq[1];    /* could be many many more, but 1 is sufficient */
71 };
72 
73 struct PGM_NAK
74 {
75     uint32_t seqnum;
76     uint16_t afil1;
77     uint16_t res1;
78     uint32_t src;
79     uint16_t afi2;
80     uint16_t res2;
81     uint32_t multi;
82     PGM_NAK_OPT opt;
83 };
84 
85 struct PgmHeader
86 {
87     uint16_t srcport;
88     uint16_t dstport;
89     uint8_t type;
90     uint8_t opt;
91     uint16_t checksum;
92     uint8_t gsd[6];
93     uint16_t length;
94     PGM_NAK nak;
95 };
96 } // namespace
97 
98 /* This PGM NAK function started off as an SO rule, sid 8351. */
pgm_nak_detect(const RawData & raw)99 static inline int pgm_nak_detect(const RawData& raw)
100 {
101     /* request must be bigger than 44 bytes to cause vuln,
102        and length must be divisible by 4 */
103     if (raw.len <= sizeof(PgmHeader) or (raw.len & 0x03) != 0)
104     {
105         return PGM_NAK_ERR;
106     }
107 
108     const PgmHeader* const header =
109         reinterpret_cast<const PgmHeader*>(raw.data);
110 
111     if (8 != header->type)
112         return PGM_NAK_ERR;
113 
114     if (2 != header->nak.opt.type)
115         return PGM_NAK_ERR;
116 
117     /*
118      * alert if the amount of data after the options is more than the length
119      * specified.
120      */
121     const uint16_t data_left = raw.len - 36;
122 
123     if (data_left > header->nak.opt.len)
124     {
125         /* checksum is expensive... do that only if the length is bad */
126         if (header->checksum != 0)
127         {
128             const uint16_t checksum =
129                 checksum::cksum_add((const uint16_t*)raw.data, raw.len);
130 
131             if (checksum != 0)
132                 return PGM_NAK_ERR;
133         }
134 
135         return PGM_NAK_VULN;
136     }
137 
138     return PGM_NAK_OK;
139 }
140 
141 //-------------------------------------------------------------------------
142 // private functions
143 //-------------------------------------------------------------------------
144 
decode(const RawData & raw,CodecData & codec,DecodeData &)145 bool PgmCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
146 {
147     if ( pgm_nak_detect(raw) == PGM_NAK_VULN )
148         codec_event(codec, DECODE_PGM_NAK_OVERFLOW);
149     return true;
150 }
151 
get_protocol_ids(std::vector<ProtocolId> & v)152 void PgmCodec::get_protocol_ids(std::vector<ProtocolId>& v)
153 {
154     v.emplace_back(ProtocolId::PGM);
155 }
156 
157 //-------------------------------------------------------------------------
158 // api
159 //-------------------------------------------------------------------------
160 
mod_ctor()161 static Module* mod_ctor()
162 { return new PgmModule; }
163 
mod_dtor(Module * m)164 static void mod_dtor(Module* m)
165 { delete m; }
166 
ctor(Module *)167 static Codec* ctor(Module*)
168 { return new PgmCodec(); }
169 
dtor(Codec * cd)170 static void dtor(Codec* cd)
171 { delete cd; }
172 
173 static const CodecApi pgm_api =
174 {
175     {
176         PT_CODEC,
177         sizeof(CodecApi),
178         CDAPI_VERSION,
179         0,
180         API_RESERVED,
181         API_OPTIONS,
182         CD_PGM_NAME,
183         CD_PGM_HELP,
184         mod_ctor,
185         mod_dtor,
186     },
187     nullptr, // pinit
188     nullptr, // pterm
189     nullptr, // tinit
190     nullptr, // tterm
191     ctor, // ctor
192     dtor, // dtor
193 };
194 
195 #ifdef BUILDING_SO
196 SO_PUBLIC const BaseApi* snort_plugins[] =
197 #else
198 const BaseApi* cd_pgm[] =
199 #endif
200 {
201     &pgm_api.base,
202     nullptr
203 };
204