delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/03/18/14:44:27

From: "Mark E." <snowball3 AT bigfoot DOT com>
To: djgpp-workers AT delorie DOT com
Date: Sun, 18 Mar 2001 14:44:05 -0500
MIME-Version: 1.0
Subject: Re: zero fill the eof gap 2.1
Message-ID: <3AB4C9B5.25069.91E3E5@localhost>
References: <3AB401CC DOT 27501 DOT 4C0CA2 AT localhost>
In-reply-to: <Pine.SUN.3.91.1010318113637.11615M-100000@is>
X-mailer: Pegasus Mail for Win32 (v3.12c)
Reply-To: djgpp-workers AT delorie DOT com

> Maybe a better option would be to leave _DEV_CDEV out of this, and
> instead provide a means to enable and disable the zero-fill on a
> by-handle basis?

I think that's a good idea. I made changes to do just that.

Index: src/docs/kb/wc204.txi
===================================================================
RCS file: /cvs/djgpp/djgpp/src/docs/kb/wc204.txi,v
retrieving revision 1.57
diff -c -p -r1.57 wc204.txi
*** wc204.txi	2001/03/18 16:52:41	1.57
--- wc204.txi	2001/03/18 19:42:22
*************** is disabled.  This solves the problem wi
*** 348,350 ****
--- 348,356 ----
  the @env{LFN} variable is set to @samp{n} because @code{stubify.exe}
  failed to rename the produced executable and reported @code{EINVAL}.
  
