Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+28 −11
Original line number Diff line number Diff line
@@ -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;
+20 −2
Original line number Diff line number Diff line
@@ -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);
+5 −2
Original line number Diff line number Diff line
@@ -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;