Summary
CVE | CVE-2014-1444 |
---|---|
Author | Salva Peiró |
Date | October 2013 - Discovery of the vulnerability. |
Impact | The vulnerability discloses 2 bytes of kernel process stack. |
Affected Versions | From Linux-2.6.12-rc2 to linux-3.15-rc3 |
Bug Timespan | 8.5 years: 2005-04-16 to 2013-10-14 commit 1da177e4 |
InfoLeak Description
The fst_get_iface() code fails to initialize the two padding bytes of struct sync_serial_settings after the ->loopback field. Add an explicit memset(0) before filling the structure to avoid the info leak.
Analysis of the Leak Code
The code of fs_get_iface()
is annotated above with the interesting steps:
- [1] The analysis of the struct layout shows a two byte hole.
- [2] The
sync
struct is allocated on the stack. - [3] The contents of the
sync struct
are filled. - [4] The contents of the
sync struct
are copied to user.
/* From from #include <linux/hdlc/ioctl.h> */ struct sync_serial_settings { unsigned int clock_rate; unsigned int clock_type; unsigned short loopback; // [1] 2-byte hole from [10-12] }; /* From linux/drivers/net/wan/farsync.c */ 1986 static int 1987 fst_get_iface(struct fst_card_info *card, struct fst_port_info *port, 1988 struct ifreq *ifr) 1989 { 1990 sync_serial_settings sync; // [2] 2001 int i; /* ... */ 2027 i = port->index; 2028 sync.clock_rate = FST_RDL(card, portConfig[i].lineSpeed); // [3] 2029 /* Lucky card and linux use same encoding here */ 2030 sync.clock_type = FST_RDB(card, portConfig[i].internalClock) == 2031 INTCLK ? CLOCK_INT : CLOCK_EXT; 2032 sync.loopback = 0; 2033 2034 if (copy_to_user(ifr->ifr_settings.ifs_ifsu.sync, &sync, sizeof (sync))) { // [4] 2035 return -EFAULT; 2036 } /* ... */ 2040 }
Analysis of the Leak
To check if fst_get_iface() initialise the two byte hole at the end of
sync_serial_settings sync, We verify that the assembly emitted by the compiler
performs the initialisation of the sync.loopback = 0.
The listing shows that sync.loopback is filled at [5]
using a movw
of 2-byte word that leaves the 2-bytes uninitalised and leaking data.
8132eeb0 <fst_get_iface>: 8132eeb0: 55 push %ebp 8132eeb1: 89 e5 mov %esp,%ebp 8132eeb3: 56 push %esi 8132eeb4: 53 push %ebx 8132eeb5: 8d 19 lea (%ecx),%ebx 8132eeb7: 8d 64 24 f4 lea -0xc(%esp),%esp ... 8132ef0b: 8d 55 ec lea -0x14(%ebp),%edx 8132ef0e: 0f b6 c0 movzbl %al,%eax 8132ef11: 66 c7 45 f4 00 00 movw $0x0,-0xc(%ebp) /* [5] sync.loopback=0 */ 8132ef17: 83 c0 01 add $0x1,%eax 8132ef1a: 89 45 f0 mov %eax,-0x10(%ebp) 8132ef1d: 8b 43 18 mov 0x18(%ebx),%eax 8132ef20: e8 5b 7d f3 ff call 81266c80 <copy_to_user>
Fixing the Infoleak
Based on the analysis performed a small patch has been prepared that adds
an explicit memset(0) before filling the structure to avoid the info leak.
Closer analysis revealed this infoleak occurring at other places
that used struct sync_serial_settings
, as a result,
patches fixing the infoleak are pushed upstream to the Linux Kernel: