aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2007-06-16 14:03:45 -0400
committerVlad Yasevich <vladislav.yasevich@hp.com>2007-06-19 09:46:34 -0400
commit408f22e81ea2fcf96c80e85ee12d20ef5148bf7c (patch)
treeee155bc07749f551247c9fbf86e39356351db49d /net/sctp
parent19e6454ca778e11e81497bd87c930dc0defd03d7 (diff)
SCTP: update sctp_getsockopt helpers to allow oversized buffers
I noted the other day while looking at a bug that was ostensibly in some perl networking library, that we strictly avoid allowing getsockopt operations to complete if we pass in oversized buffers. This seems to make libraries like Perl::NET malfunction since it seems to allocate oversized buffers for use in several operations. It also seems to be out of line with the way udp, tcp and ip getsockopt routines handle buffer input (since the *optlen pointer in both an input and an output and gets set to the length of the data that we copy into the buffer). This patch brings our getsockopt helpers into line with other protocols, and allows us to accept oversized buffers for our getsockopt operations. Tested by me with good results. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/socket.c108
1 files changed, 74 insertions, 34 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 6edaaa009d62..c1f239ac12b9 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3375,12 +3375,13 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
3375 sctp_assoc_t associd; 3375 sctp_assoc_t associd;
3376 int retval = 0; 3376 int retval = 0;
3377 3377
3378 if (len != sizeof(status)) { 3378 if (len < sizeof(status)) {
3379 retval = -EINVAL; 3379 retval = -EINVAL;
3380 goto out; 3380 goto out;
3381 } 3381 }
3382 3382
3383 if (copy_from_user(&status, optval, sizeof(status))) { 3383 len = sizeof(status);
3384 if (copy_from_user(&status, optval, len)) {
3384 retval = -EFAULT; 3385 retval = -EFAULT;
3385 goto out; 3386 goto out;
3386 } 3387 }
@@ -3452,12 +3453,13 @@ static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
3452 struct sctp_transport *transport; 3453 struct sctp_transport *transport;
3453 int retval = 0; 3454 int retval = 0;
3454 3455
3455 if (len != sizeof(pinfo)) { 3456 if (len < sizeof(pinfo)) {
3456 retval = -EINVAL; 3457 retval = -EINVAL;
3457 goto out; 3458 goto out;
3458 } 3459 }
3459 3460
3460 if (copy_from_user(&pinfo, optval, sizeof(pinfo))) { 3461 len = sizeof(pinfo);
3462 if (copy_from_user(&pinfo, optval, len)) {
3461 retval = -EFAULT; 3463 retval = -EFAULT;
3462 goto out; 3464 goto out;
3463 } 3465 }
@@ -3523,8 +3525,11 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
3523static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 3525static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
3524 int __user *optlen) 3526 int __user *optlen)
3525{ 3527{
3526 if (len != sizeof(struct sctp_event_subscribe)) 3528 if (len < sizeof(struct sctp_event_subscribe))
3527 return -EINVAL; 3529 return -EINVAL;
3530 len = sizeof(struct sctp_event_subscribe);
3531 if (put_user(len, optlen))
3532 return -EFAULT;
3528 if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) 3533 if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len))
3529 return -EFAULT; 3534 return -EFAULT;
3530 return 0; 3535 return 0;
@@ -3546,9 +3551,12 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv
3546 /* Applicable to UDP-style socket only */ 3551 /* Applicable to UDP-style socket only */
3547 if (sctp_style(sk, TCP)) 3552 if (sctp_style(sk, TCP))
3548 return -EOPNOTSUPP; 3553 return -EOPNOTSUPP;
3549 if (len != sizeof(int)) 3554 if (len < sizeof(int))
3550 return -EINVAL; 3555 return -EINVAL;
3551 if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) 3556 len = sizeof(int);
3557 if (put_user(len, optlen))
3558 return -EFAULT;
3559 if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int)))
3552 return -EFAULT; 3560 return -EFAULT;
3553 return 0; 3561 return 0;
3554} 3562}
@@ -3599,8 +3607,9 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
3599 int retval = 0; 3607 int retval = 0;
3600 struct sctp_association *asoc; 3608 struct sctp_association *asoc;
3601 3609
3602 if (len != sizeof(sctp_peeloff_arg_t)) 3610 if (len < sizeof(sctp_peeloff_arg_t))
3603 return -EINVAL; 3611 return -EINVAL;
3612 len = sizeof(sctp_peeloff_arg_t);
3604 if (copy_from_user(&peeloff, optval, len)) 3613 if (copy_from_user(&peeloff, optval, len))
3605 return -EFAULT; 3614 return -EFAULT;
3606 3615
@@ -3628,6 +3637,8 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
3628 3637
3629 /* Return the fd mapped to the new socket. */ 3638 /* Return the fd mapped to the new socket. */
3630 peeloff.sd = retval; 3639 peeloff.sd = retval;
3640 if (put_user(len, optlen))
3641 return -EFAULT;
3631 if (copy_to_user(optval, &peeloff, len)) 3642 if (copy_to_user(optval, &peeloff, len))
3632 retval = -EFAULT; 3643 retval = -EFAULT;
3633 3644
@@ -3736,9 +3747,9 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
3736 struct sctp_association *asoc = NULL; 3747 struct sctp_association *asoc = NULL;
3737 struct sctp_sock *sp = sctp_sk(sk); 3748 struct sctp_sock *sp = sctp_sk(sk);
3738 3749
3739 if (len != sizeof(struct sctp_paddrparams)) 3750 if (len < sizeof(struct sctp_paddrparams))
3740 return -EINVAL; 3751 return -EINVAL;
3741 3752 len = sizeof(struct sctp_paddrparams);
3742 if (copy_from_user(&params, optval, len)) 3753 if (copy_from_user(&params, optval, len))
3743 return -EFAULT; 3754 return -EFAULT;
3744 3755
@@ -3837,9 +3848,11 @@ static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
3837 struct sctp_association *asoc = NULL; 3848 struct sctp_association *asoc = NULL;
3838 struct sctp_sock *sp = sctp_sk(sk); 3849 struct sctp_sock *sp = sctp_sk(sk);
3839 3850
3840 if (len != sizeof(struct sctp_assoc_value)) 3851 if (len < sizeof(struct sctp_assoc_value))
3841 return - EINVAL; 3852 return - EINVAL;
3842 3853
3854 len = sizeof(struct sctp_assoc_value);
3855
3843 if (copy_from_user(&params, optval, len)) 3856 if (copy_from_user(&params, optval, len))
3844 return -EFAULT; 3857 return -EFAULT;
3845 3858
@@ -3888,8 +3901,11 @@ static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
3888 */ 3901 */
3889static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 3902static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen)
3890{ 3903{
3891 if (len != sizeof(struct sctp_initmsg)) 3904 if (len < sizeof(struct sctp_initmsg))
3892 return -EINVAL; 3905 return -EINVAL;
3906 len = sizeof(struct sctp_initmsg);
3907 if (put_user(len, optlen))
3908 return -EFAULT;
3893 if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 3909 if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len))
3894 return -EFAULT; 3910 return -EFAULT;
3895 return 0; 3911 return 0;
@@ -3904,7 +3920,7 @@ static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len,
3904 struct list_head *pos; 3920 struct list_head *pos;
3905 int cnt = 0; 3921 int cnt = 0;
3906 3922
3907 if (len != sizeof(sctp_assoc_t)) 3923 if (len < sizeof(sctp_assoc_t))
3908 return -EINVAL; 3924 return -EINVAL;
3909 3925
3910 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) 3926 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
@@ -3940,10 +3956,12 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
3940 struct sctp_sock *sp = sctp_sk(sk); 3956 struct sctp_sock *sp = sctp_sk(sk);
3941 int addrlen; 3957 int addrlen;
3942 3958
3943 if (len != sizeof(struct sctp_getaddrs_old)) 3959 if (len < sizeof(struct sctp_getaddrs_old))
3944 return -EINVAL; 3960 return -EINVAL;
3945 3961
3946 if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) 3962 len = sizeof(struct sctp_getaddrs_old);
3963
3964 if (copy_from_user(&getaddrs, optval, len))
3947 return -EFAULT; 3965 return -EFAULT;
3948 3966
3949 if (getaddrs.addr_num <= 0) return -EINVAL; 3967 if (getaddrs.addr_num <= 0) return -EINVAL;
@@ -3966,7 +3984,9 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len,
3966 if (cnt >= getaddrs.addr_num) break; 3984 if (cnt >= getaddrs.addr_num) break;
3967 } 3985 }
3968 getaddrs.addr_num = cnt; 3986 getaddrs.addr_num = cnt;
3969 if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 3987 if (put_user(len, optlen))
3988 return -EFAULT;
3989 if (copy_to_user(optval, &getaddrs, len))
3970 return -EFAULT; 3990 return -EFAULT;
3971 3991
3972 return 0; 3992 return 0;
@@ -4037,7 +4057,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
4037 rwlock_t *addr_lock; 4057 rwlock_t *addr_lock;
4038 int cnt = 0; 4058 int cnt = 0;
4039 4059
4040 if (len != sizeof(sctp_assoc_t)) 4060 if (len < sizeof(sctp_assoc_t))
4041 return -EINVAL; 4061 return -EINVAL;
4042 4062
4043 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) 4063 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
@@ -4179,10 +4199,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
4179 void *buf; 4199 void *buf;
4180 int bytes_copied = 0; 4200 int bytes_copied = 0;
4181 4201
4182 if (len != sizeof(struct sctp_getaddrs_old)) 4202 if (len < sizeof(struct sctp_getaddrs_old))
4183 return -EINVAL; 4203 return -EINVAL;
4184 4204
4185 if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) 4205 len = sizeof(struct sctp_getaddrs_old);
4206 if (copy_from_user(&getaddrs, optval, len))
4186 return -EFAULT; 4207 return -EFAULT;
4187 4208
4188 if (getaddrs.addr_num <= 0) return -EINVAL; 4209 if (getaddrs.addr_num <= 0) return -EINVAL;
@@ -4254,7 +4275,7 @@ copy_getaddrs:
4254 4275
4255 /* copy the leading structure back to user */ 4276 /* copy the leading structure back to user */
4256 getaddrs.addr_num = cnt; 4277 getaddrs.addr_num = cnt;
4257 if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 4278 if (copy_to_user(optval, &getaddrs, len))
4258 err = -EFAULT; 4279 err = -EFAULT;
4259 4280
4260error: 4281error:
@@ -4282,7 +4303,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
4282 void *addrs; 4303 void *addrs;
4283 void *buf; 4304 void *buf;
4284 4305
4285 if (len <= sizeof(struct sctp_getaddrs)) 4306 if (len < sizeof(struct sctp_getaddrs))
4286 return -EINVAL; 4307 return -EINVAL;
4287 4308
4288 if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) 4309 if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs)))
@@ -4379,10 +4400,12 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
4379 struct sctp_association *asoc; 4400 struct sctp_association *asoc;
4380 struct sctp_sock *sp = sctp_sk(sk); 4401 struct sctp_sock *sp = sctp_sk(sk);
4381 4402
4382 if (len != sizeof(struct sctp_prim)) 4403 if (len < sizeof(struct sctp_prim))
4383 return -EINVAL; 4404 return -EINVAL;
4384 4405
4385 if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) 4406 len = sizeof(struct sctp_prim);
4407
4408 if (copy_from_user(&prim, optval, len))
4386 return -EFAULT; 4409 return -EFAULT;
4387 4410
4388 asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); 4411 asoc = sctp_id2assoc(sk, prim.ssp_assoc_id);
@@ -4398,7 +4421,9 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
4398 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, 4421 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp,
4399 (union sctp_addr *)&prim.ssp_addr); 4422 (union sctp_addr *)&prim.ssp_addr);
4400 4423
4401 if (copy_to_user(optval, &prim, sizeof(struct sctp_prim))) 4424 if (put_user(len, optlen))
4425 return -EFAULT;
4426 if (copy_to_user(optval, &prim, len))
4402 return -EFAULT; 4427 return -EFAULT;
4403 4428
4404 return 0; 4429 return 0;
@@ -4415,10 +4440,15 @@ static int sctp_getsockopt_adaptation_layer(struct sock *sk, int len,
4415{ 4440{
4416 struct sctp_setadaptation adaptation; 4441 struct sctp_setadaptation adaptation;
4417 4442
4418 if (len != sizeof(struct sctp_setadaptation)) 4443 if (len < sizeof(struct sctp_setadaptation))
4419 return -EINVAL; 4444 return -EINVAL;
4420 4445
4446 len = sizeof(struct sctp_setadaptation);
4447
4421 adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 4448 adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind;
4449
4450 if (put_user(len, optlen))
4451 return -EFAULT;
4422 if (copy_to_user(optval, &adaptation, len)) 4452 if (copy_to_user(optval, &adaptation, len))
4423 return -EFAULT; 4453 return -EFAULT;
4424 4454
@@ -4452,9 +4482,12 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
4452 struct sctp_association *asoc; 4482 struct sctp_association *asoc;
4453 struct sctp_sock *sp = sctp_sk(sk); 4483 struct sctp_sock *sp = sctp_sk(sk);
4454 4484
4455 if (len != sizeof(struct sctp_sndrcvinfo)) 4485 if (len < sizeof(struct sctp_sndrcvinfo))
4456 return -EINVAL; 4486 return -EINVAL;
4457 if (copy_from_user(&info, optval, sizeof(struct sctp_sndrcvinfo))) 4487
4488 len = sizeof(struct sctp_sndrcvinfo);
4489
4490 if (copy_from_user(&info, optval, len))
4458 return -EFAULT; 4491 return -EFAULT;
4459 4492
4460 asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); 4493 asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
@@ -4475,7 +4508,9 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
4475 info.sinfo_timetolive = sp->default_timetolive; 4508 info.sinfo_timetolive = sp->default_timetolive;
4476 } 4509 }
4477 4510
4478 if (copy_to_user(optval, &info, sizeof(struct sctp_sndrcvinfo))) 4511 if (put_user(len, optlen))
4512 return -EFAULT;
4513 if (copy_to_user(optval, &info, len))
4479 return -EFAULT; 4514 return -EFAULT;
4480 4515
4481 return 0; 4516 return 0;
@@ -4526,10 +4561,12 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
4526 struct sctp_rtoinfo rtoinfo; 4561 struct sctp_rtoinfo rtoinfo;
4527 struct sctp_association *asoc; 4562 struct sctp_association *asoc;
4528 4563
4529 if (len != sizeof (struct sctp_rtoinfo)) 4564 if (len < sizeof (struct sctp_rtoinfo))
4530 return -EINVAL; 4565 return -EINVAL;
4531 4566
4532 if (copy_from_user(&rtoinfo, optval, sizeof (struct sctp_rtoinfo))) 4567 len = sizeof(struct sctp_rtoinfo);
4568
4569 if (copy_from_user(&rtoinfo, optval, len))
4533 return -EFAULT; 4570 return -EFAULT;
4534 4571
4535 asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); 4572 asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id);
@@ -4581,11 +4618,12 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len,
4581 struct list_head *pos; 4618 struct list_head *pos;
4582 int cnt = 0; 4619 int cnt = 0;
4583 4620
4584 if (len != sizeof (struct sctp_assocparams)) 4621 if (len < sizeof (struct sctp_assocparams))
4585 return -EINVAL; 4622 return -EINVAL;
4586 4623
4587 if (copy_from_user(&assocparams, optval, 4624 len = sizeof(struct sctp_assocparams);
4588 sizeof (struct sctp_assocparams))) 4625
4626 if (copy_from_user(&assocparams, optval, len))
4589 return -EFAULT; 4627 return -EFAULT;
4590 4628
4591 asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); 4629 asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id);
@@ -4671,9 +4709,11 @@ static int sctp_getsockopt_context(struct sock *sk, int len,
4671 struct sctp_sock *sp; 4709 struct sctp_sock *sp;
4672 struct sctp_association *asoc; 4710 struct sctp_association *asoc;
4673 4711
4674 if (len != sizeof(struct sctp_assoc_value)) 4712 if (len < sizeof(struct sctp_assoc_value))
4675 return -EINVAL; 4713 return -EINVAL;
4676 4714
4715 len = sizeof(struct sctp_assoc_value);
4716
4677 if (copy_from_user(&params, optval, len)) 4717 if (copy_from_user(&params, optval, len))
4678 return -EFAULT; 4718 return -EFAULT;
4679 4719