Dissecting QNXJos Wetzels1,2,3 , Ali Abbasi3,41

Midnight Blue
Eindhoven University of Technology (TU/e)
3
University of Twente (UT)
4
Ruhr-University Bochum (RUB)
2

T

his work concerns a dissection of QNX: a proprietary, real-time operating system aimed
at the embedded market. QNX is used inmany sensitive and critical devices in different industry verticals and while some prior security research has discussed QNX, mainly as a byproductof BlackBerry mobile research, there is no priorwork on QNX exploit mitigations and secure random number generators. In this work, carried out
as part of the master’s thesis of the first author, we
present the first reverse-engineering and analysisof the exploit mitigations, secure random number
generators and memory management internals of
QNX versions up to and including QNX 6.6 and thebrand new 64-bit QNX 7.0 released in March 2017.
We uncover a variety of design issues and vulnerabilities which have significant implications for the
exploitability of memory corruption vulnerabilities
on QNX as well as the strength of its cryptographic
ecosystem.

1

Introduction

QNX [17] is a proprietary, closed-source, Unix-likereal-time operating system with POSIX support aimed
primarily at the embedded market. Initially released
in 1982 for the Intel 8088 and later acquired byBlackBerry, it forms the basis of BlackBerry OS,
BlackBerry Tablet OS and BlackBerry 10 used in
mobile devices as well as forming the basis of Cisco’s
IOS-XR used in carrier-grade routers such as the
CRS, the 12000 and the ASR9000 series. QNX also
dominates the automotive market [61] (particularly
telematics, infotainment and navigation systems) andis found in millions of cars from Audi, Toyota, BMW,
Porsche, Honda and Ford to Jaguar and Lincoln. In

addition, it is deployed in highly sensitive embedded
systems such as industrial automation PLCs, medical
devices, building management systems, railway
safety equipment, Unmanned Aerial Vehicles (UAVs),anti-tank weapons guidance systems, the Harris
Falcon III military radios, Caterpillar mining control
systems, General Electric turbine control systems andWestinghouse and AECL nuclear powerplants.
The interest of high-profile actors in QNX-based
systems is evidenced by a series of documents fromthe United States Central Intelligence Agency (CIA)obtained and released by WikiLeaks under the name
’Vault 7’. These documents show an interest on partof the CIA’s Embedded Development Branch (EDB) of
the Engineering Development Group (EDG) (whichdevelops and tests exploits and malware used in covert
operations) in targeting QNX [65].
In this work, we focus primarily on QNX’s ’binary
security’ ie. its hardening against memory corruption
exploitation, as well as the quality of its secure random
number generators.
More precisely, this work makes the following novel
contributions:• It presents the first reverse-engineering of the
proprietary, closed-source QNX OS to document
the internals of its memory manager, exploit
mitigations (eg. NX memory, ASLR, stack canaries,
RELRO) and secure random number generators(both the kernel PRNG and /dev/random),covering all QNX versions as of writing (ie. ≤ 6.6
and the newly released QNX 7.0).
• It presents the first analysis of the exploit

Dissecting QNX

mitigations and secure RNGs on QNX ≤ 6.6 and7.0 and uncovers a variety of design issues andvulnerabilities which have significant implications
for the exploitability of memory corruption
vulnerabilities on QNX as well as the strength of
its cryptographic ecosystem.
• As a result of this work, we disclosed the uncovered issues to the vendor and cooperated indrafting patches to help protect system end-users.
Given that there is, as discussed in Section 2.1,
no prior work on QNX’s mitigations, secure random number generators or memory management
internals, we consider this work a significant contribution to the state of the art in understanding
QNX security as well as QNX OS internals more broadly.
In Section 2 we present an brief overview of QNX’s
OS architecture, its security architecture and its memory management internals. We discuss the result of ourreverse-engineering and analysis of the exploit mitigations of QNX versions up to and including 6.6 in Section
3 and those of QNX version 7.0 in Section 4. In Section
5 we present the results of our reverse-engineering andanalysis of the secure random number generators of
QNX versions ≤ 6.6 and 7.0. Finally, in Section 6 we
present our concluding remarks.

for hundreds of POSIX utilities, common networking
technologies (IPv4/IPv6, IPSec, FTP, HTTP, SSH,etc.) and dynamic libraries. As opposed to themonolithic kernel architecture of most general-purpose
OSes, QNX features a microkernel which provides
minimal services (eg. system call and interrupt
handling, task scheduling, IPC message-passing, etc.)
to the rest of the operating system which runs as
a team of cooperating processes as illustrated in
Figure 1. As a result, only the microkernel resides
in kernelspace with the rest of the operating systemand other typical kernel-level functionality (drivers,
protocol stacks, etc.) residing in userspace next toregular user applications albeit separated by privilege
boundaries. In QNX the microkernel is combined withthe process manager in a single executable module
called procnto. QNX libc converts POSIX function
calls into message handling functions which passmessages through the microkernel to the relevant process. As of writing, the latest QNX release is version 7.0.

Process
M anager

PS FileM anager

QNX Overview

2.1

Security History

Most of the relatively scarce public research available
on QNX security has been the byproduct of research
into BlackBerry’s QNX-based mobile operating systems
such as Tablet OS, BlackBerry OS and BlackBerry
10 [3, 13–15, 66] most of which has not focussed on
QNX itself. Recent work by Plaskett et al. [1, 42] has
focussed on QNX itself, particularly security of the InterProcess Communication (IPC), message passing andPersistent Publish Subscribe (PPS) interfaces as wellas kernel security through system call fuzzing. Whenit comes to specific vulnerabilities the work done by
Julio Cesar Fort [27] and Tim Brown [19] stands out inparticular and the MITRE CVE database [25] reports,
as of writing, 34 vulnerabilities most of which are setuid
logic bugs or memory corruption vulnerabilities.

2.2

OS Architecture

QNX supports a wide range of CPU architecturesand features a pre-emptible microkernel architecture with multi-core support ensuring virtually any
component (even core OS components and drivers)
can fail without bringing down the kernel. QNX
itself has a small footprint but support is available

U DF File
M anager

N FS File
M anagerFlash File
M anagerQ N X N eutrino
M icrokernel
Software Bus

Character
M anager

GU I
M anager
Application

2

H FS File
M anager

M queue
M anager

Application

CI FS File
M anager

N etwork
M anager

Figure 1: QNX Microkernel Architecture [60]Most elements of the QNX system architecture (suchas the messaging layer, process & resource management, filesystem and networking functionality, etc.)
are well described in prior work [42] and since thiswork focuses on memory corruption we will only discuss QNX memory management and the security architecture in ’broad strokes’.

2.3

Security Architecture

As a Unix-like operating system QNX inherits a largepart of the Unix security model, primarily in theform of user groups and associated permission-based
access controls. QNX is certified to Common Criteria
ISO/IEC 15408 Evaluation Assurance Level (EAL) 4+.
The certification report [21] indicates that the Target
of Evaluation (TOE) boundary encompasses only the
procnto system process (ie. the microkernel andprocess manager) and libc.
QNX features a strong separation between kerneland userspace running everything except for the
microkernel and process manager in kernelspaceby assigning it to the procnto process which runs
as root with PID 1. Other OS components run as
Page 2 of 22

Dissecting QNX

their own root processes in userspace next to non-OS
processes. Separation between OS processes andnon-OS processes comes down to a combinationof enforcement of user permissions and additional
sandboxing capabilities [54]. If a non-OS process
is run as root, the only way to wall it off from thewider OS is by restricting its capabilities. On the other
hand, capabilities can be assigned on a granular level
allowing or disallowing access to system actions andresources meaning for many processes there is no needto run as root to perform their functionality. Security
separation between userspace and kernelspace isalso mediated in this fashion which does mean,
however, that there is no ’absolute isolation’ of the
microkernel and a root user without significant
capability restrictions (as is the default for most OS
processes) can easily pivot into the microkernel bymeans of common kernel calls, access to sensitive
devices (eg. /dev/mem) or installation of Interrupt
Service Routines (ISRs).
As such one should not confuse the safety guaranteethat the crashing of one component does not lead toa crash of the entire system with a security guaranteethat the compromise of one component could not leadto the compromise of the entire system. If no explicit
capability restrictions are put in place by system integrators, nothing prevents a compromise of a processwith the right privileges or capabilities from leading toarbitrary kernelspace code execution.

2.4

Memory Management

QNX offers a full-protection memory model placing
each process within its own private virtual memory byutilizing the MMU as shown in Figure 2. On QNX every
process is created with at least one main thread (with
its own, OS-supplied stack) and any subsequently
created thread can either be given a customly allocatedstack by the program or a (default) system-allocatedstack for that thread. QNX’s virtual memory provides
permission capabilities and the memory manager
ensures inter-process memory access is mediatedby privilege as well as capability checks [54]. QNX
handles typical memory objects such as stacks, theheap, object memory (eg. video card memory mapped
into userspace), shared libraries, etc. and has support
for shared- and typed memory [57, 59]. The relevant
memory manager internals are described in detail in
Section 3.2.
For QNX versions up to and including 7.0, we illustrate QNX user- and kernel-space address boundaries,
derived from reverse-engineering, in Tables 1 and 2.
On QNX systems where ASLR is not enabled, libc
is loaded by default at the addresses illustrated inTable 3. For QNX versions up to and including 6.6
on x86, the default user- and kernel-space layouts
when ASLR is disabled are illustrated in Figures 3 and 4

U ser Process 1

U ser Process 2

U ser Process 3

System Processprocnto

0

3.5G

0

3.5G

0

3.5G

3.5G

4G

Figure 2: QNX Private Virtual Memory [53]Architecture
Userspace
x86
AArch32MIPS
PPC
SuperH
Kernelspace
x86
AArch32MIPS
PPC
SuperH

Start

End

0x00000000
0x00000000
0x00000000
0x40000000
0x00000000

0xBFFFFFFF
0x7FFFFFFF
0x7FFFFFFF
0xFFFB0000
0x7BFF0000

0xC0000000
0x80000000
0x80000000
0x00000000
0x80000000

0xFFFFFFFF
0xFFFFFFFF
0xFFFFFFFF
0x3FFFFFFF
0xCFFFFFFF

Table 1: QNX ≤ 6.6 Address Boundaries

Architecture
Userspacex86
x86-64
AArch32
AArch64
Kernelspace
x86
x86-64
AArch32
AArch64

Start

End

0x00000000
0x00000000
0x00000000
0x00000000

0xBFFFFFFF
0x0000007FFFFFFFFF
0x7FFFFFFF
0x0000007FFFFFFFFF

0xC0000000
0x0000008000000000
0x80000000
0x0000008000000000

0xFFFFFFFF
0xFFFFFFFFFFFFFFFF
0xFFFFFFFF
0xFFFFFFFFFFFFFFFF

Table 2: QNX 7.0 Address Boundaries

Architecture
QNX ≤ 6.6x86
AArch32MIPS
PPC
SuperHQNX 7.0x86
x86-64
AArch32
AArch64

