Add several new message types to address longstanding 32-bit/64-bit
compatibility issues.  Use xfrm_user_legacy to handle the existing
message types, which will retain the old IDs for compatibility with
existing binaries.

For user->kernel messages, the nlmsg_type will determine whether to use
the old format or the new format (for both requests and replies).  For
kernel->user multicasts, both types will be sent.

setsockopt() will deduce the format from the length.

Signed-off-by: Kevin Cernekee <cerne...@chromium.org>
---
 include/uapi/linux/xfrm.h   | 152 ++++++++++++++++++++++++++++++---------
 net/xfrm/xfrm_user.c        | 136 ++++++++++++++++++++++++++++++++---
 net/xfrm/xfrm_user.h        |  75 ++++++++++++++++++++
 net/xfrm/xfrm_user_legacy.c | 169 ++++++++++++++++++++++++++++----------------
 security/selinux/nlmsgtab.c |  61 +++++++++-------
 5 files changed, 466 insertions(+), 127 deletions(-)

diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
index 1fc62b239f1b..ae5f97681989 100644
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -1,6 +1,7 @@
 #ifndef _LINUX_XFRM_H
 #define _LINUX_XFRM_H
 
+#include <linux/compiler.h>
 #include <linux/in6.h>
 #include <linux/types.h>
 
