Update to 2.6.32.41 Mainline
/net/unix/af_unix.c
blob:065dc6677e90e606205112d0aa846b549c4e2284 -> blob:db8d51a974b4fff10ab964aee0692ed1f291c418
--- net/unix/af_unix.c
+++ net/unix/af_unix.c
@@ -503,6 +503,8 @@ static int unix_dgram_connect(struct soc
int, int);
static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
struct msghdr *, size_t);
+static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
+ struct msghdr *, size_t, int);
static const struct proto_ops unix_stream_ops = {
.family = PF_UNIX,
@@ -562,7 +564,7 @@ static const struct proto_ops unix_seqpa
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.sendmsg = unix_seqpacket_sendmsg,
- .recvmsg = unix_dgram_recvmsg,
+ .recvmsg = unix_seqpacket_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
@@ -1323,9 +1325,25 @@ static void unix_destruct_fds(struct sk_
sock_wfree(skb);
}
+#define MAX_RECURSION_LEVEL 4
+
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
{
int i;
+ unsigned char max_level = 0;
+ int unix_sock_count = 0;
+
+ for (i = scm->fp->count - 1; i >= 0; i--) {
+ struct sock *sk = unix_get_socket(scm->fp->fp[i]);
+
+ if (sk) {
+ unix_sock_count++;
+ max_level = max(max_level,
+ unix_sk(sk)->recursion_level);
+ }
+ }
+ if (unlikely(max_level > MAX_RECURSION_LEVEL))
+ return -ETOOMANYREFS;
/*
* Need to duplicate file references for the sake of garbage
@@ -1336,10 +1354,12 @@ static int unix_attach_fds(struct scm_co
if (!UNIXCB(skb).fp)
return -ENOMEM;
- for (i = scm->fp->count-1; i >= 0; i--)
- unix_inflight(scm->fp->fp[i]);
+ if (unix_sock_count) {
+ for (i = scm->fp->count - 1; i >= 0; i--)
+ unix_inflight(scm->fp->fp[i]);
+ }
skb->destructor = unix_destruct_fds;
- return 0;
+ return max_level;
}
/*
@@ -1361,6 +1381,7 @@ static int unix_dgram_sendmsg(struct kio
struct sk_buff *skb;
long timeo;
struct scm_cookie tmp_scm;
+ int max_level = 0;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1401,8 +1422,9 @@ static int unix_dgram_sendmsg(struct kio
memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
if (siocb->scm->fp) {
err = unix_attach_fds(siocb->scm, skb);
- if (err)
+ if (err < 0)
goto out_free;
+ max_level = err + 1;
}
unix_get_secdata(siocb->scm, skb);
@@ -1483,6 +1505,8 @@ restart:
}
skb_queue_tail(&other->sk_receive_queue, skb);
+ if (max_level > unix_sk(other)->recursion_level)
+ unix_sk(other)->recursion_level = max_level;
unix_state_unlock(other);
other->sk_data_ready(other, len);
sock_put(other);
@@ -1513,6 +1537,7 @@ static int unix_stream_sendmsg(struct ki
int sent = 0;
struct scm_cookie tmp_scm;
bool fds_sent = false;
+ int max_level = 0;
if (NULL == siocb->scm)
siocb->scm = &tmp_scm;
@@ -1577,10 +1602,11 @@ static int unix_stream_sendmsg(struct ki
/* Only send the fds in the first buffer */
if (siocb->scm->fp && !fds_sent) {
err = unix_attach_fds(siocb->scm, skb);
- if (err) {
+ if (err < 0) {
kfree_skb(skb);
goto out_err;
}
+ max_level = err + 1;
fds_sent = true;
}
@@ -1597,6 +1623,8 @@ static int unix_stream_sendmsg(struct ki
goto pipe_err_free;
skb_queue_tail(&other->sk_receive_queue, skb);
+ if (max_level > unix_sk(other)->recursion_level)
+ unix_sk(other)->recursion_level = max_level;
unix_state_unlock(other);
other->sk_data_ready(other, size);
sent += size;
@@ -1639,6 +1667,18 @@ static int unix_seqpacket_sendmsg(struct
return unix_dgram_sendmsg(kiocb, sock, msg, len);
}
+static int unix_seqpacket_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size,
+ int flags)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk->sk_state != TCP_ESTABLISHED)
+ return -ENOTCONN;
+
+ return unix_dgram_recvmsg(iocb, sock, msg, size, flags);
+}
+
static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
{
struct unix_sock *u = unix_sk(sk);
@@ -1813,6 +1853,7 @@ static int unix_stream_recvmsg(struct ki
unix_state_lock(sk);
skb = skb_dequeue(&sk->sk_receive_queue);
if (skb == NULL) {
+ unix_sk(sk)->recursion_level = 0;
if (copied >= target)
goto unlock;