xfrm: Provide API to register translator module
Add a skeleton for xfrm_compat module and provide API to register it in xfrm_state.ko. struct xfrm_translator will have function pointers to translate messages received from 32-bit userspace or to be sent to it from 64-bit kernel. module_get()/module_put() are used instead of rcu_read_lock() as the module will vmalloc() memory for translation. The new API is registered with xfrm_state module, not with xfrm_user as the former needs translator for user_policy set by setsockopt() and xfrm_user already uses functions from xfrm_state. Signed-off-by: Dmitry Safonov <dima@arista.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
committed by
Steffen Klassert
parent
02a20d4fef
commit
c9e7c76d70
@@ -2000,6 +2000,25 @@ static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct xfrm_translator {
|
||||||
|
struct module *owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_XFRM_USER_COMPAT)
|
||||||
|
extern int xfrm_register_translator(struct xfrm_translator *xtr);
|
||||||
|
extern int xfrm_unregister_translator(struct xfrm_translator *xtr);
|
||||||
|
extern struct xfrm_translator *xfrm_get_translator(void);
|
||||||
|
extern void xfrm_put_translator(struct xfrm_translator *xtr);
|
||||||
|
#else
|
||||||
|
static inline struct xfrm_translator *xfrm_get_translator(void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static inline void xfrm_put_translator(struct xfrm_translator *xtr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
static inline bool xfrm6_local_dontfrag(const struct sock *sk)
|
static inline bool xfrm6_local_dontfrag(const struct sock *sk)
|
||||||
{
|
{
|
||||||
|
@@ -28,6 +28,16 @@ config XFRM_USER
|
|||||||
|
|
||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config XFRM_USER_COMPAT
|
||||||
|
tristate "Compatible ABI support"
|
||||||
|
depends on XFRM_USER && COMPAT_FOR_U64_ALIGNMENT
|
||||||
|
select WANT_COMPAT_NETLINK_MESSAGES
|
||||||
|
help
|
||||||
|
Transformation(XFRM) user configuration interface like IPsec
|
||||||
|
used by compatible Linux applications.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
config XFRM_INTERFACE
|
config XFRM_INTERFACE
|
||||||
tristate "Transformation virtual interface"
|
tristate "Transformation virtual interface"
|
||||||
depends on XFRM && IPV6
|
depends on XFRM && IPV6
|
||||||
|
@@ -9,6 +9,7 @@ obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
|
|||||||
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
|
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
|
||||||
obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
|
obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
|
||||||
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
|
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
|
||||||
|
obj-$(CONFIG_XFRM_USER_COMPAT) += xfrm_compat.o
|
||||||
obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
|
obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
|
||||||
obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o
|
obj-$(CONFIG_XFRM_INTERFACE) += xfrm_interface.o
|
||||||
obj-$(CONFIG_XFRM_ESPINTCP) += espintcp.o
|
obj-$(CONFIG_XFRM_ESPINTCP) += espintcp.o
|
||||||
|
29
net/xfrm/xfrm_compat.c
Normal file
29
net/xfrm/xfrm_compat.c
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* XFRM compat layer
|
||||||
|
* Author: Dmitry Safonov <dima@arista.com>
|
||||||
|
* Based on code and translator idea by: Florian Westphal <fw@strlen.de>
|
||||||
|
*/
|
||||||
|
#include <linux/compat.h>
|
||||||
|
#include <linux/xfrm.h>
|
||||||
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
|
static struct xfrm_translator xfrm_translator = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init xfrm_compat_init(void)
|
||||||
|
{
|
||||||
|
return xfrm_register_translator(&xfrm_translator);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit xfrm_compat_exit(void)
|
||||||
|
{
|
||||||
|
xfrm_unregister_translator(&xfrm_translator);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(xfrm_compat_init);
|
||||||
|
module_exit(xfrm_compat_exit);
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Dmitry Safonov");
|
||||||
|
MODULE_DESCRIPTION("XFRM 32-bit compatibility layer");
|
@@ -2264,6 +2264,66 @@ static bool km_is_alive(const struct km_event *c)
|
|||||||
return is_alive;
|
return is_alive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_XFRM_USER_COMPAT)
|
||||||
|
static DEFINE_SPINLOCK(xfrm_translator_lock);
|
||||||
|
static struct xfrm_translator __rcu *xfrm_translator;
|
||||||
|
|
||||||
|
struct xfrm_translator *xfrm_get_translator(void)
|
||||||
|
{
|
||||||
|
struct xfrm_translator *xtr;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
xtr = rcu_dereference(xfrm_translator);
|
||||||
|
if (unlikely(!xtr))
|
||||||
|
goto out;
|
||||||
|
if (!try_module_get(xtr->owner))
|
||||||
|
xtr = NULL;
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return xtr;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xfrm_get_translator);
|
||||||
|
|
||||||
|
void xfrm_put_translator(struct xfrm_translator *xtr)
|
||||||
|
{
|
||||||
|
module_put(xtr->owner);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xfrm_put_translator);
|
||||||
|
|
||||||
|
int xfrm_register_translator(struct xfrm_translator *xtr)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
spin_lock_bh(&xfrm_translator_lock);
|
||||||
|
if (unlikely(xfrm_translator != NULL))
|
||||||
|
err = -EEXIST;
|
||||||
|
else
|
||||||
|
rcu_assign_pointer(xfrm_translator, xtr);
|
||||||
|
spin_unlock_bh(&xfrm_translator_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xfrm_register_translator);
|
||||||
|
|
||||||
|
int xfrm_unregister_translator(struct xfrm_translator *xtr)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
spin_lock_bh(&xfrm_translator_lock);
|
||||||
|
if (likely(xfrm_translator != NULL)) {
|
||||||
|
if (rcu_access_pointer(xfrm_translator) != xtr)
|
||||||
|
err = -EINVAL;
|
||||||
|
else
|
||||||
|
RCU_INIT_POINTER(xfrm_translator, NULL);
|
||||||
|
}
|
||||||
|
spin_unlock_bh(&xfrm_translator_lock);
|
||||||
|
synchronize_rcu();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xfrm_unregister_translator);
|
||||||
|
#endif
|
||||||
|
|
||||||
int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
|
int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
Reference in New Issue
Block a user