Commit 974f7bc5 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo

Merge master.kernel.org:/pub/scm/linux/kernel/git/sridhar/lksctp-2.6

parents 89fbb69c 64a0c1c8
...@@ -171,10 +171,10 @@ struct sctp_sndrcvinfo { ...@@ -171,10 +171,10 @@ struct sctp_sndrcvinfo {
*/ */
enum sctp_sinfo_flags { enum sctp_sinfo_flags {
MSG_UNORDERED = 1, /* Send/receive message unordered. */ SCTP_UNORDERED = 1, /* Send/receive message unordered. */
MSG_ADDR_OVER = 2, /* Override the primary destination. */ SCTP_ADDR_OVER = 2, /* Override the primary destination. */
MSG_ABORT=4, /* Send an ABORT message to the peer. */ SCTP_ABORT=4, /* Send an ABORT message to the peer. */
/* MSG_EOF is already defined per socket.h */ SCTP_EOF=MSG_FIN, /* Initiate graceful shutdown process. */
}; };
......
...@@ -554,7 +554,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc, ...@@ -554,7 +554,7 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
dp.ppid = sinfo->sinfo_ppid; dp.ppid = sinfo->sinfo_ppid;
/* Set the flags for an unordered send. */ /* Set the flags for an unordered send. */
if (sinfo->sinfo_flags & MSG_UNORDERED) { if (sinfo->sinfo_flags & SCTP_UNORDERED) {
flags |= SCTP_DATA_UNORDERED; flags |= SCTP_DATA_UNORDERED;
dp.ssn = 0; dp.ssn = 0;
} else } else
......
...@@ -1010,6 +1010,19 @@ static int __sctp_connect(struct sock* sk, ...@@ -1010,6 +1010,19 @@ static int __sctp_connect(struct sock* sk,
err = -EAGAIN; err = -EAGAIN;
goto out_free; goto out_free;
} }
} else {
/*
* If an unprivileged user inherits a 1-many
* style socket with open associations on a
* privileged port, it MAY be permitted to
* accept new associations, but it SHOULD NOT
* be permitted to open new associations.
*/
if (ep->base.bind_addr.port < PROT_SOCK &&
!capable(CAP_NET_BIND_SERVICE)) {
err = -EACCES;
goto out_free;
}
} }
scope = sctp_scope(&to); scope = sctp_scope(&to);
...@@ -1389,27 +1402,27 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1389,27 +1402,27 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
SCTP_DEBUG_PRINTK("msg_len: %zu, sinfo_flags: 0x%x\n", SCTP_DEBUG_PRINTK("msg_len: %zu, sinfo_flags: 0x%x\n",
msg_len, sinfo_flags); msg_len, sinfo_flags);
/* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */ /* SCTP_EOF or SCTP_ABORT cannot be set on a TCP-style socket. */
if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) { if (sctp_style(sk, TCP) && (sinfo_flags & (SCTP_EOF | SCTP_ABORT))) {
err = -EINVAL; err = -EINVAL;
goto out_nounlock; goto out_nounlock;
} }
/* If MSG_EOF is set, no data can be sent. Disallow sending zero /* If SCTP_EOF is set, no data can be sent. Disallow sending zero
* length messages when MSG_EOF|MSG_ABORT is not set. * length messages when SCTP_EOF|SCTP_ABORT is not set.
* If MSG_ABORT is set, the message length could be non zero with * If SCTP_ABORT is set, the message length could be non zero with
* the msg_iov set to the user abort reason. * the msg_iov set to the user abort reason.
*/ */
if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) || if (((sinfo_flags & SCTP_EOF) && (msg_len > 0)) ||
(!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) { (!(sinfo_flags & (SCTP_EOF|SCTP_ABORT)) && (msg_len == 0))) {
err = -EINVAL; err = -EINVAL;
goto out_nounlock; goto out_nounlock;
} }
/* If MSG_ADDR_OVER is set, there must be an address /* If SCTP_ADDR_OVER is set, there must be an address
* specified in msg_name. * specified in msg_name.
*/ */
if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) { if ((sinfo_flags & SCTP_ADDR_OVER) && (!msg->msg_name)) {
err = -EINVAL; err = -EINVAL;
goto out_nounlock; goto out_nounlock;
} }
...@@ -1458,14 +1471,14 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1458,14 +1471,14 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
goto out_unlock; goto out_unlock;
} }
if (sinfo_flags & MSG_EOF) { if (sinfo_flags & SCTP_EOF) {
SCTP_DEBUG_PRINTK("Shutting down association: %p\n", SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
asoc); asoc);
sctp_primitive_SHUTDOWN(asoc, NULL); sctp_primitive_SHUTDOWN(asoc, NULL);
err = 0; err = 0;
goto out_unlock; goto out_unlock;
} }
if (sinfo_flags & MSG_ABORT) { if (sinfo_flags & SCTP_ABORT) {
SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc); SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
sctp_primitive_ABORT(asoc, msg); sctp_primitive_ABORT(asoc, msg);
err = 0; err = 0;
...@@ -1477,7 +1490,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1477,7 +1490,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
if (!asoc) { if (!asoc) {
SCTP_DEBUG_PRINTK("There is no association yet.\n"); SCTP_DEBUG_PRINTK("There is no association yet.\n");
if (sinfo_flags & (MSG_EOF | MSG_ABORT)) { if (sinfo_flags & (SCTP_EOF | SCTP_ABORT)) {
err = -EINVAL; err = -EINVAL;
goto out_unlock; goto out_unlock;
} }
...@@ -1515,6 +1528,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1515,6 +1528,19 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
err = -EAGAIN; err = -EAGAIN;
goto out_unlock; goto out_unlock;
} }
} else {
/*
* If an unprivileged user inherits a one-to-many
* style socket with open associations on a privileged
* port, it MAY be permitted to accept new associations,
* but it SHOULD NOT be permitted to open new
* associations.
*/
if (ep->base.bind_addr.port < PROT_SOCK &&
!capable(CAP_NET_BIND_SERVICE)) {
err = -EACCES;
goto out_unlock;
}
} }
scope = sctp_scope(&to); scope = sctp_scope(&to);
...@@ -1611,10 +1637,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1611,10 +1637,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* If an address is passed with the sendto/sendmsg call, it is used /* If an address is passed with the sendto/sendmsg call, it is used
* to override the primary destination address in the TCP model, or * to override the primary destination address in the TCP model, or
* when MSG_ADDR_OVER flag is set in the UDP model. * when SCTP_ADDR_OVER flag is set in the UDP model.
*/ */
if ((sctp_style(sk, TCP) && msg_name) || if ((sctp_style(sk, TCP) && msg_name) ||
(sinfo_flags & MSG_ADDR_OVER)) { (sinfo_flags & SCTP_ADDR_OVER)) {
chunk_tp = sctp_assoc_lookup_paddr(asoc, &to); chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);
if (!chunk_tp) { if (!chunk_tp) {
err = -EINVAL; err = -EINVAL;
...@@ -2306,16 +2332,14 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl ...@@ -2306,16 +2332,14 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl
return -EINVAL; return -EINVAL;
if (get_user(val, (int __user *)optval)) if (get_user(val, (int __user *)optval))
return -EFAULT; return -EFAULT;
if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)) if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN)))
return -EINVAL; return -EINVAL;
sp->user_frag = val; sp->user_frag = val;
if (val) { /* Update the frag_point of the existing associations. */
/* Update the frag_point of the existing associations. */ list_for_each(pos, &(sp->ep->asocs)) {
list_for_each(pos, &(sp->ep->asocs)) { asoc = list_entry(pos, struct sctp_association, asocs);
asoc = list_entry(pos, struct sctp_association, asocs); asoc->frag_point = sctp_frag_point(sp, asoc->pmtu);
asoc->frag_point = sctp_frag_point(sp, asoc->pmtu);
}
} }
return 0; return 0;
...@@ -2384,14 +2408,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva ...@@ -2384,14 +2408,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval, static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval,
int optlen) int optlen)
{ {
__u32 val; struct sctp_setadaption adaption;
if (optlen < sizeof(__u32)) if (optlen != sizeof(struct sctp_setadaption))
return -EINVAL; return -EINVAL;
if (copy_from_user(&val, optval, sizeof(__u32))) if (copy_from_user(&adaption, optval, optlen))
return -EFAULT; return -EFAULT;
sctp_sk(sk)->adaption_ind = val; sctp_sk(sk)->adaption_ind = adaption.ssb_adaption_ind;
return 0; return 0;
} }
...@@ -3672,17 +3696,15 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, ...@@ -3672,17 +3696,15 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
static int sctp_getsockopt_adaption_layer(struct sock *sk, int len, static int sctp_getsockopt_adaption_layer(struct sock *sk, int len,
char __user *optval, int __user *optlen) char __user *optval, int __user *optlen)
{ {
__u32 val; struct sctp_setadaption adaption;
if (len < sizeof(__u32)) if (len != sizeof(struct sctp_setadaption))
return -EINVAL; return -EINVAL;
len = sizeof(__u32); adaption.ssb_adaption_ind = sctp_sk(sk)->adaption_ind;
val = sctp_sk(sk)->adaption_ind; if (copy_to_user(optval, &adaption, len))
if (put_user(len, optlen))
return -EFAULT;
if (copy_to_user(optval, &val, len))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
...@@ -4640,8 +4662,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -4640,8 +4662,8 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
/* Minimally, validate the sinfo_flags. */ /* Minimally, validate the sinfo_flags. */
if (cmsgs->info->sinfo_flags & if (cmsgs->info->sinfo_flags &
~(MSG_UNORDERED | MSG_ADDR_OVER | ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
MSG_ABORT | MSG_EOF)) SCTP_ABORT | SCTP_EOF))
return -EINVAL; return -EINVAL;
break; break;
......
...@@ -698,7 +698,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, ...@@ -698,7 +698,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
event->ssn = ntohs(chunk->subh.data_hdr->ssn); event->ssn = ntohs(chunk->subh.data_hdr->ssn);
event->ppid = chunk->subh.data_hdr->ppid; event->ppid = chunk->subh.data_hdr->ppid;
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) { if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) {
event->flags |= MSG_UNORDERED; event->flags |= SCTP_UNORDERED;
event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); event->cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
} }
event->tsn = ntohl(chunk->subh.data_hdr->tsn); event->tsn = ntohl(chunk->subh.data_hdr->tsn);
...@@ -824,7 +824,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, ...@@ -824,7 +824,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
* *
* recvmsg() flags: * recvmsg() flags:
* *
* MSG_UNORDERED - This flag is present when the message was sent * SCTP_UNORDERED - This flag is present when the message was sent
* non-ordered. * non-ordered.
*/ */
sinfo.sinfo_flags = event->flags; sinfo.sinfo_flags = event->flags;
...@@ -839,7 +839,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, ...@@ -839,7 +839,7 @@ void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
* This field will hold the current cumulative TSN as * This field will hold the current cumulative TSN as
* known by the underlying SCTP layer. Note this field is * known by the underlying SCTP layer. Note this field is
* ignored when sending and only valid for a receive * ignored when sending and only valid for a receive
* operation when sinfo_flags are set to MSG_UNORDERED. * operation when sinfo_flags are set to SCTP_UNORDERED.
*/ */
sinfo.sinfo_cumtsn = event->cumtsn; sinfo.sinfo_cumtsn = event->cumtsn;
/* sinfo_assoc_id: sizeof (sctp_assoc_t) /* sinfo_assoc_id: sizeof (sctp_assoc_t)
......
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