1c9e7c76dSDmitry Safonov // SPDX-License-Identifier: GPL-2.0 2c9e7c76dSDmitry Safonov /* 3c9e7c76dSDmitry Safonov * XFRM compat layer 4c9e7c76dSDmitry Safonov * Author: Dmitry Safonov <dima@arista.com> 5c9e7c76dSDmitry Safonov * Based on code and translator idea by: Florian Westphal <fw@strlen.de> 6c9e7c76dSDmitry Safonov */ 7c9e7c76dSDmitry Safonov #include <linux/compat.h> 8c9e7c76dSDmitry Safonov #include <linux/xfrm.h> 9c9e7c76dSDmitry Safonov #include <net/xfrm.h> 10c9e7c76dSDmitry Safonov 115461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cfg { 125461fc0cSDmitry Safonov compat_u64 soft_byte_limit, hard_byte_limit; 135461fc0cSDmitry Safonov compat_u64 soft_packet_limit, hard_packet_limit; 145461fc0cSDmitry Safonov compat_u64 soft_add_expires_seconds, hard_add_expires_seconds; 155461fc0cSDmitry Safonov compat_u64 soft_use_expires_seconds, hard_use_expires_seconds; 165461fc0cSDmitry Safonov }; /* same size on 32bit, but only 4 byte alignment required */ 175461fc0cSDmitry Safonov 185461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cur { 195461fc0cSDmitry Safonov compat_u64 bytes, packets, add_time, use_time; 205461fc0cSDmitry Safonov }; /* same size on 32bit, but only 4 byte alignment required */ 215461fc0cSDmitry Safonov 225461fc0cSDmitry Safonov struct compat_xfrm_userpolicy_info { 235461fc0cSDmitry Safonov struct xfrm_selector sel; 245461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cfg lft; 255461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cur curlft; 265461fc0cSDmitry Safonov __u32 priority, index; 275461fc0cSDmitry Safonov u8 dir, action, flags, share; 285461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 295461fc0cSDmitry Safonov }; 305461fc0cSDmitry Safonov 315461fc0cSDmitry Safonov struct compat_xfrm_usersa_info { 325461fc0cSDmitry Safonov struct xfrm_selector sel; 335461fc0cSDmitry Safonov struct xfrm_id id; 345461fc0cSDmitry Safonov xfrm_address_t saddr; 355461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cfg lft; 365461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cur curlft; 375461fc0cSDmitry Safonov struct xfrm_stats stats; 385461fc0cSDmitry Safonov __u32 seq, reqid; 395461fc0cSDmitry Safonov u16 family; 405461fc0cSDmitry Safonov u8 mode, replay_window, flags; 415461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 425461fc0cSDmitry Safonov }; 435461fc0cSDmitry Safonov 445461fc0cSDmitry Safonov struct compat_xfrm_user_acquire { 455461fc0cSDmitry Safonov struct xfrm_id id; 465461fc0cSDmitry Safonov xfrm_address_t saddr; 475461fc0cSDmitry Safonov struct xfrm_selector sel; 485461fc0cSDmitry Safonov struct compat_xfrm_userpolicy_info policy; 495461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 505461fc0cSDmitry Safonov __u32 aalgos, ealgos, calgos, seq; 515461fc0cSDmitry Safonov }; 525461fc0cSDmitry Safonov 535461fc0cSDmitry Safonov struct compat_xfrm_userspi_info { 545461fc0cSDmitry Safonov struct compat_xfrm_usersa_info info; 555461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 565461fc0cSDmitry Safonov __u32 min, max; 575461fc0cSDmitry Safonov }; 585461fc0cSDmitry Safonov 595461fc0cSDmitry Safonov struct compat_xfrm_user_expire { 605461fc0cSDmitry Safonov struct compat_xfrm_usersa_info state; 615461fc0cSDmitry Safonov /* 8 bytes additional padding on 64bit */ 625461fc0cSDmitry Safonov u8 hard; 635461fc0cSDmitry Safonov }; 645461fc0cSDmitry Safonov 655461fc0cSDmitry Safonov struct compat_xfrm_user_polexpire { 665461fc0cSDmitry Safonov struct compat_xfrm_userpolicy_info pol; 675461fc0cSDmitry Safonov /* 8 bytes additional padding on 64bit */ 685461fc0cSDmitry Safonov u8 hard; 695461fc0cSDmitry Safonov }; 705461fc0cSDmitry Safonov 715461fc0cSDmitry Safonov #define XMSGSIZE(type) sizeof(struct type) 725461fc0cSDmitry Safonov 735461fc0cSDmitry Safonov static const int compat_msg_min[XFRM_NR_MSGTYPES] = { 745461fc0cSDmitry Safonov [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info), 755461fc0cSDmitry Safonov [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 765461fc0cSDmitry Safonov [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 775461fc0cSDmitry Safonov [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info), 785461fc0cSDmitry Safonov [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 795461fc0cSDmitry Safonov [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 805461fc0cSDmitry Safonov [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userspi_info), 815461fc0cSDmitry Safonov [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_acquire), 825461fc0cSDmitry Safonov [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_expire), 835461fc0cSDmitry Safonov [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info), 845461fc0cSDmitry Safonov [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info), 855461fc0cSDmitry Safonov [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_polexpire), 865461fc0cSDmitry Safonov [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), 875461fc0cSDmitry Safonov [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0, 885461fc0cSDmitry Safonov [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 895461fc0cSDmitry Safonov [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 905461fc0cSDmitry Safonov [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), 915461fc0cSDmitry Safonov [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 925461fc0cSDmitry Safonov [XFRM_MSG_NEWSADINFO - XFRM_MSG_BASE] = sizeof(u32), 935461fc0cSDmitry Safonov [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32), 945461fc0cSDmitry Safonov [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 955461fc0cSDmitry Safonov [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 965461fc0cSDmitry Safonov [XFRM_MSG_MAPPING - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping) 975461fc0cSDmitry Safonov }; 985461fc0cSDmitry Safonov 995106f4a8SDmitry Safonov static const struct nla_policy compat_policy[XFRMA_MAX+1] = { 1005106f4a8SDmitry Safonov [XFRMA_SA] = { .len = XMSGSIZE(compat_xfrm_usersa_info)}, 1015106f4a8SDmitry Safonov [XFRMA_POLICY] = { .len = XMSGSIZE(compat_xfrm_userpolicy_info)}, 1025106f4a8SDmitry Safonov [XFRMA_LASTUSED] = { .type = NLA_U64}, 1035106f4a8SDmitry Safonov [XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)}, 1045106f4a8SDmitry Safonov [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, 1055106f4a8SDmitry Safonov [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, 1065106f4a8SDmitry Safonov [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, 1075106f4a8SDmitry Safonov [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, 1085106f4a8SDmitry Safonov [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) }, 1095106f4a8SDmitry Safonov [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) }, 1105106f4a8SDmitry Safonov [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) }, 1115106f4a8SDmitry Safonov [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) }, 1125106f4a8SDmitry Safonov [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) }, 1135106f4a8SDmitry Safonov [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 }, 1145106f4a8SDmitry Safonov [XFRMA_ETIMER_THRESH] = { .type = NLA_U32 }, 1155106f4a8SDmitry Safonov [XFRMA_SRCADDR] = { .len = sizeof(xfrm_address_t) }, 1165106f4a8SDmitry Safonov [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, 1175106f4a8SDmitry Safonov [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, 1185106f4a8SDmitry Safonov [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, 1195106f4a8SDmitry Safonov [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, 1205106f4a8SDmitry Safonov [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, 1215106f4a8SDmitry Safonov [XFRMA_TFCPAD] = { .type = NLA_U32 }, 1225106f4a8SDmitry Safonov [XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) }, 1235106f4a8SDmitry Safonov [XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 }, 1245106f4a8SDmitry Safonov [XFRMA_PROTO] = { .type = NLA_U8 }, 1255106f4a8SDmitry Safonov [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, 1265106f4a8SDmitry Safonov [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, 1275106f4a8SDmitry Safonov [XFRMA_SET_MARK] = { .type = NLA_U32 }, 1285106f4a8SDmitry Safonov [XFRMA_SET_MARK_MASK] = { .type = NLA_U32 }, 1295106f4a8SDmitry Safonov [XFRMA_IF_ID] = { .type = NLA_U32 }, 130*4e484b3eSAntony Antony [XFRMA_MTIMER_THRESH] = { .type = NLA_U32 }, 1315106f4a8SDmitry Safonov }; 1325106f4a8SDmitry Safonov 1335461fc0cSDmitry Safonov static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb, 1345461fc0cSDmitry Safonov const struct nlmsghdr *nlh_src, u16 type) 1355461fc0cSDmitry Safonov { 1365461fc0cSDmitry Safonov int payload = compat_msg_min[type]; 1375461fc0cSDmitry Safonov int src_len = xfrm_msg_min[type]; 1385461fc0cSDmitry Safonov struct nlmsghdr *nlh_dst; 1395461fc0cSDmitry Safonov 1405461fc0cSDmitry Safonov /* Compat messages are shorter or equal to native (+padding) */ 1415461fc0cSDmitry Safonov if (WARN_ON_ONCE(src_len < payload)) 1425461fc0cSDmitry Safonov return ERR_PTR(-EMSGSIZE); 1435461fc0cSDmitry Safonov 1445461fc0cSDmitry Safonov nlh_dst = nlmsg_put(skb, nlh_src->nlmsg_pid, nlh_src->nlmsg_seq, 1455461fc0cSDmitry Safonov nlh_src->nlmsg_type, payload, nlh_src->nlmsg_flags); 1465461fc0cSDmitry Safonov if (!nlh_dst) 1475461fc0cSDmitry Safonov return ERR_PTR(-EMSGSIZE); 1485461fc0cSDmitry Safonov 1495461fc0cSDmitry Safonov memset(nlmsg_data(nlh_dst), 0, payload); 1505461fc0cSDmitry Safonov 1515461fc0cSDmitry Safonov switch (nlh_src->nlmsg_type) { 1525461fc0cSDmitry Safonov /* Compat message has the same layout as native */ 1535461fc0cSDmitry Safonov case XFRM_MSG_DELSA: 1545461fc0cSDmitry Safonov case XFRM_MSG_DELPOLICY: 1555461fc0cSDmitry Safonov case XFRM_MSG_FLUSHSA: 1565461fc0cSDmitry Safonov case XFRM_MSG_FLUSHPOLICY: 1575461fc0cSDmitry Safonov case XFRM_MSG_NEWAE: 1585461fc0cSDmitry Safonov case XFRM_MSG_REPORT: 1595461fc0cSDmitry Safonov case XFRM_MSG_MIGRATE: 1605461fc0cSDmitry Safonov case XFRM_MSG_NEWSADINFO: 1615461fc0cSDmitry Safonov case XFRM_MSG_NEWSPDINFO: 1625461fc0cSDmitry Safonov case XFRM_MSG_MAPPING: 1635461fc0cSDmitry Safonov WARN_ON_ONCE(src_len != payload); 1645461fc0cSDmitry Safonov memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), src_len); 1655461fc0cSDmitry Safonov break; 1665461fc0cSDmitry Safonov /* 4 byte alignment for trailing u64 on native, but not on compat */ 1675461fc0cSDmitry Safonov case XFRM_MSG_NEWSA: 1685461fc0cSDmitry Safonov case XFRM_MSG_NEWPOLICY: 1695461fc0cSDmitry Safonov case XFRM_MSG_UPDSA: 1705461fc0cSDmitry Safonov case XFRM_MSG_UPDPOLICY: 1715461fc0cSDmitry Safonov WARN_ON_ONCE(src_len != payload + 4); 1725461fc0cSDmitry Safonov memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), payload); 1735461fc0cSDmitry Safonov break; 1745461fc0cSDmitry Safonov case XFRM_MSG_EXPIRE: { 1755461fc0cSDmitry Safonov const struct xfrm_user_expire *src_ue = nlmsg_data(nlh_src); 1765461fc0cSDmitry Safonov struct compat_xfrm_user_expire *dst_ue = nlmsg_data(nlh_dst); 1775461fc0cSDmitry Safonov 1785461fc0cSDmitry Safonov /* compat_xfrm_user_expire has 4-byte smaller state */ 1795461fc0cSDmitry Safonov memcpy(dst_ue, src_ue, sizeof(dst_ue->state)); 1805461fc0cSDmitry Safonov dst_ue->hard = src_ue->hard; 1815461fc0cSDmitry Safonov break; 1825461fc0cSDmitry Safonov } 1835461fc0cSDmitry Safonov case XFRM_MSG_ACQUIRE: { 1845461fc0cSDmitry Safonov const struct xfrm_user_acquire *src_ua = nlmsg_data(nlh_src); 1855461fc0cSDmitry Safonov struct compat_xfrm_user_acquire *dst_ua = nlmsg_data(nlh_dst); 1865461fc0cSDmitry Safonov 1875461fc0cSDmitry Safonov memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos)); 1885461fc0cSDmitry Safonov dst_ua->aalgos = src_ua->aalgos; 1895461fc0cSDmitry Safonov dst_ua->ealgos = src_ua->ealgos; 1905461fc0cSDmitry Safonov dst_ua->calgos = src_ua->calgos; 1915461fc0cSDmitry Safonov dst_ua->seq = src_ua->seq; 1925461fc0cSDmitry Safonov break; 1935461fc0cSDmitry Safonov } 1945461fc0cSDmitry Safonov case XFRM_MSG_POLEXPIRE: { 1955461fc0cSDmitry Safonov const struct xfrm_user_polexpire *src_upe = nlmsg_data(nlh_src); 1965461fc0cSDmitry Safonov struct compat_xfrm_user_polexpire *dst_upe = nlmsg_data(nlh_dst); 1975461fc0cSDmitry Safonov 1985461fc0cSDmitry Safonov /* compat_xfrm_user_polexpire has 4-byte smaller state */ 1995461fc0cSDmitry Safonov memcpy(dst_upe, src_upe, sizeof(dst_upe->pol)); 2005461fc0cSDmitry Safonov dst_upe->hard = src_upe->hard; 2015461fc0cSDmitry Safonov break; 2025461fc0cSDmitry Safonov } 2035461fc0cSDmitry Safonov case XFRM_MSG_ALLOCSPI: { 2045461fc0cSDmitry Safonov const struct xfrm_userspi_info *src_usi = nlmsg_data(nlh_src); 2055461fc0cSDmitry Safonov struct compat_xfrm_userspi_info *dst_usi = nlmsg_data(nlh_dst); 2065461fc0cSDmitry Safonov 2075461fc0cSDmitry Safonov /* compat_xfrm_user_polexpire has 4-byte smaller state */ 2085461fc0cSDmitry Safonov memcpy(dst_usi, src_usi, sizeof(src_usi->info)); 2095461fc0cSDmitry Safonov dst_usi->min = src_usi->min; 2105461fc0cSDmitry Safonov dst_usi->max = src_usi->max; 2115461fc0cSDmitry Safonov break; 2125461fc0cSDmitry Safonov } 2135461fc0cSDmitry Safonov /* Not being sent by kernel */ 2145461fc0cSDmitry Safonov case XFRM_MSG_GETSA: 2155461fc0cSDmitry Safonov case XFRM_MSG_GETPOLICY: 2165461fc0cSDmitry Safonov case XFRM_MSG_GETAE: 2175461fc0cSDmitry Safonov case XFRM_MSG_GETSADINFO: 2185461fc0cSDmitry Safonov case XFRM_MSG_GETSPDINFO: 2195461fc0cSDmitry Safonov default: 220ef19e111SDmitry Safonov pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type); 2215461fc0cSDmitry Safonov return ERR_PTR(-EOPNOTSUPP); 2225461fc0cSDmitry Safonov } 2235461fc0cSDmitry Safonov 2245461fc0cSDmitry Safonov return nlh_dst; 2255461fc0cSDmitry Safonov } 2265461fc0cSDmitry Safonov 2275461fc0cSDmitry Safonov static int xfrm_nla_cpy(struct sk_buff *dst, const struct nlattr *src, int len) 2285461fc0cSDmitry Safonov { 2295461fc0cSDmitry Safonov return nla_put(dst, src->nla_type, len, nla_data(src)); 2305461fc0cSDmitry Safonov } 2315461fc0cSDmitry Safonov 2325461fc0cSDmitry Safonov static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src) 2335461fc0cSDmitry Safonov { 2345461fc0cSDmitry Safonov switch (src->nla_type) { 2355461fc0cSDmitry Safonov case XFRMA_PAD: 2365461fc0cSDmitry Safonov /* Ignore */ 2375461fc0cSDmitry Safonov return 0; 238dbd7ae51SDmitry Safonov case XFRMA_UNSPEC: 2395461fc0cSDmitry Safonov case XFRMA_ALG_AUTH: 2405461fc0cSDmitry Safonov case XFRMA_ALG_CRYPT: 2415461fc0cSDmitry Safonov case XFRMA_ALG_COMP: 2425461fc0cSDmitry Safonov case XFRMA_ENCAP: 2435461fc0cSDmitry Safonov case XFRMA_TMPL: 2445461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 2455461fc0cSDmitry Safonov case XFRMA_SA: 2465461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_usersa_info)); 2475461fc0cSDmitry Safonov case XFRMA_POLICY: 2485461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_userpolicy_info)); 2495461fc0cSDmitry Safonov case XFRMA_SEC_CTX: 2505461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 2515461fc0cSDmitry Safonov case XFRMA_LTIME_VAL: 2525461fc0cSDmitry Safonov return nla_put_64bit(dst, src->nla_type, nla_len(src), 2535461fc0cSDmitry Safonov nla_data(src), XFRMA_PAD); 2545461fc0cSDmitry Safonov case XFRMA_REPLAY_VAL: 2555461fc0cSDmitry Safonov case XFRMA_REPLAY_THRESH: 2565461fc0cSDmitry Safonov case XFRMA_ETIMER_THRESH: 2575461fc0cSDmitry Safonov case XFRMA_SRCADDR: 2585461fc0cSDmitry Safonov case XFRMA_COADDR: 2595461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 2605461fc0cSDmitry Safonov case XFRMA_LASTUSED: 2615461fc0cSDmitry Safonov return nla_put_64bit(dst, src->nla_type, nla_len(src), 2625461fc0cSDmitry Safonov nla_data(src), XFRMA_PAD); 2635461fc0cSDmitry Safonov case XFRMA_POLICY_TYPE: 2645461fc0cSDmitry Safonov case XFRMA_MIGRATE: 2655461fc0cSDmitry Safonov case XFRMA_ALG_AEAD: 2665461fc0cSDmitry Safonov case XFRMA_KMADDRESS: 2675461fc0cSDmitry Safonov case XFRMA_ALG_AUTH_TRUNC: 2685461fc0cSDmitry Safonov case XFRMA_MARK: 2695461fc0cSDmitry Safonov case XFRMA_TFCPAD: 2705461fc0cSDmitry Safonov case XFRMA_REPLAY_ESN_VAL: 2715461fc0cSDmitry Safonov case XFRMA_SA_EXTRA_FLAGS: 2725461fc0cSDmitry Safonov case XFRMA_PROTO: 2735461fc0cSDmitry Safonov case XFRMA_ADDRESS_FILTER: 2745461fc0cSDmitry Safonov case XFRMA_OFFLOAD_DEV: 2755461fc0cSDmitry Safonov case XFRMA_SET_MARK: 2765461fc0cSDmitry Safonov case XFRMA_SET_MARK_MASK: 2775461fc0cSDmitry Safonov case XFRMA_IF_ID: 278*4e484b3eSAntony Antony case XFRMA_MTIMER_THRESH: 2795461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 2805461fc0cSDmitry Safonov default: 281*4e484b3eSAntony Antony BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); 282ef19e111SDmitry Safonov pr_warn_once("unsupported nla_type %d\n", src->nla_type); 2835461fc0cSDmitry Safonov return -EOPNOTSUPP; 2845461fc0cSDmitry Safonov } 2855461fc0cSDmitry Safonov } 2865461fc0cSDmitry Safonov 2875461fc0cSDmitry Safonov /* Take kernel-built (64bit layout) and create 32bit layout for userspace */ 2885461fc0cSDmitry Safonov static int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src) 2895461fc0cSDmitry Safonov { 2905461fc0cSDmitry Safonov u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE; 2915461fc0cSDmitry Safonov const struct nlattr *nla, *attrs; 2925461fc0cSDmitry Safonov struct nlmsghdr *nlh_dst; 2935461fc0cSDmitry Safonov int len, remaining; 2945461fc0cSDmitry Safonov 2955461fc0cSDmitry Safonov nlh_dst = xfrm_nlmsg_put_compat(dst, nlh_src, type); 2965461fc0cSDmitry Safonov if (IS_ERR(nlh_dst)) 2975461fc0cSDmitry Safonov return PTR_ERR(nlh_dst); 2985461fc0cSDmitry Safonov 2995461fc0cSDmitry Safonov attrs = nlmsg_attrdata(nlh_src, xfrm_msg_min[type]); 3005461fc0cSDmitry Safonov len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]); 3015461fc0cSDmitry Safonov 3025461fc0cSDmitry Safonov nla_for_each_attr(nla, attrs, len, remaining) { 3034e950506SDmitry Safonov int err; 3045461fc0cSDmitry Safonov 3054e950506SDmitry Safonov switch (type) { 3064e950506SDmitry Safonov case XFRM_MSG_NEWSPDINFO: 3074e950506SDmitry Safonov err = xfrm_nla_cpy(dst, nla, nla_len(nla)); 3084e950506SDmitry Safonov break; 3094e950506SDmitry Safonov default: 3104e950506SDmitry Safonov err = xfrm_xlate64_attr(dst, nla); 3114e950506SDmitry Safonov break; 3124e950506SDmitry Safonov } 3135461fc0cSDmitry Safonov if (err) 3145461fc0cSDmitry Safonov return err; 3155461fc0cSDmitry Safonov } 3165461fc0cSDmitry Safonov 3175461fc0cSDmitry Safonov nlmsg_end(dst, nlh_dst); 3185461fc0cSDmitry Safonov 3195461fc0cSDmitry Safonov return 0; 3205461fc0cSDmitry Safonov } 3215461fc0cSDmitry Safonov 3225461fc0cSDmitry Safonov static int xfrm_alloc_compat(struct sk_buff *skb, const struct nlmsghdr *nlh_src) 3235461fc0cSDmitry Safonov { 3245461fc0cSDmitry Safonov u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE; 3255461fc0cSDmitry Safonov struct sk_buff *new = NULL; 3265461fc0cSDmitry Safonov int err; 3275461fc0cSDmitry Safonov 328ef19e111SDmitry Safonov if (type >= ARRAY_SIZE(xfrm_msg_min)) { 329ef19e111SDmitry Safonov pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type); 3305461fc0cSDmitry Safonov return -EOPNOTSUPP; 331ef19e111SDmitry Safonov } 3325461fc0cSDmitry Safonov 3335461fc0cSDmitry Safonov if (skb_shinfo(skb)->frag_list == NULL) { 3345461fc0cSDmitry Safonov new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC); 3355461fc0cSDmitry Safonov if (!new) 3365461fc0cSDmitry Safonov return -ENOMEM; 3375461fc0cSDmitry Safonov skb_shinfo(skb)->frag_list = new; 3385461fc0cSDmitry Safonov } 3395461fc0cSDmitry Safonov 3405461fc0cSDmitry Safonov err = xfrm_xlate64(skb_shinfo(skb)->frag_list, nlh_src); 3415461fc0cSDmitry Safonov if (err) { 3425461fc0cSDmitry Safonov if (new) { 3435461fc0cSDmitry Safonov kfree_skb(new); 3445461fc0cSDmitry Safonov skb_shinfo(skb)->frag_list = NULL; 3455461fc0cSDmitry Safonov } 3465461fc0cSDmitry Safonov return err; 3475461fc0cSDmitry Safonov } 3485461fc0cSDmitry Safonov 3495461fc0cSDmitry Safonov return 0; 3505461fc0cSDmitry Safonov } 3515461fc0cSDmitry Safonov 3525106f4a8SDmitry Safonov /* Calculates len of translated 64-bit message. */ 3535106f4a8SDmitry Safonov static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src, 3544e950506SDmitry Safonov struct nlattr *attrs[XFRMA_MAX + 1], 3554e950506SDmitry Safonov int maxtype) 3565106f4a8SDmitry Safonov { 3575106f4a8SDmitry Safonov size_t len = nlmsg_len(src); 3585106f4a8SDmitry Safonov 3595106f4a8SDmitry Safonov switch (src->nlmsg_type) { 3605106f4a8SDmitry Safonov case XFRM_MSG_NEWSA: 3615106f4a8SDmitry Safonov case XFRM_MSG_NEWPOLICY: 3625106f4a8SDmitry Safonov case XFRM_MSG_ALLOCSPI: 3635106f4a8SDmitry Safonov case XFRM_MSG_ACQUIRE: 3645106f4a8SDmitry Safonov case XFRM_MSG_UPDPOLICY: 3655106f4a8SDmitry Safonov case XFRM_MSG_UPDSA: 3665106f4a8SDmitry Safonov len += 4; 3675106f4a8SDmitry Safonov break; 3685106f4a8SDmitry Safonov case XFRM_MSG_EXPIRE: 3695106f4a8SDmitry Safonov case XFRM_MSG_POLEXPIRE: 3705106f4a8SDmitry Safonov len += 8; 3715106f4a8SDmitry Safonov break; 3724e950506SDmitry Safonov case XFRM_MSG_NEWSPDINFO: 3734e950506SDmitry Safonov /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */ 3744e950506SDmitry Safonov return len; 3755106f4a8SDmitry Safonov default: 3765106f4a8SDmitry Safonov break; 3775106f4a8SDmitry Safonov } 3785106f4a8SDmitry Safonov 3794e950506SDmitry Safonov /* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please 3804e950506SDmitry Safonov * correct both 64=>32-bit and 32=>64-bit translators to copy 3814e950506SDmitry Safonov * new attributes. 3824e950506SDmitry Safonov */ 3834e950506SDmitry Safonov if (WARN_ON_ONCE(maxtype)) 3844e950506SDmitry Safonov return len; 3854e950506SDmitry Safonov 3865106f4a8SDmitry Safonov if (attrs[XFRMA_SA]) 3875106f4a8SDmitry Safonov len += 4; 3885106f4a8SDmitry Safonov if (attrs[XFRMA_POLICY]) 3895106f4a8SDmitry Safonov len += 4; 3905106f4a8SDmitry Safonov 3915106f4a8SDmitry Safonov /* XXX: some attrs may need to be realigned 3925106f4a8SDmitry Safonov * if !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 3935106f4a8SDmitry Safonov */ 3945106f4a8SDmitry Safonov 3955106f4a8SDmitry Safonov return len; 3965106f4a8SDmitry Safonov } 3975106f4a8SDmitry Safonov 3985106f4a8SDmitry Safonov static int xfrm_attr_cpy32(void *dst, size_t *pos, const struct nlattr *src, 3995106f4a8SDmitry Safonov size_t size, int copy_len, int payload) 4005106f4a8SDmitry Safonov { 4015106f4a8SDmitry Safonov struct nlmsghdr *nlmsg = dst; 4025106f4a8SDmitry Safonov struct nlattr *nla; 4035106f4a8SDmitry Safonov 404ef19e111SDmitry Safonov /* xfrm_user_rcv_msg_compat() relies on fact that 32-bit messages 405ef19e111SDmitry Safonov * have the same len or shorted than 64-bit ones. 406ef19e111SDmitry Safonov * 32-bit translation that is bigger than 64-bit original is unexpected. 407ef19e111SDmitry Safonov */ 4085106f4a8SDmitry Safonov if (WARN_ON_ONCE(copy_len > payload)) 4095106f4a8SDmitry Safonov copy_len = payload; 4105106f4a8SDmitry Safonov 4115106f4a8SDmitry Safonov if (size - *pos < nla_attr_size(payload)) 4125106f4a8SDmitry Safonov return -ENOBUFS; 4135106f4a8SDmitry Safonov 4145106f4a8SDmitry Safonov nla = dst + *pos; 4155106f4a8SDmitry Safonov 4165106f4a8SDmitry Safonov memcpy(nla, src, nla_attr_size(copy_len)); 4175106f4a8SDmitry Safonov nla->nla_len = nla_attr_size(payload); 418d1949d04SDmitry Safonov *pos += nla_attr_size(copy_len); 4195106f4a8SDmitry Safonov nlmsg->nlmsg_len += nla->nla_len; 4205106f4a8SDmitry Safonov 4215106f4a8SDmitry Safonov memset(dst + *pos, 0, payload - copy_len); 4225106f4a8SDmitry Safonov *pos += payload - copy_len; 4235106f4a8SDmitry Safonov 4245106f4a8SDmitry Safonov return 0; 4255106f4a8SDmitry Safonov } 4265106f4a8SDmitry Safonov 4275106f4a8SDmitry Safonov static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla, 4285106f4a8SDmitry Safonov size_t *pos, size_t size, 4295106f4a8SDmitry Safonov struct netlink_ext_ack *extack) 4305106f4a8SDmitry Safonov { 4315106f4a8SDmitry Safonov int type = nla_type(nla); 4325106f4a8SDmitry Safonov u16 pol_len32, pol_len64; 4335106f4a8SDmitry Safonov int err; 4345106f4a8SDmitry Safonov 4355106f4a8SDmitry Safonov if (type > XFRMA_MAX) { 436*4e484b3eSAntony Antony BUILD_BUG_ON(XFRMA_MAX != XFRMA_MTIMER_THRESH); 4375106f4a8SDmitry Safonov NL_SET_ERR_MSG(extack, "Bad attribute"); 4385106f4a8SDmitry Safonov return -EOPNOTSUPP; 4395106f4a8SDmitry Safonov } 4405106f4a8SDmitry Safonov if (nla_len(nla) < compat_policy[type].len) { 4415106f4a8SDmitry Safonov NL_SET_ERR_MSG(extack, "Attribute bad length"); 4425106f4a8SDmitry Safonov return -EOPNOTSUPP; 4435106f4a8SDmitry Safonov } 4445106f4a8SDmitry Safonov 4455106f4a8SDmitry Safonov pol_len32 = compat_policy[type].len; 4465106f4a8SDmitry Safonov pol_len64 = xfrma_policy[type].len; 4475106f4a8SDmitry Safonov 4485106f4a8SDmitry Safonov /* XFRMA_SA and XFRMA_POLICY - need to know how-to translate */ 4495106f4a8SDmitry Safonov if (pol_len32 != pol_len64) { 4505106f4a8SDmitry Safonov if (nla_len(nla) != compat_policy[type].len) { 4515106f4a8SDmitry Safonov NL_SET_ERR_MSG(extack, "Attribute bad length"); 4525106f4a8SDmitry Safonov return -EOPNOTSUPP; 4535106f4a8SDmitry Safonov } 4545106f4a8SDmitry Safonov err = xfrm_attr_cpy32(dst, pos, nla, size, pol_len32, pol_len64); 4555106f4a8SDmitry Safonov if (err) 4565106f4a8SDmitry Safonov return err; 4575106f4a8SDmitry Safonov } 4585106f4a8SDmitry Safonov 4595106f4a8SDmitry Safonov return xfrm_attr_cpy32(dst, pos, nla, size, nla_len(nla), nla_len(nla)); 4605106f4a8SDmitry Safonov } 4615106f4a8SDmitry Safonov 4625106f4a8SDmitry Safonov static int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src, 4635106f4a8SDmitry Safonov struct nlattr *attrs[XFRMA_MAX+1], 4644e950506SDmitry Safonov size_t size, u8 type, int maxtype, 4654e950506SDmitry Safonov struct netlink_ext_ack *extack) 4665106f4a8SDmitry Safonov { 4675106f4a8SDmitry Safonov size_t pos; 4685106f4a8SDmitry Safonov int i; 4695106f4a8SDmitry Safonov 4705106f4a8SDmitry Safonov memcpy(dst, src, NLMSG_HDRLEN); 4715106f4a8SDmitry Safonov dst->nlmsg_len = NLMSG_HDRLEN + xfrm_msg_min[type]; 4725106f4a8SDmitry Safonov memset(nlmsg_data(dst), 0, xfrm_msg_min[type]); 4735106f4a8SDmitry Safonov 4745106f4a8SDmitry Safonov switch (src->nlmsg_type) { 4755106f4a8SDmitry Safonov /* Compat message has the same layout as native */ 4765106f4a8SDmitry Safonov case XFRM_MSG_DELSA: 4775106f4a8SDmitry Safonov case XFRM_MSG_GETSA: 4785106f4a8SDmitry Safonov case XFRM_MSG_DELPOLICY: 4795106f4a8SDmitry Safonov case XFRM_MSG_GETPOLICY: 4805106f4a8SDmitry Safonov case XFRM_MSG_FLUSHSA: 4815106f4a8SDmitry Safonov case XFRM_MSG_FLUSHPOLICY: 4825106f4a8SDmitry Safonov case XFRM_MSG_NEWAE: 4835106f4a8SDmitry Safonov case XFRM_MSG_GETAE: 4845106f4a8SDmitry Safonov case XFRM_MSG_REPORT: 4855106f4a8SDmitry Safonov case XFRM_MSG_MIGRATE: 4865106f4a8SDmitry Safonov case XFRM_MSG_NEWSADINFO: 4875106f4a8SDmitry Safonov case XFRM_MSG_GETSADINFO: 4885106f4a8SDmitry Safonov case XFRM_MSG_NEWSPDINFO: 4895106f4a8SDmitry Safonov case XFRM_MSG_GETSPDINFO: 4905106f4a8SDmitry Safonov case XFRM_MSG_MAPPING: 4915106f4a8SDmitry Safonov memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]); 4925106f4a8SDmitry Safonov break; 4935106f4a8SDmitry Safonov /* 4 byte alignment for trailing u64 on native, but not on compat */ 4945106f4a8SDmitry Safonov case XFRM_MSG_NEWSA: 4955106f4a8SDmitry Safonov case XFRM_MSG_NEWPOLICY: 4965106f4a8SDmitry Safonov case XFRM_MSG_UPDSA: 4975106f4a8SDmitry Safonov case XFRM_MSG_UPDPOLICY: 4985106f4a8SDmitry Safonov memcpy(nlmsg_data(dst), nlmsg_data(src), compat_msg_min[type]); 4995106f4a8SDmitry Safonov break; 5005106f4a8SDmitry Safonov case XFRM_MSG_EXPIRE: { 5015106f4a8SDmitry Safonov const struct compat_xfrm_user_expire *src_ue = nlmsg_data(src); 5025106f4a8SDmitry Safonov struct xfrm_user_expire *dst_ue = nlmsg_data(dst); 5035106f4a8SDmitry Safonov 5045106f4a8SDmitry Safonov /* compat_xfrm_user_expire has 4-byte smaller state */ 5055106f4a8SDmitry Safonov memcpy(dst_ue, src_ue, sizeof(src_ue->state)); 5065106f4a8SDmitry Safonov dst_ue->hard = src_ue->hard; 5075106f4a8SDmitry Safonov break; 5085106f4a8SDmitry Safonov } 5095106f4a8SDmitry Safonov case XFRM_MSG_ACQUIRE: { 5105106f4a8SDmitry Safonov const struct compat_xfrm_user_acquire *src_ua = nlmsg_data(src); 5115106f4a8SDmitry Safonov struct xfrm_user_acquire *dst_ua = nlmsg_data(dst); 5125106f4a8SDmitry Safonov 5135106f4a8SDmitry Safonov memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos)); 5145106f4a8SDmitry Safonov dst_ua->aalgos = src_ua->aalgos; 5155106f4a8SDmitry Safonov dst_ua->ealgos = src_ua->ealgos; 5165106f4a8SDmitry Safonov dst_ua->calgos = src_ua->calgos; 5175106f4a8SDmitry Safonov dst_ua->seq = src_ua->seq; 5185106f4a8SDmitry Safonov break; 5195106f4a8SDmitry Safonov } 5205106f4a8SDmitry Safonov case XFRM_MSG_POLEXPIRE: { 5215106f4a8SDmitry Safonov const struct compat_xfrm_user_polexpire *src_upe = nlmsg_data(src); 5225106f4a8SDmitry Safonov struct xfrm_user_polexpire *dst_upe = nlmsg_data(dst); 5235106f4a8SDmitry Safonov 5245106f4a8SDmitry Safonov /* compat_xfrm_user_polexpire has 4-byte smaller state */ 5255106f4a8SDmitry Safonov memcpy(dst_upe, src_upe, sizeof(src_upe->pol)); 5265106f4a8SDmitry Safonov dst_upe->hard = src_upe->hard; 5275106f4a8SDmitry Safonov break; 5285106f4a8SDmitry Safonov } 5295106f4a8SDmitry Safonov case XFRM_MSG_ALLOCSPI: { 5305106f4a8SDmitry Safonov const struct compat_xfrm_userspi_info *src_usi = nlmsg_data(src); 5315106f4a8SDmitry Safonov struct xfrm_userspi_info *dst_usi = nlmsg_data(dst); 5325106f4a8SDmitry Safonov 5335106f4a8SDmitry Safonov /* compat_xfrm_user_polexpire has 4-byte smaller state */ 5345106f4a8SDmitry Safonov memcpy(dst_usi, src_usi, sizeof(src_usi->info)); 5355106f4a8SDmitry Safonov dst_usi->min = src_usi->min; 5365106f4a8SDmitry Safonov dst_usi->max = src_usi->max; 5375106f4a8SDmitry Safonov break; 5385106f4a8SDmitry Safonov } 5395106f4a8SDmitry Safonov default: 5405106f4a8SDmitry Safonov NL_SET_ERR_MSG(extack, "Unsupported message type"); 5415106f4a8SDmitry Safonov return -EOPNOTSUPP; 5425106f4a8SDmitry Safonov } 5435106f4a8SDmitry Safonov pos = dst->nlmsg_len; 5445106f4a8SDmitry Safonov 5454e950506SDmitry Safonov if (maxtype) { 5464e950506SDmitry Safonov /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */ 5474e950506SDmitry Safonov WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO); 5484e950506SDmitry Safonov 5494e950506SDmitry Safonov for (i = 1; i <= maxtype; i++) { 5504e950506SDmitry Safonov int err; 5514e950506SDmitry Safonov 5524e950506SDmitry Safonov if (!attrs[i]) 5534e950506SDmitry Safonov continue; 5544e950506SDmitry Safonov 5554e950506SDmitry Safonov /* just copy - no need for translation */ 5564e950506SDmitry Safonov err = xfrm_attr_cpy32(dst, &pos, attrs[i], size, 5574e950506SDmitry Safonov nla_len(attrs[i]), nla_len(attrs[i])); 5584e950506SDmitry Safonov if (err) 5594e950506SDmitry Safonov return err; 5604e950506SDmitry Safonov } 5614e950506SDmitry Safonov return 0; 5624e950506SDmitry Safonov } 5634e950506SDmitry Safonov 5645106f4a8SDmitry Safonov for (i = 1; i < XFRMA_MAX + 1; i++) { 5655106f4a8SDmitry Safonov int err; 5665106f4a8SDmitry Safonov 5675106f4a8SDmitry Safonov if (i == XFRMA_PAD) 5685106f4a8SDmitry Safonov continue; 5695106f4a8SDmitry Safonov 5705106f4a8SDmitry Safonov if (!attrs[i]) 5715106f4a8SDmitry Safonov continue; 5725106f4a8SDmitry Safonov 5735106f4a8SDmitry Safonov err = xfrm_xlate32_attr(dst, attrs[i], &pos, size, extack); 5745106f4a8SDmitry Safonov if (err) 5755106f4a8SDmitry Safonov return err; 5765106f4a8SDmitry Safonov } 5775106f4a8SDmitry Safonov 5785106f4a8SDmitry Safonov return 0; 5795106f4a8SDmitry Safonov } 5805106f4a8SDmitry Safonov 5815106f4a8SDmitry Safonov static struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32, 5825106f4a8SDmitry Safonov int maxtype, const struct nla_policy *policy, 5835106f4a8SDmitry Safonov struct netlink_ext_ack *extack) 5845106f4a8SDmitry Safonov { 5855106f4a8SDmitry Safonov /* netlink_rcv_skb() checks if a message has full (struct nlmsghdr) */ 5865106f4a8SDmitry Safonov u16 type = h32->nlmsg_type - XFRM_MSG_BASE; 5875106f4a8SDmitry Safonov struct nlattr *attrs[XFRMA_MAX+1]; 5885106f4a8SDmitry Safonov struct nlmsghdr *h64; 5895106f4a8SDmitry Safonov size_t len; 5905106f4a8SDmitry Safonov int err; 5915106f4a8SDmitry Safonov 5925106f4a8SDmitry Safonov BUILD_BUG_ON(ARRAY_SIZE(xfrm_msg_min) != ARRAY_SIZE(compat_msg_min)); 5935106f4a8SDmitry Safonov 5945106f4a8SDmitry Safonov if (type >= ARRAY_SIZE(xfrm_msg_min)) 5955106f4a8SDmitry Safonov return ERR_PTR(-EINVAL); 5965106f4a8SDmitry Safonov 5975106f4a8SDmitry Safonov /* Don't call parse: the message might have only nlmsg header */ 5985106f4a8SDmitry Safonov if ((h32->nlmsg_type == XFRM_MSG_GETSA || 5995106f4a8SDmitry Safonov h32->nlmsg_type == XFRM_MSG_GETPOLICY) && 6005106f4a8SDmitry Safonov (h32->nlmsg_flags & NLM_F_DUMP)) 6015106f4a8SDmitry Safonov return NULL; 6025106f4a8SDmitry Safonov 6035106f4a8SDmitry Safonov err = nlmsg_parse_deprecated(h32, compat_msg_min[type], attrs, 6045106f4a8SDmitry Safonov maxtype ? : XFRMA_MAX, policy ? : compat_policy, extack); 6055106f4a8SDmitry Safonov if (err < 0) 6065106f4a8SDmitry Safonov return ERR_PTR(err); 6075106f4a8SDmitry Safonov 6084e950506SDmitry Safonov len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype); 6095106f4a8SDmitry Safonov /* The message doesn't need translation */ 6105106f4a8SDmitry Safonov if (len == nlmsg_len(h32)) 6115106f4a8SDmitry Safonov return NULL; 6125106f4a8SDmitry Safonov 6135106f4a8SDmitry Safonov len += NLMSG_HDRLEN; 614ad37f77fSDmitry Safonov h64 = kvmalloc(len, GFP_KERNEL); 6155106f4a8SDmitry Safonov if (!h64) 6165106f4a8SDmitry Safonov return ERR_PTR(-ENOMEM); 6175106f4a8SDmitry Safonov 6184e950506SDmitry Safonov err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack); 6195106f4a8SDmitry Safonov if (err < 0) { 6205106f4a8SDmitry Safonov kvfree(h64); 6215106f4a8SDmitry Safonov return ERR_PTR(err); 6225106f4a8SDmitry Safonov } 6235106f4a8SDmitry Safonov 6245106f4a8SDmitry Safonov return h64; 6255106f4a8SDmitry Safonov } 6265106f4a8SDmitry Safonov 62796392ee5SDmitry Safonov static int xfrm_user_policy_compat(u8 **pdata32, int optlen) 62896392ee5SDmitry Safonov { 62996392ee5SDmitry Safonov struct compat_xfrm_userpolicy_info *p = (void *)*pdata32; 63096392ee5SDmitry Safonov u8 *src_templates, *dst_templates; 63196392ee5SDmitry Safonov u8 *data64; 63296392ee5SDmitry Safonov 63396392ee5SDmitry Safonov if (optlen < sizeof(*p)) 63496392ee5SDmitry Safonov return -EINVAL; 63596392ee5SDmitry Safonov 63696392ee5SDmitry Safonov data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN); 63796392ee5SDmitry Safonov if (!data64) 63896392ee5SDmitry Safonov return -ENOMEM; 63996392ee5SDmitry Safonov 64096392ee5SDmitry Safonov memcpy(data64, *pdata32, sizeof(*p)); 64196392ee5SDmitry Safonov memset(data64 + sizeof(*p), 0, 4); 64296392ee5SDmitry Safonov 64396392ee5SDmitry Safonov src_templates = *pdata32 + sizeof(*p); 64496392ee5SDmitry Safonov dst_templates = data64 + sizeof(*p) + 4; 64596392ee5SDmitry Safonov memcpy(dst_templates, src_templates, optlen - sizeof(*p)); 64696392ee5SDmitry Safonov 64796392ee5SDmitry Safonov kfree(*pdata32); 64896392ee5SDmitry Safonov *pdata32 = data64; 64996392ee5SDmitry Safonov return 0; 65096392ee5SDmitry Safonov } 65196392ee5SDmitry Safonov 652c9e7c76dSDmitry Safonov static struct xfrm_translator xfrm_translator = { 653c9e7c76dSDmitry Safonov .owner = THIS_MODULE, 6545461fc0cSDmitry Safonov .alloc_compat = xfrm_alloc_compat, 6555106f4a8SDmitry Safonov .rcv_msg_compat = xfrm_user_rcv_msg_compat, 65696392ee5SDmitry Safonov .xlate_user_policy_sockptr = xfrm_user_policy_compat, 657c9e7c76dSDmitry Safonov }; 658c9e7c76dSDmitry Safonov 659c9e7c76dSDmitry Safonov static int __init xfrm_compat_init(void) 660c9e7c76dSDmitry Safonov { 661c9e7c76dSDmitry Safonov return xfrm_register_translator(&xfrm_translator); 662c9e7c76dSDmitry Safonov } 663c9e7c76dSDmitry Safonov 664c9e7c76dSDmitry Safonov static void __exit xfrm_compat_exit(void) 665c9e7c76dSDmitry Safonov { 666c9e7c76dSDmitry Safonov xfrm_unregister_translator(&xfrm_translator); 667c9e7c76dSDmitry Safonov } 668c9e7c76dSDmitry Safonov 669c9e7c76dSDmitry Safonov module_init(xfrm_compat_init); 670c9e7c76dSDmitry Safonov module_exit(xfrm_compat_exit); 671c9e7c76dSDmitry Safonov MODULE_LICENSE("GPL"); 672c9e7c76dSDmitry Safonov MODULE_AUTHOR("Dmitry Safonov"); 673c9e7c76dSDmitry Safonov MODULE_DESCRIPTION("XFRM 32-bit compatibility layer"); 674