1 // SPDX-License-Identifier: GPL-2.0
4 * Author: Dmitry Safonov <dima@arista.com>
5 * Based on code and translator idea by: Florian Westphal <fw@strlen.de>
7 #include <linux/compat.h>
8 #include <linux/xfrm.h>
11 struct compat_xfrm_lifetime_cfg
{
12 compat_u64 soft_byte_limit
, hard_byte_limit
;
13 compat_u64 soft_packet_limit
, hard_packet_limit
;
14 compat_u64 soft_add_expires_seconds
, hard_add_expires_seconds
;
15 compat_u64 soft_use_expires_seconds
, hard_use_expires_seconds
;
16 }; /* same size on 32bit, but only 4 byte alignment required */
18 struct compat_xfrm_lifetime_cur
{
19 compat_u64 bytes
, packets
, add_time
, use_time
;
20 }; /* same size on 32bit, but only 4 byte alignment required */
22 struct compat_xfrm_userpolicy_info
{
23 struct xfrm_selector sel
;
24 struct compat_xfrm_lifetime_cfg lft
;
25 struct compat_xfrm_lifetime_cur curlft
;
26 __u32 priority
, index
;
27 u8 dir
, action
, flags
, share
;
28 /* 4 bytes additional padding on 64bit */
31 struct compat_xfrm_usersa_info
{
32 struct xfrm_selector sel
;
35 struct compat_xfrm_lifetime_cfg lft
;
36 struct compat_xfrm_lifetime_cur curlft
;
37 struct xfrm_stats stats
;
40 u8 mode
, replay_window
, flags
;
41 /* 4 bytes additional padding on 64bit */
44 struct compat_xfrm_user_acquire
{
47 struct xfrm_selector sel
;
48 struct compat_xfrm_userpolicy_info policy
;
49 /* 4 bytes additional padding on 64bit */
50 __u32 aalgos
, ealgos
, calgos
, seq
;
53 struct compat_xfrm_userspi_info
{
54 struct compat_xfrm_usersa_info info
;
55 /* 4 bytes additional padding on 64bit */
59 struct compat_xfrm_user_expire
{
60 struct compat_xfrm_usersa_info state
;
61 /* 8 bytes additional padding on 64bit */
65 struct compat_xfrm_user_polexpire
{
66 struct compat_xfrm_userpolicy_info pol
;
67 /* 8 bytes additional padding on 64bit */
71 #define XMSGSIZE(type) sizeof(struct type)
73 static const int compat_msg_min
[XFRM_NR_MSGTYPES
] = {
74 [XFRM_MSG_NEWSA
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_usersa_info
),
75 [XFRM_MSG_DELSA
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_usersa_id
),
76 [XFRM_MSG_GETSA
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_usersa_id
),
77 [XFRM_MSG_NEWPOLICY
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_userpolicy_info
),
78 [XFRM_MSG_DELPOLICY
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_userpolicy_id
),
79 [XFRM_MSG_GETPOLICY
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_userpolicy_id
),
80 [XFRM_MSG_ALLOCSPI
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_userspi_info
),
81 [XFRM_MSG_ACQUIRE
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_user_acquire
),
82 [XFRM_MSG_EXPIRE
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_user_expire
),
83 [XFRM_MSG_UPDPOLICY
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_userpolicy_info
),
84 [XFRM_MSG_UPDSA
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_usersa_info
),
85 [XFRM_MSG_POLEXPIRE
- XFRM_MSG_BASE
] = XMSGSIZE(compat_xfrm_user_polexpire
),
86 [XFRM_MSG_FLUSHSA
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_usersa_flush
),
87 [XFRM_MSG_FLUSHPOLICY
- XFRM_MSG_BASE
] = 0,
88 [XFRM_MSG_NEWAE
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_aevent_id
),
89 [XFRM_MSG_GETAE
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_aevent_id
),
90 [XFRM_MSG_REPORT
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_user_report
),
91 [XFRM_MSG_MIGRATE
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_userpolicy_id
),
92 [XFRM_MSG_NEWSADINFO
- XFRM_MSG_BASE
] = sizeof(u32
),
93 [XFRM_MSG_GETSADINFO
- XFRM_MSG_BASE
] = sizeof(u32
),
94 [XFRM_MSG_NEWSPDINFO
- XFRM_MSG_BASE
] = sizeof(u32
),
95 [XFRM_MSG_GETSPDINFO
- XFRM_MSG_BASE
] = sizeof(u32
),
96 [XFRM_MSG_MAPPING
- XFRM_MSG_BASE
] = XMSGSIZE(xfrm_user_mapping
)
99 static const struct nla_policy compat_policy
[XFRMA_MAX
+1] = {
100 [XFRMA_SA
] = { .len
= XMSGSIZE(compat_xfrm_usersa_info
)},
101 [XFRMA_POLICY
] = { .len
= XMSGSIZE(compat_xfrm_userpolicy_info
)},
102 [XFRMA_LASTUSED
] = { .type
= NLA_U64
},
103 [XFRMA_ALG_AUTH_TRUNC
] = { .len
= sizeof(struct xfrm_algo_auth
)},
104 [XFRMA_ALG_AEAD
] = { .len
= sizeof(struct xfrm_algo_aead
) },
105 [XFRMA_ALG_AUTH
] = { .len
= sizeof(struct xfrm_algo
) },
106 [XFRMA_ALG_CRYPT
] = { .len
= sizeof(struct xfrm_algo
) },
107 [XFRMA_ALG_COMP
] = { .len
= sizeof(struct xfrm_algo
) },
108 [XFRMA_ENCAP
] = { .len
= sizeof(struct xfrm_encap_tmpl
) },
109 [XFRMA_TMPL
] = { .len
= sizeof(struct xfrm_user_tmpl
) },
110 [XFRMA_SEC_CTX
] = { .len
= sizeof(struct xfrm_sec_ctx
) },
111 [XFRMA_LTIME_VAL
] = { .len
= sizeof(struct xfrm_lifetime_cur
) },
112 [XFRMA_REPLAY_VAL
] = { .len
= sizeof(struct xfrm_replay_state
) },
113 [XFRMA_REPLAY_THRESH
] = { .type
= NLA_U32
},
114 [XFRMA_ETIMER_THRESH
] = { .type
= NLA_U32
},
115 [XFRMA_SRCADDR
] = { .len
= sizeof(xfrm_address_t
) },
116 [XFRMA_COADDR
] = { .len
= sizeof(xfrm_address_t
) },
117 [XFRMA_POLICY_TYPE
] = { .len
= sizeof(struct xfrm_userpolicy_type
)},
118 [XFRMA_MIGRATE
] = { .len
= sizeof(struct xfrm_user_migrate
) },
119 [XFRMA_KMADDRESS
] = { .len
= sizeof(struct xfrm_user_kmaddress
) },
120 [XFRMA_MARK
] = { .len
= sizeof(struct xfrm_mark
) },
121 [XFRMA_TFCPAD
] = { .type
= NLA_U32
},
122 [XFRMA_REPLAY_ESN_VAL
] = { .len
= sizeof(struct xfrm_replay_state_esn
) },
123 [XFRMA_SA_EXTRA_FLAGS
] = { .type
= NLA_U32
},
124 [XFRMA_PROTO
] = { .type
= NLA_U8
},
125 [XFRMA_ADDRESS_FILTER
] = { .len
= sizeof(struct xfrm_address_filter
) },
126 [XFRMA_OFFLOAD_DEV
] = { .len
= sizeof(struct xfrm_user_offload
) },
127 [XFRMA_SET_MARK
] = { .type
= NLA_U32
},
128 [XFRMA_SET_MARK_MASK
] = { .type
= NLA_U32
},
129 [XFRMA_IF_ID
] = { .type
= NLA_U32
},
132 static struct nlmsghdr
*xfrm_nlmsg_put_compat(struct sk_buff
*skb
,
133 const struct nlmsghdr
*nlh_src
, u16 type
)
135 int payload
= compat_msg_min
[type
];
136 int src_len
= xfrm_msg_min
[type
];
137 struct nlmsghdr
*nlh_dst
;
139 /* Compat messages are shorter or equal to native (+padding) */
140 if (WARN_ON_ONCE(src_len
< payload
))
141 return ERR_PTR(-EMSGSIZE
);
143 nlh_dst
= nlmsg_put(skb
, nlh_src
->nlmsg_pid
, nlh_src
->nlmsg_seq
,
144 nlh_src
->nlmsg_type
, payload
, nlh_src
->nlmsg_flags
);
146 return ERR_PTR(-EMSGSIZE
);
148 memset(nlmsg_data(nlh_dst
), 0, payload
);
150 switch (nlh_src
->nlmsg_type
) {
151 /* Compat message has the same layout as native */
153 case XFRM_MSG_DELPOLICY
:
154 case XFRM_MSG_FLUSHSA
:
155 case XFRM_MSG_FLUSHPOLICY
:
157 case XFRM_MSG_REPORT
:
158 case XFRM_MSG_MIGRATE
:
159 case XFRM_MSG_NEWSADINFO
:
160 case XFRM_MSG_NEWSPDINFO
:
161 case XFRM_MSG_MAPPING
:
162 WARN_ON_ONCE(src_len
!= payload
);
163 memcpy(nlmsg_data(nlh_dst
), nlmsg_data(nlh_src
), src_len
);
165 /* 4 byte alignment for trailing u64 on native, but not on compat */
167 case XFRM_MSG_NEWPOLICY
:
169 case XFRM_MSG_UPDPOLICY
:
170 WARN_ON_ONCE(src_len
!= payload
+ 4);
171 memcpy(nlmsg_data(nlh_dst
), nlmsg_data(nlh_src
), payload
);
173 case XFRM_MSG_EXPIRE
: {
174 const struct xfrm_user_expire
*src_ue
= nlmsg_data(nlh_src
);
175 struct compat_xfrm_user_expire
*dst_ue
= nlmsg_data(nlh_dst
);
177 /* compat_xfrm_user_expire has 4-byte smaller state */
178 memcpy(dst_ue
, src_ue
, sizeof(dst_ue
->state
));
179 dst_ue
->hard
= src_ue
->hard
;
182 case XFRM_MSG_ACQUIRE
: {
183 const struct xfrm_user_acquire
*src_ua
= nlmsg_data(nlh_src
);
184 struct compat_xfrm_user_acquire
*dst_ua
= nlmsg_data(nlh_dst
);
186 memcpy(dst_ua
, src_ua
, offsetof(struct compat_xfrm_user_acquire
, aalgos
));
187 dst_ua
->aalgos
= src_ua
->aalgos
;
188 dst_ua
->ealgos
= src_ua
->ealgos
;
189 dst_ua
->calgos
= src_ua
->calgos
;
190 dst_ua
->seq
= src_ua
->seq
;
193 case XFRM_MSG_POLEXPIRE
: {
194 const struct xfrm_user_polexpire
*src_upe
= nlmsg_data(nlh_src
);
195 struct compat_xfrm_user_polexpire
*dst_upe
= nlmsg_data(nlh_dst
);
197 /* compat_xfrm_user_polexpire has 4-byte smaller state */
198 memcpy(dst_upe
, src_upe
, sizeof(dst_upe
->pol
));
199 dst_upe
->hard
= src_upe
->hard
;
202 case XFRM_MSG_ALLOCSPI
: {
203 const struct xfrm_userspi_info
*src_usi
= nlmsg_data(nlh_src
);
204 struct compat_xfrm_userspi_info
*dst_usi
= nlmsg_data(nlh_dst
);
206 /* compat_xfrm_user_polexpire has 4-byte smaller state */
207 memcpy(dst_usi
, src_usi
, sizeof(src_usi
->info
));
208 dst_usi
->min
= src_usi
->min
;
209 dst_usi
->max
= src_usi
->max
;
212 /* Not being sent by kernel */
214 case XFRM_MSG_GETPOLICY
:
216 case XFRM_MSG_GETSADINFO
:
217 case XFRM_MSG_GETSPDINFO
:
219 WARN_ONCE(1, "unsupported nlmsg_type %d", nlh_src
->nlmsg_type
);
220 return ERR_PTR(-EOPNOTSUPP
);
226 static int xfrm_nla_cpy(struct sk_buff
*dst
, const struct nlattr
*src
, int len
)
228 return nla_put(dst
, src
->nla_type
, len
, nla_data(src
));
231 static int xfrm_xlate64_attr(struct sk_buff
*dst
, const struct nlattr
*src
)
233 switch (src
->nla_type
) {
239 case XFRMA_ALG_CRYPT
:
243 return xfrm_nla_cpy(dst
, src
, nla_len(src
));
245 return xfrm_nla_cpy(dst
, src
, XMSGSIZE(compat_xfrm_usersa_info
));
247 return xfrm_nla_cpy(dst
, src
, XMSGSIZE(compat_xfrm_userpolicy_info
));
249 return xfrm_nla_cpy(dst
, src
, nla_len(src
));
250 case XFRMA_LTIME_VAL
:
251 return nla_put_64bit(dst
, src
->nla_type
, nla_len(src
),
252 nla_data(src
), XFRMA_PAD
);
253 case XFRMA_REPLAY_VAL
:
254 case XFRMA_REPLAY_THRESH
:
255 case XFRMA_ETIMER_THRESH
:
258 return xfrm_nla_cpy(dst
, src
, nla_len(src
));
260 return nla_put_64bit(dst
, src
->nla_type
, nla_len(src
),
261 nla_data(src
), XFRMA_PAD
);
262 case XFRMA_POLICY_TYPE
:
265 case XFRMA_KMADDRESS
:
266 case XFRMA_ALG_AUTH_TRUNC
:
269 case XFRMA_REPLAY_ESN_VAL
:
270 case XFRMA_SA_EXTRA_FLAGS
:
272 case XFRMA_ADDRESS_FILTER
:
273 case XFRMA_OFFLOAD_DEV
:
275 case XFRMA_SET_MARK_MASK
:
277 return xfrm_nla_cpy(dst
, src
, nla_len(src
));
279 BUILD_BUG_ON(XFRMA_MAX
!= XFRMA_IF_ID
);
280 WARN_ONCE(1, "unsupported nla_type %d", src
->nla_type
);
285 /* Take kernel-built (64bit layout) and create 32bit layout for userspace */
286 static int xfrm_xlate64(struct sk_buff
*dst
, const struct nlmsghdr
*nlh_src
)
288 u16 type
= nlh_src
->nlmsg_type
- XFRM_MSG_BASE
;
289 const struct nlattr
*nla
, *attrs
;
290 struct nlmsghdr
*nlh_dst
;
293 nlh_dst
= xfrm_nlmsg_put_compat(dst
, nlh_src
, type
);
295 return PTR_ERR(nlh_dst
);
297 attrs
= nlmsg_attrdata(nlh_src
, xfrm_msg_min
[type
]);
298 len
= nlmsg_attrlen(nlh_src
, xfrm_msg_min
[type
]);
300 nla_for_each_attr(nla
, attrs
, len
, remaining
) {
301 int err
= xfrm_xlate64_attr(dst
, nla
);
307 nlmsg_end(dst
, nlh_dst
);
312 static int xfrm_alloc_compat(struct sk_buff
*skb
, const struct nlmsghdr
*nlh_src
)
314 u16 type
= nlh_src
->nlmsg_type
- XFRM_MSG_BASE
;
315 struct sk_buff
*new = NULL
;
318 if (WARN_ON_ONCE(type
>= ARRAY_SIZE(xfrm_msg_min
)))
321 if (skb_shinfo(skb
)->frag_list
== NULL
) {
322 new = alloc_skb(skb
->len
+ skb_tailroom(skb
), GFP_ATOMIC
);
325 skb_shinfo(skb
)->frag_list
= new;
328 err
= xfrm_xlate64(skb_shinfo(skb
)->frag_list
, nlh_src
);
332 skb_shinfo(skb
)->frag_list
= NULL
;
340 /* Calculates len of translated 64-bit message. */
341 static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr
*src
,
342 struct nlattr
*attrs
[XFRMA_MAX
+1])
344 size_t len
= nlmsg_len(src
);
346 switch (src
->nlmsg_type
) {
348 case XFRM_MSG_NEWPOLICY
:
349 case XFRM_MSG_ALLOCSPI
:
350 case XFRM_MSG_ACQUIRE
:
351 case XFRM_MSG_UPDPOLICY
:
355 case XFRM_MSG_EXPIRE
:
356 case XFRM_MSG_POLEXPIRE
:
365 if (attrs
[XFRMA_POLICY
])
368 /* XXX: some attrs may need to be realigned
369 * if !CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
375 static int xfrm_attr_cpy32(void *dst
, size_t *pos
, const struct nlattr
*src
,
376 size_t size
, int copy_len
, int payload
)
378 struct nlmsghdr
*nlmsg
= dst
;
381 if (WARN_ON_ONCE(copy_len
> payload
))
384 if (size
- *pos
< nla_attr_size(payload
))
389 memcpy(nla
, src
, nla_attr_size(copy_len
));
390 nla
->nla_len
= nla_attr_size(payload
);
391 *pos
+= nla_attr_size(copy_len
);
392 nlmsg
->nlmsg_len
+= nla
->nla_len
;
394 memset(dst
+ *pos
, 0, payload
- copy_len
);
395 *pos
+= payload
- copy_len
;
400 static int xfrm_xlate32_attr(void *dst
, const struct nlattr
*nla
,
401 size_t *pos
, size_t size
,
402 struct netlink_ext_ack
*extack
)
404 int type
= nla_type(nla
);
405 u16 pol_len32
, pol_len64
;
408 if (type
> XFRMA_MAX
) {
409 BUILD_BUG_ON(XFRMA_MAX
!= XFRMA_IF_ID
);
410 NL_SET_ERR_MSG(extack
, "Bad attribute");
413 if (nla_len(nla
) < compat_policy
[type
].len
) {
414 NL_SET_ERR_MSG(extack
, "Attribute bad length");
418 pol_len32
= compat_policy
[type
].len
;
419 pol_len64
= xfrma_policy
[type
].len
;
421 /* XFRMA_SA and XFRMA_POLICY - need to know how-to translate */
422 if (pol_len32
!= pol_len64
) {
423 if (nla_len(nla
) != compat_policy
[type
].len
) {
424 NL_SET_ERR_MSG(extack
, "Attribute bad length");
427 err
= xfrm_attr_cpy32(dst
, pos
, nla
, size
, pol_len32
, pol_len64
);
432 return xfrm_attr_cpy32(dst
, pos
, nla
, size
, nla_len(nla
), nla_len(nla
));
435 static int xfrm_xlate32(struct nlmsghdr
*dst
, const struct nlmsghdr
*src
,
436 struct nlattr
*attrs
[XFRMA_MAX
+1],
437 size_t size
, u8 type
, struct netlink_ext_ack
*extack
)
442 memcpy(dst
, src
, NLMSG_HDRLEN
);
443 dst
->nlmsg_len
= NLMSG_HDRLEN
+ xfrm_msg_min
[type
];
444 memset(nlmsg_data(dst
), 0, xfrm_msg_min
[type
]);
446 switch (src
->nlmsg_type
) {
447 /* Compat message has the same layout as native */
450 case XFRM_MSG_DELPOLICY
:
451 case XFRM_MSG_GETPOLICY
:
452 case XFRM_MSG_FLUSHSA
:
453 case XFRM_MSG_FLUSHPOLICY
:
456 case XFRM_MSG_REPORT
:
457 case XFRM_MSG_MIGRATE
:
458 case XFRM_MSG_NEWSADINFO
:
459 case XFRM_MSG_GETSADINFO
:
460 case XFRM_MSG_NEWSPDINFO
:
461 case XFRM_MSG_GETSPDINFO
:
462 case XFRM_MSG_MAPPING
:
463 memcpy(nlmsg_data(dst
), nlmsg_data(src
), compat_msg_min
[type
]);
465 /* 4 byte alignment for trailing u64 on native, but not on compat */
467 case XFRM_MSG_NEWPOLICY
:
469 case XFRM_MSG_UPDPOLICY
:
470 memcpy(nlmsg_data(dst
), nlmsg_data(src
), compat_msg_min
[type
]);
472 case XFRM_MSG_EXPIRE
: {
473 const struct compat_xfrm_user_expire
*src_ue
= nlmsg_data(src
);
474 struct xfrm_user_expire
*dst_ue
= nlmsg_data(dst
);
476 /* compat_xfrm_user_expire has 4-byte smaller state */
477 memcpy(dst_ue
, src_ue
, sizeof(src_ue
->state
));
478 dst_ue
->hard
= src_ue
->hard
;
481 case XFRM_MSG_ACQUIRE
: {
482 const struct compat_xfrm_user_acquire
*src_ua
= nlmsg_data(src
);
483 struct xfrm_user_acquire
*dst_ua
= nlmsg_data(dst
);
485 memcpy(dst_ua
, src_ua
, offsetof(struct compat_xfrm_user_acquire
, aalgos
));
486 dst_ua
->aalgos
= src_ua
->aalgos
;
487 dst_ua
->ealgos
= src_ua
->ealgos
;
488 dst_ua
->calgos
= src_ua
->calgos
;
489 dst_ua
->seq
= src_ua
->seq
;
492 case XFRM_MSG_POLEXPIRE
: {
493 const struct compat_xfrm_user_polexpire
*src_upe
= nlmsg_data(src
);
494 struct xfrm_user_polexpire
*dst_upe
= nlmsg_data(dst
);
496 /* compat_xfrm_user_polexpire has 4-byte smaller state */
497 memcpy(dst_upe
, src_upe
, sizeof(src_upe
->pol
));
498 dst_upe
->hard
= src_upe
->hard
;
501 case XFRM_MSG_ALLOCSPI
: {
502 const struct compat_xfrm_userspi_info
*src_usi
= nlmsg_data(src
);
503 struct xfrm_userspi_info
*dst_usi
= nlmsg_data(dst
);
505 /* compat_xfrm_user_polexpire has 4-byte smaller state */
506 memcpy(dst_usi
, src_usi
, sizeof(src_usi
->info
));
507 dst_usi
->min
= src_usi
->min
;
508 dst_usi
->max
= src_usi
->max
;
512 NL_SET_ERR_MSG(extack
, "Unsupported message type");
515 pos
= dst
->nlmsg_len
;
517 for (i
= 1; i
< XFRMA_MAX
+ 1; i
++) {
526 err
= xfrm_xlate32_attr(dst
, attrs
[i
], &pos
, size
, extack
);
534 static struct nlmsghdr
*xfrm_user_rcv_msg_compat(const struct nlmsghdr
*h32
,
535 int maxtype
, const struct nla_policy
*policy
,
536 struct netlink_ext_ack
*extack
)
538 /* netlink_rcv_skb() checks if a message has full (struct nlmsghdr) */
539 u16 type
= h32
->nlmsg_type
- XFRM_MSG_BASE
;
540 struct nlattr
*attrs
[XFRMA_MAX
+1];
541 struct nlmsghdr
*h64
;
545 BUILD_BUG_ON(ARRAY_SIZE(xfrm_msg_min
) != ARRAY_SIZE(compat_msg_min
));
547 if (type
>= ARRAY_SIZE(xfrm_msg_min
))
548 return ERR_PTR(-EINVAL
);
550 /* Don't call parse: the message might have only nlmsg header */
551 if ((h32
->nlmsg_type
== XFRM_MSG_GETSA
||
552 h32
->nlmsg_type
== XFRM_MSG_GETPOLICY
) &&
553 (h32
->nlmsg_flags
& NLM_F_DUMP
))
556 err
= nlmsg_parse_deprecated(h32
, compat_msg_min
[type
], attrs
,
557 maxtype
? : XFRMA_MAX
, policy
? : compat_policy
, extack
);
561 len
= xfrm_user_rcv_calculate_len64(h32
, attrs
);
562 /* The message doesn't need translation */
563 if (len
== nlmsg_len(h32
))
567 h64
= kvmalloc(len
, GFP_KERNEL
);
569 return ERR_PTR(-ENOMEM
);
571 err
= xfrm_xlate32(h64
, h32
, attrs
, len
, type
, extack
);
580 static int xfrm_user_policy_compat(u8
**pdata32
, int optlen
)
582 struct compat_xfrm_userpolicy_info
*p
= (void *)*pdata32
;
583 u8
*src_templates
, *dst_templates
;
586 if (optlen
< sizeof(*p
))
589 data64
= kmalloc_track_caller(optlen
+ 4, GFP_USER
| __GFP_NOWARN
);
593 memcpy(data64
, *pdata32
, sizeof(*p
));
594 memset(data64
+ sizeof(*p
), 0, 4);
596 src_templates
= *pdata32
+ sizeof(*p
);
597 dst_templates
= data64
+ sizeof(*p
) + 4;
598 memcpy(dst_templates
, src_templates
, optlen
- sizeof(*p
));
605 static struct xfrm_translator xfrm_translator
= {
606 .owner
= THIS_MODULE
,
607 .alloc_compat
= xfrm_alloc_compat
,
608 .rcv_msg_compat
= xfrm_user_rcv_msg_compat
,
609 .xlate_user_policy_sockptr
= xfrm_user_policy_compat
,
612 static int __init
xfrm_compat_init(void)
614 return xfrm_register_translator(&xfrm_translator
);
617 static void __exit
xfrm_compat_exit(void)
619 xfrm_unregister_translator(&xfrm_translator
);
622 module_init(xfrm_compat_init
);
623 module_exit(xfrm_compat_exit
);
624 MODULE_LICENSE("GPL");
625 MODULE_AUTHOR("Dmitry Safonov");
626 MODULE_DESCRIPTION("XFRM 32-bit compatibility layer");