]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
[SPARC64]: Fix MD property lifetime bugs.
authorDavid S. Miller <davem@sunset.davemloft.net>
Thu, 12 Jul 2007 21:16:22 +0000 (14:16 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 16 Jul 2007 11:04:33 +0000 (04:04 -0700)
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>
arch/sparc64/kernel/vio.c
include/asm-sparc64/mdesc.h
include/asm-sparc64/vio.h

index 64f082555bcd243431c8b1db7d880eabe2f3f2f5..8b269aabff070c1dd4e3f1350293fb8764120e25 100644 (file)
@@ -44,12 +44,11 @@ static const struct vio_device_id *vio_match_device(
 
        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 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        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 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
        }
 
        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;
index bbb0c0bed486051527a26ee5f75b5ed6707c6259..dc372df23fb350109e44b7db0fe2b5fa63afa657 100644 (file)
@@ -23,8 +23,28 @@ extern u64 mdesc_node_by_name(struct mdesc_handle *handle,
             (__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_next_arc(struct mdesc_handle *handle, u64 from,
 
 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);
index a8a53e6fc2509658e77d61ef4fb20f2eb9091366..83c96422e9d61deba94a0cb9ee446b81d1b7a266 100644 (file)
@@ -264,12 +264,15 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
                ((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;