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