SQLite

Check-in [745a9a7fef]
Login

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

Overview
Comment:Fix some crashes in the sqlite3changeset_apply() function that could be caused by corrupt changeset blobs.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 745a9a7fef0f28a57ea3f44899058993f6ecdedda52c81a09a4a9ce09c9004d6
User & Date: dan 2018-03-01 12:05:51.293
Context
2018-03-01
15:20
Fix further crashes in sqlite3changeset_apply() caused by corrupt changeset blobs. (check-in: 2c01c72e35 user: dan tags: trunk)
13:44
Merge the latest enhancements from trunk. (check-in: c8083de14b user: drh tags: memdb)
12:05
Fix some crashes in the sqlite3changeset_apply() function that could be caused by corrupt changeset blobs. (check-in: 745a9a7fef user: dan tags: trunk)
2018-02-28
22:21
Enhance the sessions documentation to show the methods of the various objects. (check-in: e01177754a user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/session/session4.test.
59
60
61
62
63
64
65

























66
67
  list [catch { sqlite3changeset_invert $x } msg] $msg
} {1 SQLITE_CORRUPT}

do_test 1.3 {
  set x [binary format "ca*" 0 [string range $changeset 1 end]]
  list [catch { sqlite3changeset_apply db $x xConflict } msg] $msg
} {1 SQLITE_CORRUPT}


























finish_test







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


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  list [catch { sqlite3changeset_invert $x } msg] $msg
} {1 SQLITE_CORRUPT}

do_test 1.3 {
  set x [binary format "ca*" 0 [string range $changeset 1 end]]
  list [catch { sqlite3changeset_apply db $x xConflict } msg] $msg
} {1 SQLITE_CORRUPT}

#-------------------------------------------------------------------------
reset_db
do_execsql_test 2.0 {
  CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d);
  CREATE TABLE t2(e TEXT PRIMARY KEY NOT NULL,f,g);
  CREATE TABLE t3(w REAL PRIMARY KEY NOT NULL,x,y);
  CREATE TABLE t4(z PRIMARY KEY) WITHOUT ROWID;
}

foreach {tn blob} {
  1 {54010174340012000000}
  2 {54fefe8bcb0012000300}
  3 {5480809280808001017434001200fb}
  4 {50af9c939c9c9cb09c9c6400b09c9c6400}
  5 {12000300}
  6 {09847304}
  7 {5401017434001208}
} {
if {$tn==7} breakpoint
  do_test 2.$tn {
    set changeset [binary decode hex $blob]
    list [catch { sqlite3changeset_apply db $changeset xConflict } msg] $msg
  } {1 SQLITE_CORRUPT}
}

finish_test
Changes to ext/session/sqlite3session.c.
2714
2715
2716
2717
2718
2719
2720



2721

2722
2723
2724
2725
2726
2727
2728
2729

