Shared memory bug in QNX4.25

Hi,

Debugging a fault app I’ve found what seems to be a bug in the shared memory
protection mechanism on QNX4.25. A shared segment is accessed past its end
without memory violation detection. In the case of the fault app instead of
stoping with a memory violation it was corrupting another shared memory
segment because of this problem.

I’ve attached a simple test program to show the problem.

Regards,

Leonel Vicente Mota Ivo


begin 666 testshmem.c
M+RH*“E1E<W0@<’)O9W)A;2!T;R!D96UO;G-T<F%T92!A(&)U9R!I;B!T:&4@
M<VAA<F5D(&UE;6]R>2!P<F]T96-T:6]N(&UE8VAA;FES;2X*“D$@<VAA<F5D
M(’-E9VUE;G0@8W)E871E9”!W:71H(&$@9&5F:6YE9”!S:7IE(&ES(&%C8V5S
M<V5D(’!A<W0@:71S(&5N9 IW:71H;W5T(&UE;6]R>2!V:6]L871I;VX@9&5T
M96-T:6]N+@H5&@8V]M<&EL92!U<V4Z"@IC8R M;R!T97-T<VAM96T@=&5S
M=’-H;65M+F,@"@I#;VUP:6QE<CH@5V%T8V]M(#$P+C8@<&%T8V@@;&5V96P@
M0@I1;G@@-“XR-2!P871C:”!%“BHO”@HO
@HJBHJBHJBHJBHJBHJBHJ
MBHJ(’-I;B!I;F9O(&]F('1H92!T97-T(&UA8VAI;F4@BHJBHJBHJBHJ
M
BHJBHJ"E!23T=204T@(" @(" @(" @(" @(" @($Y!344@(" @(" @("!6
M15)324].($1!5$4
<WES+U!R;V,S,B @(" @(" @(" @(" @4’)O8R @(" @
M(" @(#0N,C5,(" @1F5B(#$U(#(P,#$<WES+U!R;V,S,B @(" @(" @(" @
M(" @4VQI8C$V(" @(" @(#0N,C-’(" @3V-T(# T(#$Y.38
<WES+U-L:6(S
M,B @(" @(" @(" @(" @4VQI8C,R(" @(" @(#0N,C1"(" @075G(#$R(#$Y
M.3<+V)I;B]&<WES(" @(" @(" @(" @(" @1G-Y<S,R(" @(" @(#0N,C16
M(" @1F5B(#$X(#(P,# +V)I;B]&<WES(" @(" @(" @(" @(" @1FQO<’!Y
M(" @(" @(#0N,C1"(" @075G(#$Y(#$Y.3<
+V)I;B]&<WES+F5I9&4@(" @
M(" @(" @96ED92 @(" @(" @(#0N,C5!(" @1F5B(# Y(#(P,# +V)I;B]$
M978S,B @(" @(" @(" @1&5V,S(@(" @(" @(#0N,C-’(" @3V-T(# T(#$Y
M.38
+V)I;B]$978S,BYA;G-I(" @(" @1&5V,S(N86YS:2 @(#0N,C-((" @
M3F]V(#(Q(#$Y.38
+V)I;B]$978S,BYS97(@(" @(" @1&5V,S(N<V5R(" @
M(#0N,C-)(" @2G5N(#(W(#$Y.3<+V)I;B]$978S,BYP87(@(" @(" @1&5V
M,S(N<&%R(" @(#0N,C5!(" @2F%N(# X(#(P,#$
+V)I;B]$978S,BYP=‘D@
M(" @(" @1&5V,S(N<‘1Y(" @(#0N,C-’(" @3V-T(# T(#$Y.38*+V)I;B]0
M:7!E(" @(" @(" @(" @4&EP92 @(" @(" @(#0N,C-!(" @1F5B(#(V(#$Y
M.38*+V)I;B].970@(" @(" @(" @(" @3F5T(" @(" @(" @(#0N,C5#(" @
M075G(#,P(#$Y.3D*+V)I;B].970N971H97(Q,# P(" @3F5T+F5T:&5R,3 P
M(#0N,C1"(" @2G5L(#(T(#$Y.3@+V)I;B])<V\Y-C8P9G-Y<R @(" @27-O
M.38V,&9S>7,@(#0N,C-$(" @36%R(#(P(#(P,# +V)I;B]&871F<WES(" @
M(" @(" @1F%T9G-Y<R @(" @(#0N,C9!(" @36%R(#(W(#(P,# +V)I;B]-
M;W5S92 @(" @(" @(" @36]U<V4@(" @(" @(#0N,C1!(" @075G(#(R(#$Y
M.3<
+W5S<B]B:6XO;’!S<G9R(" @(" @;’!S<G9R(" @(" @(#0N,C1!(" @
M2G5N(#(V(#$Y.3<
+W5S<B]U8V(O4V]C:VQE=" @(%-O8VML970@(" @(" T
M+C(U2" @($IU;" S," Q.3DY"B]B:6XO8W)O;B @(" @(" @(" @(&-R;VX@
M(" @(" @(" T+C(S0B @($]C=" S," Q.3DW"B]B:6XO9W(N=F=A(" @(" @
M("!61T$@1W)A9G@@(" @,2XP,T<@("!&96(@,C@@,3DY-@HO8FEN+W!H9F]N
M=&%L;" @(" @4&AO=&]N($9O;G0@(#$N,31((" @2G5N(# U(#(P,# +W!H
M;W1O;B]B:6XO4&AO=&]N(%!H;W1O;B @(" @(" Q+C$T0B @(%-E<" P,R Q
M.3DY"BHJ
BHJ
BHJBHJBHJBHJBHJBH@<VEN(&EN9F@;V8@=&AE('1E
M<W0@;6%C:&EN92 J
BHJBHJBHJBHJBHJ*@HJ+PH*(VEN8VQU9&4)/’-T
M9&EO+F@^“B-I;F-L=61E"3QS=’)I;F<N:#X*(VEN8VQU9&4)/&5R<FYO+F@^
M"B-I;F-L=61E"3QF8VYT;“YH/@HC:6YC;‘5D90D<WES+VUM86XN:#X*(VEN
M8VQU9&4)/’-Y<R]S=&%T+F@^“B-I;F-L=61E"3QS>7,O='EP97,N:#X*(VEN
M8VQU9&4)/'5N:7-T9"YH/@H*(V1E9FEN90D)35E?4TE:10D)-# Y-@H*=‘EP
M961E9B!S=’)U8W0@;7E?<W1R=6-T"GL*(”!U;G-I9VYE9”!C:&%R"0EV86QU
M95M-65]325I%73L*?2!T7VUY7W-T<G5C=#L*“FEN=”!#<F5A=&5396=M96YT
M*&-H87(@G-E9U]N86UE+"!U;G-I9VYE9"!S96=?<VEZ92P@=F]I9" JG!D
M871A3L@HOB!497-T(’!R;V=R86T@+2!&;W)C92!S96=M96YT('9I;VQA
M=&EO;B H2&]P92!S;R Z+3XI(“HO"FEN=”!M86EN
&EN="!A<F=C+"!C:&%R
M(“IA<F=V6UTI"GL*(”!T7VUY7W-T<G5C=" J<’-H;65M.PH@(&EN="!I.PH@
M(" @“B @:68@$-R96%T95-E9VUE;G0H(E1E<W0B+"!S:7IE;V8H=%]M>5]S
M=’)U8W0I+" F<’-H;65M
2 A/2 P0H@('L"7!R:6YT9B@B7&Y#<F5A=&4@
M<V5G;65N=”!F86EL=7)E(5QN(BD["@ER971U<FX@,3L*("!]“B @(” ("!F
M;W(@
&D],#L@:3Q-65]325I%.R!IRLI"B @("!P<VAM96TM/G9A;'5E6VE=
M/2AU;G-I9VYE9"!C:&%R
6D["@HO+R JBHJBHJBH@:68@86YY(&]N92!B
M96QO=R!I<R!U;F-O;6UE;G1E9"!W92!G;W0@86X@97AC97!T:6]N(&%S(&5X
M<&5C=&5D("HJ
BHJ"0HO+R @<’)I;G1F*")V86QU95LE9%T@/2 E9%QN(BP@
M35E?4TE:12P@<’-H;65M+3YV86QU95M-65]325I%72D[“B\O(”!P<VAM96TM
M/G9A;‘5E6TU97U-)6D5=(#T@,3L*“B\O(” JBHJBHJBH@5&AI<R!C;V1E
M(&)E;&]W(’-H;W5L9"!F86EL(’=I=&@@;65M;W)Y('9I;VQA=&EO;BP@8G5T
M(&ET"B\O(" @<G5N<R!W:71H;W5T(&%N>2!E>&-E<'1I;VX@(2$A(2!7:'D_
M/S@BHJBHJ
BHJBHJBHJBHJ@H@(&9O<B H:3TH35E?4TE:12TU3L@
M:3PH35E?4TE:12LR,“D(&DKRD"7!R:6YT9B@B=F%L=65;)61=(#T@)61<
M;B(L(&DL(’!S:&UE;2T^=F%L=65;:5TI.PH*("!P<FEN=&8H(G9A;'5E6R5D
M72
6D5=3L
M(”!P<VAM96TM/G9A;'5E6TU97U-)6D5=(#T@,3L
("!P<FEN=&8H(G9A;‘5E
M6R5D72 ](“5D7&XB+”!-65]325I%+"!P<VAM96TM/G9A;‘5E6TU97U-)6D5=
M3L(" ("!R971U<FX@,#L?0H*“B\J($9U;F-T:6]N(‘1O(&-R96%T92!A
M(’-H87)E9”!M96UO<GD@87)E82 J+PII;G0@0W)E871E4V5G;65N=“AC:&%R
M(“IS96=?;F%M92P@=6YS:6=N960@F4L('9O:60@BIP9&%T82D
M>PH@(&EN= D)<W1A=‘5S/3 ["B @:6YT"0EF9#L*"B @:68@’-E9U]N86UE
M("$]($Y53$PI"B @>PH)<VAM7W5N;&EN:RAS96=?;F%M92D["@EF9" ](’-H
M;5]O<&5N
’-E9U]N86UE+”!/7U)$5U(@?”!/7T-214%4+ H)“0E37TE255-2
M('P@4U])5U534B!(%-?25)'4E @?”!37TE71U)0(‘P@4U])4D]42"D["@EI
M9B H9F0@(3T@+3$I"@E["@D@(&EF("AL=’)U;F,H9F0L(’-E9U]S:7IE+"!3
M145+7U-%5"D@/3T@+3$I"@D@(‘L*“0EP<FEN=&8H(EQN4V5G;65N=”!S:7IE
M(&1E9FEN:71I;VX@9F%I;‘5R92!S:7IE*“5D2!S96<@)7,@6R5S72%<;B(L
M"@D)"7-E9U]S:7IE+’-E9U]N86UE+’-T<F5R<F]R
&5R<FYO2D["@D)<W1A
M='5S/38["@D@('T
"2 @96QS90H)(”!["@D)G!D871A(#T@;6UA<"@P+"!S
M96=?<VEZ92P@4%)/5%]214%$('P@4%)/5%]74DE412P
"0D)“0D@(”!-05!?
M4TA!4D5$+"!F9"P@,“D[”@D):68@“IP9&%T82 ]/2 H=F]I9” J2 M,2D*
M"0E["@D)("!P<FEN=&8H(EQN;6UA<"!F86EL=7)E("5S(%LE<UU<;B(L( H)
M"0ES96=?;F%M92QS=’)E<G)O<BAE<G)N;RDI.PH)“2 @<W1A='5S(#T@-3L*
M"0E]”@D)96QS90H)"2 @;65M<V5T*"IP9&%T82PP+’-E9U]S:7IE3L"2 @
M?0H)("!C;&]S92AF9"D["@E]"@EE;’-E"@E["@D@(’!R:6YT9B@B7&YS:&U?
M;W!E;B!F86EL=7)E(’-E9R E<R!;)7-=(5QN(BQS96=?;F%M92P*“0D)<W1R
M97)R;W(H97)R;F\I3L"2 @<W1A='5S/3,[”@E]“B @?0H@(’)E='5R;BAS
*=&%T=7,I.PI]”@``
`
end

I’ve compiled the same test program in QNX Neutrino 6.2.0 and it worked as
expected, rising the memory fault.


“Leonel Vicente Mota Ivo” <leonel@atan.com.br> wrote in message
news:bl9dpe$h0p$1@inn.qnx.com

Hi,

Debugging a fault app I’ve found what seems to be a bug in the shared
memory
protection mechanism on QNX4.25. A shared segment is accessed past its end
without memory violation detection. In the case of the fault app instead
of
stoping with a memory violation it was corrupting another shared memory
segment because of this problem.

I’ve attached a simple test program to show the problem.

Regards,

Leonel Vicente Mota Ivo

Leonel Vicente Mota Ivo <leonel@atan.com.br> wrote:

Hi,

Debugging a fault app I’ve found what seems to be a bug in the shared memory
protection mechanism on QNX4.25. A shared segment is accessed past its end
without memory violation detection. In the case of the fault app instead of
stoping with a memory violation it was corrupting another shared memory
segment because of this problem.

A bit of clarification – was it corrupting another area of shared
memory mapped into the same process, or an area of shared memory
not mapped into the same process?

QNX4 and QNX6 are very different in how they layout the virtual
address space of a process.

In QNX6 (where, as you said, this example faults as you would expect),
it generally uses a very sparse virtual map for the process – shared
memory segments are mapped into the process space in a disjoint virtual
range from heap/data/stack, and mapped in (generally) disjoint from
each other as well.

In QNX4, the mapping tends to be very tight – mapped areas of memory
can be interspersed with sections of the heap, and there could in
fact be valid process memory just above/below the virtual address
range of a mapping. If you are corrupting the virtual mapping of
another area of memory mapped into your process, that is likely what
is happening.

But, if you are corrupting an area of shared memory not mapped into
your process, you have a problem.

I just added a printf() to your program, before the CreateSegment()
call. If I do this, your program sigsegv’s as expected under QNX4.

What was happening – you mapped in the area, then later called
printf() – which allocated some memory, into heap area at a
virtual address just after the area you created. Your “invalid”
memory pointers, actually hit valid pages in the heap (malloc
area), rather than invalid memory. By re-ordering, that is,
by causing the malloc() in printf() to happen first, your mmap()
is now at the top of the valid virtual address space for your
process, and writing beyond the end now fails.

So, I would say there is no OS bug here.

-David

P.S. using shared memory to allocate should give you zero-filled
pages, so the memset() in your allocation is redundant.


QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Leonel Vicente Mota Ivo <leonel@atan.com.br> wrote in message
news:bl9dpe$h0p$1@inn.qnx.com

Debugging a fault app I’ve found what seems to be a bug in the shared
memory
protection mechanism on QNX4.25. A shared segment is accessed past its end
without memory violation detection. In the case of the fault app instead
of
stoping with a memory violation it was corrupting another shared memory
segment because of this problem.

In addition to Dave’s request to clarify exactly where corruption is
happening, you cannot assume that just because you go past the end of a
mapped shared object, that there isn’t another mapped object directly next
to it. And unless we trap on each data access (oh how that would be slow -
I suppose we could do it only on write, but it’d still be painfully slow),
there isn’t a way for the OS to catch you doing.

-Adam

Hi David! Thanks for your answer. See below some clarification.

“David Gibbs” <dagibbs@qnx.com> wrote in message
news:bl9rvj$4to$1@nntp.qnx.com

Leonel Vicente Mota Ivo <> leonel@atan.com.br> > wrote:
Hi,

Debugging a fault app I’ve found what seems to be a bug in the shared
memory
protection mechanism on QNX4.25. A shared segment is accessed past its
end
without memory violation detection. In the case of the fault app instead
of
stoping with a memory violation it was corrupting another shared memory
segment because of this problem.

A bit of clarification – was it corrupting another area of shared
memory mapped into the same process, or an area of shared memory
not mapped into the same process?

The process mapped 3 shared memory segments used by other processes and it
was corrupting one of this segments.

QNX4 and QNX6 are very different in how they layout the virtual
address space of a process.

In QNX6 (where, as you said, this example faults as you would expect),
it generally uses a very sparse virtual map for the process – shared
memory segments are mapped into the process space in a disjoint virtual
range from heap/data/stack, and mapped in (generally) disjoint from
each other as well.

In QNX4, the mapping tends to be very tight – mapped areas of memory
can be interspersed with sections of the heap, and there could in
fact be valid process memory just above/below the virtual address
range of a mapping. If you are corrupting the virtual mapping of
another area of memory mapped into your process, that is likely what
is happening.

Yes, problably this is what happened.

But, if you are corrupting an area of shared memory not mapped into
your process, you have a problem.

I just added a printf() to your program, before the CreateSegment()
call. If I do this, your program sigsegv’s as expected under QNX4.

What was happening – you mapped in the area, then later called
printf() – which allocated some memory, into heap area at a
virtual address just after the area you created. Your “invalid”
memory pointers, actually hit valid pages in the heap (malloc
area), rather than invalid memory. By re-ordering, that is,
by causing the malloc() in printf() to happen first, your mmap()
is now at the top of the valid virtual address space for your
process, and writing beyond the end now fails.

So, I would say there is no OS bug here.

In my system each process maps 3 or more shared memory segments at the same
time and as you have explained they will probably be mapped in a contiguous
way, so if one of the process misbehave and try to access past for example
the first segment it could corrupt the next one.
Is it possible to force this mapping to be in a disjuint virtual space in
order to improve the fault tolerance of my system?

-David

P.S. using shared memory to allocate should give you zero-filled
pages, so the memset() in your allocation is redundant.


QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Adam, I’ve just replied Dave before I saw your comment.

“Adam Mallory” <amallory@qnx.com> wrote in message
news:bl9u6m$63r$1@nntp.qnx.com

Leonel Vicente Mota Ivo <> leonel@atan.com.br> > wrote in message
news:bl9dpe$h0p$> 1@inn.qnx.com> …

Debugging a fault app I’ve found what seems to be a bug in the shared
memory
protection mechanism on QNX4.25. A shared segment is accessed past its
end
without memory violation detection. In the case of the fault app instead
of
stoping with a memory violation it was corrupting another shared memory
segment because of this problem.

In addition to Dave’s request to clarify exactly where corruption is
happening, you cannot assume that just because you go past the end of a
mapped shared object, that there isn’t another mapped object directly next
to it.

Now I realised that I couldn’t assume that. But at first I thought I would
have individual protection.

And unless we trap on each data access (oh how that would be slow -
I suppose we could do it only on write, but it’d still be painfully slow),
there isn’t a way for the OS to catch you doing.

-Adam

Leonel Vicente Mota Ivo <leonel@atan.com.br> wrote in message
news:bl9vdg$8q$1@inn.qnx.com

Adam, I’ve just replied Dave before I saw your comment.

Now I realised that I couldn’t assume that. But at first I thought I would
have individual protection.

Well, what you could do map in a readonly page after each of your shared
object mapping. If you happen to scribble past the end, you should cause a
trap.

-Adam

Leonel Vicente Mota Ivo <leonel@atan.com.br> wrote:

In my system each process maps 3 or more shared memory segments at the same
time and as you have explained they will probably be mapped in a contiguous
way, so if one of the process misbehave and try to access past for example
the first segment it could corrupt the next one.
Is it possible to force this mapping to be in a disjuint virtual space in
order to improve the fault tolerance of my system?

You might get away with MAP_FIXED. This allows you to specify the
address they are put at.

But, it is my understanding that QNX4 does not allocate Process (virtual)
address space in a sparse manner, that is… if you pick a “high” address,
then QNX4 will set up a page table entry (with appropriate overhead costs)
for every empty page up to that “high” address as well.

So, if you have a fairly good idea of your system setup, and how these
processes will use allocated memory, you could probably do this.

Or, if none of these processes use a shared library (that is, they don’t
use Photon, QWindows, or TCP/IP libraries), you could play with the
undocumented -@ option to the compiler to move the base address of main
upwards in the virtual address of the process, and put your shared objects
at MAP_FIXED below this address. (Then, you know your heap won’t grow
up around them.)

Note: -@ specifies the offset to the low-address of code. Stack grows
downwards from this. You must specify:
+ + to -@ if you go this
route.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Thanks David for your support. I will try Adam’s suggestion of mapping a
readonly page after each of my shared object mapping.

Regards,

Leonel.

“David Gibbs” <dagibbs@qnx.com> wrote in message
news:blacup$emh$1@nntp.qnx.com

Leonel Vicente Mota Ivo <> leonel@atan.com.br> > wrote:

In my system each process maps 3 or more shared memory segments at the
same
time and as you have explained they will probably be mapped in a
contiguous
way, so if one of the process misbehave and try to access past for
example
the first segment it could corrupt the next one.
Is it possible to force this mapping to be in a disjuint virtual space
in
order to improve the fault tolerance of my system?

You might get away with MAP_FIXED. This allows you to specify the
address they are put at.

But, it is my understanding that QNX4 does not allocate Process (virtual)
address space in a sparse manner, that is… if you pick a “high” address,
then QNX4 will set up a page table entry (with appropriate overhead costs)
for every empty page up to that “high” address as well.

So, if you have a fairly good idea of your system setup, and how these
processes will use allocated memory, you could probably do this.

Or, if none of these processes use a shared library (that is, they don’t
use Photon, QWindows, or TCP/IP libraries), you could play with the
undocumented -@ option to the compiler to move the base address of main
upwards in the virtual address of the process, and put your shared objects
at MAP_FIXED below this address. (Then, you know your heap won’t grow
up around them.)

Note: -@ specifies the offset to the low-address of code. Stack grows
downwards from this. You must specify:
shared objects> + + to -@ if you go this
route.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Thanks Adam! I will do this.

Regards,

Leonel.

“Adam Mallory” <amallory@qnx.com> wrote in message
news:bla5u5$aso$1@nntp.qnx.com

Leonel Vicente Mota Ivo <> leonel@atan.com.br> > wrote in message
news:bl9vdg$8q$> 1@inn.qnx.com> …
Adam, I’ve just replied Dave before I saw your comment.

Now I realised that I couldn’t assume that. But at first I thought I
would
have individual protection.

Well, what you could do map in a readonly page after each of your shared
object mapping. If you happen to scribble past the end, you should cause
a
trap.

-Adam