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