2730
2731
2732
2733
2734
2735
2736
){
  int i;                          /* Used to iterate through columns */
  int rc = SQLITE_OK;

  for(i=0; i<nCol && rc==SQLITE_OK; i++){
    int eType = 0;                /* Type of value (SQLITE_NULL, TEXT etc.) */
    if( abPK && abPK[i]==0 ) continue;



    rc = sessionInputBuffer(pIn, 9);

    if( rc==SQLITE_OK ){
      eType = pIn->aData[pIn->iNext++];
    }

    assert( apOut[i]==0 );
    if( eType ){
      apOut[i] = sqlite3ValueNew(0);
      if( !apOut[i] ) rc = SQLITE_NOMEM;

    }

    if( rc==SQLITE_OK ){
      u8 *aVal = &pIn->aData[pIn->iNext];
      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
        int nByte;
        pIn->iNext += sessionVarintGet(aVal, &nByte);







>
>
>
|
>


<
<
|
|
|
|
>







2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727


2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
){
  int i;                          /* Used to iterate through columns */
  int rc = SQLITE_OK;

  for(i=0; i<nCol && rc==SQLITE_OK; i++){
    int eType = 0;                /* Type of value (SQLITE_NULL, TEXT etc.) */
    if( abPK && abPK[i]==0 ) continue;
    if( pIn->iNext>=pIn->nData ){
      rc = SQLITE_CORRUPT;
    }else{
      rc = sessionInputBuffer(pIn, 9);
    }
    if( rc==SQLITE_OK ){
      eType = pIn->aData[pIn->iNext++];


      assert( apOut[i]==0 );
      if( eType ){
        apOut[i] = sqlite3ValueNew(0);
        if( !apOut[i] ) rc = SQLITE_NOMEM;
      }
    }

    if( rc==SQLITE_OK ){
      u8 *aVal = &pIn->aData[pIn->iNext];
      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
        int nByte;
        pIn->iNext += sessionVarintGet(aVal, &nByte);
2853
2854
2855
2856
2857
2858
2859

2860
2861
2862
2863
2864



2865
2866
2867
2868
2869
2870
2871
  assert( p->rc==SQLITE_OK );

  rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
  if( rc==SQLITE_OK ){
    int nByte;
    int nVarint;
    nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);

    nCopy -= nVarint;
    p->in.iNext += nVarint;
    nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
    p->tblhdr.nBuf = 0;
    sessionBufferGrow(&p->tblhdr, nByte, &rc);



  }

  if( rc==SQLITE_OK ){
    int iPK = sizeof(sqlite3_value*)*p->nCol*2;
    memset(p->tblhdr.aBuf, 0, iPK);
    memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
    p->in.iNext += nCopy;







>
|
|
|
|
|
>
>
>







2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
  assert( p->rc==SQLITE_OK );

  rc = sessionChangesetBufferTblhdr(&p->in, &nCopy);
  if( rc==SQLITE_OK ){
    int nByte;
    int nVarint;
    nVarint = sessionVarintGet(&p->in.aData[p->in.iNext], &p->nCol);
    if( p->nCol>0 ){
      nCopy -= nVarint;
      p->in.iNext += nVarint;
      nByte = p->nCol * sizeof(sqlite3_value*) * 2 + nCopy;
      p->tblhdr.nBuf = 0;
      sessionBufferGrow(&p->tblhdr, nByte, &rc);
    }else{
      rc = SQLITE_CORRUPT;
    }
  }

  if( rc==SQLITE_OK ){
    int iPK = sizeof(sqlite3_value*)*p->nCol*2;
    memset(p->tblhdr.aBuf, 0, iPK);
    memcpy(&p->tblhdr.aBuf[iPK], &p->in.aData[p->in.iNext], nCopy);
    p->in.iNext += nCopy;
2934
2935
2936
2937
2938
2939
2940







2941
2942
2943
2944
2945
2946
2947
    p->bPatchset = (op=='P');
    if( sessionChangesetReadTblhdr(p) ) return p->rc;
    if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
    p->in.iCurrent = p->in.iNext;
    if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
    op = p->in.aData[p->in.iNext++];
  }








  p->op = op;
  p->bIndirect = p->in.aData[p->in.iNext++];
  if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
    return (p->rc = SQLITE_CORRUPT_BKPT);
  }








>
>
>
>
>
>
>







2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
    p->bPatchset = (op=='P');
    if( sessionChangesetReadTblhdr(p) ) return p->rc;
    if( (p->rc = sessionInputBuffer(&p->in, 2)) ) return p->rc;
    p->in.iCurrent = p->in.iNext;
    if( p->in.iNext>=p->in.nData ) return SQLITE_DONE;
    op = p->in.aData[p->in.iNext++];
  }

  if( p->zTab==0 ){
    /* The first record in the changeset is not a table header. Must be a
    ** corrupt changeset. */
    assert( p->in.iNext==1 );
    return (p->rc = SQLITE_CORRUPT_BKPT);
  }

  p->op = op;
  p->bIndirect = p->in.aData[p->in.iNext++];
  if( p->op!=SQLITE_UPDATE && p->op!=SQLITE_DELETE && p->op!=SQLITE_INSERT ){
    return (p->rc = SQLITE_CORRUPT_BKPT);
  }

3704
3705
3706
3707
3708
3709
3710





3711

3712
3713
3714
3715
3716
3717
3718
  ** in the code below. */
  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );

  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    if( !abPK || abPK[i] ){
      sqlite3_value *pVal;
      (void)xValue(pIter, i, &pVal);





      rc = sessionBindValue(pStmt, i+1, pVal);

    }
  }
  return rc;
}

/*
** SQL statement pSelect is as generated by the sessionSelectRow() function.







>
>
>
>
>
|
>







3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
  ** in the code below. */
  assert( xValue==sqlite3changeset_old || xValue==sqlite3changeset_new );

  for(i=0; rc==SQLITE_OK && i<nCol; i++){
    if( !abPK || abPK[i] ){
      sqlite3_value *pVal;
      (void)xValue(pIter, i, &pVal);
      if( pVal==0 ){
        /* The value in the changeset was "undefined". This indicates a
        ** corrupt changeset blob.  */
        rc = SQLITE_CORRUPT;
      }else{
        rc = sessionBindValue(pStmt, i+1, pVal);
      }
    }
  }
  return rc;
}

/*
** SQL statement pSelect is as generated by the sessionSelectRow() function.