Thread (9 messages) flat view 9 messages, 2 authors, 2010-02-18

Re: [PATCH 4/5] xfrm: CONFIG_COMPAT support for x86 architecture

From: Johannes Berg <johannes@sipsolutions.net>
Date: 2010-02-18 07:57:43

On Mon, 2010-02-15 at 17:46 +0100, Florian Westphal wrote:
+static bool xfrm_msg_compat(const struct sk_buff *skb)
+{
+	return unlikely(!!NETLINK_CB(skb).msg_compat);
+}
The !! seems pointless but that's not why I'm quoting this here.

I think this function should only be used in the input path.
+static bool xfrm_add_compatskb(struct sk_buff *skb,
+                               unsigned int len, gfp_t gfp)
+{
I think this should return the new skb, and I don't think it should set
the msg_compat flag in the NETLINK_CB.
+static struct sk_buff *xfrm_get_compatskb(struct sk_buff *skb)
+{
making this no longer needed.
+/*
+ * avoids #ifdefs all over the place. Use of these must be
conditional via
+ * xfrm_add_compatskb/xfrm_get_compatskb so compiler can remove
branches.
+ */
+#define compat_xfrm_user_expire     xfrm_user_expire
+#define compat_xfrm_user_acquire    xfrm_user_acquire
+#define compat_xfrm_user_polexpire  xfrm_user_polexpire
+#define compat_xfrm_userpolicy_info xfrm_userpolicy_info
+#define compat_xfrm_usersa_info     xfrm_usersa_info
+#define compat_xfrm_userspi_info    xfrm_userspi_info
Good thing I didn't have to deal with compat _input_ in wireless since I
had killed the netlink input code :))
+#endif
+
+/*
+ * userspace size of some structures is smaller by this amount
+ * due to different u64 alignment on x86 platform.
+ *
+ * Some of the structures need to use the compat_* structure
definition
+ * when accessing certain members.
+ */
+static const u8 xfrm_msg_min_compat_pad[XFRM_NR_MSGTYPES] = {
+	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = 4, /* padding at end */
+	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = 4, /* padding at end */
+
+	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = 4, /* access might need
compat_ */
+	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = 4, /* access might need
compat_ */
+	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = 4, /* access might need
compat_ */
+	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = 4, /* padding at end */
+	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = 4, /* padding at end */
+	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = 4, /* access might need
compat_ */
+};
Shouldn't that be some sizeof() trickery instead of hardcoding 4?
+static int get_user_expire_hard(const struct sk_buff *skb,
+                                const struct xfrm_user_expire *ue)
+{
+	if (xfrm_msg_compat(skb)) {
+		const struct compat_xfrm_user_expire *cmpt;
+		cmpt = (const struct compat_xfrm_user_expire*) ue;
+		return cmpt->hard;
+	}
+	return ue->hard;
+}
That looks good to me, good use of the compat helper.
quoted hunk ↗ jump to hunk
@@ -700,6 +856,9 @@ static int copy_one_state(struct sk_buff *skb,
struct xfrm_state *x, struct xfrm
 	size_t len = sizeof(*p);
 	int err;
 
+	if (xfrm_msg_compat(skb))
+		len = sizeof(struct compat_xfrm_usersa_info);
+
I really dislike this use though.
quoted hunk ↗ jump to hunk
@@ -724,6 +883,13 @@ static int dump_one_state(struct xfrm_state *x,
int count, void *ptr)
 	struct xfrm_dump_info *sp = ptr;
 	struct sk_buff *skb = sp->out_skb;
 	int ret = copy_one_state(skb, x, sp);
+#ifdef CONFIG_COMPAT_FOR_U64_ALIGNMENT
+	if (ret == 0) {
+		skb = xfrm_get_compatskb(skb);
+		if (skb)
+			copy_one_state(skb, x, sp);
+	}
+#endif
 	return ret;
 }
And that's really convoluted.
quoted hunk ↗ jump to hunk
@@ -753,6 +919,8 @@ static int xfrm_dump_sa(struct sk_buff *skb,
struct netlink_callback *cb)
 		xfrm_state_walk_init(walk, 0);
 	}
 
+	xfrm_add_compatskb(skb, NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+
 	(void) xfrm_state_walk(net, walk, dump_one_state, &info);
 
 	return skb->len;
And this just seems wrong -- doesn't that fill _only_ the compat skb
here then??

(same thing happens again in this file)
quoted hunk ↗ jump to hunk
@@ -2200,6 +2455,9 @@ static int xfrm_exp_state_notify(struct
xfrm_state *x, struct km_event *c)
 	if (build_expire(skb, x, c) < 0)
 		BUG();
 
+	if (xfrm_add_compatskb(skb, compat_xfrm_expire_msgsize(), GFP_ATOMIC))
+		compat_build_expire(skb_shinfo(skb)->frag_list, x, c);
This is a good model, although I'd change it to be like this:

if (cskb = xfrm_add_compatskb(skb, ...))
compat_build_expire(cskb, x, c);

And I think the code would be a lot clearer if the other user were like

build_foo(skb, ..., false /* not compat */);
if ((cskb = xfrm_add_compatskb(skb, ...)))
build_foo(cskb, ..., true /* compat */);

instead of all the trickery with setting msg_compat on the output path
and then checking it again in the fill functions.

So for example:
quoted hunk ↗ jump to hunk
@@ -2302,6 +2567,11 @@ static int copy_to_user_xfrm_notify_sa(struct
sk_buff *skb,
 	int sizeof_xfrm_usersa_info = sizeof(*p);
 	int headlen = xfrm_notify_sa_headlen(c);
 
+	if (xfrm_msg_compat(skb)) {
+		headlen = compat_xfrm_notify_sa_headlen(c);
+		sizeof_xfrm_usersa_info = sizeof(struct compat_xfrm_usersa_info);
+	}
That'd get a compat parameter, and use it here instead of the
xfrm_msg_compat(skb) check.
quoted hunk ↗ jump to hunk
	nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0);
 	if (nlh == NULL)
 		goto nla_put_failure;
@@ -2347,6 +2617,9 @@ static int xfrm_notify_sa(struct xfrm_state *x,
struct km_event *c)
 	if (copy_to_user_xfrm_notify_sa(skb, x, c))
 		goto nla_put_failure;
 
+	if (xfrm_add_compatskb(skb, len, GFP_ATOMIC))
+		copy_to_user_xfrm_notify_sa(skb_shinfo(skb)->frag_list, x, c);
and instead of touching frag_list here, you'd pass the result of
xfrm_add_compatskb().

That way, the use of xfrm_msg_compat() is restricted to the input path,
which I think is much clearer.

johannes 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help