xref: /kernel/linux/linux-5.10/net/xfrm/xfrm_compat.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * XFRM compat layer
48c2ecf20Sopenharmony_ci * Author: Dmitry Safonov <dima@arista.com>
58c2ecf20Sopenharmony_ci * Based on code and translator idea by: Florian Westphal <fw@strlen.de>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/compat.h>
88c2ecf20Sopenharmony_ci#include <linux/nospec.h>
98c2ecf20Sopenharmony_ci#include <linux/xfrm.h>
108c2ecf20Sopenharmony_ci#include <net/xfrm.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistruct compat_xfrm_lifetime_cfg {
138c2ecf20Sopenharmony_ci	compat_u64 soft_byte_limit, hard_byte_limit;
148c2ecf20Sopenharmony_ci	compat_u64 soft_packet_limit, hard_packet_limit;
158c2ecf20Sopenharmony_ci	compat_u64 soft_add_expires_seconds, hard_add_expires_seconds;
168c2ecf20Sopenharmony_ci	compat_u64 soft_use_expires_seconds, hard_use_expires_seconds;
178c2ecf20Sopenharmony_ci}; /* same size on 32bit, but only 4 byte alignment required */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct compat_xfrm_lifetime_cur {
208c2ecf20Sopenharmony_ci	compat_u64 bytes, packets, add_time, use_time;
218c2ecf20Sopenharmony_ci}; /* same size on 32bit, but only 4 byte alignment required */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct compat_xfrm_userpolicy_info {
248c2ecf20Sopenharmony_ci	struct xfrm_selector sel;
258c2ecf20Sopenharmony_ci	struct compat_xfrm_lifetime_cfg lft;
268c2ecf20Sopenharmony_ci	struct compat_xfrm_lifetime_cur curlft;
278c2ecf20Sopenharmony_ci	__u32 priority, index;
288c2ecf20Sopenharmony_ci	u8 dir, action, flags, share;
298c2ecf20Sopenharmony_ci	/* 4 bytes additional padding on 64bit */
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct compat_xfrm_usersa_info {
338c2ecf20Sopenharmony_ci	struct xfrm_selector sel;
348c2ecf20Sopenharmony_ci	struct xfrm_id id;
358c2ecf20Sopenharmony_ci	xfrm_address_t saddr;
368c2ecf20Sopenharmony_ci	struct compat_xfrm_lifetime_cfg lft;
378c2ecf20Sopenharmony_ci	struct compat_xfrm_lifetime_cur curlft;
388c2ecf20Sopenharmony_ci	struct xfrm_stats stats;
398c2ecf20Sopenharmony_ci	__u32 seq, reqid;
408c2ecf20Sopenharmony_ci	u16 family;
418c2ecf20Sopenharmony_ci	u8 mode, replay_window, flags;
428c2ecf20Sopenharmony_ci	/* 4 bytes additional padding on 64bit */
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct compat_xfrm_user_acquire {
468c2ecf20Sopenharmony_ci	struct xfrm_id id;
478c2ecf20Sopenharmony_ci	xfrm_address_t saddr;
488c2ecf20Sopenharmony_ci	struct xfrm_selector sel;
498c2ecf20Sopenharmony_ci	struct compat_xfrm_userpolicy_info policy;
508c2ecf20Sopenharmony_ci	/* 4 bytes additional padding on 64bit */
518c2ecf20Sopenharmony_ci	__u32 aalgos, ealgos, calgos, seq;
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct compat_xfrm_userspi_info {
558c2ecf20Sopenharmony_ci	struct compat_xfrm_usersa_info info;
568c2ecf20Sopenharmony_ci	/* 4 bytes additional padding on 64bit */
578c2ecf20Sopenharmony_ci	__u32 min, max;
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cistruct compat_xfrm_user_expire {
618c2ecf20Sopenharmony_ci	struct compat_xfrm_usersa_info state;
628c2ecf20Sopenharmony_ci	/* 8 bytes additional padding on 64bit */
638c2ecf20Sopenharmony_ci	u8 hard;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistruct compat_xfrm_user_polexpire {
678c2ecf20Sopenharmony_ci	struct compat_xfrm_userpolicy_info pol;
688c2ecf20Sopenharmony_ci	/* 8 bytes additional padding on 64bit */
698c2ecf20Sopenharmony_ci	u8 hard;
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#define XMSGSIZE(type) sizeof(struct type)
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_cistatic const int compat_msg_min[XFRM_NR_MSGTYPES] = {
758c2ecf20Sopenharmony_ci	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info),
768c2ecf20Sopenharmony_ci	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
778c2ecf20Sopenharmony_ci	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
788c2ecf20Sopenharmony_ci	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info),
798c2ecf20Sopenharmony_ci	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
808c2ecf20Sopenharmony_ci	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
818c2ecf20Sopenharmony_ci	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userspi_info),
828c2ecf20Sopenharmony_ci	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_acquire),
838c2ecf20Sopenharmony_ci	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_expire),
848c2ecf20Sopenharmony_ci	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info),
858c2ecf20Sopenharmony_ci	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info),
868c2ecf20Sopenharmony_ci	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_polexpire),
878c2ecf20Sopenharmony_ci	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
888c2ecf20Sopenharmony_ci	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
898c2ecf20Sopenharmony_ci	[XFRM_MSG_NEWAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
908c2ecf20Sopenharmony_ci	[XFRM_MSG_GETAE       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
918c2ecf20Sopenharmony_ci	[XFRM_MSG_REPORT      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
928c2ecf20Sopenharmony_ci	[XFRM_MSG_MIGRATE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
938c2ecf20Sopenharmony_ci	[XFRM_MSG_NEWSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
948c2ecf20Sopenharmony_ci	[XFRM_MSG_GETSADINFO  - XFRM_MSG_BASE] = sizeof(u32),
958c2ecf20Sopenharmony_ci	[XFRM_MSG_NEWSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
968c2ecf20Sopenharmony_ci	[XFRM_MSG_GETSPDINFO  - XFRM_MSG_BASE] = sizeof(u32),
978c2ecf20Sopenharmony_ci	[XFRM_MSG_MAPPING     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping)
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic const struct nla_policy compat_policy[XFRMA_MAX+1] = {
1018c2ecf20Sopenharmony_ci	[XFRMA_SA]		= { .len = XMSGSIZE(compat_xfrm_usersa_info)},
1028c2ecf20Sopenharmony_ci	[XFRMA_POLICY]		= { .len = XMSGSIZE(compat_xfrm_userpolicy_info)},
1038c2ecf20Sopenharmony_ci	[XFRMA_LASTUSED]	= { .type = NLA_U64},
1048c2ecf20Sopenharmony_ci	[XFRMA_ALG_AUTH_TRUNC]	= { .len = sizeof(struct xfrm_algo_auth)},
1058c2ecf20Sopenharmony_ci	[XFRMA_ALG_AEAD]	= { .len = sizeof(struct xfrm_algo_aead) },
1068c2ecf20Sopenharmony_ci	[XFRMA_ALG_AUTH]	= { .len = sizeof(struct xfrm_algo) },
1078c2ecf20Sopenharmony_ci	[XFRMA_ALG_CRYPT]	= { .len = sizeof(struct xfrm_algo) },
1088c2ecf20Sopenharmony_ci	[XFRMA_ALG_COMP]	= { .len = sizeof(struct xfrm_algo) },
1098c2ecf20Sopenharmony_ci	[XFRMA_ENCAP]		= { .len = sizeof(struct xfrm_encap_tmpl) },
1108c2ecf20Sopenharmony_ci	[XFRMA_TMPL]		= { .len = sizeof(struct xfrm_user_tmpl) },
1118c2ecf20Sopenharmony_ci	[XFRMA_SEC_CTX]		= { .len = sizeof(struct xfrm_user_sec_ctx) },
1128c2ecf20Sopenharmony_ci	[XFRMA_LTIME_VAL]	= { .len = sizeof(struct xfrm_lifetime_cur) },
1138c2ecf20Sopenharmony_ci	[XFRMA_REPLAY_VAL]	= { .len = sizeof(struct xfrm_replay_state) },
1148c2ecf20Sopenharmony_ci	[XFRMA_REPLAY_THRESH]	= { .type = NLA_U32 },
1158c2ecf20Sopenharmony_ci	[XFRMA_ETIMER_THRESH]	= { .type = NLA_U32 },
1168c2ecf20Sopenharmony_ci	[XFRMA_SRCADDR]		= { .len = sizeof(xfrm_address_t) },
1178c2ecf20Sopenharmony_ci	[XFRMA_COADDR]		= { .len = sizeof(xfrm_address_t) },
1188c2ecf20Sopenharmony_ci	[XFRMA_POLICY_TYPE]	= { .len = sizeof(struct xfrm_userpolicy_type)},
1198c2ecf20Sopenharmony_ci	[XFRMA_MIGRATE]		= { .len = sizeof(struct xfrm_user_migrate) },
1208c2ecf20Sopenharmony_ci	[XFRMA_KMADDRESS]	= { .len = sizeof(struct xfrm_user_kmaddress) },
1218c2ecf20Sopenharmony_ci	[XFRMA_MARK]		= { .len = sizeof(struct xfrm_mark) },
1228c2ecf20Sopenharmony_ci	[XFRMA_TFCPAD]		= { .type = NLA_U32 },
1238c2ecf20Sopenharmony_ci	[XFRMA_REPLAY_ESN_VAL]	= { .len = sizeof(struct xfrm_replay_state_esn) },
1248c2ecf20Sopenharmony_ci	[XFRMA_SA_EXTRA_FLAGS]	= { .type = NLA_U32 },
1258c2ecf20Sopenharmony_ci	[XFRMA_PROTO]		= { .type = NLA_U8 },
1268c2ecf20Sopenharmony_ci	[XFRMA_ADDRESS_FILTER]	= { .len = sizeof(struct xfrm_address_filter) },
1278c2ecf20Sopenharmony_ci	[XFRMA_OFFLOAD_DEV]	= { .len = sizeof(struct xfrm_user_offload) },
1288c2ecf20Sopenharmony_ci	[XFRMA_SET_MARK]	= { .type = NLA_U32 },
1298c2ecf20Sopenharmony_ci	[XFRMA_SET_MARK_MASK]	= { .type = NLA_U32 },
1308c2ecf20Sopenharmony_ci	[XFRMA_IF_ID]		= { .type = NLA_U32 },
1318c2ecf20Sopenharmony_ci	[XFRMA_MTIMER_THRESH]	= { .type = NLA_U32 },
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb,
1358c2ecf20Sopenharmony_ci			const struct nlmsghdr *nlh_src, u16 type)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	int payload = compat_msg_min[type];
1388c2ecf20Sopenharmony_ci	int src_len = xfrm_msg_min[type];
1398c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh_dst;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* Compat messages are shorter or equal to native (+padding) */
1428c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(src_len < payload))
1438c2ecf20Sopenharmony_ci		return ERR_PTR(-EMSGSIZE);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	nlh_dst = nlmsg_put(skb, nlh_src->nlmsg_pid, nlh_src->nlmsg_seq,
1468c2ecf20Sopenharmony_ci			    nlh_src->nlmsg_type, payload, nlh_src->nlmsg_flags);
1478c2ecf20Sopenharmony_ci	if (!nlh_dst)
1488c2ecf20Sopenharmony_ci		return ERR_PTR(-EMSGSIZE);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	memset(nlmsg_data(nlh_dst), 0, payload);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	switch (nlh_src->nlmsg_type) {
1538c2ecf20Sopenharmony_ci	/* Compat message has the same layout as native */
1548c2ecf20Sopenharmony_ci	case XFRM_MSG_DELSA:
1558c2ecf20Sopenharmony_ci	case XFRM_MSG_DELPOLICY:
1568c2ecf20Sopenharmony_ci	case XFRM_MSG_FLUSHSA:
1578c2ecf20Sopenharmony_ci	case XFRM_MSG_FLUSHPOLICY:
1588c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWAE:
1598c2ecf20Sopenharmony_ci	case XFRM_MSG_REPORT:
1608c2ecf20Sopenharmony_ci	case XFRM_MSG_MIGRATE:
1618c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSADINFO:
1628c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSPDINFO:
1638c2ecf20Sopenharmony_ci	case XFRM_MSG_MAPPING:
1648c2ecf20Sopenharmony_ci		WARN_ON_ONCE(src_len != payload);
1658c2ecf20Sopenharmony_ci		memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), src_len);
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	/* 4 byte alignment for trailing u64 on native, but not on compat */
1688c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSA:
1698c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWPOLICY:
1708c2ecf20Sopenharmony_ci	case XFRM_MSG_UPDSA:
1718c2ecf20Sopenharmony_ci	case XFRM_MSG_UPDPOLICY:
1728c2ecf20Sopenharmony_ci		WARN_ON_ONCE(src_len != payload + 4);
1738c2ecf20Sopenharmony_ci		memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), payload);
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	case XFRM_MSG_EXPIRE: {
1768c2ecf20Sopenharmony_ci		const struct xfrm_user_expire *src_ue  = nlmsg_data(nlh_src);
1778c2ecf20Sopenharmony_ci		struct compat_xfrm_user_expire *dst_ue = nlmsg_data(nlh_dst);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		/* compat_xfrm_user_expire has 4-byte smaller state */
1808c2ecf20Sopenharmony_ci		memcpy(dst_ue, src_ue, sizeof(dst_ue->state));
1818c2ecf20Sopenharmony_ci		dst_ue->hard = src_ue->hard;
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci	case XFRM_MSG_ACQUIRE: {
1858c2ecf20Sopenharmony_ci		const struct xfrm_user_acquire *src_ua  = nlmsg_data(nlh_src);
1868c2ecf20Sopenharmony_ci		struct compat_xfrm_user_acquire *dst_ua = nlmsg_data(nlh_dst);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos));
1898c2ecf20Sopenharmony_ci		dst_ua->aalgos = src_ua->aalgos;
1908c2ecf20Sopenharmony_ci		dst_ua->ealgos = src_ua->ealgos;
1918c2ecf20Sopenharmony_ci		dst_ua->calgos = src_ua->calgos;
1928c2ecf20Sopenharmony_ci		dst_ua->seq    = src_ua->seq;
1938c2ecf20Sopenharmony_ci		break;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci	case XFRM_MSG_POLEXPIRE: {
1968c2ecf20Sopenharmony_ci		const struct xfrm_user_polexpire *src_upe  = nlmsg_data(nlh_src);
1978c2ecf20Sopenharmony_ci		struct compat_xfrm_user_polexpire *dst_upe = nlmsg_data(nlh_dst);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		/* compat_xfrm_user_polexpire has 4-byte smaller state */
2008c2ecf20Sopenharmony_ci		memcpy(dst_upe, src_upe, sizeof(dst_upe->pol));
2018c2ecf20Sopenharmony_ci		dst_upe->hard = src_upe->hard;
2028c2ecf20Sopenharmony_ci		break;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci	case XFRM_MSG_ALLOCSPI: {
2058c2ecf20Sopenharmony_ci		const struct xfrm_userspi_info *src_usi = nlmsg_data(nlh_src);
2068c2ecf20Sopenharmony_ci		struct compat_xfrm_userspi_info *dst_usi = nlmsg_data(nlh_dst);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		/* compat_xfrm_user_polexpire has 4-byte smaller state */
2098c2ecf20Sopenharmony_ci		memcpy(dst_usi, src_usi, sizeof(src_usi->info));
2108c2ecf20Sopenharmony_ci		dst_usi->min = src_usi->min;
2118c2ecf20Sopenharmony_ci		dst_usi->max = src_usi->max;
2128c2ecf20Sopenharmony_ci		break;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	/* Not being sent by kernel */
2158c2ecf20Sopenharmony_ci	case XFRM_MSG_GETSA:
2168c2ecf20Sopenharmony_ci	case XFRM_MSG_GETPOLICY:
2178c2ecf20Sopenharmony_ci	case XFRM_MSG_GETAE:
2188c2ecf20Sopenharmony_ci	case XFRM_MSG_GETSADINFO:
2198c2ecf20Sopenharmony_ci	case XFRM_MSG_GETSPDINFO:
2208c2ecf20Sopenharmony_ci	default:
2218c2ecf20Sopenharmony_ci		pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
2228c2ecf20Sopenharmony_ci		return ERR_PTR(-EOPNOTSUPP);
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	return nlh_dst;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int xfrm_nla_cpy(struct sk_buff *dst, const struct nlattr *src, int len)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	return nla_put(dst, src->nla_type, len, nla_data(src));
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	switch (src->nla_type) {
2368c2ecf20Sopenharmony_ci	case XFRMA_PAD:
2378c2ecf20Sopenharmony_ci		/* Ignore */
2388c2ecf20Sopenharmony_ci		return 0;
2398c2ecf20Sopenharmony_ci	case XFRMA_UNSPEC:
2408c2ecf20Sopenharmony_ci	case XFRMA_ALG_AUTH:
2418c2ecf20Sopenharmony_ci	case XFRMA_ALG_CRYPT:
2428c2ecf20Sopenharmony_ci	case XFRMA_ALG_COMP:
2438c2ecf20Sopenharmony_ci	case XFRMA_ENCAP:
2448c2ecf20Sopenharmony_ci	case XFRMA_TMPL:
2458c2ecf20Sopenharmony_ci		return xfrm_nla_cpy(dst, src, nla_len(src));
2468c2ecf20Sopenharmony_ci	case XFRMA_SA:
2478c2ecf20Sopenharmony_ci		return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_usersa_info));
2488c2ecf20Sopenharmony_ci	case XFRMA_POLICY:
2498c2ecf20Sopenharmony_ci		return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_userpolicy_info));
2508c2ecf20Sopenharmony_ci	case XFRMA_SEC_CTX:
2518c2ecf20Sopenharmony_ci		return xfrm_nla_cpy(dst, src, nla_len(src));
2528c2ecf20Sopenharmony_ci	case XFRMA_LTIME_VAL:
2538c2ecf20Sopenharmony_ci		return nla_put_64bit(dst, src->nla_type, nla_len(src),
2548c2ecf20Sopenharmony_ci			nla_data(src), XFRMA_PAD);
2558c2ecf20Sopenharmony_ci	case XFRMA_REPLAY_VAL:
2568c2ecf20Sopenharmony_ci	case XFRMA_REPLAY_THRESH:
2578c2ecf20Sopenharmony_ci	case XFRMA_ETIMER_THRESH:
2588c2ecf20Sopenharmony_ci	case XFRMA_SRCADDR:
2598c2ecf20Sopenharmony_ci	case XFRMA_COADDR:
2608c2ecf20Sopenharmony_ci		return xfrm_nla_cpy(dst, src, nla_len(src));
2618c2ecf20Sopenharmony_ci	case XFRMA_LASTUSED:
2628c2ecf20Sopenharmony_ci		return nla_put_64bit(dst, src->nla_type, nla_len(src),
2638c2ecf20Sopenharmony_ci			nla_data(src), XFRMA_PAD);
2648c2ecf20Sopenharmony_ci	case XFRMA_POLICY_TYPE:
2658c2ecf20Sopenharmony_ci	case XFRMA_MIGRATE:
2668c2ecf20Sopenharmony_ci	case XFRMA_ALG_AEAD:
2678c2ecf20Sopenharmony_ci	case XFRMA_KMADDRESS:
2688c2ecf20Sopenharmony_ci	case XFRMA_ALG_AUTH_TRUNC:
2698c2ecf20Sopenharmony_ci	case XFRMA_MARK:
2708c2ecf20Sopenharmony_ci	case XFRMA_TFCPAD:
2718c2ecf20Sopenharmony_ci	case XFRMA_REPLAY_ESN_VAL:
2728c2ecf20Sopenharmony_ci	case XFRMA_SA_EXTRA_FLAGS:
2738c2ecf20Sopenharmony_ci	case XFRMA_PROTO:
2748c2ecf20Sopenharmony_ci	case XFRMA_ADDRESS_FILTER:
2758c2ecf20Sopenharmony_ci	case XFRMA_OFFLOAD_DEV:
2768c2ecf20Sopenharmony_ci	case XFRMA_SET_MARK:
2778c2ecf20Sopenharmony_ci	case XFRMA_SET_MARK_MASK:
2788c2ecf20Sopenharmony_ci	case XFRMA_IF_ID:
2798c2ecf20Sopenharmony_ci	case XFRMA_MTIMER_THRESH:
2808c2ecf20Sopenharmony_ci		return xfrm_nla_cpy(dst, src, nla_len(src));
2818c2ecf20Sopenharmony_ci	default:
2828c2ecf20Sopenharmony_ci		BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
2838c2ecf20Sopenharmony_ci		pr_warn_once("unsupported nla_type %d\n", src->nla_type);
2848c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci/* Take kernel-built (64bit layout) and create 32bit layout for userspace */
2898c2ecf20Sopenharmony_cistatic int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE;
2928c2ecf20Sopenharmony_ci	const struct nlattr *nla, *attrs;
2938c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh_dst;
2948c2ecf20Sopenharmony_ci	int len, remaining;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	nlh_dst = xfrm_nlmsg_put_compat(dst, nlh_src, type);
2978c2ecf20Sopenharmony_ci	if (IS_ERR(nlh_dst))
2988c2ecf20Sopenharmony_ci		return PTR_ERR(nlh_dst);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	attrs = nlmsg_attrdata(nlh_src, xfrm_msg_min[type]);
3018c2ecf20Sopenharmony_ci	len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	nla_for_each_attr(nla, attrs, len, remaining) {
3048c2ecf20Sopenharmony_ci		int err;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		switch (nlh_src->nlmsg_type) {
3078c2ecf20Sopenharmony_ci		case XFRM_MSG_NEWSPDINFO:
3088c2ecf20Sopenharmony_ci			err = xfrm_nla_cpy(dst, nla, nla_len(nla));
3098c2ecf20Sopenharmony_ci			break;
3108c2ecf20Sopenharmony_ci		default:
3118c2ecf20Sopenharmony_ci			err = xfrm_xlate64_attr(dst, nla);
3128c2ecf20Sopenharmony_ci			break;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci		if (err)
3158c2ecf20Sopenharmony_ci			return err;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	nlmsg_end(dst, nlh_dst);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	return 0;
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int xfrm_alloc_compat(struct sk_buff *skb, const struct nlmsghdr *nlh_src)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE;
3268c2ecf20Sopenharmony_ci	struct sk_buff *new = NULL;
3278c2ecf20Sopenharmony_ci	int err;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	if (type >= ARRAY_SIZE(xfrm_msg_min)) {
3308c2ecf20Sopenharmony_ci		pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type);
3318c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (skb_shinfo(skb)->frag_list == NULL) {
3358c2ecf20Sopenharmony_ci		new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC);
3368c2ecf20Sopenharmony_ci		if (!new)
3378c2ecf20Sopenharmony_ci			return -ENOMEM;
3388c2ecf20Sopenharmony_ci		skb_shinfo(skb)->frag_list = new;
3398c2ecf20Sopenharmony_ci	}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	err = xfrm_xlate64(skb_shinfo(skb)->frag_list, nlh_src);
3428c2ecf20Sopenharmony_ci	if (err) {
3438c2ecf20Sopenharmony_ci		if (new) {
3448c2ecf20Sopenharmony_ci			kfree_skb(new);
3458c2ecf20Sopenharmony_ci			skb_shinfo(skb)->frag_list = NULL;
3468c2ecf20Sopenharmony_ci		}
3478c2ecf20Sopenharmony_ci		return err;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return 0;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci/* Calculates len of translated 64-bit message. */
3548c2ecf20Sopenharmony_cistatic size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src,
3558c2ecf20Sopenharmony_ci					    struct nlattr *attrs[XFRMA_MAX + 1],
3568c2ecf20Sopenharmony_ci					    int maxtype)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	size_t len = nlmsg_len(src);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	switch (src->nlmsg_type) {
3618c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSA:
3628c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWPOLICY:
3638c2ecf20Sopenharmony_ci	case XFRM_MSG_ALLOCSPI:
3648c2ecf20Sopenharmony_ci	case XFRM_MSG_ACQUIRE:
3658c2ecf20Sopenharmony_ci	case XFRM_MSG_UPDPOLICY:
3668c2ecf20Sopenharmony_ci	case XFRM_MSG_UPDSA:
3678c2ecf20Sopenharmony_ci		len += 4;
3688c2ecf20Sopenharmony_ci		break;
3698c2ecf20Sopenharmony_ci	case XFRM_MSG_EXPIRE:
3708c2ecf20Sopenharmony_ci	case XFRM_MSG_POLEXPIRE:
3718c2ecf20Sopenharmony_ci		len += 8;
3728c2ecf20Sopenharmony_ci		break;
3738c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSPDINFO:
3748c2ecf20Sopenharmony_ci		/* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
3758c2ecf20Sopenharmony_ci		return len;
3768c2ecf20Sopenharmony_ci	default:
3778c2ecf20Sopenharmony_ci		break;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	/* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please
3818c2ecf20Sopenharmony_ci	 * correct both 64=>32-bit and 32=>64-bit translators to copy
3828c2ecf20Sopenharmony_ci	 * new attributes.
3838c2ecf20Sopenharmony_ci	 */
3848c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(maxtype))
3858c2ecf20Sopenharmony_ci		return len;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	if (attrs[XFRMA_SA])
3888c2ecf20Sopenharmony_ci		len += 4;
3898c2ecf20Sopenharmony_ci	if (attrs[XFRMA_POLICY])
3908c2ecf20Sopenharmony_ci		len += 4;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	/* XXX: some attrs may need to be realigned
3938c2ecf20Sopenharmony_ci	 * if !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
3948c2ecf20Sopenharmony_ci	 */
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	return len;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic int xfrm_attr_cpy32(void *dst, size_t *pos, const struct nlattr *src,
4008c2ecf20Sopenharmony_ci			   size_t size, int copy_len, int payload)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct nlmsghdr *nlmsg = dst;
4038c2ecf20Sopenharmony_ci	struct nlattr *nla;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* xfrm_user_rcv_msg_compat() relies on fact that 32-bit messages
4068c2ecf20Sopenharmony_ci	 * have the same len or shorted than 64-bit ones.
4078c2ecf20Sopenharmony_ci	 * 32-bit translation that is bigger than 64-bit original is unexpected.
4088c2ecf20Sopenharmony_ci	 */
4098c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(copy_len > payload))
4108c2ecf20Sopenharmony_ci		copy_len = payload;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (size - *pos < nla_attr_size(payload))
4138c2ecf20Sopenharmony_ci		return -ENOBUFS;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	nla = dst + *pos;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	memcpy(nla, src, nla_attr_size(copy_len));
4188c2ecf20Sopenharmony_ci	nla->nla_len = nla_attr_size(payload);
4198c2ecf20Sopenharmony_ci	*pos += nla_attr_size(copy_len);
4208c2ecf20Sopenharmony_ci	nlmsg->nlmsg_len += nla->nla_len;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	memset(dst + *pos, 0, payload - copy_len);
4238c2ecf20Sopenharmony_ci	*pos += payload - copy_len;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	return 0;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cistatic int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
4298c2ecf20Sopenharmony_ci			     size_t *pos, size_t size,
4308c2ecf20Sopenharmony_ci			     struct netlink_ext_ack *extack)
4318c2ecf20Sopenharmony_ci{
4328c2ecf20Sopenharmony_ci	int type = nla_type(nla);
4338c2ecf20Sopenharmony_ci	u16 pol_len32, pol_len64;
4348c2ecf20Sopenharmony_ci	int err;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (type > XFRMA_MAX) {
4378c2ecf20Sopenharmony_ci		BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH);
4388c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Bad attribute");
4398c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci	type = array_index_nospec(type, XFRMA_MAX + 1);
4428c2ecf20Sopenharmony_ci	if (nla_len(nla) < compat_policy[type].len) {
4438c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Attribute bad length");
4448c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	pol_len32 = compat_policy[type].len;
4488c2ecf20Sopenharmony_ci	pol_len64 = xfrma_policy[type].len;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/* XFRMA_SA and XFRMA_POLICY - need to know how-to translate */
4518c2ecf20Sopenharmony_ci	if (pol_len32 != pol_len64) {
4528c2ecf20Sopenharmony_ci		if (nla_len(nla) != compat_policy[type].len) {
4538c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG(extack, "Attribute bad length");
4548c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci		err = xfrm_attr_cpy32(dst, pos, nla, size, pol_len32, pol_len64);
4578c2ecf20Sopenharmony_ci		if (err)
4588c2ecf20Sopenharmony_ci			return err;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	return xfrm_attr_cpy32(dst, pos, nla, size, nla_len(nla), nla_len(nla));
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src,
4658c2ecf20Sopenharmony_ci			struct nlattr *attrs[XFRMA_MAX+1],
4668c2ecf20Sopenharmony_ci			size_t size, u8 type, int maxtype,
4678c2ecf20Sopenharmony_ci			struct netlink_ext_ack *extack)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	size_t pos;
4708c2ecf20Sopenharmony_ci	int i;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	memcpy(dst, src, NLMSG_HDRLEN);
4738c2ecf20Sopenharmony_ci	dst->nlmsg_len = NLMSG_HDRLEN + xfrm_msg_min[type];
4748c2ecf20Sopenharmony_ci	memset(nlmsg_data(dst), 0, xfrm_msg_min[type]);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	switch (src->nlmsg_type) {
4778c2ecf20Sopenharmony_ci	/* Compat message has the same layout as native */
4788c2ecf20Sopenharmony_ci	case XFRM_MSG_DELSA:
4798c2ecf20Sopenharmony_ci	case XFRM_MSG_GETSA:
4808c2ecf20Sopenharmony_ci	case XFRM_MSG_DELPOLICY:
4818c2ecf20Sopenharmony_ci	case XFRM_MSG_GETPOLICY:
4828c2ecf20Sopenharmony_ci	case XFRM_MSG_FLUSHSA:
4838c2ecf20Sopenharmony_ci	case XFRM_MSG_FLUSHPOLICY:
4848c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWAE:
4858c2ecf20Sopenharmony_ci	case XFRM_MSG_GETAE:
4868c2ecf20Sopenharmony_ci	case XFRM_MSG_REPORT:
4878c2ecf20Sopenharmony_ci	case XFRM_MSG_MIGRATE:
4888c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSADINFO:
4898c2ecf20Sopenharmony_ci	case XFRM_MSG_GETSADINFO:
4908c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSPDINFO:
4918c2ecf20Sopenharmony_ci	case XFRM_MSG_GETSPDINFO:
4928c2ecf20Sopenharmony_ci	case XFRM_MSG_MAPPING:
4938c2ecf20Sopenharmony_ci		memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]);
4948c2ecf20Sopenharmony_ci		break;
4958c2ecf20Sopenharmony_ci	/* 4 byte alignment for trailing u64 on native, but not on compat */
4968c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWSA:
4978c2ecf20Sopenharmony_ci	case XFRM_MSG_NEWPOLICY:
4988c2ecf20Sopenharmony_ci	case XFRM_MSG_UPDSA:
4998c2ecf20Sopenharmony_ci	case XFRM_MSG_UPDPOLICY:
5008c2ecf20Sopenharmony_ci		memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]);
5018c2ecf20Sopenharmony_ci		break;
5028c2ecf20Sopenharmony_ci	case XFRM_MSG_EXPIRE: {
5038c2ecf20Sopenharmony_ci		const struct compat_xfrm_user_expire *src_ue = nlmsg_data(src);
5048c2ecf20Sopenharmony_ci		struct xfrm_user_expire *dst_ue = nlmsg_data(dst);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		/* compat_xfrm_user_expire has 4-byte smaller state */
5078c2ecf20Sopenharmony_ci		memcpy(dst_ue, src_ue, sizeof(src_ue->state));
5088c2ecf20Sopenharmony_ci		dst_ue->hard = src_ue->hard;
5098c2ecf20Sopenharmony_ci		break;
5108c2ecf20Sopenharmony_ci	}
5118c2ecf20Sopenharmony_ci	case XFRM_MSG_ACQUIRE: {
5128c2ecf20Sopenharmony_ci		const struct compat_xfrm_user_acquire *src_ua = nlmsg_data(src);
5138c2ecf20Sopenharmony_ci		struct xfrm_user_acquire *dst_ua = nlmsg_data(dst);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos));
5168c2ecf20Sopenharmony_ci		dst_ua->aalgos = src_ua->aalgos;
5178c2ecf20Sopenharmony_ci		dst_ua->ealgos = src_ua->ealgos;
5188c2ecf20Sopenharmony_ci		dst_ua->calgos = src_ua->calgos;
5198c2ecf20Sopenharmony_ci		dst_ua->seq    = src_ua->seq;
5208c2ecf20Sopenharmony_ci		break;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci	case XFRM_MSG_POLEXPIRE: {
5238c2ecf20Sopenharmony_ci		const struct compat_xfrm_user_polexpire *src_upe = nlmsg_data(src);
5248c2ecf20Sopenharmony_ci		struct xfrm_user_polexpire *dst_upe = nlmsg_data(dst);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		/* compat_xfrm_user_polexpire has 4-byte smaller state */
5278c2ecf20Sopenharmony_ci		memcpy(dst_upe, src_upe, sizeof(src_upe->pol));
5288c2ecf20Sopenharmony_ci		dst_upe->hard = src_upe->hard;
5298c2ecf20Sopenharmony_ci		break;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci	case XFRM_MSG_ALLOCSPI: {
5328c2ecf20Sopenharmony_ci		const struct compat_xfrm_userspi_info *src_usi = nlmsg_data(src);
5338c2ecf20Sopenharmony_ci		struct xfrm_userspi_info *dst_usi = nlmsg_data(dst);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		/* compat_xfrm_user_polexpire has 4-byte smaller state */
5368c2ecf20Sopenharmony_ci		memcpy(dst_usi, src_usi, sizeof(src_usi->info));
5378c2ecf20Sopenharmony_ci		dst_usi->min = src_usi->min;
5388c2ecf20Sopenharmony_ci		dst_usi->max = src_usi->max;
5398c2ecf20Sopenharmony_ci		break;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	default:
5428c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG(extack, "Unsupported message type");
5438c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci	pos = dst->nlmsg_len;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (maxtype) {
5488c2ecf20Sopenharmony_ci		/* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */
5498c2ecf20Sopenharmony_ci		WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		for (i = 1; i <= maxtype; i++) {
5528c2ecf20Sopenharmony_ci			int err;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci			if (!attrs[i])
5558c2ecf20Sopenharmony_ci				continue;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci			/* just copy - no need for translation */
5588c2ecf20Sopenharmony_ci			err = xfrm_attr_cpy32(dst, &pos, attrs[i], size,
5598c2ecf20Sopenharmony_ci					nla_len(attrs[i]), nla_len(attrs[i]));
5608c2ecf20Sopenharmony_ci			if (err)
5618c2ecf20Sopenharmony_ci				return err;
5628c2ecf20Sopenharmony_ci		}
5638c2ecf20Sopenharmony_ci		return 0;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	for (i = 1; i < XFRMA_MAX + 1; i++) {
5678c2ecf20Sopenharmony_ci		int err;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		if (i == XFRMA_PAD)
5708c2ecf20Sopenharmony_ci			continue;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci		if (!attrs[i])
5738c2ecf20Sopenharmony_ci			continue;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci		err = xfrm_xlate32_attr(dst, attrs[i], &pos, size, extack);
5768c2ecf20Sopenharmony_ci		if (err)
5778c2ecf20Sopenharmony_ci			return err;
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	return 0;
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32,
5848c2ecf20Sopenharmony_ci			int maxtype, const struct nla_policy *policy,
5858c2ecf20Sopenharmony_ci			struct netlink_ext_ack *extack)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	/* netlink_rcv_skb() checks if a message has full (struct nlmsghdr) */
5888c2ecf20Sopenharmony_ci	u16 type = h32->nlmsg_type - XFRM_MSG_BASE;
5898c2ecf20Sopenharmony_ci	struct nlattr *attrs[XFRMA_MAX+1];
5908c2ecf20Sopenharmony_ci	struct nlmsghdr *h64;
5918c2ecf20Sopenharmony_ci	size_t len;
5928c2ecf20Sopenharmony_ci	int err;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(xfrm_msg_min) != ARRAY_SIZE(compat_msg_min));
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	if (type >= ARRAY_SIZE(xfrm_msg_min))
5978c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	/* Don't call parse: the message might have only nlmsg header */
6008c2ecf20Sopenharmony_ci	if ((h32->nlmsg_type == XFRM_MSG_GETSA ||
6018c2ecf20Sopenharmony_ci	     h32->nlmsg_type == XFRM_MSG_GETPOLICY) &&
6028c2ecf20Sopenharmony_ci	    (h32->nlmsg_flags & NLM_F_DUMP))
6038c2ecf20Sopenharmony_ci		return NULL;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	err = nlmsg_parse_deprecated(h32, compat_msg_min[type], attrs,
6068c2ecf20Sopenharmony_ci			maxtype ? : XFRMA_MAX, policy ? : compat_policy, extack);
6078c2ecf20Sopenharmony_ci	if (err < 0)
6088c2ecf20Sopenharmony_ci		return ERR_PTR(err);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype);
6118c2ecf20Sopenharmony_ci	/* The message doesn't need translation */
6128c2ecf20Sopenharmony_ci	if (len == nlmsg_len(h32))
6138c2ecf20Sopenharmony_ci		return NULL;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	len += NLMSG_HDRLEN;
6168c2ecf20Sopenharmony_ci	h64 = kvmalloc(len, GFP_KERNEL);
6178c2ecf20Sopenharmony_ci	if (!h64)
6188c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack);
6218c2ecf20Sopenharmony_ci	if (err < 0) {
6228c2ecf20Sopenharmony_ci		kvfree(h64);
6238c2ecf20Sopenharmony_ci		return ERR_PTR(err);
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	return h64;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int xfrm_user_policy_compat(u8 **pdata32, int optlen)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct compat_xfrm_userpolicy_info *p = (void *)*pdata32;
6328c2ecf20Sopenharmony_ci	u8 *src_templates, *dst_templates;
6338c2ecf20Sopenharmony_ci	u8 *data64;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (optlen < sizeof(*p))
6368c2ecf20Sopenharmony_ci		return -EINVAL;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN);
6398c2ecf20Sopenharmony_ci	if (!data64)
6408c2ecf20Sopenharmony_ci		return -ENOMEM;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	memcpy(data64, *pdata32, sizeof(*p));
6438c2ecf20Sopenharmony_ci	memset(data64 + sizeof(*p), 0, 4);
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	src_templates = *pdata32 + sizeof(*p);
6468c2ecf20Sopenharmony_ci	dst_templates = data64 + sizeof(*p) + 4;
6478c2ecf20Sopenharmony_ci	memcpy(dst_templates, src_templates, optlen - sizeof(*p));
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	kfree(*pdata32);
6508c2ecf20Sopenharmony_ci	*pdata32 = data64;
6518c2ecf20Sopenharmony_ci	return 0;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic struct xfrm_translator xfrm_translator = {
6558c2ecf20Sopenharmony_ci	.owner				= THIS_MODULE,
6568c2ecf20Sopenharmony_ci	.alloc_compat			= xfrm_alloc_compat,
6578c2ecf20Sopenharmony_ci	.rcv_msg_compat			= xfrm_user_rcv_msg_compat,
6588c2ecf20Sopenharmony_ci	.xlate_user_policy_sockptr	= xfrm_user_policy_compat,
6598c2ecf20Sopenharmony_ci};
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic int __init xfrm_compat_init(void)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	return xfrm_register_translator(&xfrm_translator);
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistatic void __exit xfrm_compat_exit(void)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	xfrm_unregister_translator(&xfrm_translator);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cimodule_init(xfrm_compat_init);
6728c2ecf20Sopenharmony_cimodule_exit(xfrm_compat_exit);
6738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dmitry Safonov");
6758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("XFRM 32-bit compatibility layer");
676