SQLite

Check-in [d9c018f815]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improvements to the robust_open() logic in the unix VFS so that if an attempt is made to open a repository on file descriptors 0, 1, or 2, and blocking that file descriptor by opening it on /dev/null fails, then the open will fail.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d9c018f8155ab48df8e0e02519bba50588fe49fc
User & Date: drh 2013-08-30 06:20:23.091
Context
2013-08-30
13:29
Add a test for fts4 unicode61 option remove_diacritics=0. (check-in: 6bf7ae6ff6 user: dan tags: trunk)
06:20
Improvements to the robust_open() logic in the unix VFS so that if an attempt is made to open a repository on file descriptors 0, 1, or 2, and blocking that file descriptor by opening it on /dev/null fails, then the open will fail. (check-in: d9c018f815 user: drh tags: trunk)
2013-08-29
23:36
Make the unix VFS defensive against the error of having a database file open on file descriptors 1 or 2, as an error message might easily be written onto those file descriptors and thus overwrite and corrupt the database. (check-in: 30d38cc449 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_unix.c.
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599

600
601
602
603
604

605









606
607
608
609
610
611
612
  }
  for(i++; i<ArraySize(aSyscall); i++){
    if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
  }
  return 0;
}

/*
** If fd is a file descriptor that would be dangerous to use for an
** ordinary file, the close it, reopen it as /dev/null to get it out
** of the way, then return true.
**
** If fd is safe, return 0.
**
** It is dangerous to have a database file open of file descriptors 1 or
** 2 because those normally mean standard output and standard error.  Other
** components of the system might write directly to those file descriptors
** and overwrite parts of the database file.  Something like this happened
** on 2013-08-29 to the canonical Fossil repository when some error caused
** the database file to be opened on file descriptor 2 and later an assert()
** fired and wrote error message text into file descriptor 2, corrupting
** the repository.
*/
static int isReservedFd(int fd, const char *z, int f, int m){
  if( fd<0 || fd>2 ) return 0;
  sqlite3_log(SQLITE_WARNING,
              "attempt to open \"%s\" as file descriptor %d", z, fd);
  osClose(fd);
  (void)osOpen("/dev/null",f,m);
  return 1;
}

/*
** Invoke open().  Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite.  The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask.  If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files.  We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int robust_open(const char *z, int f, mode_t m){
  int fd;
  mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;
  do{

#if defined(O_CLOEXEC)
    fd = osOpen(z,f|O_CLOEXEC,m2);
#else
    fd = osOpen(z,f,m2);
#endif

  }while( (fd<0 && errno==EINTR) || isReservedFd(fd,z,f,m2) );









  if( fd>=0 ){
    if( m!=0 ){
      struct stat statbuf;
      if( osFstat(fd, &statbuf)==0 
       && statbuf.st_size==0
       && (statbuf.st_mode&0777)!=m 
      ){







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















<
>





>
|
>
>
>
>
>
>
>
>
>







547
548
549
550
551
552
553

























554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573

574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
  }
  for(i++; i<ArraySize(aSyscall); i++){
    if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
  }
  return 0;
}


























/*
** Invoke open().  Do so multiple times, until it either succeeds or
** fails for some reason other than EINTR.
**
** If the file creation mode "m" is 0 then set it to the default for
** SQLite.  The default is SQLITE_DEFAULT_FILE_PERMISSIONS (normally
** 0644) as modified by the system umask.  If m is not 0, then
** make the file creation mode be exactly m ignoring the umask.
**
** The m parameter will be non-zero only when creating -wal, -journal,
** and -shm files.  We want those files to have *exactly* the same
** permissions as their original database, unadulterated by the umask.
** In that way, if a database file is -rw-rw-rw or -rw-rw-r-, and a
** transaction crashes and leaves behind hot journals, then any
** process that is able to write to the database will also be able to
** recover the hot journals.
*/
static int robust_open(const char *z, int f, mode_t m){
  int fd;
  mode_t m2 = m ? m : SQLITE_DEFAULT_FILE_PERMISSIONS;

  while(1){
#if defined(O_CLOEXEC)
    fd = osOpen(z,f|O_CLOEXEC,m2);
#else
    fd = osOpen(z,f,m2);
#endif
    if( fd<0 ){
      if( errno==EINTR ) continue;
      break;
    }
    if( fd>2 ) break;
    osClose(fd);
    sqlite3_log(SQLITE_WARNING, 
                "attempt to open \"%s\" as file descriptor %d", z, fd);
    fd = -1;
    if( osOpen("/dev/null", f, m)<0 ) break;
  }
  if( fd>=0 ){
    if( m!=0 ){
      struct stat statbuf;
      if( osFstat(fd, &statbuf)==0 
       && statbuf.st_size==0
       && (statbuf.st_mode&0777)!=m 
      ){