@@ -157,34 +158,34 @@ enum {
 enum {
        XFRM_MSG_BASE = 0x10,
 
-       XFRM_MSG_NEWSA = 0x10,
-#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA
-       XFRM_MSG_DELSA,
-#define XFRM_MSG_DELSA XFRM_MSG_DELSA
-       XFRM_MSG_GETSA,
-#define XFRM_MSG_GETSA XFRM_MSG_GETSA
-
-       XFRM_MSG_NEWPOLICY,
-#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY
-       XFRM_MSG_DELPOLICY,
-#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY
-       XFRM_MSG_GETPOLICY,
-#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY
-
-       XFRM_MSG_ALLOCSPI,
-#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI
-       XFRM_MSG_ACQUIRE,
-#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE
-       XFRM_MSG_EXPIRE,
-#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE
-
-       XFRM_MSG_UPDPOLICY,
-#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY
-       XFRM_MSG_UPDSA,
-#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA
-
-       XFRM_MSG_POLEXPIRE,
-#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE
+       XFRM_MSG_NEWSA_LEGACY = 0x10,
+#define XFRM_MSG_NEWSA_LEGACY XFRM_MSG_NEWSA_LEGACY
+       XFRM_MSG_DELSA_LEGACY,
+#define XFRM_MSG_DELSA_LEGACY XFRM_MSG_DELSA_LEGACY
+       XFRM_MSG_GETSA_LEGACY,
+#define XFRM_MSG_GETSA_LEGACY XFRM_MSG_GETSA_LEGACY
+
+       XFRM_MSG_NEWPOLICY_LEGACY,
+#define XFRM_MSG_NEWPOLICY_LEGACY XFRM_MSG_NEWPOLICY_LEGACY
+       XFRM_MSG_DELPOLICY_LEGACY,
+#define XFRM_MSG_DELPOLICY_LEGACY XFRM_MSG_DELPOLICY_LEGACY
+       XFRM_MSG_GETPOLICY_LEGACY,
+#define XFRM_MSG_GETPOLICY_LEGACY XFRM_MSG_GETPOLICY_LEGACY
+
+       XFRM_MSG_ALLOCSPI_LEGACY,
+#define XFRM_MSG_ALLOCSPI_LEGACY XFRM_MSG_ALLOCSPI_LEGACY
+       XFRM_MSG_ACQUIRE_LEGACY,
+#define XFRM_MSG_ACQUIRE_LEGACY XFRM_MSG_ACQUIRE_LEGACY
+       XFRM_MSG_EXPIRE_LEGACY,
+#define XFRM_MSG_EXPIRE_LEGACY XFRM_MSG_EXPIRE_LEGACY
+
+       XFRM_MSG_UPDPOLICY_LEGACY,
+#define XFRM_MSG_UPDPOLICY_LEGACY XFRM_MSG_UPDPOLICY_LEGACY
+       XFRM_MSG_UPDSA_LEGACY,
+#define XFRM_MSG_UPDSA_LEGACY XFRM_MSG_UPDSA_LEGACY
+
+       XFRM_MSG_POLEXPIRE_LEGACY,
+#define XFRM_MSG_POLEXPIRE_LEGACY XFRM_MSG_POLEXPIRE_LEGACY
 
        XFRM_MSG_FLUSHSA,
 #define XFRM_MSG_FLUSHSA XFRM_MSG_FLUSHSA
@@ -214,6 +215,34 @@ enum {
 
        XFRM_MSG_MAPPING,
 #define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
+
+       XFRM_MSG_ALLOCSPI,
+#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI
+       XFRM_MSG_ACQUIRE,
+#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE
+       XFRM_MSG_EXPIRE,
+#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE
+       XFRM_MSG_POLEXPIRE,
+#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE
+
+       XFRM_MSG_NEWSA,
+#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA
+       XFRM_MSG_UPDSA,
+#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA
+       XFRM_MSG_DELSA,
+#define XFRM_MSG_DELSA XFRM_MSG_DELSA
+       XFRM_MSG_GETSA,
+#define XFRM_MSG_GETSA XFRM_MSG_GETSA
+
+       XFRM_MSG_NEWPOLICY,
+#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY
+       XFRM_MSG_UPDPOLICY,
+#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY
+       XFRM_MSG_DELPOLICY,
+#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY
+       XFRM_MSG_GETPOLICY,
+#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY
+
        __XFRM_MSG_MAX
 };
 #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -221,7 +250,7 @@ enum {
 #define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)
 
 /*
- * Generic LSM security context for comunicating to user space
+ * Generic LSM security context for communicating to user space
  * NOTE: Same format as sadb_x_sec_ctx
  */
 struct xfrm_user_sec_ctx {
@@ -357,6 +386,22 @@ struct xfrmu_spdhthresh {
        __u8 rbits;
 };
 
+/* Legacy structs are incompatible between 32-bit and 64-bit. */
+struct xfrm_usersa_info_legacy {
+       struct xfrm_selector            sel;
+       struct xfrm_id                  id;
+       xfrm_address_t                  saddr;
+       struct xfrm_lifetime_cfg        lft;
+       struct xfrm_lifetime_cur        curlft;
+       struct xfrm_stats               stats;
+       __u32                           seq;
+       __u32                           reqid;
+       __u16                           family;
+       __u8                            mode;           /* XFRM_MODE_xxx */
+       __u8                            replay_window;
+       __u8                            flags;
+};
+
 struct xfrm_usersa_info {
        struct xfrm_selector            sel;
        struct xfrm_id                  id;
@@ -378,7 +423,8 @@ struct xfrm_usersa_info {
 #define XFRM_STATE_AF_UNSPEC   32
 #define XFRM_STATE_ALIGN4      64
 #define XFRM_STATE_ESN         128
-};
+       __u8                            reserved[7];
+} __packed;
 
 #define XFRM_SA_XFLAG_DONT_ENCAP_DSCP  1
 
@@ -396,10 +442,28 @@ struct xfrm_aevent_id {
        __u32                           reqid;
 };
 
+struct xfrm_userspi_info_legacy {
+       struct xfrm_usersa_info_legacy  info;
+       __u32                           min;
+       __u32                           max;
+};
+
 struct xfrm_userspi_info {
        struct xfrm_usersa_info         info;
        __u32                           min;
        __u32                           max;
+} __packed;
+
+struct xfrm_userpolicy_info_legacy {
+       struct xfrm_selector            sel;
+       struct xfrm_lifetime_cfg        lft;
+       struct xfrm_lifetime_cur        curlft;
+       __u32                           priority;
+       __u32                           index;
+       __u8                            dir;
+       __u8                            action;
+       __u8                            flags;
+       __u8                            share;
 };
 
 struct xfrm_userpolicy_info {
@@ -417,7 +481,8 @@ struct xfrm_userpolicy_info {
        /* Automatically expand selector to include matching ICMP payloads. */
 #define XFRM_POLICY_ICMP       2
        __u8                            share;
-};
+       __u8                            reserved[4];
+} __packed;
 
 struct xfrm_userpolicy_id {
        struct xfrm_selector            sel;
@@ -425,6 +490,17 @@ struct xfrm_userpolicy_id {
        __u8                            dir;
 };
 
+struct xfrm_user_acquire_legacy {
+       struct xfrm_id                          id;
+       xfrm_address_t                          saddr;
+       struct xfrm_selector                    sel;
+       struct xfrm_userpolicy_info_legacy      policy;
+       __u32                                   aalgos;
+       __u32                                   ealgos;
+       __u32                                   calgos;
+       __u32                                   seq;
+};
+
 struct xfrm_user_acquire {
        struct xfrm_id                  id;
        xfrm_address_t                  saddr;
@@ -434,17 +510,29 @@ struct xfrm_user_acquire {
        __u32                           ealgos;
        __u32                           calgos;
        __u32                           seq;
+} __packed;
+
+struct xfrm_user_expire_legacy {
+       struct xfrm_usersa_info_legacy  state;
+       __u8                            hard;
 };
 
 struct xfrm_user_expire {
        struct xfrm_usersa_info         state;
        __u8                            hard;
+       __u8                            reserved[7];
+} __packed;
+
+struct xfrm_user_polexpire_legacy {
+       struct xfrm_userpolicy_info_legacy      pol;
+       __u8                                    hard;
 };
 
 struct xfrm_user_polexpire {
        struct xfrm_userpolicy_info     pol;
        __u8                            hard;
-};
+       __u8                            reserved[7];
+} __packed;
 
 struct xfrm_usersa_flush {
        __u8                            proto;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 4d733f02c3a1..5456dde974bc 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -2350,6 +2350,32 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
        [XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
        [XFRM_MSG_NEWSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
        [XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
+
+       [XFRM_MSG_ALLOCSPI_LEGACY  - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_userspi_info_legacy),
+       [XFRM_MSG_ACQUIRE_LEGACY   - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_user_acquire_legacy),
+       [XFRM_MSG_EXPIRE_LEGACY    - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_user_expire_legacy),
+       [XFRM_MSG_POLEXPIRE_LEGACY - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_user_polexpire_legacy),
+
+       [XFRM_MSG_NEWSA_LEGACY     - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_usersa_info_legacy),
+       [XFRM_MSG_UPDSA_LEGACY     - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_usersa_info_legacy),
+       [XFRM_MSG_DELSA_LEGACY     - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_usersa_id),
+       [XFRM_MSG_GETSA_LEGACY     - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_usersa_id),
+       [XFRM_MSG_NEWPOLICY_LEGACY - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_userpolicy_info_legacy),
+       [XFRM_MSG_UPDPOLICY_LEGACY - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_userpolicy_info_legacy),
+       [XFRM_MSG_DELPOLICY_LEGACY - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_userpolicy_id),
+       [XFRM_MSG_GETPOLICY_LEGACY - XFRM_MSG_BASE] =
+               XMSGSIZE(xfrm_userpolicy_id),
 };
 
 #undef XMSGSIZE
@@ -2396,6 +2422,7 @@ static const struct xfrm_link {
        int (*done)(struct netlink_callback *);
        const struct nla_policy *nla_pol;
        int nla_max;
+       bool legacy;
 } xfrm_dispatch[XFRM_NR_MSGTYPES] = {
        [XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
        [XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        },
@@ -2423,6 +2450,62 @@ static const struct xfrm_link {
                                                   .nla_pol = xfrma_spd_policy,
                                                   .nla_max = XFRMA_SPD_MAX },
        [XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo   },
+
+#ifdef CONFIG_XFRM_USER_LEGACY
+       [XFRM_MSG_ALLOCSPI_LEGACY  - XFRM_MSG_BASE] = {
+               .doit = xfrm_alloc_userspi_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_ACQUIRE_LEGACY   - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_acquire_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_EXPIRE_LEGACY    - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_sa_expire_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_POLEXPIRE_LEGACY - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_pol_expire_legacy,
+               .legacy = true,
+       },
+
+       [XFRM_MSG_NEWSA_LEGACY     - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_sa_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_UPDSA_LEGACY     - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_sa_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_DELSA_LEGACY     - XFRM_MSG_BASE] = {
+               .doit = xfrm_del_sa_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_GETSA_LEGACY     - XFRM_MSG_BASE] = {
+               .doit = xfrm_get_sa_legacy,
+               .dump = xfrm_dump_sa_legacy,
+               .done = xfrm_dump_sa_done_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_NEWPOLICY_LEGACY - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_policy_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_UPDPOLICY_LEGACY - XFRM_MSG_BASE] = {
+               .doit = xfrm_add_policy_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_DELPOLICY_LEGACY - XFRM_MSG_BASE] = {
+               .doit = xfrm_get_policy_legacy,
+               .legacy = true,
+       },
+       [XFRM_MSG_GETPOLICY_LEGACY - XFRM_MSG_BASE] = {
+               .doit = xfrm_get_policy_legacy,
+               .dump = xfrm_dump_policy_legacy,
+               .done = xfrm_dump_policy_done_legacy,
+               .legacy = true,
+       },
+#endif /* CONFIG_XFRM_USER_LEGACY */
 };
 
 static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
@@ -2432,11 +2515,6 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct 
nlmsghdr *nlh)
        const struct xfrm_link *link;
        int type, err;
 
-#ifdef CONFIG_COMPAT
-       if (in_compat_syscall())
-               return -EOPNOTSUPP;
-#endif
-
        type = nlh->nlmsg_type;
        if (type > XFRM_MSG_MAX)
                return -EINVAL;
@@ -2444,12 +2522,19 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, 
struct nlmsghdr *nlh)
        type -= XFRM_MSG_BASE;
        link = &xfrm_dispatch[type];
 
+#ifdef CONFIG_COMPAT
+       if (link->legacy && in_compat_syscall())
+               return -EOPNOTSUPP;
+#endif
+
        /* All operations require privileges, even GET */
        if (!netlink_net_capable(skb, CAP_NET_ADMIN))
                return -EPERM;
 
        if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
-            type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
+            type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE) ||
+            type == (XFRM_MSG_GETSA_LEGACY - XFRM_MSG_BASE) ||
+            type == (XFRM_MSG_GETPOLICY_LEGACY - XFRM_MSG_BASE)) &&
            (nlh->nlmsg_flags & NLM_F_DUMP)) {
                if (link->dump == NULL)
                        return -EINVAL;
@@ -2670,16 +2755,23 @@ static int xfrm_notify_sa(const struct xfrm_state *x, 
const struct km_event *c)
 static int xfrm_send_state_notify(const struct xfrm_state *x,
                                  const struct km_event *c)
 {
+       int err;
 
        switch (c->event) {
        case XFRM_MSG_EXPIRE:
-               return xfrm_exp_state_notify(x, c);
+               err = xfrm_exp_state_notify(x, c);
+               if (err)
+                       return err;
+               return xfrm_exp_state_notify_legacy(x, c);
        case XFRM_MSG_NEWAE:
                return xfrm_aevent_state_notify(x, c);
        case XFRM_MSG_DELSA:
        case XFRM_MSG_UPDSA:
        case XFRM_MSG_NEWSA:
-               return xfrm_notify_sa(x, c);
+               err = xfrm_notify_sa(x, c);
+               if (err)
+                       return err;
+               return xfrm_notify_sa_legacy(x, c);
        case XFRM_MSG_FLUSHSA:
                return xfrm_notify_sa_flush(c);
        default:
@@ -2748,6 +2840,7 @@ static int xfrm_send_acquire(struct xfrm_state *x,
 {
        struct net *net = xs_net(x);
        struct sk_buff *skb;
+       int err;
 
        skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
        if (skb == NULL)
@@ -2756,7 +2849,11 @@ static int xfrm_send_acquire(struct xfrm_state *x,
        if (build_acquire(skb, x, xt, xp) < 0)
                BUG();
 
-       return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE);
+       err = xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE);
+       if (err)
+               return err;
+
+       return xfrm_send_acquire_legacy(x, xt, xp);
 }
 
 /* User gives us xfrm_user_policy_info followed by an array of 0
@@ -2799,6 +2896,16 @@ static struct xfrm_policy *xfrm_compile_policy(struct 
sock *sk, int opt,
                return NULL;
 
        nr = ((len - sizeof(*p)) / sizeof(*ut));
+       if (len == (nr + 1) * sizeof(*ut) + sizeof(*p) - sizeof(u32)) {
+               /* The user passed a legacy xfrm_userpolicy_info struct whose
+                * length is padded to 32 bits instead of 64, so the above
+                * division had a remainder.  Adjust the start address and
+                * count accordingly.
+                */
+               ut = (void *)data + sizeof(*p) - sizeof(u32);
+               nr++;
+       }
+
        if (validate_tmpl(nr, ut, p->sel.family))
                return NULL;
 
@@ -2979,16 +3086,23 @@ static int xfrm_send_policy_notify(const struct 
xfrm_policy *xp,
                                   int dir,
                                   const struct km_event *c)
 {
+       int err;
 
        switch (c->event) {
        case XFRM_MSG_NEWPOLICY:
        case XFRM_MSG_UPDPOLICY:
        case XFRM_MSG_DELPOLICY:
-               return xfrm_notify_policy(xp, dir, c);
+               err = xfrm_notify_policy(xp, dir, c);
+               if (err)
+                       return err;
+               return xfrm_notify_policy_legacy(xp, dir, c);
        case XFRM_MSG_FLUSHPOLICY:
                return xfrm_notify_policy_flush(c);
        case XFRM_MSG_POLEXPIRE:
-               return xfrm_exp_policy_notify(xp, dir, c);
+               err = xfrm_exp_policy_notify(xp, dir, c);
+               if (err)
+                       return err;
+               return xfrm_exp_policy_notify_legacy(xp, dir, c);
        default:
                printk(KERN_NOTICE "xfrm_user: Unknown Policy event %d\n",
                       c->event);
diff --git a/net/xfrm/xfrm_user.h b/net/xfrm/xfrm_user.h
index 29bab2ebee83..78627d1c1cec 100644
--- a/net/xfrm/xfrm_user.h
+++ b/net/xfrm/xfrm_user.h
@@ -1,6 +1,7 @@
 #ifndef _XFRM_USER_H
 #define _XFRM_USER_H
 
+#include <linux/errno.h>
 #include <linux/netlink.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
@@ -87,4 +88,78 @@ static inline int copy_to_user_state_sec_ctx(const struct 
xfrm_state *x,
        return 0;
 }
 
+/* Legacy functions */
+
+#ifdef CONFIG_XFRM_USER_LEGACY
+int xfrm_alloc_userspi_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                             struct nlattr **attrs);
+int xfrm_add_pol_expire_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                              struct nlattr **attrs);
+int xfrm_add_sa_expire_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                             struct nlattr **attrs);
+int xfrm_add_acquire_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                           struct nlattr **attrs);
+
+int xfrm_add_sa_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                      struct nlattr **attrs);
+int xfrm_del_sa_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                      struct nlattr **attrs);
+int xfrm_dump_sa_done_legacy(struct netlink_callback *cb);
+int xfrm_dump_sa_legacy(struct sk_buff *skb, struct netlink_callback *cb);
+int xfrm_get_sa_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                      struct nlattr **attrs);
+int xfrm_add_policy_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                          struct nlattr **attrs);
+int xfrm_dump_policy_done_legacy(struct netlink_callback *cb);
+int xfrm_dump_policy_legacy(struct sk_buff *skb, struct netlink_callback *cb);
+int xfrm_get_policy_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+                          struct nlattr **attrs);
+
+int xfrm_exp_state_notify_legacy(const struct xfrm_state *x,
+                                const struct km_event *c);
+int xfrm_notify_sa_legacy(const struct xfrm_state *x, const struct km_event 
*c);
+int xfrm_send_acquire_legacy(struct xfrm_state *x,
+                            const struct xfrm_tmpl *xt,
+                            const struct xfrm_policy *xp);
+int xfrm_exp_policy_notify_legacy(const struct xfrm_policy *xp,
+                                 int dir,
+                                 const struct km_event *c);
+int xfrm_notify_policy_legacy(const struct xfrm_policy *xp,
+                             int dir,
+                             const struct km_event *c);
+#else /* CONFIG_XFRM_USER_LEGACY */
+static inline int xfrm_exp_state_notify_legacy(const struct xfrm_state *x,
+                                              const struct km_event *c)
+{
+       return 0;
+}
+
+static inline int xfrm_notify_sa_legacy(const struct xfrm_state *x,
+                                       const struct km_event *c)
+{
+       return 0;
+}
+
+static inline int xfrm_send_acquire_legacy(struct xfrm_state *x,
+                                          const struct xfrm_tmpl *xt,
+                                          const struct xfrm_policy *xp)
+{
+       return 0;
+}
+
+static inline int xfrm_exp_policy_notify_legacy(const struct xfrm_policy *xp,
+                                               int dir,
+                                               const struct km_event *c)
+{
+       return 0;
+}
+
+static inline int xfrm_notify_policy_legacy(const struct xfrm_policy *xp,
+                                           int dir,
+                                           const struct km_event *c)
+{
+       return 0;
+}
+#endif /* CONFIG_XFRM_USER_LEGACY */
+
 #endif /* _XFRM_USER_H */
diff --git a/net/xfrm/xfrm_user_legacy.c b/net/xfrm/xfrm_user_legacy.c
index 058accfefc83..aa48845b47fa 100644
--- a/net/xfrm/xfrm_user_legacy.c
+++ b/net/xfrm/xfrm_user_legacy.c
@@ -29,28 +29,33 @@
 #include <asm/unaligned.h>
 #include "xfrm_user.h"
 
-static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_add_sa_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                       struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
-       const struct xfrm_usersa_info *p = nlmsg_data(nlh);
+       const struct xfrm_usersa_info_legacy *p = nlmsg_data(nlh);
        struct xfrm_state *x;
        int err;
        struct km_event c;
 
-       err = xfrm_verify_newsa_info(p, attrs);
+       /* This cast is safe because the only difference is end padding. */
+       err = xfrm_verify_newsa_info((const struct xfrm_usersa_info *)p, attrs);
        if (err)
                return err;
 
-       x = xfrm_state_construct(net, p, attrs, &err);
+       x = xfrm_state_construct(net, (const struct xfrm_usersa_info *)p,
+                                attrs, &err);
        if (!x)
                return err;
 
        xfrm_state_hold(x);
-       if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+       if (nlh->nlmsg_type == XFRM_MSG_NEWSA_LEGACY) {
                err = xfrm_state_add(x);
-       else
+               c.event = XFRM_MSG_NEWSA;
+       } else {
                err = xfrm_state_update(x);
+               c.event = XFRM_MSG_UPDSA;
+       }
 
        xfrm_audit_state_add(x, err ? 0 : 1, true);
 
