libprelude/master: Prevent unsafe modification of Libprelude provided Analyzer object

[email protected] Wed, 20 Jan 2010 16:16:09 +0100 (CET)
Newsgroups gmane.comp.security.ids.prelude.cvs
Message-ID <[email protected]>
commit 6d43c53505a3071d4b66e4d2a4aa13a56bb80934
Author: Yoann Vandoorselaere <[email protected]>
Date:   Wed Jan 20 15:51:54 2010 +0100

    Prevent unsafe modification of Libprelude provided Analyzer object
    
    Modifying the idmef_node_t or idmef_address_t object within an
    idmef_analyzer_t retrieved through prelude_client_get_analyzer()
    could result in undefined behavior when the analyzer was later
    accessed through the administrative console.


========================================

 src/include/prelude-option.h |   15 +++--
 src/prelude-client.c         |  136 +++++++++++++++++++++++++++++++++++-------
 src/prelude-option.c         |   13 ++++
 3 files changed, 137 insertions(+), 27 deletions(-)

========================================

diff --git a/src/include/prelude-option.h b/src/include/prelude-option.h
index 7d15835..2506a94 100644
--- a/src/include/prelude-option.h
+++ b/src/include/prelude-option.h
@@ -40,18 +40,18 @@ typedef enum {
         PRELUDE_OPTION_TYPE_DESTROY = 0x20
 } prelude_option_type_t;
 
-         
+
 typedef enum {
         PRELUDE_OPTION_INPUT_TYPE_STRING   = 1,
         PRELUDE_OPTION_INPUT_TYPE_INTEGER  = 2,
         PRELUDE_OPTION_INPUT_TYPE_BOOLEAN  = 3
 } prelude_option_input_type_t;
-         
+
 
 typedef struct prelude_option prelude_option_t;
 typedef struct prelude_option_context prelude_option_context_t;
 
-typedef int (*prelude_option_destroy_callback_t)(prelude_option_t *opt, prelude_string_t *out, void *context);         
+typedef int (*prelude_option_destroy_callback_t)(prelude_option_t *opt, prelude_string_t *out, void *context);
 typedef int (*prelude_option_commit_callback_t)(prelude_option_t *opt, prelude_string_t *out, void *context);
 typedef int (*prelude_option_get_callback_t)(prelude_option_t *opt, prelude_string_t *out, void *context);
 typedef int (*prelude_option_set_callback_t)(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context);
@@ -170,7 +170,7 @@ prelude_option_t *prelude_option_get_parent(prelude_option_t *opt);
 
 void prelude_option_set_destroy_callback(prelude_option_t *opt,
                                          prelude_option_destroy_callback_t destroy);
-         
+
 prelude_option_destroy_callback_t prelude_option_get_destroy_callback(prelude_option_t *opt);
 
 
@@ -195,14 +195,17 @@ int prelude_option_new_context(prelude_option_t *opt, prelude_option_context_t *
 
 void prelude_option_context_destroy(prelude_option_context_t *oc);
 
+void *prelude_option_context_get_data(prelude_option_context_t *oc);
+
+void prelude_option_context_set_data(prelude_option_context_t *oc, void *data);
 
 prelude_option_t *prelude_option_search(prelude_option_t *parent, const char *name,
                                         prelude_option_type_t type, prelude_bool_t walk_children);
 
 prelude_option_context_t *prelude_option_search_context(prelude_option_t *opt, const char *name);
-         
+
 #ifdef __cplusplus
  }
 #endif
-         
+
 #endif /* _LIBPRELUDE_PRELUDE_GETOPT_H */
diff --git a/src/prelude-client.c b/src/prelude-client.c
index 5fc7f66..17ffead 100644
--- a/src/prelude-client.c
+++ b/src/prelude-client.c
@@ -90,6 +90,13 @@
 
 
 