Libc Addr.

0xB0300000
0x01000000
0x70300000
0xFE300000
0x70300000
0xB0300000
0x0000000100000000
0x01000000
0x0000000100000000

Table 3: QNX Default Libc Load Addresses

Page 3 of 22

Dissecting QNX(...)

0xBFFFFFFF

shared libraries
0xB0300000(...)
shared objects
0x40100000
(...)
heap
(...)
.bss
.data
.text
program image
0x08048000
thread stack 1(...)
thread stack n

generator as they are implemented in QNX versions up
to and including 6.6. QNX supports a variety of exploit
mitigations as outlined in Table 4 and the compilerand linker parts of these mitigations rely on the factthat the QNX Compile Command (QCC) uses GCC as its
back-end [16]. On the operating system side of things,
however, the mitigation implementations are heavily
customized as we will see in this section.
We can also see from Table 4 that while basic mitigations (ESP, ASLR, SSP, RELRO) are supported, this is
not the case for more modern ones (eg. CFI, Kernel
Data & Code Isolation, etc.) which are becoming
the norm in general purpose operating systems such as
Windows or Linux. While some of these mitigations(eg. CFI, CPI, Vtable Protection) are mostly implemented in the compiler and several libraries, it is currently not clear to what degree they are (in)compatible
with QNX’s design.

(...)
systemMitigation
ESP
ASLR
SSP
RELRO
NULL-deref Protection
Vtable Protection
CFI
CPI
Kernel Data Isolation2
Kernel Code Isolation3

0x00000000

Figure 3: QNX ≤ 6.6 Userspace Memory Layout (x86)(...)
L1 pagetable
map to self
syspage, GDT ,FPU stub, etc.
Startupallocations

0xFFFFFFFF

0xFFC00000

normal kernel
mapping
temp. map tozero L2
pagetables
message pass
temp. map

Default
×
×
×1
×1
n/a
n/a
n/a
n/a
n/a
n/a

0xFEC00000

0xF0000000

We disclosed all discovered issues to the vendor andas a result fixes and improvements based on our suggestions were included in QNX 7.0 as documented in
Section ??.

0xE0000000

3.1

0xD0400000

0xD0000000

0xC0000000

Figure 4: QNX ≤ 6.6 Kernelspace Memory Layout (x86)

3

Since
6.3.2
6.5
6.5
6.5
n/a
n/a
n/a
n/a
n/a
n/a

Table 4: QNX ≤ 6.6 Exploit Mitigation Overview
Default QNX Momentics IDE Settings, 2 eg. UDEREF / SMAP/ PAN, 3 eg. KERNEXEC / SMEP / PXN

0xFF400000

normal kernel
mapping OR
4m pagetablefor kernel code
& datafirst 256M ofphys. mem

Support
X
X
X
X
×
×
×
×
×
×

QNX ≤ 6.6 Exploit Mitigations

In this section we will present the results of ourreverse-engineering and subsequent analysis of
QNX’s exploit mitigations and secure random number

1

Executable Space Protection

Executable Space Protection (ESP), also referred
to as Data Execution Prevention (DEP), NX memoryor WˆX memory, is a mitigation that seeks to prevent
attackers from executing arbitrary injected payloads
through a Harvard-style code and data memory
separation on Von Neumann processors by rendering
data memory non-executable and ensuring code
memory is non-writable. ESP can be implemented byeither relying on hardware support (eg. the x86 NX
bit or ARM XN bit) or by means of software emulation.
QNX has support for hardware-facilitated ESP among
most of the architectures which support it since version
6.3.2 as shown in Table 5.
Insecure ESP Default Policy (CVE-2017-XXXX):
While QNX supports ESP for several architectures, its
Page 4 of 22

Dissecting QNX

Architecture
x86
ARM
MIPS
PPC 400
PPC 600
PPC 900

SupportX(requires PAE on IA-32e)
X
×
X
X
X

Table 5: QNX ≤ 6.6 Hardware ESP Support

implementation is dangerously weakened due to insecure default settings. As a result, the stack (but not theheap) is always executable regardless of the presenceof hardware ESP support. As the documentation [55]states, the QNX microkernel, and process manager executable (procnto) has a memory management startup
option relating to stack executability (available as of
QNX 6.4.0 or later):• -mx: (Default) Enable the PROT_EXEC flag forsystem-allocated threads (the default). This
option allows gcc to generate code on the stack which it does when taking the address of a nested
function (a GCC extension).
• -m˜x: Turn off PROT_EXEC for system-allocatedstacks, which increases security but disallows taking the address of nested functions. You canstill do this on a case-by-case basis by doing an
mprotect() call that turns on PROT_EXEC for therequired stacks.
Since the first option is the default, any QNX system
which starts procnto without explicit -m˜x settings
will have an executable stack, regardless of hardware
ESP support or individual binary GNU_STACK [35] settings. The rationale behind this decision seems to havebeen a desire for backwards compatibility with binaries
which require executable stacks which has caused similar issues on Linux in the past [33]. This backwards
compatibility is enforced on a system-wide (rather thanon an opt-out, per-binary basis) as confirmed by thefact that the QNX program loader does not parse the
GNU_STACK header of binaries. The problem with the
QNX approach here is that this setting is applied on asystem-wide basis and has an insecure default, putting
the secure configuration burden on system integrators.

3.2

memory objects (eg. code, stack, heap, etc.) and
rendering them hard to guess.
QNX has ASLR support since version 6.5 (notsupported for QNX Neutrino RTOS Safe Kernel 1.0)
but it’s disabled by default. QNX ASLR can be enabled
on a system-wide basis by starting the procnto
microkernel with the -mr option [55] and disabledwith the -m∼r option. A QNX child process normallyinherits its parent’s ASLR setting but as of QNX 6.6
ASLR can also be enabled or disabled on a per-processbasis by using the on utility [51] (with the -ae and -ad
options respectively). Alternatively, one can use the
SPAWN_ASLR_INVERT or POSIX_SPAWN_ASLR_INVERT
flags with the spawn and posix_spawn processspawning calls. To determine whether or not a process
is using ASLR, one can use the DCMD_PROC_INFO [49]command with the devctl [50] device control calland test for the _NTO_PF_ASLR bit in the flags memberof the procfs_info structure.
As shown in Table 6, QNX ASLR randomizes the baseaddresses of userspace and kernelspace stack, heap
and mmap’ed addresses as well as those of userspaceshared objects (eg. loaded libraries) and the executable
image (if the binary is compiled with PIE [16]). It does
not, however, have so-called KASLR support in order
to randomize the kernel image base address. The QNX
Momentics Tool Suite development environment (asof version 5.0.1, SDP 6.6) does not have PIE enabled
by default and indeed after an evaluation with acustomized version of the checksec [34] utility wefound that none of the system binaries (eg. those in/bin, /boot, /sbin directories) are PIE binaries in a
default installation.
Memory Object
Userspace
Stack
Heap
Executable Image
Shared Objects
mmap
Kernelspace
Stack
Heap
Kernel Image
mmap

Randomized
X
X
X
X
X
X
X
×
X

Address Space Layout Randomization

Table 6: QNX ≤ 6.6 ASLR Memory Object Randomization Support

When developing exploits, attackers rely on knowledgeof the target application’s memory map for directing
write and read operations as well as crafting code-reuse
payloads. Address Space Layout Randomization(ASLR) [31] is a technique which seeks to breakthis assumption by ensuring memory layout secrecy
via randomization of addresses belonging to various

We reverse-engineered QNX’s ASLR implementation(as illustrated in Figure 5) and found that it isultimately implemented in two function residing in
the microkernel: stack_randomize and map_find_va(called as part of mmap calls). QNX uses the Executableand Linking Format (ELF) binary format and proPage 5 of 22

Dissecting QNX

cesses are loaded from a filesystem using the exec*,
posix_spawn or spawn calls which invoke the program
loader implemented in the microkernel. If the ELF
binary in question is compiled with PIE-support, theprogram loader will randomize the program image
base address as part of an mmap call. When a loaded
program was linked against a shared object, or ashared object is requested for loading dynamically,
the runtime linker (contained in libc) will load it
into memory using a series of mmap calls. A stack isallocated automatically for the main thread (which
involves an allocation of stack space using mmap)
and has its base address (further) randomized by acall to stack_randomize. Whenever a new threadis spawned, a dedicated stack is either allocated(and managed) by the program itself or (by default)
allocated and managed by the system in a similar
fashion. Userspace and kernelspace heap memory
allocation, done using functions such as malloc,
realloc and free, ultimately relies on mmap as well.
In kernelspace, a dedicated stack is allocated for eachprocessor using a call to _scalloc and thus relies onmmap. As such, all ASLR randomization can be reduced
to analysis of stack_randomize and map_find_va:

U serspace ASLR

program image
base

loader_load

thread stack(s)shared object
image base

elf_load

thread_specretdlopenloader_load

main stackT hreadT LS

stack_randomize

heap_heap_alloc

Listing 1: QNX 6.6 vmm_mmap Routine
i n t vmm_mmap(PROCESS * prp , u i n t p t r _ t
vaddr_requested , s i z e _ t size_requested ,i n t prot , i n t f l a g s , OBJECT * obp ,u i n t 6 4 _ t b o f f , unsignedalignval ,unsigned preload , i n t fd , void **vaddrp , s i z e _ t * s i z e p ,p a r t _ i d _ t mpart_id ){...
create_flags = flags ;...
i f ( prp−>f l a g s & _NTO_PF_ASLR )c r e a t e _ f l a g s |= MAP_SPARE1 ;}r = map_create ( . . . , c r e a t e _ f l a g s ) ;Listing 2: QNX 6.6 map_create Routine
i n t map_create ( s t r u c t map_set * ms , s t r u c t
map_set * r e p l , s t r u c t mm_map_head *mh,u i n t p t r _ t va , u i n t p t r _ t s i z e ,u i n t p t r _ t mask , unsigned f l a g s ){...
i f ( f l a g s & ( MAP_FIXED|IMAP_GLOBAL) ) {...
} else {r e p l −> f i r s t = NULL ;load_object

memmgr.mmap

vmm_map

ClockCycles

map_find_va

init_objects

kernel heap

kernel stack(s)Kernelspace
ASLR

Figure 5: QNX ≤ 6.6 ASLR Memory Object Graph

map_find_va: As shown in Listings 1, 2 and3, the QNX memory manager’s vmm_mmap handler
function invokes map_create and passes a dedicatedmapping flag (identified only as MAP_SPARE1 in older
QNX documentation) if the ASLR process flag isset. map_create then invokes map_find_va withthese same flags, which randomizes the found virtual
address with a randomization value obtained from thelower 32 bits of the result of the ClockCycles [46]kernel call. This 32-bit randomization value is thenbitwise left-shifted by 12 bits and bitwise and-masked
with 24 bits resulting in a value with a mask form of
0x00FFF000, ie. a randomization value with at most
12 bits of entropy.

}}