@@ -62,7 +67,6 @@ static int xfrm_add_sa(struct sk_buff *skb, const struct 
nlmsghdr *nlh,
 
        c.seq = nlh->nlmsg_seq;
        c.portid = nlh->nlmsg_pid;
-       c.event = nlh->nlmsg_type;
 
        km_state_notify(x, &c);
 out:
@@ -70,7 +74,7 @@ static int xfrm_add_sa(struct sk_buff *skb, const struct 
nlmsghdr *nlh,
        return err;
 }
 
-static int xfrm_del_sa(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_del_sa_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                       struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
@@ -98,7 +102,7 @@ static int xfrm_del_sa(struct sk_buff *skb, const struct 
nlmsghdr *nlh,
 
        c.seq = nlh->nlmsg_seq;
        c.portid = nlh->nlmsg_pid;
-       c.event = nlh->nlmsg_type;
+       c.event = XFRM_MSG_DELSA;
        km_state_notify(x, &c);
 
 out:
@@ -108,7 +112,7 @@ static int xfrm_del_sa(struct sk_buff *skb, const struct 
nlmsghdr *nlh,
 }
 
 static void copy_to_user_state(const struct xfrm_state *x,
-                              struct xfrm_usersa_info *p)
+                              struct xfrm_usersa_info_legacy *p)
 {
        memset(p, 0, sizeof(*p));
        memcpy(&p->id, &x->id, sizeof(p->id));
@@ -128,7 +132,7 @@ static void copy_to_user_state(const struct xfrm_state *x,
 }
 
 static int copy_to_user_state_extra(const struct xfrm_state *x,
-                                   struct xfrm_usersa_info *p,
+                                   struct xfrm_usersa_info_legacy *p,
                                    struct sk_buff *skb)
 {
        int ret = 0;
@@ -209,12 +213,12 @@ static int dump_one_state(const struct xfrm_state *x, int 
count, void *ptr)
        struct xfrm_dump_info *sp = ptr;
        struct sk_buff *in_skb = sp->in_skb;
        struct sk_buff *skb = sp->out_skb;
-       struct xfrm_usersa_info *p;
+       struct xfrm_usersa_info_legacy *p;
        struct nlmsghdr *nlh;
        int err;
 
        nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq,
-                       XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
+                       XFRM_MSG_NEWSA_LEGACY, sizeof(*p), sp->nlmsg_flags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -229,7 +233,7 @@ static int dump_one_state(const struct xfrm_state *x, int 
count, void *ptr)
        return 0;
 }
 
-static int xfrm_dump_sa_done(struct netlink_callback *cb)
+int xfrm_dump_sa_done_legacy(struct netlink_callback *cb)
 {
        struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
        struct sock *sk = cb->skb->sk;
@@ -241,7 +245,7 @@ static int xfrm_dump_sa_done(struct netlink_callback *cb)
 }
 
 static const struct nla_policy xfrma_policy[XFRMA_MAX+1];
-static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
+int xfrm_dump_sa_legacy(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct net *net = sock_net(skb->sk);
        struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
@@ -311,7 +315,7 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff 
*in_skb,
        return skb;
 }
 
-static int xfrm_get_sa(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_get_sa_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                       struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
@@ -335,12 +339,12 @@ static int xfrm_get_sa(struct sk_buff *skb, const struct 
nlmsghdr *nlh,
        return err;
 }
 
-static int xfrm_alloc_userspi(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_alloc_userspi_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                              struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
        struct xfrm_state *x;
-       const struct xfrm_userspi_info *p;
+       const struct xfrm_userspi_info_legacy *p;
        struct sk_buff *resp_skb;
        const xfrm_address_t *daddr;
        int family;
@@ -395,7 +399,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
 }
 
 static void copy_to_user_policy(const struct xfrm_policy *xp,
-                               struct xfrm_userpolicy_info *p,
+                               struct xfrm_userpolicy_info_legacy *p,
                                int dir)
 {
        memset(p, 0, sizeof(*p));
@@ -411,24 +415,27 @@ static void copy_to_user_policy(const struct xfrm_policy 
*xp,
        p->share = XFRM_SHARE_ANY; /* XXX xp->share */
 }
 
-static int xfrm_add_policy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_add_policy_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                           struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
-       const struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
+       const struct xfrm_userpolicy_info_legacy *p = nlmsg_data(nlh);
        struct xfrm_policy *xp;
        struct km_event c;
        int err;
        int excl;
 
-       err = xfrm_verify_newpolicy_info(p);
+       /* This cast is safe because the only difference is end padding. */
+       err = xfrm_verify_newpolicy_info(
+               (const struct xfrm_userpolicy_info *)p);
        if (err)
                return err;
        err = xfrm_verify_sec_ctx_len(attrs);
        if (err)
                return err;
 
-       xp = xfrm_policy_construct(net, p, attrs, &err);
+       xp = xfrm_policy_construct(net, (const struct xfrm_userpolicy_info *)p,
+                                  attrs, &err);
        if (!xp)
                return err;
 
@@ -436,7 +443,13 @@ static int xfrm_add_policy(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
         * Aha! this is anti-netlink really i.e  more pfkey derived
         * in netlink excl is a flag and you wouldnt need
         * a type XFRM_MSG_UPDPOLICY - JHS */
-       excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
+       if (nlh->nlmsg_type == XFRM_MSG_NEWPOLICY_LEGACY) {
+               excl = 1;
+               c.event = XFRM_MSG_NEWPOLICY;
+       } else {
+               excl = 0;
+               c.event = XFRM_MSG_UPDPOLICY;
+       }
        err = xfrm_policy_insert(p->dir, xp, excl);
        xfrm_audit_policy_add(xp, err ? 0 : 1, true);
 
@@ -446,7 +459,6 @@ static int xfrm_add_policy(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
                return err;
        }
 
-       c.event = nlh->nlmsg_type;
        c.seq = nlh->nlmsg_seq;
        c.portid = nlh->nlmsg_pid;
        km_policy_notify(xp, p->dir, &c);
@@ -471,14 +483,14 @@ static int dump_one_policy(const struct xfrm_policy *xp,
                           void *ptr)
 {
        struct xfrm_dump_info *sp = ptr;
-       struct xfrm_userpolicy_info *p;
+       struct xfrm_userpolicy_info_legacy *p;
        struct sk_buff *in_skb = sp->in_skb;
        struct sk_buff *skb = sp->out_skb;
        struct nlmsghdr *nlh;
        int err;
 
        nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq,
-                       XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
+                       XFRM_MSG_NEWPOLICY_LEGACY, sizeof(*p), sp->nlmsg_flags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -499,7 +511,7 @@ static int dump_one_policy(const struct xfrm_policy *xp,
        return 0;
 }
 
-static int xfrm_dump_policy_done(struct netlink_callback *cb)
+int xfrm_dump_policy_done_legacy(struct netlink_callback *cb)
 {
        struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) 
&cb->args[1];
        struct net *net = sock_net(cb->skb->sk);
@@ -508,7 +520,7 @@ static int xfrm_dump_policy_done(struct netlink_callback 
*cb)
        return 0;
 }
 
-static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
+int xfrm_dump_policy_legacy(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct net *net = sock_net(skb->sk);
        struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) 
&cb->args[1];
@@ -559,7 +571,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff 
*in_skb,
        return skb;
 }
 
-static int xfrm_get_policy(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_get_policy_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                           struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
@@ -573,7 +585,13 @@ static int xfrm_get_policy(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
        u32 mark = xfrm_mark_get(attrs, &m);
 
        p = nlmsg_data(nlh);
-       delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
+       if (nlh->nlmsg_type == XFRM_MSG_DELPOLICY_LEGACY) {
+               delete = 1;
+               c.event = XFRM_MSG_DELPOLICY;
+       } else {
+               delete = 0;
+               c.event = XFRM_MSG_GETPOLICY;
+       }
 
        err = xfrm_copy_from_user_policy_type(&type, attrs);
        if (err)
@@ -625,7 +643,6 @@ static int xfrm_get_policy(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
                        goto out;
 
                c.data.byid = p->index;
-               c.event = nlh->nlmsg_type;
                c.seq = nlh->nlmsg_seq;
                c.portid = nlh->nlmsg_pid;
                km_policy_notify(xp, p->dir, &c);
@@ -638,13 +655,13 @@ static int xfrm_get_policy(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
        return err;
 }
 
-static int xfrm_add_pol_expire(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_add_pol_expire_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                               struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
        struct xfrm_policy *xp;
-       const struct xfrm_user_polexpire *up = nlmsg_data(nlh);
-       const struct xfrm_userpolicy_info *p = &up->pol;
+       const struct xfrm_user_polexpire_legacy *up = nlmsg_data(nlh);
+       const struct xfrm_userpolicy_info_legacy *p = &up->pol;
        u8 type = XFRM_POLICY_TYPE_MAIN;
        int err = -ENOENT;
        struct xfrm_mark m;
@@ -698,14 +715,14 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
        return err;
 }
 
-static int xfrm_add_sa_expire(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_add_sa_expire_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                              struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
        struct xfrm_state *x;
        int err;
-       const struct xfrm_user_expire *ue = nlmsg_data(nlh);
-       const struct xfrm_usersa_info *p = &ue->state;
+       const struct xfrm_user_expire_legacy *ue = nlmsg_data(nlh);
+       const struct xfrm_usersa_info_legacy *p = &ue->state;
        struct xfrm_mark m;
        u32 mark = xfrm_mark_get(attrs, &m);
 
@@ -732,7 +749,7 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
        return err;
 }
 
-static int xfrm_add_acquire(struct sk_buff *skb, const struct nlmsghdr *nlh,
+int xfrm_add_acquire_legacy(struct sk_buff *skb, const struct nlmsghdr *nlh,
                            struct nlattr **attrs)
 {
        struct net *net = sock_net(skb->sk);
@@ -742,7 +759,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
        struct nlattr *rt = attrs[XFRMA_TMPL];
        struct xfrm_mark mark;
 
-       const struct xfrm_user_acquire *ua = nlmsg_data(nlh);
+       const struct xfrm_user_acquire_legacy *ua = nlmsg_data(nlh);
        struct xfrm_state *x = xfrm_state_alloc(net);
        int err = -ENOMEM;
 
@@ -751,12 +768,15 @@ static int xfrm_add_acquire(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
 
        xfrm_mark_get(attrs, &mark);
 
-       err = xfrm_verify_newpolicy_info(&ua->policy);
+       /* This cast is safe because the only difference is end padding. */
+       err = xfrm_verify_newpolicy_info(
+               (const struct xfrm_userpolicy_info *)&ua->policy);
        if (err)
                goto free_state;
 
        /*   build an XP */
-       xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
+       xp = xfrm_policy_construct(net, (const struct xfrm_userpolicy_info *)
+                                  &ua->policy, attrs, &err);
        if (!xp)
                goto free_state;
 
@@ -793,7 +813,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, const 
struct nlmsghdr *nlh,
 
 static inline size_t xfrm_expire_msgsize(void)
 {
-       return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
+       return NLMSG_ALIGN(sizeof(struct xfrm_user_expire_legacy))
               + nla_total_size(sizeof(struct xfrm_mark));
 }
 
@@ -801,11 +821,12 @@ static int build_expire(struct sk_buff *skb,
                        const struct xfrm_state *x,
                        const struct km_event *c)
 {
-       struct xfrm_user_expire *ue;
+       struct xfrm_user_expire_legacy *ue;
        struct nlmsghdr *nlh;
        int err;
 
-       nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0);
+       nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_EXPIRE_LEGACY,
+                       sizeof(*ue), 0);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -821,7 +842,7 @@ static int build_expire(struct sk_buff *skb,
        return 0;
 }
 
-static int xfrm_exp_state_notify(const struct xfrm_state *x,
+int xfrm_exp_state_notify_legacy(const struct xfrm_state *x,
                                 const struct km_event *c)
 {
        struct net *net = xs_net(x);
@@ -839,15 +860,16 @@ static int xfrm_exp_state_notify(const struct xfrm_state 
*x,
        return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
 }
 
-static int xfrm_notify_sa(const struct xfrm_state *x, const struct km_event *c)
+int xfrm_notify_sa_legacy(const struct xfrm_state *x, const struct km_event *c)
 {
        struct net *net = xs_net(x);
-       struct xfrm_usersa_info *p;
+       struct xfrm_usersa_info_legacy *p;
        struct xfrm_usersa_id *id;
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        int len = xfrm_sa_len(x);
        int headlen, err;
+       u32 event = 0;
 
        headlen = sizeof(*p);
        if (c->event == XFRM_MSG_DELSA) {
@@ -861,7 +883,19 @@ static int xfrm_notify_sa(const struct xfrm_state *x, 
const struct km_event *c)
        if (skb == NULL)
                return -ENOMEM;
 
-       nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0);
+       switch (c->event) {
+       case XFRM_MSG_NEWSA:
+               event = XFRM_MSG_NEWSA_LEGACY;
+               break;
+       case XFRM_MSG_UPDSA:
+               event = XFRM_MSG_UPDSA_LEGACY;
+               break;
+       case XFRM_MSG_DELSA:
+               event = XFRM_MSG_DELSA_LEGACY;
+               break;
+       }
+
+       nlh = nlmsg_put(skb, c->portid, c->seq, event, headlen, 0);
        err = -EMSGSIZE;
        if (nlh == NULL)
                goto out_free_skb;
@@ -899,7 +933,7 @@ static int xfrm_notify_sa(const struct xfrm_state *x, const 
struct km_event *c)
 static inline size_t xfrm_acquire_msgsize(const struct xfrm_state *x,
                                          const struct xfrm_policy *xp)
 {
-       return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))
+       return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire_legacy))
               + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
               + nla_total_size(sizeof(struct xfrm_mark))
               + nla_total_size(xfrm_user_sec_ctx_size(x->security))
@@ -912,11 +946,11 @@ static int build_acquire(struct sk_buff *skb,
                         const struct xfrm_policy *xp)
 {
        __u32 seq = xfrm_get_acqseq();
-       struct xfrm_user_acquire *ua;
+       struct xfrm_user_acquire_legacy *ua;
        struct nlmsghdr *nlh;
        int err;
 
-       nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0);
+       nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE_LEGACY, sizeof(*ua), 0);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -946,7 +980,7 @@ static int build_acquire(struct sk_buff *skb,
        return 0;
 }
 
-static int xfrm_send_acquire(struct xfrm_state *x,
+int xfrm_send_acquire_legacy(struct xfrm_state *x,
                             const struct xfrm_tmpl *xt,
                             const struct xfrm_policy *xp)
 {
@@ -965,7 +999,7 @@ static int xfrm_send_acquire(struct xfrm_state *x,
 
 static inline size_t xfrm_polexpire_msgsize(const struct xfrm_policy *xp)
 {
-       return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire))
+       return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire_legacy))
               + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
               + nla_total_size(xfrm_user_sec_ctx_size(xp->security))
               + nla_total_size(sizeof(struct xfrm_mark))
@@ -977,12 +1011,13 @@ static int build_polexpire(struct sk_buff *skb,
                           int dir,
                           const struct km_event *c)
 {
-       struct xfrm_user_polexpire *upe;
+       struct xfrm_user_polexpire_legacy *upe;
        int hard = c->data.hard;
        struct nlmsghdr *nlh;
        int err;
 
-       nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0);
+       nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE_LEGACY,
+                       sizeof(*upe), 0);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -1005,7 +1040,7 @@ static int build_polexpire(struct sk_buff *skb,
        return 0;
 }
 
-static int xfrm_exp_policy_notify(const struct xfrm_policy *xp,
+int xfrm_exp_policy_notify_legacy(const struct xfrm_policy *xp,
                                  int dir,
                                  const struct km_event *c)
 {
@@ -1022,19 +1057,21 @@ static int xfrm_exp_policy_notify(const struct 
xfrm_policy *xp,
        return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
 }
 
-static int xfrm_notify_policy(const struct xfrm_policy *xp,
+int xfrm_notify_policy_legacy(const struct xfrm_policy *xp,
                              int dir,
                              const struct km_event *c)
 {
        int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
        struct net *net = xp_net(xp);
-       struct xfrm_userpolicy_info *p;
+       struct xfrm_userpolicy_info_legacy *p;
        struct xfrm_userpolicy_id *id;
        struct nlmsghdr *nlh;
        struct sk_buff *skb;
        int headlen, err;
+       u32 event = 0;
 
        headlen = sizeof(*p);
+
        if (c->event == XFRM_MSG_DELPOLICY) {
                len += nla_total_size(headlen);
                headlen = sizeof(*id);
@@ -1047,7 +1084,19 @@ static int xfrm_notify_policy(const struct xfrm_policy 
*xp,
        if (skb == NULL)
                return -ENOMEM;
 
-       nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0);
+       switch (c->event) {
+       case XFRM_MSG_NEWPOLICY:
+               event = XFRM_MSG_NEWPOLICY_LEGACY;
+               break;
+       case XFRM_MSG_UPDPOLICY:
+               event = XFRM_MSG_UPDPOLICY_LEGACY;
+               break;
+       case XFRM_MSG_DELPOLICY:
+               event = XFRM_MSG_DELPOLICY_LEGACY;
+               break;
+       }
+
+       nlh = nlmsg_put(skb, c->portid, c->seq, event, headlen, 0);
        err = -EMSGSIZE;
        if (nlh == NULL)
                goto out_free_skb;
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 2ca9cde939d4..15e8b1381c13 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -90,29 +90,42 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
 
 static struct nlmsg_perm nlmsg_xfrm_perms[] =
 {
-       { XFRM_MSG_NEWSA,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_DELSA,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_GETSA,       NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_NEWPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_DELPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_GETPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_ALLOCSPI,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_ACQUIRE,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_EXPIRE,      NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_UPDPOLICY,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_UPDSA,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_POLEXPIRE,   NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_FLUSHSA,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_NEWAE,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_GETAE,       NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_REPORT,      NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_MIGRATE,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_NEWSADINFO,  NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_GETSADINFO,  NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_NEWSPDINFO,  NETLINK_XFRM_SOCKET__NLMSG_WRITE },
-       { XFRM_MSG_GETSPDINFO,  NETLINK_XFRM_SOCKET__NLMSG_READ  },
-       { XFRM_MSG_MAPPING,     NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_NEWSA_LEGACY,        NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_DELSA_LEGACY,        NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETSA_LEGACY,        NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_NEWPOLICY_LEGACY,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_DELPOLICY_LEGACY,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETPOLICY_LEGACY,    NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_ALLOCSPI_LEGACY,     NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_ACQUIRE_LEGACY,      NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_EXPIRE_LEGACY,       NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_UPDPOLICY_LEGACY,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_UPDSA_LEGACY,        NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_POLEXPIRE_LEGACY,    NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_FLUSHSA,             NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_FLUSHPOLICY,         NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_NEWAE,               NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETAE,               NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_REPORT,              NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_MIGRATE,             NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_NEWSADINFO,          NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_GETSADINFO,          NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_NEWSPDINFO,          NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETSPDINFO,          NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_MAPPING,             NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_ALLOCSPI,            NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_ACQUIRE,             NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_EXPIRE,              NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_POLEXPIRE,           NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_NEWSA,               NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_NEWSA,               NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_UPDSA,               NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_DELSA,               NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETSA,               NETLINK_XFRM_SOCKET__NLMSG_READ  },
+       { XFRM_MSG_NEWPOLICY,           NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_UPDPOLICY,           NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_DELPOLICY,           NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+       { XFRM_MSG_GETPOLICY,           NETLINK_XFRM_SOCKET__NLMSG_READ  },
 };
 
 static struct nlmsg_perm nlmsg_audit_perms[] =
@@ -168,7 +181,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 
*perm)
                break;
 
        case SECCLASS_NETLINK_XFRM_SOCKET:
-               BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_MAPPING);
+               BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_GETPOLICY);
                err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms,
                                 sizeof(nlmsg_xfrm_perms));
                break;
-- 
2.11.0.483.g087da7b7c-goog

Reply via email to