Fossil

Check-in [a64e384f0c]
Login

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

Overview
Comment:When writing files to disk for a check-out, refuse to write through a symbolic link to a directory. Ticket [f9831fdef1d4edcc].
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | sec2020
Files: files | file ages | folders
SHA3-256: a64e384f0c53ddce4cc0b1f46a671c07917bf30d2367dbcede6101a76d0ce9d4
User & Date: drh 2020-08-18 12:17:39.566
Context
2020-08-19
01:07
Cherrypick key fixes from the sec2020 branch in order to devise a minimal patch to get us to version 2.12.1. check-in: fe1264d35d user: drh tags: sec2020-2.12-patch
2020-08-18
13:17
More missing db_unprotect() calls. check-in: 06d3789a2a user: drh tags: sec2020
12:17
When writing files to disk for a check-out, refuse to write through a symbolic link to a directory. Ticket [f9831fdef1d4edcc]. check-in: a64e384f0c user: drh tags: sec2020
02:58
More missing calls to db_unprotect(). check-in: 3ced48bdf8 user: drh tags: sec2020
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/file.c.
321
322
323
324
325
326
327









































328
329
330
331
332
333
334
** This routines RepoFILE - that zFilename is always a file under management.
**
** On Windows, always return False.
*/
int file_islink(const char *zFilename){
  return file_perm(zFilename, RepoFILE)==PERM_LNK;
}










































/*
** Return 1 if zFilename is a directory.  Return 0 if zFilename
** does not exist.  Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
** This routines RepoFILE - that zFilename is always a file under management.
**
** On Windows, always return False.
*/
int file_islink(const char *zFilename){
  return file_perm(zFilename, RepoFILE)==PERM_LNK;
}

/*
** Check every sub-directory of zRoot along the path to zFile.
** If any sub-directory is really an ordinary file or a symbolic link,
** then delete that object.  The inputs are expected to be full
** pathnames.
**
** Example:  Given inputs
**
**     zRoot = /home/alice/project1
**     zFile = /home/alice/project1/main/src/js/fileA.js
**
** Look for objects in the following order:
**
**      /home/alice/project/main
**      /home/alice/project/main/src
**      /home/alice/project/main/src/js
**
** If any of those objects exist and are something other than a directory
** then delete the object and return.
*/
void file_delete_objects_on_path(const char *zRoot, const char *zFile){
  int i = (int)strlen(zRoot);
  char *z = fossil_strdup(zFile);
  assert( fossil_strnicmp(zRoot, z, i)==0 );
  if( i && zRoot[i-1]=='/' ) i--;
  while( z[i]=='/' ){
    int j, rc;
    for(j=i+1; z[j] && z[j]!='/'; j++){}
    if( z[j]!='/' ) break;
    z[j] = 0;
    rc = file_isdir(z, SymFILE);
    if( rc!=1 ){
      if( rc==2 ) file_delete(z);
      break;
    }
    z[j] = '/';
    i = j;
  }
  fossil_free(z);
}

/*
** Return 1 if zFilename is a directory.  Return 0 if zFilename
** does not exist.  Return 2 if zFilename exists but is something
** other than a directory.
*/
int file_isdir(const char *zFilename, int eFType){
568
569
570
571
572
573
574
575



576
577
578
579
580
581
582
** zFilename is a symbolic link, it is the object that zFilename points
** to that is modified.
*/
int file_setexe(const char *zFilename, int onoff){
  int rc = 0;
#if !defined(_WIN32)
  struct stat buf;
  if( fossil_stat(zFilename, &buf, RepoFILE)!=0 || S_ISLNK(buf.st_mode) ){



    return 0;
  }
  if( onoff ){
    int targetMode = (buf.st_mode & 0444)>>2;
    if( (buf.st_mode & 0100)==0 ){
      chmod(zFilename, buf.st_mode | targetMode);
      rc = 1;







|
>
>
>







609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
** zFilename is a symbolic link, it is the object that zFilename points
** to that is modified.
*/
int file_setexe(const char *zFilename, int onoff){
  int rc = 0;
#if !defined(_WIN32)
  struct stat buf;
  if( fossil_stat(zFilename, &buf, RepoFILE)!=0 
   || S_ISLNK(buf.st_mode)
   || S_ISDIR(buf.st_mode)
  ){
    return 0;
  }
  if( onoff ){
    int targetMode = (buf.st_mode & 0444)>>2;
    if( (buf.st_mode & 0100)==0 ){
      chmod(zFilename, buf.st_mode | targetMode);
      rc = 1;
Changes to src/vfile.c.
337
338
339
340
341
342
343

344
345
346
347
348
349
350
        promptFlag = 0;
      } else if( cReply!='y' && cReply!='Y' ){
        blob_reset(&content);
        continue;
      }
    }
    if( verbose ) fossil_print("%s\n", &zName[nRepos]);

    if( file_isdir(zName, RepoFILE)==1 ){
      /*TODO(dchest): remove directories? */
      fossil_fatal("%s is directory, cannot overwrite", zName);
    }
    if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
      file_delete(zName);
    }







>







337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
        promptFlag = 0;
      } else if( cReply!='y' && cReply!='Y' ){
        blob_reset(&content);
        continue;
      }
    }
    if( verbose ) fossil_print("%s\n", &zName[nRepos]);
    file_delete_objects_on_path(g.zLocalRoot, zName);
    if( file_isdir(zName, RepoFILE)==1 ){
      /*TODO(dchest): remove directories? */
      fossil_fatal("%s is directory, cannot overwrite", zName);
    }
    if( file_size(zName, RepoFILE)>=0 && (isLink || file_islink(0)) ){
      file_delete(zName);
    }