va = map_find_va (mh, va , s i z e ,mask , f l a g s ) ;i f ( va == VA_INVALID ) {r = ENOMEM;
goto f a i l 1 ;}...

Listing 3: QNX 6.6 map_find_va Routine
u i n t p t r _ t map_find_va ( s t r u c t mm_map_head *mh, u i n t p t r _ t va , u i n t p t r _ t s i z e ,u i n t p t r _ t mask , unsigned f l a g s ){sz_val = s i z e − 1;...
i f ( f l a g s & MAP_SPARE1 ){uint64_t clk_val = ClockCycles () ;Page 6 of 22

Dissecting QNX

unsigned i n t r n d _ v a l = ( (_DWORD)c l k _ v a l << 12) & 0xFFFFFF ;}i f ( f l a g s & MAP_BELOW ){start_distance = start −best_start ;i f ( s t a r t != b e s t _ s t a r t ){i f ( rnd_val >start_distance )r n d _ v a l %=start_distance ;s t a r t −= r n d _ v a l ;
}
}
else
{
end_distance = best_end −sz_val − start ;i f ( b e s t _ e n d − s z _ v a l !=start ){i f ( rnd_val >end_distance )r n d _ v a l %=end_distance ;s t a r t += r n d _ v a l ;}}stack_randomize: Userspace processes have a mainstack and a dedicated stack for each subsequently
spawned thread. The main stack is allocated by the
program loader using an mmap call and subsequently
has its start address randomized by stack_randomize
called as part of a ThreadTLS call. Dedicated thread
stacks are spawned by the thread_specret routine
which allocates them with an mmap call (invoked as partof a call to procmgr_stack_alloc) and subsequently
randomizes their start address with stack_randomize.
This function, as shown in reverse-engineered formin Listing 4, checks whether a process has the ASLR
flag set and if so it generates a sizemask (between
0x000 and 0x7FF). A randomization value is drawn
from the lower 32 bits of the result of a ClockCycles
kernel call which are then bitwise left-shifted by 4
bits and have the sizemask applied to them. The
resulting value is subtracted from the original stack
pointer value and bitwise and-masked with 28 bits.
This results of a randomization value with a maskform of 0x000007F0, ie. an upper limit of 7 bits ofentropy for the maximum value of size_mask = 0x7FF.
Listing 4: QNX 6.6 stack_randomize Routine
u i n t p t r _ t s t a c k _ r a n d o m i z e ( const THREAD *const thp , u i n t p t r _ t new_sp ){u i n t p t r _ t rnd_sp ;size_t stack_size ;unsigned i n t size_mask ;rnd_sp = new_sp ;i f ( thp−>p r o c e s s −>f l a g s &_NTO_PF_ASLR ){s t a c k _ s i z e = thp−>un . l c l . s t a c k s i z e>> 4 ;
if ( stack_size ){size_mask = 0x7FF ;i f ( s t a c k _ s i z e <= 0x7FE )do { size_mask >>= 1 ; }while ( size_mask >stack_size ) ;rnd_sp = ( new_sp − ( (C l o c k C y c l e s ( ) << 4) &size_mask ) ) & 0xFFFFFFF0 ;}}}return rnd_sp ;Weak ASLR Randomization (CVE-2017-3892):
As observed above, the randomization underlying
mmap has a theoretical upper limit of 12 bits ofentropy and the additional randomization applied touserspace stacks introduces at most 7 bits of entropy,
combining into at most 19 bits of entropy with amask of form 0x00FFF7F0. Addresses with such
low amounts of entropy can be easily bruteforced(especially locally) and while ASLR on 32-bit systems
is generally considered inherently limited [7] one
should remember that these are upper bounds, ie. theyexpress the maximum possible introduced entropy.
Given that these upper bounds already compare
rather unfavorably against the measurements ofactual ASLR entropy in eg. Linux 4.5.0, PaX 3.14.21
and ASLR-NG 4.5.0 as per [7], this does not bode well.
All QNX ASLR randomization draws upon ClockCycles as the sole source of entropy. The QNX
ClockCycles [46] kernel call returns the current
value of a free-running 64-bit cycle counter using a
different implementation per architecture as outlinedin Table 7. Even though QNX’s usage of ClockCycles
seems to provide 32 bits of ’randomness’, it is an
ill-advised source of entropy due to its inherent
regularity, non-secrecy, and predictability.
Architecture
x86
ARM
MIPS
PPC
SuperH

Implementation
RDTSC
Emulation
Count Register
Time Base Facility
Timer Unit (TMU)

Table 7: QNX ClockCycles Implementations

Page 7 of 22

Dissecting QNX

In order to demonstrate this, we evaluated theentropic quality of QNX ASLR randomized addressesof several userspace memory objects. We did this witha script starting 3000 ASLR-enabled PIE processes perboot session and running 10 boot sessions, collecting
30000 samples per memory object in total. We used
the NIST SP800-90B [41] Entropy Source Testing (EST)tool [38] in order to evaluate the entropic qualityof the address samples by means of a min entropy
estimate, illustrated in Table 8. Min entropy is aconservative way of measuring the (un)predictabilityof a random variable X and expresses the number of(nearly) uniform bits contained in X , with 256 bits of
uniformly random data corresponding to 256 bits ofmin entropy.

value is not considered secret and in fact it leaks everywhere (both to local users as well as via network
services). As a result, an attacker in posession of thecurrent clock cycle counter value could reconstruct theclock cycle counter value (in a fashion analogous to thework in [36]) at the time of memory object randomization. Given the current clock cycle counter value
and an estimate on memory object initialization times,
an attacker can deduce the clock cycle counter value
at randomization time for a given memory object andreconstruct it as:
clockt = clockc − ((timec − timet ) ∗ cycless )where clockt , clockc , timet and timec are the target
and current clock cycle counter and timestamp values
Memory Object
Min Entropy (8 bits per symbol) and cycless is the number of cycle increments per
Stack
1.59986
second.
Heap
1.00914
Executable Image
0.956793
procfs Infoleak (CVE-2017-3892): The proc
Shared Objects
0.905646
filesystem (procfs) is a pseudo-filesystem on Unixlike operating systems that contains information
Table 8: QNX 6.6 ASLR Userspace Memory Object Min Entropy
about running processes and other system aspects
via a hierarchical file-like structure. This exposure
From Table 8 we can see that, on average, a QNX
of process information often includes ASLR-sensitive
randomized userspace memory object has a min
information (eg. memory layout maps, individual
entropy of 1.11785975. This means that it has a little
pointers, etc.) and as such has a history as a source formore than 1 bit of min entropy per 8 bits of data. If welocal ASLR infoleaks [12, 44, 62] with both GrSecurity
extrapolate this to the full 32 bits of a given address
and mainline Linux [26, 64] seeking to address
this means that the stack, heap, executable image
procfs as an infoleak source. On QNX procfs [48]and shared object base addresses have min entropy
is implemented by the process manager component
values of 6.39944, 4.03656, 3.827172 and 3.622584
of procnto and provides the following elements forrespectively, with an average of 4.471439 bits of mineach running process:entropy. This compares very unfavorably with theentropy measurements for various Linux-oriented
ASLR mechanisms in [7].
• cmdline: Process command-line arguments.
• exefile: Executable path.
On QNX, as is the case with many operating systems,• as: The virtual address space of the target process
child processes inherit the memory layout of parent
mapped as a pseudo-file.
processes. As a result when attacking forked or
pre-forked applications an attacker can guess an ASLR
These procfs entries can be interacted with like files
address, after which the target child crashes and isand subsequently manipulated using the devctl [50]
restarted with an identical memory layout allowing
API to operate on a file-descriptor resulting fromthe attacker to make another guess and so on. This
opening a procfs PID entry. Since process entries
facilitates both brute-force attacks and malicious childin QNX’s procfs are world-readable by default, thisprocesses attacking siblings in Android Zygote-stylemeans a wide range of devctl-based information
models [23]. Given this memory layout inheritance,
retrieval about any process is available to users
the fact that QNX ASLR provides only limited entropy
regardless of privilege boundaries. For example, theand has no active relocation (ie. memory object
QNX pidin [52] utility, which makes use of procfs
locations are never re-randomized), QNX ASLR isto provide a wide range of process inspection andhighly susceptible to brute-force attacks.
debugging options, easily allows any user to obtainstackframe backtraces, full memory mappings andFinally it should be noted that ClockCycles is notprogram states for any process. This effectively
a secure random number generator and by drawing diconstitutes a system-wide local information leakrectly from its output the clock cycle counter value actsallowing attackers to circumvent ASLR. It should be
analogous to a random number generator’s internal
noted this issue is not due to the availability of any
state. Contrary to a secure random number generaparticular utility (such as pidin) but rather results
tor’s internal state, however, the clock cycle counterfrom a fundamental lack of privilege enforcement on
Page 8 of 22

Dissecting QNX

procfs.

failure handler.

LD_DEBUG Infoleak (CVE-2017-9369):
The
LD_DEBUG [37] environment variable is used on some
Unix-like systems to instruct the dynamic linker to
output debug information during execution. On
QNX there are no cross-privilege restrictions on thisenvironment variable, leading to a (local) information
leak that can be used to circumvent ASLR. Since there
are no privilege checks (akin to the ’secure-execution
mode’ [63] offered by some Linux distributions) on
this environment variable, a local attacker can execute
setuid binaries with higher privileges using dynamic
linker debugging settings (eg. LD_DEBUG=all) inorder to output sensitive information (eg. memory
layout, pointers, etc.). This issue is similar to CVE2004-1453 [22] affecting certain versions of GNU glibc.

QNX’s QCC implements the GCC SSP scheme [43]and supports all the usual SSP flags (strong, all, etc.).
Since the compiler-side of the QNX SSP implementation is identical to the regular GCC implementation,
the master canary is stored accordingly and canary
violation invokes the __stack_chk_fail handler.

ASLR Correlation Attack (CVE-2017-3892):
ASLR randomization of memory object base addresses
can prove to be insufficient if different memory objects
are correlated. In such a case an attacker in theposession of one address can determine the locationof others by means of applying a static (or minimallyvarying) offset, rendering even the most limited
information leaks very powerful.
During our evaluation we found a partial correlation attack on QNX’s ASLR implementation, affecting
both PIE and non-PIE binaries. The offset from the program image base to the base address of the first loaded
shared library (libc) is of the mask form 0x00FFF000
with at most 12 bits being randomized. We evaluatedthe entropic quality of this offset value in order to determine the feasibility of correlation attacks by collecting
300 offset samples per boot session and running 10
boot sessions, making for 3000 samples total. Using
the NIST Entropy Source Testing (EST) tool [38] wedetermined the min entropy of these offset values tobe 0.918311, making for less than 1 bit of min entropy
per 8 bits of data, which corresponds to 1.3774665
bits of min entropy for the 12 affected variable bitsin the offset. Given that this is well below an exhaustive search, this makes a variation of the offset2lib [6]attack feasible.

3.3

Insecure User Canary Generation (CVE-2017XXXX): For userspace applications, this handler isimplemented in QNX’s libc. On the OS-side, reverseengineering of libc shows us that violation handler(shown in cleaned-up form in Listing 5) is a wrapper
for a custom function called _ssp_fail which writes
an alert message to the /dev/tty device and raises
a SIGABRT signal. QNX generates its master canaryvalue once upon program startup (during loading oflibc) and it is not renewed at any time. Instead of theregular libssp function __guard_setup, QNX uses acustom function called __init_cookies (shown in
Listing 6) invoked by the _init_libc routine in orderto (among other things) generate the master canaryvalue.
Listing 5: QNX 6.6 Stack Canary Failure Handler (Userspace)void _ _ s t a c k _ c h k _ f a i l ( void ){i f ( ( f d = open ( " / dev / t t y " , 1) ) != −1)
w r i t e ( fd , " *** s t a c k smashingd e t e c t e d *** " ) ;r a i s e ( SIGABRT ) ;}Listing 6: QNX 6.6 Userspace Canary Generation
void _ i n i t _ c o o k i e s ( void ){void * s t a c k v a l ;ts0 = ( ClockCycles () & 0 x f f f f f f f f ) ;can0 = ( t s 0 ^ (((& s t a c k v a l ) ^ (_ i n i t _ c o o k i e s ) ) >> 8) ) ;_ s t a c k _ c h k _ g u a r d = can0 ;ts1 = ( ClockCycles () & 0 x f f f f f f f f ) ;can1 = (((& s t a c k v a l ) ^ can0 ) >> 8) ;_ a t e x i t _ l i s t _ c o o k i e = ( can1 ^ t s 1 ) ;Stack Smashing Protector

Stack Smashing Protector (SSP) [43] is a so-called
stack canary scheme which seeks to prevent the
exploitation of stack buffer overflows by insertinga secret and unpredictably random canary value inbetween the local stack variables and the stackframe
metadata (eg. saved return address, saved frame
pointer). Any attempt at stack smashing which seeks
to overwrite such metadata also ends up corrupting
the canary value which is, upon function return,
compared against the original master value so thatwhen a mismatch is detected the SSP will invoke a

ts2 = ( ClockCycles () & 0 x f f f f f f f f ) ;_ a t q e x i t _ l i s t _ c o o k i e = ( can1 ^ t s 2 ) ;}_ s t a c k _ c h k _ g u a r d &= 0 x f f 0 0 f f f f ;As shown in Listing 6, QNX canaries have aterminator-style NULL-byte in the middle and are
generated using a custom randomization routine(slightly resembling the "poor man’s randomization
patch" included in some Linux distributions forPage 9 of 22

Dissecting QNX

performance purposes [28, 29]) rather than drawing itfrom a secure random number generator. The custom
randomization routine draws upon three sources:• _init_cookies: This is the function’s own address
and as such, the only randomization it introduces
is derived from ASLR’s effect on shared librarybase addresses which means that if ASLR isdisabled (or circumvented) this is a static value.
• stackval: This is an offset to the current stack
pointer and as such, the only randomization it
introduces is derived from ASLR’s effect on thestack base which means that if ASLR is disabled(or circumvented) this is simply a static value.
• ClockCycles: The lower 32 bits of the result ofa ClockCycles() call are used to construct themaster canary value.
Since it includes a terminator-style NULL-byte, the
QNX master canary value has a theoretical upper limitof 24 bits of entropy. However, all entropy in QNX
stack canaries is ultimately based on invocations of
the ClockCycles kernel call. If ASLR is enabled,
the stackval address gets randomized when themain thread is spawned during program startup andthe _init_cookies address gets randomized whenlibc gets loaded by the runtime linker. The ts0
value is generated when _init_cookies is called by_init_libc which is invoked upon application startup(but after libc is loaded).
The first problem with using ClockCycles as asource of randomness is the limited entropy provided
and thus the degree to which the canary is unpredictable and the size of the search space. In orderto evaluate the entropic quality of QNX’s canarygeneration mechanism, we collected canary values
for three different process configurations: No ASLR,
ASLR but no PIE and ASLR with PIE. We used ascript starting 785 instances of each configuration perboot session and repeated this for 10 boot sessions,collecting 7850 samples per configuration in total.
We then used the NIST Entropy Source Testing (EST)tool [38] in order to obtain min entropy estimates
for the sample sets as illustrated in Table 9. Basedon these observations we can conclude that a) QNX
canary entropy is far less than the hypothetical upperbound of 24 bits, being on average 7.78981332 bits fora 32-bit canary value and b) ASLR plays no significant
contributing role to the overall QNX canary entropy.
Due to the absence of any canary renewal functionality [5], regular as well as byte-for-byte [67]brute-force attacks are feasible against QNX, especiallyconsidering the low entropic quality of the canaries.