+typedef struct {
+        prelude_client_t *client;
+        idmef_address_t *addr;
+        idmef_address_t *idmef_addr;
+} node_address_data_t;
+
+
 struct prelude_client {
 
         int refcount;
@@ -498,12 +505,13 @@ static int fill_client_infos(prelude_client_t *client, const char *program)
 static int set_node_address_category(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
 {
         idmef_address_category_t category;
+        node_address_data_t *data = context;
 
         category = idmef_address_category_to_numeric(optarg);
         if ( category < 0 )
                 return category;
 
-        idmef_address_set_category(context, category);
+        idmef_address_set_category(data->addr, category);
 
         return 0;
 }
@@ -512,7 +520,8 @@ static int set_node_address_category(prelude_option_t *opt, const char *optarg,
 
 static int get_node_address_category(prelude_option_t *opt, prelude_string_t *out, void *context)
 {
-        idmef_address_category_t category = idmef_address_get_category(context);
+        node_address_data_t *data = context;
+        idmef_address_category_t category = idmef_address_get_category(data->addr);
         return prelude_string_cat(out, idmef_address_category_to_string(category));
 }
 
@@ -520,10 +529,12 @@ static int get_node_address_category(prelude_option_t *opt, prelude_string_t *ou
 
 static int set_node_address_vlan_num(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
 {
+        node_address_data_t *data = context;
+
         if ( ! optarg )
-                idmef_address_unset_vlan_num(context);
+                idmef_address_unset_vlan_num(data->addr);
         else
-                idmef_address_set_vlan_num(context, atoi(optarg));
+                idmef_address_set_vlan_num(data->addr, atoi(optarg));
 
         return 0;
 }
@@ -533,8 +544,9 @@ static int set_node_address_vlan_num(prelude_option_t *opt, const char *optarg,
 static int get_node_address_vlan_num(prelude_option_t *opt, prelude_string_t *out, void *context)
 {
         int32_t *num;
+        node_address_data_t *data = context;
 
-        num = idmef_address_get_vlan_num(context);
+        num = idmef_address_get_vlan_num(data->addr);
         if ( num )
                 return prelude_string_sprintf(out, "%" PRELUDE_PRId32, *num);
 
@@ -547,6 +559,7 @@ static int set_node_address_vlan_name(prelude_option_t *opt, const char *optarg,
 {
         int ret;
         prelude_string_t *str = NULL;
+        node_address_data_t *data = context;
 
         if ( optarg ) {
                 ret = prelude_string_new_dup(&str, optarg);
@@ -554,7 +567,7 @@ static int set_node_address_vlan_name(prelude_option_t *opt, const char *optarg,
                         return ret;
         }
 
-        idmef_address_set_vlan_name(context, str);
+        idmef_address_set_vlan_name(data->addr, str);
 
         return 0;
 }
@@ -564,8 +577,9 @@ static int set_node_address_vlan_name(prelude_option_t *opt, const char *optarg,
 static int get_node_address_vlan_name(prelude_option_t *opt, prelude_string_t *out, void *context)
 {
         prelude_string_t *str;
+        node_address_data_t *data = context;
 
-        str = idmef_address_get_vlan_name(context);
+        str = idmef_address_get_vlan_name(data->addr);
         if ( ! str )
                 return 0;
 
@@ -578,6 +592,7 @@ static int set_node_address_address(prelude_option_t *opt, const char *optarg, p
 {
         int ret;
         prelude_string_t *str = NULL;
+        node_address_data_t *data = context;
 
         if ( optarg ) {
                 ret = prelude_string_new_dup(&str, optarg);
@@ -585,7 +600,7 @@ static int set_node_address_address(prelude_option_t *opt, const char *optarg, p
                         return ret;
         }
 
-        idmef_address_set_address(context, str);
+        idmef_address_set_address(data->addr, str);
         return 0;
 }
 
@@ -594,8 +609,9 @@ static int set_node_address_address(prelude_option_t *opt, const char *optarg, p
 static int get_node_address_address(prelude_option_t *opt, prelude_string_t *out, void *context)
 {
         prelude_string_t *str;
+        node_address_data_t *data = context;
 
-        str = idmef_address_get_address(context);
+        str = idmef_address_get_address(data->addr);
         if ( ! str )
                 return 0;
 
@@ -608,6 +624,7 @@ static int set_node_address_netmask(prelude_option_t *opt, const char *optarg, p
 {
         int ret;
         prelude_string_t *str = NULL;
+        node_address_data_t *data = context;
 
         if ( optarg ) {
                 ret = prelude_string_new_dup(&str, optarg);
@@ -615,7 +632,7 @@ static int set_node_address_netmask(prelude_option_t *opt, const char *optarg, p
                         return ret;
         }
 
-        idmef_address_set_netmask(context, str);
+        idmef_address_set_netmask(data->addr, str);
         return 0;
 }
 
@@ -624,8 +641,9 @@ static int set_node_address_netmask(prelude_option_t *opt, const char *optarg, p
 static int get_node_address_netmask(prelude_option_t *opt, prelude_string_t *out, void *context)
 {
         prelude_string_t *str;
+        node_address_data_t *data = context;
 
-        str = idmef_address_get_netmask(context);
+        str = idmef_address_get_netmask(data->addr);
         if ( ! str )
                 return 0;
 
@@ -634,35 +652,110 @@ static int get_node_address_netmask(prelude_option_t *opt, prelude_string_t *out
 
 
 
+
 static int set_node_address(prelude_option_t *opt, const char *optarg, prelude_string_t *err, void *context)
 {
         int ret;
-        idmef_node_t *node;
-        idmef_address_t *addr;
+        node_address_data_t *data;
         prelude_option_context_t *octx;
         prelude_client_t *ptr = context;
 
-        if ( prelude_option_search_context(opt, optarg) )
+        octx = prelude_option_search_context(opt, optarg);
+        if ( octx )
                 return 0;
 
-        ret = idmef_analyzer_new_node(ptr->analyzer, &node);
+        data = malloc(sizeof(*data));
+        if ( ! data )
+                return prelude_error_from_errno(errno);
+
+        data->client = ptr;
+        data->idmef_addr = NULL;
+
+        ret = idmef_address_new(&data->addr);
+        if ( ret < 0 ) {
+                free(data);
+                return ret;
+        }
+
+        ret = prelude_option_new_context(opt, &octx, optarg, data);
+        if ( ret < 0 ) {
+                idmef_address_destroy(data->addr);
+                free(data);
+        }
+
+        return ret;
+}
+
+
+static int commit_node_address(prelude_option_t *opt, prelude_string_t *out, void *context)
+{
+        int ret;
+        idmef_node_t *node;
+        idmef_analyzer_t *analyzer;
+        idmef_address_t *addr = NULL, *naddr;
+        node_address_data_t *data = context;
+
+        ret = idmef_analyzer_new_node(data->client->analyzer, &node);
         if ( ret < 0 )
                 return ret;
 
-        ret = idmef_node_new_address(node, &addr, -1);
+        if ( node && data->idmef_addr ) {
+                while ( (addr = idmef_node_get_next_address(node, addr)) ) {
+                        if ( addr == data->idmef_addr ) {
+                                idmef_address_destroy(addr);
+                                break;
+                        }
+                }
+        }
+
+        ret = idmef_address_clone(data->addr, &naddr);
         if ( ret < 0 )
-                return -1;
+                return ret;
 
-        return prelude_option_new_context(opt, &octx, optarg, addr);
-}
+        data->idmef_addr = naddr;
+        idmef_node_set_address(node, naddr, -1);
+
+        if ( data->client->_analyzer_copy ) {
+                ret = idmef_analyzer_clone(data->client->analyzer, &analyzer);
+                if ( ret < 0 )
+                        return ret;
 
+                idmef_analyzer_destroy(data->client->_analyzer_copy);
+                data->client->_analyzer_copy = analyzer;
+        }
+
+        return 0;
+}
 
 
 static int destroy_node_address(prelude_option_t *opt, prelude_string_t *out, void *context)
 {
-        idmef_address_t *addr = context;
+        int ret;
+        idmef_node_t *node;
+        idmef_analyzer_t *analyzer;
+        idmef_address_t *addr = NULL;
+        node_address_data_t *data = context;
+
+        node = idmef_analyzer_get_node(data->client->analyzer);
+        if ( node ) {
+                while ( (addr = idmef_node_get_next_address(node, addr)) ) {
+                        if ( addr == data->idmef_addr ) {
+                                idmef_address_destroy(addr);
+                                break;
+                        }
+                }
+        }
+
+        if ( data->client->_analyzer_copy ) {
+                ret = idmef_analyzer_clone(data->client->analyzer, &analyzer);
+                if ( ret == 0 ) {
+                        idmef_analyzer_destroy(data->client->_analyzer_copy);
+                        data->client->_analyzer_copy = analyzer;
+                }
+        }
 
-        idmef_address_destroy(addr);
+        idmef_address_destroy(data->addr);
+        free(data);
 
         return 0;
 }
@@ -1097,6 +1190,7 @@ int _prelude_client_register_options(void)
         if ( ret < 0 )
                 return ret;
 
+        prelude_option_set_commit_callback(opt, commit_node_address);
         prelude_option_set_destroy_callback(opt, destroy_node_address);
 
         ret = prelude_option_add(opt, NULL, PRELUDE_OPTION_TYPE_CFG|PRELUDE_OPTION_TYPE_WIDE, 0, "address",
diff --git a/src/prelude-option.c b/src/prelude-option.c
index 72364ad..61b7b1e 100644
--- a/src/prelude-option.c
+++ b/src/prelude-option.c
@@ -1610,6 +1610,19 @@ int prelude_option_new_context(prelude_option_t *opt, prelude_option_context_t *
 }
 
 
+void prelude_option_context_set_data(prelude_option_context_t *oc, void *data)
+{
+        oc->data = data;
+}
+
+
+
+void *prelude_option_context_get_data(prelude_option_context_t *oc)
+{
+        return oc->data;
+}
+
+
 
 void prelude_option_context_destroy(prelude_option_context_t *oc)
 {
_______________________________________________
Prelude-cvslog site list
[email protected]
http://lists.prelude-ids.org/mailman/listinfo/prelude-cvslog