On Mon, Aug 10, 2009 at 1:28 PM, Paul Moore<paul.moore@xxxxxx> wrote: > 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 Looks good to me, feel free to add my Ack. -Eric > --- > > drivers/net/tun.c | 22 +++++++++++++++------- > include/linux/security.h | 31 +++++++++++++++++++++++++++++++ > security/capability.c | 19 +++++++++++++++++++ > security/security.c | 18 ++++++++++++++++++ > 4 files changed, 83 insertions(+), 7 deletions(-) > > diff --git a/drivers/net/tun.c b/drivers/net/tun.c > index 027f7ab..e6667ce 100644 > --- a/drivers/net/tun.c > +++ b/drivers/net/tun.c > @@ -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) > { > struct tun_file *tfile = file->private_data; > - const struct cred *cred = current_cred(); > int err; > > 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); > > err = -EINVAL; > @@ -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); > if (dev) { > + const struct cred *cred = current_cred(); > + > if (ifr->ifr_flags & IFF_TUN_EXCL) > return -EBUSY; > 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) > else > 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); > if (err < 0) > return err; > @@ -947,6 +950,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) > > if (!capable(CAP_NET_ADMIN)) > return -EPERM; > + err = security_tun_dev_create(); > + if (err < 0) > + return err; > > /* Set dev type */ > if (ifr->ifr_flags & IFF_TUN) { > @@ -989,6 +995,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) > tun->sk = sk; > container_of(sk, struct tun_sock, sk)->tun = tun; > > + security_tun_dev_post_create(sk); > + > tun_net_init(dev); > > if (strchr(dev->name, '%')) { > diff --git a/include/linux/security.h b/include/linux/security.h > index 5eff459..d8efc35 100644 > --- a/include/linux/security.h > +++ b/include/linux/security.h > @@ -974,6 +974,17 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) > * Sets the connection's peersid to the secmark on skb. > * @req_classify_flow: > * 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. > * > @@ -1572,6 +1583,9 @@ struct security_operations { > void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req); > void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb); > 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 */ > > #ifdef CONFIG_SECURITY_NETWORK_XFRM > @@ -2557,6 +2571,9 @@ void security_inet_csk_clone(struct sock *newsk, > const struct request_sock *req); > void security_inet_conn_established(struct sock *sk, > 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 */ > static inline int security_unix_stream_connect(struct socket *sock, > @@ -2707,6 +2724,20 @@ static inline void security_inet_conn_established(struct sock *sk, > 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 */ > > #ifdef CONFIG_SECURITY_NETWORK_XFRM > diff --git a/security/capability.c b/security/capability.c > index 21b6cea..a10a44a 100644 > --- a/security/capability.c > +++ b/security/capability.c > @@ -710,10 +710,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, > 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 */ > > #ifdef CONFIG_SECURITY_NETWORK_XFRM > @@ -1029,6 +1045,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_conn_established); > 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 */ > #ifdef CONFIG_SECURITY_NETWORK_XFRM > set_to_cap_if_null(ops, xfrm_policy_alloc_security); > diff --git a/security/security.c b/security/security.c > index dc7674f..dc6953c 100644 > --- a/security/security.c > +++ b/security/security.c > @@ -1112,6 +1112,24 @@ void security_inet_conn_established(struct sock *sk, > 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 */ > > #ifdef CONFIG_SECURITY_NETWORK_XFRM > > -- > To unsubscribe from this list: send the line "unsubscribe linux-security-module" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with the words "unsubscribe selinux" without quotes as the message.