[Snort-devel] Help with a Segmentation fault, on a preprocessor

Martin Roesch roesch at ...402...
Tue May 20 17:57:57 EDT 2008


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Just in general you should check the parameters you're passing to the  
inet_ntop() call you're making from the RequiredTrafficFunc() function  
on line 232 of spp_requiredtraffic.c.  You can do what Lurene said  
too, but generally speaking when you see a backtrace like that it's a  
parameter problem in the "lowest" call on the backtrace stack.

I'd be interested to see the output from the commands Lurene  
recommended though.  :)

	-Marty

On May 20, 2008, at 10:47 AM, Salvo Danilo Giuffrida wrote:

> Hello, after having been able to compile my preprocessor, which should
> check if 'mandatory' traffic is present or not (the absence could be
> the sign of a DOS), and after having fixed some mistakes, I'm stuck
> with a segmentation fault that the preprocessor gives me after a while
> that it's running.
> The code of the preprocessor is this:
>
> /* RequiredTraffic
> * TODO:    Remember to handle errors
> *          Add a reference to the GPL license
> */
>
> #ifdef HAVE_CONFIG_H
> #include "config.h"
> #endif
>
> #include "ctype.h"
> #include "event_queue.h"
> //Files related functions
> #include <sys/file.h>
> //Generators
> #include "generators.h"
> //Headers for HashTable related functions
> #include "hashtable.h"
> #include "GeneralHashFunctions.h"
> //Limits for integers, chars, etc...
> #include <limits.h>
> //Functions Add* and RegisterPreprocessor
> #include "plugbase.h"
> //Preprocessor IDs
> #include "preprocids.h"
> //Pthread library
> #include <pthread.h>
> //Rule struct definition, plugins APIs
> #include "../../dynamic-plugins/sf_engine/sf_snort_plugin_api.h"
> //Signals library
> #include <signal.h>
> //Memory related functions
> #include "smalloc.h"
> //Standard C libraries
> #include <stdio.h>
> #include <stdlib.h>
> #include <stddef.h>
> //String library
> #include <string.h>
> //Time related functions
> #include <time.h>
> #include <unistd.h>
> //Utility functions (LogMessage, ...)
> #include "util.h"
>
> //My header file
> #include "spp_requiredtraffic.h"
>
> //Signature id for alarms triggered by 'required' traffic rule. To be
> adjusted in some way...
> #define SIGNATURE_ID_REQUIREDTRAFFIC 1000001
>
> /*  Ultimately calls SnortEventqAdd
>    Arguments are: gid, sid, rev, classification, priority, message,  
> rule_info
>    x: sid, y: message
> */
> //#define ALERT(x,y) { SnortEventqAdd(GENERATOR_SPP_REQUIREDTRAFFIC,
> x, 1, 0, 3, y, 0 ); }
> #define ALERT(x,y) { LogMessage(y); }
>
> /*
> * Definition of required structures
> */
> struct RequiredTrafficRule {
>    Rule normalRule;
>    int maxTime;
> };
>
> //struct Entry *hashTable, *hashTableEntry;
>
> struct hashtable* hashTable;
> Rule* key;
> timer_t* value;
> struct itimerspec* timing;
> struct sigevent* event;
> char* key_concatenation;
>
> //Prototypes of internal functions
>
> /*  Initialization function (usually, takes parameters from the config
> file, calls a parseargs function,
> *  like strtok, and initializes local variables)
> */
> void RequiredTrafficInit(char*);
> //What the pre-processor actually does
> void RequiredTrafficFunc(Packet*, void*);
> //The termination function
> void RequiredTrafficCleanExitFunction();
> //The restart function
> void RequiredTrafficRestartFunction();
> //Function to print an alarm in case of missing traffic. The parameter
> contains the reference to the rule that triggered the alarm
> void raiseAlarm(void*);
> //Function to convert an array of 6 integers to a string representing
> the correspondent MAC address (6 hex strings separated by ':')
> void arrayIntToEtherAddr(u_int8_t[], char*);
>
> //Prototypes of function used to manage the hashtable
> static unsigned int hash(void *k);
> static int keys_equal(void *key1, void *key2);
>
> /* Setup function, which will be called from plugbase.c */
> void SetupRequiredTraffic(void) {
>    /* If you really want this message to appear anyway (not only in
> debug mode, the place depends on the type of messaging log,
>     * it could even be registered in the syslog) use the function
> LogMessage at util.h.
>     * To register the preprocessor, call the function
> 'RegisterPreprocessor': It receives the name of your preprocessor
>     * (the one in the config file) and a pointer to the entry  
> point's function
>     */
>    LogMessage("RequiredTraffic: The preprocessor has been included in
> the config file, and is being registered...");
>    RegisterPreprocessor("requiredtraffic", RequiredTrafficInit);
> }
>
> /* The initialization function. "args" is a string with the arguments
> in the config file (snort.conf: preprocessor: <options>).
> * Arguments can have any separator, at $SNORT_DIR/msplit.h, there is
> a good collection of functions to get the right values, eg, msplit.
> */
> void RequiredTrafficInit(char* args) {
>    LogMessage("RequiredTraffic: The preprocessor is being  
> initialized... \n");
>    /* args: Name of the file containing the list of rules for
> required traffic (L2 and L3) */
>
>    /* What to do:
>     * 1 - Open the file (passed as an argument)
>     * 2 - Read each rule (1 line (non empty)=1 rule)
>     * 3 - Parse and add it to the internal hashtable mantained by  
> the plugin
>     * 4 - Create a timer for each rule,which if armed runs a function
> that prints an alert
>     **/
>    //1 - Open the file
>    FILE* rulesFile = fopen(args, "r");
>    if (rulesFile == NULL)
>        perror("Error during the reading of the rules file");
>    if ((hashTable = create_hashtable(16, hash, keys_equal)) == NULL)
>        perror("Error during the creation of the hashtable");
>
>    char tmpLine[256];
>
>    //2 - Read each rule from the appropriate file
>    while (fgets(tmpLine, 256, rulesFile) != NULL) {
>        if (strlen(tmpLine) > 0) {
>            /* 3 - Parse and add it to the internal list mantained by  
> the plugin
>             *  Format of the rules:
>             *  1 - Keyword 'required'
>             *  2 - Source address (IP or MAC)
>             *  3 - Source port (number or 'any', not significant in
> case of MAC addresses, but required in any case)
>             *  4 - Direction of traffic (should always be '->')
>             *  5 - Destination address
>             *  6 - Destination port
>             *  7 - Maximum time (We don't need to specify minTime,  
> do we?)
>             **/
>
>            strtok(tmpLine, " "); //Skip the keyword 'required'
>
>            key = (Rule*) malloc(sizeof (Rule));
>            key->ip.src_addr = (char*) malloc(sizeof (char) *18);
>            key->ip.src_port = (char*) malloc(sizeof (char) *6);
>            strcpy(key->ip.src_addr, strtok(NULL, " ")); //Source  
> address
>            strcpy(key->ip.src_port, strtok(NULL, " ")); //Source port
>            strtok(NULL, " "); //Skip the direction of traffic ('->')
>
>            //INSERT HERE A REGEXP TO CHECK IF THE ADDRESS IN THE RULE
> IS IN MAC FORMAT?
>
>            key->ip.dst_addr = (char*) malloc(sizeof (char) *18);
>            key->ip.dst_port = (char*) malloc(sizeof (char) *6);
>            strcpy(key->ip.dst_addr, strtok(NULL, " ")); // 
> Destination address
>            strcpy(key->ip.dst_port, strtok(NULL, " ")); // 
> Destination port
>
>            event = (struct sigevent*) malloc(sizeof (struct  
> sigevent));
>            event->sigev_notify = SIGEV_THREAD; //How the arming of
> the timer is handled
>            event->sigev_signo = SIGUSR1; //Type of signal sent at
> arming of the timer
>            event->sigev_notify_function = (void*) raiseAlarm;
> //Pointer to the handler function
>            event->sigev_notify_attributes = NULL; //Attributes of the
> thread (NULL=default)
>            event->sigev_value = (sigval_t) (void*) key; //Argument of
> the handler function
>
>            timing = (struct itimerspec*) malloc(sizeof (struct  
> itimerspec));
>            timing->it_value.tv_sec = atoi(strtok(NULL, " "));
> //maxTime=Time of first arming (it's better to always use nanoseconds)
>            timing->it_interval = timing->it_value; //and time of all
> the subsequent armings
>
>            //4 - Create a timer for each rule
>            value = (timer_t*) malloc(sizeof (timer_t));
>            if (timer_create(CLOCK_REALTIME, event, value) != 0)
>                perror("Error during the creation of the timer");
>            if (timer_settime(*(value), 0, timing, NULL) != 0)
>                perror("Error during the setting of the timer");
>            //I try to insert the key (which corresponds to a rule) in
> the hashtable
>
>            key_concatenation = (char*) malloc(sizeof (char) *(18 * 2
> + 6 * 2 + 3));
>            strcat(key_concatenation, key->ip.src_addr);
>            strcat(key_concatenation, key->ip.src_port);
>            strcat(key_concatenation, key->ip.dst_addr);
>            strcat(key_concatenation, key->ip.dst_port);
>            if (!hashtable_insert(hashTable, key_concatenation, value))
>                perror("Error during the inserion of a key in the  
> hashtable");
>        }
>    }
>    fclose(rulesFile);
>    /* Add this preprocessor to the preprocessors list.
>     * To do this, pass the pointer to the "main" preprocessor's  
> function,
>     * that is, the function to be executed everytime a packet arrives
>     */
>    AddFuncToPreprocList(RequiredTrafficFunc, PRIORITY_APPLICATION,
> GENERATOR_SPP_REQUIREDTRAFFIC);
>    //If necessary, register a function to handle a termination order  
> (SIGTERM)
>    //AddFuncToCleanExitList(RequiredTrafficCleanExitFunction, NULL);
>    //Idem, but to handle a restart
>    //AddFuncToRestartList(RequiredTrafficRestartFunction, NULL);
> }
>
> /* The preprocessor's main function */
> void RequiredTrafficFunc(Packet* packet, void* context) {
>    //LogMessage("RequiredTraffic: The preprocessor's main function is
> being called...\n");
>    /* Here we should extract the information from the packet that are
> interesting to us,
>     * build a key with them, and see if there is a corresponding
> entry in the hash table.
>     * If there is one, we must set the timer corresponding to the
> reference present in the
>     * entry to its next period.
>     * The information that are of interest for us are:
>     * - Source addresses (both MAC and IP)
>     * - Source port
>     * - Destination addresses
>     * - Destination port
>     **/
>    /* We must consider all the possible 4 combinations:
>     * 1 - L2->L2
>     * 2 - L2->L3
>     * 3 - L3->L3
>     * 4 - L3->L2
>     */
>
>    //2
>
>    key = (Rule*) calloc(1, sizeof (Rule));
>
>    key->ip.src_addr = (char*) calloc(18, sizeof (char));
>    key->ip.src_port = (char*) calloc(6, sizeof (char));
>    arrayIntToEtherAddr(packet->eh->ether_src, key->ip.src_addr);
>    strcpy(key->ip.src_port, "any");
>
>    key->ip.dst_addr = (char*) calloc(INET_ADDRSTRLEN, sizeof (char));
>    key->ip.dst_port = (char*) calloc(6, sizeof (char));
>    if (inet_ntop(AF_INET, (void*) &(packet->iph->ip_dst),
> key->ip.dst_addr, (socklen_t) (sizeof (char) *
> INET_ADDRSTRLEN))==NULL)
>        perror("RequiredTraffic: Error during the reading of the
> packet's header");
>    //arrayIntToEtherAddr(packet->eh->ether_dst, key->ip.dst_addr);
>    strcpy(key->ip.dst_port, "any");
>
>    key_concatenation = (char*) calloc(18 + INET_ADDRSTRLEN + 6 * 2 +
> 1, sizeof (char));
>    strcat(key_concatenation, key->ip.src_addr);
>    strcat(key_concatenation, key->ip.src_port);
>    strcat(key_concatenation, key->ip.dst_addr);
>    strcat(key_concatenation, key->ip.dst_port);
>    free(key);
>
>    //Look for a specific rule
>    value = (timer_t*) malloc(sizeof (timer_t));
>    if ((value = hashtable_search(hashTable, key_concatenation)) !=  
> NULL) {
>        if (timer_gettime(*value, timing) != 0)
>            perror("Error during the retrieval of the timer");
>        timing->it_value = timing->it_interval; //it_value contains
> the time until the next timer expiration, so I reset it to it_interval
>        timer_settime(*value, 0, timing, NULL);
>    }
>    free(key_concatenation);
>
>    /*  Now consider L3/L4 rules (a packet must be considered by two
> points of view...)
>     *  The only differences are:
>     *  1 - Different size of the fields src_addr/dst_addr (but this
> can also be skipped)
>     *  2 - We (should) take into consideration the source and  
> destination port
>     */
> }
>
> void RequiredTrafficRestartFunction() {
> }
>
> void RequiredTrafficCleanExitFunction() {
>    /* Free pointers and other resources, for example */
> }
>
> void raiseAlarm(void* rule) {
>    struct RequiredTrafficRule* ruleOfReference = (struct
> RequiredTrafficRule*) rule;
>    char message[200];
>    sprintf(message, "Traffic missing:\n\t"
>            "Source address: %s\n\t"
>            "Source port: %s\n\t"
>            "Destination address: %s\n\t"
>            "Destination port: %s\n",
>            ruleOfReference->normalRule.ip.src_addr,
>            ruleOfReference->normalRule.ip.src_port,
>            ruleOfReference->normalRule.ip.dst_addr,
>            ruleOfReference->normalRule.ip.dst_port);
>    ALERT(SIGNATURE_ID_REQUIREDTRAFFIC, message);
> }
>
> void arrayIntToEtherAddr(u_int8_t src[], char* dst) {
>    char hexOctect[3]; //2 characters
>    int i;
>    for (i = 0; i < 6; i++) {
>        sprintf(hexOctect, "%02X", src[i]);
>        if (i > 0)
>            strcat(dst, ":");
>        strcat(dst, hexOctect);
>    }
> }
>
> static unsigned int hash(void *key) {
>    return RSHash(key, strlen(key));
> }
>
> static int keys_equal(void *key1, void *key2) {
>    if (hash(key1) == hash(key2))
>        return 1;
>    else
>        return 0;
> }
>
> This is a sample (sanitized) 'required.rules' file:
> required 00:xx:xx:xx:xx:xx any -> 74.125.39.104 any 15
> required 00:xx:xx:xx:xx:xx any -> 208.80.152.2 any 14
> required 00:xx:xx:xx:xx:xx any -> 72.5.124.51 any 10
> required 00:xx:xx:xx:xx:xx any -> 72.5.124.52 any 3
>
> When I debug Snort with gdb, that's the output of the program:
> ....
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> Initializing rule chains...
> 0 Snort rules read
>    0 detection rules
>    0 decoder rules
>    0 preprocessor rules
> 0 Option Chains linked into 0 Chain Headers
> 0 Dynamic rules
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>
> +-------------------[Rule Port  
> Counts]---------------------------------------
> |             tcp     udp    icmp      ip
> |     src       0       0       0       0
> |     dst       0       0       0       0
> |     any       0       0       0       0
> |      nc       0       0       0       0
> |     s+d       0       0       0       0
> + 
> ----------------------------------------------------------------------------
>
> +-----------------------[thresholding- 
> config]----------------------------------
> | memory-cap : 1048576 bytes
> +-----------------------[thresholding- 
> global]----------------------------------
> | none
> +-----------------------[thresholding- 
> local]-----------------------------------
> | none
> +----------------------- 
> [suppression]------------------------------------------
> | none
> -------------------------------------------------------------------------------
> Rule application order: activation->dynamic->pass->drop->alert->log
> Log directory = /var/log/snort
> Verifying Preprocessor Configurations!
> 0 out of 512 flowbits in use.
> Decoding Ethernet on interface eth0
>
>        --== Initialization Complete ==--
>
>   ,,_     -*> Snort! <*-
>  o"  )~   Version 2.8.1 (Build 28)
>   ''''    By Martin Roesch & The Snort Team: http://www.snort.org/team.html
>           (C) Copyright 1998-2008 Sourcefire Inc., et al.
>           Using PCRE version: 7.2 2007-06-19
>
>           Rules Engine: SF_SNORT_DETECTION_ENGINE  Version 1.8   
> <Build 13>
>           Preprocessor Object: SF_SSH  Version 1.1  <Build 1>
>           Preprocessor Object: SF_SMTP  Version 1.1  <Build 7>
>           Preprocessor Object: SF_FTPTELNET  Version 1.1  <Build 10>
>           Preprocessor Object: SF_DNS  Version 1.1  <Build 2>
>           Preprocessor Object: SF_DCERPC  Version 1.1  <Build 4>
> Not Using PCAP_FRAMES
> [New Thread -1242231920 (LWP 23636)]
> Traffic missing:
>        Source address: 00:xx:xx:xx:xx:xx
>        Source port: any
>        Destination address: 74.125.39.104
>        Destination port: any
> [Thread -1242231920 (LWP 23636) exited]
>
> [Other messages of missing traffic follow, printed using the function
> LogMessage() (SnortEventqAdd still doesn't work). After a while, when
> some traffic is listened on eth0, any traffic, a segmentation fault is
> raised on the function RequiredTrafficFunc(Packet* packet, void*
> context))
>
> Program received signal SIGSEGV, Segmentation fault.
> [Switching to Thread -1211107664 (LWP 23632)]
> 0xb7dfa003 in inet_ntop () from /lib/tls/i686/cmov/libc.so.6
> (gdb) bt
> #0  0xb7dfa003 in inet_ntop () from /lib/tls/i686/cmov/libc.so.6
> #1  0x080c85b6 in RequiredTrafficFunc (packet=0xbf94aa3c, context=0x0)
>    at spp_requiredtraffic.c:232
> #2  0x08068cc2 in Preprocess (p=0xbf94aa3c) at detect.c:176
> #3  0x08063108 in ProcessPacket (user=0x0, pkthdr=0xbf94ae40,
>    pkt=0x8cbd812 "������", ft=0x0) at snort.c:2085
> #4  0x0806332d in PcapProcessPacket (user=0x0, pkthdr=0xbf94ae40,
>    pkt=0x8cbd812 "������") at snort.c:1441
> #5  0xb7ea9d67 in ?? () from /usr/lib/libpcap.so.0.8
> #6  0x00000000 in ?? ()
> (gdb)
>
> I'm not very good in decoding gdb backtraces, but I don't like that
> 0x00000000 on stack #6. What could be the reason of the segmentation
> fault?
> Also, speaking of the functionality in itself, do you think it would
> be better to implement it in the 'main' Snort engine, so that I'll be
> able to use the same exact rule sintaxt of 'traditional'
> alert/log/pass rules, and the 'required' rules (new keyword) will be
> parsed automaticly by Snort functions, and put in the 3-D list that
> represents the various kind of rules? My only doubt in doing this is
> that I need to check for mandatory traffic not only on L3/L4, but also
> on L2 (Ethernet), and also mixed, so that it should be possible to
> check if packets from the NIC 00:xx:xx:xx:xx:xx toward the IP address
> xyz.xyz.xyz.xyz (mixed L2/L3 check) are flowing through the network.
> Could this be implemented in the main Snort engine, by extending the
> Rule struct and modifying the parser functions?
> Thanks
> -------------------------------------------------------------------------
> This SF.net email is sponsored by: Microsoft
> Defy all challenges. Microsoft(R) Visual Studio 2008.
> http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
> _______________________________________________
> Snort-devel mailing list
> Snort-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/snort-devel

- --
Martin Roesch - Founder/CTO, Sourcefire Inc. - +1-410-290-1616
Sourcefire - Security for the Real World - http://www.sourcefire.com
Snort: Open Source IDP - http://www.snort.org

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkgzSWUACgkQqj0FAQQ3KOAdtACfTCNS2DDkvwjeL0VJRFI+cTWL
Q7sAn3MjmNY5ARu3Gc2bMnq7QMCq0DyK
=Lo4/
-----END PGP SIGNATURE-----




More information about the Snort-devel mailing list