2005-04-16 15:20:36 -07: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 00:12:27 -07:00
|
|
|
*
|
2005-04-16 15:20:36 -07:00
|
|
|
*/
|
|
|
|
|
2006-08-06 02:49:12 -07:00
|
|
|
#include <linux/crypto.h>
|
2005-04-16 15:20:36 -07: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/rtnetlink.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-09 18:25:54 -07:00
|
|
|
#include <net/netlink.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
#include <asm/uaccess.h>
|
2006-08-23 20:33:28 -07:00
|
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
#include <linux/in6.h>
|
|
|
|
#endif
|
2006-11-27 12:11:54 -07:00
|
|
|
#include <linux/audit.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[type - 1];
|
|
|
|
struct xfrm_algo *algp;
|
2005-05-19 12:39:49 -07:00
|
|
|
int len;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
2005-05-19 12:39:49 -07:00
|
|
|
len = (rt->rta_len - sizeof(*rt)) - sizeof(*algp);
|
|
|
|
if (len < 0)
|
2005-04-16 15:20:36 -07:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
algp = RTA_DATA(rt);
|
2005-05-19 12:39:49 -07:00
|
|
|
|
2007-02-09 07:25:29 -07:00
|
|
|
len -= (algp->alg_key_len + 7U) / 8;
|
2005-05-19 12:39:49 -07:00
|
|
|
if (len < 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
switch (type) {
|
|
|
|
case XFRMA_ALG_AUTH:
|
|
|
|
if (!algp->alg_key_len &&
|
|
|
|
strcmp(algp->alg_name, "digest_null") != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRMA_ALG_CRYPT:
|
|
|
|
if (!algp->alg_key_len &&
|
|
|
|
strcmp(algp->alg_name, "cipher_null") != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XFRMA_ALG_COMP:
|
|
|
|
/* Zero length keys are legal. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int verify_encap_tmpl(struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_ENCAP - 1];
|
|
|
|
struct xfrm_encap_tmpl *encap;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((rt->rta_len - sizeof(*rt)) < sizeof(*encap))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-08-23 17:56:04 -07:00
|
|
|
static int verify_one_addr(struct rtattr **xfrma, enum xfrm_attr_type_t type,
|
|
|
|
xfrm_address_t **addrp)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[type - 1];
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((rt->rta_len - sizeof(*rt)) < sizeof(**addrp))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (addrp)
|
|
|
|
*addrp = RTA_DATA(rt);
|
|
|
|
|
|
|
|
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 00:12:27 -07:00
|
|
|
|
|
|
|
static inline int verify_sec_ctx_len(struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_SEC_CTX - 1];
|
|
|
|
struct xfrm_user_sec_ctx *uctx;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (rt->rta_len < sizeof(*uctx))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
uctx = RTA_DATA(rt);
|
|
|
|
|
|
|
|
len += sizeof(struct xfrm_user_sec_ctx);
|
|
|
|
len += uctx->ctx_len;
|
|
|
|
|
|
|
|
if (uctx->len != len)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static int verify_newsa_info(struct xfrm_usersa_info *p,
|
|
|
|
struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
switch (p->family) {
|
|
|
|
case AF_INET:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
err = -EAFNOSUPPORT;
|
|
|
|
goto out;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto out;
|
|
|
|
};
|
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
switch (p->id.proto) {
|
|
|
|
case IPPROTO_AH:
|
|
|
|
if (!xfrma[XFRMA_ALG_AUTH-1] ||
|
|
|
|
xfrma[XFRMA_ALG_CRYPT-1] ||
|
|
|
|
xfrma[XFRMA_ALG_COMP-1])
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPPROTO_ESP:
|
|
|
|
if ((!xfrma[XFRMA_ALG_AUTH-1] &&
|
|
|
|
!xfrma[XFRMA_ALG_CRYPT-1]) ||
|
|
|
|
xfrma[XFRMA_ALG_COMP-1])
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPPROTO_COMP:
|
|
|
|
if (!xfrma[XFRMA_ALG_COMP-1] ||
|
|
|
|
xfrma[XFRMA_ALG_AUTH-1] ||
|
|
|
|
xfrma[XFRMA_ALG_CRYPT-1])
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
|
2006-08-23 20:33:28 -07:00
|
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
case IPPROTO_DSTOPTS:
|
|
|
|
case IPPROTO_ROUTING:
|
|
|
|
if (xfrma[XFRMA_ALG_COMP-1] ||
|
|
|
|
xfrma[XFRMA_ALG_AUTH-1] ||
|
|
|
|
xfrma[XFRMA_ALG_CRYPT-1] ||
|
|
|
|
xfrma[XFRMA_ENCAP-1] ||
|
|
|
|
xfrma[XFRMA_SEC_CTX-1] ||
|
|
|
|
!xfrma[XFRMA_COADDR-1])
|
|
|
|
goto out;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
default:
|
|
|
|
goto out;
|
|
|
|
};
|
|
|
|
|
|
|
|
if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH)))
|
|
|
|
goto out;
|
|
|
|
if ((err = verify_one_alg(xfrma, XFRMA_ALG_CRYPT)))
|
|
|
|
goto out;
|
|
|
|
if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP)))
|
|
|
|
goto out;
|
|
|
|
if ((err = verify_encap_tmpl(xfrma)))
|
|
|
|
goto out;
|
[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 00:12:27 -07:00
|
|
|
if ((err = verify_sec_ctx_len(xfrma)))
|
|
|
|
goto out;
|
2006-08-23 18:18:55 -07:00
|
|
|
if ((err = verify_one_addr(xfrma, XFRMA_COADDR, NULL)))
|
|
|
|
goto out;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
err = -EINVAL;
|
|
|
|
switch (p->mode) {
|
2006-09-22 15:05:15 -07:00
|
|
|
case XFRM_MODE_TRANSPORT:
|
|
|
|
case XFRM_MODE_TUNNEL:
|
2006-08-23 18:18:55 -07:00
|
|
|
case XFRM_MODE_ROUTEOPTIMIZATION:
|
2006-10-03 23:47:05 -07:00
|
|
|
case XFRM_MODE_BEET:
|
2005-04-16 15:20:36 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
goto out;
|
|
|
|
};
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int attach_one_algo(struct xfrm_algo **algpp, u8 *props,
|
|
|
|
struct xfrm_algo_desc *(*get_byname)(char *, int),
|
|
|
|
struct rtattr *u_arg)
|
|
|
|
{
|
|
|
|
struct rtattr *rta = u_arg;
|
|
|
|
struct xfrm_algo *p, *ualg;
|
|
|
|
struct xfrm_algo_desc *algo;
|
2005-05-19 12:39:04 -07:00
|
|
|
int len;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ualg = RTA_DATA(rta);
|
|
|
|
|
|
|
|
algo = get_byname(ualg->alg_name, 1);
|
|
|
|
if (!algo)
|
|
|
|
return -ENOSYS;
|
|
|
|
*props = algo->desc.sadb_alg_id;
|
|
|
|
|
2005-05-19 12:39:04 -07:00
|
|
|
len = sizeof(*ualg) + (ualg->alg_key_len + 7U) / 8;
|
2006-11-20 20:22:51 -07:00
|
|
|
p = kmemdup(ualg, len, GFP_KERNEL);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-08-12 15:50:00 -07:00
|
|
|
strcpy(p->alg_name, algo->name);
|
2005-04-16 15:20:36 -07:00
|
|
|
*algpp = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int attach_encap_tmpl(struct xfrm_encap_tmpl **encapp, struct rtattr *u_arg)
|
|
|
|
{
|
|
|
|
struct rtattr *rta = u_arg;
|
|
|
|
struct xfrm_encap_tmpl *p, *uencap;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uencap = RTA_DATA(rta);
|
2006-11-20 20:22:51 -07:00
|
|
|
p = kmemdup(uencap, sizeof(*p), GFP_KERNEL);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*encapp = p;
|
|
|
|
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 00:12:27 -07:00
|
|
|
|
2007-04-13 16:14:35 -07:00
|
|
|
static inline 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 00:12:27 -07:00
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
if (xfrm_ctx) {
|
|
|
|
len += sizeof(struct xfrm_user_sec_ctx);
|
|
|
|
len += xfrm_ctx->ctx_len;
|
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int attach_sec_ctx(struct xfrm_state *x, struct rtattr *u_arg)
|
|
|
|
{
|
|
|
|
struct xfrm_user_sec_ctx *uctx;
|
|
|
|
|
|
|
|
if (!u_arg)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uctx = RTA_DATA(u_arg);
|
|
|
|
return security_xfrm_state_alloc(x, uctx);
|
|
|
|
}
|
|
|
|
|
2006-08-23 18:18:55 -07:00
|
|
|
static int attach_one_addr(xfrm_address_t **addrpp, struct rtattr *u_arg)
|
|
|
|
{
|
|
|
|
struct rtattr *rta = u_arg;
|
|
|
|
xfrm_address_t *p, *uaddrp;
|
|
|
|
|
|
|
|
if (!rta)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uaddrp = RTA_DATA(rta);
|
2006-11-20 20:22:51 -07:00
|
|
|
p = kmemdup(uaddrp, sizeof(*p), GFP_KERNEL);
|
2006-08-23 18:18:55 -07:00
|
|
|
if (!p)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
*addrpp = p;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07: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;
|
|
|
|
x->props.replay_window = p->replay_window;
|
|
|
|
x->props.reqid = p->reqid;
|
|
|
|
x->props.family = p->family;
|
2006-10-27 15:29:47 -07:00
|
|
|
memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr));
|
2005-04-16 15:20:36 -07:00
|
|
|
x->props.flags = p->flags;
|
|
|
|
}
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
/*
|
|
|
|
* someday when pfkey also has support, we could have the code
|
|
|
|
* somehow made shareable and move it to xfrm_state.c - JHS
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int xfrm_update_ae_params(struct xfrm_state *x, struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
int err = - EINVAL;
|
|
|
|
struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1];
|
|
|
|
struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1];
|
|
|
|
struct rtattr *et = xfrma[XFRMA_ETIMER_THRESH-1];
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_REPLAY_THRESH-1];
|
|
|
|
|
|
|
|
if (rp) {
|
|
|
|
struct xfrm_replay_state *replay;
|
|
|
|
if (RTA_PAYLOAD(rp) < sizeof(*replay))
|
|
|
|
goto error;
|
|
|
|
replay = RTA_DATA(rp);
|
|
|
|
memcpy(&x->replay, replay, sizeof(*replay));
|
|
|
|
memcpy(&x->preplay, replay, sizeof(*replay));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lt) {
|
|
|
|
struct xfrm_lifetime_cur *ltime;
|
|
|
|
if (RTA_PAYLOAD(lt) < sizeof(*ltime))
|
|
|
|
goto error;
|
|
|
|
ltime = RTA_DATA(lt);
|
|
|
|
x->curlft.bytes = ltime->bytes;
|
|
|
|
x->curlft.packets = ltime->packets;
|
|
|
|
x->curlft.add_time = ltime->add_time;
|
|
|
|
x->curlft.use_time = ltime->use_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (et) {
|
|
|
|
if (RTA_PAYLOAD(et) < sizeof(u32))
|
|
|
|
goto error;
|
|
|
|
x->replay_maxage = *(u32*)RTA_DATA(et);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rt) {
|
|
|
|
if (RTA_PAYLOAD(rt) < sizeof(u32))
|
|
|
|
goto error;
|
|
|
|
x->replay_maxdiff = *(u32*)RTA_DATA(rt);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
error:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
|
|
|
|
struct rtattr **xfrma,
|
|
|
|
int *errp)
|
|
|
|
{
|
|
|
|
struct xfrm_state *x = xfrm_state_alloc();
|
|
|
|
int err = -ENOMEM;
|
|
|
|
|
|
|
|
if (!x)
|
|
|
|
goto error_no_put;
|
|
|
|
|
|
|
|
copy_from_user_state(x, p);
|
|
|
|
|
|
|
|
if ((err = attach_one_algo(&x->aalg, &x->props.aalgo,
|
|
|
|
xfrm_aalg_get_byname,
|
|
|
|
xfrma[XFRMA_ALG_AUTH-1])))
|
|
|
|
goto error;
|
|
|
|
if ((err = attach_one_algo(&x->ealg, &x->props.ealgo,
|
|
|
|
xfrm_ealg_get_byname,
|
|
|
|
xfrma[XFRMA_ALG_CRYPT-1])))
|
|
|
|
goto error;
|
|
|
|
if ((err = attach_one_algo(&x->calg, &x->props.calgo,
|
|
|
|
xfrm_calg_get_byname,
|
|
|
|
xfrma[XFRMA_ALG_COMP-1])))
|
|
|
|
goto error;
|
|
|
|
if ((err = attach_encap_tmpl(&x->encap, xfrma[XFRMA_ENCAP-1])))
|
|
|
|
goto error;
|
2006-08-23 18:18:55 -07:00
|
|
|
if ((err = attach_one_addr(&x->coaddr, xfrma[XFRMA_COADDR-1])))
|
|
|
|
goto error;
|
2005-06-20 13:18:08 -07:00
|
|
|
err = xfrm_init_state(x);
|
2005-04-16 15:20:36 -07:00
|
|
|
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 00:12:27 -07:00
|
|
|
if ((err = attach_sec_ctx(x, xfrma[XFRMA_SEC_CTX-1])))
|
|
|
|
goto error;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
x->km.seq = p->seq;
|
2006-03-20 20:16:12 -07:00
|
|
|
x->replay_maxdiff = sysctl_xfrm_aevent_rseqth;
|
|
|
|
/* sysctl_xfrm_aevent_etime is in 100ms units */
|
|
|
|
x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M;
|
|
|
|
x->preplay.bitmap = 0;
|
|
|
|
x->preplay.seq = x->replay.seq+x->replay_maxdiff;
|
|
|
|
x->preplay.oseq = x->replay.oseq +x->replay_maxdiff;
|
|
|
|
|
|
|
|
/* override default values from above */
|
|
|
|
|
|
|
|
err = xfrm_update_ae_params(x, (struct rtattr **)xfrma);
|
|
|
|
if (err < 0)
|
|
|
|
goto error;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
return x;
|
|
|
|
|
|
|
|
error:
|
|
|
|
x->km.state = XFRM_STATE_DEAD;
|
|
|
|
xfrm_state_put(x);
|
|
|
|
error_no_put:
|
|
|
|
*errp = err;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_state *x;
|
|
|
|
int err;
|
2005-06-18 22:42:13 -07:00
|
|
|
struct km_event c;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
err = verify_newsa_info(p, xfrma);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
x = xfrm_state_construct(p, xfrma, &err);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (!x)
|
|
|
|
return err;
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
xfrm_state_hold(x);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
|
|
|
|
err = xfrm_state_add(x);
|
|
|
|
else
|
|
|
|
err = xfrm_state_update(x);
|
|
|
|
|
2006-11-27 12:11:54 -07:00
|
|
|
xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
|
|
|
|
AUDIT_MAC_IPSEC_ADDSA, err ? 0 : 1, NULL, x);
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
if (err < 0) {
|
|
|
|
x->km.state = XFRM_STATE_DEAD;
|
2006-02-22 15:47:13 -07:00
|
|
|
__xfrm_state_put(x);
|
2005-06-18 22:45:31 -07:00
|
|
|
goto out;
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
2005-06-18 22:44:37 -07:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
km_state_notify(x, &c);
|
2005-06-18 22:45:31 -07:00
|
|
|
out:
|
2005-06-18 22:42:13 -07:00
|
|
|
xfrm_state_put(x);
|
2005-04-16 15:20:36 -07:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-08-23 17:56:04 -07:00
|
|
|
static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p,
|
|
|
|
struct rtattr **xfrma,
|
|
|
|
int *errp)
|
|
|
|
{
|
|
|
|
struct xfrm_state *x = NULL;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) {
|
|
|
|
err = -ESRCH;
|
|
|
|
x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
|
|
|
|
} else {
|
|
|
|
xfrm_address_t *saddr = NULL;
|
|
|
|
|
|
|
|
err = verify_one_addr(xfrma, XFRMA_SRCADDR, &saddr);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (!saddr) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2006-11-24 21:34:51 -07:00
|
|
|
err = -ESRCH;
|
2006-08-23 17:56:04 -07:00
|
|
|
x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto,
|
|
|
|
p->family);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (!x && errp)
|
|
|
|
*errp = err;
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_state *x;
|
2006-08-23 17:56:04 -07:00
|
|
|
int err = -ESRCH;
|
2005-06-18 22:42:13 -07:00
|
|
|
struct km_event c;
|
2005-04-16 15:20:36 -07:00
|
|
|
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
x = xfrm_user_state_lookup(p, xfrma, &err);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (x == NULL)
|
2006-08-23 17:56:04 -07:00
|
|
|
return err;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2006-06-08 23:58:52 -07:00
|
|
|
if ((err = security_xfrm_state_delete(x)) != 0)
|
2006-06-08 23:39:49 -07:00
|
|
|
goto out;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
if (xfrm_state_kern(x)) {
|
2006-06-08 23:39:49 -07:00
|
|
|
err = -EPERM;
|
|
|
|
goto out;
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
err = xfrm_state_delete(x);
|
2006-11-27 12:11:54 -07:00
|
|
|
|
2006-06-08 23:39:49 -07:00
|
|
|
if (err < 0)
|
|
|
|
goto out;
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
2005-06-18 22:44:37 -07:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-18 22:42:13 -07:00
|
|
|
km_state_notify(x, &c);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2006-06-08 23:39:49 -07:00
|
|
|
out:
|
2007-03-07 17:02:16 -07:00
|
|
|
xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
|
|
|
|
AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x);
|
2006-06-08 23:39:49 -07:00
|
|
|
xfrm_state_put(x);
|
2005-06-18 22:42:13 -07:00
|
|
|
return err;
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
memcpy(&p->stats, &x->stats, sizeof(p->stats));
|
2006-10-27 15:29:47 -07:00
|
|
|
memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr));
|
2005-04-16 15:20:36 -07: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;
|
|
|
|
int start_idx;
|
|
|
|
int this_idx;
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
struct xfrm_usersa_info *p;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
|
|
|
|
if (sp->this_idx < sp->start_idx)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid,
|
|
|
|
sp->nlmsg_seq,
|
|
|
|
XFRM_MSG_NEWSA, sizeof(*p));
|
|
|
|
nlh->nlmsg_flags = sp->nlmsg_flags;
|
|
|
|
|
|
|
|
p = NLMSG_DATA(nlh);
|
|
|
|
copy_to_user_state(x, p);
|
|
|
|
|
|
|
|
if (x->aalg)
|
|
|
|
RTA_PUT(skb, XFRMA_ALG_AUTH,
|
|
|
|
sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg);
|
|
|
|
if (x->ealg)
|
|
|
|
RTA_PUT(skb, XFRMA_ALG_CRYPT,
|
|
|
|
sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg);
|
|
|
|
if (x->calg)
|
|
|
|
RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
|
|
|
|
|
|
|
|
if (x->encap)
|
|
|
|
RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
|
|
|
|
|
[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 00:12:27 -07:00
|
|
|
if (x->security) {
|
|
|
|
int ctx_size = sizeof(struct xfrm_sec_ctx) +
|
|
|
|
x->security->ctx_len;
|
|
|
|
struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size);
|
|
|
|
struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
|
|
|
|
|
|
|
|
uctx->exttype = XFRMA_SEC_CTX;
|
|
|
|
uctx->len = ctx_size;
|
|
|
|
uctx->ctx_doi = x->security->ctx_doi;
|
|
|
|
uctx->ctx_alg = x->security->ctx_alg;
|
|
|
|
uctx->ctx_len = x->security->ctx_len;
|
|
|
|
memcpy(uctx + 1, x->security->ctx_str, x->security->ctx_len);
|
|
|
|
}
|
2006-08-23 18:18:55 -07:00
|
|
|
|
|
|
|
if (x->coaddr)
|
|
|
|
RTA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr);
|
|
|
|
|
2006-08-23 18:20:16 -07:00
|
|
|
if (x->lastused)
|
|
|
|
RTA_PUT(skb, XFRMA_LASTUSED, sizeof(x->lastused), &x->lastused);
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
out:
|
|
|
|
sp->this_idx++;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
rtattr_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
info.this_idx = 0;
|
|
|
|
info.start_idx = cb->args[0];
|
2006-08-23 17:49:52 -07:00
|
|
|
(void) xfrm_state_walk(0, dump_one_state, &info);
|
2005-04-16 15:20:36 -07:00
|
|
|
cb->args[0] = info.this_idx;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
|
|
|
|
if (!skb)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
info.in_skb = in_skb;
|
|
|
|
info.out_skb = skb;
|
|
|
|
info.nlmsg_seq = seq;
|
|
|
|
info.nlmsg_flags = 0;
|
|
|
|
info.this_idx = info.start_idx = 0;
|
|
|
|
|
|
|
|
if (dump_one_state(x, 0, &info)) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_state *x;
|
|
|
|
struct sk_buff *resp_skb;
|
2006-08-23 17:56:04 -07:00
|
|
|
int err = -ESRCH;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
x = xfrm_user_state_lookup(p, xfrma, &err);
|
2005-04-16 15:20:36 -07: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 {
|
|
|
|
err = netlink_unicast(xfrm_nl, resp_skb,
|
|
|
|
NETLINK_CB(skb).pid, MSG_DONTWAIT);
|
|
|
|
}
|
|
|
|
xfrm_state_put(x);
|
|
|
|
out_noput:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int verify_userspi_info(struct xfrm_userspi_info *p)
|
|
|
|
{
|
|
|
|
switch (p->info.id.proto) {
|
|
|
|
case IPPROTO_AH:
|
|
|
|
case IPPROTO_ESP:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case IPPROTO_COMP:
|
|
|
|
/* IPCOMP spi is 16-bits. */
|
|
|
|
if (p->max >= 0x10000)
|
|
|
|
return -EINVAL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (p->min > p->max)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_state *x;
|
|
|
|
struct xfrm_userspi_info *p;
|
|
|
|
struct sk_buff *resp_skb;
|
|
|
|
xfrm_address_t *daddr;
|
|
|
|
int family;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
p = NLMSG_DATA(nlh);
|
|
|
|
err = verify_userspi_info(p);
|
|
|
|
if (err)
|
|
|
|
goto out_noput;
|
|
|
|
|
|
|
|
family = p->info.family;
|
|
|
|
daddr = &p->info.id.daddr;
|
|
|
|
|
|
|
|
x = NULL;
|
|
|
|
if (p->info.seq) {
|
|
|
|
x = xfrm_find_acq_byseq(p->info.seq);
|
|
|
|
if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {
|
|
|
|
xfrm_state_put(x);
|
|
|
|
x = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!x)
|
|
|
|
x = xfrm_find_acq(p->info.mode, p->info.reqid,
|
|
|
|
p->info.id.proto, daddr,
|
|
|
|
&p->info.saddr, 1,
|
|
|
|
family);
|
|
|
|
err = -ENOENT;
|
|
|
|
if (x == NULL)
|
|
|
|
goto out_noput;
|
|
|
|
|
|
|
|
resp_skb = ERR_PTR(-ENOENT);
|
|
|
|
|
|
|
|
spin_lock_bh(&x->lock);
|
|
|
|
if (x->km.state != XFRM_STATE_DEAD) {
|
|
|
|
xfrm_alloc_spi(x, htonl(p->min), htonl(p->max));
|
|
|
|
if (x->id.spi)
|
|
|
|
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
|
|
|
|
}
|
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
|
|
|
|
if (IS_ERR(resp_skb)) {
|
|
|
|
err = PTR_ERR(resp_skb);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = netlink_unicast(xfrm_nl, resp_skb,
|
|
|
|
NETLINK_CB(skb).pid, MSG_DONTWAIT);
|
|
|
|
|
|
|
|
out:
|
|
|
|
xfrm_state_put(x);
|
|
|
|
out_noput:
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2006-11-27 13:59:30 -07:00
|
|
|
static int verify_policy_dir(u8 dir)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
switch (dir) {
|
|
|
|
case XFRM_POLICY_IN:
|
|
|
|
case XFRM_POLICY_OUT:
|
|
|
|
case XFRM_POLICY_FWD:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-27 13:59:30 -07:00
|
|
|
static int verify_policy_type(u8 type)
|
2006-08-23 22:49:28 -07:00
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case XFRM_POLICY_TYPE_MAIN:
|
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
case XFRM_POLICY_TYPE_SUB:
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
|
|
|
|
{
|
|
|
|
switch (p->share) {
|
|
|
|
case XFRM_SHARE_ANY:
|
|
|
|
case XFRM_SHARE_SESSION:
|
|
|
|
case XFRM_SHARE_USER:
|
|
|
|
case XFRM_SHARE_UNIQUE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (p->action) {
|
|
|
|
case XFRM_POLICY_ALLOW:
|
|
|
|
case XFRM_POLICY_BLOCK:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (p->sel.family) {
|
|
|
|
case AF_INET:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AF_INET6:
|
|
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
return -EAFNOSUPPORT;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
|
|
|
|
return verify_policy_dir(p->dir);
|
|
|
|
}
|
|
|
|
|
[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 00:12:27 -07:00
|
|
|
static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
|
|
|
|
struct xfrm_user_sec_ctx *uctx;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uctx = RTA_DATA(rt);
|
|
|
|
return security_xfrm_policy_alloc(pol, uctx);
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07: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;
|
2006-11-30 17:40:51 -07:00
|
|
|
t->encap_family = ut->family;
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-03 20:19:26 -07:00
|
|
|
static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (nr > XFRM_MAX_DEPTH)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
switch (ut[i].family) {
|
|
|
|
case AF_INET:
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
case AF_INET6:
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static int copy_from_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_TMPL-1];
|
|
|
|
|
|
|
|
if (!rt) {
|
|
|
|
pol->xfrm_nr = 0;
|
|
|
|
} else {
|
2006-12-03 20:19:26 -07:00
|
|
|
struct xfrm_user_tmpl *utmpl = RTA_DATA(rt);
|
|
|
|
int nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl);
|
|
|
|
int err;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2006-12-03 20:19:26 -07:00
|
|
|
err = validate_tmpl(nr, utmpl, pol->family);
|
|
|
|
if (err)
|
|
|
|
return err;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
copy_templates(pol, RTA_DATA(rt), nr);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-08-23 22:49:28 -07:00
|
|
|
static int copy_from_user_policy_type(u8 *tp, struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_POLICY_TYPE-1];
|
|
|
|
struct xfrm_userpolicy_type *upt;
|
2006-11-27 13:59:30 -07:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2006-08-23 22:49:28 -07:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (rt) {
|
|
|
|
if (rt->rta_len < sizeof(*upt))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
upt = RTA_DATA(rt);
|
|
|
|
type = upt->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = verify_policy_type(type);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
*tp = type;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07: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)
|
|
|
|
{
|
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp)
|
|
|
|
{
|
|
|
|
struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL);
|
|
|
|
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 00:12:27 -07:00
|
|
|
|
2006-08-23 22:49:28 -07:00
|
|
|
err = copy_from_user_policy_type(&xp->type, xfrma);
|
|
|
|
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 00:12:27 -07:00
|
|
|
if (!(err = copy_from_user_tmpl(xp, xfrma)))
|
|
|
|
err = copy_from_user_sec_ctx(xp, xfrma);
|
2006-08-23 22:49:28 -07:00
|
|
|
if (err)
|
|
|
|
goto error;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
return xp;
|
2006-08-23 22:49:28 -07:00
|
|
|
error:
|
|
|
|
*errp = err;
|
|
|
|
kfree(xp);
|
|
|
|
return NULL;
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_policy *xp;
|
2005-06-18 22:42:13 -07:00
|
|
|
struct km_event c;
|
2005-04-16 15:20:36 -07: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 00:12:27 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
2007-01-02 16:22:30 -07:00
|
|
|
err = verify_sec_ctx_len(xfrma);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
xp = xfrm_policy_construct(p, xfrma, &err);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (!xp)
|
|
|
|
return err;
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
/* shouldnt excl be based on nlh flags??
|
|
|
|
* Aha! this is anti-netlink really i.e more pfkey derived
|
|
|
|
* in netlink excl is a flag and you wouldnt need
|
|
|
|
* a type XFRM_MSG_UPDPOLICY - JHS */
|
2005-04-16 15:20:36 -07:00
|
|
|
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
|
|
|
|
err = xfrm_policy_insert(p->dir, xp, excl);
|
2006-11-27 12:11:54 -07:00
|
|
|
xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
|
|
|
|
AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
if (err) {
|
2006-01-06 14:22:39 -07:00
|
|
|
security_xfrm_policy_free(xp);
|
2005-04-16 15:20:36 -07:00
|
|
|
kfree(xp);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2005-06-18 22:44:37 -07:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-18 22:42:13 -07:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
|
|
|
km_policy_notify(xp, p->dir, &c);
|
|
|
|
|
2005-04-16 15:20:36 -07: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];
|
|
|
|
|
|
|
|
memcpy(&up->id, &kp->id, sizeof(up->id));
|
2006-11-30 17:40:51 -07:00
|
|
|
up->family = kp->encap_family;
|
2005-04-16 15:20:36 -07: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;
|
|
|
|
}
|
|
|
|
RTA_PUT(skb, XFRMA_TMPL,
|
|
|
|
(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr),
|
|
|
|
vec);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rtattr_failure:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-07-24 23:30:44 -07:00
|
|
|
static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *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 00:12:27 -07:00
|
|
|
{
|
2006-07-24 23:30:44 -07:00
|
|
|
int ctx_size = sizeof(struct xfrm_sec_ctx) + s->ctx_len;
|
|
|
|
struct rtattr *rt = __RTA_PUT(skb, XFRMA_SEC_CTX, ctx_size);
|
|
|
|
struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
|
|
|
|
|
|
|
|
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);
|
2007-02-09 07:25:29 -07:00
|
|
|
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 00:12:27 -07:00
|
|
|
|
2006-07-24 23:30:44 -07:00
|
|
|
rtattr_failure:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 00:12:27 -07:00
|
|
|
}
|
|
|
|
return 0;
|
2006-07-24 23:30:44 -07: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 00:12:27 -07:00
|
|
|
|
2006-07-24 23:30:44 -07:00
|
|
|
static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
if (xp->security) {
|
|
|
|
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 00:12:27 -07:00
|
|
|
}
|
|
|
|
|
2006-08-23 22:49:28 -07:00
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
2006-11-27 13:59:30 -07:00
|
|
|
static int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
|
2006-08-23 22:49:28 -07:00
|
|
|
{
|
|
|
|
struct xfrm_userpolicy_type upt;
|
|
|
|
|
|
|
|
memset(&upt, 0, sizeof(upt));
|
2006-11-20 17:51:22 -07:00
|
|
|
upt.type = type;
|
2006-08-23 22:49:28 -07:00
|
|
|
|
|
|
|
RTA_PUT(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rtattr_failure:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
2006-11-27 13:59:30 -07:00
|
|
|
static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb)
|
2006-08-23 22:49:28 -07:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 15:20:36 -07: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;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
|
|
|
|
if (sp->this_idx < sp->start_idx)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid,
|
|
|
|
sp->nlmsg_seq,
|
|
|
|
XFRM_MSG_NEWPOLICY, sizeof(*p));
|
|
|
|
p = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = sp->nlmsg_flags;
|
|
|
|
|
|
|
|
copy_to_user_policy(xp, p, dir);
|
|
|
|
if (copy_to_user_tmpl(xp, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
[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 00:12:27 -07:00
|
|
|
if (copy_to_user_sec_ctx(xp, skb))
|
|
|
|
goto nlmsg_failure;
|
2006-11-20 17:51:22 -07:00
|
|
|
if (copy_to_user_policy_type(xp->type, skb) < 0)
|
2006-08-23 22:49:28 -07:00
|
|
|
goto nlmsg_failure;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
out:
|
|
|
|
sp->this_idx++;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
info.this_idx = 0;
|
|
|
|
info.start_idx = cb->args[0];
|
2006-08-23 22:49:28 -07:00
|
|
|
(void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info);
|
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
(void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info);
|
|
|
|
#endif
|
2005-04-16 15:20:36 -07:00
|
|
|
cb->args[0] = info.this_idx;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
|
|
|
|
if (!skb)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
info.in_skb = in_skb;
|
|
|
|
info.out_skb = skb;
|
|
|
|
info.nlmsg_seq = seq;
|
|
|
|
info.nlmsg_flags = 0;
|
|
|
|
info.this_idx = info.start_idx = 0;
|
|
|
|
|
|
|
|
if (dump_one_policy(xp, dir, 0, &info) < 0) {
|
|
|
|
kfree_skb(skb);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return skb;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_policy *xp;
|
|
|
|
struct xfrm_userpolicy_id *p;
|
2006-11-27 13:59:30 -07:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2005-04-16 15:20:36 -07:00
|
|
|
int err;
|
2005-06-18 22:42:13 -07:00
|
|
|
struct km_event c;
|
2005-04-16 15:20:36 -07:00
|
|
|
int delete;
|
|
|
|
|
|
|
|
p = NLMSG_DATA(nlh);
|
|
|
|
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
err = copy_from_user_policy_type(&type, xfrma);
|
2006-08-23 22:49:28 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
err = verify_policy_dir(p->dir);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (p->index)
|
2007-03-07 16:37:58 -07:00
|
|
|
xp = xfrm_policy_byid(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 00:12:27 -07:00
|
|
|
else {
|
2007-01-02 16:22:30 -07:00
|
|
|
struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
|
[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 00:12:27 -07:00
|
|
|
struct xfrm_policy tmp;
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
err = verify_sec_ctx_len(xfrma);
|
[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 00:12:27 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(struct xfrm_policy));
|
|
|
|
if (rt) {
|
|
|
|
struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
|
|
|
|
|
|
|
|
if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
|
|
|
|
return err;
|
|
|
|
}
|
2007-03-07 16:37:58 -07:00
|
|
|
xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security,
|
|
|
|
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 00:12:27 -07:00
|
|
|
security_xfrm_policy_free(&tmp);
|
|
|
|
}
|
2005-04-16 15:20:36 -07: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 {
|
|
|
|
err = netlink_unicast(xfrm_nl, resp_skb,
|
|
|
|
NETLINK_CB(skb).pid,
|
|
|
|
MSG_DONTWAIT);
|
|
|
|
}
|
2005-06-18 22:42:13 -07:00
|
|
|
} else {
|
2007-02-12 14:53:54 -07:00
|
|
|
xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
|
|
|
|
AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
|
|
|
|
|
|
|
|
if (err != 0)
|
2006-06-08 23:39:49 -07:00
|
|
|
goto out;
|
2007-02-12 14:53:54 -07:00
|
|
|
|
2005-06-18 22:44:18 -07:00
|
|
|
c.data.byid = p->index;
|
2005-06-18 22:44:37 -07:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-18 22:42:13 -07:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
|
|
|
km_policy_notify(xp, p->dir, &c);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2006-06-08 23:39:49 -07:00
|
|
|
out:
|
2007-03-07 16:37:58 -07:00
|
|
|
xfrm_pol_put(xp);
|
2005-04-16 15:20:36 -07:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
2005-06-18 22:42:13 -07:00
|
|
|
struct km_event c;
|
2005-04-16 15:20:36 -07:00
|
|
|
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
|
2006-11-27 12:11:54 -07:00
|
|
|
struct xfrm_audit audit_info;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2006-11-27 12:11:54 -07:00
|
|
|
audit_info.loginuid = NETLINK_CB(skb).loginuid;
|
|
|
|
audit_info.secid = NETLINK_CB(skb).sid;
|
|
|
|
xfrm_state_flush(p->proto, &audit_info);
|
2005-06-18 22:44:00 -07:00
|
|
|
c.data.proto = p->proto;
|
2005-06-18 22:44:37 -07:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-18 22:42:13 -07:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
|
|
|
km_state_notify(NULL, &c);
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
|
|
|
|
static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
|
|
|
|
{
|
|
|
|
struct xfrm_aevent_id *id;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct xfrm_lifetime_cur ltime;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id));
|
|
|
|
id = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
2006-12-02 23:22:25 -07:00
|
|
|
memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr));
|
2006-03-20 20:16:12 -07:00
|
|
|
id->sa_id.spi = x->id.spi;
|
|
|
|
id->sa_id.family = x->props.family;
|
|
|
|
id->sa_id.proto = x->id.proto;
|
2006-12-02 23:22:25 -07:00
|
|
|
memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr));
|
|
|
|
id->reqid = x->props.reqid;
|
2006-03-20 20:16:12 -07:00
|
|
|
id->flags = c->data.aevent;
|
|
|
|
|
|
|
|
RTA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay);
|
|
|
|
|
|
|
|
ltime.bytes = x->curlft.bytes;
|
|
|
|
ltime.packets = x->curlft.packets;
|
|
|
|
ltime.add_time = x->curlft.add_time;
|
|
|
|
ltime.use_time = x->curlft.use_time;
|
|
|
|
|
|
|
|
RTA_PUT(skb, XFRMA_LTIME_VAL, sizeof(struct xfrm_lifetime_cur), <ime);
|
|
|
|
|
|
|
|
if (id->flags&XFRM_AE_RTHR) {
|
|
|
|
RTA_PUT(skb,XFRMA_REPLAY_THRESH,sizeof(u32),&x->replay_maxdiff);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (id->flags&XFRM_AE_ETHR) {
|
|
|
|
u32 etimer = x->replay_maxage*10/HZ;
|
|
|
|
RTA_PUT(skb,XFRMA_ETIMER_THRESH,sizeof(u32),&etimer);
|
|
|
|
}
|
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
rtattr_failure:
|
|
|
|
nlmsg_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2006-03-20 20:16:12 -07:00
|
|
|
{
|
|
|
|
struct xfrm_state *x;
|
|
|
|
struct sk_buff *r_skb;
|
|
|
|
int err;
|
|
|
|
struct km_event c;
|
|
|
|
struct xfrm_aevent_id *p = NLMSG_DATA(nlh);
|
|
|
|
int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
|
|
|
|
struct xfrm_usersa_id *id = &p->sa_id;
|
|
|
|
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_replay_state));
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur));
|
|
|
|
|
|
|
|
if (p->flags&XFRM_AE_RTHR)
|
|
|
|
len+=RTA_SPACE(sizeof(u32));
|
|
|
|
|
|
|
|
if (p->flags&XFRM_AE_ETHR)
|
|
|
|
len+=RTA_SPACE(sizeof(u32));
|
|
|
|
|
|
|
|
r_skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (r_skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family);
|
|
|
|
if (x == NULL) {
|
2007-02-27 10:57:37 -07:00
|
|
|
kfree_skb(r_skb);
|
2006-03-20 20:16:12 -07:00
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
|
|
|
|
|
|
|
if (build_aevent(r_skb, x, &c) < 0)
|
|
|
|
BUG();
|
|
|
|
err = netlink_unicast(xfrm_nl, r_skb,
|
|
|
|
NETLINK_CB(skb).pid, MSG_DONTWAIT);
|
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2006-03-20 20:16:12 -07:00
|
|
|
{
|
|
|
|
struct xfrm_state *x;
|
|
|
|
struct km_event c;
|
|
|
|
int err = - EINVAL;
|
|
|
|
struct xfrm_aevent_id *p = NLMSG_DATA(nlh);
|
|
|
|
struct rtattr *rp = xfrma[XFRMA_REPLAY_VAL-1];
|
|
|
|
struct rtattr *lt = xfrma[XFRMA_LTIME_VAL-1];
|
|
|
|
|
|
|
|
if (!lt && !rp)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* pedantic mode - thou shalt sayeth replaceth */
|
|
|
|
if (!(nlh->nlmsg_flags&NLM_F_REPLACE))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family);
|
|
|
|
if (x == NULL)
|
|
|
|
return -ESRCH;
|
|
|
|
|
|
|
|
if (x->km.state != XFRM_STATE_VALID)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
spin_lock_bh(&x->lock);
|
2007-01-02 16:22:30 -07:00
|
|
|
err = xfrm_update_ae_params(x, xfrma);
|
2006-03-20 20:16:12 -07:00
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
if (err < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
c.event = nlh->nlmsg_type;
|
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
|
|
|
c.data.aevent = XFRM_AE_CU;
|
|
|
|
km_state_notify(x, &c);
|
|
|
|
err = 0;
|
|
|
|
out:
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
2006-08-23 22:49:28 -07:00
|
|
|
struct km_event c;
|
2006-11-27 13:59:30 -07:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2006-08-23 22:49:28 -07:00
|
|
|
int err;
|
2006-11-27 12:11:54 -07:00
|
|
|
struct xfrm_audit audit_info;
|
2006-08-23 22:49:28 -07:00
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
err = copy_from_user_policy_type(&type, xfrma);
|
2006-08-23 22:49:28 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
2005-06-18 22:42:13 -07:00
|
|
|
|
2006-11-27 12:11:54 -07:00
|
|
|
audit_info.loginuid = NETLINK_CB(skb).loginuid;
|
|
|
|
audit_info.secid = NETLINK_CB(skb).sid;
|
|
|
|
xfrm_policy_flush(type, &audit_info);
|
2006-08-23 22:49:28 -07:00
|
|
|
c.data.type = type;
|
2005-06-18 22:44:37 -07:00
|
|
|
c.event = nlh->nlmsg_type;
|
2005-06-18 22:42:13 -07:00
|
|
|
c.seq = nlh->nlmsg_seq;
|
|
|
|
c.pid = nlh->nlmsg_pid;
|
|
|
|
km_policy_notify(NULL, 0, &c);
|
2005-04-16 15:20:36 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2006-03-20 20:17:25 -07:00
|
|
|
{
|
|
|
|
struct xfrm_policy *xp;
|
|
|
|
struct xfrm_user_polexpire *up = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_userpolicy_info *p = &up->pol;
|
2006-11-27 13:59:30 -07:00
|
|
|
u8 type = XFRM_POLICY_TYPE_MAIN;
|
2006-03-20 20:17:25 -07:00
|
|
|
int err = -ENOENT;
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
err = copy_from_user_policy_type(&type, xfrma);
|
2006-08-23 22:49:28 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
2006-03-20 20:17:25 -07:00
|
|
|
if (p->index)
|
2007-03-07 16:37:58 -07:00
|
|
|
xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err);
|
2006-03-20 20:17:25 -07:00
|
|
|
else {
|
2007-01-02 16:22:30 -07:00
|
|
|
struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
|
2006-03-20 20:17:25 -07:00
|
|
|
struct xfrm_policy tmp;
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
err = verify_sec_ctx_len(xfrma);
|
2006-03-20 20:17:25 -07:00
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(struct xfrm_policy));
|
|
|
|
if (rt) {
|
|
|
|
struct xfrm_user_sec_ctx *uctx = RTA_DATA(rt);
|
|
|
|
|
|
|
|
if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
|
|
|
|
return err;
|
|
|
|
}
|
2007-03-07 16:37:58 -07:00
|
|
|
xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security,
|
|
|
|
0, &err);
|
2006-03-20 20:17:25 -07:00
|
|
|
security_xfrm_policy_free(&tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xp == NULL)
|
2007-03-07 16:37:58 -07:00
|
|
|
return -ENOENT;
|
|
|
|
read_lock(&xp->lock);
|
2006-03-20 20:17:25 -07:00
|
|
|
if (xp->dead) {
|
|
|
|
read_unlock(&xp->lock);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
read_unlock(&xp->lock);
|
|
|
|
err = 0;
|
|
|
|
if (up->hard) {
|
|
|
|
xfrm_policy_delete(xp, p->dir);
|
2006-11-27 12:11:54 -07:00
|
|
|
xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
|
|
|
|
AUDIT_MAC_IPSEC_DELSPD, 1, xp, NULL);
|
|
|
|
|
2006-03-20 20:17:25 -07:00
|
|
|
} else {
|
|
|
|
// reset the timers here?
|
|
|
|
printk("Dont know what to do with soft policy expire\n");
|
|
|
|
}
|
|
|
|
km_policy_expired(xp, p->dir, up->hard, current->pid);
|
|
|
|
|
|
|
|
out:
|
|
|
|
xfrm_pol_put(xp);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
2006-03-20 20:17:03 -07:00
|
|
|
{
|
|
|
|
struct xfrm_state *x;
|
|
|
|
int err;
|
|
|
|
struct xfrm_user_expire *ue = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_usersa_info *p = &ue->state;
|
|
|
|
|
|
|
|
x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family);
|
|
|
|
|
2007-02-26 15:52:21 -07:00
|
|
|
err = -ENOENT;
|
2006-03-20 20:17:03 -07:00
|
|
|
if (x == NULL)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
spin_lock_bh(&x->lock);
|
2007-02-26 15:52:21 -07:00
|
|
|
err = -EINVAL;
|
2006-03-20 20:17:03 -07:00
|
|
|
if (x->km.state != XFRM_STATE_VALID)
|
|
|
|
goto out;
|
|
|
|
km_state_expired(x, ue->hard, current->pid);
|
|
|
|
|
2006-11-27 12:11:54 -07:00
|
|
|
if (ue->hard) {
|
2006-03-20 20:17:03 -07:00
|
|
|
__xfrm_state_delete(x);
|
2006-11-27 12:11:54 -07:00
|
|
|
xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
|
|
|
|
AUDIT_MAC_IPSEC_DELSA, 1, NULL, x);
|
|
|
|
}
|
2007-02-26 15:52:21 -07:00
|
|
|
err = 0;
|
2006-03-20 20:17:03 -07:00
|
|
|
out:
|
|
|
|
spin_unlock_bh(&x->lock);
|
|
|
|
xfrm_state_put(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2007-01-02 16:22:30 -07:00
|
|
|
static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
[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-20 20:16:40 -07:00
|
|
|
{
|
|
|
|
struct xfrm_policy *xp;
|
|
|
|
struct xfrm_user_tmpl *ut;
|
|
|
|
int i;
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_TMPL-1];
|
|
|
|
|
|
|
|
struct xfrm_user_acquire *ua = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_state *x = xfrm_state_alloc();
|
|
|
|
int err = -ENOMEM;
|
|
|
|
|
|
|
|
if (!x)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = verify_newpolicy_info(&ua->policy);
|
|
|
|
if (err) {
|
|
|
|
printk("BAD policy passed\n");
|
|
|
|
kfree(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* build an XP */
|
2006-12-03 20:19:26 -07:00
|
|
|
xp = xfrm_policy_construct(&ua->policy, (struct rtattr **) xfrma, &err);
|
|
|
|
if (!xp) {
|
[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-20 20:16:40 -07:00
|
|
|
kfree(x);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
ut = RTA_DATA(rt);
|
|
|
|
/* 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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(x);
|
|
|
|
kfree(xp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-08 14:12:32 -07:00
|
|
|
#ifdef CONFIG_XFRM_MIGRATE
|
|
|
|
static int verify_user_migrate(struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_MIGRATE-1];
|
|
|
|
struct xfrm_user_migrate *um;
|
|
|
|
|
|
|
|
if (!rt)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if ((rt->rta_len - sizeof(*rt)) < sizeof(*um))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int copy_from_user_migrate(struct xfrm_migrate *ma,
|
|
|
|
struct rtattr **xfrma, int *num)
|
|
|
|
{
|
|
|
|
struct rtattr *rt = xfrma[XFRMA_MIGRATE-1];
|
|
|
|
struct xfrm_user_migrate *um;
|
|
|
|
int i, num_migrate;
|
|
|
|
|
|
|
|
um = RTA_DATA(rt);
|
|
|
|
num_migrate = (rt->rta_len - sizeof(*rt)) / sizeof(*um);
|
|
|
|
|
|
|
|
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,
|
|
|
|
struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
struct xfrm_userpolicy_id *pi = NLMSG_DATA(nlh);
|
|
|
|
struct xfrm_migrate m[XFRM_MAX_DEPTH];
|
|
|
|
u8 type;
|
|
|
|
int err;
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
err = verify_user_migrate((struct rtattr **)xfrma);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = copy_from_user_policy_type(&type, (struct rtattr **)xfrma);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
err = copy_from_user_migrate((struct xfrm_migrate *)m,
|
|
|
|
(struct rtattr **)xfrma, &n);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
xfrm_migrate(&pi->sel, pi->dir, type, m, n);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct rtattr **xfrma)
|
|
|
|
{
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_XFRM_MIGRATE
|
|
|
|
static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
|
|
|
|
RTA_PUT(skb, XFRMA_MIGRATE, sizeof(um), &um);
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rtattr_failure:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m,
|
|
|
|
int num_migrate, struct xfrm_selector *sel,
|
|
|
|
u8 dir, u8 type)
|
|
|
|
{
|
|
|
|
struct xfrm_migrate *mp;
|
|
|
|
struct xfrm_userpolicy_id *pol_id;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id));
|
|
|
|
pol_id = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
|
|
|
if (copy_to_user_policy_type(type, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
|
|
|
|
|
|
|
for (i = 0, mp = m ; i < num_migrate; i++, mp++) {
|
|
|
|
if (copy_to_user_migrate(mp, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
return skb->len;
|
|
|
|
nlmsg_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
|
|
|
|
struct xfrm_migrate *m, int num_migrate)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = RTA_SPACE(sizeof(struct xfrm_user_migrate) * num_migrate);
|
|
|
|
len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_id));
|
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
|
|
|
|
#endif
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/* build migrate */
|
|
|
|
if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0)
|
|
|
|
BUG();
|
|
|
|
|
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_MIGRATE;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE,
|
|
|
|
GFP_ATOMIC);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
|
|
|
|
struct xfrm_migrate *m, int num_migrate)
|
|
|
|
{
|
|
|
|
return -ENOPROTOOPT;
|
|
|
|
}
|
|
|
|
#endif
|
2006-03-20 20:16:12 -07:00
|
|
|
|
2005-05-03 14:26:40 -07:00
|
|
|
#define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type))
|
|
|
|
|
|
|
|
static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
|
|
|
|
[XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
|
|
|
|
[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-20 20:16:40 -07:00
|
|
|
[XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire),
|
2006-03-20 20:17:03 -07:00
|
|
|
[XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire),
|
2005-05-03 14:26:40 -07:00
|
|
|
[XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info),
|
|
|
|
[XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info),
|
2006-03-20 20:17:25 -07:00
|
|
|
[XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire),
|
2005-05-03 14:26:40 -07:00
|
|
|
[XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush),
|
|
|
|
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),
|
2006-03-20 20:16:12 -07:00
|
|
|
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
|
|
|
|
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id),
|
2006-08-23 20:44:06 -07:00
|
|
|
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
|
2007-02-08 14:12:32 -07:00
|
|
|
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
|
2005-04-16 15:20:36 -07:00
|
|
|
};
|
|
|
|
|
2005-05-03 14:26:40 -07:00
|
|
|
#undef XMSGSIZE
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static struct xfrm_link {
|
2007-01-02 16:22:30 -07:00
|
|
|
int (*doit)(struct sk_buff *, struct nlmsghdr *, struct rtattr **);
|
2005-04-16 15:20:36 -07:00
|
|
|
int (*dump)(struct sk_buff *, struct netlink_callback *);
|
2005-05-03 14:26:40 -07: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,
|
|
|
|
.dump = xfrm_dump_sa },
|
|
|
|
[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,
|
|
|
|
.dump = xfrm_dump_policy },
|
|
|
|
[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-20 20:16:40 -07:00
|
|
|
[XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire },
|
2006-03-20 20:17:03 -07:00
|
|
|
[XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
|
2005-05-03 14:26:40 -07:00
|
|
|
[XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
|
|
|
|
[XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
|
2006-03-20 20:17:25 -07:00
|
|
|
[XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire},
|
2005-05-03 14:26:40 -07:00
|
|
|
[XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa },
|
|
|
|
[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy },
|
2006-03-20 20:16:12 -07:00
|
|
|
[XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae },
|
|
|
|
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
|
2007-02-08 14:12:32 -07:00
|
|
|
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
|
2005-04-16 15:20:36 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
|
|
|
|
{
|
|
|
|
struct rtattr *xfrma[XFRMA_MAX];
|
|
|
|
struct xfrm_link *link;
|
|
|
|
int type, min_len;
|
|
|
|
|
|
|
|
if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
type = nlh->nlmsg_type;
|
|
|
|
|
|
|
|
/* A control message: ignore them */
|
|
|
|
if (type < XFRM_MSG_BASE)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Unknown message: reply with EINVAL */
|
|
|
|
if (type > XFRM_MSG_MAX)
|
|
|
|
goto err_einval;
|
|
|
|
|
|
|
|
type -= XFRM_MSG_BASE;
|
|
|
|
link = &xfrm_dispatch[type];
|
|
|
|
|
|
|
|
/* All operations require privileges, even GET */
|
2006-06-27 13:26:11 -07:00
|
|
|
if (security_netlink_recv(skb, CAP_NET_ADMIN)) {
|
2005-04-16 15:20:36 -07:00
|
|
|
*errp = -EPERM;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-05-03 14:26:40 -07:00
|
|
|
if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) ||
|
|
|
|
type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) &&
|
|
|
|
(nlh->nlmsg_flags & NLM_F_DUMP)) {
|
2005-04-16 15:20:36 -07:00
|
|
|
if (link->dump == NULL)
|
|
|
|
goto err_einval;
|
|
|
|
|
|
|
|
if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,
|
2005-11-09 18:25:52 -07:00
|
|
|
link->dump, NULL)) != 0) {
|
2005-04-16 15:20:36 -07:00
|
|
|
return -1;
|
|
|
|
}
|
2005-11-09 18:25:54 -07:00
|
|
|
|
|
|
|
netlink_queue_skip(nlh, skb);
|
2005-04-16 15:20:36 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(xfrma, 0, sizeof(xfrma));
|
|
|
|
|
|
|
|
if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))
|
|
|
|
goto err_einval;
|
|
|
|
|
|
|
|
if (nlh->nlmsg_len > min_len) {
|
|
|
|
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
|
|
|
|
struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len);
|
|
|
|
|
|
|
|
while (RTA_OK(attr, attrlen)) {
|
|
|
|
unsigned short flavor = attr->rta_type;
|
|
|
|
if (flavor) {
|
|
|
|
if (flavor > XFRMA_MAX)
|
|
|
|
goto err_einval;
|
|
|
|
xfrma[flavor - 1] = attr;
|
|
|
|
}
|
|
|
|
attr = RTA_NEXT(attr, attrlen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (link->doit == NULL)
|
|
|
|
goto err_einval;
|
2007-01-02 16:22:30 -07:00
|
|
|
*errp = link->doit(skb, nlh, xfrma);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
return *errp;
|
|
|
|
|
|
|
|
err_einval:
|
|
|
|
*errp = -EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void xfrm_netlink_rcv(struct sock *sk, int len)
|
|
|
|
{
|
2005-11-09 18:25:54 -07:00
|
|
|
unsigned int qlen = 0;
|
2005-05-03 14:55:09 -07:00
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
do {
|
2006-03-20 23:33:17 -07:00
|
|
|
mutex_lock(&xfrm_cfg_mutex);
|
2005-11-09 18:25:54 -07:00
|
|
|
netlink_run_queue(sk, &qlen, &xfrm_user_rcv_msg);
|
2006-03-20 23:33:17 -07:00
|
|
|
mutex_unlock(&xfrm_cfg_mutex);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2005-05-03 14:55:09 -07:00
|
|
|
} while (qlen);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_user_expire *ue;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_EXPIRE,
|
2005-04-16 15:20:36 -07:00
|
|
|
sizeof(*ue));
|
|
|
|
ue = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
copy_to_user_state(x, &ue->state);
|
2006-03-20 20:16:12 -07:00
|
|
|
ue->hard = (c->data.hard != 0) ? 1 : 0;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
2005-06-18 22:45:56 -07:00
|
|
|
int len = NLMSG_LENGTH(sizeof(struct xfrm_user_expire));
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2005-06-18 22:45:56 -07:00
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
if (build_expire(skb, x, c) < 0)
|
2005-04-16 15:20:36 -07:00
|
|
|
BUG();
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
int len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
|
|
|
|
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_replay_state));
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_lifetime_cur));
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (build_aevent(skb, x, c) < 0)
|
|
|
|
BUG();
|
|
|
|
|
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_AEVENTS;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC);
|
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
static int xfrm_notify_sa_flush(struct km_event *c)
|
|
|
|
{
|
|
|
|
struct xfrm_usersa_flush *p;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
unsigned char *b;
|
|
|
|
int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
|
|
|
|
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
b = skb->tail;
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, c->pid, c->seq,
|
|
|
|
XFRM_MSG_FLUSHSA, sizeof(*p));
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
p = NLMSG_DATA(nlh);
|
2005-06-18 22:44:00 -07:00
|
|
|
p->proto = c->data.proto;
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_SA;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-22 12:27:49 -07:00
|
|
|
static inline int xfrm_sa_len(struct xfrm_state *x)
|
2005-06-18 22:42:13 -07:00
|
|
|
{
|
2005-06-18 22:54:36 -07:00
|
|
|
int l = 0;
|
2005-06-18 22:42:13 -07:00
|
|
|
if (x->aalg)
|
|
|
|
l += RTA_SPACE(sizeof(*x->aalg) + (x->aalg->alg_key_len+7)/8);
|
|
|
|
if (x->ealg)
|
|
|
|
l += RTA_SPACE(sizeof(*x->ealg) + (x->ealg->alg_key_len+7)/8);
|
|
|
|
if (x->calg)
|
|
|
|
l += RTA_SPACE(sizeof(*x->calg));
|
|
|
|
if (x->encap)
|
|
|
|
l += RTA_SPACE(sizeof(*x->encap));
|
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
|
|
|
|
{
|
|
|
|
struct xfrm_usersa_info *p;
|
2005-06-18 22:54:36 -07:00
|
|
|
struct xfrm_usersa_id *id;
|
2005-06-18 22:42:13 -07:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
unsigned char *b;
|
|
|
|
int len = xfrm_sa_len(x);
|
2005-06-18 22:54:36 -07:00
|
|
|
int headlen;
|
|
|
|
|
|
|
|
headlen = sizeof(*p);
|
|
|
|
if (c->event == XFRM_MSG_DELSA) {
|
|
|
|
len += RTA_SPACE(headlen);
|
|
|
|
headlen = sizeof(*id);
|
|
|
|
}
|
|
|
|
len += NLMSG_SPACE(headlen);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
b = skb->tail;
|
|
|
|
|
2005-06-18 22:54:36 -07:00
|
|
|
nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen);
|
2005-06-18 22:42:13 -07:00
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
p = NLMSG_DATA(nlh);
|
2005-06-18 22:54:36 -07:00
|
|
|
if (c->event == XFRM_MSG_DELSA) {
|
|
|
|
id = NLMSG_DATA(nlh);
|
|
|
|
memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr));
|
|
|
|
id->spi = x->id.spi;
|
|
|
|
id->family = x->props.family;
|
|
|
|
id->proto = x->id.proto;
|
|
|
|
|
|
|
|
p = RTA_DATA(__RTA_PUT(skb, XFRMA_SA, sizeof(*p)));
|
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
copy_to_user_state(x, p);
|
|
|
|
|
|
|
|
if (x->aalg)
|
|
|
|
RTA_PUT(skb, XFRMA_ALG_AUTH,
|
|
|
|
sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg);
|
|
|
|
if (x->ealg)
|
|
|
|
RTA_PUT(skb, XFRMA_ALG_CRYPT,
|
|
|
|
sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg);
|
|
|
|
if (x->calg)
|
|
|
|
RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
|
|
|
|
|
|
|
|
if (x->encap)
|
|
|
|
RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
|
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_SA;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
rtattr_failure:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (c->event) {
|
2005-06-18 22:44:37 -07:00
|
|
|
case XFRM_MSG_EXPIRE:
|
2005-06-18 22:42:13 -07:00
|
|
|
return xfrm_exp_state_notify(x, c);
|
2006-03-20 20:16:12 -07:00
|
|
|
case XFRM_MSG_NEWAE:
|
|
|
|
return xfrm_aevent_state_notify(x, c);
|
2005-06-18 22:44:37 -07:00
|
|
|
case XFRM_MSG_DELSA:
|
|
|
|
case XFRM_MSG_UPDSA:
|
|
|
|
case XFRM_MSG_NEWSA:
|
2005-06-18 22:42:13 -07:00
|
|
|
return xfrm_notify_sa(x, c);
|
2005-06-18 22:44:37 -07:00
|
|
|
case XFRM_MSG_FLUSHSA:
|
2005-06-18 22:42:13 -07:00
|
|
|
return xfrm_notify_sa_flush(c);
|
|
|
|
default:
|
|
|
|
printk("xfrm_user: Unknown SA event %d\n", c->event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
|
|
|
|
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
|
|
|
|
int dir)
|
|
|
|
{
|
|
|
|
struct xfrm_user_acquire *ua;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
__u32 seq = xfrm_get_acqseq();
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE,
|
|
|
|
sizeof(*ua));
|
|
|
|
ua = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
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));
|
|
|
|
copy_to_user_policy(xp, &ua->policy, dir);
|
|
|
|
ua->aalgos = xt->aalgos;
|
|
|
|
ua->ealgos = xt->ealgos;
|
|
|
|
ua->calgos = xt->calgos;
|
|
|
|
ua->seq = x->km.seq = seq;
|
|
|
|
|
|
|
|
if (copy_to_user_tmpl(xp, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
2006-07-24 23:30:44 -07:00
|
|
|
if (copy_to_user_state_sec_ctx(x, 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 00:12:27 -07:00
|
|
|
goto nlmsg_failure;
|
2006-11-20 17:51:22 -07:00
|
|
|
if (copy_to_user_policy_type(xp->type, skb) < 0)
|
2006-08-23 22:49:28 -07:00
|
|
|
goto nlmsg_failure;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
|
|
|
|
struct xfrm_policy *xp, int dir)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
|
|
|
|
len += NLMSG_SPACE(sizeof(struct xfrm_user_acquire));
|
2007-04-13 16:14:35 -07:00
|
|
|
len += RTA_SPACE(xfrm_user_sec_ctx_size(x->security));
|
2006-11-19 15:55:30 -07:00
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
|
|
|
|
#endif
|
2005-04-16 15:20:36 -07:00
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (build_acquire(skb, x, xt, xp, dir) < 0)
|
|
|
|
BUG();
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_ACQUIRE;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* User gives us xfrm_user_policy_info followed by an array of 0
|
|
|
|
* or more templates.
|
|
|
|
*/
|
2006-07-24 23:32:20 -07:00
|
|
|
static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
|
2005-04-16 15:20:36 -07:00
|
|
|
u8 *data, int len, int *dir)
|
|
|
|
{
|
|
|
|
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-24 23:32:20 -07:00
|
|
|
switch (sk->sk_family) {
|
2005-04-16 15:20:36 -07:00
|
|
|
case AF_INET:
|
|
|
|
if (opt != IP_XFRM_POLICY) {
|
|
|
|
*dir = -EOPNOTSUPP;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
|
|
|
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-03 20:19:26 -07:00
|
|
|
if (validate_tmpl(nr, ut, p->sel.family))
|
2005-04-16 15:20:36 -07:00
|
|
|
return NULL;
|
|
|
|
|
2005-07-26 15:43:17 -07:00
|
|
|
if (p->dir > XFRM_POLICY_OUT)
|
|
|
|
return NULL;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
xp = xfrm_policy_alloc(GFP_KERNEL);
|
|
|
|
if (xp == NULL) {
|
|
|
|
*dir = -ENOBUFS;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
copy_from_user_policy(xp, p);
|
2006-08-23 22:49:28 -07:00
|
|
|
xp->type = XFRM_POLICY_TYPE_MAIN;
|
2005-04-16 15:20:36 -07:00
|
|
|
copy_templates(xp, ut, nr);
|
|
|
|
|
|
|
|
*dir = p->dir;
|
|
|
|
|
|
|
|
return xp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp,
|
2006-03-20 20:16:12 -07:00
|
|
|
int dir, struct km_event *c)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct xfrm_user_polexpire *upe;
|
|
|
|
struct nlmsghdr *nlh;
|
2006-03-20 20:16:12 -07:00
|
|
|
int hard = c->data.hard;
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
nlh = NLMSG_PUT(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe));
|
2005-04-16 15:20:36 -07:00
|
|
|
upe = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
copy_to_user_policy(xp, &upe->pol, dir);
|
|
|
|
if (copy_to_user_tmpl(xp, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
[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 00:12:27 -07:00
|
|
|
if (copy_to_user_sec_ctx(xp, skb))
|
|
|
|
goto nlmsg_failure;
|
2006-11-20 17:51:22 -07:00
|
|
|
if (copy_to_user_policy_type(xp->type, skb) < 0)
|
2006-08-23 22:49:28 -07:00
|
|
|
goto nlmsg_failure;
|
2005-04-16 15:20:36 -07:00
|
|
|
upe->hard = !!hard;
|
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
|
|
|
|
len += NLMSG_SPACE(sizeof(struct xfrm_user_polexpire));
|
2007-04-13 16:14:35 -07:00
|
|
|
len += RTA_SPACE(xfrm_user_sec_ctx_size(xp->security));
|
2006-11-19 15:55:30 -07:00
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
|
|
|
|
#endif
|
2005-04-16 15:20:36 -07:00
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2006-03-20 20:16:12 -07:00
|
|
|
if (build_polexpire(skb, xp, dir, c) < 0)
|
2005-04-16 15:20:36 -07:00
|
|
|
BUG();
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_EXPIRE;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2005-06-18 22:42:13 -07:00
|
|
|
static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c)
|
|
|
|
{
|
|
|
|
struct xfrm_userpolicy_info *p;
|
2005-06-18 22:54:36 -07:00
|
|
|
struct xfrm_userpolicy_id *id;
|
2005-06-18 22:42:13 -07:00
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
unsigned char *b;
|
|
|
|
int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
|
2005-06-18 22:54:36 -07:00
|
|
|
int headlen;
|
|
|
|
|
|
|
|
headlen = sizeof(*p);
|
|
|
|
if (c->event == XFRM_MSG_DELPOLICY) {
|
|
|
|
len += RTA_SPACE(headlen);
|
|
|
|
headlen = sizeof(*id);
|
|
|
|
}
|
2006-11-19 15:53:07 -07:00
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
|
|
|
|
#endif
|
2005-06-18 22:54:36 -07:00
|
|
|
len += NLMSG_SPACE(headlen);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
b = skb->tail;
|
|
|
|
|
2005-06-18 22:54:36 -07:00
|
|
|
nlh = NLMSG_PUT(skb, c->pid, c->seq, c->event, headlen);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
p = NLMSG_DATA(nlh);
|
2005-06-18 22:54:36 -07:00
|
|
|
if (c->event == XFRM_MSG_DELPOLICY) {
|
|
|
|
id = NLMSG_DATA(nlh);
|
|
|
|
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));
|
|
|
|
|
|
|
|
p = RTA_DATA(__RTA_PUT(skb, XFRMA_POLICY, sizeof(*p)));
|
|
|
|
}
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
copy_to_user_policy(xp, p, dir);
|
|
|
|
if (copy_to_user_tmpl(xp, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
2006-11-20 17:51:22 -07:00
|
|
|
if (copy_to_user_policy_type(xp->type, skb) < 0)
|
2006-08-23 22:49:28 -07:00
|
|
|
goto nlmsg_failure;
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlmsg_failure:
|
2005-06-18 22:54:36 -07:00
|
|
|
rtattr_failure:
|
2005-06-18 22:42:13 -07:00
|
|
|
kfree_skb(skb);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_notify_policy_flush(struct km_event *c)
|
|
|
|
{
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
struct sk_buff *skb;
|
|
|
|
unsigned char *b;
|
2006-11-19 15:55:30 -07:00
|
|
|
int len = 0;
|
2006-08-23 22:49:28 -07:00
|
|
|
#ifdef CONFIG_XFRM_SUB_POLICY
|
2006-11-19 15:55:30 -07:00
|
|
|
len += RTA_SPACE(sizeof(struct xfrm_userpolicy_type));
|
2006-08-23 22:49:28 -07:00
|
|
|
#endif
|
2006-11-19 15:55:30 -07:00
|
|
|
len += NLMSG_LENGTH(0);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
b = skb->tail;
|
|
|
|
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
|
2006-08-23 22:49:28 -07:00
|
|
|
nlh->nlmsg_flags = 0;
|
2006-11-27 13:58:20 -07:00
|
|
|
if (copy_to_user_policy_type(c->data.type, skb) < 0)
|
|
|
|
goto nlmsg_failure;
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
|
2005-08-14 19:29:52 -07:00
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_POLICY;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC);
|
2005-06-18 22:42:13 -07:00
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
kfree_skb(skb);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (c->event) {
|
2005-06-18 22:44:37 -07:00
|
|
|
case XFRM_MSG_NEWPOLICY:
|
|
|
|
case XFRM_MSG_UPDPOLICY:
|
|
|
|
case XFRM_MSG_DELPOLICY:
|
2005-06-18 22:42:13 -07:00
|
|
|
return xfrm_notify_policy(xp, dir, c);
|
2005-06-18 22:44:37 -07:00
|
|
|
case XFRM_MSG_FLUSHPOLICY:
|
2005-06-18 22:42:13 -07:00
|
|
|
return xfrm_notify_policy_flush(c);
|
2005-06-18 22:44:37 -07:00
|
|
|
case XFRM_MSG_POLEXPIRE:
|
2005-06-18 22:42:13 -07:00
|
|
|
return xfrm_exp_policy_notify(xp, dir, c);
|
|
|
|
default:
|
|
|
|
printk("xfrm_user: Unknown Policy event %d\n", c->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-08-23 20:44:06 -07: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;
|
|
|
|
unsigned char *b = skb->tail;
|
|
|
|
|
|
|
|
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur));
|
|
|
|
ur = NLMSG_DATA(nlh);
|
|
|
|
nlh->nlmsg_flags = 0;
|
|
|
|
|
|
|
|
ur->proto = proto;
|
|
|
|
memcpy(&ur->sel, sel, sizeof(ur->sel));
|
|
|
|
|
|
|
|
if (addr)
|
|
|
|
RTA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr);
|
|
|
|
|
|
|
|
nlh->nlmsg_len = skb->tail - b;
|
|
|
|
return skb->len;
|
|
|
|
|
|
|
|
nlmsg_failure:
|
|
|
|
rtattr_failure:
|
|
|
|
skb_trim(skb, b - skb->data);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int xfrm_send_report(u8 proto, struct xfrm_selector *sel,
|
|
|
|
xfrm_address_t *addr)
|
|
|
|
{
|
|
|
|
struct sk_buff *skb;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(struct xfrm_user_report)));
|
|
|
|
skb = alloc_skb(len, GFP_ATOMIC);
|
|
|
|
if (skb == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (build_report(skb, proto, sel, addr) < 0)
|
|
|
|
BUG();
|
|
|
|
|
|
|
|
NETLINK_CB(skb).dst_group = XFRMNLGRP_REPORT;
|
|
|
|
return netlink_broadcast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC);
|
|
|
|
}
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
static struct xfrm_mgr netlink_mgr = {
|
|
|
|
.id = "netlink",
|
|
|
|
.notify = xfrm_send_state_notify,
|
|
|
|
.acquire = xfrm_send_acquire,
|
|
|
|
.compile_policy = xfrm_compile_policy,
|
|
|
|
.notify_policy = xfrm_send_policy_notify,
|
2006-08-23 20:44:06 -07:00
|
|
|
.report = xfrm_send_report,
|
2007-02-08 14:12:32 -07:00
|
|
|
.migrate = xfrm_send_migrate,
|
2005-04-16 15:20:36 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init xfrm_user_init(void)
|
|
|
|
{
|
2006-03-20 23:40:54 -07:00
|
|
|
struct sock *nlsk;
|
|
|
|
|
2006-08-23 19:12:56 -07:00
|
|
|
printk(KERN_INFO "Initializing XFRM netlink socket\n");
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2006-03-20 23:40:54 -07:00
|
|
|
nlsk = netlink_kernel_create(NETLINK_XFRM, XFRMNLGRP_MAX,
|
2007-02-09 07:25:29 -07:00
|
|
|
xfrm_netlink_rcv, THIS_MODULE);
|
2006-03-20 23:40:54 -07:00
|
|
|
if (nlsk == NULL)
|
2005-04-16 15:20:36 -07:00
|
|
|
return -ENOMEM;
|
2006-03-20 23:40:54 -07:00
|
|
|
rcu_assign_pointer(xfrm_nl, nlsk);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
xfrm_register_km(&netlink_mgr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit xfrm_user_exit(void)
|
|
|
|
{
|
2006-03-20 23:40:54 -07:00
|
|
|
struct sock *nlsk = xfrm_nl;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
xfrm_unregister_km(&netlink_mgr);
|
2006-03-20 23:40:54 -07:00
|
|
|
rcu_assign_pointer(xfrm_nl, NULL);
|
|
|
|
synchronize_rcu();
|
|
|
|
sock_release(nlsk->sk_socket);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(xfrm_user_init);
|
|
|
|
module_exit(xfrm_user_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
2005-08-09 19:40:55 -07:00
|
|
|
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
|
2006-03-20 20:15:11 -07:00
|
|
|
|