aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/vt
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2012-02-24 07:47:11 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-02-24 16:59:34 -0500
commit247ff8e610cb63c015de19191db9666754c2ed79 (patch)
treee4d097c10c6211ff05f9d8ec6669c584de9e08ae /drivers/tty/vt
parentce1000ddca01c81684da844be4676eac50a70c2a (diff)
vt: lock the accent table
First step to debletcherising the vt console layer - pick a victim and fix the locking This is a nice simple object with its own rules so lets pick it out for treatment. The user of the table already has a lock so we will also use the same lock for updates. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r--drivers/tty/vt/keyboard.c162
-rw-r--r--drivers/tty/vt/vt_ioctl.c81
2 files changed, 165 insertions, 78 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index a605549ee28f..bdf838dd3e44 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -1452,3 +1452,165 @@ int __init kbd_init(void)
1452 1452
1453 return 0; 1453 return 0;
1454} 1454}
1455
1456/* Ioctl support code */
1457
1458/**
1459 * vt_do_diacrit - diacritical table updates
1460 * @cmd: ioctl request
1461 * @up: pointer to user data for ioctl
1462 * @perm: permissions check computed by caller
1463 *
1464 * Update the diacritical tables atomically and safely. Lock them
1465 * against simultaneous keypresses
1466 */
1467int vt_do_diacrit(unsigned int cmd, void __user *up, int perm)
1468{
1469 struct kbdiacrs __user *a = up;
1470 unsigned long flags;
1471 int asize;
1472 int ret = 0;
1473
1474 switch (cmd) {
1475 case KDGKBDIACR:
1476 {
1477 struct kbdiacr *diacr;
1478 int i;
1479
1480 diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr),
1481 GFP_KERNEL);
1482 if (diacr == NULL)
1483 return -ENOMEM;
1484
1485 /* Lock the diacriticals table, make a copy and then
1486 copy it after we unlock */
1487 spin_lock_irqsave(&kbd_event_lock, flags);
1488
1489 asize = accent_table_size;
1490 for (i = 0; i < asize; i++) {
1491 diacr[i].diacr = conv_uni_to_8bit(
1492 accent_table[i].diacr);
1493 diacr[i].base = conv_uni_to_8bit(
1494 accent_table[i].base);
1495 diacr[i].result = conv_uni_to_8bit(
1496 accent_table[i].result);
1497 }
1498 spin_unlock_irqrestore(&kbd_event_lock, flags);
1499
1500 if (put_user(asize, &a->kb_cnt))
1501 ret = -EFAULT;
1502 else if (copy_to_user(a->kbdiacr, diacr,
1503 asize * sizeof(struct kbdiacr)))
1504 ret = -EFAULT;
1505 kfree(diacr);
1506 return ret;
1507 }
1508 case KDGKBDIACRUC:
1509 {
1510 struct kbdiacrsuc __user *a = up;
1511 void *buf;
1512
1513 buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc),
1514 GFP_KERNEL);
1515 if (buf == NULL)
1516 return -ENOMEM;
1517
1518 /* Lock the diacriticals table, make a copy and then
1519 copy it after we unlock */
1520 spin_lock_irqsave(&kbd_event_lock, flags);
1521
1522 asize = accent_table_size;
1523 memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc));
1524
1525 spin_unlock_irqrestore(&kbd_event_lock, flags);
1526
1527 if (put_user(asize, &a->kb_cnt))
1528 ret = -EFAULT;
1529 else if (copy_to_user(a->kbdiacruc, buf,
1530 asize*sizeof(struct kbdiacruc)))
1531 ret = -EFAULT;
1532 kfree(buf);
1533 return ret;
1534 }
1535
1536 case KDSKBDIACR:
1537 {
1538 struct kbdiacrs __user *a = up;
1539 struct kbdiacr *diacr = NULL;
1540 unsigned int ct;
1541 int i;
1542
1543 if (!perm)
1544 return -EPERM;
1545 if (get_user(ct, &a->kb_cnt))
1546 return -EFAULT;
1547 if (ct >= MAX_DIACR)
1548 return -EINVAL;
1549
1550 if (ct) {
1551 diacr = kmalloc(sizeof(struct kbdiacr) * ct,
1552 GFP_KERNEL);
1553 if (diacr == NULL)
1554 return -ENOMEM;
1555
1556 if (copy_from_user(diacr, a->kbdiacr,
1557 sizeof(struct kbdiacr) * ct)) {
1558 kfree(diacr);
1559 return -EFAULT;
1560 }
1561 }
1562
1563 spin_lock_irqsave(&kbd_event_lock, flags);
1564 accent_table_size = ct;
1565 for (i = 0; i < ct; i++) {
1566 accent_table[i].diacr =
1567 conv_8bit_to_uni(diacr[i].diacr);
1568 accent_table[i].base =
1569 conv_8bit_to_uni(diacr[i].base);
1570 accent_table[i].result =
1571 conv_8bit_to_uni(diacr[i].result);
1572 }
1573 spin_unlock_irqrestore(&kbd_event_lock, flags);
1574 kfree(diacr);
1575 return 0;
1576 }
1577
1578 case KDSKBDIACRUC:
1579 {
1580 struct kbdiacrsuc __user *a = up;
1581 unsigned int ct;
1582 void *buf = NULL;
1583
1584 if (!perm)
1585 return -EPERM;
1586
1587 if (get_user(ct, &a->kb_cnt))
1588 return -EFAULT;
1589
1590 if (ct >= MAX_DIACR)
1591 return -EINVAL;
1592
1593 if (ct) {
1594 buf = kmalloc(ct * sizeof(struct kbdiacruc),
1595 GFP_KERNEL);
1596 if (buf == NULL)
1597 return -ENOMEM;
1598
1599 if (copy_from_user(buf, a->kbdiacruc,
1600 ct * sizeof(struct kbdiacruc))) {
1601 kfree(buf);
1602 return -EFAULT;
1603 }
1604 }
1605 spin_lock_irqsave(&kbd_event_lock, flags);
1606 if (ct)
1607 memcpy(accent_table, buf,
1608 ct * sizeof(struct kbdiacruc));
1609 accent_table_size = ct;
1610 spin_unlock_irqrestore(&kbd_event_lock, flags);
1611 kfree(buf);
1612 return 0;
1613 }
1614 }
1615 return ret;
1616}
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 65447c5f91d7..80af0f9bef5b 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -753,89 +753,14 @@ int vt_ioctl(struct tty_struct *tty,
753 ret = do_kdgkb_ioctl(cmd, up, perm); 753 ret = do_kdgkb_ioctl(cmd, up, perm);
754 break; 754 break;
755 755
756 /* Diacritical processing. Handled in keyboard.c as it has
757 to operate on the keyboard locks and structures */
756 case KDGKBDIACR: 758 case KDGKBDIACR:
757 {
758 struct kbdiacrs __user *a = up;
759 struct kbdiacr diacr;
760 int i;
761
762 if (put_user(accent_table_size, &a->kb_cnt)) {
763 ret = -EFAULT;
764 break;
765 }
766 for (i = 0; i < accent_table_size; i++) {
767 diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
768 diacr.base = conv_uni_to_8bit(accent_table[i].base);
769 diacr.result = conv_uni_to_8bit(accent_table[i].result);
770 if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
771 ret = -EFAULT;
772 break;
773 }
774 }
775 break;
776 }
777 case KDGKBDIACRUC: 759 case KDGKBDIACRUC:
778 {
779 struct kbdiacrsuc __user *a = up;
780
781 if (put_user(accent_table_size, &a->kb_cnt))
782 ret = -EFAULT;
783 else if (copy_to_user(a->kbdiacruc, accent_table,
784 accent_table_size*sizeof(struct kbdiacruc)))
785 ret = -EFAULT;
786 break;
787 }
788
789 case KDSKBDIACR: 760 case KDSKBDIACR:
790 {
791 struct kbdiacrs __user *a = up;
792 struct kbdiacr diacr;
793 unsigned int ct;
794 int i;
795
796 if (!perm)
797 goto eperm;
798 if (get_user(ct,&a->kb_cnt)) {
799 ret = -EFAULT;
800 break;
801 }
802 if (ct >= MAX_DIACR) {
803 ret = -EINVAL;
804 break;
805 }
806 accent_table_size = ct;
807 for (i = 0; i < ct; i++) {
808 if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
809 ret = -EFAULT;
810 break;
811 }
812 accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
813 accent_table[i].base = conv_8bit_to_uni(diacr.base);
814 accent_table[i].result = conv_8bit_to_uni(diacr.result);
815 }
816 break;
817 }
818
819 case KDSKBDIACRUC: 761 case KDSKBDIACRUC:
820 { 762 ret = vt_do_diacrit(cmd, up, perm);
821 struct kbdiacrsuc __user *a = up;
822 unsigned int ct;
823
824 if (!perm)
825 goto eperm;
826 if (get_user(ct,&a->kb_cnt)) {
827 ret = -EFAULT;
828 break;
829 }
830 if (ct >= MAX_DIACR) {
831 ret = -EINVAL;
832 break;
833 }
834 accent_table_size = ct;
835 if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
836 ret = -EFAULT;
837 break; 763 break;
838 }
839 764
840 /* the ioctls below read/set the flags usually shown in the leds */ 765 /* the ioctls below read/set the flags usually shown in the leds */
841 /* don't use them - they will go away without warning */ 766 /* don't use them - they will go away without warning */