+ @findex write AT r{, security fix and increased POSIX compliance}
+ @findex _write AT r{, security fix}
+ When @code{write} and @code{_write} detect that a file pointer is past EOF,
+ that space will now be filled with zeroes to increase POSIX compliance
+ and plug a security hole on disks containing sensitive information.
+ 
Index: include/libc/fd_props.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/libc/fd_props.h,v
retrieving revision 1.1
diff -c -p -r1.1 fd_props.h
*** fd_props.h	2001/03/07 05:34:26	1.1
--- fd_props.h	2001/03/18 19:42:25
*************** extern "C" {
*** 13,20 ****
  #ifndef _POSIX_SOURCE
  
  /* Delete file when the last descriptor referencing it is closed.  */
! #define FILE_DESC_TEMPORARY 0x01
  
  typedef struct fd_properties fd_properties;
  
  struct fd_properties
--- 13,27 ----
  #ifndef _POSIX_SOURCE
  
  /* Delete file when the last descriptor referencing it is closed.  */
! #define FILE_DESC_TEMPORARY         0x01
  
+ /* Tell write and _write to test for file offset greater than EOF.  If so,
+    they will fill the gap with zeroes.  */
+ #define FILE_DESC_ZERO_FILL_EOF_GAP 0x02
+ 
+ /* Set when there can't be an EOF gap or it should be left alone.  */
+ #define FILE_DESC_DONT_FILL_EOF_GAP 0x04
+ 
  typedef struct fd_properties fd_properties;
  
  struct fd_properties
*************** void __dup_fd_properties(int _from, int 
*** 33,40 ****
  int __clear_fd_properties(int _fd);
  
  static __inline__ int __has_fd_properties(int _fd)
  {
!   return __fd_properties && __fd_properties[_fd];
  }
  
  #endif /* !_POSIX_SOURCE */
--- 40,57 ----
  int __clear_fd_properties(int _fd);
  
  static __inline__ int __has_fd_properties(int _fd)
+ {
+   return _fd >= 0 && __fd_properties && __fd_properties[_fd];
+ }
+ 
+ static __inline__ void __set_fd_flags(int _fd, unsigned long _flags)
+ {
+   __fd_properties[_fd]->flags |= _flags;  
+ }
+ 
+ static __inline__ void __clear_fd_flags(int _fd, unsigned long _flags)
  {
!   __fd_properties[_fd]->flags &= ~_flags;
  }
  
  #endif /* !_POSIX_SOURCE */
Index: src/libc/posix/unistd/lseek.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/lseek.c,v
retrieving revision 1.2
diff -c -p -r1.2 lseek.c
*** lseek.c	1998/06/28 17:29:36	1.2
--- lseek.c	2001/03/18 19:42:29
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  #include <libc/stubs.h>
***************
*** 7,17 ****
--- 8,21 ----
  #include <dpmi.h>
  #include <sys/fsext.h>
  #include <libc/dosio.h>
+ #include <libc/fd_props.h>
  
  off_t
  lseek(int handle, off_t offset, int whence)
  {
    __dpmi_regs r;
+   int has_props;
+   
    __FSEXT_Function *func = __FSEXT_get_function(handle);
    if (func)
    {
*************** lseek(int handle, off_t offset, int when
*** 30,35 ****
--- 34,54 ----
    {
      errno = __doserr_to_errno(r.x.ax);
      return -1;
+   }
+ 
+   has_props = __has_fd_properties(handle);
+   if (!has_props ||
+       (__fd_properties[handle]->flags & FILE_DESC_DONT_FILL_EOF_GAP) == 0)
+   {
+     if (offset > 0)
+     {
+       if (!has_props)
+         has_props = (__set_fd_properties(handle, NULL, 0) == 0);
+       if (has_props)
+         __set_fd_flags(handle, FILE_DESC_ZERO_FILL_EOF_GAP);
+     }
+     else if (has_props && (whence == SEEK_SET || whence == SEEK_END))
+       __clear_fd_flags(handle, FILE_DESC_ZERO_FILL_EOF_GAP);
    }
    return (r.x.dx << 16) + r.x.ax;
  }
Index: src/libc/compat/unistd/llseek.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/compat/unistd/llseek.c,v
retrieving revision 1.1
diff -c -p -r1.1 llseek.c
*** llseek.c	2000/06/19 18:00:56	1.1
--- llseek.c	2001/03/18 19:42:32
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /*
   * File llseek.c.
   *
***************
*** 14,25 ****
  #include <errno.h>
  #include <libc/dosio.h>
  #include <sys/fsext.h>
  
- 
  offset_t
  llseek( int handle, offset_t offset, int whence )
  {
    __dpmi_regs r;
  
    __FSEXT_Function *func = __FSEXT_get_function(handle);
    if( func )
--- 15,27 ----
  #include <errno.h>
  #include <libc/dosio.h>
  #include <sys/fsext.h>
+ #include <libc/fd_props.h>
  
  offset_t
  llseek( int handle, offset_t offset, int whence )
  {
    __dpmi_regs r;
+   int has_props;
  
    __FSEXT_Function *func = __FSEXT_get_function(handle);
    if( func )
*************** llseek( int handle, offset_t offset, int
*** 42,47 ****
--- 44,61 ----
      errno = __doserr_to_errno(r.x.ax);
      return -1;
    }
+ 
+   has_props = __has_fd_properties(handle);
+   if (offset > 0)
+   {
+     if (!has_props)
+       has_props = (__set_fd_properties(handle, NULL, 0) == 0);
+     if (has_props)
+       __set_fd_flags(handle, FILE_DESC_ZERO_FILL_EOF_GAP);
+   }
+   else if (has_props && (whence == SEEK_SET || whence == SEEK_END))
+     __clear_fd_flags(handle, FILE_DESC_ZERO_FILL_EOF_GAP);
+ 
    return( ( ( (unsigned)r.x.dx ) << 16) + r.x.ax );
  }
  
Index: src/libc/posix/unistd/write.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/write.c,v
retrieving revision 1.3
diff -c -p -r1.3 write.c
*** write.c	1997/08/31 17:49:14	1.3
--- write.c	2001/03/18 19:42:35
***************
*** 1,3 ****
--- 1,4 ----
+ /* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
***************
*** 12,31 ****
  #include <sys/fsext.h>
  #include <libc/dosio.h>
  #include <libc/ttyprvt.h>
  
  #define tblen _go32_info_block.size_of_transfer_buffer
  
  int (*__libc_write_termios_hook)(int handle, const void *buffer, size_t count,
  				 ssize_t *rv) = NULL;
  
  ssize_t
  write(int handle, const void* buffer, size_t count)
  {
    const char *buf = (const char *)buffer;
    int bytes_in_tb = 0;
    int offset_into_buf = 0;
!   __dpmi_regs r;
! 
    ssize_t rv;
    __FSEXT_Function *func = __FSEXT_get_function(handle);
  
--- 13,36 ----
  #include <sys/fsext.h>
  #include <libc/dosio.h>
  #include <libc/ttyprvt.h>
+ #include <libc/fd_props.h>
  
  #define tblen _go32_info_block.size_of_transfer_buffer
  
  int (*__libc_write_termios_hook)(int handle, const void *buffer, size_t count,
  				 ssize_t *rv) = NULL;
  
+ /* From _write.c. */
+ int _write_fill_seek_gap(int fd);
+ int _write_int(int fd, const char *buffer, size_t count);
+ 
  ssize_t
  write(int handle, const void* buffer, size_t count)
  {
    const char *buf = (const char *)buffer;
    int bytes_in_tb = 0;
    int offset_into_buf = 0;
!   int out;
    ssize_t rv;
    __FSEXT_Function *func = __FSEXT_get_function(handle);
  
*************** write(int handle, const void* buffer, si
*** 45,50 ****
--- 50,62 ----
       func(__FSEXT_write, &rv, &handle)) /* ... call extension ... */
        return rv;			/* ... and exit if handled. */
  
+   if (__has_fd_properties(handle)
+       && (__fd_properties[handle]->flags & FILE_DESC_ZERO_FILL_EOF_GAP))
+   {
+     if (_write_fill_seek_gap(handle) < 0)
+       return -1;
+   }
+   
    while (offset_into_buf < count)
    {
      _farsetsel(_dos_ds);
*************** write(int handle, const void* buffer, si
*** 62,87 ****
        offset_into_buf++;
      }
  
!     /* we now have a transfer buf stuffed with data; write it out */
!     r.x.ax = 0x4000;
!     r.x.bx = handle;
!     r.x.cx = bytes_in_tb;
!     r.x.dx = __tb & 15;
!     r.x.ds = __tb / 16;
!     __dpmi_int(0x21, &r);
!     if (r.x.flags & 1)
!     {
!       errno = __doserr_to_errno(r.x.ax);
        return -1;
!     }
! 
!     if (r.x.ax < bytes_in_tb) /* disk full? */
      {
!       offset_into_buf += r.x.ax;
        errno = ENOSPC;
        return count - offset_into_buf;
      }
! 
      bytes_in_tb = 0;
    }
  
--- 74,90 ----
        offset_into_buf++;
      }
  
!     /* Write out the contents of the transfer buffer. */
!     out = _write_int(handle, NULL, bytes_in_tb);
!     if (out < 0)
        return -1;
!     if (out < bytes_in_tb)
      {
!       offset_into_buf += out;
        errno = ENOSPC;
        return count - offset_into_buf;
      }
!     
      bytes_in_tb = 0;
    }
  
Index: src/libc/dos/io/_write.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/dos/io/_write.c,v
retrieving revision 1.3
diff -c -p -r1.3 _write.c
*** _write.c	1996/10/24 23:26:26	1.3
--- _write.c	2001/03/18 19:42:38
***************
*** 10,24 ****
  #include <sys/fsext.h>
  
  #include <libc/dosio.h>
  
  int
  _write(int handle, const void* buffer, size_t count)
  {
-   size_t j, i;
-   int nput;
-   unsigned long tbsize;
-   __dpmi_regs r;
- 
    __FSEXT_Function *func = __FSEXT_get_function(handle);
    if (func)
    {
--- 10,25 ----
  #include <sys/fsext.h>
  
  #include <libc/dosio.h>
+ #include <libc/fd_props.h>
+ #include <libc/farptrgs.h>
+ #include <libc/getdinfo.h>
  
+ int _write_fill_seek_gap(int fd);
+ int _write_int(int fd, const char *buffer, size_t count);
+ 
  int
  _write(int handle, const void* buffer, size_t count)
  {
    __FSEXT_Function *func = __FSEXT_get_function(handle);
    if (func)
    {
*************** _write(int handle, const void* buffer, s
*** 27,60 ****
        return rv;
    }
  
    tbsize = _go32_info_block.size_of_transfer_buffer;
!   nput = 0;
!   do {
!     j = (count <= tbsize) ? count : tbsize;
!     if (j)
!       dosmemput(buffer, j, __tb);
      r.x.ax = 0x4000;
!     r.x.bx = handle;
!     r.x.cx = j;
      r.x.dx = __tb & 15;
      r.x.ds = __tb / 16;
      __dpmi_int(0x21, &r);
      if (r.x.flags & 1)
      {
!       errno = __doserr_to_errno(r.x.ax);
        return -1;
      }
!     i = r.x.ax;
!     count -= i;
!     buffer = (void *)((int)buffer + i);
!     nput += i;
!   } while(count && (i == j));
  
!   if (count && nput == 0)
    {
      errno = ENOSPC;
      return -1;
    }
  
!   return nput;
  }
--- 28,154 ----
        return rv;
    }
  
+   if (__has_fd_properties(handle)
+       && (__fd_properties[handle]->flags & FILE_DESC_ZERO_FILL_EOF_GAP))
+   {
+     if (_write_fill_seek_gap(handle) < 0)
+       return -1;
+   }
+ 
+   return _write_int(handle, buffer, count);
+ }
+ 
+ /* If the file pointer offset is beyond EOF, fill the gap between EOF and
+    the file pointer offset with zeroes.  This emulates the behavior described
+    in the POSIX documentation for lseek.  */
+ int
+ _write_fill_seek_gap(int fd)
+ {
+   offset_t eof_off, cur_off, fill_count;
+   unsigned long tbsize, buf_size;
+   unsigned long i;
+   short fd_info;
+   
+   __clear_fd_flags(fd, FILE_DESC_ZERO_FILL_EOF_GAP);
+ 
+   /* Quit when there can't be an EOF gap or its existance doesn't matter.  */
+   if (__fd_properties[fd]->flags & FILE_DESC_DONT_FILL_EOF_GAP)
+     return 0;
+     
+   /* Quit when not working with a file.  */
+   fd_info = _get_dev_info(fd);
+   if (fd_info & (_DEV_STDIN | _DEV_STDOUT | _DEV_NUL))
+   {
+     /* Don't bother with handles that don't need the fix.  */
+     __fd_properties[fd]->flags |= FILE_DESC_DONT_FILL_EOF_GAP;
+     return 0;
+   }
+   
+   /* Quit when unable to get the file length.  */    
+   eof_off = lfilelength (fd);
+   if (eof_off < 0)
+     return 0;
+   
+   /* Quit when unable to get the current file offset.  */
+   cur_off = llseek (fd, 0, SEEK_CUR);
+   if (cur_off < 0)
+     return 0;
+ 
+   /* Quit if the current offset is not past EOF.  */
+   if (cur_off <= eof_off)
+     return 0;
+     
+   /* Quit when unable to seek to EOF.  */
+   if (llseek (fd, eof_off, SEEK_SET) == -1)
+     return 0;
+ 
+   /* Clear once again because the llseek call above will
+      set the fill test flag.  */
+   __clear_fd_flags(fd, FILE_DESC_ZERO_FILL_EOF_GAP);
+   
+   /* Fill the transfer buffer with zeros.  */
    tbsize = _go32_info_block.size_of_transfer_buffer;
!   fill_count = cur_off - eof_off;
! 
!   buf_size = (fill_count > tbsize) ? tbsize : fill_count;
! 
!   i = 0;
!   _farsetsel(_dos_ds);
!   while (i < buf_size)
!   {
!     _farnspokel(__tb + i, 0);
!     i += 4;
!   }
! 
!   /* Write out 'fill_count' number of zeros.  */
!   return _write_int(fd, NULL, fill_count);
! }
! 
! /* Write WRITE_COUNT bytes of data to the file associated with FD.
!    If BUFFER is not NULL, the data pointed to by BUFFER is put into the
!    transfer buffer and written out. Otherwise, the data already in the
!    transfer buffer is written out. */
! int
! _write_int(int fd, const char *buffer, size_t write_count)
! {
!   unsigned long buf_size, tb_size;
!   unsigned long chunk_count;
!   int total_written;
!   unsigned short bytes_written;
!   __dpmi_regs r;
!   
!   tb_size = _go32_info_block.size_of_transfer_buffer;
!   buf_size = (write_count > tb_size) ? tb_size : write_count;
!   
!   total_written = 0;
!   do
!   {
!     chunk_count = (write_count <= buf_size) ? write_count : buf_size;
!     if (buffer && chunk_count)
!       dosmemput(buffer, chunk_count, __tb);
      r.x.ax = 0x4000;
!     r.x.bx = fd;
!     r.x.cx = chunk_count;
      r.x.dx = __tb & 15;
      r.x.ds = __tb / 16;
      __dpmi_int(0x21, &r);
      if (r.x.flags & 1)
      {
!       errno =__doserr_to_errno(r.x.ax);
        return -1;
      }
!     bytes_written = r.x.ax;
!     write_count -= bytes_written;
!     total_written += bytes_written;
!     if (buffer)
!       buffer += bytes_written;
!   } while (write_count && (chunk_count == bytes_written));
  
!   if (write_count && total_written == 0)
    {
      errno = ENOSPC;
      return -1;
    }
  
!   return total_written;
  }

- Raw text -


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