From 839085f8026afd6f6920a0c31ad2a9d880d97932 Mon Sep 17 00:00:00 2001
From: Stephen C North <scnorth@gmail.com>
Date: Tue, 9 Apr 2019 12:38:23 -0400
Subject: [PATCH] attempted fix for null pointer deference on malformed input

---
 cmd/tools/graphml2gv.c | 36 +++++++++++++++++++++---------------
 lib/cgraph/grammar.y   |  8 ++++++++
 lib/cgraph/obj.c       |  2 ++
 3 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/cmd/tools/graphml2gv.c b/cmd/tools/graphml2gv.c
index f4798089e..b9fc9730c 100644
--- a/cmd/tools/graphml2gv.c
+++ b/cmd/tools/graphml2gv.c
@@ -468,8 +468,10 @@ startElementHandler(void *userData, const char *name, const char **atts)
 	if (pos > 0) {
 	    const char *attrname;
 	    attrname = atts[pos];
-
-	    bind_node(attrname);
+            if (G == 0)
+                fprintf(stderr,"node %s outside graph, ignored\n",attrname);
+	    else
+                bind_node(attrname);
 
 	    pushString(&ud->elements, attrname);
 	}
@@ -495,21 +497,25 @@ startElementHandler(void *userData, const char *name, const char **atts)
 	if (tname)
 	    head = tname;
 
-	bind_edge(tail, head);
+        if (G == 0)
+            fprintf(stderr,"edge source %s target %s outside graph, ignored\n",(char*)tail,(char*)head);
+        else {
+            bind_edge(tail, head);
 
-	t = AGTAIL(E);
-	tname = agnameof(t);
+            t = AGTAIL(E);
+	    tname = agnameof(t);
 
-	if (strcmp(tname, tail) == 0) {
-	    ud->edgeinverted = FALSE;
-	} else if (strcmp(tname, head) == 0) {
-	    ud->edgeinverted = TRUE;
-	}
+	    if (strcmp(tname, tail) == 0) {
+	        ud->edgeinverted = FALSE;
+	    } else if (strcmp(tname, head) == 0) {
+	        ud->edgeinverted = TRUE;
+	    }
 
-	pos = get_xml_attr("id", atts);
-	if (pos > 0) {
-	    setEdgeAttr(E, GRAPHML_ID, (char *) atts[pos], ud);
-	}
+	    pos = get_xml_attr("id", atts);
+	    if (pos > 0) {
+	        setEdgeAttr(E, GRAPHML_ID, (char *) atts[pos], ud);
+	    }
+        }
     } else {
 	/* must be some extension */
 	fprintf(stderr,
@@ -530,7 +536,7 @@ static void endElementHandler(void *userData, const char *name)
 	char *ele_name = topString(ud->elements);
 	if (ud->closedElementType == TAG_GRAPH) {
 	    Agnode_t *node = agnode(root, ele_name, 0);
-	    agdelete(root, node);
+	    if (node) agdelete(root, node);
 	}
 	popString(&ud->elements);
 	Current_class = TAG_GRAPH;
diff --git a/lib/cgraph/grammar.y b/lib/cgraph/grammar.y
index 90aa27387..127a7241a 100644
--- a/lib/cgraph/grammar.y
+++ b/lib/cgraph/grammar.y
@@ -22,6 +22,7 @@ extern void yyerror(char *);	/* gets mapped to aagerror, see below */
 #endif
 
 static char Key[] = "key";
+static int SubgraphDepth = 0;
 
 typedef union s {					/* possible items in generic list */
 		Agnode_t		*n;
@@ -542,6 +543,7 @@ static void startgraph(char *name, int directed, int strict)
 	static Agdesc_t	req;	/* get rid of warnings */
 
 	if (G == NILgraph) {
+    SubgraphDepth = 0;
 		req.directed = directed;
 		req.strict = strict;
 		req.maingraph = TRUE;
@@ -562,6 +564,11 @@ static void endgraph()
 
 static void opensubg(char *name)
 {
+  if (++SubgraphDepth >= YYMAXDEPTH/2) {
+    char buf[128];
+    sprintf(buf,"subgraphs nested more than %d deep",YYMAXDEPTH);
+    agerr(AGERR,buf);
+  }
 	S = push(S,agsubg(S->g,name,TRUE));
 	agstrfree(G,name);
 }
@@ -569,6 +576,7 @@ static void opensubg(char *name)
 static void closesubg()
 {
 	Agraph_t *subg = S->g;
+  --SubgraphDepth;
 	S = pop(S);
 	S->subg = subg;
 	assert(subg);
diff --git a/lib/cgraph/obj.c b/lib/cgraph/obj.c
index 7b1c8c101..709774e3d 100644
--- a/lib/cgraph/obj.c
+++ b/lib/cgraph/obj.c
@@ -168,6 +168,8 @@ void agdelcb(Agraph_t * g, void *obj, Agcbstack_t * cbstack)
 
 Agraph_t *agroot(void* obj)
 {
+    // fixes CVE-2019-11023 by moving the problem to the caller :-)
+    if (obj == 0) return NILgraph; 
     switch (AGTYPE(obj)) {
     case AGINEDGE:
     case AGOUTEDGE:
-- 
2.21.0

