Commit 31efcebb7d7196adcee73027f513d7c0bf572b47
Committed by
Richard Weinberger
1 parent
d8c215adbf
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
um: fix races between line_open() and line_config()
Pull parse_chan_pair() call into setup_one_line(), under the mutex. We really don't want open() to succeed before parse_chan_pair() had been done (or after it has failed, BTW). We also want "remove con<n>" to free irqs, etc., same as "config con<n>=none". Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Richard Weinberger <richard@nod.at>
Showing 2 changed files with 29 additions and 28 deletions Side-by-side Diff
arch/um/drivers/chan_kern.c
arch/um/drivers/line.c
... | ... | @@ -482,7 +482,7 @@ |
482 | 482 | } |
483 | 483 | |
484 | 484 | static int setup_one_line(struct line *lines, int n, char *init, |
485 | - char **error_out) | |
485 | + const struct chan_opts *opts, char **error_out) | |
486 | 486 | { |
487 | 487 | struct line *line = &lines[n]; |
488 | 488 | int err = -EINVAL; |
489 | 489 | |
490 | 490 | |
... | ... | @@ -494,13 +494,28 @@ |
494 | 494 | goto out; |
495 | 495 | } |
496 | 496 | |
497 | - if (!strcmp(init, "none")) | |
498 | - line->valid = 0; | |
499 | - else { | |
500 | - line->init_str = init; | |
497 | + if (!strcmp(init, "none")) { | |
498 | + if (line->valid) { | |
499 | + line->valid = 0; | |
500 | + kfree(line->init_str); | |
501 | + parse_chan_pair(NULL, line, n, opts, error_out); | |
502 | + err = 0; | |
503 | + } | |
504 | + } else { | |
505 | + char *new = kstrdup(init, GFP_KERNEL); | |
506 | + if (!new) { | |
507 | + *error_out = "Failed to allocate memory"; | |
508 | + return -ENOMEM; | |
509 | + } | |
510 | + line->init_str = new; | |
501 | 511 | line->valid = 1; |
512 | + err = parse_chan_pair(new, line, n, opts, error_out); | |
513 | + if (err) { | |
514 | + line->init_str = NULL; | |
515 | + line->valid = 0; | |
516 | + kfree(new); | |
517 | + } | |
502 | 518 | } |
503 | - err = 0; | |
504 | 519 | out: |
505 | 520 | mutex_unlock(&line->count_lock); |
506 | 521 | return err; |
507 | 522 | |
... | ... | @@ -549,10 +564,8 @@ |
549 | 564 | int line_config(struct line *lines, unsigned int num, char *str, |
550 | 565 | const struct chan_opts *opts, char **error_out) |
551 | 566 | { |
552 | - struct line *line; | |
553 | - char *new; | |
554 | 567 | char *end; |
555 | - int n, err; | |
568 | + int n; | |
556 | 569 | |
557 | 570 | if (*str == '=') { |
558 | 571 | *error_out = "Can't configure all devices from mconsole"; |
... | ... | @@ -569,16 +582,7 @@ |
569 | 582 | return -EINVAL; |
570 | 583 | } |
571 | 584 | |
572 | - new = kstrdup(end, GFP_KERNEL); | |
573 | - if (new == NULL) { | |
574 | - *error_out = "Failed to allocate memory"; | |
575 | - return -ENOMEM; | |
576 | - } | |
577 | - err = setup_one_line(lines, n, new, error_out); | |
578 | - if (err) | |
579 | - return err; | |
580 | - line = &lines[n]; | |
581 | - return parse_chan_pair(line->init_str, line, n, opts, error_out); | |
585 | + return setup_one_line(lines, n, end, opts, error_out); | |
582 | 586 | } |
583 | 587 | |
584 | 588 | int line_get_config(char *name, struct line *lines, unsigned int num, char *str, |
... | ... | @@ -633,7 +637,7 @@ |
633 | 637 | *error_out = "Device number out of range"; |
634 | 638 | return -EINVAL; |
635 | 639 | } |
636 | - return setup_one_line(lines, n, "none", error_out); | |
640 | + return setup_one_line(lines, n, "none", NULL, error_out); | |
637 | 641 | } |
638 | 642 | |
639 | 643 | struct tty_driver *register_lines(struct line_driver *line_driver, |
640 | 644 | |
... | ... | @@ -688,15 +692,9 @@ |
688 | 692 | if (line->init_str == NULL) |
689 | 693 | continue; |
690 | 694 | |
691 | - line->init_str = kstrdup(line->init_str, GFP_KERNEL); | |
692 | - if (line->init_str == NULL) | |
693 | - printk(KERN_ERR "lines_init - kstrdup returned NULL\n"); | |
694 | - | |
695 | - if (parse_chan_pair(line->init_str, line, i, opts, &error)) { | |
696 | - printk(KERN_ERR "parse_chan_pair failed for " | |
695 | + if (setup_one_line(lines, i, line->init_str, opts, &error)) | |
696 | + printk(KERN_ERR "setup_one_line failed for " | |
697 | 697 | "device %d : %s\n", i, error); |
698 | - line->valid = 0; | |
699 | - } | |
700 | 698 | } |
701 | 699 | } |
702 | 700 |