Commit 2b980dbd authored by Paul Moore's avatar Paul Moore Committed by James Morris

lsm: Add hooks to the TUN driver

The TUN driver lacks any LSM hooks which makes it difficult for LSM modules,
such as SELinux, to enforce access controls on network traffic generated by
TUN users; this is particularly problematic for virtualization apps such as
QEMU and KVM.  This patch adds three new LSM hooks designed to control the
creation and attachment of TUN devices, the hooks are:

 * security_tun_dev_create()
   Provides access control for the creation of new TUN devices

 * security_tun_dev_post_create()
   Provides the ability to create the necessary socket LSM state for newly
   created TUN devices

 * security_tun_dev_attach()
   Provides access control for attaching to existing, persistent TUN devices
   and the ability to update the TUN device's socket LSM state as necessary
Signed-off-by: default avatarPaul Moore <paul.moore@hp.com>
Acked-by: default avatarEric Paris <eparis@parisplace.org>
Acked-by: default avatarSerge Hallyn <serue@us.ibm.com>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent d8e180dc
...@@ -130,17 +130,10 @@ static inline struct tun_sock *tun_sk(struct sock *sk) ...@@ -130,17 +130,10 @@ static inline struct tun_sock *tun_sk(struct sock *sk)
static int tun_attach(struct tun_struct *tun, struct file *file) static int tun_attach(struct tun_struct *tun, struct file *file)
{ {
struct tun_file *tfile = file->private_data; struct tun_file *tfile = file->private_data;
const struct cred *cred = current_cred();
int err; int err;
ASSERT_RTNL(); ASSERT_RTNL();
/* Check permissions */
if (((tun->owner != -1 && cred->euid != tun->owner) ||
(tun->group != -1 && !in_egroup_p(tun->group))) &&
!capable(CAP_NET_ADMIN))
return -EPERM;
netif_tx_lock_bh(tun->dev); netif_tx_lock_bh(tun->dev);
err = -EINVAL; err = -EINVAL;
...@@ -926,6 +919,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) ...@@ -926,6 +919,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
dev = __dev_get_by_name(net, ifr->ifr_name); dev = __dev_get_by_name(net, ifr->ifr_name);
if (dev) { if (dev) {
const struct cred *cred = current_cred();
if (ifr->ifr_flags & IFF_TUN_EXCL) if (ifr->ifr_flags & IFF_TUN_EXCL)
return -EBUSY; return -EBUSY;
if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops) if ((ifr->ifr_flags & IFF_TUN) && dev->netdev_ops == &tun_netdev_ops)
...@@ -935,6 +930,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) ...@@ -935,6 +930,14 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
else else
return -EINVAL; return -EINVAL;
if (((tun->owner != -1 && cred->euid != tun->owner) ||
(tun->group != -1 && !in_egroup_p(tun->group))) &&
!capable(CAP_NET_ADMIN))
return -EPERM;
err = security_tun_dev_attach(tun->sk);
if (err < 0)
return err;
err = tun_attach(tun, file); err = tun_attach(tun, file);
if (err < 0) if (err < 0)
return err; return err;
...@@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) ...@@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
err = security_tun_dev_create();
if (err < 0)
return err;
/* Set dev type */ /* Set dev type */
if (ifr->ifr_flags & IFF_TUN) { if (ifr->ifr_flags & IFF_TUN) {
...@@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) ...@@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
tun->sk = sk; tun->sk = sk;
container_of(sk, struct tun_sock, sk)->tun = tun; container_of(sk, struct tun_sock, sk)->tun = tun;
security_tun_dev_post_create(sk);
tun_net_init(dev); tun_net_init(dev);
if (strchr(dev->name, '%')) { if (strchr(dev->name, '%')) {
......
...@@ -998,6 +998,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -998,6 +998,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Sets the connection's peersid to the secmark on skb. * Sets the connection's peersid to the secmark on skb.
* @req_classify_flow: * @req_classify_flow:
* Sets the flow's sid to the openreq sid. * Sets the flow's sid to the openreq sid.
* @tun_dev_create:
* Check permissions prior to creating a new TUN device.
* @tun_dev_post_create:
* This hook allows a module to update or allocate a per-socket security
* structure.
* @sk contains the newly created sock structure.
* @tun_dev_attach:
* Check permissions prior to attaching to a persistent TUN device. This
* hook can also be used by the module to update any security state
* associated with the TUN device's sock structure.
* @sk contains the existing sock structure.
* *
* Security hooks for XFRM operations. * Security hooks for XFRM operations.
* *
...@@ -1597,6 +1608,9 @@ struct security_operations { ...@@ -1597,6 +1608,9 @@ struct security_operations {
void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req);
void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb);
void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl); void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl);
int (*tun_dev_create)(void);
void (*tun_dev_post_create)(struct sock *sk);
int (*tun_dev_attach)(struct sock *sk);
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
...@@ -2586,6 +2600,9 @@ void security_inet_csk_clone(struct sock *newsk, ...@@ -2586,6 +2600,9 @@ void security_inet_csk_clone(struct sock *newsk,
const struct request_sock *req); const struct request_sock *req);
void security_inet_conn_established(struct sock *sk, void security_inet_conn_established(struct sock *sk,
struct sk_buff *skb); struct sk_buff *skb);
int security_tun_dev_create(void);
void security_tun_dev_post_create(struct sock *sk);
int security_tun_dev_attach(struct sock *sk);
#else /* CONFIG_SECURITY_NETWORK */ #else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct socket *sock, static inline int security_unix_stream_connect(struct socket *sock,
...@@ -2736,6 +2753,20 @@ static inline void security_inet_conn_established(struct sock *sk, ...@@ -2736,6 +2753,20 @@ static inline void security_inet_conn_established(struct sock *sk,
struct sk_buff *skb) struct sk_buff *skb)
{ {
} }
static inline int security_tun_dev_create(void)
{
return 0;
}
static inline void security_tun_dev_post_create(struct sock *sk)
{
}
static inline int security_tun_dev_attach(struct sock *sk)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
......
...@@ -706,10 +706,26 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb) ...@@ -706,10 +706,26 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb)
{ {
} }
static void cap_req_classify_flow(const struct request_sock *req, static void cap_req_classify_flow(const struct request_sock *req,
struct flowi *fl) struct flowi *fl)
{ {
} }
static int cap_tun_dev_create(void)
{
return 0;
}
static void cap_tun_dev_post_create(struct sock *sk)
{
}
static int cap_tun_dev_attach(struct sock *sk)
{
return 0;
}
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
...@@ -1026,6 +1042,9 @@ void security_fixup_ops(struct security_operations *ops) ...@@ -1026,6 +1042,9 @@ void security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, inet_csk_clone); set_to_cap_if_null(ops, inet_csk_clone);
set_to_cap_if_null(ops, inet_conn_established); set_to_cap_if_null(ops, inet_conn_established);
set_to_cap_if_null(ops, req_classify_flow); set_to_cap_if_null(ops, req_classify_flow);
set_to_cap_if_null(ops, tun_dev_create);
set_to_cap_if_null(ops, tun_dev_post_create);
set_to_cap_if_null(ops, tun_dev_attach);
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
set_to_cap_if_null(ops, xfrm_policy_alloc_security); set_to_cap_if_null(ops, xfrm_policy_alloc_security);
......
...@@ -1117,6 +1117,24 @@ void security_inet_conn_established(struct sock *sk, ...@@ -1117,6 +1117,24 @@ void security_inet_conn_established(struct sock *sk,
security_ops->inet_conn_established(sk, skb); security_ops->inet_conn_established(sk, skb);
} }
int security_tun_dev_create(void)
{
return security_ops->tun_dev_create();
}
EXPORT_SYMBOL(security_tun_dev_create);
void security_tun_dev_post_create(struct sock *sk)
{
return security_ops->tun_dev_post_create(sk);
}
EXPORT_SYMBOL(security_tun_dev_post_create);
int security_tun_dev_attach(struct sock *sk)
{
return security_ops->tun_dev_attach(sk);
}
EXPORT_SYMBOL(security_tun_dev_attach);
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment