On 2013/12/9 10:40, Vlad Yasevich wrote: > On 12/08/2013 09:28 PM, Wang Weidong wrote: >> On 2013/12/9 10:19, Vlad Yasevich wrote: >>> On 12/08/2013 08:53 PM, Wang Weidong wrote: >>>> On 2013/12/8 2:54, Vlad Yasevich wrote: >>>>> On 12/07/2013 02:17 AM, Wang Weidong wrote: >>>>>> rto_min should be smaller than rto_max while rto_max should be larger >>>>>> than rto_min. Add two proc_handler for the checking. Add the check in >>>>>> sctp_setsockopt_rtoinfo. >>>>>> >>>>>> Suggested-by: Vlad Yasevich <vyasevich@xxxxxxxxx> >>>>>> Signed-off-by: Wang Weidong <wangweidong1@xxxxxxxxxx> >>>>>> --- >>>>>> include/net/sctp/constants.h | 3 ++ >>>>>> net/sctp/socket.c | 5 +++ >>>>>> net/sctp/sysctl.c | 73 ++++++++++++++++++++++++++++++++++++++++---- >>>>>> 3 files changed, 75 insertions(+), 6 deletions(-) >>>>>> >>>>>> diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h >>>>>> index 2f0a565..d276978 100644 >>>>>> --- a/include/net/sctp/constants.h >>>>>> +++ b/include/net/sctp/constants.h >>>>>> @@ -279,6 +279,9 @@ enum { SCTP_MAX_GABS = 16 }; >>>>>> #define SCTP_RTO_ALPHA 3 /* 1/8 when converted to right shifts. */ >>>>>> #define SCTP_RTO_BETA 2 /* 1/4 when converted to right shifts. */ >>>>>> >>>>>> +#define SCTP_ONE 1 /* 1 ms */ >>>>>> +#define SCTP_TIMER_MAX 86400000 /* ms in one day */ >>>>>> + >>>>>> /* Maximum number of new data packets that can be sent in a burst. */ >>>>>> #define SCTP_DEFAULT_MAX_BURST 4 >>>>>> >>>>>> diff --git a/net/sctp/socket.c b/net/sctp/socket.c >>>>>> index 72046b9..13411ad 100644 >>>>>> --- a/net/sctp/socket.c >>>>>> +++ b/net/sctp/socket.c >>>>>> @@ -2818,6 +2818,11 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigne >>>>>> if (copy_from_user(&rtoinfo, optval, optlen)) >>>>>> return -EFAULT; >>>>>> >>>>>> + if (rtoinfo.srto_min < SCTP_ONE || >>>>>> + rtoinfo.srto_max > SCTP_TIMER_MAX || >>>>>> + rtoinfo.srto_max < rtoinfo.srto_min) >>>>>> + return -EINVAL; >>>>>> + >>>>> >>>>> You can not do the check for srto_min < 1. The following is the text >>>>> from the spec: >>>>> All times are given in milliseconds. A value of 0, when modifying >>>>> the parameters, indicates that the current value should not be >>>>> changed. >>>>> >>>> Yes, Your are right, I found it in draft-ietf-tsvwg-sctpsocket-14.txt. >>>> Thanks. >>>> >>>>> So, it is valid for a user to pass in a value of 0. Also, I am not sure >>>>> if it makes sense to bind the upper limit here, as well. >>>>> >>>>> -vlad >>>>> >>>> Here, I am not sure as well. I think it should like what we do to the >>>> init_net.sctp.rto_max when set larger than timer_max. Just not change the value. >>>> >>> >>> So, the basic reason that sysctl is limited is that it is a default >>> for all sctp association on the system. It makes some sense to limit >>> what the max value here could be. Limiting it to double suggested >>> RTO.MAX would only make it 2 minutes and may be insufficient for some >>> of the high latency low-throughput wireless links. Making it about an >>> hour should be fine... This would be a separate patch though... >>> >> Here, you mean that we should use 3600*1000 rather than 86400000? So >> we should use another patch to fix that after my patchs? >> >>> Limiting the user-supplied value is not as appropriate since the >>> assumption is that user application may know better what it's >>> requirements are and it is not up to the stack to limit those. As >>> long as the user value is withing the usable range (and the kernel >>> will already knows how and does limit this range), we should not >>> limit this further. >>> >>> -vlad >>> >> Agree, So I should check like this: >> !srto_min || !srto_max || srto_min > srto_max ? >> And no need to add macros for checking. > > No, I think this would have to be a little more complicated :( > Remember it's ok to have srto_min == 0 and srto_max == 0. It just > means that no change happens. > > You may need to do something like > > unsigned long rto_max, rto_min; > > if (rtoinfo.srto_max) > rto_max = msecs_to_jiffies(rtoinfo.srto_max); > else > rto_max = asoc ? asoc->rto_max : sp->rto_max; > > if (rtoinfo.srto_min) > rto_min = msecs_to_jiffies(rtoinfo.srto_min); > else > rto_min = asoc ? asoc->rto_min : sp->rto_min; > > if (rto_min > rto_max) > return -EINVAL; > > if (asoc) { > asoc->rto_min = rto_min; > asoc->rto_max = rto_max; > ... > etc.... > > This way we make sure that the user that supplied just rto_min or just > rto_max didn't set them so that min > max. > > -vlad Hi vald, I found that we had checked the value of 0 in sctp_setsockopt_rtoinfo. So I only do this: if (asoc) { + if (msecs_to_jiffies(rtoinfo.srto_min) > + msecs_to_jiffies(rtoinfo.srto_max)) + return -EINVAL; ... } else { ... + if (rtoinfo.srto_min > rtoinfo.srto_max) + return -EINVAL; ... } There because we set value to asoc and sp is not same. So I add the check into two path. Regards. Wang >> >> Thanks. >> >>>> >>>> Regards. >>>> Wang >>>> >>>>>> asoc = sctp_id2assoc(sk, rtoinfo.srto_assoc_id); >>>>>> >>>>>> /* Set the values to the specific association */ >>>>>> diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c >>>>>> index 6b36561..33c56c6 100644 >>>>>> --- a/net/sctp/sysctl.c >>>>>> +++ b/net/sctp/sysctl.c >>>>>> @@ -40,8 +40,8 @@ >>>>>> #include <linux/sysctl.h> >>>>>> >>>>>> static int zero = 0; >>>>>> -static int one = 1; >>>>>> -static int timer_max = 86400000; /* ms in one day */ >>>>>> +static int one = SCTP_ONE; >>>>>> +static int timer_max = SCTP_TIMER_MAX; >>>>>> static int int_max = INT_MAX; >>>>>> static int sack_timer_min = 1; >>>>>> static int sack_timer_max = 500; >>>>>> @@ -61,6 +61,13 @@ static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, >>>>>> void __user *buffer, size_t *lenp, >>>>>> >>>>>> loff_t *ppos); >>>>>> +static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, >>>>>> + void __user *buffer, size_t *lenp, >>>>>> + loff_t *ppos); >>>>>> +static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, >>>>>> + void __user *buffer, size_t *lenp, >>>>>> + loff_t *ppos); >>>>>> + >>>>>> static struct ctl_table sctp_table[] = { >>>>>> { >>>>>> .procname = "sctp_mem", >>>>>> @@ -102,17 +109,17 @@ static struct ctl_table sctp_net_table[] = { >>>>>> .data = &init_net.sctp.rto_min, >>>>>> .maxlen = sizeof(unsigned int), >>>>>> .mode = 0644, >>>>>> - .proc_handler = proc_dointvec_minmax, >>>>>> + .proc_handler = proc_sctp_do_rto_min, >>>>>> .extra1 = &one, >>>>>> - .extra2 = &timer_max >>>>>> + .extra2 = &init_net.sctp.rto_max >>>>>> }, >>>>>> { >>>>>> .procname = "rto_max", >>>>>> .data = &init_net.sctp.rto_max, >>>>>> .maxlen = sizeof(unsigned int), >>>>>> .mode = 0644, >>>>>> - .proc_handler = proc_dointvec_minmax, >>>>>> - .extra1 = &one, >>>>>> + .proc_handler = proc_sctp_do_rto_max, >>>>>> + .extra1 = &init_net.sctp.rto_min, >>>>>> .extra2 = &timer_max >>>>>> }, >>>>>> { >>>>>> @@ -342,6 +349,60 @@ static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, >>>>>> return ret; >>>>>> } >>>>>> >>>>>> +static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, >>>>>> + void __user*buffer, size_t *lenp, >>>>>> + loff_t *ppos) >>>>>> +{ >>>>>> + struct net *net = current->nsproxy->net_ns; >>>>>> + int new_value; >>>>>> + struct ctl_table tbl; >>>>>> + unsigned int min = *(unsigned int *) ctl->extra1; >>>>>> + unsigned int max = *(unsigned int *) ctl->extra2; >>>>>> + int ret; >>>>>> + >>>>>> + memset(&tbl, 0, sizeof(struct ctl_table)); >>>>>> + tbl.maxlen = sizeof(unsigned int); >>>>>> + >>>>>> + if (write) >>>>>> + tbl.data = &new_value; >>>>>> + else >>>>>> + tbl.data = &net->sctp.rto_min; >>>>>> + ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); >>>>>> + if (write) { >>>>>> + if (ret || new_value > max || new_value < min) >>>>>> + return -EINVAL; >>>>>> + net->sctp.rto_min = new_value; >>>>>> + } >>>>>> + return ret; >>>>>> +} >>>>>> + >>>>>> +static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, >>>>>> + void __user*buffer, size_t *lenp, >>>>>> + loff_t *ppos) >>>>>> +{ >>>>>> + struct net *net = current->nsproxy->net_ns; >>>>>> + int new_value; >>>>>> + struct ctl_table tbl; >>>>>> + unsigned int min = *(unsigned int *) ctl->extra1; >>>>>> + unsigned int max = *(unsigned int *) ctl->extra2; >>>>>> + int ret; >>>>>> + >>>>>> + memset(&tbl, 0, sizeof(struct ctl_table)); >>>>>> + tbl.maxlen = sizeof(unsigned int); >>>>>> + >>>>>> + if (write) >>>>>> + tbl.data = &new_value; >>>>>> + else >>>>>> + tbl.data = &net->sctp.rto_max; >>>>>> + ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); >>>>>> + if (write) { >>>>>> + if (ret || new_value > max || new_value < min) >>>>>> + return -EINVAL; >>>>>> + net->sctp.rto_max = new_value; >>>>>> + } >>>>>> + return ret; >>>>>> +} >>>>>> + >>>>>> int sctp_sysctl_net_register(struct net *net) >>>>>> { >>>>>> struct ctl_table *table; >>>>>> >>>>> >>>>> -- >>>>> To unsubscribe from this list: send the line "unsubscribe netdev" in >>>>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>>>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>>>> >>>>> . >>>>> >>>> >>>> >>> >>> -- >>> To unsubscribe from this list: send the line "unsubscribe linux-sctp" in >>> the body of a message to majordomo@xxxxxxxxxxxxxxx >>> More majordomo info at http://vger.kernel.org/majordomo-info.html >>> >>> . >>> >> >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-sctp" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > > . > -- To unsubscribe from this list: send the line "unsubscribe linux-sctp" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html