aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2020-07-19 18:26:44 -0700
committerDavid S. Miller <davem@davemloft.net>2020-07-19 18:26:44 -0700
commitbed1ce78761925785cfccbd73aea2d889f625b68 (patch)
tree5777c2bb4290c44013dabc658d1e43e890a80f5a
parent9aa0dfe1fc9920ad2224b53f9be748c030f0a12e (diff)
parent6c8983a606622b61a429830091fdfe643328b96a (diff)
Merge branch 'do-a-single-memdup_user-in-sctp_setsockopt-v2'
Christoph Hellwig says: ==================== do a single memdup_user in sctp_setsockopt v2 here is a resend of my series to lift the copy_from_user out of the individual sctp sockopt handlers into the main sctp_setsockopt routine. Changes since v1: - fixes a few sizeof calls. - use memzero_explicit in sctp_setsockopt_auth_key instead of special casing it for a kzfree in the caller - remove some minor cleanups from sctp_setsockopt_autoclose to keep it closer to the existing version - add another little only vaguely related cleanup patch ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sctp/socket.c1199
1 files changed, 477 insertions, 722 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index d57e1a002ffc..9a767f359718 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -979,9 +979,8 @@ int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)
*
* Returns 0 if ok, <0 errno code on error.
*/
-static int sctp_setsockopt_bindx_kernel(struct sock *sk,
- struct sockaddr *addrs, int addrs_size,
- int op)
+static int sctp_setsockopt_bindx(struct sock *sk, struct sockaddr *addrs,
+ int addrs_size, int op)
{
int err;
int addrcnt = 0;
@@ -991,7 +990,7 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk,
struct sctp_af *af;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d opt:%d\n",
- __func__, sk, addrs, addrs_size, op);
+ __func__, sk, addr_buf, addrs_size, op);
if (unlikely(addrs_size <= 0))
return -EINVAL;
@@ -1037,29 +1036,13 @@ static int sctp_setsockopt_bindx_kernel(struct sock *sk,
}
}
-static int sctp_setsockopt_bindx(struct sock *sk,
- struct sockaddr __user *addrs,
- int addrs_size, int op)
-{
- struct sockaddr *kaddrs;
- int err;
-
- kaddrs = memdup_user(addrs, addrs_size);
- if (IS_ERR(kaddrs))
- return PTR_ERR(kaddrs);
- err = sctp_setsockopt_bindx_kernel(sk, kaddrs, addrs_size, op);
- kfree(kaddrs);
- return err;
-}
-
static int sctp_bind_add(struct sock *sk, struct sockaddr *addrs,
int addrlen)
{
int err;
lock_sock(sk);
- err = sctp_setsockopt_bindx_kernel(sk, addrs, addrlen,
- SCTP_BINDX_ADD_ADDR);
+ err = sctp_setsockopt_bindx(sk, addrs, addrlen, SCTP_BINDX_ADD_ADDR);
release_sock(sk);
return err;
}
@@ -1303,36 +1286,29 @@ out_free:
* it.
*
* sk The sk of the socket
- * addrs The pointer to the addresses in user land
+ * addrs The pointer to the addresses
* addrssize Size of the addrs buffer
*
* Returns >=0 if ok, <0 errno code on error.
*/
-static int __sctp_setsockopt_connectx(struct sock *sk,
- struct sockaddr __user *addrs,
- int addrs_size,
- sctp_assoc_t *assoc_id)
+static int __sctp_setsockopt_connectx(struct sock *sk, struct sockaddr *kaddrs,
+ int addrs_size, sctp_assoc_t *assoc_id)
{
- struct sockaddr *kaddrs;
int err = 0, flags = 0;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
- __func__, sk, addrs, addrs_size);
+ __func__, sk, kaddrs, addrs_size);
/* make sure the 1st addr's sa_family is accessible later */
if (unlikely(addrs_size < sizeof(sa_family_t)))
return -EINVAL;
- kaddrs = memdup_user(addrs, addrs_size);
- if (IS_ERR(kaddrs))
- return PTR_ERR(kaddrs);
-
/* Allow security module to validate connectx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
(struct sockaddr *)kaddrs,
addrs_size);
if (err)
- goto out_free;
+ return err;
/* in-kernel sockets don't generally have a file allocated to them
* if all they do is call sock_create_kern().
@@ -1340,12 +1316,7 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
if (sk->sk_socket->file)
flags = sk->sk_socket->file->f_flags;
- err = __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
-
-out_free:
- kfree(kaddrs);
-
- return err;
+ return __sctp_connect(sk, kaddrs, addrs_size, flags, assoc_id);
}
/*
@@ -1353,10 +1324,10 @@ out_free:
* to the option that doesn't provide association id.
*/
static int sctp_setsockopt_connectx_old(struct sock *sk,
- struct sockaddr __user *addrs,
+ struct sockaddr *kaddrs,
int addrs_size)
{
- return __sctp_setsockopt_connectx(sk, addrs, addrs_size, NULL);
+ return __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, NULL);
}
/*
@@ -1366,13 +1337,13 @@ static int sctp_setsockopt_connectx_old(struct sock *sk,
* always positive.
*/
static int sctp_setsockopt_connectx(struct sock *sk,
- struct sockaddr __user *addrs,
+ struct sockaddr *kaddrs,
int addrs_size)
{
sctp_assoc_t assoc_id = 0;
int err = 0;
- err = __sctp_setsockopt_connectx(sk, addrs, addrs_size, &assoc_id);
+ err = __sctp_setsockopt_connectx(sk, kaddrs, addrs_size, &assoc_id);
if (err)
return err;
@@ -1402,6 +1373,7 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
{
struct sctp_getaddrs_old param;
sctp_assoc_t assoc_id = 0;
+ struct sockaddr *kaddrs;
int err = 0;
#ifdef CONFIG_COMPAT
@@ -1425,9 +1397,12 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
return -EFAULT;
}
- err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *)
- param.addrs, param.addr_num,
- &assoc_id);
+ kaddrs = memdup_user(param.addrs, param.addr_num);
+ if (IS_ERR(kaddrs))
+ return PTR_ERR(kaddrs);
+
+ err = __sctp_setsockopt_connectx(sk, kaddrs, param.addr_num, &assoc_id);
+ kfree(kaddrs);
if (err == 0 || err == -EINPROGRESS) {
if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
return -EFAULT;
@@ -2209,28 +2184,18 @@ out:
* exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user.
*/
-static int sctp_setsockopt_disable_fragments(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_disable_fragments(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen < sizeof(int))
return -EINVAL;
-
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
-
- sctp_sk(sk)->disable_fragments = (val == 0) ? 0 : 1;
-
+ sctp_sk(sk)->disable_fragments = (*val == 0) ? 0 : 1;
return 0;
}
-static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_events(struct sock *sk, __u8 *sn_type,
unsigned int optlen)
{
- struct sctp_event_subscribe subscribe;
- __u8 *sn_type = (__u8 *)&subscribe;
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
int i;
@@ -2238,9 +2203,6 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
if (optlen > sizeof(struct sctp_event_subscribe))
return -EINVAL;
- if (copy_from_user(&subscribe, optval, optlen))
- return -EFAULT;
-
for (i = 0; i < optlen; i++)
sctp_ulpevent_type_set(&sp->subscribe, SCTP_SN_TYPE_BASE + i,
sn_type[i]);
@@ -2280,7 +2242,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval,
* integer defining the number of seconds of idle time before an
* association is closed.
*/
-static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_autoclose(struct sock *sk, u32 *optval,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
@@ -2291,9 +2253,8 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval,
return -EOPNOTSUPP;
if (optlen != sizeof(int))
return -EINVAL;
- if (copy_from_user(&sp->autoclose, optval, optlen))
- return -EFAULT;
+ sp->autoclose = *optval;
if (sp->autoclose > net->sctp.max_autoclose)
sp->autoclose = net->sctp.max_autoclose;
@@ -2628,48 +2589,42 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
}
static int sctp_setsockopt_peer_addr_params(struct sock *sk,
- char __user *optval,
+ struct sctp_paddrparams *params,
unsigned int optlen)
{
- struct sctp_paddrparams params;
struct sctp_transport *trans = NULL;
struct sctp_association *asoc = NULL;
struct sctp_sock *sp = sctp_sk(sk);
int error;
int hb_change, pmtud_change, sackdelay_change;
- if (optlen == sizeof(params)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- } else if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
+ if (optlen == ALIGN(offsetof(struct sctp_paddrparams,
spp_ipv6_flowlabel), 4)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- if (params.spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
+ if (params->spp_flags & (SPP_DSCP | SPP_IPV6_FLOWLABEL))
return -EINVAL;
- } else {
+ } else if (optlen != sizeof(*params)) {
return -EINVAL;
}
/* Validate flags and value parameters. */
- hb_change = params.spp_flags & SPP_HB;
- pmtud_change = params.spp_flags & SPP_PMTUD;
- sackdelay_change = params.spp_flags & SPP_SACKDELAY;
+ hb_change = params->spp_flags & SPP_HB;
+ pmtud_change = params->spp_flags & SPP_PMTUD;
+ sackdelay_change = params->spp_flags & SPP_SACKDELAY;
if (hb_change == SPP_HB ||
pmtud_change == SPP_PMTUD ||
sackdelay_change == SPP_SACKDELAY ||
- params.spp_sackdelay > 500 ||
- (params.spp_pathmtu &&
- params.spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
+ params->spp_sackdelay > 500 ||
+ (params->spp_pathmtu &&
+ params->spp_pathmtu < SCTP_DEFAULT_MINSEGMENT))
return -EINVAL;
/* If an address other than INADDR_ANY is specified, and
* no transport is found, then the request is invalid.
*/
- if (!sctp_is_any(sk, (union sctp_addr *)&params.spp_address)) {
- trans = sctp_addr_id2transport(sk, &params.spp_address,
- params.spp_assoc_id);
+ if (!sctp_is_any(sk, (union sctp_addr *)&params->spp_address)) {
+ trans = sctp_addr_id2transport(sk, &params->spp_address,
+ params->spp_assoc_id);
if (!trans)
return -EINVAL;
}
@@ -2678,19 +2633,19 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
* socket is a one to many style socket, and an association
* was not found, then the id was invalid.
*/
- asoc = sctp_id2assoc(sk, params.spp_assoc_id);
- if (!asoc && params.spp_assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->spp_assoc_id);
+ if (!asoc && params->spp_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
/* Heartbeat demand can only be sent on a transport or
* association, but not a socket.
*/
- if (params.spp_flags & SPP_HB_DEMAND && !trans && !asoc)
+ if (params->spp_flags & SPP_HB_DEMAND && !trans && !asoc)
return -EINVAL;
/* Process parameters. */
- error = sctp_apply_peer_addr_params(&params, trans, asoc, sp,
+ error = sctp_apply_peer_addr_params(params, trans, asoc, sp,
hb_change, pmtud_change,
sackdelay_change);
@@ -2703,7 +2658,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
if (!trans && asoc) {
list_for_each_entry(trans, &asoc->peer.transport_addr_list,
transports) {
- sctp_apply_peer_addr_params(&params, trans, asoc, sp,
+ sctp_apply_peer_addr_params(params, trans, asoc, sp,
hb_change, pmtud_change,
sackdelay_change);
}
@@ -2796,17 +2751,14 @@ static void sctp_apply_asoc_delayed_ack(struct sctp_sack_info *params,
*/
static int sctp_setsockopt_delayed_ack(struct sock *sk,
- char __user *optval, unsigned int optlen)
+ struct sctp_sack_info *params,
+ unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_sack_info params;
if (optlen == sizeof(struct sctp_sack_info)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
-
- if (params.sack_delay == 0 && params.sack_freq == 0)
+ if (params->sack_delay == 0 && params->sack_freq == 0)
return 0;
} else if (optlen == sizeof(struct sctp_assoc_value)) {
pr_warn_ratelimited(DEPRECATED
@@ -2814,59 +2766,57 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
"Use of struct sctp_assoc_value in delayed_ack socket option.\n"
"Use struct sctp_sack_info instead\n",
current->comm, task_pid_nr(current));
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- if (params.sack_delay == 0)
- params.sack_freq = 1;
+ if (params->sack_delay == 0)
+ params->sack_freq = 1;
else
- params.sack_freq = 0;
+ params->sack_freq = 0;
} else
return -EINVAL;
/* Validate value parameter. */
- if (params.sack_delay > 500)
+ if (params->sack_delay > 500)
return -EINVAL;
/* Get association, if sack_assoc_id != SCTP_FUTURE_ASSOC and the
* socket is a one to many style socket, and an association
* was not found, then the id was invalid.
*/
- asoc = sctp_id2assoc(sk, params.sack_assoc_id);
- if (!asoc && params.sack_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->sack_assoc_id);
+ if (!asoc && params->sack_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- sctp_apply_asoc_delayed_ack(&params, asoc);
+ sctp_apply_asoc_delayed_ack(params, asoc);
return 0;
}
if (sctp_style(sk, TCP))
- params.sack_assoc_id = SCTP_FUTURE_ASSOC;
+ params->sack_assoc_id = SCTP_FUTURE_ASSOC;
- if (params.sack_assoc_id == SCTP_FUTURE_ASSOC ||
- params.sack_assoc_id == SCTP_ALL_ASSOC) {
- if (params.sack_delay) {
- sp->sackdelay = params.sack_delay;
+ if (params->sack_assoc_id == SCTP_FUTURE_ASSOC ||
+ params->sack_assoc_id == SCTP_ALL_ASSOC) {
+ if (params->sack_delay) {
+ sp->sackdelay = params->sack_delay;
sp->param_flags =
sctp_spp_sackdelay_enable(sp->param_flags);
}
- if (params.sack_freq == 1) {
+ if (params->sack_freq == 1) {
sp->param_flags =
sctp_spp_sackdelay_disable(sp->param_flags);
- } else if (params.sack_freq > 1) {
- sp->sackfreq = params.sack_freq;
+ } else if (params->sack_freq > 1) {
+ sp->sackfreq = params->sack_freq;
sp->param_flags =
sctp_spp_sackdelay_enable(sp->param_flags);
}
}
- if (params.sack_assoc_id == SCTP_CURRENT_ASSOC ||
- params.sack_assoc_id == SCTP_ALL_ASSOC)
+ if (params->sack_assoc_id == SCTP_CURRENT_ASSOC ||
+ params->sack_assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs)
- sctp_apply_asoc_delayed_ack(&params, asoc);
+ sctp_apply_asoc_delayed_ack(params, asoc);
return 0;
}
@@ -2882,24 +2832,22 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk,
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
-static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_initmsg(struct sock *sk, struct sctp_initmsg *sinit,
+ unsigned int optlen)
{
- struct sctp_initmsg sinit;
struct sctp_sock *sp = sctp_sk(sk);
if (optlen != sizeof(struct sctp_initmsg))
return -EINVAL;
- if (copy_from_user(&sinit, optval, optlen))
- return -EFAULT;
- if (sinit.sinit_num_ostreams)
- sp->initmsg.sinit_num_ostreams = sinit.sinit_num_ostreams;
- if (sinit.sinit_max_instreams)
- sp->initmsg.sinit_max_instreams = sinit.sinit_max_instreams;
- if (sinit.sinit_max_attempts)
- sp->initmsg.sinit_max_attempts = sinit.sinit_max_attempts;
- if (sinit.sinit_max_init_timeo)
- sp->initmsg.sinit_max_init_timeo = sinit.sinit_max_init_timeo;
+ if (sinit->sinit_num_ostreams)
+ sp->initmsg.sinit_num_ostreams = sinit->sinit_num_ostreams;
+ if (sinit->sinit_max_instreams)
+ sp->initmsg.sinit_max_instreams = sinit->sinit_max_instreams;
+ if (sinit->sinit_max_attempts)
+ sp->initmsg.sinit_max_attempts = sinit->sinit_max_attempts;
+ if (sinit->sinit_max_init_timeo)
+ sp->initmsg.sinit_max_init_timeo = sinit->sinit_max_init_timeo;
return 0;
}
@@ -2919,57 +2867,54 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigne
* to this call if the caller is using the UDP model.
*/
static int sctp_setsockopt_default_send_param(struct sock *sk,
- char __user *optval,
+ struct sctp_sndrcvinfo *info,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_sndrcvinfo info;
- if (optlen != sizeof(info))
+ if (optlen != sizeof(*info))
return -EINVAL;
- if (copy_from_user(&info, optval, optlen))
- return -EFAULT;
- if (info.sinfo_flags &
+ if (info->sinfo_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
- asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
- if (!asoc && info.sinfo_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, info->sinfo_assoc_id);
+ if (!asoc && info->sinfo_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->default_stream = info.sinfo_stream;
- asoc->default_flags = info.sinfo_flags;
- asoc->default_ppid = info.sinfo_ppid;
- asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_stream = info->sinfo_stream;
+ asoc->default_flags = info->sinfo_flags;
+ asoc->default_ppid = info->sinfo_ppid;
+ asoc->default_context = info->sinfo_context;
+ asoc->default_timetolive = info->sinfo_timetolive;
return 0;
}
if (sctp_style(sk, TCP))
- info.sinfo_assoc_id = SCTP_FUTURE_ASSOC;
+ info->sinfo_assoc_id = SCTP_FUTURE_ASSOC;
- if (info.sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
- info.sinfo_assoc_id == SCTP_ALL_ASSOC) {
- sp->default_stream = info.sinfo_stream;
- sp->default_flags = info.sinfo_flags;
- sp->default_ppid = info.sinfo_ppid;
- sp->default_context = info.sinfo_context;
- sp->default_timetolive = info.sinfo_timetolive;
+ if (info->sinfo_assoc_id == SCTP_FUTURE_ASSOC ||
+ info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
+ sp->default_stream = info->sinfo_stream;
+ sp->default_flags = info->sinfo_flags;
+ sp->default_ppid = info->sinfo_ppid;
+ sp->default_context = info->sinfo_context;
+ sp->default_timetolive = info->sinfo_timetolive;
}
- if (info.sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
- info.sinfo_assoc_id == SCTP_ALL_ASSOC) {
+ if (info->sinfo_assoc_id == SCTP_CURRENT_ASSOC ||
+ info->sinfo_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
- asoc->default_stream = info.sinfo_stream;
- asoc->default_flags = info.sinfo_flags;
- asoc->default_ppid = info.sinfo_ppid;
- asoc->default_context = info.sinfo_context;
- asoc->default_timetolive = info.sinfo_timetolive;
+ asoc->default_stream = info->sinfo_stream;
+ asoc->default_flags = info->sinfo_flags;
+ asoc->default_ppid = info->sinfo_ppid;
+ asoc->default_context = info->sinfo_context;
+ asoc->default_timetolive = info->sinfo_timetolive;
}
}
@@ -2980,54 +2925,51 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
* (SCTP_DEFAULT_SNDINFO)
*/
static int sctp_setsockopt_default_sndinfo(struct sock *sk,
- char __user *optval,
+ struct sctp_sndinfo *info,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_association *asoc;
- struct sctp_sndinfo info;
- if (optlen != sizeof(info))
+ if (optlen != sizeof(*info))
return -EINVAL;
- if (copy_from_user(&info, optval, optlen))
- return -EFAULT;
- if (info.snd_flags &
+ if (info->snd_flags &
~(SCTP_UNORDERED | SCTP_ADDR_OVER |
SCTP_ABORT | SCTP_EOF))
return -EINVAL;
- asoc = sctp_id2assoc(sk, info.snd_assoc_id);
- if (!asoc && info.snd_assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, info->snd_assoc_id);
+ if (!asoc && info->snd_assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->default_stream = info.snd_sid;
- asoc->default_flags = info.snd_flags;
- asoc->default_ppid = info.snd_ppid;
- asoc->default_context = info.snd_context;
+ asoc->default_stream = info->snd_sid;
+ asoc->default_flags = info->snd_flags;
+ asoc->default_ppid = info->snd_ppid;
+ asoc->default_context = info->snd_context;
return 0;
}
if (sctp_style(sk, TCP))
- info.snd_assoc_id = SCTP_FUTURE_ASSOC;
+ info->snd_assoc_id = SCTP_FUTURE_ASSOC;
- if (info.snd_assoc_id == SCTP_FUTURE_ASSOC ||
- info.snd_assoc_id == SCTP_ALL_ASSOC) {
- sp->default_stream = info.snd_sid;
- sp->default_flags = info.snd_flags;
- sp->default_ppid = info.snd_ppid;
- sp->default_context = info.snd_context;
+ if (info->snd_assoc_id == SCTP_FUTURE_ASSOC ||
+ info->snd_assoc_id == SCTP_ALL_ASSOC) {
+ sp->default_stream = info->snd_sid;
+ sp->default_flags = info->snd_flags;
+ sp->default_ppid = info->snd_ppid;
+ sp->default_context = info->snd_context;
}
- if (info.snd_assoc_id == SCTP_CURRENT_ASSOC ||
- info.snd_assoc_id == SCTP_ALL_ASSOC) {
+ if (info->snd_assoc_id == SCTP_CURRENT_ASSOC ||
+ info->snd_assoc_id == SCTP_ALL_ASSOC) {
list_for_each_entry(asoc, &sp->ep->asocs, asocs) {
- asoc->default_stream = info.snd_sid;
- asoc->default_flags = info.snd_flags;
- asoc->default_ppid = info.snd_ppid;
- asoc->default_context = info.snd_context;
+ asoc->default_stream = info->snd_sid;
+ asoc->default_flags = info->snd_flags;
+ asoc->default_ppid = info->snd_ppid;
+ asoc->default_context = info->snd_context;
}
}
@@ -3040,10 +2982,9 @@ static int sctp_setsockopt_default_sndinfo(struct sock *sk,
* the association primary. The enclosed address must be one of the
* association peer's addresses.
*/
-static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_primary_addr(struct sock *sk, struct sctp_prim *prim,
unsigned int optlen)
{
- struct sctp_prim prim;
struct sctp_transport *trans;
struct sctp_af *af;
int err;
@@ -3051,21 +2992,18 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
if (optlen != sizeof(struct sctp_prim))
return -EINVAL;
- if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
- return -EFAULT;
-
/* Allow security module to validate address but need address len. */
- af = sctp_get_af_specific(prim.ssp_addr.ss_family);
+ af = sctp_get_af_specific(prim->ssp_addr.ss_family);
if (!af)
return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
- (struct sockaddr *)&prim.ssp_addr,
+ (struct sockaddr *)&prim->ssp_addr,
af->sockaddr_len);
if (err)
return err;
- trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id);
+ trans = sctp_addr_id2transport(sk, &prim->ssp_addr, prim->ssp_assoc_id);
if (!trans)
return -EINVAL;
@@ -3082,17 +3020,12 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
* introduced, at the cost of more packets in the network. Expects an
* integer boolean flag.
*/
-static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_nodelay(struct sock *sk, int *val,
unsigned int optlen)
{
- int val;
-
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
-
- sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
+ sctp_sk(sk)->nodelay = (*val == 0) ? 0 : 1;
return 0;
}
@@ -3108,9 +3041,10 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval,
* be changed.
*
*/
-static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_rtoinfo(struct sock *sk,
+ struct sctp_rtoinfo *rtoinfo,
+ unsigned int optlen)
{
- struct sctp_rtoinfo rtoinfo;
struct sctp_association *asoc;
unsigned long rto_min, rto_max;
struct sctp_sock *sp = sctp_sk(sk);
@@ -3118,18 +3052,15 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
if (optlen != sizeof (struct sctp_rtoinfo))
return -EINVAL;
- if (copy_from_user(&rtoinfo, optval, optlen))
- return -EFAULT;
-
- asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
+ asoc = sctp_id2assoc(sk, rtoinfo->srto_assoc_id);
/* Set the values to the specific association */
- if (!asoc && rtoinfo.srto_assoc_id != SCTP_FUTURE_ASSOC &&
+ if (!asoc && rtoinfo->srto_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
- rto_max = rtoinfo.srto_max;
- rto_min = rtoinfo.srto_min;
+ rto_max = rtoinfo->srto_max;
+ rto_min = rtoinfo->srto_min;
if (rto_max)
rto_max = asoc ? msecs_to_jiffies(rto_max) : rto_max;
@@ -3145,17 +3076,17 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
return -EINVAL;
if (asoc) {
- if (rtoinfo.srto_initial != 0)
+ if (rtoinfo->srto_initial != 0)
asoc->rto_initial =
- msecs_to_jiffies(rtoinfo.srto_initial);
+ msecs_to_jiffies(rtoinfo->srto_initial);
asoc->rto_max = rto_max;
asoc->rto_min = rto_min;
} else {
/* If there is no association or the association-id = 0
* set the values to the endpoint.
*/
- if (rtoinfo.srto_initial != 0)
- sp->rtoinfo.srto_initial = rtoinfo.srto_initial;
+ if (rtoinfo->srto_initial != 0)
+ sp->rtoinfo.srto_initial = rtoinfo->srto_initial;
sp->rtoinfo.srto_max = rto_max;
sp->rtoinfo.srto_min = rto_min;
}
@@ -3174,26 +3105,25 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne
* See [SCTP] for more information.
*
*/
-static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_associnfo(struct sock *sk,
+ struct sctp_assocparams *assocparams,
+ unsigned int optlen)
{
- struct sctp_assocparams assocparams;
struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assocparams))
return -EINVAL;
- if (copy_from_user(&assocparams, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
+ asoc = sctp_id2assoc(sk, assocparams->sasoc_assoc_id);
- if (!asoc && assocparams.sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
+ if (!asoc && assocparams->sasoc_assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
/* Set the values to the specific association */
if (asoc) {
- if (assocparams.sasoc_asocmaxrxt != 0) {
+ if (assocparams->sasoc_asocmaxrxt != 0) {
__u32 path_sum = 0;
int paths = 0;
struct sctp_transport *peer_addr;
@@ -3210,24 +3140,25 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig
* then one path.
*/
if (paths > 1 &&
- assocparams.sasoc_asocmaxrxt > path_sum)
+ assocparams->sasoc_asocmaxrxt > path_sum)
return -EINVAL;
- asoc->max_retrans = assocparams.sasoc_asocmaxrxt;
+ asoc->max_retrans = assocparams->sasoc_asocmaxrxt;
}
- if (assocparams.sasoc_cookie_life != 0)
- asoc->cookie_life = ms_to_ktime(assocparams.sasoc_cookie_life);
+ if (assocparams->sasoc_cookie_life != 0)
+ asoc->cookie_life =
+ ms_to_ktime(assocparams->sasoc_cookie_life);
} else {
/* Set the values to the endpoint */
struct sctp_sock *sp = sctp_sk(sk);
- if (assocparams.sasoc_asocmaxrxt != 0)
+ if (assocparams->sasoc_asocmaxrxt != 0)
sp->assocparams.sasoc_asocmaxrxt =
- assocparams.sasoc_asocmaxrxt;
- if (assocparams.sasoc_cookie_life != 0)
+ assocparams->sasoc_asocmaxrxt;
+ if (assocparams->sasoc_cookie_life != 0)
sp->assocparams.sasoc_cookie_life =
- assocparams.sasoc_cookie_life;
+ assocparams->sasoc_cookie_life;
}
return 0;
}
@@ -3242,16 +3173,14 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsig
* addresses and a user will receive both PF_INET6 and PF_INET type
* addresses on the socket.
*/
-static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_mappedv4(struct sock *sk, int *val,
+ unsigned int optlen)
{
- int val;
struct sctp_sock *sp = sctp_sk(sk);
if (optlen < sizeof(int))
return -EINVAL;
- if (get_user(val, (int __user *)optval))
- return -EFAULT;
- if (val)
+ if (*val)
sp->v4mapped = 1;
else
sp->v4mapped = 0;
@@ -3286,11 +3215,13 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
* changed (effecting future associations only).
* assoc_value: This parameter specifies the maximum size in bytes.
*/
-static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
+static int sctp_setsockopt_maxseg(struct sock *sk,
+ struct sctp_assoc_value *params,
+ unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_assoc_value params;
struct sctp_association *asoc;
+ sctp_assoc_t assoc_id;
int val;
if (optlen == sizeof(int)) {
@@ -3299,19 +3230,17 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
"Use of int in maxseg socket option.\n"
"Use struct sctp_assoc_value instead\n",
current->comm, task_pid_nr(current));
- if (copy_from_user(&val, optval, optlen))
- return -EFAULT;
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ assoc_id = SCTP_FUTURE_ASSOC;
+ val = *(int *)params;
} else if (optlen == sizeof(struct sctp_assoc_value)) {
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- val = params.assoc_value;
+ assoc_id = params->assoc_id;
+ val = params->assoc_value;
} else {
return -EINVAL;
}
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id != SCTP_FUTURE_ASSOC &&
+ asoc = sctp_id2assoc(sk, assoc_id);
+ if (!asoc && assoc_id != SCTP_FUTURE_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
@@ -3346,12 +3275,12 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
* locally bound addresses. The following structure is used to make a
* set primary request:
*/
-static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_peer_primary_addr(struct sock *sk,
+ struct sctp_setpeerprim *prim,
unsigned int optlen)
{
struct sctp_sock *sp;
struct sctp_association *asoc = NULL;
- struct sctp_setpeerprim prim;
struct sctp_chunk *chunk;
struct sctp_af *af;
int err;
@@ -3364,10 +3293,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (optlen != sizeof(struct sctp_setpeerprim))
return -EINVAL;
- if (copy_from_user(&prim, optval, optlen))
- return -EFAULT;
-
- asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
+ asoc = sctp_id2assoc(sk, prim->sspp_assoc_id);
if (!asoc)
return -EINVAL;
@@ -3380,26 +3306,26 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (!sctp_state(asoc, ESTABLISHED))
return -ENOTCONN;
- af = sctp_get_af_specific(prim.sspp_addr.ss_family);
+ af = sctp_get_af_specific(prim->sspp_addr.ss_family);
if (!af)
return -EINVAL;
- if (!af->addr_valid((union sctp_addr *)&prim.sspp_addr, sp, NULL))
+ if (!af->addr_valid((union sctp_addr *)&prim->sspp_addr, sp, NULL))
return -EADDRNOTAVAIL;
- if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
+ if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim->sspp_addr))
return -EADDRNOTAVAIL;
/* Allow security module to validate address. */
err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
- (struct sockaddr *)&prim.sspp_addr,
+ (struct sockaddr *)&prim->sspp_addr,
af->sockaddr_len);
if (err)
return err;
/* Create an ASCONF chunk with SET_PRIMARY parameter */
chunk = sctp_make_asconf_set_prim(asoc,
- (union sctp_addr *)&prim.sspp_addr);
+ (union sctp_addr *)&prim->sspp_addr);
if (!chunk)
return -ENOMEM;
@@ -3410,17 +3336,14 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
return err;
}
-static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_adaptation_layer(struct sock *sk,
+ struct sctp_setadaptation *adapt,
unsigned int optlen)
{
- struct sctp_setadaptation adaptation;
-
if (optlen != sizeof(struct sctp_setadaptation))
return -EINVAL;
- if (copy_from_user(&adaptation, optval, optlen))
- return -EFAULT;
- sctp_sk(sk)->adaptation_ind = adaptation.ssb_adaptation_ind;
+ sctp_sk(sk)->adaptation_ind = adapt->ssb_adaptation_ind;
return 0;
}
@@ -3439,40 +3362,38 @@ static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval
* received messages from the peer and does not effect the value that is
* saved with outbound messages.
*/
-static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
+static int sctp_setsockopt_context(struct sock *sk,
+ struct sctp_assoc_value *params,
unsigned int optlen)
{
struct sctp_sock *sp = sctp_sk(sk);
- struct sctp_assoc_value params;
struct sctp_association *asoc;
if (optlen != sizeof(struct sctp_assoc_value))
return -EINVAL;
- if (copy_from_user(&params, optval, optlen))
- return -EFAULT;
- asoc = sctp_id2assoc(sk, params.assoc_id);
- if (!asoc && params.assoc_id > SCTP_ALL_ASSOC &&
+ asoc = sctp_id2assoc(sk, params->assoc_id);
+ if (!asoc && params->assoc_id > SCTP_ALL_ASSOC &&
sctp_style(sk, UDP))
return -EINVAL;
if (asoc) {
- asoc->default_rcv_context = params.assoc_value;
+ asoc->default_rcv_context = params->assoc_value;
return 0;
}
if (sctp_style(sk, TCP))
- params.assoc_id = SCTP_FUTURE_ASSOC;
+ params->assoc_id = SCTP_FUTURE_ASSOC;
- if (params.assoc_id == SCTP_FUTURE_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
- sp->default_rcv_context = params.assoc_value;
+ if (params->assoc_id == SCTP_FUTURE_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
+ sp->default_rcv_context = params->assoc_value;
- if (params.assoc_id == SCTP_CURRENT_ASSOC ||
- params.assoc_id == SCTP_ALL_ASSOC)
+ if (params->assoc_id == SCTP_CURRENT_ASSOC ||
+ params->assoc_id == SCTP_ALL_ASSOC)
list_for_each_entry(asoc, &sp->ep->asocs, asocs)
- asoc->default_rcv_context = params.assoc_value;
+ asoc->default_rcv_context = params->assoc_value;
return 0;
}
@@ -3501,18 +3422,13 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
* application using the one to many model may become confused and act
* incorrectly.
*/
-static int sctp_setsockopt_fragment_interleave(struct sock *sk,
- char __user *optval,
+static int sctp_setsockopt_fragment_interleave(struct sock *sk, int *val,
unsigned int optlen)
{
- in