2019-05-19 20:08:20 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2005-04-17 06:20:36 +08:00
|
|
|
/* xfrm_user.c: User interface to configure xfrm engine.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
|
|
|
|
*
|
|
|
|
* Changes:
|
|
|
|
* Mitsuru KANDA @USAGI
|
|
|
|
* Kazunori MIYAZAWA @USAGI
|
|
|
|
* Kunihiro Ishiguro <kunihiro@ipinfusion.com>
|
|
|
|
* IPv6 support
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
2021-12-29 08:49:13 +08:00
|
|
|
#include <linux/compat.h>
|
2006-08-06 17:49:12 +08:00
|
|
|
#include <linux/crypto.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/socket.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/pfkeyv2.h>
|
|
|
|
#include <linux/ipsec.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/security.h>
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/xfrm.h>
|
2005-11-10 09:25:54 +08:00
|
|
|
#include <net/netlink.h>
|
2011-01-11 16:04:12 +08:00
|
|
|
#include <net/ah.h>
|
2016-12-25 03:46:01 +08:00
|
|
|
#include <linux/uaccess.h>
|
2011-12-10 17:48:31 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
2006-08-24 11:33:28 +08:00
|
|
|
#include <linux/in6.h>
|
|
|
|
#endif
|
2015-10-21 23:48:25 +08:00
|
|
|
#include <asm/unaligned.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[type];
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_algo *algp;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
algp = nla_data(rt);
|
2017-09-22 04:46:30 +08:00
|
|
|
if (nla_len(rt) < (int)xfrm_alg_len(algp))
|
2005-05-20 03:39:49 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (type) {
|
|
|
|
case XFRMA_ALG_AUTH:
|
|
|
|
case XFRMA_ALG_CRYPT:
|
|
|
|
case XFRMA_ALG_COMP:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2017-04-06 16:16:10 +08:00
|
|
|
algp->alg_name[sizeof(algp->alg_name) - 1] = '\0';
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-25 08:29:52 +08:00
|
|
|
static int verify_auth_trunc(struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC];
|
|
|
|
struct xfrm_algo_auth *algp;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
algp = nla_data(rt);
|
2017-09-22 04:47:09 +08:00
|
|
|
if (nla_len(rt) < (int)xfrm_alg_auth_len(algp))
|
2009-11-25 08:29:52 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-04-06 16:16:10 +08:00
|
|
|
algp->alg_name[sizeof(algp->alg_name) - 1] = '\0';
|
2009-11-25 08:29:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-29 11:37:29 +08:00
|
|
|
static int verify_aead(struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
struct nlattr *rt = attrs[XFRMA_ALG_AEAD];
|
|
|
|
struct xfrm_algo_aead *algp;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
algp = nla_data(rt);
|
2017-09-22 04:45:43 +08:00
|
|
|
if (nla_len(rt) < (int)aead_len(algp))
|
2008-01-29 11:37:29 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-04-06 16:16:10 +08:00
|
|
|
algp->alg_name[sizeof(algp->alg_name) - 1] = '\0';
|
2008-01-29 11:37:29 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type,
|
2006-08-24 08:56:04 +08:00
|
|
|
xfrm_address_t **addrp)
|
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[type];
|
2006-08-24 08:56:04 +08:00
|
|
|
|
2007-08-23 04:59:04 +08:00
|
|
|
if (rt && addrp)
|
2007-08-23 05:01:33 +08:00
|
|
|
*addrp = nla_data(rt);
|
2006-08-24 08:56:04 +08:00
|
|
|
}
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
static inline int verify_sec_ctx_len(struct nlattr **attrs)
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
struct xfrm_user_sec_ctx *uctx;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
uctx = nla_data(rt);
|
2020-02-09 21:15:29 +08:00
|
|
|
if (uctx->len > nla_len(rt) ||
|
|
|
|
uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len))
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
static inline int verify_replay(struct xfrm_usersa_info *p,
|
|
|
|
struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
|
2012-09-20 18:01:49 +08:00
|
|
|
struct xfrm_replay_state_esn *rs;
|
2011-03-08 08:10:27 +08:00
|
|
|
|
2018-02-12 21:42:01 +08:00
|
|
|
if (!rt)
|
|
|
|
return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
|
2012-09-20 18:01:49 +08:00
|
|
|
|
2018-02-12 21:42:01 +08:00
|
|
|
rs = nla_data(rt);
|
2012-09-20 18:01:49 +08:00
|
|
|
|
2018-02-12 21:42:01 +08:00
|
|
|
if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
|
|
|
|
return -EINVAL;
|
2011-04-26 03:41:21 +08:00
|
|
|
|
2018-02-12 21:42:01 +08:00
|
|
|
if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
|
|
|
|
nla_len(rt) != sizeof(*rs))
|
|
|
|
return -EINVAL;
|
2011-03-08 08:10:27 +08:00
|
|
|
|
2014-01-18 09:54:28 +08:00
|
|
|
/* As only ESP and AH support ESN feature. */
|
|
|
|
if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
|
2011-03-29 03:48:09 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
if (p->replay_window != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int verify_newsa_info(struct xfrm_usersa_info *p,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
switch (p->family) {
|
2019-05-21 23:29:47 +08:00
|
|
|
case AF_INET:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
err = -EAFNOSUPPORT;
|
|
|
|
goto out;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (p->sel.family) {
|
2019-06-14 17:13:55 +08:00
|
|
|
case AF_UNSPEC:
|
|
|
|
break;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
case AF_INET:
|
2018-08-01 19:45:11 +08:00
|
|
|
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
|
|
|
|
goto out;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
2011-12-10 17:48:31 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
2018-08-01 19:45:11 +08:00
|
|
|
if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128)
|
|
|
|
goto out;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
#else
|
|
|
|
err = -EAFNOSUPPORT;
|
|
|
|
goto out;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto out;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
switch (p->id.proto) {
|
|
|
|
case IPPROTO_AH:
|
2009-11-25 08:29:52 +08:00
|
|
|
if ((!attrs[XFRMA_ALG_AUTH] &&
|
|
|
|
!attrs[XFRMA_ALG_AUTH_TRUNC]) ||
|
2008-01-29 11:37:29 +08:00
|
|
|
attrs[XFRMA_ALG_AEAD] ||
|
2007-08-23 05:00:40 +08:00
|
|
|
attrs[XFRMA_ALG_CRYPT] ||
|
2010-12-08 12:37:49 +08:00
|
|
|
attrs[XFRMA_ALG_COMP] ||
|
2014-06-26 21:12:45 +08:00
|
|
|
attrs[XFRMA_TFCPAD])
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPPROTO_ESP:
|
2008-01-29 11:37:29 +08:00
|
|
|
if (attrs[XFRMA_ALG_COMP])
|
|
|
|
goto out;
|
|
|
|
if (!attrs[XFRMA_ALG_AUTH] &&
|
2009-11-25 08:29:52 +08:00
|
|
|
!attrs[XFRMA_ALG_AUTH_TRUNC] &&
|
2008-01-29 11:37:29 +08:00
|
|
|
!attrs[XFRMA_ALG_CRYPT] &&
|
|
|
|
!attrs[XFRMA_ALG_AEAD])
|
|
|
|
goto out;
|
|
|
|
if ((attrs[XFRMA_ALG_AUTH] ||
|
2009-11-25 08:29:52 +08:00
|
|
|
attrs[XFRMA_ALG_AUTH_TRUNC] ||
|
2008-01-29 11:37:29 +08:00
|
|
|
attrs[XFRMA_ALG_CRYPT]) &&
|
|
|
|
attrs[XFRMA_ALG_AEAD])
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
2010-12-08 12:37:49 +08:00
|
|
|
if (attrs[XFRMA_TFCPAD] &&
|
|
|
|
p->mode != XFRM_MODE_TUNNEL)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPPROTO_COMP:
|
2007-08-23 05:00:40 +08:00
|
|
|
if (!attrs[XFRMA_ALG_COMP] ||
|
2008-01-29 11:37:29 +08:00
|
|
|
attrs[XFRMA_ALG_AEAD] ||
|
2007-08-23 05:00:40 +08:00
|
|
|
attrs[XFRMA_ALG_AUTH] ||
|
2009-11-25 08:29:52 +08:00
|
|
|
attrs[XFRMA_ALG_AUTH_TRUNC] ||
|
2010-12-08 12:37:49 +08:00
|
|
|
attrs[XFRMA_ALG_CRYPT] ||
|
2014-06-26 21:12:45 +08:00
|
|
|
attrs[XFRMA_TFCPAD] ||
|
|
|
|
(ntohl(p->id.spi) >= 0x10000))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
2011-12-10 17:48:31 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
2006-08-24 11:33:28 +08:00
|
|
|
case IPPROTO_DSTOPTS:
|
|
|
|
case IPPROTO_ROUTING:
|
2007-08-23 05:00:40 +08:00
|
|
|
if (attrs[XFRMA_ALG_COMP] ||
|
|
|
|
attrs[XFRMA_ALG_AUTH] ||
|
2009-11-25 08:29:52 +08:00
|
|
|
attrs[XFRMA_ALG_AUTH_TRUNC] ||
|
2008-01-29 11:37:29 +08:00
|
|
|
attrs[XFRMA_ALG_AEAD] ||
|
2007-08-23 05:00:40 +08:00
|
|
|
attrs[XFRMA_ALG_CRYPT] ||
|
|
|
|
attrs[XFRMA_ENCAP] ||
|
|
|
|
attrs[XFRMA_SEC_CTX] ||
|
2010-12-08 12:37:49 +08:00
|
|
|
attrs[XFRMA_TFCPAD] ||
|
2007-08-23 05:00:40 +08:00
|
|
|
!attrs[XFRMA_COADDR])
|
2006-08-24 11:33:28 +08:00
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
default:
|
|
|
|
goto out;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-01-29 11:37:29 +08:00
|
|
|
if ((err = verify_aead(attrs)))
|
|
|
|
goto out;
|
2009-11-25 08:29:52 +08:00
|
|
|
if ((err = verify_auth_trunc(attrs)))
|
|
|
|
goto out;
|
2007-08-23 05:00:40 +08:00
|
|
|
if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH)))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
2007-08-23 05:00:40 +08:00
|
|
|
if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT)))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
2007-08-23 05:00:40 +08:00
|
|
|
if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP)))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto out;
|
2007-08-23 05:00:40 +08:00
|
|
|
if ((err = verify_sec_ctx_len(attrs)))
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
goto out;
|
2011-03-08 08:10:27 +08:00
|
|
|
if ((err = verify_replay(p, attrs)))
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
switch (p->mode) {
|
2006-09-23 06:05:15 +08:00
|
|
|
case XFRM_MODE_TRANSPORT:
|
|
|
|
case XFRM_MODE_TUNNEL:
|
2006-08-24 09:18:55 +08:00
|
|
|
case XFRM_MODE_ROUTEOPTIMIZATION:
|
2006-10-04 14:47:05 +08:00
|
|
|
case XFRM_MODE_BEET:
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto out;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
2021-12-22 21:11:18 +08:00
|
|
|
if (attrs[XFRMA_MTIMER_THRESH])
|
|
|
|
if (!attrs[XFRMA_ENCAP])
|
|
|
|
err = -EINVAL;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
|
2011-02-28 15:04:45 +08:00
|
|
|
struct xfrm_algo_desc *(*get_byname)(const char *, int),
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rta)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct xfrm_algo *p, *ualg;
|
|
|
|
struct xfrm_algo_desc *algo;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
ualg = nla_data(rta);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
algo = get_byname(ualg->alg_name, 1);
|
|
|
|
if (!algo)
|
|
|
|
return -ENOSYS;
|
|
|
|
*props = algo->desc.sadb_alg_id;
|
|
|
|
|
2008-01-09 15:39:06 +08:00
|
|
|
p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-08-13 06:50:00 +08:00
|
|
|
strcpy(p->alg_name, algo->name);
|
2005-04-17 06:20:36 +08:00
|
|
|
*algpp = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-27 16:03:45 +08:00
|
|
|
static int attach_crypt(struct xfrm_state *x, struct nlattr *rta)
|
|
|
|
{
|
|
|
|
struct xfrm_algo *p, *ualg;
|
|
|
|
struct xfrm_algo_desc *algo;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ualg = nla_data(rta);
|
|
|
|
|
|
|
|
algo = xfrm_ealg_get_byname(ualg->alg_name, 1);
|
|
|
|
if (!algo)
|
|
|
|
return -ENOSYS;
|
|
|
|
x->props.ealgo = algo->desc.sadb_alg_id;
|
|
|
|
|
|
|
|
p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
strcpy(p->alg_name, algo->name);
|
|
|
|
x->ealg = p;
|
|
|
|
x->geniv = algo->uinfo.encr.geniv;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-11-25 08:29:52 +08:00
|
|
|
static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props,
|
|
|
|
struct nlattr *rta)
|
|
|
|
{
|
|
|
|
struct xfrm_algo *ualg;
|
|
|
|
struct xfrm_algo_auth *p;
|
|
|
|
struct xfrm_algo_desc *algo;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ualg = nla_data(rta);
|
|
|
|
|
|
|
|
algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
|
|
|
|
if (!algo)
|
|
|
|
return -ENOSYS;
|
|
|
|
*props = algo->desc.sadb_alg_id;
|
|
|
|
|
|
|
|
p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
strcpy(p->alg_name, algo->name);
|
|
|
|
p->alg_key_len = ualg->alg_key_len;
|
|
|
|
p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
|
|
|
|
memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8);
|
|
|
|
|
|
|
|
*algpp = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props,
|
|
|
|
struct nlattr *rta)
|
|
|
|
{
|
|
|
|
struct xfrm_algo_auth *p, *ualg;
|
|
|
|
struct xfrm_algo_desc *algo;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ualg = nla_data(rta);
|
|
|
|
|
|
|
|
algo = xfrm_aalg_get_byname(ualg->alg_name, 1);
|
|
|
|
if (!algo)
|
|
|
|
return -ENOSYS;
|
2014-09-18 16:38:18 +08:00
|
|
|
if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits)
|
2009-11-25 08:29:52 +08:00
|
|
|
return -EINVAL;
|
|
|
|
*props = algo->desc.sadb_alg_id;
|
|
|
|
|
|
|
|
p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
strcpy(p->alg_name, algo->name);
|
|
|
|
if (!p->alg_trunc_len)
|
|
|
|
p->alg_trunc_len = algo->uinfo.auth.icv_truncbits;
|
|
|
|
|
|
|
|
*algpp = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-05-27 16:03:45 +08:00
|
|
|
static int attach_aead(struct xfrm_state *x, struct nlattr *rta)
|
2008-01-29 11:37:29 +08:00
|
|
|
{
|
|
|
|
struct xfrm_algo_aead *p, *ualg;
|
|
|
|
struct xfrm_algo_desc *algo;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ualg = nla_data(rta);
|
|
|
|
|
|
|
|
algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1);
|
|
|
|
if (!algo)
|
|
|
|
return -ENOSYS;
|
2015-05-27 16:03:45 +08:00
|
|
|
x->props.ealgo = algo->desc.sadb_alg_id;
|
2008-01-29 11:37:29 +08:00
|
|
|
|
|
|
|
p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL);
|
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
strcpy(p->alg_name, algo->name);
|
2015-05-27 16:03:45 +08:00
|
|
|
x->aead = p;
|
|
|
|
x->geniv = algo->uinfo.aead.geniv;
|
2008-01-29 11:37:29 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-29 03:47:30 +08:00
|
|
|
static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_esn,
|
|
|
|
struct nlattr *rp)
|
|
|
|
{
|
|
|
|
struct xfrm_replay_state_esn *up;
|
2017-09-22 04:47:50 +08:00
|
|
|
unsigned int ulen;
|
2011-03-29 03:47:30 +08:00
|
|
|
|
|
|
|
if (!replay_esn || !rp)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
up = nla_data(rp);
|
2012-09-20 18:01:49 +08:00
|
|
|
ulen = xfrm_replay_state_esn_len(up);
|
2011-03-29 03:47:30 +08:00
|
|
|
|
2017-03-23 15:45:44 +08:00
|
|
|
/* Check the overall length and the internal bitmap length to avoid
|
|
|
|
* potential overflow. */
|
2017-09-22 04:47:50 +08:00
|
|
|
if (nla_len(rp) < (int)ulen ||
|
2017-03-23 15:45:44 +08:00
|
|
|
xfrm_replay_state_esn_len(replay_esn) != ulen ||
|
|
|
|
replay_esn->bmp_len != up->bmp_len)
|
2011-03-29 03:47:30 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2017-03-22 15:29:31 +08:00
|
|
|
if (up->replay_window > up->bmp_len * sizeof(__u32) * 8)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-03-29 03:47:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
static int xfrm_alloc_replay_state_esn(struct xfrm_replay_state_esn **replay_esn,
|
|
|
|
struct xfrm_replay_state_esn **preplay_esn,
|
|
|
|
struct nlattr *rta)
|
|
|
|
{
|
|
|
|
struct xfrm_replay_state_esn *p, *pp, *up;
|
2017-09-22 04:47:50 +08:00
|
|
|
unsigned int klen, ulen;
|
2011-03-08 08:10:27 +08:00
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
up = nla_data(rta);
|
2012-09-20 18:01:49 +08:00
|
|
|
klen = xfrm_replay_state_esn_len(up);
|
2017-09-22 04:47:50 +08:00
|
|
|
ulen = nla_len(rta) >= (int)klen ? klen : sizeof(*up);
|
2011-03-08 08:10:27 +08:00
|
|
|
|
2012-09-20 18:01:49 +08:00
|
|
|
p = kzalloc(klen, GFP_KERNEL);
|
2011-03-08 08:10:27 +08:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-09-20 18:01:49 +08:00
|
|
|
pp = kzalloc(klen, GFP_KERNEL);
|
2011-03-08 08:10:27 +08:00
|
|
|
if (!pp) {
|
|
|
|
kfree(p);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2012-09-20 18:01:49 +08:00
|
|
|
memcpy(p, up, ulen);
|
|
|
|
memcpy(pp, up, ulen);
|
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
*replay_esn = p;
|
|
|
|
*preplay_esn = pp;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx)
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
{
|
2017-09-22 04:48:54 +08:00
|
|
|
unsigned int len = 0;
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
|
|
|
if (xfrm_ctx) {
|
|
|
|
len += sizeof(struct xfrm_user_sec_ctx);
|
|
|
|
len += xfrm_ctx->ctx_len;
|
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
|
|
|
|
{
|
|
|
|
memcpy(&x->id, &p->id, sizeof(x->id));
|
|
|
|
memcpy(&x->sel, &p->sel, sizeof(x->sel));
|
|
|
|
memcpy(&x->lft, &p->lft, sizeof(x->lft));
|
|
|
|
x->props.mode = p->mode;
|
2013-09-17 15:14:13 +08:00
|
|
|
x->props.replay_window = min_t(unsigned int, p->replay_window,
|
|
|
|
sizeof(x->replay.bitmap) * 8);
|
2005-04-17 06:20:36 +08:00
|
|
|
x->props.reqid = p->reqid;
|
|
|
|
x->props.family = p->family;
|
2006-10-28 06:29:47 +08:00
|
|
|
memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
|
2005-04-17 06:20:36 +08:00
|
|
|
x->props.flags = p->flags;
|
2007-07-31 17:04:32 +08:00
|
|
|
|
2008-07-11 07:55:37 +08:00
|
|
|
if (!x->sel.family && !(p->flags & XFRM_STATE_AF_UNSPEC))
|
2007-07-31 17:04:32 +08:00
|
|
|
x->sel.family = p->family;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-03-21 11:16:12 +08:00
|
|
|
/*
|
|
|
|
* someday when pfkey also has support, we could have the code
|
|
|
|
* somehow made shareable and move it to xfrm_state.c - JHS
|
|
|
|
*
|
|
|
|
*/
|
2012-09-19 19:33:43 +08:00
|
|
|
static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs,
|
|
|
|
int update_esn)
|
2006-03-21 11:16:12 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
|
2012-09-19 19:33:43 +08:00
|
|
|
struct nlattr *re = update_esn ? attrs[XFRMA_REPLAY_ESN_VAL] : NULL;
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
|
|
|
|
struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
|
|
|
|
struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
|
2021-12-22 21:11:18 +08:00
|
|
|
struct nlattr *mt = attrs[XFRMA_MTIMER_THRESH];
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
if (re) {
|
|
|
|
struct xfrm_replay_state_esn *replay_esn;
|
|
|
|
replay_esn = nla_data(re);
|
|
|
|
memcpy(x->replay_esn, replay_esn,
|
|
|
|
xfrm_replay_state_esn_len(replay_esn));
|
|
|
|
memcpy(x->preplay_esn, replay_esn,
|
|
|
|
xfrm_replay_state_esn_len(replay_esn));
|
|
|
|
}
|
|
|
|
|
2006-03-21 11:16:12 +08:00
|
|
|
if (rp) {
|
|
|
|
struct xfrm_replay_state *replay;
|
2007-08-23 05:01:33 +08:00
|
|
|
replay = nla_data(rp);
|
2006-03-21 11:16:12 +08:00
|
|
|
memcpy(&x->replay, replay, sizeof(*replay));
|
|
|
|
memcpy(&x->preplay, replay, sizeof(*replay));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lt) {
|
|
|
|
struct xfrm_lifetime_cur *ltime;
|
2007-08-23 05:01:33 +08:00
|
|
|
ltime = nla_data(lt);
|
2006-03-21 11:16:12 +08:00
|
|
|
x->curlft.bytes = ltime->bytes;
|
|
|
|
x->curlft.packets = ltime->packets;
|
|
|
|
x->curlft.add_time = ltime->add_time;
|
|
|
|
x->curlft.use_time = ltime->use_time;
|
|
|
|
}
|
|
|
|
|
2007-08-23 04:59:04 +08:00
|
|
|
if (et)
|
2007-08-23 05:01:33 +08:00
|
|
|
x->replay_maxage = nla_get_u32(et);
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2007-08-23 04:59:04 +08:00
|
|
|
if (rt)
|
2007-08-23 05:01:33 +08:00
|
|
|
x->replay_maxdiff = nla_get_u32(rt);
|
2021-12-22 21:11:18 +08:00
|
|
|
|
|
|
|
if (mt)
|
|
|
|
x->mapping_maxage = nla_get_u32(mt);
|
2006-03-21 11:16:12 +08:00
|
|
|
}
|
|
|
|
|
2018-06-12 18:44:26 +08:00
|
|
|
static void xfrm_smark_init(struct nlattr **attrs, struct xfrm_mark *m)
|
|
|
|
{
|
|
|
|
if (attrs[XFRMA_SET_MARK]) {
|
|
|
|
m->v = nla_get_u32(attrs[XFRMA_SET_MARK]);
|
|
|
|
if (attrs[XFRMA_SET_MARK_MASK])
|
|
|
|
m->m = nla_get_u32(attrs[XFRMA_SET_MARK_MASK]);
|
|
|
|
else
|
|
|
|
m->m = 0xffffffff;
|
|
|
|
} else {
|
|
|
|
m->v = m->m = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
static struct xfrm_state *xfrm_state_construct(struct net *net,
|
|
|
|
struct xfrm_usersa_info *p,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs,
|
2005-04-17 06:20:36 +08:00
|
|
|
int *errp)
|
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct xfrm_state *x = xfrm_state_alloc(net);
|
2005-04-17 06:20:36 +08:00
|
|
|
int err = -ENOMEM;
|
|
|
|
|
|
|
|
if (!x)
|
|
|
|
goto error_no_put;
|
|
|
|
|
|
|
|
copy_from_user_state(x, p);
|
|
|
|
|
2021-06-07 21:21:49 +08:00
|
|
|
if (attrs[XFRMA_ENCAP]) {
|
|
|
|
x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]),
|
|
|
|
sizeof(*x->encap), GFP_KERNEL);
|
|
|
|
if (x->encap == NULL)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrs[XFRMA_COADDR]) {
|
|
|
|
x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]),
|
|
|
|
sizeof(*x->coaddr), GFP_KERNEL);
|
|
|
|
if (x->coaddr == NULL)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-02-22 17:54:54 +08:00
|
|
|
if (attrs[XFRMA_SA_EXTRA_FLAGS])
|
|
|
|
x->props.extra_flags = nla_get_u32(attrs[XFRMA_SA_EXTRA_FLAGS]);
|
|
|
|
|
2015-05-27 16:03:45 +08:00
|
|
|
if ((err = attach_aead(x, attrs[XFRMA_ALG_AEAD])))
|
2008-01-29 11:37:29 +08:00
|
|
|
goto error;
|
2009-11-25 08:29:52 +08:00
|
|
|
if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo,
|
|
|
|
attrs[XFRMA_ALG_AUTH_TRUNC])))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto error;
|
2009-11-25 08:29:52 +08:00
|
|
|
if (!x->props.aalgo) {
|
|
|
|
if ((err = attach_auth(&x->aalg, &x->props.aalgo,
|
|
|
|
attrs[XFRMA_ALG_AUTH])))
|
|
|
|
goto error;
|
|
|
|
}
|
2015-05-27 16:03:45 +08:00
|
|
|
if ((err = attach_crypt(x, attrs[XFRMA_ALG_CRYPT])))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto error;
|
|
|
|
if ((err = attach_one_algo(&x->calg, &x->props.calgo,
|
|
|
|
xfrm_calg_get_byname,
|
2007-08-23 05:00:40 +08:00
|
|
|
attrs[XFRMA_ALG_COMP])))
|
2005-04-17 06:20:36 +08:00
|
|
|
goto error;
|
2007-09-06 18:28:08 +08:00
|
|
|
|
2010-12-08 12:37:49 +08:00
|
|
|
if (attrs[XFRMA_TFCPAD])
|
|
|
|
x->tfcpad = nla_get_u32(attrs[XFRMA_TFCPAD]);
|
|
|
|
|
2010-02-22 19:32:59 +08:00
|
|
|
xfrm_mark_get(attrs, &x->mark);
|
|
|
|
|
2018-06-12 18:44:26 +08:00
|
|
|
xfrm_smark_init(attrs, &x->props.smark);
|
net: xfrm: support setting an output mark.
On systems that use mark-based routing it may be necessary for
routing lookups to use marks in order for packets to be routed
correctly. An example of such a system is Android, which uses
socket marks to route packets via different networks.
Currently, routing lookups in tunnel mode always use a mark of
zero, making routing incorrect on such systems.
This patch adds a new output_mark element to the xfrm state and
a corresponding XFRMA_OUTPUT_MARK netlink attribute. The output
mark differs from the existing xfrm mark in two ways:
1. The xfrm mark is used to match xfrm policies and states, while
the xfrm output mark is used to set the mark (and influence
the routing) of the packets emitted by those states.
2. The existing mark is constrained to be a subset of the bits of
the originating socket or transformed packet, but the output
mark is arbitrary and depends only on the state.
The use of a separate mark provides additional flexibility. For
example:
- A packet subject to two transforms (e.g., transport mode inside
tunnel mode) can have two different output marks applied to it,
one for the transport mode SA and one for the tunnel mode SA.
- On a system where socket marks determine routing, the packets
emitted by an IPsec tunnel can be routed based on a mark that
is determined by the tunnel, not by the marks of the
unencrypted packets.
- Support for setting the output marks can be introduced without
breaking any existing setups that employ both mark-based
routing and xfrm tunnel mode. Simply changing the code to use
the xfrm mark for routing output packets could xfrm mark could
change behaviour in a way that breaks these setups.
If the output mark is unspecified or set to zero, the mark is not
set or changed.
Tested: make allyesconfig; make -j64
Tested: https://android-review.googlesource.com/452776
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2017-08-11 01:11:33 +08:00
|
|
|
|
2022-03-03 22:55:10 +08:00
|
|
|
if (attrs[XFRMA_IF_ID])
|
2018-06-12 20:07:07 +08:00
|
|
|
x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
net: xfrm: support setting an output mark.
On systems that use mark-based routing it may be necessary for
routing lookups to use marks in order for packets to be routed
correctly. An example of such a system is Android, which uses
socket marks to route packets via different networks.
Currently, routing lookups in tunnel mode always use a mark of
zero, making routing incorrect on such systems.
This patch adds a new output_mark element to the xfrm state and
a corresponding XFRMA_OUTPUT_MARK netlink attribute. The output
mark differs from the existing xfrm mark in two ways:
1. The xfrm mark is used to match xfrm policies and states, while
the xfrm output mark is used to set the mark (and influence
the routing) of the packets emitted by those states.
2. The existing mark is constrained to be a subset of the bits of
the originating socket or transformed packet, but the output
mark is arbitrary and depends only on the state.
The use of a separate mark provides additional flexibility. For
example:
- A packet subject to two transforms (e.g., transport mode inside
tunnel mode) can have two different output marks applied to it,
one for the transport mode SA and one for the tunnel mode SA.
- On a system where socket marks determine routing, the packets
emitted by an IPsec tunnel can be routed based on a mark that
is determined by the tunnel, not by the marks of the
unencrypted packets.
- Support for setting the output marks can be introduced without
breaking any existing setups that employ both mark-based
routing and xfrm tunnel mode. Simply changing the code to use
the xfrm mark for routing output packets could xfrm mark could
change behaviour in a way that breaks these setups.
If the output mark is unspecified or set to zero, the mark is not
set or changed.
Tested: make allyesconfig; make -j64
Tested: https://android-review.googlesource.com/452776
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2017-08-11 01:11:33 +08:00
|
|
|
|
2017-08-01 17:49:08 +08:00
|
|
|
err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
|
2016-09-09 00:09:57 +08:00
|
|
|
if (attrs[XFRMA_SEC_CTX]) {
|
|
|
|
err = security_xfrm_state_alloc(x,
|
|
|
|
nla_data(attrs[XFRMA_SEC_CTX]));
|
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
}
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
if ((err = xfrm_alloc_replay_state_esn(&x->replay_esn, &x->preplay_esn,
|
|
|
|
attrs[XFRMA_REPLAY_ESN_VAL])))
|
|
|
|
goto error;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
x->km.seq = p->seq;
|
2008-11-26 10:00:48 +08:00
|
|
|
x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth;
|
2006-03-21 11:16:12 +08:00
|
|
|
/* sysctl_xfrm_aevent_etime is in 100ms units */
|
2008-11-26 10:00:48 +08:00
|
|
|
x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2011-03-08 08:08:32 +08:00
|
|
|
if ((err = xfrm_init_replay(x)))
|
|
|
|
goto error;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2011-03-08 08:08:32 +08:00
|
|
|
/* override default values from above */
|
2012-09-19 19:33:43 +08:00
|
|
|
xfrm_update_ae_params(x, attrs, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-01-17 21:52:41 +08:00
|
|
|
/* configure the hardware if offload is requested */
|
|
|
|
if (attrs[XFRMA_OFFLOAD_DEV]) {
|
|
|
|
err = xfrm_dev_state_add(net, x,
|
|
|
|
nla_data(attrs[XFRMA_OFFLOAD_DEV]));
|
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return x;
|
|
|
|
|
|
|
|
error:
|
|
|
|
x->km.state = XFRM_STATE_DEAD;
|
|
|
|
xfrm_state_put(x);
|
|
|
|
error_no_put:
|
|
|
|
*errp = err;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_usersa_info *p = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_state *x;
|
|
|
|
int err;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct km_event c;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = verify_newsa_info(p, attrs);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
x = xfrm_state_construct(net, p, attrs, &err);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!x)
|
|
|
|
return err;
|
|
|
|
|
2005-06-19 13:42:13 +08:00
|
|
|
xfrm_state_hold(x);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
|
|
|
|
err = xfrm_state_add(x);
|
|
|
|
else
|
|
|
|
err = xfrm_state_update(x);
|
|
|
|
|
2014-04-22 20:48:30 +08:00
|
|
|
xfrm_audit_state_add(x, err ? 0 : 1, true);
|
2006-11-28 03:11:54 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err < 0) {
|
|
|
|
x->km.state = XFRM_STATE_DEAD;
|
2017-09-04 16:28:02 +08:00
|
|
|
xfrm_dev_state_delete(x);
|
2006-02-23 06:47:13 +08:00
|
|
|
__xfrm_state_put(x);
|
2005-06-19 13:45:31 +08:00
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2018-01-17 21:52:41 +08:00
|
|
|
if (x->km.state == XFRM_STATE_VOID)
|
|
|
|
x->km.state = XFRM_STATE_VALID;
|
|
|
|
|
2005-06-19 13:42:13 +08:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2005-06-19 13:44:37 +08:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
|
|
|
km_state_notify(x, &c);
|
2005-06-19 13:45:31 +08:00
|
|
|
out:
|
2005-06-19 13:42:13 +08:00
|
|
|
xfrm_state_put(x);
|
2005-04-17 06:20:36 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
static struct xfrm_state *xfrm_user_state_lookup(struct net *net,
|
|
|
|
struct xfrm_usersa_id *p,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs,
|
2006-08-24 08:56:04 +08:00
|
|
|
int *errp)
|
|
|
|
{
|
|
|
|
struct xfrm_state *x = NULL;
|
2010-02-22 19:32:59 +08:00
|
|
|
struct xfrm_mark m;
|
2006-08-24 08:56:04 +08:00
|
|
|
int err;
|
2010-02-22 19:32:59 +08:00
|
|
|
u32 mark = xfrm_mark_get(attrs, &m);
|
2006-08-24 08:56:04 +08:00
|
|
|
|
|
|
|
if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
|
|
|
|
err = -ESRCH;
|
2010-02-22 19:32:59 +08:00
|
|
|
x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family);
|
2006-08-24 08:56:04 +08:00
|
|
|
} else {
|
|
|
|
xfrm_address_t *saddr = NULL;
|
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
verify_one_addr(attrs, XFRMA_SRCADDR, &saddr);
|
2006-08-24 08:56:04 +08:00
|
|
|
if (!saddr) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2006-11-25 12:34:51 +08:00
|
|
|
err = -ESRCH;
|
2010-02-22 19:32:59 +08:00
|
|
|
x = xfrm_state_lookup_byaddr(net, mark,
|
|
|
|
&p->daddr, saddr,
|
2008-11-26 09:30:50 +08:00
|
|
|
p->proto, p->family);
|
2006-08-24 08:56:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (!x && errp)
|
|
|
|
*errp = err;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_state *x;
|
2006-08-24 08:56:04 +08:00
|
|
|
int err = -ESRCH;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct km_event c;
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_usersa_id *p = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
x = xfrm_user_state_lookup(net, p, attrs, &err);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (x == NULL)
|
2006-08-24 08:56:04 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-09 14:58:52 +08:00
|
|
|
if ((err = security_xfrm_state_delete(x)) != 0)
|
2006-06-09 14:39:49 +08:00
|
|
|
goto out;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (xfrm_state_kern(x)) {
|
2006-06-09 14:39:49 +08:00
|
|
|
err = -EPERM;
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-06-19 13:42:13 +08:00
|
|
|
err = xfrm_state_delete(x);
|
2006-11-28 03:11:54 +08:00
|
|
|
|
2006-06-09 14:39:49 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto out;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2005-06-19 13:44:37 +08:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-19 13:42:13 +08:00
|
|
|
km_state_notify(x, &c);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-06-09 14:39:49 +08:00
|
|
|
out:
|
2014-04-22 20:48:30 +08:00
|
|
|
xfrm_audit_state_delete(x, err ? 0 : 1, true);
|
2006-06-09 14:39:49 +08:00
|
|
|
xfrm_state_put(x);
|
2005-06-19 13:42:13 +08:00
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
|
|
|
|
{
|
2012-09-19 19:33:39 +08:00
|
|
|
memset(p, 0, sizeof(*p));
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(&p->id, &x->id, sizeof(p->id));
|
|
|
|
memcpy(&p->sel, &x->sel, sizeof(p->sel));
|
|
|
|
memcpy(&p->lft, &x->lft, sizeof(p->lft));
|
|
|
|
memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
|
2015-10-21 23:48:25 +08:00
|
|
|
put_unaligned(x->stats.replay_window, &p->stats.replay_window);
|
|
|
|
put_unaligned(x->stats.replay, &p->stats.replay);
|
|
|
|
put_unaligned(x->stats.integrity_failed, &p->stats.integrity_failed);
|
2006-10-28 06:29:47 +08:00
|
|
|
memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr));
|
2005-04-17 06:20:36 +08:00
|
|
|
p->mode = x->props.mode;
|
|
|
|
p->replay_window = x->props.replay_window;
|
|
|
|
p->reqid = x->props.reqid;
|
|
|
|
p->family = x->props.family;
|
|
|
|
p->flags = x->props.flags;
|
|
|
|
p->seq = x->km.seq;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xfrm_dump_info {
|
|
|
|
struct sk_buff *in_skb;
|
|
|
|
struct sk_buff *out_skb;
|
|
|
|
u32 nlmsg_seq;
|
|
|
|
u16 nlmsg_flags;
|
|
|
|
};
|
|
|
|
|
2007-08-23 04:55:43 +08:00
|
|
|
static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct xfrm_user_sec_ctx *uctx;
|
|
|
|
struct nlattr *attr;
|
2007-10-10 04:30:57 +08:00
|
|
|
int ctx_size = sizeof(*uctx) + s->ctx_len;
|
2007-08-23 04:55:43 +08:00
|
|
|
|
|
|
|
attr = nla_reserve(skb, XFRMA_SEC_CTX, ctx_size);
|
|
|
|
if (attr == NULL)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
uctx = nla_data(attr);
|
|
|
|
uctx->exttype = XFRMA_SEC_CTX;
|
|
|
|
uctx->len = ctx_size;
|
|
|
|
uctx->ctx_doi = s->ctx_doi;
|
|
|
|
uctx->ctx_alg = s->ctx_alg;
|
|
|
|
uctx->ctx_len = s->ctx_len;
|
|
|
|
memcpy(uctx + 1, s->ctx_str, s->ctx_len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-14 16:06:10 +08:00
|
|
|
static int copy_user_offload(struct xfrm_state_offload *xso, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct xfrm_user_offload *xuo;
|
|
|
|
struct nlattr *attr;
|
|
|
|
|
|
|
|
attr = nla_reserve(skb, XFRMA_OFFLOAD_DEV, sizeof(*xuo));
|
|
|
|
if (attr == NULL)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
xuo = nla_data(attr);
|
2017-08-26 23:08:57 +08:00
|
|
|
memset(xuo, 0, sizeof(*xuo));
|
2017-04-14 16:06:10 +08:00
|
|
|
xuo->ifindex = xso->dev->ifindex;
|
|
|
|
xuo->flags = xso->flags;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-11-18 00:47:23 +08:00
|
|
|
static bool xfrm_redact(void)
|
|
|
|
{
|
|
|
|
return IS_ENABLED(CONFIG_SECURITY) &&
|
|
|
|
security_locked_down(LOCKDOWN_XFRM_SECRET);
|
|
|
|
}
|
|
|
|
|
2009-11-25 08:29:52 +08:00
|
|
|
static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct xfrm_algo *algo;
|
2020-11-18 00:47:23 +08:00
|
|
|
struct xfrm_algo_auth *ap;
|
2009-11-25 08:29:52 +08:00
|
|
|
struct nlattr *nla;
|
2020-11-18 00:47:23 +08:00
|
|
|
bool redact_secret = xfrm_redact();
|
2009-11-25 08:29:52 +08:00
|
|
|
|
|
|
|
nla = nla_reserve(skb, XFRMA_ALG_AUTH,
|
|
|
|
sizeof(*algo) + (auth->alg_key_len + 7) / 8);
|
|
|
|
if (!nla)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
algo = nla_data(nla);
|
2012-09-19 19:33:38 +08:00
|
|
|
strncpy(algo->alg_name, auth->alg_name, sizeof(algo->alg_name));
|
2020-11-18 00:47:23 +08:00
|
|
|
|
|
|
|
if (redact_secret && auth->alg_key_len)
|
|
|
|
memset(algo->alg_key, 0, (auth->alg_key_len + 7) / 8);
|
|
|
|
else
|
|
|
|
memcpy(algo->alg_key, auth->alg_key,
|
|
|
|
(auth->alg_key_len + 7) / 8);
|
2009-11-25 08:29:52 +08:00
|
|
|
algo->alg_key_len = auth->alg_key_len;
|
|
|
|
|
2020-11-18 00:47:23 +08:00
|
|
|
nla = nla_reserve(skb, XFRMA_ALG_AUTH_TRUNC, xfrm_alg_auth_len(auth));
|
|
|
|
if (!nla)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
ap = nla_data(nla);
|
|
|
|
memcpy(ap, auth, sizeof(struct xfrm_algo_auth));
|
|
|
|
if (redact_secret && auth->alg_key_len)
|
|
|
|
memset(ap->alg_key, 0, (auth->alg_key_len + 7) / 8);
|
|
|
|
else
|
|
|
|
memcpy(ap->alg_key, auth->alg_key,
|
|
|
|
(auth->alg_key_len + 7) / 8);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int copy_to_user_aead(struct xfrm_algo_aead *aead, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct nlattr *nla = nla_reserve(skb, XFRMA_ALG_AEAD, aead_len(aead));
|
|
|
|
struct xfrm_algo_aead *ap;
|
|
|
|
bool redact_secret = xfrm_redact();
|
|
|
|
|
|
|
|
if (!nla)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
ap = nla_data(nla);
|
|
|
|
memcpy(ap, aead, sizeof(*aead));
|
|
|
|
|
|
|
|
if (redact_secret && aead->alg_key_len)
|
|
|
|
memset(ap->alg_key, 0, (aead->alg_key_len + 7) / 8);
|
|
|
|
else
|
|
|
|
memcpy(ap->alg_key, aead->alg_key,
|
|
|
|
(aead->alg_key_len + 7) / 8);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int copy_to_user_ealg(struct xfrm_algo *ealg, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct xfrm_algo *ap;
|
|
|
|
bool redact_secret = xfrm_redact();
|
|
|
|
struct nlattr *nla = nla_reserve(skb, XFRMA_ALG_CRYPT,
|
|
|
|
xfrm_alg_len(ealg));
|
|
|
|
if (!nla)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
ap = nla_data(nla);
|
|
|
|
memcpy(ap, ealg, sizeof(*ealg));
|
|
|
|
|
|
|
|
if (redact_secret && ealg->alg_key_len)
|
|
|
|
memset(ap->alg_key, 0, (ealg->alg_key_len + 7) / 8);
|
|
|
|
else
|
|
|
|
memcpy(ap->alg_key, ealg->alg_key,
|
|
|
|
(ealg->alg_key_len + 7) / 8);
|
|
|
|
|
2009-11-25 08:29:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-12 18:44:26 +08:00
|
|
|
static int xfrm_smark_put(struct sk_buff *skb, struct xfrm_mark *m)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (m->v | m->m) {
|
|
|
|
ret = nla_put_u32(skb, XFRMA_SET_MARK, m->v);
|
|
|
|
if (!ret)
|
|
|
|
ret = nla_put_u32(skb, XFRMA_SET_MARK_MASK, m->m);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-10-10 04:30:57 +08:00
|
|
|
/* Don't change this without updating xfrm_sa_len! */
|
|
|
|
static int copy_to_user_state_extra(struct xfrm_state *x,
|
|
|
|
struct xfrm_usersa_info *p,
|
|
|
|
struct sk_buff *skb)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-06-28 12:57:03 +08:00
|
|
|
int ret = 0;
|
2012-03-29 16:02:26 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
copy_to_user_state(x, p);
|
2007-10-10 04:30:57 +08:00
|
|
|
|
2013-02-22 17:54:54 +08:00
|
|
|
if (x->props.extra_flags) {
|
|
|
|
ret = nla_put_u32(skb, XFRMA_SA_EXTRA_FLAGS,
|
|
|
|
x->props.extra_flags);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
if (x->coaddr) {
|
|
|
|
ret = nla_put(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->lastused) {
|
2016-04-22 23:31:23 +08:00
|
|
|
ret = nla_put_u64_64bit(skb, XFRMA_LASTUSED, x->lastused,
|
|
|
|
XFRMA_PAD);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->aead) {
|
2020-11-18 00:47:23 +08:00
|
|
|
ret = copy_to_user_aead(x->aead, skb);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->aalg) {
|
|
|
|
ret = copy_to_user_auth(x->aalg, skb);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->ealg) {
|
2020-11-18 00:47:23 +08:00
|
|
|
ret = copy_to_user_ealg(x->ealg, skb);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->calg) {
|
|
|
|
ret = nla_put(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->encap) {
|
|
|
|
ret = nla_put(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->tfcpad) {
|
|
|
|
ret = nla_put_u32(skb, XFRMA_TFCPAD, x->tfcpad);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
ret = xfrm_mark_put(skb, &x->mark);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2018-06-12 18:44:26 +08:00
|
|
|
|
|
|
|
ret = xfrm_smark_put(skb, &x->props.smark);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
|
2014-10-30 16:39:36 +08:00
|
|
|
if (x->replay_esn)
|
2012-06-28 12:57:03 +08:00
|
|
|
ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
|
|
|
|
xfrm_replay_state_esn_len(x->replay_esn),
|
|
|
|
x->replay_esn);
|
2014-10-30 16:39:36 +08:00
|
|
|
else
|
|
|
|
ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
|
|
|
|
&x->replay);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2017-04-14 16:06:10 +08:00
|
|
|
if(x->xso.dev)
|
|
|
|
ret = copy_user_offload(&x->xso, skb);
|
|
|
|
if (ret)
|
|
|
|
goto out;
|
2018-06-12 20:07:07 +08:00
|
|
|
if (x->if_id) {
|
|
|
|
ret = nla_put_u32(skb, XFRMA_IF_ID, x->if_id);
|
net: xfrm: support setting an output mark.
On systems that use mark-based routing it may be necessary for
routing lookups to use marks in order for packets to be routed
correctly. An example of such a system is Android, which uses
socket marks to route packets via different networks.
Currently, routing lookups in tunnel mode always use a mark of
zero, making routing incorrect on such systems.
This patch adds a new output_mark element to the xfrm state and
a corresponding XFRMA_OUTPUT_MARK netlink attribute. The output
mark differs from the existing xfrm mark in two ways:
1. The xfrm mark is used to match xfrm policies and states, while
the xfrm output mark is used to set the mark (and influence
the routing) of the packets emitted by those states.
2. The existing mark is constrained to be a subset of the bits of
the originating socket or transformed packet, but the output
mark is arbitrary and depends only on the state.
The use of a separate mark provides additional flexibility. For
example:
- A packet subject to two transforms (e.g., transport mode inside
tunnel mode) can have two different output marks applied to it,
one for the transport mode SA and one for the tunnel mode SA.
- On a system where socket marks determine routing, the packets
emitted by an IPsec tunnel can be routed based on a mark that
is determined by the tunnel, not by the marks of the
unencrypted packets.
- Support for setting the output marks can be introduced without
breaking any existing setups that employ both mark-based
routing and xfrm tunnel mode. Simply changing the code to use
the xfrm mark for routing output packets could xfrm mark could
change behaviour in a way that breaks these setups.
If the output mark is unspecified or set to zero, the mark is not
set or changed.
Tested: make allyesconfig; make -j64
Tested: https://android-review.googlesource.com/452776
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2017-08-11 01:11:33 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
2021-12-22 21:11:18 +08:00
|
|
|
if (x->security) {
|
2017-08-31 16:37:00 +08:00
|
|
|
ret = copy_sec_ctx(x->security, skb);
|
2021-12-22 21:11:18 +08:00
|
|
|
if (ret)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (x->mapping_maxage)
|
|
|
|
ret = nla_put_u32(skb, XFRMA_MTIMER_THRESH, x->mapping_maxage);
|
2012-06-28 12:57:03 +08:00
|
|
|
out:
|
|
|
|
return ret;
|
2007-10-10 04:30:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
|
|
|
|
{
|
|
|
|
struct xfrm_dump_info *sp = ptr;
|
|
|
|
struct sk_buff *in_skb = sp->in_skb;
|
|
|
|
struct sk_buff *skb = sp->out_skb;
|
2020-09-21 22:36:53 +08:00
|
|
|
struct xfrm_translator *xtr;
|
2007-10-10 04:30:57 +08:00
|
|
|
struct xfrm_usersa_info *p;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
int err;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq,
|
2007-10-10 04:30:57 +08:00
|
|
|
XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
|
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
p = nlmsg_data(nlh);
|
|
|
|
|
|
|
|
err = copy_to_user_state_extra(x, p, skb);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
2020-09-21 22:36:53 +08:00
|
|
|
|
|
|
|
xtr = xfrm_get_translator();
|
|
|
|
if (xtr) {
|
|
|
|
err = xtr->alloc_compat(skb, nlh);
|
|
|
|
|
|
|
|
xfrm_put_translator(xtr);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-29 13:31:08 +08:00
|
|
|
static int xfrm_dump_sa_done(struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
|
2013-11-07 17:47:50 +08:00
|
|
|
struct sock *sk = cb->skb->sk;
|
|
|
|
struct net *net = sock_net(sk);
|
|
|
|
|
2016-07-05 16:18:08 +08:00
|
|
|
if (cb->args[0])
|
|
|
|
xfrm_state_walk_done(walk, net);
|
2008-02-29 13:31:08 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2008-02-29 13:31:08 +08:00
|
|
|
struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_dump_info info;
|
|
|
|
|
2008-02-29 13:31:08 +08:00
|
|
|
BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
|
|
|
|
sizeof(cb->args) - sizeof(cb->args[0]));
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
info.in_skb = cb->skb;
|
|
|
|
info.out_skb = skb;
|
|
|
|
info.nlmsg_seq = cb->nlh->nlmsg_seq;
|
|
|
|
info.nlmsg_flags = NLM_F_MULTI;
|
2008-02-29 13:31:08 +08:00
|
|
|
|
|
|
|
if (!cb->args[0]) {
|
2014-02-14 22:30:36 +08:00
|
|
|
struct nlattr *attrs[XFRMA_MAX+1];
|
2014-03-07 01:24:29 +08:00
|
|
|
struct xfrm_address_filter *filter = NULL;
|
2014-02-14 22:30:36 +08:00
|
|
|
u8 proto = 0;
|
|
|
|
int err;
|
|
|
|
|
netlink: make validation more configurable for future strictness
We currently have two levels of strict validation:
1) liberal (default)
- undefined (type >= max) & NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
- garbage at end of message accepted
2) strict (opt-in)
- NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
Split out parsing strictness into four different options:
* TRAILING - check that there's no trailing data after parsing
attributes (in message or nested)
* MAXTYPE - reject attrs > max known type
* UNSPEC - reject attributes with NLA_UNSPEC policy entries
* STRICT_ATTRS - strictly validate attribute size
The default for future things should be *everything*.
The current *_strict() is a combination of TRAILING and MAXTYPE,
and is renamed to _deprecated_strict().
The current regular parsing has none of this, and is renamed to
*_parse_deprecated().
Additionally it allows us to selectively set one of the new flags
even on old policies. Notably, the UNSPEC flag could be useful in
this case, since it can be arranged (by filling in the policy) to
not be an incompatible userspace ABI change, but would then going
forward prevent forgetting attribute entries. Similar can apply
to the POLICY flag.
We end up with the following renames:
* nla_parse -> nla_parse_deprecated
* nla_parse_strict -> nla_parse_deprecated_strict
* nlmsg_parse -> nlmsg_parse_deprecated
* nlmsg_parse_strict -> nlmsg_parse_deprecated_strict
* nla_parse_nested -> nla_parse_nested_deprecated
* nla_validate_nested -> nla_validate_nested_deprecated
Using spatch, of course:
@@
expression TB, MAX, HEAD, LEN, POL, EXT;
@@
-nla_parse(TB, MAX, HEAD, LEN, POL, EXT)
+nla_parse_deprecated(TB, MAX, HEAD, LEN, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression TB, MAX, NLA, POL, EXT;
@@
-nla_parse_nested(TB, MAX, NLA, POL, EXT)
+nla_parse_nested_deprecated(TB, MAX, NLA, POL, EXT)
@@
expression START, MAX, POL, EXT;
@@
-nla_validate_nested(START, MAX, POL, EXT)
+nla_validate_nested_deprecated(START, MAX, POL, EXT)
@@
expression NLH, HDRLEN, MAX, POL, EXT;
@@
-nlmsg_validate(NLH, HDRLEN, MAX, POL, EXT)
+nlmsg_validate_deprecated(NLH, HDRLEN, MAX, POL, EXT)
For this patch, don't actually add the strict, non-renamed versions
yet so that it breaks compile if I get it wrong.
Also, while at it, make nla_validate and nla_parse go down to a
common __nla_validate_parse() function to avoid code duplication.
Ultimately, this allows us to have very strict validation for every
new caller of nla_parse()/nlmsg_parse() etc as re-introduced in the
next patch, while existing things will continue to work as is.
In effect then, this adds fully strict validation for any new command.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-04-26 20:07:28 +08:00
|
|
|
err = nlmsg_parse_deprecated(cb->nlh, 0, attrs, XFRMA_MAX,
|
|
|
|
xfrma_policy, cb->extack);
|
2014-02-14 22:30:36 +08:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
2014-03-07 01:24:29 +08:00
|
|
|
if (attrs[XFRMA_ADDRESS_FILTER]) {
|
2015-08-07 15:59:34 +08:00
|
|
|
filter = kmemdup(nla_data(attrs[XFRMA_ADDRESS_FILTER]),
|
|
|
|
sizeof(*filter), GFP_KERNEL);
|
2014-02-14 22:30:36 +08:00
|
|
|
if (filter == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrs[XFRMA_PROTO])
|
|
|
|
proto = nla_get_u8(attrs[XFRMA_PROTO]);
|
|
|
|
|
|
|
|
xfrm_state_walk_init(walk, proto, filter);
|
2016-07-05 16:18:08 +08:00
|
|
|
cb->args[0] = 1;
|
2008-02-29 13:31:08 +08:00
|
|
|
}
|
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
(void) xfrm_state_walk(net, walk, dump_one_state, &info);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return skb->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
|
|
|
|
struct xfrm_state *x, u32 seq)
|
|
|
|
{
|
|
|
|
struct xfrm_dump_info info;
|
|
|
|
struct sk_buff *skb;
|
2012-09-13 19:41:26 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!skb)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
info.in_skb = in_skb;
|
|
|
|
info.out_skb = skb;
|
|
|
|
info.nlmsg_seq = seq;
|
|
|
|
info.nlmsg_flags = 0;
|
|
|
|
|
2012-09-13 19:41:26 +08:00
|
|
|
err = dump_one_state(x, 0, &info);
|
|
|
|
if (err) {
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree_skb(skb);
|
2012-09-13 19:41:26 +08:00
|
|
|
return ERR_PTR(err);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
/* A wrapper for nlmsg_multicast() checking that nlsk is still available.
|
|
|
|
* Must be called with RCU read lock.
|
|
|
|
*/
|
|
|
|
static inline int xfrm_nlmsg_multicast(struct net *net, struct sk_buff *skb,
|
|
|
|
u32 pid, unsigned int group)
|
|
|
|
{
|
|
|
|
struct sock *nlsk = rcu_dereference(net->xfrm.nlsk);
|
2020-09-21 22:36:52 +08:00
|
|
|
struct xfrm_translator *xtr;
|
2014-06-03 16:26:06 +08:00
|
|
|
|
2018-06-25 20:00:07 +08:00
|
|
|
if (!nlsk) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -EPIPE;
|
|
|
|
}
|
|
|
|
|
2020-09-21 22:36:52 +08:00
|
|
|
xtr = xfrm_get_translator();
|
|
|
|
if (xtr) {
|
|
|
|
int err = xtr->alloc_compat(skb, nlmsg_hdr(skb));
|
|
|
|
|
|
|
|
xfrm_put_translator(xtr);
|
|
|
|
if (err) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-25 20:00:07 +08:00
|
|
|
return nlmsg_multicast(nlsk, skb, pid, group, GFP_ATOMIC);
|
2014-06-03 16:26:06 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_spdinfo_msgsize(void)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(4)
|
|
|
|
+ nla_total_size(sizeof(struct xfrmu_spdinfo))
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
+ nla_total_size(sizeof(struct xfrmu_spdhinfo))
|
|
|
|
+ nla_total_size(sizeof(struct xfrmu_spdhthresh))
|
|
|
|
+ nla_total_size(sizeof(struct xfrmu_spdhthresh));
|
2007-08-23 04:57:39 +08:00
|
|
|
}
|
|
|
|
|
2010-01-23 21:37:10 +08:00
|
|
|
static int build_spdinfo(struct sk_buff *skb, struct net *net,
|
2012-09-08 04:12:54 +08:00
|
|
|
u32 portid, u32 seq, u32 flags)
|
2007-04-29 12:20:32 +08:00
|
|
|
{
|
2007-05-05 03:55:39 +08:00
|
|
|
struct xfrmk_spdinfo si;
|
|
|
|
struct xfrmu_spdinfo spc;
|
|
|
|
struct xfrmu_spdhinfo sph;
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
struct xfrmu_spdhthresh spt4, spt6;
|
2007-04-29 12:20:32 +08:00
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2007-04-29 12:20:32 +08:00
|
|
|
u32 *f;
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
unsigned lseq;
|
2007-04-29 12:20:32 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
|
2011-03-31 09:57:33 +08:00
|
|
|
if (nlh == NULL) /* shouldn't really happen ... */
|
2007-04-29 12:20:32 +08:00
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
f = nlmsg_data(nlh);
|
|
|
|
*f = flags;
|
2010-01-23 21:37:10 +08:00
|
|
|
xfrm_spd_getinfo(net, &si);
|
2007-05-05 03:55:39 +08:00
|
|
|
spc.incnt = si.incnt;
|
|
|
|
spc.outcnt = si.outcnt;
|
|
|
|
spc.fwdcnt = si.fwdcnt;
|
|
|
|
spc.inscnt = si.inscnt;
|
|
|
|
spc.outscnt = si.outscnt;
|
|
|
|
spc.fwdscnt = si.fwdscnt;
|
|
|
|
sph.spdhcnt = si.spdhcnt;
|
|
|
|
sph.spdhmcnt = si.spdhmcnt;
|
|
|
|
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
do {
|
|
|
|
lseq = read_seqbegin(&net->xfrm.policy_hthresh.lock);
|
|
|
|
|
|
|
|
spt4.lbits = net->xfrm.policy_hthresh.lbits4;
|
|
|
|
spt4.rbits = net->xfrm.policy_hthresh.rbits4;
|
|
|
|
spt6.lbits = net->xfrm.policy_hthresh.lbits6;
|
|
|
|
spt6.rbits = net->xfrm.policy_hthresh.rbits6;
|
|
|
|
} while (read_seqretry(&net->xfrm.policy_hthresh.lock, lseq));
|
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
err = nla_put(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
|
|
|
|
if (!err)
|
|
|
|
err = nla_put(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
if (!err)
|
|
|
|
err = nla_put(skb, XFRMA_SPD_IPV4_HTHRESH, sizeof(spt4), &spt4);
|
|
|
|
if (!err)
|
|
|
|
err = nla_put(skb, XFRMA_SPD_IPV6_HTHRESH, sizeof(spt6), &spt6);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
2007-04-29 12:20:32 +08:00
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2007-04-29 12:20:32 +08:00
|
|
|
}
|
|
|
|
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
static int xfrm_set_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
|
struct xfrmu_spdhthresh *thresh4 = NULL;
|
|
|
|
struct xfrmu_spdhthresh *thresh6 = NULL;
|
|
|
|
|
|
|
|
/* selector prefixlen thresholds to hash policies */
|
|
|
|
if (attrs[XFRMA_SPD_IPV4_HTHRESH]) {
|
|
|
|
struct nlattr *rta = attrs[XFRMA_SPD_IPV4_HTHRESH];
|
|
|
|
|
|
|
|
if (nla_len(rta) < sizeof(*thresh4))
|
|
|
|
return -EINVAL;
|
|
|
|
thresh4 = nla_data(rta);
|
|
|
|
if (thresh4->lbits > 32 || thresh4->rbits > 32)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
if (attrs[XFRMA_SPD_IPV6_HTHRESH]) {
|
|
|
|
struct nlattr *rta = attrs[XFRMA_SPD_IPV6_HTHRESH];
|
|
|
|
|
|
|
|
if (nla_len(rta) < sizeof(*thresh6))
|
|
|
|
return -EINVAL;
|
|
|
|
thresh6 = nla_data(rta);
|
|
|
|
if (thresh6->lbits > 128 || thresh6->rbits > 128)
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thresh4 || thresh6) {
|
|
|
|
write_seqlock(&net->xfrm.policy_hthresh.lock);
|
|
|
|
if (thresh4) {
|
|
|
|
net->xfrm.policy_hthresh.lbits4 = thresh4->lbits;
|
|
|
|
net->xfrm.policy_hthresh.rbits4 = thresh4->rbits;
|
|
|
|
}
|
|
|
|
if (thresh6) {
|
|
|
|
net->xfrm.policy_hthresh.lbits6 = thresh6->lbits;
|
|
|
|
net->xfrm.policy_hthresh.rbits6 = thresh6->rbits;
|
|
|
|
}
|
|
|
|
write_sequnlock(&net->xfrm.policy_hthresh.lock);
|
|
|
|
|
|
|
|
xfrm_policy_hash_rebuild(net);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-04-29 12:20:32 +08:00
|
|
|
static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2007-04-29 12:20:32 +08:00
|
|
|
{
|
2008-11-26 09:38:20 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-04-29 12:20:32 +08:00
|
|
|
struct sk_buff *r_skb;
|
2007-08-23 04:53:52 +08:00
|
|
|
u32 *flags = nlmsg_data(nlh);
|
2012-09-08 04:12:54 +08:00
|
|
|
u32 sportid = NETLINK_CB(skb).portid;
|
2007-04-29 12:20:32 +08:00
|
|
|
u32 seq = nlh->nlmsg_seq;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2007-04-29 12:20:32 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC);
|
2007-04-29 12:20:32 +08:00
|
|
|
if (r_skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_spdinfo(r_skb, net, sportid, seq, *flags);
|
|
|
|
BUG_ON(err < 0);
|
2007-04-29 12:20:32 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid);
|
2007-04-29 12:20:32 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_sadinfo_msgsize(void)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(4)
|
|
|
|
+ nla_total_size(sizeof(struct xfrmu_sadhinfo))
|
|
|
|
+ nla_total_size(4); /* XFRMA_SAD_CNT */
|
|
|
|
}
|
|
|
|
|
2010-01-23 21:37:10 +08:00
|
|
|
static int build_sadinfo(struct sk_buff *skb, struct net *net,
|
2012-09-08 04:12:54 +08:00
|
|
|
u32 portid, u32 seq, u32 flags)
|
2007-04-26 15:10:29 +08:00
|
|
|
{
|
2007-05-05 03:55:13 +08:00
|
|
|
struct xfrmk_sadinfo si;
|
|
|
|
struct xfrmu_sadhinfo sh;
|
2007-04-26 15:10:29 +08:00
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2007-04-26 15:10:29 +08:00
|
|
|
u32 *f;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, portid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);
|
2011-03-31 09:57:33 +08:00
|
|
|
if (nlh == NULL) /* shouldn't really happen ... */
|
2007-04-26 15:10:29 +08:00
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
f = nlmsg_data(nlh);
|
|
|
|
*f = flags;
|
2010-01-23 21:37:10 +08:00
|
|
|
xfrm_sad_getinfo(net, &si);
|
2007-04-26 15:10:29 +08:00
|
|
|
|
2007-05-05 03:55:13 +08:00
|
|
|
sh.sadhmcnt = si.sadhmcnt;
|
|
|
|
sh.sadhcnt = si.sadhcnt;
|
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
err = nla_put_u32(skb, XFRMA_SAD_CNT, si.sadcnt);
|
|
|
|
if (!err)
|
|
|
|
err = nla_put(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
2007-04-26 15:10:29 +08:00
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2007-04-26 15:10:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2007-04-26 15:10:29 +08:00
|
|
|
{
|
2008-11-26 09:38:20 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-04-26 15:10:29 +08:00
|
|
|
struct sk_buff *r_skb;
|
2007-08-23 04:53:52 +08:00
|
|
|
u32 *flags = nlmsg_data(nlh);
|
2012-09-08 04:12:54 +08:00
|
|
|
u32 sportid = NETLINK_CB(skb).portid;
|
2007-04-26 15:10:29 +08:00
|
|
|
u32 seq = nlh->nlmsg_seq;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2007-04-26 15:10:29 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC);
|
2007-04-26 15:10:29 +08:00
|
|
|
if (r_skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_sadinfo(r_skb, net, sportid, seq, *flags);
|
|
|
|
BUG_ON(err < 0);
|
2007-04-26 15:10:29 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid);
|
2007-04-26 15:10:29 +08:00
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_usersa_id *p = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_state *x;
|
|
|
|
struct sk_buff *resp_skb;
|
2006-08-24 08:56:04 +08:00
|
|
|
int err = -ESRCH;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
x = xfrm_user_state_lookup(net, p, attrs, &err);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (x == NULL)
|
|
|
|
goto out_noput;
|
|
|
|
|
|
|
|
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
|
|
|
|
if (IS_ERR(resp_skb)) {
|
|
|
|
err = PTR_ERR(resp_skb);
|
|
|
|
} else {
|
2012-09-08 04:12:54 +08:00
|
|
|
err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
xfrm_state_put(x);
|
|
|
|
out_noput:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_state *x;
|
|
|
|
struct xfrm_userspi_info *p;
|
2020-09-21 22:36:53 +08:00
|
|
|
struct xfrm_translator *xtr;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct sk_buff *resp_skb;
|
|
|
|
xfrm_address_t *daddr;
|
|
|
|
int family;
|
|
|
|
int err;
|
2010-02-22 19:32:59 +08:00
|
|
|
u32 mark;
|
|
|
|
struct xfrm_mark m;
|
2018-06-12 20:07:07 +08:00
|
|
|
u32 if_id = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
p = nlmsg_data(nlh);
|
2013-12-16 18:47:49 +08:00
|
|
|
err = verify_spi_info(p->info.id.proto, p->min, p->max);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err)
|
|
|
|
goto out_noput;
|
|
|
|
|
|
|
|
family = p->info.family;
|
|
|
|
daddr = &p->info.id.daddr;
|
|
|
|
|
|
|
|
x = NULL;
|
2010-02-22 19:32:59 +08:00
|
|
|
|
|
|
|
mark = xfrm_mark_get(attrs, &m);
|
2018-06-12 20:07:07 +08:00
|
|
|
|
2022-03-03 22:55:10 +08:00
|
|
|
if (attrs[XFRMA_IF_ID])
|
2018-06-12 20:07:07 +08:00
|
|
|
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (p->info.seq) {
|
2010-02-22 19:32:59 +08:00
|
|
|
x = xfrm_find_acq_byseq(net, mark, p->info.seq);
|
2013-01-29 20:48:50 +08:00
|
|
|
if (x && !xfrm_addr_equal(&x->id.daddr, daddr, family)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
xfrm_state_put(x);
|
|
|
|
x = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!x)
|
2010-02-22 19:32:59 +08:00
|
|
|
x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid,
|
2018-06-12 20:07:07 +08:00
|
|
|
if_id, p->info.id.proto, daddr,
|
2005-04-17 06:20:36 +08:00
|
|
|
&p->info.saddr, 1,
|
|
|
|
family);
|
|
|
|
err = -ENOENT;
|
|
|
|
if (x == NULL)
|
|
|
|
goto out_noput;
|
|
|
|
|
2007-10-10 04:29:52 +08:00
|
|
|
err = xfrm_alloc_spi(x, p->min, p->max);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-10-10 04:29:52 +08:00
|
|
|
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (IS_ERR(resp_skb)) {
|
|
|
|
err = PTR_ERR(resp_skb);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-09-21 22:36:53 +08:00
|
|
|
xtr = xfrm_get_translator();
|
|
|
|
if (xtr) {
|
|
|
|
err = xtr->alloc_compat(skb, nlmsg_hdr(skb));
|
|
|
|
|
|
|
|
xfrm_put_translator(xtr);
|
|
|
|
if (err) {
|
|
|
|
kfree_skb(resp_skb);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
xfrm_state_put(x);
|
|
|
|
out_noput:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-11-28 04:59:30 +08:00
|
|
|
static int verify_policy_dir(u8 dir)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
switch (dir) {
|
|
|
|
case XFRM_POLICY_IN:
|
|
|
|
case XFRM_POLICY_OUT:
|
|
|
|
case XFRM_POLICY_FWD:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-28 04:59:30 +08:00
|
|
|
static int verify_policy_type(u8 type)
|
2006-08-24 13:49:28 +08:00
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case XFRM_POLICY_TYPE_MAIN:
|
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
case XFRM_POLICY_TYPE_SUB:
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2006-08-24 13:49:28 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
|
|
|
|
{
|
2013-11-07 17:47:48 +08:00
|
|
|
int ret;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (p->share) {
|
|
|
|
case XFRM_SHARE_ANY:
|
|
|
|
case XFRM_SHARE_SESSION:
|
|
|
|
case XFRM_SHARE_USER:
|
|
|
|
case XFRM_SHARE_UNIQUE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
switch (p->action) {
|
|
|
|
case XFRM_POLICY_ALLOW:
|
|
|
|
case XFRM_POLICY_BLOCK:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
switch (p->sel.family) {
|
|
|
|
case AF_INET:
|
2018-08-01 19:45:11 +08:00
|
|
|
if (p->sel.prefixlen_d > 32 || p->sel.prefixlen_s > 32)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
2011-12-10 17:48:31 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
2018-08-01 19:45:11 +08:00
|
|
|
if (p->sel.prefixlen_d > 128 || p->sel.prefixlen_s > 128)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
break;
|
|
|
|
#else
|
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2013-11-07 17:47:48 +08:00
|
|
|
ret = verify_policy_dir(p->dir);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
xfrm: policy: Fix out-of-bound array accesses in __xfrm_policy_unlink
UBSAN report this:
UBSAN: Undefined behaviour in net/xfrm/xfrm_policy.c:1289:24
index 6 is out of range for type 'unsigned int [6]'
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.4.162-514.55.6.9.x86_64+ #13
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
0000000000000000 1466cf39b41b23c9 ffff8801f6b07a58 ffffffff81cb35f4
0000000041b58ab3 ffffffff83230f9c ffffffff81cb34e0 ffff8801f6b07a80
ffff8801f6b07a20 1466cf39b41b23c9 ffffffff851706e0 ffff8801f6b07ae8
Call Trace:
<IRQ> [<ffffffff81cb35f4>] __dump_stack lib/dump_stack.c:15 [inline]
<IRQ> [<ffffffff81cb35f4>] dump_stack+0x114/0x1a0 lib/dump_stack.c:51
[<ffffffff81d94225>] ubsan_epilogue+0x12/0x8f lib/ubsan.c:164
[<ffffffff81d954db>] __ubsan_handle_out_of_bounds+0x16e/0x1b2 lib/ubsan.c:382
[<ffffffff82a25acd>] __xfrm_policy_unlink+0x3dd/0x5b0 net/xfrm/xfrm_policy.c:1289
[<ffffffff82a2e572>] xfrm_policy_delete+0x52/0xb0 net/xfrm/xfrm_policy.c:1309
[<ffffffff82a3319b>] xfrm_policy_timer+0x30b/0x590 net/xfrm/xfrm_policy.c:243
[<ffffffff813d3927>] call_timer_fn+0x237/0x990 kernel/time/timer.c:1144
[<ffffffff813d8e7e>] __run_timers kernel/time/timer.c:1218 [inline]
[<ffffffff813d8e7e>] run_timer_softirq+0x6ce/0xb80 kernel/time/timer.c:1401
[<ffffffff8120d6f9>] __do_softirq+0x299/0xe10 kernel/softirq.c:273
[<ffffffff8120e676>] invoke_softirq kernel/softirq.c:350 [inline]
[<ffffffff8120e676>] irq_exit+0x216/0x2c0 kernel/softirq.c:391
[<ffffffff82c5edab>] exiting_irq arch/x86/include/asm/apic.h:652 [inline]
[<ffffffff82c5edab>] smp_apic_timer_interrupt+0x8b/0xc0 arch/x86/kernel/apic/apic.c:926
[<ffffffff82c5c985>] apic_timer_interrupt+0xa5/0xb0 arch/x86/entry/entry_64.S:735
<EOI> [<ffffffff81188096>] ? native_safe_halt+0x6/0x10 arch/x86/include/asm/irqflags.h:52
[<ffffffff810834d7>] arch_safe_halt arch/x86/include/asm/paravirt.h:111 [inline]
[<ffffffff810834d7>] default_idle+0x27/0x430 arch/x86/kernel/process.c:446
[<ffffffff81085f05>] arch_cpu_idle+0x15/0x20 arch/x86/kernel/process.c:437
[<ffffffff8132abc3>] default_idle_call+0x53/0x90 kernel/sched/idle.c:92
[<ffffffff8132b32d>] cpuidle_idle_call kernel/sched/idle.c:156 [inline]
[<ffffffff8132b32d>] cpu_idle_loop kernel/sched/idle.c:251 [inline]
[<ffffffff8132b32d>] cpu_startup_entry+0x60d/0x9a0 kernel/sched/idle.c:299
[<ffffffff8113e119>] start_secondary+0x3c9/0x560 arch/x86/kernel/smpboot.c:245
The issue is triggered as this:
xfrm_add_policy
-->verify_newpolicy_info //check the index provided by user with XFRM_POLICY_MAX
//In my case, the index is 0x6E6BB6, so it pass the check.
-->xfrm_policy_construct //copy the user's policy and set xfrm_policy_timer
-->xfrm_policy_insert
--> __xfrm_policy_link //use the orgin dir, in my case is 2
--> xfrm_gen_index //generate policy index, there is 0x6E6BB6
then xfrm_policy_timer be fired
xfrm_policy_timer
--> xfrm_policy_id2dir //get dir from (policy index & 7), in my case is 6
--> xfrm_policy_delete
--> __xfrm_policy_unlink //access policy_count[dir], trigger out of range access
Add xfrm_policy_id2dir check in verify_newpolicy_info, make sure the computed dir is
valid, to fix the issue.
Reported-by: Hulk Robot <hulkci@huawei.com>
Fixes: e682adf021be ("xfrm: Try to honor policy index if it's supplied by user")
Signed-off-by: YueHaibing <yuehaibing@huawei.com>
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2019-02-28 15:18:59 +08:00
|
|
|
if (p->index && (xfrm_policy_id2dir(p->index) != p->dir))
|
2013-11-07 17:47:48 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs)
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
struct xfrm_user_sec_ctx *uctx;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
uctx = nla_data(rt);
|
2014-03-07 19:44:19 +08:00
|
|
|
return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
|
|
|
|
int nr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
xp->xfrm_nr = nr;
|
|
|
|
for (i = 0; i < nr; i++, ut++) {
|
|
|
|
struct xfrm_tmpl *t = &xp->xfrm_vec[i];
|
|
|
|
|
|
|
|
memcpy(&t->id, &ut->id, sizeof(struct xfrm_id));
|
|
|
|
memcpy(&t->saddr, &ut->saddr,
|
|
|
|
sizeof(xfrm_address_t));
|
|
|
|
t->reqid = ut->reqid;
|
|
|
|
t->mode = ut->mode;
|
|
|
|
t->share = ut->share;
|
|
|
|
t->optional = ut->optional;
|
|
|
|
t->aalgos = ut->aalgos;
|
|
|
|
t->ealgos = ut->ealgos;
|
|
|
|
t->calgos = ut->calgos;
|
2008-04-22 15:46:42 +08:00
|
|
|
/* If all masks are ~0, then we allow all algorithms. */
|
|
|
|
t->allalgs = !~(t->aalgos & t->ealgos & t->calgos);
|
2006-12-01 08:40:51 +08:00
|
|
|
t->encap_family = ut->family;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-04 11:19:26 +08:00
|
|
|
static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
|
|
|
|
{
|
2017-12-08 15:07:25 +08:00
|
|
|
u16 prev_family;
|
2006-12-04 11:19:26 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (nr > XFRM_MAX_DEPTH)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-12-08 15:07:25 +08:00
|
|
|
prev_family = family;
|
|
|
|
|
2006-12-04 11:19:26 +08:00
|
|
|
for (i = 0; i < nr; i++) {
|
|
|
|
/* We never validated the ut->family value, so many
|
|
|
|
* applications simply leave it at zero. The check was
|
|
|
|
* never made and ut->family was ignored because all
|
|
|
|
* templates could be assumed to have the same family as
|
|
|
|
* the policy itself. Now that we will have ipv4-in-ipv6
|
|
|
|
* and ipv6-in-ipv4 tunnels, this is no longer true.
|
|
|
|
*/
|
|
|
|
if (!ut[i].family)
|
|
|
|
ut[i].family = family;
|
|
|
|
|
2019-01-09 21:37:34 +08:00
|
|
|
switch (ut[i].mode) {
|
|
|
|
case XFRM_MODE_TUNNEL:
|
|
|
|
case XFRM_MODE_BEET:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (ut[i].family != prev_family)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2018-09-20 03:54:56 +08:00
|
|
|
if (ut[i].mode >= XFRM_MODE_MAX)
|
|
|
|
return -EINVAL;
|
2017-12-08 15:07:25 +08:00
|
|
|
|
|
|
|
prev_family = ut[i].family;
|
|
|
|
|
2006-12-04 11:19:26 +08:00
|
|
|
switch (ut[i].family) {
|
|
|
|
case AF_INET:
|
|
|
|
break;
|
2011-12-10 17:48:31 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
2006-12-04 11:19:26 +08:00
|
|
|
case AF_INET6:
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2007-04-21 08:09:22 +08:00
|
|
|
}
|
2017-11-28 03:15:16 +08:00
|
|
|
|
2019-03-23 07:26:19 +08:00
|
|
|
if (!xfrm_id_proto_valid(ut[i].id.proto))
|
2017-11-28 03:15:16 +08:00
|
|
|
return -EINVAL;
|
2006-12-04 11:19:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_TMPL];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!rt) {
|
|
|
|
pol->xfrm_nr = 0;
|
|
|
|
} else {
|
2007-08-23 05:01:33 +08:00
|
|
|
struct xfrm_user_tmpl *utmpl = nla_data(rt);
|
|
|
|
int nr = nla_len(rt) / sizeof(*utmpl);
|
2006-12-04 11:19:26 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2006-12-04 11:19:26 +08:00
|
|
|
err = validate_tmpl(nr, utmpl, pol->family);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
copy_templates(pol, utmpl, nr);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs)
|
2006-08-24 13:49:28 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_POLICY_TYPE];
|
2006-08-24 13:49:28 +08:00
|
|
|
struct xfrm_userpolicy_type *upt;
|
2006-11-28 04:59:30 +08:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2006-08-24 13:49:28 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (rt) {
|
2007-08-23 05:01:33 +08:00
|
|
|
upt = nla_data(rt);
|
2006-08-24 13:49:28 +08:00
|
|
|
type = upt->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = verify_policy_type(type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
*tp = type;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p)
|
|
|
|
{
|
|
|
|
xp->priority = p->priority;
|
|
|
|
xp->index = p->index;
|
|
|
|
memcpy(&xp->selector, &p->sel, sizeof(xp->selector));
|
|
|
|
memcpy(&xp->lft, &p->lft, sizeof(xp->lft));
|
|
|
|
xp->action = p->action;
|
|
|
|
xp->flags = p->flags;
|
|
|
|
xp->family = p->sel.family;
|
|
|
|
/* XXX xp->share = p->share; */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)
|
|
|
|
{
|
2012-09-19 19:33:40 +08:00
|
|
|
memset(p, 0, sizeof(*p));
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(&p->sel, &xp->selector, sizeof(p->sel));
|
|
|
|
memcpy(&p->lft, &xp->lft, sizeof(p->lft));
|
|
|
|
memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));
|
|
|
|
p->priority = xp->priority;
|
|
|
|
p->index = xp->index;
|
|
|
|
p->sel.family = xp->family;
|
|
|
|
p->dir = dir;
|
|
|
|
p->action = xp->action;
|
|
|
|
p->flags = xp->flags;
|
|
|
|
p->share = XFRM_SHARE_ANY; /* XXX xp->share */
|
|
|
|
}
|
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!xp) {
|
|
|
|
*errp = -ENOMEM;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
copy_from_user_policy(xp, p);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = copy_from_user_policy_type(&xp->type, attrs);
|
2006-08-24 13:49:28 +08:00
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
if (!(err = copy_from_user_tmpl(xp, attrs)))
|
|
|
|
err = copy_from_user_sec_ctx(xp, attrs);
|
2006-08-24 13:49:28 +08:00
|
|
|
if (err)
|
|
|
|
goto error;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-02-22 19:33:00 +08:00
|
|
|
xfrm_mark_get(attrs, &xp->mark);
|
|
|
|
|
2022-03-03 22:55:10 +08:00
|
|
|
if (attrs[XFRMA_IF_ID])
|
2018-06-12 20:07:07 +08:00
|
|
|
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return xp;
|
2006-08-24 13:49:28 +08:00
|
|
|
error:
|
|
|
|
*errp = err;
|
2008-10-01 22:03:24 +08:00
|
|
|
xp->walk.dead = 1;
|
2008-01-08 14:34:29 +08:00
|
|
|
xfrm_policy_destroy(xp);
|
2006-08-24 13:49:28 +08:00
|
|
|
return NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_userpolicy_info *p = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_policy *xp;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct km_event c;
|
2005-04-17 06:20:36 +08:00
|
|
|
int err;
|
|
|
|
int excl;
|
|
|
|
|
|
|
|
err = verify_newpolicy_info(p);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
2007-08-23 05:00:40 +08:00
|
|
|
err = verify_sec_ctx_len(attrs);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
xp = xfrm_policy_construct(net, p, attrs, &err);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!xp)
|
|
|
|
return err;
|
|
|
|
|
2011-03-31 09:57:33 +08:00
|
|
|
/* shouldn't excl be based on nlh flags??
|
2005-06-19 13:42:13 +08:00
|
|
|
* Aha! this is anti-netlink really i.e more pfkey derived
|
2021-03-27 07:12:54 +08:00
|
|
|
* in netlink excl is a flag and you wouldn't need
|
2005-06-19 13:42:13 +08:00
|
|
|
* a type XFRM_MSG_UPDPOLICY - JHS */
|
2005-04-17 06:20:36 +08:00
|
|
|
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
|
|
|
|
err = xfrm_policy_insert(p->dir, xp, excl);
|
2014-04-22 20:48:30 +08:00
|
|
|
xfrm_audit_policy_add(xp, err ? 0 : 1, true);
|
2006-11-28 03:11:54 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (err) {
|
2008-04-13 10:07:52 +08:00
|
|
|
security_xfrm_policy_free(xp->security);
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree(xp);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2005-06-19 13:44:37 +08:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-19 13:42:13 +08:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2005-06-19 13:42:13 +08:00
|
|
|
km_policy_notify(xp, p->dir, &c);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
xfrm_pol_put(xp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (xp->xfrm_nr == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0; i < xp->xfrm_nr; i++) {
|
|
|
|
struct xfrm_user_tmpl *up = &vec[i];
|
|
|
|
struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
|
|
|
|
|
2012-09-19 19:33:41 +08:00
|
|
|
memset(up, 0, sizeof(*up));
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(&up->id, &kp->id, sizeof(up->id));
|
2006-12-01 08:40:51 +08:00
|
|
|
up->family = kp->encap_family;
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));
|
|
|
|
up->reqid = kp->reqid;
|
|
|
|
up->mode = kp->mode;
|
|
|
|
up->share = kp->share;
|
|
|
|
up->optional = kp->optional;
|
|
|
|
up->aalgos = kp->aalgos;
|
|
|
|
up->ealgos = kp->ealgos;
|
|
|
|
up->calgos = kp->calgos;
|
|
|
|
}
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2007-08-23 04:55:43 +08:00
|
|
|
return nla_put(skb, XFRMA_TMPL,
|
|
|
|
sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec);
|
2006-07-25 14:30:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
if (x->security) {
|
|
|
|
return copy_sec_ctx(x->security, skb);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
}
|
|
|
|
return 0;
|
2006-07-25 14:30:44 +08:00
|
|
|
}
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2006-07-25 14:30:44 +08:00
|
|
|
static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
|
|
|
|
{
|
2012-06-28 12:57:03 +08:00
|
|
|
if (xp->security)
|
2006-07-25 14:30:44 +08:00
|
|
|
return copy_sec_ctx(xp->security, skb);
|
|
|
|
return 0;
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
}
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int userpolicy_type_attrsize(void)
|
2007-08-23 04:57:04 +08:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
return nla_total_size(sizeof(struct xfrm_userpolicy_type));
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2006-08-24 13:49:28 +08:00
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
2006-11-28 04:59:30 +08:00
|
|
|
static int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
|
2006-08-24 13:49:28 +08:00
|
|
|
{
|
2018-06-19 12:35:07 +08:00
|
|
|
struct xfrm_userpolicy_type upt;
|
|
|
|
|
|
|
|
/* Sadly there are two holes in struct xfrm_userpolicy_type */
|
|
|
|
memset(&upt, 0, sizeof(upt));
|
|
|
|
upt.type = type;
|
2006-08-24 13:49:28 +08:00
|
|
|
|
2007-08-23 04:55:43 +08:00
|
|
|
return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
|
2006-08-24 13:49:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2006-11-28 04:59:30 +08:00
|
|
|
static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
|
2006-08-24 13:49:28 +08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr)
|
|
|
|
{
|
|
|
|
struct xfrm_dump_info *sp = ptr;
|
|
|
|
struct xfrm_userpolicy_info *p;
|
|
|
|
struct sk_buff *in_skb = sp->in_skb;
|
|
|
|
struct sk_buff *skb = sp->out_skb;
|
2020-09-21 22:36:53 +08:00
|
|
|
struct xfrm_translator *xtr;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, NETLINK_CB(in_skb).portid, sp->nlmsg_seq,
|
2007-08-23 03:46:53 +08:00
|
|
|
XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
|
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
p = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
copy_to_user_policy(xp, p, dir);
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_tmpl(xp, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_sec_ctx(xp, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
|
if (!err)
|
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
2018-06-12 20:07:07 +08:00
|
|
|
if (!err)
|
|
|
|
err = xfrm_if_id_put(skb, xp->if_id);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
2020-09-21 22:36:53 +08:00
|
|
|
|
|
|
|
xtr = xfrm_get_translator();
|
|
|
|
if (xtr) {
|
|
|
|
err = xtr->alloc_compat(skb, nlh);
|
|
|
|
|
|
|
|
xfrm_put_translator(xtr);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-29 13:31:08 +08:00
|
|
|
static int xfrm_dump_policy_done(struct netlink_callback *cb)
|
|
|
|
{
|
2017-10-19 20:51:10 +08:00
|
|
|
struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args;
|
2013-11-07 17:47:50 +08:00
|
|
|
struct net *net = sock_net(cb->skb->sk);
|
2008-02-29 13:31:08 +08:00
|
|
|
|
2013-11-07 17:47:50 +08:00
|
|
|
xfrm_policy_walk_done(walk, net);
|
2008-02-29 13:31:08 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-19 20:51:10 +08:00
|
|
|
static int xfrm_dump_policy_start(struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args;
|
|
|
|
|
|
|
|
BUILD_BUG_ON(sizeof(*walk) > sizeof(cb->args));
|
|
|
|
|
|
|
|
xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2017-10-19 20:51:10 +08:00
|
|
|
struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *)cb->args;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_dump_info info;
|
|
|
|
|
|
|
|
info.in_skb = cb->skb;
|
|
|
|
info.out_skb = skb;
|
|
|
|
info.nlmsg_seq = cb->nlh->nlmsg_seq;
|
|
|
|
info.nlmsg_flags = NLM_F_MULTI;
|
2008-02-29 13:31:08 +08:00
|
|
|
|
2008-11-26 09:50:08 +08:00
|
|
|
(void) xfrm_policy_walk(net, walk, dump_one_policy, &info);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
return skb->len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
|
|
|
|
struct xfrm_policy *xp,
|
|
|
|
int dir, u32 seq)
|
|
|
|
{
|
|
|
|
struct xfrm_dump_info info;
|
|
|
|
struct sk_buff *skb;
|
2012-09-14 17:58:32 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (!skb)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
info.in_skb = in_skb;
|
|
|
|
info.out_skb = skb;
|
|
|
|
info.nlmsg_seq = seq;
|
|
|
|
info.nlmsg_flags = 0;
|
|
|
|
|
2012-09-14 17:58:32 +08:00
|
|
|
err = dump_one_policy(xp, dir, 0, &info);
|
|
|
|
if (err) {
|
2005-04-17 06:20:36 +08:00
|
|
|
kfree_skb(skb);
|
2012-09-14 17:58:32 +08:00
|
|
|
return ERR_PTR(err);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2021-09-14 22:46:34 +08:00
|
|
|
static int xfrm_notify_userpolicy(struct net *net)
|
|
|
|
{
|
|
|
|
struct xfrm_userpolicy_default *up;
|
|
|
|
int len = NLMSG_ALIGN(sizeof(*up));
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
2021-09-22 16:50:06 +08:00
|
|
|
int err;
|
2021-09-14 22:46:34 +08:00
|
|
|
|
|
|
|
skb = nlmsg_new(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_GETDEFAULT, sizeof(*up), 0);
|
|
|
|
if (nlh == NULL) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
up = nlmsg_data(nlh);
|
2022-03-14 18:38:22 +08:00
|
|
|
up->in = net->xfrm.policy_default[XFRM_POLICY_IN];
|
|
|
|
up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD];
|
|
|
|
up->out = net->xfrm.policy_default[XFRM_POLICY_OUT];
|
2021-09-14 22:46:34 +08:00
|
|
|
|
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
|
2021-09-22 16:50:06 +08:00
|
|
|
rcu_read_lock();
|
|
|
|
err = xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
|
|
|
return err;
|
2021-09-14 22:46:34 +08:00
|
|
|
}
|
|
|
|
|
2022-03-14 18:38:22 +08:00
|
|
|
static bool xfrm_userpolicy_is_valid(__u8 policy)
|
|
|
|
{
|
|
|
|
return policy == XFRM_USERPOLICY_BLOCK ||
|
|
|
|
policy == XFRM_USERPOLICY_ACCEPT;
|
|
|
|
}
|
|
|
|
|
2021-07-18 15:11:06 +08:00
|
|
|
static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
|
struct xfrm_userpolicy_default *up = nlmsg_data(nlh);
|
|
|
|
|
2022-03-14 18:38:22 +08:00
|
|
|
if (xfrm_userpolicy_is_valid(up->in))
|
|
|
|
net->xfrm.policy_default[XFRM_POLICY_IN] = up->in;
|
2021-07-29 00:38:18 +08:00
|
|
|
|
2022-03-14 18:38:22 +08:00
|
|
|
if (xfrm_userpolicy_is_valid(up->fwd))
|
|
|
|
net->xfrm.policy_default[XFRM_POLICY_FWD] = up->fwd;
|
2021-07-29 00:38:18 +08:00
|
|
|
|
2022-03-14 18:38:22 +08:00
|
|
|
if (xfrm_userpolicy_is_valid(up->out))
|
|
|
|
net->xfrm.policy_default[XFRM_POLICY_OUT] = up->out;
|
2021-07-18 15:11:06 +08:00
|
|
|
|
|
|
|
rt_genid_bump_all(net);
|
|
|
|
|
2021-09-14 22:46:34 +08:00
|
|
|
xfrm_notify_userpolicy(net);
|
2021-07-18 15:11:06 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct nlattr **attrs)
|
|
|
|
{
|
|
|
|
struct sk_buff *r_skb;
|
|
|
|
struct nlmsghdr *r_nlh;
|
|
|
|
struct net *net = sock_net(skb->sk);
|
2021-09-14 22:46:33 +08:00
|
|
|
struct xfrm_userpolicy_default *r_up;
|
2021-07-18 15:11:06 +08:00
|
|
|
int len = NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_default));
|
|
|
|
u32 portid = NETLINK_CB(skb).portid;
|
|
|
|
u32 seq = nlh->nlmsg_seq;
|
|
|
|
|
|
|
|
r_skb = nlmsg_new(len, GFP_ATOMIC);
|
|
|
|
if (!r_skb)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r_nlh = nlmsg_put(r_skb, portid, seq, XFRM_MSG_GETDEFAULT, sizeof(*r_up), 0);
|
|
|
|
if (!r_nlh) {
|
|
|
|
kfree_skb(r_skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
r_up = nlmsg_data(r_nlh);
|
2022-03-14 18:38:22 +08:00
|
|
|
r_up->in = net->xfrm.policy_default[XFRM_POLICY_IN];
|
|
|
|
r_up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD];
|
|
|
|
r_up->out = net->xfrm.policy_default[XFRM_POLICY_OUT];
|
2021-07-18 15:11:06 +08:00
|
|
|
nlmsg_end(r_skb, r_nlh);
|
|
|
|
|
|
|
|
return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid);
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_policy *xp;
|
|
|
|
struct xfrm_userpolicy_id *p;
|
2006-11-28 04:59:30 +08:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2005-04-17 06:20:36 +08:00
|
|
|
int err;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct km_event c;
|
2005-04-17 06:20:36 +08:00
|
|
|
int delete;
|
2010-02-22 19:33:00 +08:00
|
|
|
struct xfrm_mark m;
|
2018-06-12 20:07:07 +08:00
|
|
|
u32 if_id = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
p = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
|
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = copy_from_user_policy_type(&type, attrs);
|
2006-08-24 13:49:28 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
err = verify_policy_dir(p->dir);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2018-06-12 20:07:07 +08:00
|
|
|
if (attrs[XFRMA_IF_ID])
|
|
|
|
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
|
|
2020-06-22 16:40:29 +08:00
|
|
|
xfrm_mark_get(attrs, &m);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (p->index)
|
2020-06-22 16:40:29 +08:00
|
|
|
xp = xfrm_policy_byid(net, &m, if_id, type, p->dir,
|
|
|
|
p->index, delete, &err);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
else {
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
|
2008-04-13 10:07:52 +08:00
|
|
|
struct xfrm_sec_ctx *ctx;
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = verify_sec_ctx_len(attrs);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2008-04-15 05:47:48 +08:00
|
|
|
ctx = NULL;
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
if (rt) {
|
2007-08-23 05:01:33 +08:00
|
|
|
struct xfrm_user_sec_ctx *uctx = nla_data(rt);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
|
2014-03-07 19:44:19 +08:00
|
|
|
err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
|
2008-04-13 10:07:52 +08:00
|
|
|
if (err)
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
return err;
|
2008-04-15 05:47:48 +08:00
|
|
|
}
|
2020-06-22 16:40:29 +08:00
|
|
|
xp = xfrm_policy_bysel_ctx(net, &m, if_id, type, p->dir,
|
|
|
|
&p->sel, ctx, delete, &err);
|
2008-04-13 10:07:52 +08:00
|
|
|
security_xfrm_policy_free(ctx);
|
[LSM-IPSec]: Security association restriction.
This patch series implements per packet access control via the
extension of the Linux Security Modules (LSM) interface by hooks in
the XFRM and pfkey subsystems that leverage IPSec security
associations to label packets. Extensions to the SELinux LSM are
included that leverage the patch for this purpose.
This patch implements the changes necessary to the XFRM subsystem,
pfkey interface, ipv4/ipv6, and xfrm_user interface to restrict a
socket to use only authorized security associations (or no security
association) to send/receive network packets.
Patch purpose:
The patch is designed to enable access control per packets based on
the strongly authenticated IPSec security association. Such access
controls augment the existing ones based on network interface and IP
address. The former are very coarse-grained, and the latter can be
spoofed. By using IPSec, the system can control access to remote
hosts based on cryptographic keys generated using the IPSec mechanism.
This enables access control on a per-machine basis or per-application
if the remote machine is running the same mechanism and trusted to
enforce the access control policy.
Patch design approach:
The overall approach is that policy (xfrm_policy) entries set by
user-level programs (e.g., setkey for ipsec-tools) are extended with a
security context that is used at policy selection time in the XFRM
subsystem to restrict the sockets that can send/receive packets via
security associations (xfrm_states) that are built from those
policies.
A presentation available at
www.selinux-symposium.org/2005/presentations/session2/2-3-jaeger.pdf
from the SELinux symposium describes the overall approach.
Patch implementation details:
On output, the policy retrieved (via xfrm_policy_lookup or
xfrm_sk_policy_lookup) must be authorized for the security context of
the socket and the same security context is required for resultant
security association (retrieved or negotiated via racoon in
ipsec-tools). This is enforced in xfrm_state_find.
On input, the policy retrieved must also be authorized for the socket
(at __xfrm_policy_check), and the security context of the policy must
also match the security association being used.
The patch has virtually no impact on packets that do not use IPSec.
The existing Netfilter (outgoing) and LSM rcv_skb hooks are used as
before.
Also, if IPSec is used without security contexts, the impact is
minimal. The LSM must allow such policies to be selected for the
combination of socket and remote machine, but subsequent IPSec
processing proceeds as in the original case.
Testing:
The pfkey interface is tested using the ipsec-tools. ipsec-tools have
been modified (a separate ipsec-tools patch is available for version
0.5) that supports assignment of xfrm_policy entries and security
associations with security contexts via setkey and the negotiation
using the security contexts via racoon.
The xfrm_user interface is tested via ad hoc programs that set
security contexts. These programs are also available from me, and
contain programs for setting, getting, and deleting policy for testing
this interface. Testing of sa functions was done by tracing kernel
behavior.
Signed-off-by: Trent Jaeger <tjaeger@cse.psu.edu>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-12-14 15:12:27 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
if (xp == NULL)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
if (!delete) {
|
|
|
|
struct sk_buff *resp_skb;
|
|
|
|
|
|
|
|
resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq);
|
|
|
|
if (IS_ERR(resp_skb)) {
|
|
|
|
err = PTR_ERR(resp_skb);
|
|
|
|
} else {
|
2008-11-26 09:38:20 +08:00
|
|
|
err = nlmsg_unicast(net->xfrm.nlsk, resp_skb,
|
2012-09-08 04:12:54 +08:00
|
|
|
NETLINK_CB(skb).portid);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2005-06-19 13:42:13 +08:00
|
|
|
} else {
|
2014-04-22 20:48:30 +08:00
|
|
|
xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
|
2007-02-13 05:53:54 +08:00
|
|
|
|
|
|
|
if (err != 0)
|
2006-06-09 14:39:49 +08:00
|
|
|
goto out;
|
2007-02-13 05:53:54 +08:00
|
|
|
|
2005-06-19 13:44:18 +08:00
|
|
|
c.data.byid = p->index;
|
2005-06-19 13:44:37 +08:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-19 13:42:13 +08:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2005-06-19 13:42:13 +08:00
|
|
|
km_policy_notify(xp, p->dir, &c);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2006-06-09 14:39:49 +08:00
|
|
|
out:
|
2007-03-08 07:37:58 +08:00
|
|
|
xfrm_pol_put(xp);
|
2005-04-17 06:20:36 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2005-06-19 13:42:13 +08:00
|
|
|
struct km_event c;
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_usersa_flush *p = nlmsg_data(nlh);
|
2007-06-05 07:05:57 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
xfrm: destroy xfrm_state synchronously on net exit path
xfrm_state_put() moves struct xfrm_state to the GC list
and schedules the GC work to clean it up. On net exit call
path, xfrm_state_flush() is called to clean up and
xfrm_flush_gc() is called to wait for the GC work to complete
before exit.
However, this doesn't work because one of the ->destructor(),
ipcomp_destroy(), schedules the same GC work again inside
the GC work. It is hard to wait for such a nested async
callback. This is also why syzbot still reports the following
warning:
WARNING: CPU: 1 PID: 33 at net/ipv6/xfrm6_tunnel.c:351 xfrm6_tunnel_net_exit+0x2cb/0x500 net/ipv6/xfrm6_tunnel.c:351
...
ops_exit_list.isra.0+0xb0/0x160 net/core/net_namespace.c:153
cleanup_net+0x51d/0xb10 net/core/net_namespace.c:551
process_one_work+0xd0c/0x1ce0 kernel/workqueue.c:2153
worker_thread+0x143/0x14a0 kernel/workqueue.c:2296
kthread+0x357/0x430 kernel/kthread.c:246
ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352
In fact, it is perfectly fine to bypass GC and destroy xfrm_state
synchronously on net exit call path, because it is in process context
and doesn't need a work struct to do any blocking work.
This patch introduces xfrm_state_put_sync() which simply bypasses
GC, and lets its callers to decide whether to use this synchronous
version. On net exit path, xfrm_state_fini() and
xfrm6_tunnel_net_exit() use it. And, as ipcomp_destroy() itself is
blocking, it can use xfrm_state_put_sync() directly too.
Also rename xfrm_state_gc_destroy() to ___xfrm_state_destroy() to
reflect this change.
Fixes: b48c05ab5d32 ("xfrm: Fix warning in xfrm6_tunnel_net_exit.")
Reported-and-tested-by: syzbot+e9aebef558e3ed673934@syzkaller.appspotmail.com
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2019-02-01 05:05:49 +08:00
|
|
|
err = xfrm_state_flush(net, p->proto, true, false);
|
2010-02-19 10:00:41 +08:00
|
|
|
if (err) {
|
|
|
|
if (err == -ESRCH) /* empty table */
|
|
|
|
return 0;
|
2010-02-18 05:41:40 +08:00
|
|
|
return err;
|
2010-02-19 10:00:41 +08:00
|
|
|
}
|
2005-06-19 13:44:00 +08:00
|
|
|
c.data.proto = p->proto;
|
2005-06-19 13:44:37 +08:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-19 13:42:13 +08:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2008-11-26 09:50:36 +08:00
|
|
|
c.net = net;
|
2005-06-19 13:42:13 +08:00
|
|
|
km_state_notify(NULL, &c);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_aevent_msgsize(struct xfrm_state *x)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
2017-09-22 04:48:54 +08:00
|
|
|
unsigned int replay_size = x->replay_esn ?
|
2011-03-08 08:10:27 +08:00
|
|
|
xfrm_replay_state_esn_len(x->replay_esn) :
|
|
|
|
sizeof(struct xfrm_replay_state);
|
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id))
|
2011-03-08 08:10:27 +08:00
|
|
|
+ nla_total_size(replay_size)
|
2016-04-22 23:31:23 +08:00
|
|
|
+ nla_total_size_64bit(sizeof(struct xfrm_lifetime_cur))
|
2010-02-22 19:32:59 +08:00
|
|
|
+ nla_total_size(sizeof(struct xfrm_mark))
|
2007-08-23 04:57:39 +08:00
|
|
|
+ nla_total_size(4) /* XFRM_AE_RTHR */
|
|
|
|
+ nla_total_size(4); /* XFRM_AE_ETHR */
|
|
|
|
}
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
|
2006-03-21 11:16:12 +08:00
|
|
|
{
|
|
|
|
struct xfrm_aevent_id *id;
|
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0);
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
id = nlmsg_data(nlh);
|
2017-08-26 23:09:00 +08:00
|
|
|
memset(&id->sa_id, 0, sizeof(id->sa_id));
|
2013-12-24 09:43:46 +08:00
|
|
|
memcpy(&id->sa_id.daddr, &x->id.daddr, sizeof(x->id.daddr));
|
2006-03-21 11:16:12 +08:00
|
|
|
id->sa_id.spi = x->id.spi;
|
|
|
|
id->sa_id.family = x->props.family;
|
|
|
|
id->sa_id.proto = x->id.proto;
|
2013-12-24 09:43:46 +08:00
|
|
|
memcpy(&id->saddr, &x->props.saddr, sizeof(x->props.saddr));
|
2006-12-03 14:22:25 +08:00
|
|
|
id->reqid = x->props.reqid;
|
2006-03-21 11:16:12 +08:00
|
|
|
id->flags = c->data.aevent;
|
|
|
|
|
2012-03-29 16:02:26 +08:00
|
|
|
if (x->replay_esn) {
|
2012-06-28 12:57:03 +08:00
|
|
|
err = nla_put(skb, XFRMA_REPLAY_ESN_VAL,
|
|
|
|
xfrm_replay_state_esn_len(x->replay_esn),
|
|
|
|
x->replay_esn);
|
2012-03-29 16:02:26 +08:00
|
|
|
} else {
|
2012-06-28 12:57:03 +08:00
|
|
|
err = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay),
|
|
|
|
&x->replay);
|
2012-03-29 16:02:26 +08:00
|
|
|
}
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
2016-04-22 23:31:23 +08:00
|
|
|
err = nla_put_64bit(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft,
|
|
|
|
XFRMA_PAD);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
if (id->flags & XFRM_AE_RTHR) {
|
|
|
|
err = nla_put_u32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
|
|
|
}
|
|
|
|
if (id->flags & XFRM_AE_ETHR) {
|
|
|
|
err = nla_put_u32(skb, XFRMA_ETIMER_THRESH,
|
|
|
|
x->replay_maxage * 10 / HZ);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
|
|
|
}
|
|
|
|
err = xfrm_mark_put(skb, &x->mark);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
2010-02-22 19:32:59 +08:00
|
|
|
|
2018-06-12 20:07:07 +08:00
|
|
|
err = xfrm_if_id_put(skb, x->if_id);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
out_cancel:
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_cancel(skb, nlh);
|
2012-06-28 12:57:03 +08:00
|
|
|
return err;
|
2006-03-21 11:16:12 +08:00
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2006-03-21 11:16:12 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2006-03-21 11:16:12 +08:00
|
|
|
struct xfrm_state *x;
|
|
|
|
struct sk_buff *r_skb;
|
|
|
|
int err;
|
|
|
|
struct km_event c;
|
2010-02-22 19:32:59 +08:00
|
|
|
u32 mark;
|
|
|
|
struct xfrm_mark m;
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_aevent_id *p = nlmsg_data(nlh);
|
2006-03-21 11:16:12 +08:00
|
|
|
struct xfrm_usersa_id *id = &p->sa_id;
|
|
|
|
|
2010-02-22 19:32:59 +08:00
|
|
|
mark = xfrm_mark_get(attrs, &m);
|
|
|
|
|
|
|
|
x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family);
|
2011-03-08 08:10:27 +08:00
|
|
|
if (x == NULL)
|
2006-03-21 11:16:12 +08:00
|
|
|
return -ESRCH;
|
2011-03-08 08:10:27 +08:00
|
|
|
|
|
|
|
r_skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC);
|
|
|
|
if (r_skb == NULL) {
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return -ENOMEM;
|
2006-03-21 11:16:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: is this lock really needed - none of the other
|
|
|
|
* gets lock (the concern is things getting updated
|
|
|
|
* while we are still reading) - jhs
|
|
|
|
*/
|
|
|
|
spin_lock_bh(&x->lock);
|
|
|
|
c.data.aevent = p->flags;
|
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_aevent(r_skb, x, &c);
|
|
|
|
BUG_ON(err < 0);
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).portid);
|
2006-03-21 11:16:12 +08:00
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2006-03-21 11:16:12 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2006-03-21 11:16:12 +08:00
|
|
|
struct xfrm_state *x;
|
|
|
|
struct km_event c;
|
2013-12-24 09:43:48 +08:00
|
|
|
int err = -EINVAL;
|
2010-02-22 19:32:59 +08:00
|
|
|
u32 mark = 0;
|
|
|
|
struct xfrm_mark m;
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_aevent_id *p = nlmsg_data(nlh);
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rp = attrs[XFRMA_REPLAY_VAL];
|
2011-03-08 08:10:27 +08:00
|
|
|
struct nlattr *re = attrs[XFRMA_REPLAY_ESN_VAL];
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *lt = attrs[XFRMA_LTIME_VAL];
|
2015-09-29 17:25:08 +08:00
|
|
|
struct nlattr *et = attrs[XFRMA_ETIMER_THRESH];
|
|
|
|
struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2015-09-29 17:25:08 +08:00
|
|
|
if (!lt && !rp && !re && !et && !rt)
|
2006-03-21 11:16:12 +08:00
|
|
|
return err;
|
|
|
|
|
|
|
|
/* pedantic mode - thou shalt sayeth replaceth */
|
|
|
|
if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
|
|
|
|
return err;
|
|
|
|
|
2010-02-22 19:32:59 +08:00
|
|
|
mark = xfrm_mark_get(attrs, &m);
|
|
|
|
|
|
|
|
x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
|
2006-03-21 11:16:12 +08:00
|
|
|
if (x == NULL)
|
|
|
|
return -ESRCH;
|
|
|
|
|
|
|
|
if (x->km.state != XFRM_STATE_VALID)
|
|
|
|
goto out;
|
|
|
|
|
2013-09-09 15:39:01 +08:00
|
|
|
err = xfrm_replay_verify_len(x->replay_esn, re);
|
2011-03-29 03:47:30 +08:00
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
2006-03-21 11:16:12 +08:00
|
|
|
spin_lock_bh(&x->lock);
|
2012-09-19 19:33:43 +08:00
|
|
|
xfrm_update_ae_params(x, attrs, 1);
|
2006-03-21 11:16:12 +08:00
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
|
|
|
|
c.event = nlh->nlmsg_type;
|
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2006-03-21 11:16:12 +08:00
|
|
|
c.data.aevent = XFRM_AE_CU;
|
|
|
|
km_state_notify(x, &c);
|
|
|
|
err = 0;
|
|
|
|
out:
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2006-08-24 13:49:28 +08:00
|
|
|
struct km_event c;
|
2006-11-28 04:59:30 +08:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2006-08-24 13:49:28 +08:00
|
|
|
int err;
|
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = copy_from_user_policy_type(&type, attrs);
|
2006-08-24 13:49:28 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2014-04-22 20:48:30 +08:00
|
|
|
err = xfrm_policy_flush(net, type, true);
|
2010-02-19 10:00:42 +08:00
|
|
|
if (err) {
|
|
|
|
if (err == -ESRCH) /* empty table */
|
|
|
|
return 0;
|
2010-02-18 05:41:40 +08:00
|
|
|
return err;
|
2010-02-19 10:00:42 +08:00
|
|
|
}
|
|
|
|
|
2006-08-24 13:49:28 +08:00
|
|
|
c.data.type = type;
|
2005-06-19 13:44:37 +08:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-19 13:42:13 +08:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
2012-09-08 04:12:54 +08:00
|
|
|
c.portid = nlh->nlmsg_pid;
|
2008-11-26 09:50:36 +08:00
|
|
|
c.net = net;
|
2005-06-19 13:42:13 +08:00
|
|
|
km_policy_notify(NULL, 0, &c);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2006-03-21 11:17:25 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2006-03-21 11:17:25 +08:00
|
|
|
struct xfrm_policy *xp;
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_user_polexpire *up = nlmsg_data(nlh);
|
2006-03-21 11:17:25 +08:00
|
|
|
struct xfrm_userpolicy_info *p = &up->pol;
|
2006-11-28 04:59:30 +08:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2006-03-21 11:17:25 +08:00
|
|
|
int err = -ENOENT;
|
2010-02-22 19:33:00 +08:00
|
|
|
struct xfrm_mark m;
|
2018-06-12 20:07:07 +08:00
|
|
|
u32 if_id = 0;
|
2006-03-21 11:17:25 +08:00
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = copy_from_user_policy_type(&type, attrs);
|
2006-08-24 13:49:28 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2010-03-31 08:17:04 +08:00
|
|
|
err = verify_policy_dir(p->dir);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2018-06-12 20:07:07 +08:00
|
|
|
if (attrs[XFRMA_IF_ID])
|
|
|
|
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
|
|
2020-06-22 16:40:29 +08:00
|
|
|
xfrm_mark_get(attrs, &m);
|
|
|
|
|
2006-03-21 11:17:25 +08:00
|
|
|
if (p->index)
|
2020-06-22 16:40:29 +08:00
|
|
|
xp = xfrm_policy_byid(net, &m, if_id, type, p->dir, p->index,
|
|
|
|
0, &err);
|
2006-03-21 11:17:25 +08:00
|
|
|
else {
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_SEC_CTX];
|
2008-04-13 10:07:52 +08:00
|
|
|
struct xfrm_sec_ctx *ctx;
|
2006-03-21 11:17:25 +08:00
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
err = verify_sec_ctx_len(attrs);
|
2006-03-21 11:17:25 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2008-04-15 05:47:48 +08:00
|
|
|
ctx = NULL;
|
2006-03-21 11:17:25 +08:00
|
|
|
if (rt) {
|
2007-08-23 05:01:33 +08:00
|
|
|
struct xfrm_user_sec_ctx *uctx = nla_data(rt);
|
2006-03-21 11:17:25 +08:00
|
|
|
|
2014-03-07 19:44:19 +08:00
|
|
|
err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
|
2008-04-13 10:07:52 +08:00
|
|
|
if (err)
|
2006-03-21 11:17:25 +08:00
|
|
|
return err;
|
2008-04-15 05:47:48 +08:00
|
|
|
}
|
2020-06-22 16:40:29 +08:00
|
|
|
xp = xfrm_policy_bysel_ctx(net, &m, if_id, type, p->dir,
|
2010-02-22 19:32:59 +08:00
|
|
|
&p->sel, ctx, 0, &err);
|
2008-04-13 10:07:52 +08:00
|
|
|
security_xfrm_policy_free(ctx);
|
2006-03-21 11:17:25 +08:00
|
|
|
}
|
|
|
|
if (xp == NULL)
|
2007-03-08 07:37:58 +08:00
|
|
|
return -ENOENT;
|
2008-04-13 10:07:52 +08:00
|
|
|
|
2010-03-31 08:17:05 +08:00
|
|
|
if (unlikely(xp->walk.dead))
|
2006-03-21 11:17:25 +08:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
if (up->hard) {
|
|
|
|
xfrm_policy_delete(xp, p->dir);
|
2014-04-22 20:48:30 +08:00
|
|
|
xfrm_audit_policy_delete(xp, 1, true);
|
2006-03-21 11:17:25 +08:00
|
|
|
}
|
2012-09-08 05:17:17 +08:00
|
|
|
km_policy_expired(xp, p->dir, up->hard, nlh->nlmsg_pid);
|
2006-03-21 11:17:25 +08:00
|
|
|
|
|
|
|
out:
|
|
|
|
xfrm_pol_put(xp);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2006-03-21 11:17:03 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2006-03-21 11:17:03 +08:00
|
|
|
struct xfrm_state *x;
|
|
|
|
int err;
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_user_expire *ue = nlmsg_data(nlh);
|
2006-03-21 11:17:03 +08:00
|
|
|
struct xfrm_usersa_info *p = &ue->state;
|
2010-02-22 19:32:59 +08:00
|
|
|
struct xfrm_mark m;
|
2010-08-31 13:54:00 +08:00
|
|
|
u32 mark = xfrm_mark_get(attrs, &m);
|
2006-03-21 11:17:03 +08:00
|
|
|
|
2010-02-22 19:32:59 +08:00
|
|
|
x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family);
|
2006-03-21 11:17:03 +08:00
|
|
|
|
2007-02-27 06:52:21 +08:00
|
|
|
err = -ENOENT;
|
2006-03-21 11:17:03 +08:00
|
|
|
if (x == NULL)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
spin_lock_bh(&x->lock);
|
2007-02-27 06:52:21 +08:00
|
|
|
err = -EINVAL;
|
2006-03-21 11:17:03 +08:00
|
|
|
if (x->km.state != XFRM_STATE_VALID)
|
|
|
|
goto out;
|
2012-09-08 05:17:17 +08:00
|
|
|
km_state_expired(x, ue->hard, nlh->nlmsg_pid);
|
2006-03-21 11:17:03 +08:00
|
|
|
|
2006-11-28 03:11:54 +08:00
|
|
|
if (ue->hard) {
|
2006-03-21 11:17:03 +08:00
|
|
|
__xfrm_state_delete(x);
|
2014-04-22 20:48:30 +08:00
|
|
|
xfrm_audit_state_delete(x, 1, true);
|
2006-11-28 03:11:54 +08:00
|
|
|
}
|
2007-02-27 06:52:21 +08:00
|
|
|
err = 0;
|
2006-03-21 11:17:03 +08:00
|
|
|
out:
|
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-03 07:22:30 +08:00
|
|
|
static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
struct xfrm_policy *xp;
|
|
|
|
struct xfrm_user_tmpl *ut;
|
|
|
|
int i;
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_TMPL];
|
2010-02-22 19:32:59 +08:00
|
|
|
struct xfrm_mark mark;
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_user_acquire *ua = nlmsg_data(nlh);
|
2008-11-26 09:50:08 +08:00
|
|
|
struct xfrm_state *x = xfrm_state_alloc(net);
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
int err = -ENOMEM;
|
|
|
|
|
|
|
|
if (!x)
|
2008-12-15 15:16:22 +08:00
|
|
|
goto nomem;
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
|
2010-02-22 19:32:59 +08:00
|
|
|
xfrm_mark_get(attrs, &mark);
|
|
|
|
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
err = verify_newpolicy_info(&ua->policy);
|
2020-02-09 21:16:38 +08:00
|
|
|
if (err)
|
|
|
|
goto free_state;
|
|
|
|
err = verify_sec_ctx_len(attrs);
|
2008-12-15 15:16:22 +08:00
|
|
|
if (err)
|
2016-07-27 14:03:18 +08:00
|
|
|
goto free_state;
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
|
|
|
|
/* build an XP */
|
2008-11-26 09:50:08 +08:00
|
|
|
xp = xfrm_policy_construct(net, &ua->policy, attrs, &err);
|
2008-12-15 15:16:22 +08:00
|
|
|
if (!xp)
|
|
|
|
goto free_state;
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
|
|
|
|
memcpy(&x->id, &ua->id, sizeof(ua->id));
|
|
|
|
memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr));
|
|
|
|
memcpy(&x->sel, &ua->sel, sizeof(ua->sel));
|
2010-02-22 19:32:59 +08:00
|
|
|
xp->mark.m = x->mark.m = mark.m;
|
|
|
|
xp->mark.v = x->mark.v = mark.v;
|
2007-08-23 05:01:33 +08:00
|
|
|
ut = nla_data(rt);
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
/* extract the templates and for each call km_key */
|
|
|
|
for (i = 0; i < xp->xfrm_nr; i++, ut++) {
|
|
|
|
struct xfrm_tmpl *t = &xp->xfrm_vec[i];
|
|
|
|
memcpy(&x->id, &t->id, sizeof(x->id));
|
|
|
|
x->props.mode = t->mode;
|
|
|
|
x->props.reqid = t->reqid;
|
|
|
|
x->props.family = ut->family;
|
|
|
|
t->aalgos = ua->aalgos;
|
|
|
|
t->ealgos = ua->ealgos;
|
|
|
|
t->calgos = ua->calgos;
|
|
|
|
err = km_query(x, t, xp);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-22 04:09:23 +08:00
|
|
|
xfrm_state_free(x);
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
kfree(xp);
|
|
|
|
|
|
|
|
return 0;
|
2008-12-15 15:16:22 +08:00
|
|
|
|
|
|
|
free_state:
|
2018-11-22 04:09:23 +08:00
|
|
|
xfrm_state_free(x);
|
2008-12-15 15:16:22 +08:00
|
|
|
nomem:
|
|
|
|
return err;
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
}
|
|
|
|
|
2007-02-09 05:12:32 +08:00
|
|
|
#ifdef CONFIG_XFRM_MIGRATE
|
|
|
|
static int copy_from_user_migrate(struct xfrm_migrate *ma,
|
2008-10-06 04:33:42 +08:00
|
|
|
struct xfrm_kmaddress *k,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs, int *num)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr *rt = attrs[XFRMA_MIGRATE];
|
2007-02-09 05:12:32 +08:00
|
|
|
struct xfrm_user_migrate *um;
|
|
|
|
int i, num_migrate;
|
|
|
|
|
2008-10-06 04:33:42 +08:00
|
|
|
if (k != NULL) {
|
|
|
|
struct xfrm_user_kmaddress *uk;
|
|
|
|
|
|
|
|
uk = nla_data(attrs[XFRMA_KMADDRESS]);
|
|
|
|
memcpy(&k->local, &uk->local, sizeof(k->local));
|
|
|
|
memcpy(&k->remote, &uk->remote, sizeof(k->remote));
|
|
|
|
k->family = uk->family;
|
|
|
|
k->reserved = uk->reserved;
|
|
|
|
}
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
um = nla_data(rt);
|
|
|
|
num_migrate = nla_len(rt) / sizeof(*um);
|
2007-02-09 05:12:32 +08:00
|
|
|
|
|
|
|
if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
for (i = 0; i < num_migrate; i++, um++, ma++) {
|
|
|
|
memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr));
|
|
|
|
memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr));
|
|
|
|
memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr));
|
|
|
|
memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr));
|
|
|
|
|
|
|
|
ma->proto = um->proto;
|
|
|
|
ma->mode = um->mode;
|
|
|
|
ma->reqid = um->reqid;
|
|
|
|
|
|
|
|
ma->old_family = um->old_family;
|
|
|
|
ma->new_family = um->new_family;
|
|
|
|
}
|
|
|
|
|
|
|
|
*num = i;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
2007-08-23 04:53:52 +08:00
|
|
|
struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
|
2007-02-09 05:12:32 +08:00
|
|
|
struct xfrm_migrate m[XFRM_MAX_DEPTH];
|
2008-10-06 04:33:42 +08:00
|
|
|
struct xfrm_kmaddress km, *kmp;
|
2007-02-09 05:12:32 +08:00
|
|
|
u8 type;
|
|
|
|
int err;
|
|
|
|
int n = 0;
|
2013-11-07 17:47:49 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2017-06-06 18:12:13 +08:00
|
|
|
struct xfrm_encap_tmpl *encap = NULL;
|
xfrm: Check if_id in xfrm_migrate
This patch enables distinguishing SAs and SPs based on if_id during
the xfrm_migrate flow. This ensures support for xfrm interfaces
throughout the SA/SP lifecycle.
When there are multiple existing SPs with the same direction,
the same xfrm_selector and different endpoint addresses,
xfrm_migrate might fail with ENODATA.
Specifically, the code path for performing xfrm_migrate is:
Stage 1: find policy to migrate with
xfrm_migrate_policy_find(sel, dir, type, net)
Stage 2: find and update state(s) with
xfrm_migrate_state_find(mp, net)
Stage 3: update endpoint address(es) of template(s) with
xfrm_policy_migrate(pol, m, num_migrate)
Currently "Stage 1" always returns the first xfrm_policy that
matches, and "Stage 3" looks for the xfrm_tmpl that matches the
old endpoint address. Thus if there are multiple xfrm_policy
with same selector, direction, type and net, "Stage 1" might
rertun a wrong xfrm_policy and "Stage 3" will fail with ENODATA
because it cannot find a xfrm_tmpl with the matching endpoint
address.
The fix is to allow userspace to pass an if_id and add if_id
to the matching rule in Stage 1 and Stage 2 since if_id is a
unique ID for xfrm_policy and xfrm_state. For compatibility,
if_id will only be checked if the attribute is set.
Tested with additions to Android's kernel unit test suite:
https://android-review.googlesource.com/c/kernel/tests/+/1668886
Signed-off-by: Yan Yan <evitayan@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2022-01-19 08:00:13 +08:00
|
|
|
u32 if_id = 0;
|
2007-02-09 05:12:32 +08:00
|
|
|
|
2007-08-23 05:00:40 +08:00
|
|
|
if (attrs[XFRMA_MIGRATE] == NULL)
|
2007-08-23 04:59:04 +08:00
|
|
|
return -EINVAL;
|
2007-02-09 05:12:32 +08:00
|
|
|
|
2008-10-06 04:33:42 +08:00
|
|
|
kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;
|
|
|
|
|
2007-08-23 05:01:33 +08:00
|
|
|
err = copy_from_user_policy_type(&type, attrs);
|
2007-02-09 05:12:32 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2008-10-06 04:33:42 +08:00
|
|
|
err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n);
|
2007-02-09 05:12:32 +08:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
2017-06-06 18:12:13 +08:00
|
|
|
if (attrs[XFRMA_ENCAP]) {
|
|
|
|
encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]),
|
|
|
|
sizeof(*encap), GFP_KERNEL);
|
|
|
|
if (!encap)
|
2021-02-04 15:42:54 +08:00
|
|
|
return -ENOMEM;
|
2017-06-06 18:12:13 +08:00
|
|
|
}
|
2007-02-09 05:12:32 +08:00
|
|
|
|
xfrm: Check if_id in xfrm_migrate
This patch enables distinguishing SAs and SPs based on if_id during
the xfrm_migrate flow. This ensures support for xfrm interfaces
throughout the SA/SP lifecycle.
When there are multiple existing SPs with the same direction,
the same xfrm_selector and different endpoint addresses,
xfrm_migrate might fail with ENODATA.
Specifically, the code path for performing xfrm_migrate is:
Stage 1: find policy to migrate with
xfrm_migrate_policy_find(sel, dir, type, net)
Stage 2: find and update state(s) with
xfrm_migrate_state_find(mp, net)
Stage 3: update endpoint address(es) of template(s) with
xfrm_policy_migrate(pol, m, num_migrate)
Currently "Stage 1" always returns the first xfrm_policy that
matches, and "Stage 3" looks for the xfrm_tmpl that matches the
old endpoint address. Thus if there are multiple xfrm_policy
with same selector, direction, type and net, "Stage 1" might
rertun a wrong xfrm_policy and "Stage 3" will fail with ENODATA
because it cannot find a xfrm_tmpl with the matching endpoint
address.
The fix is to allow userspace to pass an if_id and add if_id
to the matching rule in Stage 1 and Stage 2 since if_id is a
unique ID for xfrm_policy and xfrm_state. For compatibility,
if_id will only be checked if the attribute is set.
Tested with additions to Android's kernel unit test suite:
https://android-review.googlesource.com/c/kernel/tests/+/1668886
Signed-off-by: Yan Yan <evitayan@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2022-01-19 08:00:13 +08:00
|
|
|
if (attrs[XFRMA_IF_ID])
|
|
|
|
if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
|
|
|
|
|
|
|
|
err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id);
|
2017-06-06 18:12:13 +08:00
|
|
|
|
|
|
|
kfree(encap);
|
|
|
|
|
|
|
|
return err;
|
2007-02-09 05:12:32 +08:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2007-08-23 05:01:33 +08:00
|
|
|
struct nlattr **attrs)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_XFRM_MIGRATE
|
2011-02-24 13:28:01 +08:00
|
|
|
static int copy_to_user_migrate(const struct xfrm_migrate *m, struct sk_buff *skb)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
|
|
|
struct xfrm_user_migrate um;
|
|
|
|
|
|
|
|
memset(&um, 0, sizeof(um));
|
|
|
|
um.proto = m->proto;
|
|
|
|
um.mode = m->mode;
|
|
|
|
um.reqid = m->reqid;
|
|
|
|
um.old_family = m->old_family;
|
|
|
|
memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr));
|
|
|
|
memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr));
|
|
|
|
um.new_family = m->new_family;
|
|
|
|
memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr));
|
|
|
|
memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr));
|
|
|
|
|
2007-08-23 04:55:43 +08:00
|
|
|
return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um);
|
2007-02-09 05:12:32 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:28:01 +08:00
|
|
|
static int copy_to_user_kmaddress(const struct xfrm_kmaddress *k, struct sk_buff *skb)
|
2008-10-06 04:33:42 +08:00
|
|
|
{
|
|
|
|
struct xfrm_user_kmaddress uk;
|
|
|
|
|
|
|
|
memset(&uk, 0, sizeof(uk));
|
|
|
|
uk.family = k->family;
|
|
|
|
uk.reserved = k->reserved;
|
|
|
|
memcpy(&uk.local, &k->local, sizeof(uk.local));
|
2008-11-03 17:30:23 +08:00
|
|
|
memcpy(&uk.remote, &k->remote, sizeof(uk.remote));
|
2008-10-06 04:33:42 +08:00
|
|
|
|
|
|
|
return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk);
|
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_migrate_msgsize(int num_migrate, int with_kma,
|
|
|
|
int with_encp)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id))
|
2008-10-06 04:33:42 +08:00
|
|
|
+ (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0)
|
2017-06-06 18:12:14 +08:00
|
|
|
+ (with_encp ? nla_total_size(sizeof(struct xfrm_encap_tmpl)) : 0)
|
2008-10-06 04:33:42 +08:00
|
|
|
+ nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate)
|
|
|
|
+ userpolicy_type_attrsize();
|
2007-08-23 04:57:39 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:28:01 +08:00
|
|
|
static int build_migrate(struct sk_buff *skb, const struct xfrm_migrate *m,
|
|
|
|
int num_migrate, const struct xfrm_kmaddress *k,
|
2017-06-06 18:12:14 +08:00
|
|
|
const struct xfrm_selector *sel,
|
|
|
|
const struct xfrm_encap_tmpl *encap, u8 dir, u8 type)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
2011-02-24 13:28:01 +08:00
|
|
|
const struct xfrm_migrate *mp;
|
2007-02-09 05:12:32 +08:00
|
|
|
struct xfrm_userpolicy_id *pol_id;
|
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int i, err;
|
2007-02-09 05:12:32 +08:00
|
|
|
|
2007-08-23 03:46:53 +08:00
|
|
|
nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0);
|
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2007-02-09 05:12:32 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
pol_id = nlmsg_data(nlh);
|
2007-02-09 05:12:32 +08:00
|
|
|
/* copy data from selector, dir, and type to the pol_id */
|
|
|
|
memset(pol_id, 0, sizeof(*pol_id));
|
|
|
|
memcpy(&pol_id->sel, sel, sizeof(pol_id->sel));
|
|
|
|
pol_id->dir = dir;
|
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
if (k != NULL) {
|
|
|
|
err = copy_to_user_kmaddress(k, skb);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
|
|
|
}
|
2017-06-06 18:12:14 +08:00
|
|
|
if (encap) {
|
|
|
|
err = nla_put(skb, XFRMA_ENCAP, sizeof(*encap), encap);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
|
|
|
}
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_policy_type(type, skb);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
2007-02-09 05:12:32 +08:00
|
|
|
for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_migrate(mp, skb);
|
|
|
|
if (err)
|
|
|
|
goto out_cancel;
|
2007-02-09 05:12:32 +08:00
|
|
|
}
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2012-06-28 12:57:03 +08:00
|
|
|
|
|
|
|
out_cancel:
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_cancel(skb, nlh);
|
2012-06-28 12:57:03 +08:00
|
|
|
return err;
|
2007-02-09 05:12:32 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:28:01 +08:00
|
|
|
static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
|
|
const struct xfrm_migrate *m, int num_migrate,
|
2017-06-06 18:12:14 +08:00
|
|
|
const struct xfrm_kmaddress *k,
|
|
|
|
const struct xfrm_encap_tmpl *encap)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
2008-11-26 09:38:20 +08:00
|
|
|
struct net *net = &init_net;
|
2007-02-09 05:12:32 +08:00
|
|
|
struct sk_buff *skb;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2007-02-09 05:12:32 +08:00
|
|
|
|
2017-06-06 18:12:14 +08:00
|
|
|
skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k, !!encap),
|
|
|
|
GFP_ATOMIC);
|
2007-02-09 05:12:32 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* build migrate */
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_migrate(skb, m, num_migrate, k, sel, encap, dir, type);
|
|
|
|
BUG_ON(err < 0);
|
2007-02-09 05:12:32 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE);
|
2007-02-09 05:12:32 +08:00
|
|
|
}
|
|
|
|
#else
|
2011-02-24 13:28:01 +08:00
|
|
|
static int xfrm_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
|
|
|
|
const struct xfrm_migrate *m, int num_migrate,
|
2017-06-06 18:12:14 +08:00
|
|
|
const struct xfrm_kmaddress *k,
|
|
|
|
const struct xfrm_encap_tmpl *encap)
|
2007-02-09 05:12:32 +08:00
|
|
|
{
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
#endif
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2007-08-23 04:58:18 +08:00
|
|
|
#define XMSGSIZE(type) sizeof(struct type)
|
2005-05-04 05:26:40 +08:00
|
|
|
|
2020-09-21 22:36:52 +08:00
|
|
|
const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
|
2009-01-21 01:49:51 +08:00
|
|
|
[XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
|
|
|
|
[XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id),
|
|
|
|
[XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
|
|
|
|
[XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
|
|
|
|
[XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
|
|
|
|
[XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info),
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
[XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
|
2006-03-21 11:17:03 +08:00
|
|
|
[XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
|
2009-01-21 01:49:51 +08:00
|
|
|
[XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
|
2006-03-21 11:17:25 +08:00
|
|
|
[XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
|
2007-08-23 04:58:18 +08:00
|
|
|
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0,
|
2006-03-21 11:16:12 +08:00
|
|
|
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
|
|
|
|
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
|
2006-08-24 11:44:06 +08:00
|
|
|
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
|
2007-02-09 05:12:32 +08:00
|
|
|
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
|
2007-08-23 04:58:18 +08:00
|
|
|
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32),
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
[XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
|
2007-08-23 04:58:18 +08:00
|
|
|
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32),
|
2021-07-18 15:11:06 +08:00
|
|
|
[XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
|
|
|
|
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_default),
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
2020-09-21 22:36:52 +08:00
|
|
|
EXPORT_SYMBOL_GPL(xfrm_msg_min);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-04 05:26:40 +08:00
|
|
|
#undef XMSGSIZE
|
|
|
|
|
2020-09-21 22:36:55 +08:00
|
|
|
const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
|
2010-02-09 11:59:38 +08:00
|
|
|
[XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)},
|
|
|
|
[XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)},
|
|
|
|
[XFRMA_LASTUSED] = { .type = NLA_U64},
|
|
|
|
[XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)},
|
2008-01-29 11:37:29 +08:00
|
|
|
[XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) },
|
2007-08-23 04:59:04 +08:00
|
|
|
[XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) },
|
|
|
|
[XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) },
|
|
|
|
[XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) },
|
|
|
|
[XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) },
|
|
|
|
[XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) },
|
|
|
|
[XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) },
|
|
|
|
[XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) },
|
|
|
|
[XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) },
|
|
|
|
[XFRMA_REPLAY_THRESH] = { .type = NLA_U32 },
|
|
|
|
[XFRMA_ETIMER_THRESH] = { .type = NLA_U32 },
|
|
|
|
[XFRMA_SRCADDR] = { .len = sizeof(xfrm_address_t) },
|
|
|
|
[XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) },
|
|
|
|
[XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)},
|
|
|
|
[XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) },
|
2008-10-06 04:33:42 +08:00
|
|
|
[XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) },
|
2010-02-22 19:32:59 +08:00
|
|
|
[XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) },
|
2010-12-08 12:37:49 +08:00
|
|
|
[XFRMA_TFCPAD] = { .type = NLA_U32 },
|
2011-03-08 08:10:27 +08:00
|
|
|
[XFRMA_REPLAY_ESN_VAL] = { .len = sizeof(struct xfrm_replay_state_esn) },
|
2013-02-22 17:54:54 +08:00
|
|
|
[XFRMA_SA_EXTRA_FLAGS] = { .type = NLA_U32 },
|
2014-02-14 22:30:36 +08:00
|
|
|
[XFRMA_PROTO] = { .type = NLA_U8 },
|
2014-03-07 01:24:29 +08:00
|
|
|
[XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) },
|
2017-04-14 16:06:10 +08:00
|
|
|
[XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) },
|
2018-06-12 18:44:26 +08:00
|
|
|
[XFRMA_SET_MARK] = { .type = NLA_U32 },
|
|
|
|
[XFRMA_SET_MARK_MASK] = { .type = NLA_U32 },
|
2018-06-12 20:07:07 +08:00
|
|
|
[XFRMA_IF_ID] = { .type = NLA_U32 },
|
2007-08-23 04:59:04 +08:00
|
|
|
};
|
2020-09-21 22:36:55 +08:00
|
|
|
EXPORT_SYMBOL_GPL(xfrma_policy);
|
2007-08-23 04:59:04 +08:00
|
|
|
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = {
|
|
|
|
[XFRMA_SPD_IPV4_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
|
|
|
|
[XFRMA_SPD_IPV6_HTHRESH] = { .len = sizeof(struct xfrmu_spdhthresh) },
|
|
|
|
};
|
|
|
|
|
2013-02-24 21:10:27 +08:00
|
|
|
static const struct xfrm_link {
|
2007-08-23 05:01:33 +08:00
|
|
|
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
|
2017-10-19 20:51:10 +08:00
|
|
|
int (*start)(struct netlink_callback *);
|
2005-04-17 06:20:36 +08:00
|
|
|
int (*dump)(struct sk_buff *, struct netlink_callback *);
|
2008-02-29 13:31:08 +08:00
|
|
|
int (*done)(struct netlink_callback *);
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
const struct nla_policy *nla_pol;
|
|
|
|
int nla_max;
|
2005-05-04 05:26:40 +08:00
|
|
|
} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
|
|
|
|
[XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
|
|
|
|
[XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
|
|
|
|
[XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
|
2008-02-29 13:31:08 +08:00
|
|
|
.dump = xfrm_dump_sa,
|
|
|
|
.done = xfrm_dump_sa_done },
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
|
|
|
|
[XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy },
|
|
|
|
[XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
|
2017-10-19 20:51:10 +08:00
|
|
|
.start = xfrm_dump_policy_start,
|
2008-02-29 13:31:08 +08:00
|
|
|
.dump = xfrm_dump_policy,
|
|
|
|
.done = xfrm_dump_policy_done },
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
|
[IPSEC]: Sync series - acquire insert
This introduces a feature similar to the one described in RFC 2367:
"
... the application needing an SA sends a PF_KEY
SADB_ACQUIRE message down to the Key Engine, which then either
returns an error or sends a similar SADB_ACQUIRE message up to one or
more key management applications capable of creating such SAs.
...
...
The third is where an application-layer consumer of security
associations (e.g. an OSPFv2 or RIPv2 daemon) needs a security
association.
Send an SADB_ACQUIRE message from a user process to the kernel.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The kernel returns an SADB_ACQUIRE message to registered
sockets.
<base, address(SD), (address(P),) (identity(SD),) (sensitivity,)
proposal>
The user-level consumer waits for an SADB_UPDATE or SADB_ADD
message for its particular type, and then can use that
association by using SADB_GET messages.
"
An app such as OSPF could then use ipsec KM to get keys
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
2006-03-21 11:16:40 +08:00
|
|
|
[XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire },
|
2006-03-21 11:17:03 +08:00
|
|
|
[XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
|
|
|
|
[XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
|
2006-03-21 11:17:25 +08:00
|
|
|
[XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
|
2005-05-04 05:26:40 +08:00
|
|
|
[XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa },
|
|
|
|
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy },
|
2006-03-21 11:16:12 +08:00
|
|
|
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae },
|
|
|
|
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
|
2007-02-09 05:12:32 +08:00
|
|
|
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
|
2007-04-27 05:12:15 +08:00
|
|
|
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
|
xfrm: configure policy hash table thresholds by netlink
Enable to specify local and remote prefix length thresholds for the
policy hash table via a netlink XFRM_MSG_NEWSPDINFO message.
prefix length thresholds are specified by XFRMA_SPD_IPV4_HTHRESH and
XFRMA_SPD_IPV6_HTHRESH optional attributes (struct xfrmu_spdhthresh).
example:
struct xfrmu_spdhthresh thresh4 = {
.lbits = 0;
.rbits = 24;
};
struct xfrmu_spdhthresh thresh6 = {
.lbits = 0;
.rbits = 56;
};
struct nlmsghdr *hdr;
struct nl_msg *msg;
msg = nlmsg_alloc();
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, XFRMA_SPD_IPV4_HTHRESH, sizeof(__u32), NLM_F_REQUEST);
nla_put(msg, XFRMA_SPD_IPV4_HTHRESH, sizeof(thresh4), &thresh4);
nla_put(msg, XFRMA_SPD_IPV6_HTHRESH, sizeof(thresh6), &thresh6);
nla_send_auto(sk, msg);
The numbers are the policy selector minimum prefix lengths to put a
policy in the hash table.
- lbits is the local threshold (source address for out policies,
destination address for in and fwd policies).
- rbits is the remote threshold (destination address for out
policies, source address for in and fwd policies).
The default values are:
XFRMA_SPD_IPV4_HTHRESH: 32 32
XFRMA_SPD_IPV6_HTHRESH: 128 128
Dynamic re-building of the SPD is performed when the thresholds values
are changed.
The current thresholds can be read via a XFRM_MSG_GETSPDINFO request:
the kernel replies to XFRM_MSG_GETSPDINFO requests by an
XFRM_MSG_NEWSPDINFO message, with both attributes
XFRMA_SPD_IPV4_HTHRESH and XFRMA_SPD_IPV6_HTHRESH.
Signed-off-by: Christophe Gouault <christophe.gouault@6wind.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
2014-08-29 22:16:05 +08:00
|
|
|
[XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_set_spdinfo,
|
|
|
|
.nla_pol = xfrma_spd_policy,
|
|
|
|
.nla_max = XFRMA_SPD_MAX },
|
2007-04-29 12:20:32 +08:00
|
|
|
[XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
|
2021-07-18 15:11:06 +08:00
|
|
|
[XFRM_MSG_SETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_set_default },
|
|
|
|
[XFRM_MSG_GETDEFAULT - XFRM_MSG_BASE] = { .doit = xfrm_get_default },
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2017-04-12 20:34:04 +08:00
|
|
|
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct netlink_ext_ack *extack)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:38:20 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-08-23 05:00:40 +08:00
|
|
|
struct nlattr *attrs[XFRMA_MAX+1];
|
2013-02-24 21:10:27 +08:00
|
|
|
const struct xfrm_link *link;
|
2020-09-21 22:36:55 +08:00
|
|
|
struct nlmsghdr *nlh64 = NULL;
|
2007-08-23 04:58:18 +08:00
|
|
|
int type, err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
type = nlh->nlmsg_type;
|
|
|
|
if (type > XFRM_MSG_MAX)
|
2007-03-23 14:30:12 +08:00
|
|
|
return -EINVAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
type -= XFRM_MSG_BASE;
|
|
|
|
link = &xfrm_dispatch[type];
|
|
|
|
|
|
|
|
/* All operations require privileges, even GET */
|
2014-04-24 05:29:27 +08:00
|
|
|
if (!netlink_net_capable(skb, CAP_NET_ADMIN))
|
2007-03-23 14:30:12 +08:00
|
|
|
return -EPERM;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2020-09-21 22:36:55 +08:00
|
|
|
if (in_compat_syscall()) {
|
|
|
|
struct xfrm_translator *xtr = xfrm_get_translator();
|
|
|
|
|
|
|
|
if (!xtr)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
nlh64 = xtr->rcv_msg_compat(nlh, link->nla_max,
|
|
|
|
link->nla_pol, extack);
|
|
|
|
xfrm_put_translator(xtr);
|
|
|
|
if (IS_ERR(nlh64))
|
|
|
|
return PTR_ERR(nlh64);
|
|
|
|
if (nlh64)
|
|
|
|
nlh = nlh64;
|
|
|
|
}
|
|
|
|
|
2005-05-04 05:26:40 +08:00
|
|
|
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
|
|
|
|
type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
|
2011-01-19 04:40:38 +08:00
|
|
|
(nlh->nlmsg_flags & NLM_F_DUMP)) {
|
2020-09-21 22:36:55 +08:00
|
|
|
struct netlink_dump_control c = {
|
|
|
|
.start = link->start,
|
|
|
|
.dump = link->dump,
|
|
|
|
.done = link->done,
|
|
|
|
};
|
2005-11-10 09:25:54 +08:00
|
|
|
|
2020-09-21 22:36:55 +08:00
|
|
|
if (link->dump == NULL) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err;
|
2012-02-24 22:30:15 +08:00
|
|
|
}
|
2020-09-21 22:36:55 +08:00
|
|
|
|
|
|
|
err = netlink_dump_start(net->xfrm.nlsk, skb, nlh, &c);
|
|
|
|
goto err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
netlink: make validation more configurable for future strictness
We currently have two levels of strict validation:
1) liberal (default)
- undefined (type >= max) & NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
- garbage at end of message accepted
2) strict (opt-in)
- NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
Split out parsing strictness into four different options:
* TRAILING - check that there's no trailing data after parsing
attributes (in message or nested)
* MAXTYPE - reject attrs > max known type
* UNSPEC - reject attributes with NLA_UNSPEC policy entries
* STRICT_ATTRS - strictly validate attribute size
The default for future things should be *everything*.
The current *_strict() is a combination of TRAILING and MAXTYPE,
and is renamed to _deprecated_strict().
The current regular parsing has none of this, and is renamed to
*_parse_deprecated().
Additionally it allows us to selectively set one of the new flags
even on old policies. Notably, the UNSPEC flag could be useful in
this case, since it can be arranged (by filling in the policy) to
not be an incompatible userspace ABI change, but would then going
forward prevent forgetting attribute entries. Similar can apply
to the POLICY flag.
We end up with the following renames:
* nla_parse -> nla_parse_deprecated
* nla_parse_strict -> nla_parse_deprecated_strict
* nlmsg_parse -> nlmsg_parse_deprecated
* nlmsg_parse_strict -> nlmsg_parse_deprecated_strict
* nla_parse_nested -> nla_parse_nested_deprecated
* nla_validate_nested -> nla_validate_nested_deprecated
Using spatch, of course:
@@
expression TB, MAX, HEAD, LEN, POL, EXT;
@@
-nla_parse(TB, MAX, HEAD, LEN, POL, EXT)
+nla_parse_deprecated(TB, MAX, HEAD, LEN, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression TB, MAX, NLA, POL, EXT;
@@
-nla_parse_nested(TB, MAX, NLA, POL, EXT)
+nla_parse_nested_deprecated(TB, MAX, NLA, POL, EXT)
@@
expression START, MAX, POL, EXT;
@@
-nla_validate_nested(START, MAX, POL, EXT)
+nla_validate_nested_deprecated(START, MAX, POL, EXT)
@@
expression NLH, HDRLEN, MAX, POL, EXT;
@@
-nlmsg_validate(NLH, HDRLEN, MAX, POL, EXT)
+nlmsg_validate_deprecated(NLH, HDRLEN, MAX, POL, EXT)
For this patch, don't actually add the strict, non-renamed versions
yet so that it breaks compile if I get it wrong.
Also, while at it, make nla_validate and nla_parse go down to a
common __nla_validate_parse() function to avoid code duplication.
Ultimately, this allows us to have very strict validation for every
new caller of nla_parse()/nlmsg_parse() etc as re-introduced in the
next patch, while existing things will continue to work as is.
In effect then, this adds fully strict validation for any new command.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-04-26 20:07:28 +08:00
|
|
|
err = nlmsg_parse_deprecated(nlh, xfrm_msg_min[type], attrs,
|
|
|
|
link->nla_max ? : XFRMA_MAX,
|
|
|
|
link->nla_pol ? : xfrma_policy, extack);
|
2007-08-23 04:58:18 +08:00
|
|
|
if (err < 0)
|
2020-09-21 22:36:55 +08:00
|
|
|
goto err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2020-09-21 22:36:55 +08:00
|
|
|
if (link->doit == NULL) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = link->doit(skb, nlh, attrs);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2021-06-25 18:23:54 +08:00
|
|
|
/* We need to free skb allocated in xfrm_alloc_compat() before
|
|
|
|
* returning from this function, because consume_skb() won't take
|
|
|
|
* care of frag_list since netlink destructor sets
|
|
|
|
* sbk->head to NULL. (see netlink_skb_destructor())
|
|
|
|
*/
|
|
|
|
if (skb_has_frag_list(skb)) {
|
|
|
|
kfree_skb(skb_shinfo(skb)->frag_list);
|
|
|
|
skb_shinfo(skb)->frag_list = NULL;
|
|
|
|
}
|
|
|
|
|
2020-09-21 22:36:55 +08:00
|
|
|
err:
|
|
|
|
kvfree(nlh64);
|
|
|
|
return err;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2007-10-11 12:15:29 +08:00
|
|
|
static void xfrm_netlink_rcv(struct sk_buff *skb)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2013-11-07 17:47:50 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
|
|
|
|
|
mutex_lock(&net->xfrm.xfrm_cfg_mutex);
|
2007-10-11 12:15:29 +08:00
|
|
|
netlink_rcv_skb(skb, &xfrm_user_rcv_msg);
|
2013-11-07 17:47:50 +08:00
|
|
|
mutex_unlock(&net->xfrm.xfrm_cfg_mutex);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_expire_msgsize(void)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
2010-02-22 19:32:59 +08:00
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_user_expire))
|
|
|
|
+ nla_total_size(sizeof(struct xfrm_mark));
|
2007-08-23 04:57:39 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, const struct km_event *c)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct xfrm_user_expire *ue;
|
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0);
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
ue = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
copy_to_user_state(x, &ue->state);
|
2006-03-21 11:16:12 +08:00
|
|
|
ue->hard = (c->data.hard != 0) ? 1 : 0;
|
2017-08-26 23:08:59 +08:00
|
|
|
/* clear the padding bytes */
|
2021-06-17 23:34:19 +08:00
|
|
|
memset_after(ue, 0, hard);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
err = xfrm_mark_put(skb, &x->mark);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2010-02-22 19:32:59 +08:00
|
|
|
|
2018-06-12 20:07:07 +08:00
|
|
|
err = xfrm_if_id_put(skb, x->if_id);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_exp_state_notify(struct xfrm_state *x, const struct km_event *c)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = xs_net(x);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct sk_buff *skb;
|
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2010-02-22 19:32:59 +08:00
|
|
|
if (build_expire(skb, x, c) < 0) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_aevent_state_notify(struct xfrm_state *x, const struct km_event *c)
|
2006-03-21 11:16:12 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = xs_net(x);
|
2006-03-21 11:16:12 +08:00
|
|
|
struct sk_buff *skb;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2011-03-08 08:10:27 +08:00
|
|
|
skb = nlmsg_new(xfrm_aevent_msgsize(x), GFP_ATOMIC);
|
2006-03-21 11:16:12 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_aevent(skb, x, c);
|
|
|
|
BUG_ON(err < 0);
|
2006-03-21 11:16:12 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_AEVENTS);
|
2006-03-21 11:16:12 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_notify_sa_flush(const struct km_event *c)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
2008-11-26 09:50:36 +08:00
|
|
|
struct net *net = c->net;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct xfrm_usersa_flush *p;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
2007-08-23 04:57:39 +08:00
|
|
|
int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush));
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(len, GFP_ATOMIC);
|
2005-06-19 13:42:13 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0);
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -EMSGSIZE;
|
|
|
|
}
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
p = nlmsg_data(nlh);
|
2005-06-19 13:44:00 +08:00
|
|
|
p->proto = c->data.proto;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA);
|
2005-06-19 13:42:13 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_sa_len(struct xfrm_state *x)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
2017-09-22 04:48:54 +08:00
|
|
|
unsigned int l = 0;
|
2008-01-29 11:37:29 +08:00
|
|
|
if (x->aead)
|
|
|
|
l += nla_total_size(aead_len(x->aead));
|
2009-11-25 08:29:52 +08:00
|
|
|
if (x->aalg) {
|
|
|
|
l += nla_total_size(sizeof(struct xfrm_algo) +
|
|
|
|
(x->aalg->alg_key_len + 7) / 8);
|
|
|
|
l += nla_total_size(xfrm_alg_auth_len(x->aalg));
|
|
|
|
}
|
2005-06-19 13:42:13 +08:00
|
|
|
if (x->ealg)
|
2008-01-09 15:39:06 +08:00
|
|
|
l += nla_total_size(xfrm_alg_len(x->ealg));
|
2005-06-19 13:42:13 +08:00
|
|
|
if (x->calg)
|
2007-08-23 04:57:39 +08:00
|
|
|
l += nla_total_size(sizeof(*x->calg));
|
2005-06-19 13:42:13 +08:00
|
|
|
if (x->encap)
|
2007-08-23 04:57:39 +08:00
|
|
|
l += nla_total_size(sizeof(*x->encap));
|
2010-12-08 12:37:49 +08:00
|
|
|
if (x->tfcpad)
|
|
|
|
l += nla_total_size(sizeof(x->tfcpad));
|
2011-03-08 08:10:27 +08:00
|
|
|
if (x->replay_esn)
|
|
|
|
l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn));
|
2014-10-30 16:39:36 +08:00
|
|
|
else
|
|
|
|
l += nla_total_size(sizeof(struct xfrm_replay_state));
|
2007-10-10 04:30:57 +08:00
|
|
|
if (x->security)
|
|
|
|
l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) +
|
|
|
|
x->security->ctx_len);
|
|
|
|
if (x->coaddr)
|
|
|
|
l += nla_total_size(sizeof(*x->coaddr));
|
2013-02-22 17:54:54 +08:00
|
|
|
if (x->props.extra_flags)
|
|
|
|
l += nla_total_size(sizeof(x->props.extra_flags));
|
2017-04-14 16:06:10 +08:00
|
|
|
if (x->xso.dev)
|
2021-12-09 04:20:19 +08:00
|
|
|
l += nla_total_size(sizeof(struct xfrm_user_offload));
|
2018-06-12 18:44:26 +08:00
|
|
|
if (x->props.smark.v | x->props.smark.m) {
|
|
|
|
l += nla_total_size(sizeof(x->props.smark.v));
|
|
|
|
l += nla_total_size(sizeof(x->props.smark.m));
|
|
|
|
}
|
2018-06-12 20:07:07 +08:00
|
|
|
if (x->if_id)
|
|
|
|
l += nla_total_size(sizeof(x->if_id));
|
2007-10-10 04:30:57 +08:00
|
|
|
|
2007-11-14 13:47:08 +08:00
|
|
|
/* Must count x->lastused as it may become non-zero behind our back. */
|
2016-04-22 23:31:23 +08:00
|
|
|
l += nla_total_size_64bit(sizeof(u64));
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2021-12-22 21:11:18 +08:00
|
|
|
if (x->mapping_maxage)
|
|
|
|
l += nla_total_size(sizeof(x->mapping_maxage));
|
|
|
|
|
2005-06-19 13:42:13 +08:00
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_notify_sa(struct xfrm_state *x, const struct km_event *c)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = xs_net(x);
|
2005-06-19 13:42:13 +08:00
|
|
|
struct xfrm_usersa_info *p;
|
2005-06-19 13:54:36 +08:00
|
|
|
struct xfrm_usersa_id *id;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
2017-09-22 04:48:54 +08:00
|
|
|
unsigned int len = xfrm_sa_len(x);
|
|
|
|
unsigned int headlen;
|
|
|
|
int err;
|
2005-06-19 13:54:36 +08:00
|
|
|
|
|
|
|
headlen = sizeof(*p);
|
|
|
|
if (c->event == XFRM_MSG_DELSA) {
|
2007-08-23 04:57:39 +08:00
|
|
|
len += nla_total_size(headlen);
|
2005-06-19 13:54:36 +08:00
|
|
|
headlen = sizeof(*id);
|
2010-02-22 19:32:59 +08:00
|
|
|
len += nla_total_size(sizeof(struct xfrm_mark));
|
2005-06-19 13:54:36 +08:00
|
|
|
}
|
2007-08-23 04:57:39 +08:00
|
|
|
len += NLMSG_ALIGN(headlen);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(len, GFP_ATOMIC);
|
2005-06-19 13:42:13 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0);
|
2012-06-28 12:57:03 +08:00
|
|
|
err = -EMSGSIZE;
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL)
|
2012-06-28 12:57:03 +08:00
|
|
|
goto out_free_skb;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
p = nlmsg_data(nlh);
|
2005-06-19 13:54:36 +08:00
|
|
|
if (c->event == XFRM_MSG_DELSA) {
|
2007-08-23 04:55:43 +08:00
|
|
|
struct nlattr *attr;
|
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
id = nlmsg_data(nlh);
|
2017-08-26 23:08:58 +08:00
|
|
|
memset(id, 0, sizeof(*id));
|
2005-06-19 13:54:36 +08:00
|
|
|
memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
|
|
|
|
id->spi = x->id.spi;
|
|
|
|
id->family = x->props.family;
|
|
|
|
id->proto = x->id.proto;
|
|
|
|
|
2007-08-23 04:55:43 +08:00
|
|
|
attr = nla_reserve(skb, XFRMA_SA, sizeof(*p));
|
2012-06-28 12:57:03 +08:00
|
|
|
err = -EMSGSIZE;
|
2007-08-23 04:55:43 +08:00
|
|
|
if (attr == NULL)
|
2012-06-28 12:57:03 +08:00
|
|
|
goto out_free_skb;
|
2007-08-23 04:55:43 +08:00
|
|
|
|
|
|
|
p = nla_data(attr);
|
2005-06-19 13:54:36 +08:00
|
|
|
}
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_state_extra(x, p, skb);
|
|
|
|
if (err)
|
|
|
|
goto out_free_skb;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_SA);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
out_free_skb:
|
2005-06-19 13:42:13 +08:00
|
|
|
kfree_skb(skb);
|
2012-06-28 12:57:03 +08:00
|
|
|
return err;
|
2005-06-19 13:42:13 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_send_state_notify(struct xfrm_state *x, const struct km_event *c)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
switch (c->event) {
|
2005-06-19 13:44:37 +08:00
|
|
|
case XFRM_MSG_EXPIRE:
|
2005-06-19 13:42:13 +08:00
|
|
|
return xfrm_exp_state_notify(x, c);
|
2006-03-21 11:16:12 +08:00
|
|
|
case XFRM_MSG_NEWAE:
|
|
|
|
return xfrm_aevent_state_notify(x, c);
|
2005-06-19 13:44:37 +08:00
|
|
|
case XFRM_MSG_DELSA:
|
|
|
|
case XFRM_MSG_UPDSA:
|
|
|
|
case XFRM_MSG_NEWSA:
|
2005-06-19 13:42:13 +08:00
|
|
|
return xfrm_notify_sa(x, c);
|
2005-06-19 13:44:37 +08:00
|
|
|
case XFRM_MSG_FLUSHSA:
|
2005-06-19 13:42:13 +08:00
|
|
|
return xfrm_notify_sa_flush(c);
|
|
|
|
default:
|
2010-05-12 14:37:06 +08:00
|
|
|
printk(KERN_NOTICE "xfrm_user: Unknown SA event %d\n",
|
|
|
|
c->event);
|
|
|
|
break;
|
2005-06-19 13:42:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_acquire_msgsize(struct xfrm_state *x,
|
|
|
|
struct xfrm_policy *xp)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire))
|
|
|
|
+ nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
|
2010-02-22 19:32:59 +08:00
|
|
|
+ nla_total_size(sizeof(struct xfrm_mark))
|
2007-08-23 04:57:39 +08:00
|
|
|
+ nla_total_size(xfrm_user_sec_ctx_size(x->security))
|
|
|
|
+ userpolicy_type_attrsize();
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
|
2012-08-15 10:13:47 +08:00
|
|
|
struct xfrm_tmpl *xt, struct xfrm_policy *xp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2012-06-28 12:57:03 +08:00
|
|
|
__u32 seq = xfrm_get_acqseq();
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_user_acquire *ua;
|
|
|
|
struct nlmsghdr *nlh;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 03:46:53 +08:00
|
|
|
nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0);
|
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
ua = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
memcpy(&ua->id, &x->id, sizeof(ua->id));
|
|
|
|
memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));
|
|
|
|
memcpy(&ua->sel, &x->sel, sizeof(ua->sel));
|
2012-08-15 10:13:47 +08:00
|
|
|
copy_to_user_policy(xp, &ua->policy, XFRM_POLICY_OUT);
|
2005-04-17 06:20:36 +08:00
|
|
|
ua->aalgos = xt->aalgos;
|
|
|
|
ua->ealgos = xt->ealgos;
|
|
|
|
ua->calgos = xt->calgos;
|
|
|
|
ua->seq = x->km.seq = seq;
|
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_tmpl(xp, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_state_sec_ctx(x, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
|
if (!err)
|
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
2018-06-12 20:07:07 +08:00
|
|
|
if (!err)
|
|
|
|
err = xfrm_if_id_put(skb, xp->if_id);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
|
2012-08-15 10:13:47 +08:00
|
|
|
struct xfrm_policy *xp)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:38:20 +08:00
|
|
|
struct net *net = xs_net(x);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct sk_buff *skb;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_acquire(skb, x, xt, xp);
|
|
|
|
BUG_ON(err < 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_ACQUIRE);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* User gives us xfrm_user_policy_info followed by an array of 0
|
|
|
|
* or more templates.
|
|
|
|
*/
|
2006-07-25 14:32:20 +08:00
|
|
|
static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
|
2005-04-17 06:20:36 +08:00
|
|
|
u8 *data, int len, int *dir)
|
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = sock_net(sk);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data;
|
|
|
|
struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1);
|
|
|
|
struct xfrm_policy *xp;
|
|
|
|
int nr;
|
|
|
|
|
2006-07-25 14:32:20 +08:00
|
|
|
switch (sk->sk_family) {
|
2005-04-17 06:20:36 +08:00
|
|
|
case AF_INET:
|
|
|
|
if (opt != IP_XFRM_POLICY) {
|
|
|
|
*dir = -EOPNOTSUPP;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
2011-12-10 17:48:31 +08:00
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
2005-04-17 06:20:36 +08:00
|
|
|
case AF_INET6:
|
|
|
|
if (opt != IPV6_XFRM_POLICY) {
|
|
|
|
*dir = -EOPNOTSUPP;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
*dir = -EINVAL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*dir = -EINVAL;
|
|
|
|
|
|
|
|
if (len < sizeof(*p) ||
|
|
|
|
verify_newpolicy_info(p))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nr = ((len - sizeof(*p)) / sizeof(*ut));
|
2006-12-04 11:19:26 +08:00
|
|
|
if (validate_tmpl(nr, ut, p->sel.family))
|
2005-04-17 06:20:36 +08:00
|
|
|
return NULL;
|
|
|
|
|
2005-07-27 06:43:17 +08:00
|
|
|
if (p->dir > XFRM_POLICY_OUT)
|
|
|
|
return NULL;
|
|
|
|
|
2010-08-15 13:38:09 +08:00
|
|
|
xp = xfrm_policy_alloc(net, GFP_ATOMIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (xp == NULL) {
|
|
|
|
*dir = -ENOBUFS;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
copy_from_user_policy(xp, p);
|
2006-08-24 13:49:28 +08:00
|
|
|
xp->type = XFRM_POLICY_TYPE_MAIN;
|
2005-04-17 06:20:36 +08:00
|
|
|
copy_templates(xp, ut, nr);
|
|
|
|
|
|
|
|
*dir = p->dir;
|
|
|
|
|
|
|
|
return xp;
|
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_polexpire_msgsize(struct xfrm_policy *xp)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire))
|
|
|
|
+ nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr)
|
|
|
|
+ nla_total_size(xfrm_user_sec_ctx_size(xp->security))
|
2010-02-22 19:33:00 +08:00
|
|
|
+ nla_total_size(sizeof(struct xfrm_mark))
|
2007-08-23 04:57:39 +08:00
|
|
|
+ userpolicy_type_attrsize();
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
|
2011-02-24 13:02:38 +08:00
|
|
|
int dir, const struct km_event *c)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct xfrm_user_polexpire *upe;
|
2006-03-21 11:16:12 +08:00
|
|
|
int hard = c->data.hard;
|
2012-06-28 12:57:03 +08:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0);
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
upe = nlmsg_data(nlh);
|
2005-04-17 06:20:36 +08:00
|
|
|
copy_to_user_policy(xp, &upe->pol, dir);
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_tmpl(xp, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_sec_ctx(xp, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
|
if (!err)
|
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
2018-06-12 20:07:07 +08:00
|
|
|
if (!err)
|
|
|
|
err = xfrm_if_id_put(skb, xp->if_id);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
upe->hard = !!hard;
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = xp_net(xp);
|
2005-04-17 06:20:36 +08:00
|
|
|
struct sk_buff *skb;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_polexpire(skb, xp, dir, c);
|
|
|
|
BUG_ON(err < 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_EXPIRE);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
2017-09-22 04:48:54 +08:00
|
|
|
unsigned int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
|
2008-11-26 09:50:08 +08:00
|
|
|
struct net *net = xp_net(xp);
|
2005-06-19 13:42:13 +08:00
|
|
|
struct xfrm_userpolicy_info *p;
|
2005-06-19 13:54:36 +08:00
|
|
|
struct xfrm_userpolicy_id *id;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
2017-09-22 04:48:54 +08:00
|
|
|
unsigned int headlen;
|
|
|
|
int err;
|
2005-06-19 13:54:36 +08:00
|
|
|
|
|
|
|
headlen = sizeof(*p);
|
|
|
|
if (c->event == XFRM_MSG_DELPOLICY) {
|
2007-08-23 04:57:39 +08:00
|
|
|
len += nla_total_size(headlen);
|
2005-06-19 13:54:36 +08:00
|
|
|
headlen = sizeof(*id);
|
|
|
|
}
|
2007-08-23 04:57:04 +08:00
|
|
|
len += userpolicy_type_attrsize();
|
2010-02-22 19:33:00 +08:00
|
|
|
len += nla_total_size(sizeof(struct xfrm_mark));
|
2007-08-23 04:57:39 +08:00
|
|
|
len += NLMSG_ALIGN(headlen);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(len, GFP_ATOMIC);
|
2005-06-19 13:42:13 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, c->seq, c->event, headlen, 0);
|
2012-06-28 12:57:03 +08:00
|
|
|
err = -EMSGSIZE;
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL)
|
2012-06-28 12:57:03 +08:00
|
|
|
goto out_free_skb;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
p = nlmsg_data(nlh);
|
2005-06-19 13:54:36 +08:00
|
|
|
if (c->event == XFRM_MSG_DELPOLICY) {
|
2007-08-23 04:55:43 +08:00
|
|
|
struct nlattr *attr;
|
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
id = nlmsg_data(nlh);
|
2005-06-19 13:54:36 +08:00
|
|
|
memset(id, 0, sizeof(*id));
|
|
|
|
id->dir = dir;
|
|
|
|
if (c->data.byid)
|
|
|
|
id->index = xp->index;
|
|
|
|
else
|
|
|
|
memcpy(&id->sel, &xp->selector, sizeof(id->sel));
|
|
|
|
|
2007-08-23 04:55:43 +08:00
|
|
|
attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p));
|
2012-06-28 12:57:03 +08:00
|
|
|
err = -EMSGSIZE;
|
2007-08-23 04:55:43 +08:00
|
|
|
if (attr == NULL)
|
2012-06-28 12:57:03 +08:00
|
|
|
goto out_free_skb;
|
2007-08-23 04:55:43 +08:00
|
|
|
|
|
|
|
p = nla_data(attr);
|
2005-06-19 13:54:36 +08:00
|
|
|
}
|
2005-06-19 13:42:13 +08:00
|
|
|
|
|
|
|
copy_to_user_policy(xp, p, dir);
|
2012-06-28 12:57:03 +08:00
|
|
|
err = copy_to_user_tmpl(xp, skb);
|
|
|
|
if (!err)
|
|
|
|
err = copy_to_user_policy_type(xp->type, skb);
|
|
|
|
if (!err)
|
|
|
|
err = xfrm_mark_put(skb, &xp->mark);
|
2018-06-12 20:07:07 +08:00
|
|
|
if (!err)
|
|
|
|
err = xfrm_if_id_put(skb, xp->if_id);
|
2012-06-28 12:57:03 +08:00
|
|
|
if (err)
|
|
|
|
goto out_free_skb;
|
2010-02-22 19:33:00 +08:00
|
|
|
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
out_free_skb:
|
2005-06-19 13:42:13 +08:00
|
|
|
kfree_skb(skb);
|
2012-06-28 12:57:03 +08:00
|
|
|
return err;
|
2005-06-19 13:42:13 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_notify_policy_flush(const struct km_event *c)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
2008-11-26 09:50:36 +08:00
|
|
|
struct net *net = c->net;
|
2005-06-19 13:42:13 +08:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
2012-06-28 12:57:03 +08:00
|
|
|
int err;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC);
|
2005-06-19 13:42:13 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2012-09-08 04:12:54 +08:00
|
|
|
nlh = nlmsg_put(skb, c->portid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0);
|
2012-06-28 12:57:03 +08:00
|
|
|
err = -EMSGSIZE;
|
2007-08-23 03:46:53 +08:00
|
|
|
if (nlh == NULL)
|
2012-06-28 12:57:03 +08:00
|
|
|
goto out_free_skb;
|
|
|
|
err = copy_to_user_policy_type(c->data.type, skb);
|
|
|
|
if (err)
|
|
|
|
goto out_free_skb;
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2007-08-23 03:47:26 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_POLICY);
|
2005-06-19 13:42:13 +08:00
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
out_free_skb:
|
2005-06-19 13:42:13 +08:00
|
|
|
kfree_skb(skb);
|
2012-06-28 12:57:03 +08:00
|
|
|
return err;
|
2005-06-19 13:42:13 +08:00
|
|
|
}
|
|
|
|
|
2011-02-24 13:02:38 +08:00
|
|
|
static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c)
|
2005-06-19 13:42:13 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
switch (c->event) {
|
2005-06-19 13:44:37 +08:00
|
|
|
case XFRM_MSG_NEWPOLICY:
|
|
|
|
case XFRM_MSG_UPDPOLICY:
|
|
|
|
case XFRM_MSG_DELPOLICY:
|
2005-06-19 13:42:13 +08:00
|
|
|
return xfrm_notify_policy(xp, dir, c);
|
2005-06-19 13:44:37 +08:00
|
|
|
case XFRM_MSG_FLUSHPOLICY:
|
2005-06-19 13:42:13 +08:00
|
|
|
return xfrm_notify_policy_flush(c);
|
2005-06-19 13:44:37 +08:00
|
|
|
case XFRM_MSG_POLEXPIRE:
|
2005-06-19 13:42:13 +08:00
|
|
|
return xfrm_exp_policy_notify(xp, dir, c);
|
|
|
|
default:
|
2010-05-12 14:37:06 +08:00
|
|
|
printk(KERN_NOTICE "xfrm_user: Unknown Policy event %d\n",
|
|
|
|
c->event);
|
2005-06-19 13:42:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_report_msgsize(void)
|
2007-08-23 04:57:39 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_user_report));
|
|
|
|
}
|
|
|
|
|
2006-08-24 11:44:06 +08:00
|
|
|
static int build_report(struct sk_buff *skb, u8 proto,
|
|
|
|
struct xfrm_selector *sel, xfrm_address_t *addr)
|
|
|
|
{
|
|
|
|
struct xfrm_user_report *ur;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
|
2007-08-23 03:46:53 +08:00
|
|
|
nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0);
|
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
2006-08-24 11:44:06 +08:00
|
|
|
|
2007-08-23 04:53:52 +08:00
|
|
|
ur = nlmsg_data(nlh);
|
2006-08-24 11:44:06 +08:00
|
|
|
ur->proto = proto;
|
|
|
|
memcpy(&ur->sel, sel, sizeof(ur->sel));
|
|
|
|
|
2012-06-28 12:57:03 +08:00
|
|
|
if (addr) {
|
|
|
|
int err = nla_put(skb, XFRMA_COADDR, sizeof(*addr), addr);
|
|
|
|
if (err) {
|
|
|
|
nlmsg_cancel(skb, nlh);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
}
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2006-08-24 11:44:06 +08:00
|
|
|
}
|
|
|
|
|
2008-11-26 09:51:01 +08:00
|
|
|
static int xfrm_send_report(struct net *net, u8 proto,
|
|
|
|
struct xfrm_selector *sel, xfrm_address_t *addr)
|
2006-08-24 11:44:06 +08:00
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2006-08-24 11:44:06 +08:00
|
|
|
|
2007-08-23 04:57:39 +08:00
|
|
|
skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC);
|
2006-08-24 11:44:06 +08:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_report(skb, proto, sel, addr);
|
|
|
|
BUG_ON(err < 0);
|
2006-08-24 11:44:06 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_REPORT);
|
2006-08-24 11:44:06 +08:00
|
|
|
}
|
|
|
|
|
2017-09-22 04:48:54 +08:00
|
|
|
static inline unsigned int xfrm_mapping_msgsize(void)
|
2008-10-29 07:01:07 +08:00
|
|
|
{
|
|
|
|
return NLMSG_ALIGN(sizeof(struct xfrm_user_mapping));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int build_mapping(struct sk_buff *skb, struct xfrm_state *x,
|
|
|
|
xfrm_address_t *new_saddr, __be16 new_sport)
|
|
|
|
{
|
|
|
|
struct xfrm_user_mapping *um;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
|
|
|
|
nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MAPPING, sizeof(*um), 0);
|
|
|
|
if (nlh == NULL)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
|
|
|
|
um = nlmsg_data(nlh);
|
|
|
|
|
|
|
|
memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr));
|
|
|
|
um->id.spi = x->id.spi;
|
|
|
|
um->id.family = x->props.family;
|
|
|
|
um->id.proto = x->id.proto;
|
|
|
|
memcpy(&um->new_saddr, new_saddr, sizeof(um->new_saddr));
|
|
|
|
memcpy(&um->old_saddr, &x->props.saddr, sizeof(um->old_saddr));
|
|
|
|
um->new_sport = new_sport;
|
|
|
|
um->old_sport = x->encap->encap_sport;
|
|
|
|
um->reqid = x->props.reqid;
|
|
|
|
|
2015-01-17 05:09:00 +08:00
|
|
|
nlmsg_end(skb, nlh);
|
|
|
|
return 0;
|
2008-10-29 07:01:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
|
|
|
|
__be16 sport)
|
|
|
|
{
|
2008-11-26 09:38:20 +08:00
|
|
|
struct net *net = xs_net(x);
|
2008-10-29 07:01:07 +08:00
|
|
|
struct sk_buff *skb;
|
2017-10-26 19:31:35 +08:00
|
|
|
int err;
|
2008-10-29 07:01:07 +08:00
|
|
|
|
|
|
|
if (x->id.proto != IPPROTO_ESP)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (!x->encap)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
skb = nlmsg_new(xfrm_mapping_msgsize(), GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-10-26 19:31:35 +08:00
|
|
|
err = build_mapping(skb, x, ipaddr, sport);
|
|
|
|
BUG_ON(err < 0);
|
2008-10-29 07:01:07 +08:00
|
|
|
|
2014-06-03 16:26:06 +08:00
|
|
|
return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MAPPING);
|
2008-10-29 07:01:07 +08:00
|
|
|
}
|
|
|
|
|
2014-02-12 22:20:06 +08:00
|
|
|
static bool xfrm_is_alive(const struct km_event *c)
|
|
|
|
{
|
|
|
|
return (bool)xfrm_acquire_is_on(c->net);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static struct xfrm_mgr netlink_mgr = {
|
|
|
|
.notify = xfrm_send_state_notify,
|
|
|
|
.acquire = xfrm_send_acquire,
|
|
|
|
.compile_policy = xfrm_compile_policy,
|
|
|
|
.notify_policy = xfrm_send_policy_notify,
|
2006-08-24 11:44:06 +08:00
|
|
|
.report = xfrm_send_report,
|
2007-02-09 05:12:32 +08:00
|
|
|
.migrate = xfrm_send_migrate,
|
2008-10-29 07:01:07 +08:00
|
|
|
.new_mapping = xfrm_send_mapping,
|
2014-02-12 22:20:06 +08:00
|
|
|
.is_alive = xfrm_is_alive,
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
2008-11-26 09:38:20 +08:00
|
|
|
static int __net_init xfrm_user_net_init(struct net *net)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2006-03-21 14:40:54 +08:00
|
|
|
struct sock *nlsk;
|
2012-06-29 14:15:21 +08:00
|
|
|
struct netlink_kernel_cfg cfg = {
|
|
|
|
.groups = XFRMNLGRP_MAX,
|
|
|
|
.input = xfrm_netlink_rcv,
|
|
|
|
};
|
2006-03-21 14:40:54 +08:00
|
|
|
|
2012-09-08 10:53:54 +08:00
|
|
|
nlsk = netlink_kernel_create(net, NETLINK_XFRM, &cfg);
|
2006-03-21 14:40:54 +08:00
|
|
|
if (nlsk == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENOMEM;
|
2009-12-03 10:29:05 +08:00
|
|
|
net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */
|
2012-01-12 12:41:32 +08:00
|
|
|
rcu_assign_pointer(net->xfrm.nlsk, nlsk);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-15 00:12:53 +08:00
|
|
|
static void __net_exit xfrm_user_net_pre_exit(struct net *net)
|
|
|
|
{
|
|
|
|
RCU_INIT_POINTER(net->xfrm.nlsk, NULL);
|
|
|
|
}
|
|
|
|
|
2009-12-03 10:29:05 +08:00
|
|
|
static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2009-12-03 10:29:05 +08:00
|
|
|
struct net *net;
|
2021-04-15 00:12:53 +08:00
|
|
|
|
2009-12-03 10:29:05 +08:00
|
|
|
list_for_each_entry(net, net_exit_list, exit_list)
|
|
|
|
netlink_kernel_release(net->xfrm.nlsk_stash);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2008-11-26 09:38:20 +08:00
|
|
|
static struct pernet_operations xfrm_user_net_ops = {
|
2009-12-03 10:29:05 +08:00
|
|
|
.init = xfrm_user_net_init,
|
2021-04-15 00:12:53 +08:00
|
|
|
.pre_exit = xfrm_user_net_pre_exit,
|
2009-12-03 10:29:05 +08:00
|
|
|
.exit_batch = xfrm_user_net_exit,
|
2008-11-26 09:38:20 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init xfrm_user_init(void)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
printk(KERN_INFO "Initializing XFRM netlink socket\n");
|
|
|
|
|
|
|
|
rv = register_pernet_subsys(&xfrm_user_net_ops);
|
|
|
|
if (rv < 0)
|
|
|
|
return rv;
|
|
|
|
rv = xfrm_register_km(&netlink_mgr);
|
|
|
|
if (rv < 0)
|
|
|
|
unregister_pernet_subsys(&xfrm_user_net_ops);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit xfrm_user_exit(void)
|
|
|
|
{
|
|
|
|
xfrm_unregister_km(&netlink_mgr);
|
|
|
|
unregister_pernet_subsys(&xfrm_user_net_ops);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
module_init(xfrm_user_init);
|
|
|
|
module_exit(xfrm_user_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
2005-08-10 10:40:55 +08:00
|
|
|
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
|