diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2014-06-18 19:31:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-06-18 20:03:07 -0400 |
commit | ff5e92c1affe7166b3f6e7073e648ed65a6e2e59 (patch) | |
tree | 3e4c1685968ba9ea18fd763ea04bc0b3f3c87cef /net/sctp | |
parent | d36a4f4b472334562b8e7252e35d3d770db83815 (diff) |
net: sctp: propagate sysctl errors from proc_do* properly
sysctl handler proc_sctp_do_hmac_alg(), proc_sctp_do_rto_min() and
proc_sctp_do_rto_max() do not properly reflect some error cases
when writing values via sysctl from internal proc functions such
as proc_dointvec() and proc_dostring().
In all these cases we pass the test for write != 0 and partially
do additional work just to notice that additional sanity checks
fail and we return with hard-coded -EINVAL while proc_do*
functions might also return different errors. So fix this up by
simply testing a successful return of proc_do* right after
calling it.
This also allows to propagate its return value onwards to the user.
While touching this, also fix up some minor style issues.
Fixes: 4f3fdf3bc59c ("sctp: add check rto_min and rto_max in sysctl")
Fixes: 3c68198e7511 ("sctp: Make hmac algorithm selection for cookie generation dynamic")
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/sysctl.c | 43 |
1 files changed, 23 insertions, 20 deletions
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index dcb19592761e..cc12162ba091 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c | |||
@@ -321,41 +321,40 @@ static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write, | |||
321 | loff_t *ppos) | 321 | loff_t *ppos) |
322 | { | 322 | { |
323 | struct net *net = current->nsproxy->net_ns; | 323 | struct net *net = current->nsproxy->net_ns; |
324 | char tmp[8]; | ||
325 | struct ctl_table tbl; | 324 | struct ctl_table tbl; |
326 | int ret; | 325 | bool changed = false; |
327 | int changed = 0; | ||
328 | char *none = "none"; | 326 | char *none = "none"; |
327 | char tmp[8]; | ||
328 | int ret; | ||
329 | 329 | ||
330 | memset(&tbl, 0, sizeof(struct ctl_table)); | 330 | memset(&tbl, 0, sizeof(struct ctl_table)); |
331 | 331 | ||
332 | if (write) { | 332 | if (write) { |
333 | tbl.data = tmp; | 333 | tbl.data = tmp; |
334 | tbl.maxlen = 8; | 334 | tbl.maxlen = sizeof(tmp); |
335 | } else { | 335 | } else { |
336 | tbl.data = net->sctp.sctp_hmac_alg ? : none; | 336 | tbl.data = net->sctp.sctp_hmac_alg ? : none; |
337 | tbl.maxlen = strlen(tbl.data); | 337 | tbl.maxlen = strlen(tbl.data); |
338 | } | 338 | } |
339 | ret = proc_dostring(&tbl, write, buffer, lenp, ppos); | ||
340 | 339 | ||
341 | if (write) { | 340 | ret = proc_dostring(&tbl, write, buffer, lenp, ppos); |
341 | if (write && ret == 0) { | ||
342 | #ifdef CONFIG_CRYPTO_MD5 | 342 | #ifdef CONFIG_CRYPTO_MD5 |
343 | if (!strncmp(tmp, "md5", 3)) { | 343 | if (!strncmp(tmp, "md5", 3)) { |
344 | net->sctp.sctp_hmac_alg = "md5"; | 344 | net->sctp.sctp_hmac_alg = "md5"; |
345 | changed = 1; | 345 | changed = true; |
346 | } | 346 | } |
347 | #endif | 347 | #endif |
348 | #ifdef CONFIG_CRYPTO_SHA1 | 348 | #ifdef CONFIG_CRYPTO_SHA1 |
349 | if (!strncmp(tmp, "sha1", 4)) { | 349 | if (!strncmp(tmp, "sha1", 4)) { |
350 | net->sctp.sctp_hmac_alg = "sha1"; | 350 | net->sctp.sctp_hmac_alg = "sha1"; |
351 | changed = 1; | 351 | changed = true; |
352 | } | 352 | } |
353 | #endif | 353 | #endif |
354 | if (!strncmp(tmp, "none", 4)) { | 354 | if (!strncmp(tmp, "none", 4)) { |
355 | net->sctp.sctp_hmac_alg = NULL; | 355 | net->sctp.sctp_hmac_alg = NULL; |
356 | changed = 1; | 356 | changed = true; |
357 | } | 357 | } |
358 | |||
359 | if (!changed) | 358 | if (!changed) |
360 | ret = -EINVAL; | 359 | ret = -EINVAL; |
361 | } | 360 | } |
@@ -368,11 +367,10 @@ static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, | |||
368 | loff_t *ppos) | 367 | loff_t *ppos) |
369 | { | 368 | { |
370 | struct net *net = current->nsproxy->net_ns; | 369 | struct net *net = current->nsproxy->net_ns; |
371 | int new_value; | ||
372 | struct ctl_table tbl; | ||
373 | unsigned int min = *(unsigned int *) ctl->extra1; | 370 | unsigned int min = *(unsigned int *) ctl->extra1; |
374 | unsigned int max = *(unsigned int *) ctl->extra2; | 371 | unsigned int max = *(unsigned int *) ctl->extra2; |
375 | int ret; | 372 | struct ctl_table tbl; |
373 | int ret, new_value; | ||
376 | 374 | ||
377 | memset(&tbl, 0, sizeof(struct ctl_table)); | 375 | memset(&tbl, 0, sizeof(struct ctl_table)); |
378 | tbl.maxlen = sizeof(unsigned int); | 376 | tbl.maxlen = sizeof(unsigned int); |
@@ -381,12 +379,15 @@ static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, | |||
381 | tbl.data = &new_value; | 379 | tbl.data = &new_value; |
382 | else | 380 | else |
383 | tbl.data = &net->sctp.rto_min; | 381 | tbl.data = &net->sctp.rto_min; |
382 | |||
384 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); | 383 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); |
385 | if (write) { | 384 | if (write && ret == 0) { |
386 | if (ret || new_value > max || new_value < min) | 385 | if (new_value > max || new_value < min) |
387 | return -EINVAL; | 386 | return -EINVAL; |
387 | |||
388 | net->sctp.rto_min = new_value; | 388 | net->sctp.rto_min = new_value; |
389 | } | 389 | } |
390 | |||
390 | return ret; | 391 | return ret; |
391 | } | 392 | } |
392 | 393 | ||
@@ -395,11 +396,10 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, | |||
395 | loff_t *ppos) | 396 | loff_t *ppos) |
396 | { | 397 | { |
397 | struct net *net = current->nsproxy->net_ns; | 398 | struct net *net = current->nsproxy->net_ns; |
398 | int new_value; | ||
399 | struct ctl_table tbl; | ||
400 | unsigned int min = *(unsigned int *) ctl->extra1; | 399 | unsigned int min = *(unsigned int *) ctl->extra1; |
401 | unsigned int max = *(unsigned int *) ctl->extra2; | 400 | unsigned int max = *(unsigned int *) ctl->extra2; |
402 | int ret; | 401 | struct ctl_table tbl; |
402 | int ret, new_value; | ||
403 | 403 | ||
404 | memset(&tbl, 0, sizeof(struct ctl_table)); | 404 | memset(&tbl, 0, sizeof(struct ctl_table)); |
405 | tbl.maxlen = sizeof(unsigned int); | 405 | tbl.maxlen = sizeof(unsigned int); |
@@ -408,12 +408,15 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, | |||
408 | tbl.data = &new_value; | 408 | tbl.data = &new_value; |
409 | else | 409 | else |
410 | tbl.data = &net->sctp.rto_max; | 410 | tbl.data = &net->sctp.rto_max; |
411 | |||
411 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); | 412 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); |
412 | if (write) { | 413 | if (write && ret == 0) { |
413 | if (ret || new_value > max || new_value < min) | 414 | if (new_value > max || new_value < min) |
414 | return -EINVAL; | 415 | return -EINVAL; |
416 | |||
415 | net->sctp.rto_max = new_value; | 417 | net->sctp.rto_max = new_value; |
416 | } | 418 | } |
419 | |||
417 | return ret; | 420 | return ret; |
418 | } | 421 | } |
419 | 422 | ||