cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xfrm_compat.c (19776B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * XFRM compat layer
      4 * Author: Dmitry Safonov <dima@arista.com>
      5 * Based on code and translator idea by: Florian Westphal <fw@strlen.de>
      6 */
      7#include <linux/compat.h>
      8#include <linux/xfrm.h>
      9#include <net/xfrm.h>
     10
     11struct compat_xfrm_lifetime_cfg {
     12	compat_u64 soft_byte_limit, hard_byte_limit;
     13	compat_u64 soft_packet_limit, hard_packet_limit;
     14	compat_u64 soft_add_expires_seconds, hard_add_expires_seconds;
     15	compat_u64 soft_use_expires_seconds, hard_use_expires_seconds;
     16}; /* same size on 32bit, but only 4 byte alignment required */
     17
     18struct compat_xfrm_lifetime_cur {
     19	compat_u64 bytes, packets, add_time, use_time;
     20}; /* same size on 32bit, but only 4 byte alignment required */
     21
     22struct compat_xfrm_userpolicy_info {
     23	struct xfrm_selector sel;
     24	struct compat_xfrm_lifetime_cfg lft;
     25	struct compat_xfrm_lifetime_cur curlft;
     26	__u32 priority, index;
     27	u8 dir, action, flags, share;
     28	/* 4 bytes additional padding on 64bit */
     29};
     30
     31struct compat_xfrm_usersa_info {
     32	struct xfrm_selector sel;
     33	struct xfrm_id id;
     34	xfrm_address_t saddr;
     35	struct compat_xfrm_lifetime_cfg lft;
     36	struct compat_xfrm_lifetime_cur curlft;
     37	struct xfrm_stats stats;
     38	__u32 seq, reqid;
     39	u16 family;
     40	u8 mode, replay_window, flags;
     41	/* 4 bytes additional padding on 64bit */
     42};
     43
     44struct compat_xfrm_user_acquire {
     45	struct xfrm_id id;
     46	xfrm_address_t saddr;
     47	struct xfrm_selector sel;
     48	struct compat_xfrm_userpolicy_info policy;
     49	/* 4 bytes additional padding on 64bit */
     50	__u32 aalgos, ealgos, calgos, seq;
     51};
     52
     53struct compat_xfrm_userspi_info {
     54	struct compat_xfrm_usersa_info info;
     55	/* 4 bytes additional padding on 64bit */
     56	__u32 min, max;
     57};
     58
     59struct compat_xfrm_user_expire {
     60	struct compat_xfrm_usersa_info state;
     61	/* 8 bytes additional padding on 64bit */
     62	u8 hard;
     63};
     64
     65struct compat_xfrm_user_polexpire {
     66	struct compat_xfrm_userpolicy_info pol;
     67	/* 8 bytes additional padding on 64bit */
     68	u8 hard;
     69};
     70
     71#define XMSGSIZE(type) sizeof(struct type)
     72
     73static const int compat_msg_min[XFRM_NR_MSGTYPES] = {
     74	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info),
     75	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
     76	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
     77	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info),
     78	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
     79	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
     80	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userspi_info),
     81	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_acquire),
     82	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_expire),
     83	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info),
     84	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info),
     85	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_polexpire),
     86	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
     87	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
     88	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
     89	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
     90	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
     91	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
     92	[XFRM_MSG_NEWSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
     93	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
     94	[XFRM_MSG_NEWSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
     95	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
     96	[XFRM_MSG_MAPPING     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping)
     97};
     98
     99static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
    100	[XFRMA_SA]		= { .len = XMSGSIZE(compat_xfrm_usersa_info)},
    101	[XFRMA_POLICY]		= { .len = XMSGSIZE(compat_xfrm_userpolicy_info)},
    102	[XFRMA_LASTUSED]	= { .type = NLA_U64},
    103	[XFRMA_ALG_AUTH_TRUNC]	= { .len = sizeof(struct xfrm_algo_auth)},
    104	[XFRMA_ALG_AEAD]	= { .len = sizeof(struct xfrm_algo_aead) },
    105	[XFRMA_ALG_AUTH]	= { .len = sizeof(struct xfrm_algo) },
    106	[XFRMA_ALG_CRYPT]	= { .len = sizeof(struct xfrm_algo) },
    107	[XFRMA_ALG_COMP]	= { .len = sizeof(struct xfrm_algo) },
    108	[XFRMA_ENCAP]		= { .len = sizeof(struct xfrm_encap_tmpl) },
    109	[XFRMA_TMPL]		= { .len = sizeof(struct xfrm_user_tmpl) },
    110	[XFRMA_SEC_CTX]		= { .len = sizeof(struct xfrm_sec_ctx) },
    111	[XFRMA_LTIME_VAL]	= { .len = sizeof(struct xfrm_lifetime_cur) },
    112	[XFRMA_REPLAY_VAL]	= { .len = sizeof(struct xfrm_replay_state) },
    113	[XFRMA_REPLAY_THRESH]	= { .type = NLA_U32 },
    114	[XFRMA_ETIMER_THRESH]	= { .type = NLA_U32 },
    115	[XFRMA_SRCADDR]		= { .len = sizeof(xfrm_address_t) },
    116	[XFRMA_COADDR]		= { .len = sizeof(xfrm_address_t) },
    117	[XFRMA_POLICY_TYPE]	= { .len = sizeof(struct xfrm_userpolicy_type)},
    118	[XFRMA_MIGRATE]		= { .len = sizeof(struct xfrm_user_migrate) },
    119	[XFRMA_KMADDRESS]	= { .len = sizeof(struct xfrm_user_kmaddress) },
    120	[XFRMA_MARK]		= { .len = sizeof(struct xfrm_mark) },
    121	[XFRMA_TFCPAD]		= { .type = NLA_U32 },
    122	[XFRMA_REPLAY_ESN_VAL]	= { .len = sizeof(struct xfrm_replay_state_esn) },
    123	[XFRMA_SA_EXTRA_FLAGS]	= { .type = NLA_U32 },
    124	[XFRMA_PROTO]		= { .type = NLA_U8 },
    125	[XFRMA_ADDRESS_FILTER]	= { .len = sizeof(struct xfrm_address_filter) },
    126	[XFRMA_OFFLOAD_DEV]	= { .len = sizeof(struct xfrm_user_offload) },
    127	[XFRMA_SET_MARK]	= { .type = NLA_U32 },
    128	[XFRMA_SET_MARK_MASK]	= { .type = NLA_U32 },
    129	[XFRMA_IF_ID]		= { .type = NLA_U32 },
    130	[XFRMA_MTIMER_THRESH]	= { .type = NLA_U32 },
    131};
    132
    133static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb,
    134			const struct nlmsghdr *nlh_src, u16 type)
    135{
    136	int payload = compat_msg_min[type];
    137	int src_len = xfrm_msg_min[type];
    138	struct nlmsghdr *nlh_dst;
    139
    140	/* Compat messages are shorter or equal to native (+padding) */
    141	if (WARN_ON_ONCE(src_len < payload))
    142		return ERR_PTR(-EMSGSIZE);
    143
    144	nlh_dst = nlmsg_put(skb, nlh_src->nlmsg_pid, nlh_src->nlmsg_seq,
    145			    nlh_src->nlmsg_type, payload, nlh_src->nlmsg_flags);
    146	if (!nlh_dst)
    147		return ERR_PTR(-EMSGSIZE);
    148
    149	memset(nlmsg_data(nlh_dst), 0, payload);
    150
    151	switch (nlh_src->nlmsg_type) {
    152	/* Compat message has the same layout as native */
    153	case XFRM_MSG_DELSA:
    154	case XFRM_MSG_DELPOLICY:
    155	case XFRM_MSG_FLUSHSA:
    156	case XFRM_MSG_FLUSHPOLICY:
    157	case XFRM_MSG_NEWAE:
    158	case XFRM_MSG_REPORT:
    159	case XFRM_MSG_MIGRATE:
    160	case XFRM_MSG_NEWSADINFO:
    161	case XFRM_MSG_NEWSPDINFO:
    162	case XFRM_MSG_MAPPING:
    163		WARN_ON_ONCE(src_len != payload);
    164		memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), src_len);
    165		break;
    166	/* 4 byte alignment for trailing u64 on native, but not on compat */
    167	case XFRM_MSG_NEWSA:
    168	case XFRM_MSG_NEWPOLICY:
    169	case XFRM_MSG_UPDSA:
    170	case XFRM_MSG_UPDPOLICY:
    171		WARN_ON_ONCE(src_len != payload + 4);
    172		memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), payload);
    173		break;
    174	case XFRM_MSG_EXPIRE: {
    175		const struct xfrm_user_expire *src_ue  = nlmsg_data(nlh_src);
    176		struct compat_xfrm_user_expire *dst_ue = nlmsg_data(nlh_dst);
    177
    178		/* compat_xfrm_user_expire has 4-byte smaller state */
    179		memcpy(dst_ue, src_ue, sizeof(dst_ue->state));
    180		dst_ue->hard = src_ue->hard;
    181		break;
    182	}
    183	case XFRM_MSG_ACQUIRE: {
    184		const struct xfrm_user_acquire *src_ua  = nlmsg_data(nlh_src);
    185		struct compat_xfrm_user_acquire *dst_ua = nlmsg_data(nlh_dst);
    186
    187		memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos));
    188		dst_ua->aalgos = src_ua->aalgos;
    189		dst_ua->ealgos = src_ua->ealgos;
    190		dst_ua->calgos = src_ua->calgos;
    191		dst_ua->seq    = src_ua->seq;
    192		break;
    193	}
    194	case XFRM_MSG_POLEXPIRE: {
    195		const struct xfrm_user_polexpire *src_upe  = nlmsg_data(nlh_src);
    196		struct compat_xfrm_user_polexpire *dst_upe = nlmsg_data(nlh_dst);
    197
    198		/* compat_xfrm_user_polexpire has 4-byte smaller state */
    199		memcpy(dst_upe, src_upe, sizeof(dst_upe->pol));
    200		dst_upe->hard = src_upe->hard;
    201		break;
    202	}
    203	case XFRM_MSG_ALLOCSPI: {
    204		const struct xfrm_userspi_info *src_usi = nlmsg_data(nlh_src);
    205		struct compat_xfrm_userspi_info *dst_usi = nlmsg_data(nlh_dst);
    206
    207		/* compat_xfrm_user_polexpire has 4-byte smaller state */
    208		memcpy(dst_usi, src_usi, sizeof(src_usi->info));
    209		dst_usi->min = src_usi->min;
    210		dst_usi->max = src_usi->max;
    211		break;
    212	}
    213	/* Not being sent by kernel */
    214	case XFRM_MSG_GETSA:
    215	case XFRM_MSG_GETPOLICY:
    216	case XFRM_MSG_GETAE:
    217	case XFRM_MSG_GETSADINFO:
    218	case XFRM_MSG_GETSPDINFO:
    219	default:
    220		pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
    221		return ERR_PTR(-EOPNOTSUPP);
    222	}
    223
    224	return nlh_dst;
    225}
    226
    227static int xfrm_nla_cpy(struct sk_buff *dst, const struct nlattr *src, int len)
    228{
    229	return nla_put(dst, src->nla_type, len, nla_data(src));
    230}
    231
    232static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
    233{
    234	switch (src->nla_type) {
    235	case XFRMA_PAD:
    236		/* Ignore */
    237		return 0;
    238	case XFRMA_UNSPEC:
    239	case XFRMA_ALG_AUTH:
    240	case XFRMA_ALG_CRYPT:
    241	case XFRMA_ALG_COMP:
    242	case XFRMA_ENCAP:
    243	case XFRMA_TMPL:
    244		return xfrm_nla_cpy(dst, src, nla_len(src));
    245	case XFRMA_SA:
    246		return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_usersa_info));
    247	case XFRMA_POLICY:
    248		return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_userpolicy_info));
    249	case XFRMA_SEC_CTX:
    250		return xfrm_nla_cpy(dst, src, nla_len(src));
    251	case XFRMA_LTIME_VAL:
    252		return nla_put_64bit(dst, src->nla_type, nla_len(src),
    253			nla_data(src), XFRMA_PAD);
    254	case XFRMA_REPLAY_VAL:
    255	case XFRMA_REPLAY_THRESH:
    256	case XFRMA_ETIMER_THRESH:
    257	case XFRMA_SRCADDR:
    258	case XFRMA_COADDR:
    259		return xfrm_nla_cpy(dst, src, nla_len(src));
    260	case XFRMA_LASTUSED:
    261		return nla_put_64bit(dst, src->nla_type, nla_len(src),
    262			nla_data(src), XFRMA_PAD);
    263	case XFRMA_POLICY_TYPE:
    264	case XFRMA_MIGRATE:
    265	case XFRMA_ALG_AEAD:
    266	case XFRMA_KMADDRESS:
    267	case XFRMA_ALG_AUTH_TRUNC:
    268	case XFRMA_MARK:
    269	case XFRMA_TFCPAD:
    270	case XFRMA_REPLAY_ESN_VAL:
    271	case XFRMA_SA_EXTRA_FLAGS:
    272	case XFRMA_PROTO:
    273	case XFRMA_ADDRESS_FILTER:
    274	case XFRMA_OFFLOAD_DEV:
    275	case XFRMA_SET_MARK:
    276	case XFRMA_SET_MARK_MASK:
    277	case XFRMA_IF_ID:
    278	case XFRMA_MTIMER_THRESH:
    279		return xfrm_nla_cpy(dst, src, nla_len(src));
    280	default:
    281		BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
    282		pr_warn_once("unsupported nla_type %d\n", src->nla_type);
    283		return -EOPNOTSUPP;
    284	}
    285}
    286
    287/* Take kernel-built (64bit layout) and create 32bit layout for userspace */
    288static int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src)
    289{
    290	u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE;
    291	const struct nlattr *nla, *attrs;
    292	struct nlmsghdr *nlh_dst;
    293	int len, remaining;
    294
    295	nlh_dst = xfrm_nlmsg_put_compat(dst, nlh_src, type);
    296	if (IS_ERR(nlh_dst))
    297		return PTR_ERR(nlh_dst);
    298
    299	attrs = nlmsg_attrdata(nlh_src, xfrm_msg_min[type]);
    300	len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]);
    301
    302	nla_for_each_attr(nla, attrs, len, remaining) {
    303		int err;
    304
    305		switch (type) {
    306		case XFRM_MSG_NEWSPDINFO:
    307			err = xfrm_nla_cpy(dst, nla, nla_len(nla));
    308			break;
    309		default:
    310			err = xfrm_xlate64_attr(dst, nla);
    311			break;
    312		}
    313		if (err)
    314			return err;
    315	}
    316
    317	nlmsg_end(dst, nlh_dst);
    318
    319	return 0;
    320}
    321
    322static int xfrm_alloc_compat(struct sk_buff *skb, const struct nlmsghdr *nlh_src)
    323{
    324	u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE;
    325	struct sk_buff *new = NULL;
    326	int err;
    327
    328	if (type >= ARRAY_SIZE(xfrm_msg_min)) {
    329		pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
    330		return -EOPNOTSUPP;
    331	}
    332
    333	if (skb_shinfo(skb)->frag_list == NULL) {
    334		new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC);
    335		if (!new)
    336			return -ENOMEM;
    337		skb_shinfo(skb)->frag_list = new;
    338	}
    339
    340	err = xfrm_xlate64(skb_shinfo(skb)->frag_list, nlh_src);
    341	if (err) {
    342		if (new) {
    343			kfree_skb(new);
    344			skb_shinfo(skb)->frag_list = NULL;
    345		}
    346		return err;
    347	}
    348
    349	return 0;
    350}
    351
    352/* Calculates len of translated 64-bit message. */
    353static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src,
    354					    struct nlattr *attrs[XFRMA_MAX + 1],
    355					    int maxtype)
    356{
    357	size_t len = nlmsg_len(src);
    358
    359	switch (src->nlmsg_type) {
    360	case XFRM_MSG_NEWSA:
    361	case XFRM_MSG_NEWPOLICY:
    362	case XFRM_MSG_ALLOCSPI:
    363	case XFRM_MSG_ACQUIRE:
    364	case XFRM_MSG_UPDPOLICY:
    365	case XFRM_MSG_UPDSA:
    366		len += 4;
    367		break;
    368	case XFRM_MSG_EXPIRE:
    369	case XFRM_MSG_POLEXPIRE:
    370		len += 8;
    371		break;
    372	case XFRM_MSG_NEWSPDINFO:
    373		/* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
    374		return len;
    375	default:
    376		break;
    377	}
    378
    379	/* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please
    380	 * correct both 64=>32-bit and 32=>64-bit translators to copy
    381	 * new attributes.
    382	 */
    383	if (WARN_ON_ONCE(maxtype))
    384		return len;
    385
    386	if (attrs[XFRMA_SA])
    387		len += 4;
    388	if (attrs[XFRMA_POLICY])
    389		len += 4;
    390
    391	/* XXX: some attrs may need to be realigned
    392	 * if !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
    393	 */
    394
    395	return len;
    396}
    397
    398static int xfrm_attr_cpy32(void *dst, size_t *pos, const struct nlattr *src,
    399			   size_t size, int copy_len, int payload)
    400{
    401	struct nlmsghdr *nlmsg = dst;
    402	struct nlattr *nla;
    403
    404	/* xfrm_user_rcv_msg_compat() relies on fact that 32-bit messages
    405	 * have the same len or shorted than 64-bit ones.
    406	 * 32-bit translation that is bigger than 64-bit original is unexpected.
    407	 */
    408	if (WARN_ON_ONCE(copy_len > payload))
    409		copy_len = payload;
    410
    411	if (size - *pos < nla_attr_size(payload))
    412		return -ENOBUFS;
    413
    414	nla = dst + *pos;
    415
    416	memcpy(nla, src, nla_attr_size(copy_len));
    417	nla->nla_len = nla_attr_size(payload);
    418	*pos += nla_attr_size(copy_len);
    419	nlmsg->nlmsg_len += nla->nla_len;
    420
    421	memset(dst + *pos, 0, payload - copy_len);
    422	*pos += payload - copy_len;
    423
    424	return 0;
    425}
    426
    427static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
    428			     size_t *pos, size_t size,
    429			     struct netlink_ext_ack *extack)
    430{
    431	int type = nla_type(nla);
    432	u16 pol_len32, pol_len64;
    433	int err;
    434
    435	if (type > XFRMA_MAX) {
    436		BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
    437		NL_SET_ERR_MSG(extack, "Bad attribute");
    438		return -EOPNOTSUPP;
    439	}
    440	if (nla_len(nla) < compat_policy[type].len) {
    441		NL_SET_ERR_MSG(extack, "Attribute bad length");
    442		return -EOPNOTSUPP;
    443	}
    444
    445	pol_len32 = compat_policy[type].len;
    446	pol_len64 = xfrma_policy[type].len;
    447
    448	/* XFRMA_SA and XFRMA_POLICY - need to know how-to translate */
    449	if (pol_len32 != pol_len64) {
    450		if (nla_len(nla) != compat_policy[type].len) {
    451			NL_SET_ERR_MSG(extack, "Attribute bad length");
    452			return -EOPNOTSUPP;
    453		}
    454		err = xfrm_attr_cpy32(dst, pos, nla, size, pol_len32, pol_len64);
    455		if (err)
    456			return err;
    457	}
    458
    459	return xfrm_attr_cpy32(dst, pos, nla, size, nla_len(nla), nla_len(nla));
    460}
    461
    462static int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src,
    463			struct nlattr *attrs[XFRMA_MAX+1],
    464			size_t size, u8 type, int maxtype,
    465			struct netlink_ext_ack *extack)
    466{
    467	size_t pos;
    468	int i;
    469
    470	memcpy(dst, src, NLMSG_HDRLEN);
    471	dst->nlmsg_len = NLMSG_HDRLEN + xfrm_msg_min[type];
    472	memset(nlmsg_data(dst), 0, xfrm_msg_min[type]);
    473
    474	switch (src->nlmsg_type) {
    475	/* Compat message has the same layout as native */
    476	case XFRM_MSG_DELSA:
    477	case XFRM_MSG_GETSA:
    478	case XFRM_MSG_DELPOLICY:
    479	case XFRM_MSG_GETPOLICY:
    480	case XFRM_MSG_FLUSHSA:
    481	case XFRM_MSG_FLUSHPOLICY:
    482	case XFRM_MSG_NEWAE:
    483	case XFRM_MSG_GETAE:
    484	case XFRM_MSG_REPORT:
    485	case XFRM_MSG_MIGRATE:
    486	case XFRM_MSG_NEWSADINFO:
    487	case XFRM_MSG_GETSADINFO:
    488	case XFRM_MSG_NEWSPDINFO:
    489	case XFRM_MSG_GETSPDINFO:
    490	case XFRM_MSG_MAPPING:
    491		memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]);
    492		break;
    493	/* 4 byte alignment for trailing u64 on native, but not on compat */
    494	case XFRM_MSG_NEWSA:
    495	case XFRM_MSG_NEWPOLICY:
    496	case XFRM_MSG_UPDSA:
    497	case XFRM_MSG_UPDPOLICY:
    498		memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]);
    499		break;
    500	case XFRM_MSG_EXPIRE: {
    501		const struct compat_xfrm_user_expire *src_ue = nlmsg_data(src);
    502		struct xfrm_user_expire *dst_ue = nlmsg_data(dst);
    503
    504		/* compat_xfrm_user_expire has 4-byte smaller state */
    505		memcpy(dst_ue, src_ue, sizeof(src_ue->state));
    506		dst_ue->hard = src_ue->hard;
    507		break;
    508	}
    509	case XFRM_MSG_ACQUIRE: {
    510		const struct compat_xfrm_user_acquire *src_ua = nlmsg_data(src);
    511		struct xfrm_user_acquire *dst_ua = nlmsg_data(dst);
    512
    513		memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos));
    514		dst_ua->aalgos = src_ua->aalgos;
    515		dst_ua->ealgos = src_ua->ealgos;
    516		dst_ua->calgos = src_ua->calgos;
    517		dst_ua->seq    = src_ua->seq;
    518		break;
    519	}
    520	case XFRM_MSG_POLEXPIRE: {
    521		const struct compat_xfrm_user_polexpire *src_upe = nlmsg_data(src);
    522		struct xfrm_user_polexpire *dst_upe = nlmsg_data(dst);
    523
    524		/* compat_xfrm_user_polexpire has 4-byte smaller state */
    525		memcpy(dst_upe, src_upe, sizeof(src_upe->pol));
    526		dst_upe->hard = src_upe->hard;
    527		break;
    528	}
    529	case XFRM_MSG_ALLOCSPI: {
    530		const struct compat_xfrm_userspi_info *src_usi = nlmsg_data(src);
    531		struct xfrm_userspi_info *dst_usi = nlmsg_data(dst);
    532
    533		/* compat_xfrm_user_polexpire has 4-byte smaller state */
    534		memcpy(dst_usi, src_usi, sizeof(src_usi->info));
    535		dst_usi->min = src_usi->min;
    536		dst_usi->max = src_usi->max;
    537		break;
    538	}
    539	default:
    540		NL_SET_ERR_MSG(extack, "Unsupported message type");
    541		return -EOPNOTSUPP;
    542	}
    543	pos = dst->nlmsg_len;
    544
    545	if (maxtype) {
    546		/* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
    547		WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO);
    548
    549		for (i = 1; i <= maxtype; i++) {
    550			int err;
    551
    552			if (!attrs[i])
    553				continue;
    554
    555			/* just copy - no need for translation */
    556			err = xfrm_attr_cpy32(dst, &pos, attrs[i], size,
    557					nla_len(attrs[i]), nla_len(attrs[i]));
    558			if (err)
    559				return err;
    560		}
    561		return 0;
    562	}
    563
    564	for (i = 1; i < XFRMA_MAX + 1; i++) {
    565		int err;
    566
    567		if (i == XFRMA_PAD)
    568			continue;
    569
    570		if (!attrs[i])
    571			continue;
    572
    573		err = xfrm_xlate32_attr(dst, attrs[i], &pos, size, extack);
    574		if (err)
    575			return err;
    576	}
    577
    578	return 0;
    579}
    580
    581static struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32,
    582			int maxtype, const struct nla_policy *policy,
    583			struct netlink_ext_ack *extack)
    584{
    585	/* netlink_rcv_skb() checks if a message has full (struct nlmsghdr) */
    586	u16 type = h32->nlmsg_type - XFRM_MSG_BASE;
    587	struct nlattr *attrs[XFRMA_MAX+1];
    588	struct nlmsghdr *h64;
    589	size_t len;
    590	int err;
    591
    592	BUILD_BUG_ON(ARRAY_SIZE(xfrm_msg_min) != ARRAY_SIZE(compat_msg_min));
    593
    594	if (type >= ARRAY_SIZE(xfrm_msg_min))
    595		return ERR_PTR(-EINVAL);
    596
    597	/* Don't call parse: the message might have only nlmsg header */
    598	if ((h32->nlmsg_type == XFRM_MSG_GETSA ||
    599	     h32->nlmsg_type == XFRM_MSG_GETPOLICY) &&
    600	    (h32->nlmsg_flags & NLM_F_DUMP))
    601		return NULL;
    602
    603	err = nlmsg_parse_deprecated(h32, compat_msg_min[type], attrs,
    604			maxtype ? : XFRMA_MAX, policy ? : compat_policy, extack);
    605	if (err < 0)
    606		return ERR_PTR(err);
    607
    608	len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype);
    609	/* The message doesn't need translation */
    610	if (len == nlmsg_len(h32))
    611		return NULL;
    612
    613	len += NLMSG_HDRLEN;
    614	h64 = kvmalloc(len, GFP_KERNEL);
    615	if (!h64)
    616		return ERR_PTR(-ENOMEM);
    617
    618	err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack);
    619	if (err < 0) {
    620		kvfree(h64);
    621		return ERR_PTR(err);
    622	}
    623
    624	return h64;
    625}
    626
    627static int xfrm_user_policy_compat(u8 **pdata32, int optlen)
    628{
    629	struct compat_xfrm_userpolicy_info *p = (void *)*pdata32;
    630	u8 *src_templates, *dst_templates;
    631	u8 *data64;
    632
    633	if (optlen < sizeof(*p))
    634		return -EINVAL;
    635
    636	data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN);
    637	if (!data64)
    638		return -ENOMEM;
    639
    640	memcpy(data64, *pdata32, sizeof(*p));
    641	memset(data64 + sizeof(*p), 0, 4);
    642
    643	src_templates = *pdata32 + sizeof(*p);
    644	dst_templates = data64 + sizeof(*p) + 4;
    645	memcpy(dst_templates, src_templates, optlen - sizeof(*p));
    646
    647	kfree(*pdata32);
    648	*pdata32 = data64;
    649	return 0;
    650}
    651
    652static struct xfrm_translator xfrm_translator = {
    653	.owner				= THIS_MODULE,
    654	.alloc_compat			= xfrm_alloc_compat,
    655	.rcv_msg_compat			= xfrm_user_rcv_msg_compat,
    656	.xlate_user_policy_sockptr	= xfrm_user_policy_compat,
    657};
    658
    659static int __init xfrm_compat_init(void)
    660{
    661	return xfrm_register_translator(&xfrm_translator);
    662}
    663
    664static void __exit xfrm_compat_exit(void)
    665{
    666	xfrm_unregister_translator(&xfrm_translator);
    667}
    668
    669module_init(xfrm_compat_init);
    670module_exit(xfrm_compat_exit);
    671MODULE_LICENSE("GPL");
    672MODULE_AUTHOR("Dmitry Safonov");
    673MODULE_DESCRIPTION("XFRM 32-bit compatibility layer");