Bug 40012

Summary: PIO_UNIMAP bug: error updating Unicode-to-font map
Product: Drivers Reporter: Ivan (athlon_)
Component: Console/FramebuffersAssignee: James Simmons (jsimmons)
Status: CLOSED CODE_FIX    
Severity: normal CC: alan, cath_bugz, florian
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 3.0 Subsystem:
Regression: No Bisected commit-id:

Description Ivan 2011-07-25 17:56:13 UTC
There is an error in function con_set_unimap (file: linux-3.0/drivers/tty/vt/consolemap.c)

During the copying of the map variable l=<current unicode value> does not increment properly.
> for (i = 0, l = 0; i < 32; i++)
>                if ((p1 = p->uni_pgdir[i]))
>           ...
else (if p1 == NULL) its value will be left unchanged instead of += ...

Steps to reproduce:

1. fbdev driver should be used
2. Switch to virtual console 1 (Alt+F1)
3. Compile and run test1.c
4. Switch to virtual console 2 (Alt+F2)
5. Run test1.c
6. Compile and run test2.c

You will get something like

Current Unicode-to-font map
0x123   U+0001 // Should be U+0041
0x134   U+0042

----- test1.c -----
#define _GNU_SOURCE

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/kd.h>

int main(int argc, char *argv[])
{
struct unipair up = {0x0041, 0x0123};
struct unimapdesc ud = {1, &up};
int fd;
	
	fd = open("/dev/tty0", O_RDWR);
	if (fd < 0)
		err(1, "open");
	
	if (ioctl(fd, PIO_UNIMAPCLR, &ud) < 0)
		err(1, "ioctl(PIO_UNIMAPCLR)");
	
	if (ioctl(fd, PIO_UNIMAP, &ud) < 0)
		err(1, "ioctl(PIO_UNIMAP)");
	
	int i, ct;

	ud.entry_ct = 0;
	ud.entries = 0;
	if (ioctl(fd, GIO_UNIMAP, &ud) < 0 && errno != ENOMEM)
		err(1, "ioctl(GIO_UNIMAP)");
	
	ct = ud.entry_ct;
	ud.entries = (struct unipair *) malloc(ct * sizeof(struct unipair));
	if (ud.entries == NULL) { return -1; }
	
	if (ioctl(fd, GIO_UNIMAP, &ud) < 0)
		err(1, "ioctl(GIO_UNIMAP)");
	
	printf("Current Unicode-to-font map\n");
	for (i = 0; i < ud.entry_ct; i++)
		printf("0x%02x\tU+%04x\n", ud.entries[i].fontpos,
		                           ud.entries[i].unicode);
	
	close(fd);	
	
	return EXIT_SUCCESS;
}
----------
----- test2.c -----
#define _GNU_SOURCE

#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/kd.h>

int main(int argc, char *argv[])
{
struct unipair up = {0x0042, 0x0134};
struct unimapdesc ud = {1, &up};
int fd;
	
	fd = open("/dev/tty0", O_RDWR);
	if (fd < 0)
		err(1, "open");
	
	if (ioctl(fd, PIO_UNIMAP, &ud) < 0)
		err(1, "ioctl(PIO_UNIMAP)");
	
	int i, ct;

	ud.entry_ct = 0;
	ud.entries = 0;
	if (ioctl(fd, GIO_UNIMAP, &ud) < 0 && errno != ENOMEM)
		err(1, "ioctl(GIO_UNIMAP)");
	
	ct = ud.entry_ct;
	ud.entries = (struct unipair *) malloc(ct * sizeof(struct unipair));
	if (ud.entries == NULL) { return -1; }
	
	if (ioctl(fd, GIO_UNIMAP, &ud) < 0)
		err(1, "ioctl(GIO_UNIMAP)");
	
	printf("Current Unicode-to-font map\n");
	for (i = 0; i < ud.entry_ct; i++)
		printf("0x%02x\tU+%04x\n", ud.entries[i].fontpos,
		                           ud.entries[i].unicode);
	
	close(fd);	
	
	return EXIT_SUCCESS;
}
----------
Comment 1 Florian Mickler 2012-04-04 14:57:15 UTC
A patch referencing this bug report has been merged in Linux v3.4-rc1:

commit 4a4c61b7ce26bfc9d49ea4bd121d52114bad9f99
Author: Liz Clark <liz.clark@hp.com>
Date:   Thu Mar 15 10:33:29 2012 -0700

    TTY: Wrong unicode value copied in con_set_unimap()