Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Change the unix VFS so that it refuses to open a database file using a file descriptor less than 3. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | overwrite-avoidance |
Files: | files | file ages | folders |
SHA1: |
66dddda06898abbf97fe0ac6a10ce152 |
User & Date: | drh 2013-08-29 23:34:53.402 |
Context
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) | |
23:34 | Change the unix VFS so that it refuses to open a database file using a file descriptor less than 3. (Closed-Leaf check-in: 66dddda068 user: drh tags: overwrite-avoidance) | |
21:26 | Never leave an open file descriptor pointing into the middle of the database file if the file descriptor number is 2 or less. (check-in: 3426673e46 user: drh tags: overwrite-avoidance) | |
Changes
Changes to src/os_unix.c.
︙ | ︙ | |||
546 547 548 549 550 551 552 553 554 555 556 557 558 559 | } } 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 | > > > > > > > > > > > > > > > > > > > > > > > > > | 546 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 | } } 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 |
︙ | ︙ | |||
573 574 575 576 577 578 579 | 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 | | < | 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 | 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 ){ osFchmod(fd, m); } } #if defined(FD_CLOEXEC) && (!defined(O_CLOEXEC) || O_CLOEXEC==0) osFcntl(fd, F_SETFD, osFcntl(fd, F_GETFD, 0) | FD_CLOEXEC); #endif } return fd; } |
︙ | ︙ | |||
3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 | int got; int prior = 0; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; assert( cnt==(cnt&0x1ffff) ); cnt &= 0x1ffff; do{ #if defined(USE_PREAD) got = osPread(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 ); #elif defined(USE_PREAD64) got = osPread64(id->h, pBuf, cnt, offset); | > | 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 | int got; int prior = 0; #if (!defined(USE_PREAD) && !defined(USE_PREAD64)) i64 newOffset; #endif TIMER_START; assert( cnt==(cnt&0x1ffff) ); assert( id->h>2 ); cnt &= 0x1ffff; do{ #if defined(USE_PREAD) got = osPread(id->h, pBuf, cnt, offset); SimulateIOError( got = -1 ); #elif defined(USE_PREAD64) got = osPread64(id->h, pBuf, cnt, offset); |
︙ | ︙ | |||
3130 3131 3132 3133 3134 3135 3136 | }else if( got>0 ){ cnt -= got; offset += got; prior += got; pBuf = (void*)(got + (char*)pBuf); } }while( got>0 ); | < | 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 | }else if( got>0 ){ cnt -= got; offset += got; prior += got; pBuf = (void*)(got + (char*)pBuf); } }while( got>0 ); TIMER_END; OSTRACE(("READ %-3d %5d %7lld %llu\n", id->h, got+prior, offset-prior, TIMER_ELAPSED)); return got+prior; } /* |
︙ | ︙ | |||
3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 | const void *pBuf, /* Copy data from this buffer to the file */ int nBuf, /* Size of buffer pBuf in bytes */ int *piErrno /* OUT: Error number if error occurs */ ){ int rc = 0; /* Value returned by system call */ assert( nBuf==(nBuf&0x1ffff) ); nBuf &= 0x1ffff; TIMER_START; #if defined(USE_PREAD) do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); #else do{ i64 iSeek = lseek(fd, iOff, SEEK_SET); SimulateIOError( iSeek-- ); if( iSeek!=iOff ){ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0); return -1; } rc = osWrite(fd, pBuf, nBuf); }while( rc<0 && errno==EINTR ); #endif | > < | 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 | const void *pBuf, /* Copy data from this buffer to the file */ int nBuf, /* Size of buffer pBuf in bytes */ int *piErrno /* OUT: Error number if error occurs */ ){ int rc = 0; /* Value returned by system call */ assert( nBuf==(nBuf&0x1ffff) ); assert( fd>2 ); nBuf &= 0x1ffff; TIMER_START; #if defined(USE_PREAD) do{ rc = osPwrite(fd, pBuf, nBuf, iOff); }while( rc<0 && errno==EINTR ); #elif defined(USE_PREAD64) do{ rc = osPwrite64(fd, pBuf, nBuf, iOff);}while( rc<0 && errno==EINTR); #else do{ i64 iSeek = lseek(fd, iOff, SEEK_SET); SimulateIOError( iSeek-- ); if( iSeek!=iOff ){ if( piErrno ) *piErrno = (iSeek==-1 ? errno : 0); return -1; } rc = osWrite(fd, pBuf, nBuf); }while( rc<0 && errno==EINTR ); #endif TIMER_END; OSTRACE(("WRITE %-3d %5d %7lld %llu\n", fd, rc, iOff, TIMER_ELAPSED)); if( rc<0 && piErrno ) *piErrno = errno; return rc; } |
︙ | ︙ |