[SPARC64]: Fix MD property lifetime bugs.

Property values cannot be referenced outside of
mdesc_grab()/mdesc_release() pairs.  The only major
offender was the VIO bus layer, easily fixed.

Add some commentary to mdesc.h describing these rules.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 64f0825..8b269aa 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -44,12 +44,11 @@
 
 	while (matches->type[0] || matches->compat[0]) {
 		int match = 1;
-		if (matches->type[0]) {
-			match &= type
-				&& !strcmp(matches->type, type);
-		}
+		if (matches->type[0])
+			match &= !strcmp(matches->type, type);
+
 		if (matches->compat[0]) {
-			match &= compat &&
+			match &= len &&
 				find_in_proplist(compat, matches->compat, len);
 		}
 		if (match)
@@ -205,15 +204,30 @@
 	const char *type, *compat;
 	struct device_node *dp;
 	struct vio_dev *vdev;
-	int err, clen;
+	int err, tlen, clen;
 
-	type = mdesc_get_property(hp, mp, "device-type", NULL);
+	type = mdesc_get_property(hp, mp, "device-type", &tlen);
 	if (!type) {
-		type = mdesc_get_property(hp, mp, "name", NULL);
-		if (!type)
+		type = mdesc_get_property(hp, mp, "name", &tlen);
+		if (!type) {
 			type = mdesc_node_name(hp, mp);
+			tlen = strlen(type) + 1;
+		}
 	}
+	if (tlen > VIO_MAX_TYPE_LEN) {
+		printk(KERN_ERR "VIO: Type string [%s] is too long.\n",
+		       type);
+		return NULL;
+	}
+
 	compat = mdesc_get_property(hp, mp, "device-type", &clen);
+	if (!compat) {
+		clen = 0;
+	} else if (clen > VIO_MAX_COMPAT_LEN) {
+		printk(KERN_ERR "VIO: Compat len %d for [%s] is too long.\n",
+		       clen, type);
+		return NULL;
+	}
 
 	vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
 	if (!vdev) {
@@ -222,8 +236,11 @@
 	}
 
 	vdev->mp = mp;
-	vdev->type = type;
-	vdev->compat = compat;
+	memcpy(vdev->type, type, tlen);
+	if (compat)
+		memcpy(vdev->compat, compat, clen);
+	else
+		memset(vdev->compat, 0, sizeof(vdev->compat));
 	vdev->compat_len = clen;
 
 	vdev->channel_id = ~0UL;
diff --git a/include/asm-sparc64/mdesc.h b/include/asm-sparc64/mdesc.h
index bbb0c0b..dc372df 100644
--- a/include/asm-sparc64/mdesc.h
+++ b/include/asm-sparc64/mdesc.h
@@ -23,8 +23,28 @@
 	     (__node) != MDESC_NODE_NULL; \
 	     __node = mdesc_node_by_name(__hdl, __node, __name))
 
+/* Access to property values returned from mdesc_get_property() are
+ * only valid inside of a mdesc_grab()/mdesc_release() sequence.
+ * Once mdesc_release() is called, the memory backed up by these
+ * pointers may reference freed up memory.
+ *
+ * Therefore callers must make copies of any property values
+ * they need.
+ *
+ * These same rules apply to mdesc_node_name().
+ */
 extern const void *mdesc_get_property(struct mdesc_handle *handle,
 				      u64 node, const char *name, int *lenp);
+extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node);
+
+/* MD arc iteration, the standard sequence is:
+ *
+ *	unsigned long arc;
+ *	mdesc_for_each_arc(arc, handle, node, MDESC_ARC_TYPE_{FWD,BACK}) {
+ *		unsigned long target = mdesc_arc_target(handle, arc);
+ *		...
+ *	}
+ */
 
 #define MDESC_ARC_TYPE_FWD	"fwd"
 #define MDESC_ARC_TYPE_BACK	"back"
@@ -38,8 +58,6 @@
 
 extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
 
-extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node);
-
 extern void mdesc_update(void);
 
 extern void sun4v_mdesc_init(void);
diff --git a/include/asm-sparc64/vio.h b/include/asm-sparc64/vio.h
index a8a53e6..83c9642 100644
--- a/include/asm-sparc64/vio.h
+++ b/include/asm-sparc64/vio.h
@@ -264,12 +264,15 @@
 		((dr->prod - dr->cons) & (ring_size - 1)));
 }
 
+#define VIO_MAX_TYPE_LEN	64
+#define VIO_MAX_COMPAT_LEN	64
+
 struct vio_dev {
 	u64			mp;
 	struct device_node	*dp;
 
-	const char		*type;
-	const char		*compat;
+	char			type[VIO_MAX_TYPE_LEN];
+	char			compat[VIO_MAX_COMPAT_LEN];
 	int			compat_len;
 
 	unsigned long		channel_id;