Commit 9d7203a1946813100a0623289df8c2bbbe832831

Authored by Liz Clark
Committed by Greg Kroah-Hartman
1 parent 676ba41781

TTY: Wrong unicode value copied in con_set_unimap()

commit 4a4c61b7ce26bfc9d49ea4bd121d52114bad9f99 upstream.

Bugzilla 40012: PIO_UNIMAP bug: error updating Unicode-to-font map
https://bugzilla.kernel.org/show_bug.cgi?id=40012

The unicode font map for the virtual console is a 32x32x64 table which
allocates rows dynamically as entries are added.  The unicode value
increases sequentially and should count all entries even in empty
rows.  The defect is when copying the unicode font map in con_set_unimap(),
the unicode value is not incremented properly.  The wrong unicode value
is entered in the new font map.

Signed-off-by: Liz Clark <liz.clark@hp.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 1 changed file with 43 additions and 8 deletions Side-by-side Diff

drivers/tty/vt/consolemap.c
... ... @@ -516,6 +516,7 @@
516 516 int err = 0, err1, i;
517 517 struct uni_pagedir *p, *q;
518 518  
  519 + /* Save original vc_unipagdir_loc in case we allocate a new one */
519 520 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
520 521 if (p->readonly) return -EIO;
521 522  
522 523  
523 524  
524 525  
525 526  
526 527  
527 528  
... ... @@ -528,26 +529,57 @@
528 529 err1 = con_clear_unimap(vc, NULL);
529 530 if (err1) return err1;
530 531  
  532 + /*
  533 + * Since refcount was > 1, con_clear_unimap() allocated a
  534 + * a new uni_pagedir for this vc. Re: p != q
  535 + */
531 536 q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
532   - for (i = 0, l = 0; i < 32; i++)
  537 +
  538 + /*
  539 + * uni_pgdir is a 32*32*64 table with rows allocated
  540 + * when its first entry is added. The unicode value must
  541 + * still be incremented for empty rows. We are copying
  542 + * entries from "p" (old) to "q" (new).
  543 + */
  544 + l = 0; /* unicode value */
  545 + for (i = 0; i < 32; i++)
533 546 if ((p1 = p->uni_pgdir[i]))
534 547 for (j = 0; j < 32; j++)
535   - if ((p2 = p1[j]))
  548 + if ((p2 = p1[j])) {
536 549 for (k = 0; k < 64; k++, l++)
537 550 if (p2[k] != 0xffff) {
  551 + /*
  552 + * Found one, copy entry for unicode
  553 + * l with fontpos value p2[k].
  554 + */
538 555 err1 = con_insert_unipair(q, l, p2[k]);
539 556 if (err1) {
540 557 p->refcount++;
541 558 *vc->vc_uni_pagedir_loc = (unsigned long)p;
542 559 con_release_unimap(q);
543 560 kfree(q);
544   - return err1;
  561 + return err1;
545 562 }
546   - }
547   - p = q;
548   - } else if (p == dflt)
  563 + }
  564 + } else {
  565 + /* Account for row of 64 empty entries */
  566 + l += 64;
  567 + }
  568 + else
  569 + /* Account for empty table */
  570 + l += 32 * 64;
  571 +
  572 + /*
  573 + * Finished copying font table, set vc_uni_pagedir to new table
  574 + */
  575 + p = q;
  576 + } else if (p == dflt) {
549 577 dflt = NULL;
550   -
  578 + }
  579 +
  580 + /*
  581 + * Insert user specified unicode pairs into new table.
  582 + */
551 583 while (ct--) {
552 584 unsigned short unicode, fontpos;
553 585 __get_user(unicode, &list->unicode);
554 586  
... ... @@ -557,11 +589,14 @@
557 589 list++;
558 590 }
559 591  
  592 + /*
  593 + * Merge with fontmaps of any other virtual consoles.
  594 + */
560 595 if (con_unify_unimap(vc, p))
561 596 return err;
562 597  
563 598 for (i = 0; i <= 3; i++)
564   - set_inverse_transl(vc, p, i); /* Update all inverse translations */
  599 + set_inverse_transl(vc, p, i); /* Update inverse translations */
565 600 set_inverse_trans_unicode(vc, p);
566 601  
567 602 return err;