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>

authored by Neil Horman and committed by Vlad Yasevich 408f22e8 19e6454c

+74 -34
+74 -34
net/sctp/socket.c
··· 3375 sctp_assoc_t associd; 3376 int retval = 0; 3377 3378 - if (len != sizeof(status)) { 3379 retval = -EINVAL; 3380 goto out; 3381 } 3382 3383 - if (copy_from_user(&status, optval, sizeof(status))) { 3384 retval = -EFAULT; 3385 goto out; 3386 } ··· 3453 struct sctp_transport *transport; 3454 int retval = 0; 3455 3456 - if (len != sizeof(pinfo)) { 3457 retval = -EINVAL; 3458 goto out; 3459 } 3460 3461 - if (copy_from_user(&pinfo, optval, sizeof(pinfo))) { 3462 retval = -EFAULT; 3463 goto out; 3464 } ··· 3525 static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 3526 int __user *optlen) 3527 { 3528 - if (len != sizeof(struct sctp_event_subscribe)) 3529 return -EINVAL; 3530 if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) 3531 return -EFAULT; 3532 return 0; ··· 3551 /* Applicable to UDP-style socket only */ 3552 if (sctp_style(sk, TCP)) 3553 return -EOPNOTSUPP; 3554 - if (len != sizeof(int)) 3555 return -EINVAL; 3556 - if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) 3557 return -EFAULT; 3558 return 0; 3559 } ··· 3607 int retval = 0; 3608 struct sctp_association *asoc; 3609 3610 - if (len != sizeof(sctp_peeloff_arg_t)) 3611 return -EINVAL; 3612 if (copy_from_user(&peeloff, optval, len)) 3613 return -EFAULT; 3614 ··· 3637 3638 /* Return the fd mapped to the new socket. */ 3639 peeloff.sd = retval; 3640 if (copy_to_user(optval, &peeloff, len)) 3641 retval = -EFAULT; 3642 ··· 3747 struct sctp_association *asoc = NULL; 3748 struct sctp_sock *sp = sctp_sk(sk); 3749 3750 - if (len != sizeof(struct sctp_paddrparams)) 3751 return -EINVAL; 3752 - 3753 if (copy_from_user(&params, optval, len)) 3754 return -EFAULT; 3755 ··· 3848 struct sctp_association *asoc = NULL; 3849 struct sctp_sock *sp = sctp_sk(sk); 3850 3851 - if (len != sizeof(struct sctp_assoc_value)) 3852 return - EINVAL; 3853 3854 if (copy_from_user(&params, optval, len)) 3855 return -EFAULT; ··· 3901 */ 3902 static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 3903 { 3904 - if (len != sizeof(struct sctp_initmsg)) 3905 return -EINVAL; 3906 if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 3907 return -EFAULT; 3908 return 0; ··· 3920 struct list_head *pos; 3921 int cnt = 0; 3922 3923 - if (len != sizeof(sctp_assoc_t)) 3924 return -EINVAL; 3925 3926 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) ··· 3956 struct sctp_sock *sp = sctp_sk(sk); 3957 int addrlen; 3958 3959 - if (len != sizeof(struct sctp_getaddrs_old)) 3960 return -EINVAL; 3961 3962 - if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) 3963 return -EFAULT; 3964 3965 if (getaddrs.addr_num <= 0) return -EINVAL; ··· 3984 if (cnt >= getaddrs.addr_num) break; 3985 } 3986 getaddrs.addr_num = cnt; 3987 - if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 3988 return -EFAULT; 3989 3990 return 0; ··· 4057 rwlock_t *addr_lock; 4058 int cnt = 0; 4059 4060 - if (len != sizeof(sctp_assoc_t)) 4061 return -EINVAL; 4062 4063 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) ··· 4199 void *buf; 4200 int bytes_copied = 0; 4201 4202 - if (len != sizeof(struct sctp_getaddrs_old)) 4203 return -EINVAL; 4204 4205 - if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) 4206 return -EFAULT; 4207 4208 if (getaddrs.addr_num <= 0) return -EINVAL; ··· 4275 4276 /* copy the leading structure back to user */ 4277 getaddrs.addr_num = cnt; 4278 - if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) 4279 err = -EFAULT; 4280 4281 error: ··· 4303 void *addrs; 4304 void *buf; 4305 4306 - if (len <= sizeof(struct sctp_getaddrs)) 4307 return -EINVAL; 4308 4309 if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) ··· 4400 struct sctp_association *asoc; 4401 struct sctp_sock *sp = sctp_sk(sk); 4402 4403 - if (len != sizeof(struct sctp_prim)) 4404 return -EINVAL; 4405 4406 - if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) 4407 return -EFAULT; 4408 4409 asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); ··· 4421 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, 4422 (union sctp_addr *)&prim.ssp_addr); 4423 4424 - if (copy_to_user(optval, &prim, sizeof(struct sctp_prim))) 4425 return -EFAULT; 4426 4427 return 0; ··· 4440 { 4441 struct sctp_setadaptation adaptation; 4442 4443 - if (len != sizeof(struct sctp_setadaptation)) 4444 return -EINVAL; 4445 4446 adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 4447 if (copy_to_user(optval, &adaptation, len)) 4448 return -EFAULT; 4449 ··· 4482 struct sctp_association *asoc; 4483 struct sctp_sock *sp = sctp_sk(sk); 4484 4485 - if (len != sizeof(struct sctp_sndrcvinfo)) 4486 return -EINVAL; 4487 - if (copy_from_user(&info, optval, sizeof(struct sctp_sndrcvinfo))) 4488 return -EFAULT; 4489 4490 asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); ··· 4508 info.sinfo_timetolive = sp->default_timetolive; 4509 } 4510 4511 - if (copy_to_user(optval, &info, sizeof(struct sctp_sndrcvinfo))) 4512 return -EFAULT; 4513 4514 return 0; ··· 4561 struct sctp_rtoinfo rtoinfo; 4562 struct sctp_association *asoc; 4563 4564 - if (len != sizeof (struct sctp_rtoinfo)) 4565 return -EINVAL; 4566 4567 - if (copy_from_user(&rtoinfo, optval, sizeof (struct sctp_rtoinfo))) 4568 return -EFAULT; 4569 4570 asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); ··· 4618 struct list_head *pos; 4619 int cnt = 0; 4620 4621 - if (len != sizeof (struct sctp_assocparams)) 4622 return -EINVAL; 4623 4624 - if (copy_from_user(&assocparams, optval, 4625 - sizeof (struct sctp_assocparams))) 4626 return -EFAULT; 4627 4628 asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); ··· 4709 struct sctp_sock *sp; 4710 struct sctp_association *asoc; 4711 4712 - if (len != sizeof(struct sctp_assoc_value)) 4713 return -EINVAL; 4714 4715 if (copy_from_user(&params, optval, len)) 4716 return -EFAULT;
··· 3375 sctp_assoc_t associd; 3376 int retval = 0; 3377 3378 + if (len < sizeof(status)) { 3379 retval = -EINVAL; 3380 goto out; 3381 } 3382 3383 + len = sizeof(status); 3384 + if (copy_from_user(&status, optval, len)) { 3385 retval = -EFAULT; 3386 goto out; 3387 } ··· 3452 struct sctp_transport *transport; 3453 int retval = 0; 3454 3455 + if (len < sizeof(pinfo)) { 3456 retval = -EINVAL; 3457 goto out; 3458 } 3459 3460 + len = sizeof(pinfo); 3461 + if (copy_from_user(&pinfo, optval, len)) { 3462 retval = -EFAULT; 3463 goto out; 3464 } ··· 3523 static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval, 3524 int __user *optlen) 3525 { 3526 + if (len < sizeof(struct sctp_event_subscribe)) 3527 return -EINVAL; 3528 + len = sizeof(struct sctp_event_subscribe); 3529 + if (put_user(len, optlen)) 3530 + return -EFAULT; 3531 if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len)) 3532 return -EFAULT; 3533 return 0; ··· 3546 /* Applicable to UDP-style socket only */ 3547 if (sctp_style(sk, TCP)) 3548 return -EOPNOTSUPP; 3549 + if (len < sizeof(int)) 3550 return -EINVAL; 3551 + len = sizeof(int); 3552 + if (put_user(len, optlen)) 3553 + return -EFAULT; 3554 + if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int))) 3555 return -EFAULT; 3556 return 0; 3557 } ··· 3599 int retval = 0; 3600 struct sctp_association *asoc; 3601 3602 + if (len < sizeof(sctp_peeloff_arg_t)) 3603 return -EINVAL; 3604 + len = sizeof(sctp_peeloff_arg_t); 3605 if (copy_from_user(&peeloff, optval, len)) 3606 return -EFAULT; 3607 ··· 3628 3629 /* Return the fd mapped to the new socket. */ 3630 peeloff.sd = retval; 3631 + if (put_user(len, optlen)) 3632 + return -EFAULT; 3633 if (copy_to_user(optval, &peeloff, len)) 3634 retval = -EFAULT; 3635 ··· 3736 struct sctp_association *asoc = NULL; 3737 struct sctp_sock *sp = sctp_sk(sk); 3738 3739 + if (len < sizeof(struct sctp_paddrparams)) 3740 return -EINVAL; 3741 + len = sizeof(struct sctp_paddrparams); 3742 if (copy_from_user(&params, optval, len)) 3743 return -EFAULT; 3744 ··· 3837 struct sctp_association *asoc = NULL; 3838 struct sctp_sock *sp = sctp_sk(sk); 3839 3840 + if (len < sizeof(struct sctp_assoc_value)) 3841 return - EINVAL; 3842 + 3843 + len = sizeof(struct sctp_assoc_value); 3844 3845 if (copy_from_user(&params, optval, len)) 3846 return -EFAULT; ··· 3888 */ 3889 static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval, int __user *optlen) 3890 { 3891 + if (len < sizeof(struct sctp_initmsg)) 3892 return -EINVAL; 3893 + len = sizeof(struct sctp_initmsg); 3894 + if (put_user(len, optlen)) 3895 + return -EFAULT; 3896 if (copy_to_user(optval, &sctp_sk(sk)->initmsg, len)) 3897 return -EFAULT; 3898 return 0; ··· 3904 struct list_head *pos; 3905 int cnt = 0; 3906 3907 + if (len < sizeof(sctp_assoc_t)) 3908 return -EINVAL; 3909 3910 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) ··· 3940 struct sctp_sock *sp = sctp_sk(sk); 3941 int addrlen; 3942 3943 + if (len < sizeof(struct sctp_getaddrs_old)) 3944 return -EINVAL; 3945 3946 + len = sizeof(struct sctp_getaddrs_old); 3947 + 3948 + if (copy_from_user(&getaddrs, optval, len)) 3949 return -EFAULT; 3950 3951 if (getaddrs.addr_num <= 0) return -EINVAL; ··· 3966 if (cnt >= getaddrs.addr_num) break; 3967 } 3968 getaddrs.addr_num = cnt; 3969 + if (put_user(len, optlen)) 3970 + return -EFAULT; 3971 + if (copy_to_user(optval, &getaddrs, len)) 3972 return -EFAULT; 3973 3974 return 0; ··· 4037 rwlock_t *addr_lock; 4038 int cnt = 0; 4039 4040 + if (len < sizeof(sctp_assoc_t)) 4041 return -EINVAL; 4042 4043 if (copy_from_user(&id, optval, sizeof(sctp_assoc_t))) ··· 4179 void *buf; 4180 int bytes_copied = 0; 4181 4182 + if (len < sizeof(struct sctp_getaddrs_old)) 4183 return -EINVAL; 4184 4185 + len = sizeof(struct sctp_getaddrs_old); 4186 + if (copy_from_user(&getaddrs, optval, len)) 4187 return -EFAULT; 4188 4189 if (getaddrs.addr_num <= 0) return -EINVAL; ··· 4254 4255 /* copy the leading structure back to user */ 4256 getaddrs.addr_num = cnt; 4257 + if (copy_to_user(optval, &getaddrs, len)) 4258 err = -EFAULT; 4259 4260 error: ··· 4282 void *addrs; 4283 void *buf; 4284 4285 + if (len < sizeof(struct sctp_getaddrs)) 4286 return -EINVAL; 4287 4288 if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) ··· 4379 struct sctp_association *asoc; 4380 struct sctp_sock *sp = sctp_sk(sk); 4381 4382 + if (len < sizeof(struct sctp_prim)) 4383 return -EINVAL; 4384 4385 + len = sizeof(struct sctp_prim); 4386 + 4387 + if (copy_from_user(&prim, optval, len)) 4388 return -EFAULT; 4389 4390 asoc = sctp_id2assoc(sk, prim.ssp_assoc_id); ··· 4398 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, 4399 (union sctp_addr *)&prim.ssp_addr); 4400 4401 + if (put_user(len, optlen)) 4402 + return -EFAULT; 4403 + if (copy_to_user(optval, &prim, len)) 4404 return -EFAULT; 4405 4406 return 0; ··· 4415 { 4416 struct sctp_setadaptation adaptation; 4417 4418 + if (len < sizeof(struct sctp_setadaptation)) 4419 return -EINVAL; 4420 4421 + len = sizeof(struct sctp_setadaptation); 4422 + 4423 adaptation.ssb_adaptation_ind = sctp_sk(sk)->adaptation_ind; 4424 + 4425 + if (put_user(len, optlen)) 4426 + return -EFAULT; 4427 if (copy_to_user(optval, &adaptation, len)) 4428 return -EFAULT; 4429 ··· 4452 struct sctp_association *asoc; 4453 struct sctp_sock *sp = sctp_sk(sk); 4454 4455 + if (len < sizeof(struct sctp_sndrcvinfo)) 4456 return -EINVAL; 4457 + 4458 + len = sizeof(struct sctp_sndrcvinfo); 4459 + 4460 + if (copy_from_user(&info, optval, len)) 4461 return -EFAULT; 4462 4463 asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); ··· 4475 info.sinfo_timetolive = sp->default_timetolive; 4476 } 4477 4478 + if (put_user(len, optlen)) 4479 + return -EFAULT; 4480 + if (copy_to_user(optval, &info, len)) 4481 return -EFAULT; 4482 4483 return 0; ··· 4526 struct sctp_rtoinfo rtoinfo; 4527 struct sctp_association *asoc; 4528 4529 + if (len < sizeof (struct sctp_rtoinfo)) 4530 return -EINVAL; 4531 4532 + len = sizeof(struct sctp_rtoinfo); 4533 + 4534 + if (copy_from_user(&rtoinfo, optval, len)) 4535 return -EFAULT; 4536 4537 asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); ··· 4581 struct list_head *pos; 4582 int cnt = 0; 4583 4584 + if (len < sizeof (struct sctp_assocparams)) 4585 return -EINVAL; 4586 4587 + len = sizeof(struct sctp_assocparams); 4588 + 4589 + if (copy_from_user(&assocparams, optval, len)) 4590 return -EFAULT; 4591 4592 asoc = sctp_id2assoc(sk, assocparams.sasoc_assoc_id); ··· 4671 struct sctp_sock *sp; 4672 struct sctp_association *asoc; 4673 4674 + if (len < sizeof(struct sctp_assoc_value)) 4675 return -EINVAL; 4676 + 4677 + len = sizeof(struct sctp_assoc_value); 4678 4679 if (copy_from_user(&params, optval, len)) 4680 return -EFAULT;