delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2007/04/09/07:46:10

X-Authentication-Warning: delorie.com: mail set sender to djgpp-bounces using -f
From: "Rod Pemberton" <do_not_have AT bitfoad DOT cmm>
Newsgroups: comp.os.msdos.djgpp
Subject: Re: protecting program memory
Date: Mon, 9 Apr 2007 07:43:19 -0400
Organization: Aioe.org NNTP Server
Lines: 141
Message-ID: <evd8sa$b0p$1@aioe.org>
References: <OF8FAF1ED8 DOT 483B1086-ON872572A7 DOT 0078F978-872572A7 DOT 007C4A14 AT seagate DOT com> <46074baf DOT sandmann AT clio DOT rice DOT edu> <1174904445 DOT 122516 DOT 65450 AT l75g2000hse DOT googlegroups DOT com>
NNTP-Posting-Host: IVw7K97ih4IohxRqyKkqFw.user.aioe.org
X-Complaints-To: abuse AT aioe DOT org
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1441
X-Priority: 3
X-Newsreader: Microsoft Outlook Express 6.00.2800.1437
X-MSMail-Priority: Normal
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp
Reply-To: djgpp AT delorie DOT com

"tim" <tim DOT nicholson AT skyforcekent DOT com> wrote in message
news:1174904445 DOT 122516 DOT 65450 AT l75g2000hse DOT googlegroups DOT com...
<snip>
>
> Maybe I have misunderstood something, but I tried the following and it
> did not do what I expected. If I understand correctly, this code
> should fall over with a protection fault when it attempts to execute
> the memset() function. It does not. It fails with a SIGSEGV when it
> attempts to execute the corrupted function. The mprotect() function is
> returning a zero suggesting that the memory was protected, but it is
> not preventing the write.
>

>It does not.
I'm not seeing that.  I'm using Win98SE (both Windows and v7.10 DOS) and
v2.03 of DJGPP.  But, I changed your program slightly...

> Any ideas?
>

Yes.

> #include <stdio.h>
> #include <string.h>
> #include <pc.h>
> #include <sys/types.h>
> #include <sys/mman.h>
> #include <keys.h>
>
> void a_function(void);
>
> int main (void)
> {
> char *ptr = (char*) a_function;

Casts of a function pointer to other types or objects are illegal in
standardized C.  Use '-pedantic' to catch this.  Change line to:

void (* ptr)(void);

>
> extern char*               _text  asm(".text");
> extern char*               _etext asm("etext");
> static char*               __my_progstart   = NULL;
> static size_t              __my_progsize    = 0;

int status;

>
>   __my_progstart = (char*) &_text;
>   __my_progsize = (&_etext - &_text) - sizeof(void*);
>
>
>   //protect the application memory and print the result of the
> mprotect function.
>   printf("%d - %d\n", mprotect(__my_progstart, __my_progsize,
> PROT_READ) , (int) __my_progsize);
>

I'd separate the printf() and mprotect() calls, and exit() if not a valid
status.  The mprotect() goes into prior to the printf().  So, the printf()
can cause a failure depending on PROT_NONE, PROT_READ, PROT_WRITE.  Change
the printf() line to:

  status = mprotect(__my_progstart, __my_progsize, PROT_WRITE);
  printf("%d - %d\n",status, (int) __my_progsize);
  if(status==-1)
  {
     printf("not all pages could be locked.\n");
     return(0);
  }

>   //wait for a key press.
>   getkey();
>
>   //call a_function - This should work fine.
>   a_function();
>
>   //corrupt the function, If all is well the program should crash here
> with a protection fault.
>   memset ((char*) ptr + 5, 0, 10);

All is not well here...  You can't legally cast function pointers in ANSI-C
(or ISO-C).  A cast of a function pointer to a 'void *' or a pointer to an
object is allowed under pre-ANSI-C, though.  You can legally assign function
pointer or zero to a another function pointer.  Again, '-pedantic' will warn
about this.  Change the memset() line to:

  ptr = &a_function; /* legal in ANSI-C if ptr is a function pointer */
    /* the 'void *' cast of a function pointer below isn't legal in ANSI-C
*/
    /* conversion to 'void *' is valid in non-ANSI C */
  memset ((unsigned char *)(((unsigned long)(void *)ptr) + 5), 0, 10);

I.e., the 'void *' is the only allowable cast for a function pointer (for
non-ANSI-C).  The 'unsigned long' cast is to be able to perform arithmetic
since arithmetic isn't allowed on 'void *' types.  The 'unsigned char *'
cast is to convert the resultant value to an address pointer, a byte in
size, for memset().  A standardized C byte is the minimal addressable group
of bits, not 8-bits as defined everywhere else.

>   //If the protection worked, this line should not get printed!
>   printf ("The function is now broken!\n");
>
>   //try calling the function again, It will crash because if it
> corrupt
>   a_function();
>
>   return (0);
> }
>
>
> void a_function(void)
> {
> int a = 10;
> int b = 20;
> int c = 30;
> int d = 40;
>
>
>    printf ("a=%d; b=%d, c=%d, d=%d\n",a,b,c,d);
> }
>

Once, those changes are made.  I get the following under DOS (v7.10 for
Win98SE, using CWSDPMI r5):

  PROT_NONE causes PAGE_FAULT after mprotect()
  PROT_READ causes PAGE_FAULT on memset()
  PROT_WRITE causes SIG_SEGV on second call to a_function(), followed by
PAGE_FAULT

Of course, in a Win98SE command prompt (using Windows DPMI, not CWSDPMI), it
exits properly with the -1 return from mprotect() as "not all pages could be
locked."


Rod Pemberton


- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019