Commit 83292e0a authored by David S. Miller's avatar David S. Miller

[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: default avatarDavid S. Miller <davem@davemloft.net>
parent 43fdf274
......@@ -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", &tlen);
if (!type) {
type = mdesc_get_property(hp, mp, "name", NULL);
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;
......
......@@ -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);
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment