@@ -36,7 +36,7 @@ use self::socket::{WebSocket, WsStream};
36
36
use super :: { events:: FileEventTx , IncomingFileEventTx } ;
37
37
use crate :: {
38
38
check,
39
- file:: { self , FileToRecv } ,
39
+ file:: { self , FileSubPath , FileToRecv } ,
40
40
protocol,
41
41
quarantine:: PathExt ,
42
42
service:: State ,
@@ -921,12 +921,7 @@ impl FileXferTask {
921
921
guard : AliveGuard ,
922
922
) {
923
923
let task = async {
924
- // Check file and dir names are shorter then MAX
925
- for name in self . file . subpath ( ) . iter ( ) {
926
- if name. len ( ) + MAX_FILE_SUFFIX_LEN > MAX_FILENAME_LENGTH {
927
- return Err ( Error :: FilenameTooLong ) ;
928
- }
929
- }
924
+ validate_subpath_for_download ( self . file . subpath ( ) ) ?;
930
925
931
926
let emit_checksum_events = {
932
927
if let Some ( threshold) = state. config . checksum_events_size_threshold {
@@ -1185,3 +1180,48 @@ pub fn remove_temp_files<P, I>(
1185
1180
fn temp_file_name ( transfer_id : uuid:: Uuid , file_id : & FileId ) -> String {
1186
1181
format ! ( "{}-{file_id}.dropdl-part" , transfer_id. as_simple( ) , )
1187
1182
}
1183
+
1184
+ /// Check file and dir names are shorter then MAX and contain illegal values
1185
+ fn validate_subpath_for_download ( subpath : & FileSubPath ) -> crate :: Result < ( ) > {
1186
+ const DISALLOWED : & [ & str ] = & [ ".." ] ;
1187
+
1188
+ for name in subpath. iter ( ) {
1189
+ if name. len ( ) + MAX_FILE_SUFFIX_LEN > MAX_FILENAME_LENGTH {
1190
+ return Err ( Error :: FilenameTooLong ) ;
1191
+ }
1192
+
1193
+ if DISALLOWED . contains ( & name. as_str ( ) ) {
1194
+ return Err ( Error :: BadPath (
1195
+ "File subpath contains disallowed element" . into ( ) ,
1196
+ ) ) ;
1197
+ }
1198
+ }
1199
+
1200
+ Ok ( ( ) )
1201
+ }
1202
+
1203
+ #[ cfg( test) ]
1204
+ mod tests {
1205
+ use crate :: file:: FileSubPath ;
1206
+
1207
+ #[ test]
1208
+ fn validate_subpath ( ) {
1209
+ let sp = FileSubPath :: from_path ( "abc/dfg/hjk.txt" ) . unwrap ( ) ;
1210
+ assert ! ( super :: validate_subpath_for_download( & sp) . is_ok( ) ) ;
1211
+
1212
+ let sp = FileSubPath :: from_path ( "abc/../hjk.txt" ) . unwrap ( ) ;
1213
+ assert ! ( matches!(
1214
+ super :: validate_subpath_for_download( & sp) ,
1215
+ Err ( crate :: Error :: BadPath ( ..) )
1216
+ ) ) ;
1217
+
1218
+ let mut path = String :: from ( "abc/" ) ;
1219
+ path. extend ( std:: iter:: repeat ( 'x' ) . take ( 251 ) ) ;
1220
+ path. push_str ( "/hjk.txt" ) ;
1221
+ let sp = FileSubPath :: from_path ( & path) . unwrap ( ) ;
1222
+ assert ! ( matches!(
1223
+ super :: validate_subpath_for_download( & sp) ,
1224
+ Err ( crate :: Error :: FilenameTooLong )
1225
+ ) ) ;
1226
+ }
1227
+ }
0 commit comments