Settings
No ASLR
ASLR, no PIE
ASLR + PIE

Min Entropy (8 bits per symbol)
1.94739
1.94756
1.94741

Table 9: QNX 6.6 Stack Canary Min Entropy

On top of entropy issues, ClockCycles is not a
secure random number generator, as we discussed
before with ASLR, and as such similar reconstruction
attacks could be mounted against QNX canaries.
Absent Kernel Canary Generation (CVE-2017XXXX): When it comes to kernelspace stack canaryprotection, the QNX microkernel (in the form of the
procnto process) also features an SSP implementation covering a subset of its functions. Since thekernel neither loads nor is linked against libc (andcanary violations need to be handled differently), SSP
functionality is implemented in a custom fashion here.
Reverse-engineering of the microkernel showed that it
has a custom __stack_chk_fail handler (illustrated
in Listing 7) but no master canary initialization routine.
As a result, QNX never actually initializes the kernelmaster canary value and hence its value is completely
static and known to the attacker (0x00000000),
rendering QNX kernel stack canary protection trivial
to bypass.
Listing 7: QNX 6.6 Stack Canary Failure Handler (Kernelspace)void _ _ s t a c k _ c h k _ f a i l ( void ){k p r i n t f ( " *** s t a c k smashing d e t e c t e d
i n p r o c n t o *** " ) ;__asm{ i n t 0x22 } ;}3.4

Relocation Read-Only

QNX supports Relocation Read-Only (RELRO), a
mitigation that allows for marking relocation sections
as read-only after they have been resolved in order toprevent attackers from using memory corruption flaws
to modify relocation-related information (such as Procedure Linkage Table (PLT) related Global Offset
Table (GOT) entries using GOT-overwriting [20]).
RELRO comes in two variants: partial and full, withthe former protecting non-PLT entries and the latter
protecting the entire GOT. RELRO is implemented
partially in the toolchain and partially in the operating
system.
In most RELRO implementations, the compiler first
stores constants requiring dynamic relocation in a
dedicated section (typically named .data.rel.ro)before the linker creates a PT_GNU_RELRO program
Page 10 of 22

Dissecting QNX

segment (itself enclosed in a PT_LOAD segment) tocover the sections in question. For full RELRO thelinker also emits the BIND_NOW flag. On the operating
system side of the implementation the dynamic linker
will, upon encountering a PT_GNU_RELRO segment,
mark the relevant pages as read-only after dynamic
relocation. If the BIND_NOW flag is specified all
relocations are applied immediately upon program
startup. A proper RELRO implementation requires atleast the following:

Figure 6: Debian Linux RELRO Example• A linker which reorders relocation sections sothat they are grouped together, properly aligned
for memory permission marking and precede theprogram data sections.
• A linker which emits a GNU_RELRO segment
covering all relocation sections as well as (for full
RELRO) a BIND_NOW flag.
• A dynamic linker which parses a binary for the
GNU_RELRO segment and upon encountering it
properly marks contained sections as read-only
after applying relocations as well as immediately
applying all relocations upon encountering a
BIND_NOW flag.
• Any disabling of RELRO functionality should be
mediated by privilege checks.
We uncovered the following issues violating theabove:
BrokenRELRO(CVE-2017-3893):
The
GNU_RELRO segment emitted by QNX’s QCC
linker only covers relocation up until the .data section
but mistakenly the section order is not properly
adjusted so that internal data sections (eg. .got)
precede program data sections (eg. .data). As aresult, the most security-critical relocation section (thePLT-related elements of the GOT) are not includedin the GNU_RELRO segment and are thus not maderead-only after relocation.
For example, on Debian Linux a full RELRO binary
will look as pictured in figure 6. There we can see
the GNU_RELRO segment covers the area from
0x08049ed8 to 0x0804a000 which includes .got.
On QNX, however, the same full RELRO binary
looks as pictured in figure 7. There we can see
the GNU_RELRO segment covers the area from
0x08049f2c to 0x804a000 which does not include.got and thus allows us to violate RELRO with eg. a
GOT-overwriting attack.
Local RELRO Bypass (CVE-2017-3893): On Unixlike systems the LD_DEBUG environment variable
is used to pass debugging settings to the dynamic

Figure 7: QNX 6.6 RELRO Example

linker. QNX has a custom debugging option dubbed ’imposter’ which, among other things, disables RELRO.
Since there are no privilege checks on this debug setting, a low-privileged user could leverage it to target
setuid binaries belonging to higher-privileged users inorder to bypass any RELRO protections and thus ease
exploitation.

4

QNX 7.0 Exploit Mitigations

QNX 7, released in January 2017, is the successor to
QNX 6.6 and comes with support for 64-bit architectures such as ARM v8 or Intel x86-64. It comes witha host of new security features such as secure boot,integrity measurement, mandatory access control,
host-based anomaly detection, granular sandboxingand secure software updates.
In this section we will document the results of ourreverse-engineering and analysis of QNX 7.0’s exploit
mitigations and secure random number generators andthe degree to which they differ from and improve upon
their predecessors in QNX 6.6 and earlier. Table 10
provides an overview of QNX 7.0’s exploit mitigations
and their default settings.

4.1

Executable Space Protection

Despite our disclosure of the insecure default settings,
it turns out they have not been fixed in QNX 7 andas such, the stack (but not the heap) is executableby default. In order to enable non-executable stacks
system integrators have to start procnto with the-m˜x flag. Unfortunately there is no way to guarantee
per-binary backwards compatibility in this case as the
Page 11 of 22

Dissecting QNX

Mitigation
ESP
ASLR
SSP
RELRO
NULL-deref Protection
Vtable Protection
CFI
CPI
Kernel Data Isolation2
Kernel Code Isolation3

Support
X
X
X
X
×
×
×
×
×
×

Default
×
×
X1
X1
n/a
n/a
n/a
n/a
n/a
n/a

Table 10: QNX 7 Exploit Mitigation Overview
1
Default QNX Momentics IDE Settings, 2 eg. UDEREF / SMAP/ PAN, 3 eg. KERNEXEC / SMEP / PXN

The ASLR randomization underlying calls to mmap
is now being handled by the kerext_valloc andvm_region_create functions as part of a rewritten
memory manager. As shown in Listings 9 and 10 inboth cases all entropy is drawn from random_value.
In the former case the full 32 bits of entropy could beabsorbed on a 64-bit system while in the latter casethe bitmasking imposes a theoretical upper limit of 12
bits.
Listing 9: QNX 7 kerext_valloc Snippet
void k e r e x t _ v a l l o c ( void * data ){...
i f ( s i z e _ v a l != obj−>s i z e ){randomized_addr = ( obj−>addr + (random_value ( ) << 12) % ( obj−>
size − size_val )) & 0
xFFFFFFFFFFFFF000 ;}GNU_STACK ELF header is not parsed.

4.2

Address Space Layout Randomization

QNX 7 ASLR remains disabled by default and does
not provide KASLR support for kernel image baserandomization.
ASLR Randomization: As shown in Listing 8, QNX
7’s stack_randomize routine remains identical tothat of QNX 6.6 save for replacing ClockCycles as
the entropy source with random_value. However, theissue of the entropy being theoretically limited to an
upper bound of 7 bits as a result of the application of
the bitmasking remains.

}

Listing 10: QNX 7 vm_region_create Snippet
signed _ _ f a s t c a l l v m _ r e g i o n _ c r e a t e (vm_aspace_t * as , vm_mmap_attr_t * a t t r ){...
r n d _ v a l = ( random_value ( ) << 12) & 0
xFFF000 ;start_distance = start − best_start ;i f ( s t a r t != b e s t _ s t a r t ){i f ( s t a r t _ d i s t a n c e < rnd_val )r n d _ v a l %= s t a r t _ d i s t a n c e ;s t a r t −= r n d _ v a l ;}Listing 8: QNX 7 stack_randomize Routine
u i n t p t r _ t s t a c k _ r a n d o m i z e ( const THREAD *const thp , u i n t p t r _ t new_sp ){u i n t p t r _ t rnd_sp ;size_t stack_size ;unsigned i n t size_mask ;rnd_sp = new_sp ;s t a c k _ s i z e = thp−>un . l c l . s t a c k s i z e >> 4 ;if ( stack_size ){si ze _ma sk = 0x7FF ;i f ( s t a c k _ s i z e <= 0x7FE ){dosi ze _mask >>= 1 ;while ( s t a c k _ s i z e < size_mask ) ;}rnd_sp = ( new_sp − ( ( random_value ( ) <<4 & size_mask ) ) & 0
xFFFFFFFFFFFFFFF0 ;}}return rnd_sp ;

...

}

...

Curiously, however, QNX 7’s memory manager
restricts initial randomized mapping of userspacestack, heap and executable image objects to the lower
32 bits of the address space while restricting sharedlibraries to the lower 36 bits.
Information Leaks: While the LD_DEBUG Infoleak(CVE-2017-9369) has been fixed in QNX 7, theprocfs Infoleak (CVE-2017-3892) is still very muchpresent with only some restrictions imposed on
it. In QNX 7 procfs has been slightly modified sothat interaction with processes now goes throughthe /proc/*/ctl pseudo-file. While the /proc/*
directories have stronger permission settings and thepidin tool no longer allows for direct disclosure ofPage 12 of 22

Dissecting QNX

sensitive address information from higher-privileged
processes, /proc/*/ctl remains world-readable forall process entries and accessible to the devctl API. As
such, a local attacker is still able to disclose sensitive
address information across privilege boundaries.
While capability-based sandboxing might limit the
exposure of certain processes this is not configured tobe the case by default.
We have left correlation attack evaluation for QNX 7
to future work.

4.3

Stack Smashing Protector

SSP is enabled by default in QNX Momentics 7.0.0 andgenerates 64-bit canaries on 64-bit systems.
Userspace Canary Generation:
The new_init_cookies routine in QNX 7 is shown in
Listing 11 where we can see that _stack_chk_guard
is formed by the XOR sum of rdtsc, the code addressof _init_cookies, the stack address of stackval
and the value stored in auxil_val. This approach issimilar to the one in QNX 6.6 save for the introductionof auxil_val which is a 64-bit value drawn fromthe AT_RANDOM ELF auxiliary vector entry. ELF
auxiliary vectors [30] are a mechanism to transfer OS
information to user processes via the program loader.
This approach was integrated into QNX 7.0 based on
our suggestions to the vendor.
Listing 11: QNX 7 Userspace Canary Generation
void _ i n i t _ c o o k i e s ( ){auxv_t * a u x i l ;int auxil_type ;__int64 a u x i l _ v a l ;unsigned _ _ i n t 6 4 c0 ;unsigned _ _ i n t 6 4 c1 ;char s t a c k v a l ;a u x i l = auxv ;a u x i l _ t y p e = a u x i l −>a _ t y p e ;i f ( auxil_type ){while ( a u x i l _ t y p e != AT_RANDOM ){++a u x i l ;a u x i l _ t y p e = a u x i l −>a _ t y p e ;i f ( ! a u x i l −>a _ t y p e )goto END_AUXV ;}a u x i l _ v a l = a u x i l −>a_un . a _ v a l ;}else{
END_AUXV :a u x i l _ v a l = 0LL ;}}c0 = _ _ r d t s c ( ) ^ ( ( ( unsigned _ _ i n t 6 4 )_ i n i t _ c o o k i e s ^ ( unsigned _ _ i n t 6 4 )&s t a c k v a l ) >> 8) ^ a u x i l _ v a l ;_ s t a c k _ c h k _ g u a r d = ( void * ) c0 ;c1 = ( ( unsigned _ _ i n t 6 4 )&s t a c k v a l ^ c0 )>> 8 ;_ a t e x i t _ l i s t _ c o o k i e = ( void * ) ( c1 ^__rdtsc () ) ;BYTE_OFFSET_6 ( _ s t a c k _ c h k _ g u a r d ) = 0 ;_ a t q e x i t _ l i s t _ c o o k i e = ( void * ) ( c1 ^__rdtsc () ) ;Upon reverse-engineering the loader_load routine
in the QNX microkernel as shown in Listing 12 we cansee AT_RANDOM is filled with a concatenation of two
32-bit values drawn from the random_value kernel
PRNG (discussed below in Section 5.2).

Listing 12: QNX 7 AT_RANDOM Generationa u x i l _ p o i n t e r −>a _ t y p e = AT_RANDOM;
a u x i l _ p o i n t e r −>a_un . a _ v a l = ( unsigned
i n t ) random_value ( ) ;i f ( interp_name [ 7] & 8 ){a u x i l _ p o i n t e r −>a_un . a _ v a l |=random_value ( ) << 32;...
}

Kernelspace Canary Generation: The absent kernelspace canary generation vulnerability affecting QNX
6.6 and prior has been fixed in QNX 7. During earlyboot in kernel_main, prior to kernel kickoff, the kernelspace master canary is drawn from a concatenation of two 32-bit random values drawn from therandom_value kernel PRNG as shown in Listing 13.
Listing 13: QNX 7 Kernelspace Canary Generationc a l l i n _ i n i t () ;mdriver_check ( ) ;* (_DWORD * )&i n k e r n e l = 0xD00 ;c0 = random_value ( ) ;c1 = random_value ( ) ;_ s t a c k _ c h k _ g u a r d = ( void * ) ( ( c1 << 32)| c0 ) ;k e r _ e x i t _ k i c k o f f ( p e r c p u _ p t r−>data .
ker_stack ) ;4.4

Relocation Read-Only

The RELRO vulnerability we reported has been fixed in
QNX 7 with QCC observing proper ELF section ordering and full RELRO being enabled by default in QNXMomentics 7.0.0.
Page 13 of 22

Dissecting QNX5

QNX Secure Random Number
Generators

5.1/dev/random in QNX ≤ 6.6

Many mitigations require a source of secure randomness and ideally this is provided by the operating
system itself. As such, the security of the OS random
number generator is of crucial importance to thesecurity of exploit mitigations as well as the overall
cryptographic ecosystem. As prior work has shown [2,4, 9, 10], embedded random number generation
suffers from a variety of issues with far-reachingconsequences and as such we reverse-engineered andanalyzed the QNX OS random number generator.
QNX provides an Operating System Cryptographically
Secure Random Number Generator (OS CSPRNG)
exposed through the Unix-style /dev/random and/dev/urandom interfaces, both of which are nonblocking in practice. The OS CSPRNG is implemented
as the random service [56] which runs as a userspaceprocess started by the /etc/rc.d/startup.sh script.
On QNX versions up to and including 6.6 the CSPRNG
underlying the random service is based on the
Yarrow CSPRNG [8] (which is also used by iOS, Mac
OS X, AIX and some BSD descendants) rather than its
recommended successor Fortuna [11].

Boottime Entropy
Collection

R andom Bits

R untime Entropy
Collection

yarrow_input

yarrow_output

PR N G State

yarrow_do_sha1

yarrow_create

yarrow_make_new_state

Entropy Pool

Figure 8: Simplified QNX 6.6 Yarrow Design

The QNX Yarrow implementation (as illustrated
in Figure 8), however, is not based on the reference Yarrow-160 [8] design but instead on an older
Yarrow 0.8.71 implementation by Counterpane [24]which has not undergone the security scrutiny Yarrow
has seen over the years and differs in the following key
aspects:• Single Entropy Pool: While Yarrow-160 has
separate fast and slow entropy pools, Yarrow
0.8.71 only has a single entropy pool. The twopools were introduced so that the fast pool could
provide frequent reseeds of the Yarrow key tolimit the impact of state compromises while theslow pool provides rare, but very conservative,
reseeds of the key to limit the impact of entropy
estimates which are too optimistic. Yarrow
0.8.71’s single pool does not allow for suchsecurity mechanisms.
• No Blockcipher Applied To Output: As opposed
to Yarrow-160, Yarrow 0.8.71 does not apply ablock cipher (eg. in CTR mode) to the Yarrowinternal state before producing PRNG output andinstead simply outputs the internal state directly
which results in a significantly weaker design thanthat of Yarrow-160.
In addition, the QNX Yarrow implementation diverges from Yarrow 0.8.71 as well in the following
aspects:• Mixes PRNG Output Into Entropy Pool: As partof its various entropy collection routines, QNX
Yarrow mixes PRNG output back into the entropy
pool. For example in the high performancecounter entropy collection routine (as per thesnippet in Listing 14) we can see PRNG output isdrawn from QNX Yarrow, used as part of a delay
routine and subsequently mixed (via a xor operation with the result of a ClockCycles call) backinto the entropy pool. This construction deviatesfrom all Yarrow designs and is ill-advised in theabsence of further security analysis or justification.
Listing 14: QNX Yarrow HPC Entropy Collection Snippet
i f ( Yarrow ){yarrow_output ( Yarrow , ( u i n t 8 _ t * )&r da t a , s i z e o f ( r d a t a ) ) ;t i m e o u t = ( r d a t a & 0x3FF ) + 10;}
delay ( timeout ) ;clk = ClockCycles () ;clk = clk ^ rdata ;i f ( Yarrow )y a r r o w _ i n p u t ( Yarrow , ( u i n t 8 _ t * )&clk , sizeof ( c l k ) , pool_id , 8);• Absent Reseed Control (QNX < 6.6): In all QNX
versions prior to 6.6 reseed control is completely
absent. While the required functionality was
implemented, the responsible functions are neveractually invoked, which means that while entropy
is being accumulated during runtime it is neveractually used to reseed the state and thus only
boottime entropy is actually ever used to seed the
QNX Yarrow state in versions prior to 6.6.
• Custom Reseed Control (QNX 6.6): In QNX
6.6 there is a custom reseeding mechanism
integrated into the yarrow_do_sha1 andyarrow_make_new_state functions (as illustrated in Listings 15 and 16) which are called
upon PRNG initialization and whenever output
Page 14 of 22

Dissecting QNX

is drawn from the PRNG (which means it is also
constantly called during entropy accumulation
due to the above mentioned output mixing
mechanism). In both cases, a permutation named
IncGaloisCounter5X32 is applied to the entropy
pool before the pool contents are mixed intoa SHA1 state which eventually becomes the
Yarrow internal state. Contrary to Yarrow design
specifications, no entropy quality estimation isdone before reseeding.
Listing 15: QNX 6.6 yarrow_do_sha1 function
void yarrow_do_sha1 ( yarrow_t * p ,yarrow_gen_ctx_t * ctx ){SHA1Init (& sha ) ;I n c G a l o i s C o u n t e r 5 X 3 2 ( p−>pool . s t a t e );sha . s t a t e [ 0] ^= p−>pool . s t a t e [ 4 ] ;sha . s t a t e [ 1] ^= p−>pool . s t a t e [ 3 ] ;sha . s t a t e [ 2] ^= p−>pool . s t a t e [ 2 ] ;sha . s t a t e [ 3] ^= p−>pool . s t a t e [ 1 ] ;sha . s t a t e [ 4] ^= p−>pool . s t a t e [ 0 ] ;SHA1Update(&sha , c t x−>i v , 20) ;SHA1Update(&sha , c t x−>out , 20) ;SHA1Final ( c t x−>out , &sha ) ;}Listing 16: QNX 6.6 yarrow_make_new_state function
void yarrow_make_new_state ( yarrow_t *p , yarrow_gen_ctx_t * ctx , uint8_t* state ){f o r ( i = 0 ; i < 20; i++)c t x−>i v [ i ] ^= s t a t e
SHA1Init (& sha ) ;I n c G a l o i s C o u n t e r 5 X 3 2 ( p−>pool . s t a t e );sha . s t a t e [ 0] ^= p−>pool . s t a t e [ 4 ] ;sha . s t a t e [ 1] ^= p−>pool . s t a t e [ 3 ] ;sha . s t a t e [ 2] ^= p−>pool . s t a t e [ 2 ] ;sha . s t a t e [ 3] ^= p−>pool . s t a t e [ 1 ] ;sha . s t a t e [ 4] ^= p−>pool . s t a t e [ 0 ] ;}SHA1Update(&sha , c t x−>i v , 20) ;SHA1Final ( c t x−>out , &sha ) ;While all the above discussed divergences areat the very least ill-advised, the reseeding control
issues constitute a clear security issue. In the caseof absent reseeding control, it eliminates Yarrow’s
intended defense against state compromise as well as
greatly increasing system susceptibility to the so-called"boottime entropy hole" [10] that affects embedded
systems. In the case of the QNX Yarrow 6.6 custom
reseeding control no entropy quality estimation isdone before reseeding the state from the entropy poolthus potentially allowing for low-quality entropy todetermine the entire state.
In order to evaluate the QNX Yarrow PRNG output
quality we used two test suites: DieHarder [18]and the NIST SP800-22 [40] Statistical Test
Suite (STS) [39]. DieHarder is a random number
generator testing suite, composed of a series ofstatistical tests, "designed to permit one to push a weakgenerator to unambiguous failure" [18]. The NIST
Statistical Test Suite (STS) consists of 15 tests
developed to evaluate the ’randomness’ of binary
sequences produced by hardware- or software-based
cryptographic (pseudo-) random number generators
by assessing the presence or absence of a particularstatistical pattern. The goal is to "minimize theprobability of accepting a sequence being produced bya generator as good when the generator was actuallybad" [40]. While there are an infinite number ofpossible statistical tests and as such no specific test
suite can be deemed truly complete, they can help
uncover particularly weak random number generators.
QNX Yarrow passed both the DieHarder and
NIST STS tests but this only tells us something about
the quality of PRNG output, leaving the possibility
open that raw noise / source entropy is (heavily)
biased which can result in predictable PRNG outputs
as well as attackers being able to replicate PRNG
internal states after a reasonable number of guesses.
As such we reverse-engineered and evaluated the QNX
random service’s boot- and runtime entropy sources.
Boottime Entropy Analysis: When random is initialized it gathers initial boottime entropy from thefollowing sources (as illustrated in Figure 9) which are
fed to the SHA1 hash function to produce a digest used
to initialize the PRNG initial state:• ClockTime [47]: The current system clock time.
• ClockCycles [46]: The current value of a freerunning 64-bit clock cycle counter.
• PIDs: The currently active process IDs by walking
the /proc directory.
• Device Names: The currently available device
names by walking the /dev directory.
In order to evaluate random’s boottime entropy
quality we used the NIST SP800-90B [41] Entropy
Source Testing (EST) tool [38] to evaluate
boottime entropy by means of a min entropy estimate.
We collected random’s boottime entropy from 50
different reboot sessions on the same device (byinstrumenting yarrow_init_poll and logging thecollected raw noise) and using NIST EST determined
Page 15 of 22

Dissecting QNX

that the average min-entropy was 0.02765687, which
is far less than 1 bit of min-entropy per 8 bits of
raw noise. In addition to the boottime entropy ofindividual boot sessions being of low quality, thestatic or minimally variable nature of many of theboottime noise sources (identical processes anddevices available upon reboot, real-time nature of
QNX limiting jitter between kernel calls thus reducing
ClockCycles entropy, etc.) results in predictable andconsistent patterns across reboots.

ClockTime

ClockCycles/proc PIDs

/dev N ames

SH A1

Q N X Yarrow
Initial State

Figure 9: QNX Yarrow Boottime Entropy Collection

Another boottime entropy issue with QNX’s random
service is the fact that the service is started as a processby startup.sh. As a result, the CSPRNG is only available quite late in the boot process and many services
which need it (eg. sshd) start almost immediately after.
Since random only offers non-blocking interfaces, thismeans that one can draw as much output from the
CSPRNG as one wants immediately upon availabilityof the device interface. Hence, many applications
which start at boot and require secure random data
have their ’randomness’ determined almost completelyby the (very low quality) boottime raw noise since
there is little time for the QNX random service togather runtime entropy before being queried thus amplifying the impact of the "boot-time entropy hole" [10].
Runtime Entropy Analysis: The QNX random service leaves the choice and combination of runtime entropy sources (as illustrated in Figure 10) up to theperson configuring the system with the following options:• Interrupt Request Timing: Up to 32 different
interrupt numbers may be specified to be used as
an entropy source. The entropy here is derived
from interval timing measurements (measured by
the ClockTime kernel call) between requests to a
specific interrupt.
• System Information Polling: This source collects entropy from system information via theprocfs [48] virtual filesystem in /proc. This
information is composed of process and thread
information (process and thread IDs, stack andprogram image base addresses, register values,
flag values, task priority, etc.) for every currently
active process.
• High-Performance Clock Timing: This source
draws entropy from the PRNG (using theyarrow_output function), initiates a delay (inmilliseconds) based on the PRNG output, invokes
ClockCycles and xors the result against theearlier obtained PRNG output and feeds this into
the entropy pool.
• Library Hardware Entropy Source (Undocumented): This undocumented entropy
source (invoked using command-line parameter -l) allows a user to specify a dynamic
library to supply entropy collection callback
functions named entropy_source_init andentropy_source_start. In order to be used thelibrary has to export a symbol named cookie with
the NULL-terminated value RNG (0x524E4700).
Based on debugging information it seems this is
to allow for drawing from a hardware random
number generator as an entropy source.
• User-Supplied Input (Undocumented): In QNX
6.6 the random service has a write-handler madeavailable to users via the kernel resource manager(in the form of handling write operations to the/dev/(u)random interfaces) which takes arbitrary
user inputs of up to 1024 bytes per write operation and feeds it directly into the entropy pool bypassing it to the yarrow_input operation. Write
operations of this kind are restricted to the root
user only.
After initialization, random starts a thread for eachentroy source which will gather entropy and store itin the entropy pool. Contrary to our analysis of QNX
random’s boottime entropy, we did not perform a runtime entropy quality evaluation because during ourcontact with the vendor they had already indicatedthe current design would be overhauled in upcoming
patches and future releases as a result of our findings.
In addition, in all QNX versions except for 6.6 runtime
entropy is accumulated but not used due to the previously mentioned absent reseeding control. We didhave the following observations however:• Entropy Source Configuration: Configuringruntime entropy sources is entirely left to system
integrators. Since the entropic quality of certain
sources (eg. interrupt request timings or system
information polling) varies depending on theparticular system, it is non-trivial to pick suitablesources.
• System Information Entropy Source: System
information polling gathers raw noise fromPage 16 of 22

Dissecting QNX

currently running processes (in the form ofprocess and thread debug info). A significant
number of the fields in the process and thread
debug info structures, however, are largely static
values (eg. uid, flags, priority, stack and programbase in the absence of ASLR, etc.) with mostrandomness derived from time-based fields(starttime, runtime) or program state (ip, sp).
• Interrupt Request Timing Entropy Source: Interrupt request timing gathers raw noise from interrupt invocation timings. As such this meansthat if integrators choose to specify interrupts thatare rarely or never invoked, barely any runtime
entropy is gathered using this source. Interrupt invocation frequency can be very system specific andpicking the right interrupts is not trivial. The QNX
documentation explicitly recommends to "minimize the impact of [interrupt request timing overhead] by specifying only one or two interrupts from
low interrupt rate devices such as disk drivers andinput/serial devices" [56], an advice which would
result in less entropy being accumulated from thissource. Furthermore, it seems that if for whateverreasons the random service cannot attach to aninterrupt, the interrupt entropy gathering thread
fails silently and no entropy is gathered for thatinterrupt at all.

H igh Performance
Clock Source

System Information
Polling Source

yarrow_output

delay

ClockCycles/proc info

yarrow_output

SH A1

delay

unsigned
unsigned
uint32_t
sha256_t}

i n t new_dig_idx ;int result ;keypad [ 8 ] ;shout ;i f ( dig_idx > 7 ){keypad [0 ] = s a l t ^ C l o c k C y c l e s ( ) ;keypad [1 ] = a c t i v e s [ get_cpunum ( ) ] ;keypad [2 ] = s a l t ^ q t i m e p t r −>nsec ;keypad [3 ] = pid_unique ^ s a l t ;keypad [4 ] = wakeup_timer ;keypad [5 ] = k e r n e l _ e x i t _ c o u n t ;keypad [6 ] ^= random_seed ;s h a 2 5 6 _ i n i t (& shout ) ;sha256_add(& shout , keypad , 0x20u ) ;sha256_done(& shout , d i g e s t ) ;result = digest [0];if ( ! salt )salt = digest [0];new_dig_idx = 1 ;}else{
new_dig_idx = d i g _ i d x + 1 ;r e s u l t = digest [ dig_idx ];}d i g _ i d x = new_dig_idx ;return r e s u l t ;SysSrandom()random_seed

actives[get_cpunum()]

ClockCycles()wakeup_timer
PR N G Input Block

pid_uniqueyarrow_output

kernel_exit_countClockTimeyarrow_input

qtimeptr->nsec
interrupt invoked>= N times?

ClockTime

entropy_source_start

dev_random_write

U ndocumented
SourcesInterrupt Request
Timing Source

Initial Value: 0Salt

PR N G Stateif salt = 0

Block #0

Block #dig_idx

If dig_idx > 7

If dig_idx <= 7

Figure 10: QNX Yarrow Runtime Entropy Collection

5.2

QNX 7.0 Kernel PRNGQNX 7 has a new kernel PRNG for generation of secure
random numbers implemented in the microkernel’srandom_value function. As shown in Listing 17 andillustrated in Figure 11, the kernel PRNG consists of a
256-bit seed block fed through SHA256 to produce adigest from which 32-bit random numbers are drawn
iteratively before reseeding after exhausting the entire
digest.
Listing 17: QNX 7 Kernel PRNG
unsigned i n t random_value ( ){O utput:
R andom Value(32-bit)Figure 11: QNX Kernel PRNG

Kernel PRNG entropy is drawn from a combinationof the following values:• salt: A salt value which starts out as 0 and thengets filled with the first non-zero 32 bits of every
newly generated digest.
• ClockCycles: The current clock cycle countervalue.

Page 17 of 22

Dissecting QNX• actives[get_cpunum()]: The currently active
thread on this CPU.

Seedfile Source

fortuna_pseudorand

fortuna_save_state• qtimeptr->nsec: The current time in nanoseconds.

fortuna_load_state

H igh Performance
Clock Source

System Information
Polling Source

seedfile/proc info

fortuna_pseudorandSH A256

delay

fortuna_pseudorand• pid_unique: The currently active PID.
• wakeup_timer: The timer wakeup value [45].
• kernel_exit_count: Counter keeping track of
the number of kernel exit operations.
• random_seed: Random seed user-supplied via
SysSrandom [58] kernel calls. This kernel
call can only be made by processes with the
PROCMGR_AID_SRANDOM ability.

ClockTime
delay

ClockCycles

fortuna_pseudorandinterrupt invoked>= N times?

Interrupt Request
Timing Source

fortuna_add

ClockTime

add_entropy

entropy_source_start

dev_random_write

Library Source

U ser-Supplied
SourcePR N G state

arc4random()

getpid()gettimeofday()getuid()Reseed Source

Figure 12: QNX 7 Fortuna Entropy Collection

Of
these
sources,
pid_uniqueandactives[get_cpunum()] have a limited rangeof possible values and none of the sources except for wakeup_timer, kernel_exit_count andrandom_seed can be considered secret. Some sources(eg. ClockCycles, kernel_exit_count) are also
likely to have greatly reduced ranges during boot-time.

• High-Performance Clock Timing: This sourceis identical to the one in the QNX 6.6 random
implementation.

Finally, note that all sources are truncated to
32-bit values when stored in the seed block, that
random_seed is only initialized when system integrators utilize it and that the final block (keypad[7]) is
never initialized. As such, in many cases the theoreticalmaximum of the entropy contained within the seedblock would be reduced to 192 bits. A full evaluationof the entropic quality of the QNX 7 kernel PRNG isleft to future work.

• User-Supplied Input: Anything written to the/dev/(u)random device is immediately absorbed
into the PRNG state and, if seedfile state persistence is enabled, the state is saved as well. It
is possible to shield this functionality with the-m mode option specifying permissions but by
default the interface is world-writable which
could possibly present an avenue for reseedingattacks.

5.3/dev/random in QNX 7.0

Following our advisory on the QNX Yarrow PRNG,
the QNX 7 random service was redesigned to use
Fortuna instead. While the design and interface ofthe random service remains mostly the same, QNX
7 uses a customized version of the Heimdal [32]Fortuna implementation as illustrated in Figure 12.
The QNX 7 Fortuna implementation no longer
has dedicated boot- and runtime entropy collection
routines and draws upon the following entropy sources:• Interrupt Request Timing: This source is
identical to the one in the QNX 6.6 random
implementation.
• System Information Polling: This source is
identical to the one in the QNX 6.6 random
implementation.

• Library Hardware Entropy Source: This sourceis identical to the one in the QNX 6.6 random
implementation.

• Seedfile Source: If specified, QNX 7 Fortuna
can load and save entropy from and to a 128-byte
seedfile (done after writing to /dev/(u)randomor automatically after 8192 reseedings). This fileis owned by root with user read/write permissions
only.
• Reseed Source: Reseed control is integrated into
the fortuna_bytes and fortuna_init routinesand thus checked periodically. It is implemented
as shown in Listing 18. This routine is not likely
to provide high quality reseed entropy considering that pid and uid do not change for the
random service and that arc4random reads from/dev/random (creating a circular reseed loop) anduses the broken RC4 cipher.
Listing 18: QNX 7 fortuna_reseed#de f i ne INIT_BYTES 128
int fortuna_reseed (){Page 18 of 22

Dissecting QNX

u i n t 3 2 _ t buf [ INIT_BYTES / s i z e o f (uint32_t ) ];int i ;
i n t entropy_p = 0 ;i f ( ! init_done )abort () ;f o r ( i = 0 ; i < s i z e o f ( buf ) / s i z e o f ( buf[ 0 ] ) ; i++)buf [ i ] = arc4random ( ) ;add_entropy (& m a i n _ s t a t e , ( void * ) buf ,s i z e o f ( buf ) ) ;entropy_p = 1 ;pid_t pid = getpid () ;add_entropy (& m a i n _ s t a t e , ( void * )&pid ,sizeof ( pid ) ) ;struct timeval tv ;g e t t i m e o f d a y (& tv , NULL) ;add_entropy (& m a i n _ s t a t e , ( void * )&tv ,sizeof ( tv ) ) ;uid_t u = getuid () ;add_entropy (& m a i n _ s t a t e , ( void * )&u ,sizeof (u) ) ;}return entropy_p ;Due to the elimination of dedicated boottime entropy harvesting and its rapid startup time, QNX 7
Fortuna is likely to suffer from the "boottime entropyhole" (unless system integrators explicitly enable seedfiles / state persistence) but we leave a full analysis ofentropic quality to future work.

6

Conclusion

We reverse-engineered and analyze the exploit
mitigations and secure random number generators
of QNX ≤ 6.6 and 7.0 and found and reported amyriad of issues of varying degrees of severity. Table
11 presents an overview of the analyzed mitigations
and RNGs, their issues and what versions are affectedby them. Note that we have left proper RNG entropy
quality and ASLR correlation attack evaluation of QNX
7’s to future work and as such we can neither confirm
nor rule out issues in this regard.
We can see that despite our disclosure of the issues
affecting QNX 6.6 and subsequent fixes being drafted
for the bulk of them, some of them remained in QNX
7.0. Regardless, General Availability (GA) patches
are available for all issues affecting QNX ≤ 6.6 inTable 11 (naturally excluding those affecting QNX 7.0).
One striking observation is that while QNX clearlyattempts to keep up with at least basic exploit miti-Component
ESP
ASLR
ASLR
ASLR
ASLR
ASLR
ASLR
ASLR
SSP
SSP
SSP
SSP
RELRO
RELRO
RELRO
OS CSPRNG
OS CSPRNG
OS CSPRNG
1

IssuesDisabled by default
Disabled by default1
No KASLR1
Weak Randomization1
No Re-Randomization1
procfs Infoleak1
LD_DEBUG Infoleak3
Correlation Attack1
Disabled by default
Weak Randomization
No Re-Randomization
No Kernel Canaries
Disabled by default2
Broken RELRO2
LD_DEBUG Bypass2
Ill-Advised Design
Absent Reseed Control
Low Boottime Entropy

Affected
≤ 7.0
≤ 7.0
≤ 7.0
≤ 6.6
≤ 7.0
≤ 7.0
≤ 6.6
≤ 6.6
≤ 6.6
≤ 6.6
≤ 7.0
≤ 6.6
≤ 6.6
≤ 6.6
≤ 6.6
≤ 6.6
< 6.6
≤ 6.6

Table 11: QNX Mitigation & RNG Issues Overview
CVE-2017-3892, 2 CVE-2017-3893, 3 CVE-2017-9369

gations as they have evolved in the general purpose
world, the fact that it is a proprietary OS outsideof the Linux, Windows and BSD lineages meansthat they cannot trivially port mitigations, patches
and improvements from these operating systems.
In addition, the relative lack of attention to QNX
by outside security researchers is evident from thedegree to which certain vulnerabilities and issues(such as the local information leaks or the "poor man’s
randomization patch" design for ASLR/SSP) resemble
older vulnerabilities on other Unix-like systems.
Finally, our findings re-confirm the notion that secure
random number generation and especially integrating
suitable entropy sources is an issue that continues toplague the embedded world. The impact of this goesbeyond affecting the quality of exploit mitigations andhas consequences for the wider security ecosystem as
a whole.
It is our hope that this work inspires other security
researchers to further investigate the security and OS
internals of QNX and other closed-source embedded
operating systems.

Bibliography[1]Alex Plaskett et al. QNX: 99 Problems but a Microkernel ain’t one! 2016.

[2]

Daniel J. Bernstein et al. “Factoring RSA keys
from certified smart cards: Coppersmith in thewild”. In: ASIACRYPT (2013).

[3]

Daniel Martin Gomez et al. BlackBerry PlayBook
Security: Part one. 2011.

Page 19 of 22

Dissecting QNX

[4]

[5]

David Kaplan et al. “Attacking the Linux PRNG
on Android & Embedded Devices”. In: Black Hat
Europe (2014). url: https://www.blackhat.
com/docs/eu- 14/materials/eu- 14- KedmiAttacking - The - Linux - PRNG - On - Android Weaknesses - In - Seeding - Of - Entropic Pools-And-Low-Boot-Time-Entropy.pdf.
Hector Marco-Gisbert et al. “Preventing brute
force attacks against stack canary protection
on networking servers”. In: 12th IEEE International Symposium on Network Computing andApplications (NCA) (2013).

[20]

c0ntex. How to hijack the Global Offset Table
with pointers for root shells. url: http://www.
infosecwriters.com/text_resources/pdf/
GOT_Hijack.pdf.

[21]

Communications Security Establishment
Canada. EAL 4+ Evaluation of QNX Neutrino®
Secure Kernel v6.4.0. 2009. url: https :/ / www . commoncriteriaportal . org / files /epfiles/neutrino-v640-cert-eng.pdf.

[22]

Silvio Cesare. CVE-2004-1453. 2004. url: http:/ / www . cve . mitre . org / cgi - bin / cvename .
cgi?name=CVE-2004-1453.
Colt. Android OS - Processes and the Zygote! url:
http://coltf.blogspot.nl/p/android-osprocesses-and-zygote.html.
Counterpane. Yarrow 0.8.71. url: https : / /www.schneier.com/code/Yarrow0.8.71.zip.
CVE Details. QNX CVEs. url: https : / / www .
cvedetails . com / vulnerability - list /vendor_id-436/QNX.html.
Jake Edge. proc: avoid information leaks to
non-privileged processes. 2009. url: https://
patchwork.kernel.org/patch/21766/.
Julio Cesar Fort. QNX Advisories. url: https://packetstormsecurity . com / files / author /3551/.
Hagen Fritsch. Buffer overflows on linux-x86-64.
2009.
Hagen Fritsch. Stack Smashing as of Today.
2009.
Manu Garg. About ELF Auxiliary Vectors. url:
http : / / articles . manugarg . com /aboutelfauxiliaryvectors.
Hector Marco Gisbert. “Cyber-security protection techniques to mitigate memory errors
exploitation”. In: (2015). url: https : / /riunet . upv . es / bitstream / handle /10251 / 57806 / Marco % 20 - %20Cyber security % 20protection % 20techniques %20to % 20mitigate % 20memory % 20errors %20exploitation . pdf ? sequence = 1 &isAllowed=y.
Heimdal. The Heimdal Kerberos 5, PKIX, CMS,
GSS-API, SPNEGO, NTLM, Digest-MD5 and, SASL
implementation. url: http://www.h5l.org/.
Alejandro Hernandez. A Short Tale About executable_stack in elf_read_implies_exec() in theLinux Kernel. url: http : / / blog . ioactive .
com / 2013 / 11 / a - short - tale - about executablestack-in.html.
Tobias Klein. checksec. url: http : / / www .
trapkit.de/tools/checksec.html.
Gentoo Linux. Hardened/GNU stack quickstart.
url: https : / / wiki . gentoo . org / wiki /Hardened/GNU_stack_quickstart.

[6]

Hector Marco-Gisbert et al. “On the Effectiveness of Full-ASLR on 64-bit Linux”. In: DeepSec(2014).

[23][7]

Hector Marco-Gisbert et al. “Exploiting Linuxand PaX ASLR’s weaknesses on 32- and 64-bit
systems”. In: BlackHat Asia (2016).

[24]

[8]

John Kelsey et al. “Yarrow-160: Notes on the Design and Analysis of the Yarrow Cryptographic
Pseudorandom Number Generator”. In: Sixth
Annual Workshop on Selected Areas in Cryptography (1999).

[9]

Keaton Mowery et al. “Welcome to the Entropics:
Boot-Time Entropy in Embedded Devices”. In:
IEEE Security and Privacy (2013).

[10]

Nadia Heninger et al. “Mining Your Ps and
Qs: Detection of Widespread Weak Keys in Network Devices”. In: USENIX Security Symposium(2012).

[25]

[26]

[27]

[28]
[29]

[11]

Niels Ferguson et al. Practical Cryptography. Wiley, 2003.

[30]

[12]

Tavis Ormandy et al. Linux ASLR Curiosities.
2009. url: https://www.cr0.org/paper/tojt-linux-alsr-leak.pdf.

[31]

[13]

Zach Lanier et al. Voight-Kampff’ing The BlackBerry PlayBook. 2012.

[14]

Zach Lanier et al. No Apology Required: Deconstructing BB10. 2014.

[15]

Alexander Antukh. Dissecting Blackberry 10 –An initial analysis. 2013.

[16]

BlackBerry. Using compiler and linker defenses(BlackBerry Native SDK for PlayBook OS). url:
http : / / developer . blackberry . com /playbook / native / reference / com . qnx .
doc . native _ sdk . security / topic / using _compiler_linker_defenses.html.

[17]BlackBerry. QNX. 2017. url: http://www.qnx.
com/content/qnx/en.html.

[18]

Robert G. Brown. Dieharder: A Random Number
Test Suite. url: https://www.phy.duke.edu/\~rgb/General/dieharder.php.

[19]

Tim Brown. QNX Advisories. url: https : / /packetstormsecurity . com / files / author /4309/.

[32]

[33]

[34]
[35]

Page 20 of 22

Dissecting QNX[36]Matt Miller. “Reducing the Effective Entropy of
GS Cookies”. In: Uninformed Vol. 7 (2007).

[37]

Bojan Nikolic. The LD_DEBUG environment variable. url: http : / / www . bnikolic . co . uk /blog/linux-ld-debug.html.

[38]

NIST. NIST Entropy Source Testing (EST) tool.
url: https : / / github . com / usnistgov /SP800-90B_EntropyAssessment.

[39]

NIST. NIST Statistical Test Suite (STS). url:
http : / / csrc . nist . gov / groups / ST /toolkit / rng / documentation \ _software .
html.

[40]

NIST. “NIST SP800-22: A Statistical Test Suite
for Random and Pseudorandom Number Generators for Cryptographic Applications”. In: NIST(2010).

[41]

NIST. “NIST SP800-90B: Recommendation for
the Entropy Sources Used for Random Bit Generation”. In: NIST (2016).

[42]

Alex Plaskett. QNX Security Architecture. 2016.

[43]

Paul Rascagneres. Stack Smashing Protector.
2010.

[44]

Fermin J. Serna. “The info leak era on software
exploitation”. In: Black Hat US (2012).

[45]

QNX Software Systems. Clock and timer services.
url: http : / / www . qnx . com / developers /docs / 7 . 0 . 0 / index . html # com . qnx .
doc . neutrino . sys _ arch / topic / kernel _CLOCKANDTIMER.html.

[46]

QNX Software Systems. ClockCycles(). url:
http : / / www . qnx . com / developers / docs /660 / index . jsp ? topic = %2Fcom . qnx .
doc . neutrino . lib _ ref % 2Ftopic % 2Fc %2Fclockcycles.html.

[47]

QNX Software Systems. ClockTime(), ClockTime_r(). url: http : / / www . qnx . com /developers/docs/660/topic/com.qnx.doc.
neutrino . lib _ ref / topic / c / clocktime .
html.

[48]

[49]

[50]

QNX Software Systems. Controlling processes via
the /proc filesystem. url: http : / / www . qnx .
com / developers / docs / 660 / index . jsp ?
topic = %2Fcom . qnx . doc . neutrino . prog %2Ftopic%2Fprocess_proc_filesystem.html.
QNX Software Systems. DCMD_PROC_INFO.
url: http : / / www . qnx . com / developers /docs / 660 / index . jsp ? topic = %2Fcom . qnx .
doc . neutrino . cookbook % 2Ftopic % 2Fs3 _procfs_DCMD_PROC_INFO.html.
QNX Software Systems. devctl. url: http://
www.qnx.com/developers/docs/660/index.
jsp?topic=%2Fcom.qnx.doc.neutrino.lib_
ref%2Ftopic%2Fd%2Fdevctl.html.

[51]

QNX Software Systems. On. url: http : / /www.qnx.com/developers/docs/660/index.
jsp ? topic = %2Fcom . qnx . doc . neutrino .
utilities%2Ftopic%2Fo%2Fon.html.

[52]

QNX Software Systems. pidin. url: http : / /www . qnx . com / developers / docs / 660 /index.jsp?topic=/com.qnx.doc.neutrino.
utilities/topic/p/pidin.html.

[53]

QNX Software Systems. Private virtual memory.
url: http : / / www . qnx . com / developers /docs / 660 / index . jsp ? topic = %2Fcom . qnx .
doc.neutrino.sys_arch%2Ftopic%2Fproc_
Private_virtual_memory.html.

[54]

QNX Software Systems. Procmgr abilities. url:
http://www.qnx.com/developers/docs/6.
6.0.update/#com.qnx.doc.neutrino.prog/
topic/process_Procmgr_abilities.html.

[55]

QNX Software Systems. Procnto. url: http://
www.qnx.com/developers/docs/660/index.
jsp ? topic = %2Fcom . qnx . doc . neutrino .
utilities/topic/p/procnto.html.

[56]

QNX Software Systems. Random. url: http://
www.qnx.com/developers/docs/660/index.
jsp ? topic = %2Fcom . qnx . doc . neutrino .
utilities/topic/r/random.html.

[57]

QNX Software Systems. Shared memory. url:
http://www.qnx.com/developers/docs/7.0.
0/index.html#com.qnx.doc.neutrino.sys_
arch/topic/ipc_Shared_memory.html.

[58]

QNX Software Systems. SysSrandom(), SysSrandom_r(). url: http : / / www . qnx . com /developers / docs / 7 . 0 . 0 / index . html #com . qnx . doc . neutrino . lib _ ref / topic /s/syssrandom.html.

[59]

QNX Software Systems. Typed memory. url:
http : / / www . qnx . com / developers / docs /7.0.0/index.html#com.qnx.doc.neutrino.
sys_arch/topic/ipc_Typed_memory.html.

[60]

QNX Software Systems. QNX Neutrino RTOS:
System Architecture. 2014. url: http : / /support7 . qnx . com / download / download /26183 / QNX _ Neutrino _ RTOS _ System _Architecture.pdf.

[61]

QNX Software Systems. 50 Million Vehicles andCounting: QNX Achieves New Milestone in Automotive Market. 2015. url: http://www.qnx.
com/news/pr_6118_3.html.

[62]

Julien Tinnes. Local bypass of Linux ASLR
through /proc information leaks. 2009. url:
http : / / blog . cr0 . org / 2009 / 04 / local bypass - of - linux - aslr - through - proc .
html.

[63]

Ubuntu. ld.so, ld-linux.so - dynamic linker/loader.
2017. url: http://manpages.ubuntu.com/
manpages/xenial/man8/ld.so.8.html.
Page 21 of 22

Dissecting QNX[64]

Ubuntu. /proc/pid/maps protection. 2017. url:
https : / / wiki . ubuntu . com / Security /Features#proc-maps.

[65]

Gerrit De Vynck. CIA Listed BlackBerry’s Car Software as Possible Target. 2017. url: https://www.bloomberg.com/news/articles/201703 - 08 / cia - listed - blackberry - s - car software-as-possible-target-in-leak.

[66]

Ralf-Philipp Weinmann. BlackberryOS 10 Froma Security Perspective. 2013.

[67]

Adam ’pi3’Zabrocki. “Scraps of notes on remote
stack overflow exploitation”. In: Phrack (2010).

Page 22 of 22