Skip to content

Commit c71d8eb

Browse files
Tetsuo Handadavem330
authored andcommitted
net: Fix security_socket_sendmsg() bypass problem.
The sendmmsg() introduced by commit 228e548 "net: Add sendmmsg socket system call" is capable of sending to multiple different destination addresses. SMACK is using destination's address for checking sendmsg() permission. However, security_socket_sendmsg() is called for only once even if multiple different destination addresses are passed to sendmmsg(). Therefore, we need to call security_socket_sendmsg() for each destination address rather than only the first destination address. Since calling security_socket_sendmsg() every time when only single destination address was passed to sendmmsg() is a waste of time, omit calling security_socket_sendmsg() unless destination address of previous datagram and that of current datagram differs. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Acked-by: Anton Blanchard <anton@samba.org> Cc: stable <stable@kernel.org> [3.0+] Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 98382f4 commit c71d8eb

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed

net/socket.c

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,8 +1871,14 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how)
18711871
#define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen)
18721872
#define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags)
18731873

1874+
struct used_address {
1875+
struct sockaddr_storage name;
1876+
unsigned int name_len;
1877+
};
1878+
18741879
static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
1875-
struct msghdr *msg_sys, unsigned flags, int nosec)
1880+
struct msghdr *msg_sys, unsigned flags,
1881+
struct used_address *used_address)
18761882
{
18771883
struct compat_msghdr __user *msg_compat =
18781884
(struct compat_msghdr __user *)msg;
@@ -1953,8 +1959,28 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
19531959

19541960
if (sock->file->f_flags & O_NONBLOCK)
19551961
msg_sys->msg_flags |= MSG_DONTWAIT;
1956-
err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys,
1957-
total_len);
1962+
/*
1963+
* If this is sendmmsg() and current destination address is same as
1964+
* previously succeeded address, omit asking LSM's decision.
1965+
* used_address->name_len is initialized to UINT_MAX so that the first
1966+
* destination address never matches.
1967+
*/
1968+
if (used_address && used_address->name_len == msg_sys->msg_namelen &&
1969+
!memcmp(&used_address->name, msg->msg_name,
1970+
used_address->name_len)) {
1971+
err = sock_sendmsg_nosec(sock, msg_sys, total_len);
1972+
goto out_freectl;
1973+
}
1974+
err = sock_sendmsg(sock, msg_sys, total_len);
1975+
/*
1976+
* If this is sendmmsg() and sending to current destination address was
1977+
* successful, remember it.
1978+
*/
1979+
if (used_address && err >= 0) {
1980+
used_address->name_len = msg_sys->msg_namelen;
1981+
memcpy(&used_address->name, msg->msg_name,
1982+
used_address->name_len);
1983+
}
19581984

19591985
out_freectl:
19601986
if (ctl_buf != ctl)
@@ -1979,7 +2005,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
19792005
if (!sock)
19802006
goto out;
19812007

1982-
err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0);
2008+
err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
19832009

19842010
fput_light(sock->file, fput_needed);
19852011
out:
@@ -1998,6 +2024,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
19982024
struct mmsghdr __user *entry;
19992025
struct compat_mmsghdr __user *compat_entry;
20002026
struct msghdr msg_sys;
2027+
struct used_address used_address;
20012028

20022029
if (vlen > UIO_MAXIOV)
20032030
vlen = UIO_MAXIOV;
@@ -2008,24 +2035,22 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
20082035
if (!sock)
20092036
return err;
20102037

2038+
used_address.name_len = UINT_MAX;
20112039
entry = mmsg;
20122040
compat_entry = (struct compat_mmsghdr __user *)mmsg;
20132041
err = 0;
20142042

20152043
while (datagrams < vlen) {
2016-
/*
2017-
* No need to ask LSM for more than the first datagram.
2018-
*/
20192044
if (MSG_CMSG_COMPAT & flags) {
20202045
err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
2021-
&msg_sys, flags, datagrams);
2046+
&msg_sys, flags, &used_address);
20222047
if (err < 0)
20232048
break;
20242049
err = __put_user(err, &compat_entry->msg_len);
20252050
++compat_entry;
20262051
} else {
20272052
err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
2028-
&msg_sys, flags, datagrams);
2053+
&msg_sys, flags, &used_address);
20292054
if (err < 0)
20302055
break;
20312056
err = put_user(err, &entry->msg_len);

0 commit comments

Comments
 (0)