Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * XFRM compat layer
0004  * Author: Dmitry Safonov <dima@arista.com>
0005  * Based on code and translator idea by: Florian Westphal <fw@strlen.de>
0006  */
0007 #include <linux/compat.h>
0008 #include <linux/xfrm.h>
0009 #include <net/xfrm.h>
0010 
0011 struct compat_xfrm_lifetime_cfg {
0012     compat_u64 soft_byte_limit, hard_byte_limit;
0013     compat_u64 soft_packet_limit, hard_packet_limit;
0014     compat_u64 soft_add_expires_seconds, hard_add_expires_seconds;
0015     compat_u64 soft_use_expires_seconds, hard_use_expires_seconds;
0016 }; /* same size on 32bit, but only 4 byte alignment required */
0017 
0018 struct compat_xfrm_lifetime_cur {
0019     compat_u64 bytes, packets, add_time, use_time;
0020 }; /* same size on 32bit, but only 4 byte alignment required */
0021 
0022 struct compat_xfrm_userpolicy_info {
0023     struct xfrm_selector sel;
0024     struct compat_xfrm_lifetime_cfg lft;
0025     struct compat_xfrm_lifetime_cur curlft;
0026     __u32 priority, index;
0027     u8 dir, action, flags, share;
0028     /* 4 bytes additional padding on 64bit */
0029 };
0030 
0031 struct compat_xfrm_usersa_info {
0032     struct xfrm_selector sel;
0033     struct xfrm_id id;
0034     xfrm_address_t saddr;
0035     struct compat_xfrm_lifetime_cfg lft;
0036     struct compat_xfrm_lifetime_cur curlft;
0037     struct xfrm_stats stats;
0038     __u32 seq, reqid;
0039     u16 family;
0040     u8 mode, replay_window, flags;
0041     /* 4 bytes additional padding on 64bit */
0042 };
0043 
0044 struct compat_xfrm_user_acquire {
0045     struct xfrm_id id;
0046     xfrm_address_t saddr;
0047     struct xfrm_selector sel;
0048     struct compat_xfrm_userpolicy_info policy;
0049     /* 4 bytes additional padding on 64bit */
0050     __u32 aalgos, ealgos, calgos, seq;
0051 };
0052 
0053 struct compat_xfrm_userspi_info {
0054     struct compat_xfrm_usersa_info info;
0055     /* 4 bytes additional padding on 64bit */
0056     __u32 min, max;
0057 };
0058 
0059 struct compat_xfrm_user_expire {
0060     struct compat_xfrm_usersa_info state;
0061     /* 8 bytes additional padding on 64bit */
0062     u8 hard;
0063 };
0064 
0065 struct compat_xfrm_user_polexpire {
0066     struct compat_xfrm_userpolicy_info pol;
0067     /* 8 bytes additional padding on 64bit */
0068     u8 hard;
0069 };
0070 
0071 #define XMSGSIZE(type) sizeof(struct type)
0072 
0073 static const int compat_msg_min[XFRM_NR_MSGTYPES] = {
0074     [XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info),
0075     [XFRM_MSG_DELSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
0076     [XFRM_MSG_GETSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
0077     [XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info),
0078     [XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
0079     [XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
0080     [XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userspi_info),
0081     [XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_acquire),
0082     [XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_expire),
0083     [XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info),
0084     [XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info),
0085     [XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_polexpire),
0086     [XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
0087     [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
0088     [XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
0089     [XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
0090     [XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
0091     [XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
0092     [XFRM_MSG_NEWSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
0093     [XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
0094     [XFRM_MSG_NEWSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
0095     [XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
0096     [XFRM_MSG_MAPPING     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping)
0097 };
0098 
0099 static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
0100     [XFRMA_SA]      = { .len = XMSGSIZE(compat_xfrm_usersa_info)},
0101     [XFRMA_POLICY]      = { .len = XMSGSIZE(compat_xfrm_userpolicy_info)},
0102     [XFRMA_LASTUSED]    = { .type = NLA_U64},
0103     [XFRMA_ALG_AUTH_TRUNC]  = { .len = sizeof(struct xfrm_algo_auth)},
0104     [XFRMA_ALG_AEAD]    = { .len = sizeof(struct xfrm_algo_aead) },
0105     [XFRMA_ALG_AUTH]    = { .len = sizeof(struct xfrm_algo) },
0106     [XFRMA_ALG_CRYPT]   = { .len = sizeof(struct xfrm_algo) },
0107     [XFRMA_ALG_COMP]    = { .len = sizeof(struct xfrm_algo) },
0108     [XFRMA_ENCAP]       = { .len = sizeof(struct xfrm_encap_tmpl) },
0109     [XFRMA_TMPL]        = { .len = sizeof(struct xfrm_user_tmpl) },
0110     [XFRMA_SEC_CTX]     = { .len = sizeof(struct xfrm_sec_ctx) },
0111     [XFRMA_LTIME_VAL]   = { .len = sizeof(struct xfrm_lifetime_cur) },
0112     [XFRMA_REPLAY_VAL]  = { .len = sizeof(struct xfrm_replay_state) },
0113     [XFRMA_REPLAY_THRESH]   = { .type = NLA_U32 },
0114     [XFRMA_ETIMER_THRESH]   = { .type = NLA_U32 },
0115     [XFRMA_SRCADDR]     = { .len = sizeof(xfrm_address_t) },
0116     [XFRMA_COADDR]      = { .len = sizeof(xfrm_address_t) },
0117     [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)},
0118     [XFRMA_MIGRATE]     = { .len = sizeof(struct xfrm_user_migrate) },
0119     [XFRMA_KMADDRESS]   = { .len = sizeof(struct xfrm_user_kmaddress) },
0120     [XFRMA_MARK]        = { .len = sizeof(struct xfrm_mark) },
0121     [XFRMA_TFCPAD]      = { .type = NLA_U32 },
0122     [XFRMA_REPLAY_ESN_VAL]  = { .len = sizeof(struct xfrm_replay_state_esn) },
0123     [XFRMA_SA_EXTRA_FLAGS]  = { .type = NLA_U32 },
0124     [XFRMA_PROTO]       = { .type = NLA_U8 },
0125     [XFRMA_ADDRESS_FILTER]  = { .len = sizeof(struct xfrm_address_filter) },
0126     [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) },
0127     [XFRMA_SET_MARK]    = { .type = NLA_U32 },
0128     [XFRMA_SET_MARK_MASK]   = { .type = NLA_U32 },
0129     [XFRMA_IF_ID]       = { .type = NLA_U32 },
0130     [XFRMA_MTIMER_THRESH]   = { .type = NLA_U32 },
0131 };
0132 
0133 static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb,
0134             const struct nlmsghdr *nlh_src, u16 type)
0135 {
0136     int payload = compat_msg_min[type];
0137     int src_len = xfrm_msg_min[type];
0138     struct nlmsghdr *nlh_dst;
0139 
0140     /* Compat messages are shorter or equal to native (+padding) */
0141     if (WARN_ON_ONCE(src_len < payload))
0142         return ERR_PTR(-EMSGSIZE);
0143 
0144     nlh_dst = nlmsg_put(skb, nlh_src->nlmsg_pid, nlh_src->nlmsg_seq,
0145                 nlh_src->nlmsg_type, payload, nlh_src->nlmsg_flags);
0146     if (!nlh_dst)
0147         return ERR_PTR(-EMSGSIZE);
0148 
0149     memset(nlmsg_data(nlh_dst), 0, payload);
0150 
0151     switch (nlh_src->nlmsg_type) {
0152     /* Compat message has the same layout as native */
0153     case XFRM_MSG_DELSA:
0154     case XFRM_MSG_DELPOLICY:
0155     case XFRM_MSG_FLUSHSA:
0156     case XFRM_MSG_FLUSHPOLICY:
0157     case XFRM_MSG_NEWAE:
0158     case XFRM_MSG_REPORT:
0159     case XFRM_MSG_MIGRATE:
0160     case XFRM_MSG_NEWSADINFO:
0161     case XFRM_MSG_NEWSPDINFO:
0162     case XFRM_MSG_MAPPING:
0163         WARN_ON_ONCE(src_len != payload);
0164         memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), src_len);
0165         break;
0166     /* 4 byte alignment for trailing u64 on native, but not on compat */
0167     case XFRM_MSG_NEWSA:
0168     case XFRM_MSG_NEWPOLICY:
0169     case XFRM_MSG_UPDSA:
0170     case XFRM_MSG_UPDPOLICY:
0171         WARN_ON_ONCE(src_len != payload + 4);
0172         memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), payload);
0173         break;
0174     case XFRM_MSG_EXPIRE: {
0175         const struct xfrm_user_expire *src_ue  = nlmsg_data(nlh_src);
0176         struct compat_xfrm_user_expire *dst_ue = nlmsg_data(nlh_dst);
0177 
0178         /* compat_xfrm_user_expire has 4-byte smaller state */
0179         memcpy(dst_ue, src_ue, sizeof(dst_ue->state));
0180         dst_ue->hard = src_ue->hard;
0181         break;
0182     }
0183     case XFRM_MSG_ACQUIRE: {
0184         const struct xfrm_user_acquire *src_ua  = nlmsg_data(nlh_src);
0185         struct compat_xfrm_user_acquire *dst_ua = nlmsg_data(nlh_dst);
0186 
0187         memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos));
0188         dst_ua->aalgos = src_ua->aalgos;
0189         dst_ua->ealgos = src_ua->ealgos;
0190         dst_ua->calgos = src_ua->calgos;
0191         dst_ua->seq    = src_ua->seq;
0192         break;
0193     }
0194     case XFRM_MSG_POLEXPIRE: {
0195         const struct xfrm_user_polexpire *src_upe  = nlmsg_data(nlh_src);
0196         struct compat_xfrm_user_polexpire *dst_upe = nlmsg_data(nlh_dst);
0197 
0198         /* compat_xfrm_user_polexpire has 4-byte smaller state */
0199         memcpy(dst_upe, src_upe, sizeof(dst_upe->pol));
0200         dst_upe->hard = src_upe->hard;
0201         break;
0202     }
0203     case XFRM_MSG_ALLOCSPI: {
0204         const struct xfrm_userspi_info *src_usi = nlmsg_data(nlh_src);
0205         struct compat_xfrm_userspi_info *dst_usi = nlmsg_data(nlh_dst);
0206 
0207         /* compat_xfrm_user_polexpire has 4-byte smaller state */
0208         memcpy(dst_usi, src_usi, sizeof(src_usi->info));
0209         dst_usi->min = src_usi->min;
0210         dst_usi->max = src_usi->max;
0211         break;
0212     }
0213     /* Not being sent by kernel */
0214     case XFRM_MSG_GETSA:
0215     case XFRM_MSG_GETPOLICY:
0216     case XFRM_MSG_GETAE:
0217     case XFRM_MSG_GETSADINFO:
0218     case XFRM_MSG_GETSPDINFO:
0219     default:
0220         pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
0221         return ERR_PTR(-EOPNOTSUPP);
0222     }
0223 
0224     return nlh_dst;
0225 }
0226 
0227 static int xfrm_nla_cpy(struct sk_buff *dst, const struct nlattr *src, int len)
0228 {
0229     return nla_put(dst, src->nla_type, len, nla_data(src));
0230 }
0231 
0232 static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
0233 {
0234     switch (src->nla_type) {
0235     case XFRMA_PAD:
0236         /* Ignore */
0237         return 0;
0238     case XFRMA_UNSPEC:
0239     case XFRMA_ALG_AUTH:
0240     case XFRMA_ALG_CRYPT:
0241     case XFRMA_ALG_COMP:
0242     case XFRMA_ENCAP:
0243     case XFRMA_TMPL:
0244         return xfrm_nla_cpy(dst, src, nla_len(src));
0245     case XFRMA_SA:
0246         return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_usersa_info));
0247     case XFRMA_POLICY:
0248         return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_userpolicy_info));
0249     case XFRMA_SEC_CTX:
0250         return xfrm_nla_cpy(dst, src, nla_len(src));
0251     case XFRMA_LTIME_VAL:
0252         return nla_put_64bit(dst, src->nla_type, nla_len(src),
0253             nla_data(src), XFRMA_PAD);
0254     case XFRMA_REPLAY_VAL:
0255     case XFRMA_REPLAY_THRESH:
0256     case XFRMA_ETIMER_THRESH:
0257     case XFRMA_SRCADDR:
0258     case XFRMA_COADDR:
0259         return xfrm_nla_cpy(dst, src, nla_len(src));
0260     case XFRMA_LASTUSED:
0261         return nla_put_64bit(dst, src->nla_type, nla_len(src),
0262             nla_data(src), XFRMA_PAD);
0263     case XFRMA_POLICY_TYPE:
0264     case XFRMA_MIGRATE:
0265     case XFRMA_ALG_AEAD:
0266     case XFRMA_KMADDRESS:
0267     case XFRMA_ALG_AUTH_TRUNC:
0268     case XFRMA_MARK:
0269     case XFRMA_TFCPAD:
0270     case XFRMA_REPLAY_ESN_VAL:
0271     case XFRMA_SA_EXTRA_FLAGS:
0272     case XFRMA_PROTO:
0273     case XFRMA_ADDRESS_FILTER:
0274     case XFRMA_OFFLOAD_DEV:
0275     case XFRMA_SET_MARK:
0276     case XFRMA_SET_MARK_MASK:
0277     case XFRMA_IF_ID:
0278     case XFRMA_MTIMER_THRESH:
0279         return xfrm_nla_cpy(dst, src, nla_len(src));
0280     default:
0281         BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
0282         pr_warn_once("unsupported nla_type %d\n", src->nla_type);
0283         return -EOPNOTSUPP;
0284     }
0285 }
0286 
0287 /* Take kernel-built (64bit layout) and create 32bit layout for userspace */
0288 static int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src)
0289 {
0290     u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE;
0291     const struct nlattr *nla, *attrs;
0292     struct nlmsghdr *nlh_dst;
0293     int len, remaining;
0294 
0295     nlh_dst = xfrm_nlmsg_put_compat(dst, nlh_src, type);
0296     if (IS_ERR(nlh_dst))
0297         return PTR_ERR(nlh_dst);
0298 
0299     attrs = nlmsg_attrdata(nlh_src, xfrm_msg_min[type]);
0300     len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]);
0301 
0302     nla_for_each_attr(nla, attrs, len, remaining) {
0303         int err;
0304 
0305         switch (type) {
0306         case XFRM_MSG_NEWSPDINFO:
0307             err = xfrm_nla_cpy(dst, nla, nla_len(nla));
0308             break;
0309         default:
0310             err = xfrm_xlate64_attr(dst, nla);
0311             break;
0312         }
0313         if (err)
0314             return err;
0315     }
0316 
0317     nlmsg_end(dst, nlh_dst);
0318 
0319     return 0;
0320 }
0321 
0322 static int xfrm_alloc_compat(struct sk_buff *skb, const struct nlmsghdr *nlh_src)
0323 {
0324     u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE;
0325     struct sk_buff *new = NULL;
0326     int err;
0327 
0328     if (type >= ARRAY_SIZE(xfrm_msg_min)) {
0329         pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
0330         return -EOPNOTSUPP;
0331     }
0332 
0333     if (skb_shinfo(skb)->frag_list == NULL) {
0334         new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC);
0335         if (!new)
0336             return -ENOMEM;
0337         skb_shinfo(skb)->frag_list = new;
0338     }
0339 
0340     err = xfrm_xlate64(skb_shinfo(skb)->frag_list, nlh_src);
0341     if (err) {
0342         if (new) {
0343             kfree_skb(new);
0344             skb_shinfo(skb)->frag_list = NULL;
0345         }
0346         return err;
0347     }
0348 
0349     return 0;
0350 }
0351 
0352 /* Calculates len of translated 64-bit message. */
0353 static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src,
0354                         struct nlattr *attrs[XFRMA_MAX + 1],
0355                         int maxtype)
0356 {
0357     size_t len = nlmsg_len(src);
0358 
0359     switch (src->nlmsg_type) {
0360     case XFRM_MSG_NEWSA:
0361     case XFRM_MSG_NEWPOLICY:
0362     case XFRM_MSG_ALLOCSPI:
0363     case XFRM_MSG_ACQUIRE:
0364     case XFRM_MSG_UPDPOLICY:
0365     case XFRM_MSG_UPDSA:
0366         len += 4;
0367         break;
0368     case XFRM_MSG_EXPIRE:
0369     case XFRM_MSG_POLEXPIRE:
0370         len += 8;
0371         break;
0372     case XFRM_MSG_NEWSPDINFO:
0373         /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
0374         return len;
0375     default:
0376         break;
0377     }
0378 
0379     /* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please
0380      * correct both 64=>32-bit and 32=>64-bit translators to copy
0381      * new attributes.
0382      */
0383     if (WARN_ON_ONCE(maxtype))
0384         return len;
0385 
0386     if (attrs[XFRMA_SA])
0387         len += 4;
0388     if (attrs[XFRMA_POLICY])
0389         len += 4;
0390 
0391     /* XXX: some attrs may need to be realigned
0392      * if !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
0393      */
0394 
0395     return len;
0396 }
0397 
0398 static int xfrm_attr_cpy32(void *dst, size_t *pos, const struct nlattr *src,
0399                size_t size, int copy_len, int payload)
0400 {
0401     struct nlmsghdr *nlmsg = dst;
0402     struct nlattr *nla;
0403 
0404     /* xfrm_user_rcv_msg_compat() relies on fact that 32-bit messages
0405      * have the same len or shorted than 64-bit ones.
0406      * 32-bit translation that is bigger than 64-bit original is unexpected.
0407      */
0408     if (WARN_ON_ONCE(copy_len > payload))
0409         copy_len = payload;
0410 
0411     if (size - *pos < nla_attr_size(payload))
0412         return -ENOBUFS;
0413 
0414     nla = dst + *pos;
0415 
0416     memcpy(nla, src, nla_attr_size(copy_len));
0417     nla->nla_len = nla_attr_size(payload);
0418     *pos += nla_attr_size(copy_len);
0419     nlmsg->nlmsg_len += nla->nla_len;
0420 
0421     memset(dst + *pos, 0, payload - copy_len);
0422     *pos += payload - copy_len;
0423 
0424     return 0;
0425 }
0426 
0427 static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
0428                  size_t *pos, size_t size,
0429                  struct netlink_ext_ack *extack)
0430 {
0431     int type = nla_type(nla);
0432     u16 pol_len32, pol_len64;
0433     int err;
0434 
0435     if (type > XFRMA_MAX) {
0436         BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
0437         NL_SET_ERR_MSG(extack, "Bad attribute");
0438         return -EOPNOTSUPP;
0439     }
0440     if (nla_len(nla) < compat_policy[type].len) {
0441         NL_SET_ERR_MSG(extack, "Attribute bad length");
0442         return -EOPNOTSUPP;
0443     }
0444 
0445     pol_len32 = compat_policy[type].len;
0446     pol_len64 = xfrma_policy[type].len;
0447 
0448     /* XFRMA_SA and XFRMA_POLICY - need to know how-to translate */
0449     if (pol_len32 != pol_len64) {
0450         if (nla_len(nla) != compat_policy[type].len) {
0451             NL_SET_ERR_MSG(extack, "Attribute bad length");
0452             return -EOPNOTSUPP;
0453         }
0454         err = xfrm_attr_cpy32(dst, pos, nla, size, pol_len32, pol_len64);
0455         if (err)
0456             return err;
0457     }
0458 
0459     return xfrm_attr_cpy32(dst, pos, nla, size, nla_len(nla), nla_len(nla));
0460 }
0461 
0462 static int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src,
0463             struct nlattr *attrs[XFRMA_MAX+1],
0464             size_t size, u8 type, int maxtype,
0465             struct netlink_ext_ack *extack)
0466 {
0467     size_t pos;
0468     int i;
0469 
0470     memcpy(dst, src, NLMSG_HDRLEN);
0471     dst->nlmsg_len = NLMSG_HDRLEN + xfrm_msg_min[type];
0472     memset(nlmsg_data(dst), 0, xfrm_msg_min[type]);
0473 
0474     switch (src->nlmsg_type) {
0475     /* Compat message has the same layout as native */
0476     case XFRM_MSG_DELSA:
0477     case XFRM_MSG_GETSA:
0478     case XFRM_MSG_DELPOLICY:
0479     case XFRM_MSG_GETPOLICY:
0480     case XFRM_MSG_FLUSHSA:
0481     case XFRM_MSG_FLUSHPOLICY:
0482     case XFRM_MSG_NEWAE:
0483     case XFRM_MSG_GETAE:
0484     case XFRM_MSG_REPORT:
0485     case XFRM_MSG_MIGRATE:
0486     case XFRM_MSG_NEWSADINFO:
0487     case XFRM_MSG_GETSADINFO:
0488     case XFRM_MSG_NEWSPDINFO:
0489     case XFRM_MSG_GETSPDINFO:
0490     case XFRM_MSG_MAPPING:
0491         memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]);
0492         break;
0493     /* 4 byte alignment for trailing u64 on native, but not on compat */
0494     case XFRM_MSG_NEWSA:
0495     case XFRM_MSG_NEWPOLICY:
0496     case XFRM_MSG_UPDSA:
0497     case XFRM_MSG_UPDPOLICY:
0498         memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]);
0499         break;
0500     case XFRM_MSG_EXPIRE: {
0501         const struct compat_xfrm_user_expire *src_ue = nlmsg_data(src);
0502         struct xfrm_user_expire *dst_ue = nlmsg_data(dst);
0503 
0504         /* compat_xfrm_user_expire has 4-byte smaller state */
0505         memcpy(dst_ue, src_ue, sizeof(src_ue->state));
0506         dst_ue->hard = src_ue->hard;
0507         break;
0508     }
0509     case XFRM_MSG_ACQUIRE: {
0510         const struct compat_xfrm_user_acquire *src_ua = nlmsg_data(src);
0511         struct xfrm_user_acquire *dst_ua = nlmsg_data(dst);
0512 
0513         memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos));
0514         dst_ua->aalgos = src_ua->aalgos;
0515         dst_ua->ealgos = src_ua->ealgos;
0516         dst_ua->calgos = src_ua->calgos;
0517         dst_ua->seq    = src_ua->seq;
0518         break;
0519     }
0520     case XFRM_MSG_POLEXPIRE: {
0521         const struct compat_xfrm_user_polexpire *src_upe = nlmsg_data(src);
0522         struct xfrm_user_polexpire *dst_upe = nlmsg_data(dst);
0523 
0524         /* compat_xfrm_user_polexpire has 4-byte smaller state */
0525         memcpy(dst_upe, src_upe, sizeof(src_upe->pol));
0526         dst_upe->hard = src_upe->hard;
0527         break;
0528     }
0529     case XFRM_MSG_ALLOCSPI: {
0530         const struct compat_xfrm_userspi_info *src_usi = nlmsg_data(src);
0531         struct xfrm_userspi_info *dst_usi = nlmsg_data(dst);
0532 
0533         /* compat_xfrm_user_polexpire has 4-byte smaller state */
0534         memcpy(dst_usi, src_usi, sizeof(src_usi->info));
0535         dst_usi->min = src_usi->min;
0536         dst_usi->max = src_usi->max;
0537         break;
0538     }
0539     default:
0540         NL_SET_ERR_MSG(extack, "Unsupported message type");
0541         return -EOPNOTSUPP;
0542     }
0543     pos = dst->nlmsg_len;
0544 
0545     if (maxtype) {
0546         /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
0547         WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO);
0548 
0549         for (i = 1; i <= maxtype; i++) {
0550             int err;
0551 
0552             if (!attrs[i])
0553                 continue;
0554 
0555             /* just copy - no need for translation */
0556             err = xfrm_attr_cpy32(dst, &pos, attrs[i], size,
0557                     nla_len(attrs[i]), nla_len(attrs[i]));
0558             if (err)
0559                 return err;
0560         }
0561         return 0;
0562     }
0563 
0564     for (i = 1; i < XFRMA_MAX + 1; i++) {
0565         int err;
0566 
0567         if (i == XFRMA_PAD)
0568             continue;
0569 
0570         if (!attrs[i])
0571             continue;
0572 
0573         err = xfrm_xlate32_attr(dst, attrs[i], &pos, size, extack);
0574         if (err)
0575             return err;
0576     }
0577 
0578     return 0;
0579 }
0580 
0581 static struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32,
0582             int maxtype, const struct nla_policy *policy,
0583             struct netlink_ext_ack *extack)
0584 {
0585     /* netlink_rcv_skb() checks if a message has full (struct nlmsghdr) */
0586     u16 type = h32->nlmsg_type - XFRM_MSG_BASE;
0587     struct nlattr *attrs[XFRMA_MAX+1];
0588     struct nlmsghdr *h64;
0589     size_t len;
0590     int err;
0591 
0592     BUILD_BUG_ON(ARRAY_SIZE(xfrm_msg_min) != ARRAY_SIZE(compat_msg_min));
0593 
0594     if (type >= ARRAY_SIZE(xfrm_msg_min))
0595         return ERR_PTR(-EINVAL);
0596 
0597     /* Don't call parse: the message might have only nlmsg header */
0598     if ((h32->nlmsg_type == XFRM_MSG_GETSA ||
0599          h32->nlmsg_type == XFRM_MSG_GETPOLICY) &&
0600         (h32->nlmsg_flags & NLM_F_DUMP))
0601         return NULL;
0602 
0603     err = nlmsg_parse_deprecated(h32, compat_msg_min[type], attrs,
0604             maxtype ? : XFRMA_MAX, policy ? : compat_policy, extack);
0605     if (err < 0)
0606         return ERR_PTR(err);
0607 
0608     len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype);
0609     /* The message doesn't need translation */
0610     if (len == nlmsg_len(h32))
0611         return NULL;
0612 
0613     len += NLMSG_HDRLEN;
0614     h64 = kvmalloc(len, GFP_KERNEL);
0615     if (!h64)
0616         return ERR_PTR(-ENOMEM);
0617 
0618     err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack);
0619     if (err < 0) {
0620         kvfree(h64);
0621         return ERR_PTR(err);
0622     }
0623 
0624     return h64;
0625 }
0626 
0627 static int xfrm_user_policy_compat(u8 **pdata32, int optlen)
0628 {
0629     struct compat_xfrm_userpolicy_info *p = (void *)*pdata32;
0630     u8 *src_templates, *dst_templates;
0631     u8 *data64;
0632 
0633     if (optlen < sizeof(*p))
0634         return -EINVAL;
0635 
0636     data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN);
0637     if (!data64)
0638         return -ENOMEM;
0639 
0640     memcpy(data64, *pdata32, sizeof(*p));
0641     memset(data64 + sizeof(*p), 0, 4);
0642 
0643     src_templates = *pdata32 + sizeof(*p);
0644     dst_templates = data64 + sizeof(*p) + 4;
0645     memcpy(dst_templates, src_templates, optlen - sizeof(*p));
0646 
0647     kfree(*pdata32);
0648     *pdata32 = data64;
0649     return 0;
0650 }
0651 
0652 static struct xfrm_translator xfrm_translator = {
0653     .owner              = THIS_MODULE,
0654     .alloc_compat           = xfrm_alloc_compat,
0655     .rcv_msg_compat         = xfrm_user_rcv_msg_compat,
0656     .xlate_user_policy_sockptr  = xfrm_user_policy_compat,
0657 };
0658 
0659 static int __init xfrm_compat_init(void)
0660 {
0661     return xfrm_register_translator(&xfrm_translator);
0662 }
0663 
0664 static void __exit xfrm_compat_exit(void)
0665 {
0666     xfrm_unregister_translator(&xfrm_translator);
0667 }
0668 
0669 module_init(xfrm_compat_init);
0670 module_exit(xfrm_compat_exit);
0671 MODULE_LICENSE("GPL");
0672 MODULE_AUTHOR("Dmitry Safonov");
0673 MODULE_DESCRIPTION("XFRM 32-bit compatibility layer");