Fossil SCM

Harden the synchronization process against sending or receiving settings flagged as sensitive. Mark the th1-setup setting as sensitive because it can contain not only th1, but also arbitrary TCL code if fossil is configured using --with-tcl. This addresses [forum:6179500deadf6ec7 | forum post 6179500dead].

stephan 2024-10-15 15:03 trunk
Commit 2ff87d4e0f7864117cf312ea4f42b8b3da7dd01a743c34c24a955bbecc4a494d
2 files changed +28 -9 +1 -1
+28 -9
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118118
{ "adunit-omit-if-user", CONFIGSET_SKIN },
119119
{ "default-csp", CONFIGSET_SKIN },
120120
{ "sitemap-extra", CONFIGSET_SKIN },
121121
{ "safe-html", CONFIGSET_SKIN },
122122
123
-#ifdef FOSSIL_ENABLE_TH1_DOCS
124
- { "th1-docs", CONFIGSET_TH1 },
125
-#endif
126123
#ifdef FOSSIL_ENABLE_TH1_HOOKS
127124
{ "th1-hooks", CONFIGSET_TH1 },
128125
#endif
129
- { "th1-setup", CONFIGSET_TH1 },
130126
{ "th1-uri-regexp", CONFIGSET_TH1 },
131127
132
-#ifdef FOSSIL_ENABLE_TCL
133
- { "tcl", CONFIGSET_TH1 },
134
- { "tcl-setup", CONFIGSET_TH1 },
135
-#endif
136
-
137128
{ "project-name", CONFIGSET_PROJ },
138129
{ "short-project-name", CONFIGSET_PROJ },
139130
{ "project-description", CONFIGSET_PROJ },
140131
{ "index-page", CONFIGSET_PROJ },
141132
{ "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
239230
**
240231
** "Safe" in the previous paragraph means the permission is granted to
241232
** export the property. In other words, the requesting side has presented
242233
** login credentials and has sufficient capabilities to access the requested
243234
** information.
235
+**
236
+** Settings which are specifically flagged as sensitive will (as of
237
+** 2024-10-15) cause this function to return 0, regardless of user
238
+** permissions. As an example, if the th1-setup setting were not
239
+** sensitive then a malicious repo admin could set that to include
240
+** arbitrary TCL code and affect users who configure fossil with the
241
+** --with-tcl flag.
244242
*/
245243
int configure_is_exportable(const char *zName){
246244
int i;
247245
int n = strlen(zName);
246
+ Setting *pSet;
248247
if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
248
+ char * zCpy;
249249
zName++;
250250
n -= 2;
251
+ zCpy = fossil_strndup(zName, (ssize_t)n);
252
+ pSet = db_find_setting(zCpy, 0);
253
+ fossil_free(zCpy);
254
+ }else{
255
+ pSet = db_find_setting(zName, 0);
256
+ }
257
+ if( pSet && pSet->sensitive ){
258
+ /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
259
+ return 0;
251260
}
252261
for(i=0; i<count(aConfig); i++){
253262
if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
254263
int m = aConfig[i].groupMask;
255264
if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
414423
if( nToken>=count(azToken)-1 ) break;
415424
}
416425
if( nToken<2 ) return;
417426
if( aType[ii].zName[0]=='/' ){
418427
thisMask = configure_is_exportable(azToken[1]);
428
+ if( 0==thisMask ){
429
+ fossil_warning("Skipping non-exportable setting: %s = %s",
430
+ azToken[1], nToken>3 ? azToken[3] : "?");
431
+ /* Will be skipped below */
432
+ }
419433
}else{
420434
thisMask = configure_is_exportable(aType[ii].zName);
421435
}
422436
if( (thisMask & groupMask)==0 ) return;
423437
if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
681695
}
682696
db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
683697
" WHERE name=:name AND mtime>=%lld", iStart);
684698
for(ii=0; ii<count(aConfig); ii++){
685699
if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
700
+ const Setting * pSet = db_find_setting(aConfig[ii].zName, 0);
701
+ if( pSet && pSet->sensitive ){
702
+ /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
703
+ continue;
704
+ }
686705
db_bind_text(&q, ":name", aConfig[ii].zName);
687706
while( db_step(&q)==SQLITE_ROW ){
688707
blob_appendf(&rec,"%s %s value %s",
689708
db_column_text(&q, 0),
690709
db_column_text(&q, 1),
691710
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118 { "adunit-omit-if-user", CONFIGSET_SKIN },
119 { "default-csp", CONFIGSET_SKIN },
120 { "sitemap-extra", CONFIGSET_SKIN },
121 { "safe-html", CONFIGSET_SKIN },
122
123 #ifdef FOSSIL_ENABLE_TH1_DOCS
124 { "th1-docs", CONFIGSET_TH1 },
125 #endif
126 #ifdef FOSSIL_ENABLE_TH1_HOOKS
127 { "th1-hooks", CONFIGSET_TH1 },
128 #endif
129 { "th1-setup", CONFIGSET_TH1 },
130 { "th1-uri-regexp", CONFIGSET_TH1 },
131
132 #ifdef FOSSIL_ENABLE_TCL
133 { "tcl", CONFIGSET_TH1 },
134 { "tcl-setup", CONFIGSET_TH1 },
135 #endif
136
137 { "project-name", CONFIGSET_PROJ },
138 { "short-project-name", CONFIGSET_PROJ },
139 { "project-description", CONFIGSET_PROJ },
140 { "index-page", CONFIGSET_PROJ },
141 { "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
239 **
240 ** "Safe" in the previous paragraph means the permission is granted to
241 ** export the property. In other words, the requesting side has presented
242 ** login credentials and has sufficient capabilities to access the requested
243 ** information.
 
 
 
 
 
 
 
244 */
245 int configure_is_exportable(const char *zName){
246 int i;
247 int n = strlen(zName);
 
248 if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
 
249 zName++;
250 n -= 2;
 
 
 
 
 
 
 
 
 
251 }
252 for(i=0; i<count(aConfig); i++){
253 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
254 int m = aConfig[i].groupMask;
255 if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
414 if( nToken>=count(azToken)-1 ) break;
415 }
416 if( nToken<2 ) return;
417 if( aType[ii].zName[0]=='/' ){
418 thisMask = configure_is_exportable(azToken[1]);
 
 
 
 
 
419 }else{
420 thisMask = configure_is_exportable(aType[ii].zName);
421 }
422 if( (thisMask & groupMask)==0 ) return;
423 if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
681 }
682 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
683 " WHERE name=:name AND mtime>=%lld", iStart);
684 for(ii=0; ii<count(aConfig); ii++){
685 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
 
 
 
 
 
686 db_bind_text(&q, ":name", aConfig[ii].zName);
687 while( db_step(&q)==SQLITE_ROW ){
688 blob_appendf(&rec,"%s %s value %s",
689 db_column_text(&q, 0),
690 db_column_text(&q, 1),
691
--- src/configure.c
+++ src/configure.c
@@ -118,24 +118,15 @@
118 { "adunit-omit-if-user", CONFIGSET_SKIN },
119 { "default-csp", CONFIGSET_SKIN },
120 { "sitemap-extra", CONFIGSET_SKIN },
121 { "safe-html", CONFIGSET_SKIN },
122
 
 
 
123 #ifdef FOSSIL_ENABLE_TH1_HOOKS
124 { "th1-hooks", CONFIGSET_TH1 },
125 #endif
 
126 { "th1-uri-regexp", CONFIGSET_TH1 },
127
 
 
 
 
 
128 { "project-name", CONFIGSET_PROJ },
129 { "short-project-name", CONFIGSET_PROJ },
130 { "project-description", CONFIGSET_PROJ },
131 { "index-page", CONFIGSET_PROJ },
132 { "manifest", CONFIGSET_PROJ },
@@ -239,17 +230,35 @@
230 **
231 ** "Safe" in the previous paragraph means the permission is granted to
232 ** export the property. In other words, the requesting side has presented
233 ** login credentials and has sufficient capabilities to access the requested
234 ** information.
235 **
236 ** Settings which are specifically flagged as sensitive will (as of
237 ** 2024-10-15) cause this function to return 0, regardless of user
238 ** permissions. As an example, if the th1-setup setting were not
239 ** sensitive then a malicious repo admin could set that to include
240 ** arbitrary TCL code and affect users who configure fossil with the
241 ** --with-tcl flag.
242 */
243 int configure_is_exportable(const char *zName){
244 int i;
245 int n = strlen(zName);
246 Setting *pSet;
247 if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){
248 char * zCpy;
249 zName++;
250 n -= 2;
251 zCpy = fossil_strndup(zName, (ssize_t)n);
252 pSet = db_find_setting(zCpy, 0);
253 fossil_free(zCpy);
254 }else{
255 pSet = db_find_setting(zName, 0);
256 }
257 if( pSet && pSet->sensitive ){
258 /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
259 return 0;
260 }
261 for(i=0; i<count(aConfig); i++){
262 if( strncmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){
263 int m = aConfig[i].groupMask;
264 if( !g.perm.Admin ){
@@ -414,10 +423,15 @@
423 if( nToken>=count(azToken)-1 ) break;
424 }
425 if( nToken<2 ) return;
426 if( aType[ii].zName[0]=='/' ){
427 thisMask = configure_is_exportable(azToken[1]);
428 if( 0==thisMask ){
429 fossil_warning("Skipping non-exportable setting: %s = %s",
430 azToken[1], nToken>3 ? azToken[3] : "?");
431 /* Will be skipped below */
432 }
433 }else{
434 thisMask = configure_is_exportable(aType[ii].zName);
435 }
436 if( (thisMask & groupMask)==0 ) return;
437 if( (thisMask & checkMask)!=0 ){
@@ -681,10 +695,15 @@
695 }
696 db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config"
697 " WHERE name=:name AND mtime>=%lld", iStart);
698 for(ii=0; ii<count(aConfig); ii++){
699 if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){
700 const Setting * pSet = db_find_setting(aConfig[ii].zName, 0);
701 if( pSet && pSet->sensitive ){
702 /* https://fossil-scm.org/forum/forumpost/6179500deadf6ec7 */
703 continue;
704 }
705 db_bind_text(&q, ":name", aConfig[ii].zName);
706 while( db_step(&q)==SQLITE_ROW ){
707 blob_appendf(&rec,"%s %s value %s",
708 db_column_text(&q, 0),
709 db_column_text(&q, 1),
710
+1 -1
--- src/db.c
+++ src/db.c
@@ -4967,11 +4967,11 @@
49674967
** If enabled, special TH1 commands will be called before and
49684968
** after any Fossil command or web page.
49694969
*/
49704970
#endif
49714971
/*
4972
-** SETTING: th1-setup width=40 block-text
4972
+** SETTING: th1-setup width=40 block-text sensitive
49734973
** This is the setup script to be evaluated after creating
49744974
** and initializing the TH1 interpreter. By default, this
49754975
** is empty and no extra setup is performed.
49764976
*/
49774977
/*
49784978
--- src/db.c
+++ src/db.c
@@ -4967,11 +4967,11 @@
4967 ** If enabled, special TH1 commands will be called before and
4968 ** after any Fossil command or web page.
4969 */
4970 #endif
4971 /*
4972 ** SETTING: th1-setup width=40 block-text
4973 ** This is the setup script to be evaluated after creating
4974 ** and initializing the TH1 interpreter. By default, this
4975 ** is empty and no extra setup is performed.
4976 */
4977 /*
4978
--- src/db.c
+++ src/db.c
@@ -4967,11 +4967,11 @@
4967 ** If enabled, special TH1 commands will be called before and
4968 ** after any Fossil command or web page.
4969 */
4970 #endif
4971 /*
4972 ** SETTING: th1-setup width=40 block-text sensitive
4973 ** This is the setup script to be evaluated after creating
4974 ** and initializing the TH1 interpreter. By default, this
4975 ** is empty and no extra setup is performed.
4976 */
4977 /*
4978

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button