diff options
-rw-r--r-- | security/selinux/hooks.c | 119 |
1 files changed, 45 insertions, 74 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 01f52424cfe5..e95004010c8b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -3651,26 +3651,19 @@ static u32 socket_sockcreate_sid(const struct task_security_struct *tsec) | |||
3651 | return tsec->sockcreate_sid ? : tsec->sid; | 3651 | return tsec->sockcreate_sid ? : tsec->sid; |
3652 | } | 3652 | } |
3653 | 3653 | ||
3654 | static int socket_has_perm(struct task_struct *task, struct socket *sock, | 3654 | static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) |
3655 | u32 perms) | ||
3656 | { | 3655 | { |
3657 | struct inode_security_struct *isec; | 3656 | struct sk_security_struct *sksec = sk->sk_security; |
3658 | struct common_audit_data ad; | 3657 | struct common_audit_data ad; |
3659 | u32 sid; | 3658 | u32 tsid = task_sid(task); |
3660 | int err = 0; | ||
3661 | 3659 | ||
3662 | isec = SOCK_INODE(sock)->i_security; | 3660 | if (sksec->sid == SECINITSID_KERNEL) |
3663 | 3661 | return 0; | |
3664 | if (isec->sid == SECINITSID_KERNEL) | ||
3665 | goto out; | ||
3666 | sid = task_sid(task); | ||
3667 | 3662 | ||
3668 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3663 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
3669 | ad.u.net.sk = sock->sk; | 3664 | ad.u.net.sk = sk; |
3670 | err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | ||
3671 | 3665 | ||
3672 | out: | 3666 | return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad); |
3673 | return err; | ||
3674 | } | 3667 | } |
3675 | 3668 | ||
3676 | static int selinux_socket_create(int family, int type, | 3669 | static int selinux_socket_create(int family, int type, |
@@ -3722,10 +3715,11 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
3722 | 3715 | ||
3723 | static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) | 3716 | static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) |
3724 | { | 3717 | { |
3718 | struct sock *sk = sock->sk; | ||
3725 | u16 family; | 3719 | u16 family; |
3726 | int err; | 3720 | int err; |
3727 | 3721 | ||
3728 | err = socket_has_perm(current, sock, SOCKET__BIND); | 3722 | err = sock_has_perm(current, sk, SOCKET__BIND); |
3729 | if (err) | 3723 | if (err) |
3730 | goto out; | 3724 | goto out; |
3731 | 3725 | ||
@@ -3734,19 +3728,16 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3734 | * Multiple address binding for SCTP is not supported yet: we just | 3728 | * Multiple address binding for SCTP is not supported yet: we just |
3735 | * check the first address now. | 3729 | * check the first address now. |
3736 | */ | 3730 | */ |
3737 | family = sock->sk->sk_family; | 3731 | family = sk->sk_family; |
3738 | if (family == PF_INET || family == PF_INET6) { | 3732 | if (family == PF_INET || family == PF_INET6) { |
3739 | char *addrp; | 3733 | char *addrp; |
3740 | struct inode_security_struct *isec; | 3734 | struct sk_security_struct *sksec = sk->sk_security; |
3741 | struct common_audit_data ad; | 3735 | struct common_audit_data ad; |
3742 | struct sockaddr_in *addr4 = NULL; | 3736 | struct sockaddr_in *addr4 = NULL; |
3743 | struct sockaddr_in6 *addr6 = NULL; | 3737 | struct sockaddr_in6 *addr6 = NULL; |
3744 | unsigned short snum; | 3738 | unsigned short snum; |
3745 | struct sock *sk = sock->sk; | ||
3746 | u32 sid, node_perm; | 3739 | u32 sid, node_perm; |
3747 | 3740 | ||
3748 | isec = SOCK_INODE(sock)->i_security; | ||
3749 | |||
3750 | if (family == PF_INET) { | 3741 | if (family == PF_INET) { |
3751 | addr4 = (struct sockaddr_in *)address; | 3742 | addr4 = (struct sockaddr_in *)address; |
3752 | snum = ntohs(addr4->sin_port); | 3743 | snum = ntohs(addr4->sin_port); |
@@ -3770,15 +3761,15 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3770 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3761 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
3771 | ad.u.net.sport = htons(snum); | 3762 | ad.u.net.sport = htons(snum); |
3772 | ad.u.net.family = family; | 3763 | ad.u.net.family = family; |
3773 | err = avc_has_perm(isec->sid, sid, | 3764 | err = avc_has_perm(sksec->sid, sid, |
3774 | isec->sclass, | 3765 | sksec->sclass, |
3775 | SOCKET__NAME_BIND, &ad); | 3766 | SOCKET__NAME_BIND, &ad); |
3776 | if (err) | 3767 | if (err) |
3777 | goto out; | 3768 | goto out; |
3778 | } | 3769 | } |
3779 | } | 3770 | } |
3780 | 3771 | ||
3781 | switch (isec->sclass) { | 3772 | switch (sksec->sclass) { |
3782 | case SECCLASS_TCP_SOCKET: | 3773 | case SECCLASS_TCP_SOCKET: |
3783 | node_perm = TCP_SOCKET__NODE_BIND; | 3774 | node_perm = TCP_SOCKET__NODE_BIND; |
3784 | break; | 3775 | break; |
@@ -3809,8 +3800,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3809 | else | 3800 | else |
3810 | ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr); | 3801 | ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr); |
3811 | 3802 | ||
3812 | err = avc_has_perm(isec->sid, sid, | 3803 | err = avc_has_perm(sksec->sid, sid, |
3813 | isec->sclass, node_perm, &ad); | 3804 | sksec->sclass, node_perm, &ad); |
3814 | if (err) | 3805 | if (err) |
3815 | goto out; | 3806 | goto out; |
3816 | } | 3807 | } |
@@ -3821,19 +3812,18 @@ out: | |||
3821 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3812 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
3822 | { | 3813 | { |
3823 | struct sock *sk = sock->sk; | 3814 | struct sock *sk = sock->sk; |
3824 | struct inode_security_struct *isec; | 3815 | struct sk_security_struct *sksec = sk->sk_security; |
3825 | int err; | 3816 | int err; |
3826 | 3817 | ||
3827 | err = socket_has_perm(current, sock, SOCKET__CONNECT); | 3818 | err = sock_has_perm(current, sk, SOCKET__CONNECT); |
3828 | if (err) | 3819 | if (err) |
3829 | return err; | 3820 | return err; |
3830 | 3821 | ||
3831 | /* | 3822 | /* |
3832 | * If a TCP or DCCP socket, check name_connect permission for the port. | 3823 | * If a TCP or DCCP socket, check name_connect permission for the port. |
3833 | */ | 3824 | */ |
3834 | isec = SOCK_INODE(sock)->i_security; | 3825 | if (sksec->sclass == SECCLASS_TCP_SOCKET || |
3835 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3826 | sksec->sclass == SECCLASS_DCCP_SOCKET) { |
3836 | isec->sclass == SECCLASS_DCCP_SOCKET) { | ||
3837 | struct common_audit_data ad; | 3827 | struct common_audit_data ad; |
3838 | struct sockaddr_in *addr4 = NULL; | 3828 | struct sockaddr_in *addr4 = NULL; |
3839 | struct sockaddr_in6 *addr6 = NULL; | 3829 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3856,13 +3846,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3856 | if (err) | 3846 | if (err) |
3857 | goto out; | 3847 | goto out; |
3858 | 3848 | ||
3859 | perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? | 3849 | perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? |
3860 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | 3850 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; |
3861 | 3851 | ||
3862 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3852 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
3863 | ad.u.net.dport = htons(snum); | 3853 | ad.u.net.dport = htons(snum); |
3864 | ad.u.net.family = sk->sk_family; | 3854 | ad.u.net.family = sk->sk_family; |
3865 | err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); | 3855 | err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad); |
3866 | if (err) | 3856 | if (err) |
3867 | goto out; | 3857 | goto out; |
3868 | } | 3858 | } |
@@ -3875,7 +3865,7 @@ out: | |||
3875 | 3865 | ||
3876 | static int selinux_socket_listen(struct socket *sock, int backlog) | 3866 | static int selinux_socket_listen(struct socket *sock, int backlog) |
3877 | { | 3867 | { |
3878 | return socket_has_perm(current, sock, SOCKET__LISTEN); | 3868 | return sock_has_perm(current, sock->sk, SOCKET__LISTEN); |
3879 | } | 3869 | } |
3880 | 3870 | ||
3881 | static int selinux_socket_accept(struct socket *sock, struct socket *newsock) | 3871 | static int selinux_socket_accept(struct socket *sock, struct socket *newsock) |
@@ -3884,7 +3874,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) | |||
3884 | struct inode_security_struct *isec; | 3874 | struct inode_security_struct *isec; |
3885 | struct inode_security_struct *newisec; | 3875 | struct inode_security_struct *newisec; |
3886 | 3876 | ||
3887 | err = socket_has_perm(current, sock, SOCKET__ACCEPT); | 3877 | err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT); |
3888 | if (err) | 3878 | if (err) |
3889 | return err; | 3879 | return err; |
3890 | 3880 | ||
@@ -3901,30 +3891,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) | |||
3901 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, | 3891 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, |
3902 | int size) | 3892 | int size) |
3903 | { | 3893 | { |
3904 | return socket_has_perm(current, sock, SOCKET__WRITE); | 3894 | return sock_has_perm(current, sock->sk, SOCKET__WRITE); |
3905 | } | 3895 | } |
3906 | 3896 | ||
3907 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, | 3897 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, |
3908 | int size, int flags) | 3898 | int size, int flags) |
3909 | { | 3899 | { |
3910 | return socket_has_perm(current, sock, SOCKET__READ); | 3900 | return sock_has_perm(current, sock->sk, SOCKET__READ); |
3911 | } | 3901 | } |
3912 | 3902 | ||
3913 | static int selinux_socket_getsockname(struct socket *sock) | 3903 | static int selinux_socket_getsockname(struct socket *sock) |
3914 | { | 3904 | { |
3915 | return socket_has_perm(current, sock, SOCKET__GETATTR); | 3905 | return sock_has_perm(current, sock->sk, SOCKET__GETATTR); |
3916 | } | 3906 | } |
3917 | 3907 | ||
3918 | static int selinux_socket_getpeername(struct socket *sock) | 3908 | static int selinux_socket_getpeername(struct socket *sock) |
3919 | { | 3909 | { |
3920 | return socket_has_perm(current, sock, SOCKET__GETATTR); | 3910 | return sock_has_perm(current, sock->sk, SOCKET__GETATTR); |
3921 | } | 3911 | } |
3922 | 3912 | ||
3923 | static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) | 3913 | static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) |
3924 | { | 3914 | { |
3925 | int err; | 3915 | int err; |
3926 | 3916 | ||
3927 | err = socket_has_perm(current, sock, SOCKET__SETOPT); | 3917 | err = sock_has_perm(current, sock->sk, SOCKET__SETOPT); |
3928 | if (err) | 3918 | if (err) |
3929 | return err; | 3919 | return err; |
3930 | 3920 | ||
@@ -3934,12 +3924,12 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname | |||
3934 | static int selinux_socket_getsockopt(struct socket *sock, int level, | 3924 | static int selinux_socket_getsockopt(struct socket *sock, int level, |
3935 | int optname) | 3925 | int optname) |
3936 | { | 3926 | { |
3937 | return socket_has_perm(current, sock, SOCKET__GETOPT); | 3927 | return sock_has_perm(current, sock->sk, SOCKET__GETOPT); |
3938 | } | 3928 | } |
3939 | 3929 | ||
3940 | static int selinux_socket_shutdown(struct socket *sock, int how) | 3930 | static int selinux_socket_shutdown(struct socket *sock, int how) |
3941 | { | 3931 | { |
3942 | return socket_has_perm(current, sock, SOCKET__SHUTDOWN); | 3932 | return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN); |
3943 | } | 3933 | } |
3944 | 3934 | ||
3945 | static int selinux_socket_unix_stream_connect(struct socket *sock, | 3935 | static int selinux_socket_unix_stream_connect(struct socket *sock, |
@@ -3977,23 +3967,15 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
3977 | static int selinux_socket_unix_may_send(struct socket *sock, | 3967 | static int selinux_socket_unix_may_send(struct socket *sock, |
3978 | struct socket *other) | 3968 | struct socket *other) |
3979 | { | 3969 | { |
3980 | struct inode_security_struct *isec; | 3970 | struct sk_security_struct *ssec = sock->sk->sk_security; |
3981 | struct inode_security_struct *other_isec; | 3971 | struct sk_security_struct *osec = other->sk->sk_security; |
3982 | struct common_audit_data ad; | 3972 | struct common_audit_data ad; |
3983 | int err; | ||
3984 | |||
3985 | isec = SOCK_INODE(sock)->i_security; | ||
3986 | other_isec = SOCK_INODE(other)->i_security; | ||
3987 | 3973 | ||
3988 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3974 | COMMON_AUDIT_DATA_INIT(&ad, NET); |
3989 | ad.u.net.sk = other->sk; | 3975 | ad.u.net.sk = other->sk; |
3990 | 3976 | ||
3991 | err = avc_has_perm(isec->sid, other_isec->sid, | 3977 | return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO, |
3992 | isec->sclass, SOCKET__SENDTO, &ad); | 3978 | &ad); |
3993 | if (err) | ||
3994 | return err; | ||
3995 | |||
3996 | return 0; | ||
3997 | } | 3979 | } |
3998 | 3980 | ||
3999 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | 3981 | static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, |
@@ -4132,26 +4114,18 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op | |||
4132 | int err = 0; | 4114 | int err = 0; |
4133 | char *scontext; | 4115 | char *scontext; |
4134 | u32 scontext_len; | 4116 | u32 scontext_len; |
4135 | struct sk_security_struct *sksec; | 4117 | struct sk_security_struct *sksec = sock->sk->sk_security; |
4136 | struct inode_security_struct *isec; | ||
4137 | u32 peer_sid = SECSID_NULL; | 4118 | u32 peer_sid = SECSID_NULL; |
4138 | 4119 | ||
4139 | isec = SOCK_INODE(sock)->i_security; | 4120 | if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || |
4140 | 4121 | sksec->sclass == SECCLASS_TCP_SOCKET) | |
4141 | if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET || | ||
4142 | isec->sclass == SECCLASS_TCP_SOCKET) { | ||
4143 | sksec = sock->sk->sk_security; | ||
4144 | peer_sid = sksec->peer_sid; | 4122 | peer_sid = sksec->peer_sid; |
4145 | } | 4123 | if (peer_sid == SECSID_NULL) |
4146 | if (peer_sid == SECSID_NULL) { | 4124 | return -ENOPROTOOPT; |
4147 | err = -ENOPROTOOPT; | ||
4148 | goto out; | ||
4149 | } | ||
4150 | 4125 | ||
4151 | err = security_sid_to_context(peer_sid, &scontext, &scontext_len); | 4126 | err = security_sid_to_context(peer_sid, &scontext, &scontext_len); |
4152 | |||
4153 | if (err) | 4127 | if (err) |
4154 | goto out; | 4128 | return err; |
4155 | 4129 | ||
4156 | if (scontext_len > len) { | 4130 | if (scontext_len > len) { |
4157 | err = -ERANGE; | 4131 | err = -ERANGE; |
@@ -4164,9 +4138,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op | |||
4164 | out_len: | 4138 | out_len: |
4165 | if (put_user(scontext_len, optlen)) | 4139 | if (put_user(scontext_len, optlen)) |
4166 | err = -EFAULT; | 4140 | err = -EFAULT; |
4167 | |||
4168 | kfree(scontext); | 4141 | kfree(scontext); |
4169 | out: | ||
4170 | return err; | 4142 | return err; |
4171 | } | 4143 | } |
4172 | 4144 | ||
@@ -4378,8 +4350,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | |||
4378 | int err = 0; | 4350 | int err = 0; |
4379 | u32 perm; | 4351 | u32 perm; |
4380 | struct nlmsghdr *nlh; | 4352 | struct nlmsghdr *nlh; |
4381 | struct socket *sock = sk->sk_socket; | 4353 | struct sk_security_struct *sksec = sk->sk_security; |
4382 | struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; | ||
4383 | 4354 | ||
4384 | if (skb->len < NLMSG_SPACE(0)) { | 4355 | if (skb->len < NLMSG_SPACE(0)) { |
4385 | err = -EINVAL; | 4356 | err = -EINVAL; |
@@ -4387,13 +4358,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | |||
4387 | } | 4358 | } |
4388 | nlh = nlmsg_hdr(skb); | 4359 | nlh = nlmsg_hdr(skb); |
4389 | 4360 | ||
4390 | err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm); | 4361 | err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); |
4391 | if (err) { | 4362 | if (err) { |
4392 | if (err == -EINVAL) { | 4363 | if (err == -EINVAL) { |
4393 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR, | 4364 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR, |
4394 | "SELinux: unrecognized netlink message" | 4365 | "SELinux: unrecognized netlink message" |
4395 | " type=%hu for sclass=%hu\n", | 4366 | " type=%hu for sclass=%hu\n", |
4396 | nlh->nlmsg_type, isec->sclass); | 4367 | nlh->nlmsg_type, sksec->sclass); |
4397 | if (!selinux_enforcing || security_get_allow_unknown()) | 4368 | if (!selinux_enforcing || security_get_allow_unknown()) |
4398 | err = 0; | 4369 | err = 0; |
4399 | } | 4370 | } |
@@ -4404,7 +4375,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) | |||
4404 | goto out; | 4375 | goto out; |
4405 | } | 4376 | } |
4406 | 4377 | ||
4407 | err = socket_has_perm(current, sock, perm); | 4378 | err = sock_has_perm(current, sk, perm); |
4408 | out: | 4379 | out: |
4409 | return err; | 4380 | return err; |
4410 | } | 4381 | } |