@@ -88,6 +88,7 @@ struct upload_pack_data {
8888 enum allow_uor allow_uor ;
8989
9090 struct list_objects_filter_options filter_options ;
91+ struct string_list allowed_filters ;
9192
9293 struct packet_writer writer ;
9394
@@ -103,6 +104,8 @@ struct upload_pack_data {
103104 unsigned no_progress : 1 ;
104105 unsigned use_include_tag : 1 ;
105106 unsigned allow_filter : 1 ;
107+ unsigned allow_filter_fallback : 1 ;
108+ unsigned long tree_filter_max_depth ;
106109
107110 unsigned done : 1 ; /* v2 only */
108111 unsigned allow_ref_in_want : 1 ; /* v2 only */
@@ -120,6 +123,7 @@ static void upload_pack_data_init(struct upload_pack_data *data)
120123 struct string_list deepen_not = STRING_LIST_INIT_DUP ;
121124 struct string_list uri_protocols = STRING_LIST_INIT_DUP ;
122125 struct object_array extra_edge_obj = OBJECT_ARRAY_INIT ;
126+ struct string_list allowed_filters = STRING_LIST_INIT_DUP ;
123127
124128 memset (data , 0 , sizeof (* data ));
125129 data -> symref = symref ;
@@ -131,6 +135,9 @@ static void upload_pack_data_init(struct upload_pack_data *data)
131135 data -> deepen_not = deepen_not ;
132136 data -> uri_protocols = uri_protocols ;
133137 data -> extra_edge_obj = extra_edge_obj ;
138+ data -> allowed_filters = allowed_filters ;
139+ data -> allow_filter_fallback = 1 ;
140+ data -> tree_filter_max_depth = ULONG_MAX ;
134141 packet_writer_init (& data -> writer , 1 );
135142
136143 data -> keepalive = 5 ;
@@ -147,6 +154,7 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
147154 string_list_clear (& data -> deepen_not , 0 );
148155 object_array_clear (& data -> extra_edge_obj );
149156 list_objects_filter_release (& data -> filter_options );
157+ string_list_clear (& data -> allowed_filters , 1 );
150158
151159 free ((char * )data -> pack_objects_hook );
152160}
@@ -983,6 +991,63 @@ static int process_deepen_not(const char *line, struct string_list *deepen_not,
983991 return 0 ;
984992}
985993
994+ NORETURN __attribute__((format (printf ,2 ,3 )))
995+ static void send_err_and_die (struct upload_pack_data * data ,
996+ const char * fmt , ...)
997+ {
998+ struct strbuf buf = STRBUF_INIT ;
999+ va_list ap ;
1000+
1001+ va_start (ap , fmt );
1002+ strbuf_vaddf (& buf , fmt , ap );
1003+ va_end (ap );
1004+
1005+ packet_writer_error (& data -> writer , "%s" , buf .buf );
1006+ die ("%s" , buf .buf );
1007+ }
1008+
1009+ static void check_one_filter (struct upload_pack_data * data ,
1010+ struct list_objects_filter_options * opts )
1011+ {
1012+ const char * key = list_object_filter_config_name (opts -> choice );
1013+ struct string_list_item * item = string_list_lookup (& data -> allowed_filters ,
1014+ key );
1015+ int allowed ;
1016+
1017+ if (item )
1018+ allowed = (intptr_t )item -> util ;
1019+ else
1020+ allowed = data -> allow_filter_fallback ;
1021+
1022+ if (!allowed )
1023+ send_err_and_die (data , "filter '%s' not supported" , key );
1024+
1025+ if (opts -> choice == LOFC_TREE_DEPTH &&
1026+ opts -> tree_exclude_depth > data -> tree_filter_max_depth )
1027+ send_err_and_die (data ,
1028+ "tree filter allows max depth %lu, but got %lu" ,
1029+ data -> tree_filter_max_depth ,
1030+ opts -> tree_exclude_depth );
1031+ }
1032+
1033+ static void check_filter_recurse (struct upload_pack_data * data ,
1034+ struct list_objects_filter_options * opts )
1035+ {
1036+ size_t i ;
1037+
1038+ check_one_filter (data , opts );
1039+ if (opts -> choice != LOFC_COMBINE )
1040+ return ;
1041+
1042+ for (i = 0 ; i < opts -> sub_nr ; i ++ )
1043+ check_filter_recurse (data , & opts -> sub [i ]);
1044+ }
1045+
1046+ static void die_if_using_banned_filter (struct upload_pack_data * data )
1047+ {
1048+ check_filter_recurse (data , & data -> filter_options );
1049+ }
1050+
9861051static void receive_needs (struct upload_pack_data * data ,
9871052 struct packet_reader * reader )
9881053{
@@ -1013,6 +1078,7 @@ static void receive_needs(struct upload_pack_data *data,
10131078 die ("git upload-pack: filtering capability not negotiated" );
10141079 list_objects_filter_die_if_populated (& data -> filter_options );
10151080 parse_list_objects_filter (& data -> filter_options , arg );
1081+ die_if_using_banned_filter (data );
10161082 continue ;
10171083 }
10181084
@@ -1170,6 +1236,41 @@ static int find_symref(const char *refname, const struct object_id *oid,
11701236 return 0 ;
11711237}
11721238
1239+ static int parse_object_filter_config (const char * var , const char * value ,
1240+ struct upload_pack_data * data )
1241+ {
1242+ struct strbuf buf = STRBUF_INIT ;
1243+ const char * sub , * key ;
1244+ size_t sub_len ;
1245+
1246+ if (parse_config_key (var , "uploadpackfilter" , & sub , & sub_len , & key ))
1247+ return 0 ;
1248+
1249+ if (!sub ) {
1250+ if (!strcmp (key , "allow" ))
1251+ data -> allow_filter_fallback = git_config_bool (var , value );
1252+ return 0 ;
1253+ }
1254+
1255+ strbuf_add (& buf , sub , sub_len );
1256+
1257+ if (!strcmp (key , "allow" ))
1258+ string_list_insert (& data -> allowed_filters , buf .buf )-> util =
1259+ (void * )(intptr_t )git_config_bool (var , value );
1260+ else if (!strcmp (buf .buf , "tree" ) && !strcmp (key , "maxdepth" )) {
1261+ if (!value ) {
1262+ strbuf_release (& buf );
1263+ return config_error_nonbool (var );
1264+ }
1265+ string_list_insert (& data -> allowed_filters , buf .buf )-> util =
1266+ (void * )(intptr_t )1 ;
1267+ data -> tree_filter_max_depth = git_config_ulong (var , value );
1268+ }
1269+
1270+ strbuf_release (& buf );
1271+ return 0 ;
1272+ }
1273+
11731274static int upload_pack_config (const char * var , const char * value , void * cb_data )
11741275{
11751276 struct upload_pack_data * data = cb_data ;
@@ -1209,6 +1310,8 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data)
12091310 return git_config_string (& data -> pack_objects_hook , var , value );
12101311 }
12111312
1313+ parse_object_filter_config (var , value , data );
1314+
12121315 return parse_hide_refs_config (var , value , "uploadpack" );
12131316}
12141317
@@ -1389,6 +1492,7 @@ static void process_args(struct packet_reader *request,
13891492 if (data -> allow_filter && skip_prefix (arg , "filter " , & p )) {
13901493 list_objects_filter_die_if_populated (& data -> filter_options );
13911494 parse_list_objects_filter (& data -> filter_options , p );
1495+ die_if_using_banned_filter (data );
13921496 continue ;
13931497 }
13941498
0 commit comments