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