@@ -64,6 +64,59 @@ struct header_writer_ctx
6464/* flags for frames with request headers */
6565#define HWC_REQUEST_HANDLING_FLAGS (HWC_SERVER|HWC_PUSH_PROMISE)
6666
67+
68+ /* Field name and value grammar: [RFC 9110] Sections 5.1 (Field Names),
69+ * 5.5 (Field Values), and 5.6.2 (Tokens).
70+ * Lowercase field names: [RFC 9113] Section 8.2 (HTTP Fields) and
71+ * [RFC 9114] Section 4.1.2 (Malformed Requests and Responses).
72+ */
73+ static const unsigned char is_tchar [0x100 ] =
74+ {
75+ ['0' ] = 1 , ['1' ] = 1 , ['2' ] = 1 , ['3' ] = 1 , ['4' ] = 1 , ['5' ] = 1 ,
76+ ['6' ] = 1 , ['7' ] = 1 , ['8' ] = 1 , ['9' ] = 1 , ['a' ] = 1 , ['b' ] = 1 ,
77+ ['c' ] = 1 , ['d' ] = 1 , ['e' ] = 1 , ['f' ] = 1 , ['g' ] = 1 , ['h' ] = 1 ,
78+ ['i' ] = 1 , ['j' ] = 1 , ['k' ] = 1 , ['l' ] = 1 , ['m' ] = 1 , ['n' ] = 1 ,
79+ ['o' ] = 1 , ['p' ] = 1 , ['q' ] = 1 , ['r' ] = 1 , ['s' ] = 1 , ['t' ] = 1 ,
80+ ['u' ] = 1 , ['v' ] = 1 , ['w' ] = 1 , ['x' ] = 1 , ['y' ] = 1 , ['z' ] = 1 ,
81+ ['!' ] = 1 , ['#' ] = 1 , ['$' ] = 1 , ['%' ] = 1 , ['&' ] = 1 , ['\'' ] = 1 ,
82+ ['*' ] = 1 , ['+' ] = 1 , ['-' ] = 1 , ['.' ] = 1 , ['^' ] = 1 , ['_' ] = 1 ,
83+ ['`' ] = 1 , ['|' ] = 1 , ['~' ] = 1 ,
84+ };
85+
86+
87+ static int
88+ valid_field_name (const char * name , unsigned name_len )
89+ {
90+ unsigned i ;
91+
92+ if (name_len == 0 )
93+ return 0 ;
94+
95+ for (i = 0 ; i < name_len ; ++ i )
96+ if (!is_tchar [(unsigned char ) name [i ]])
97+ return 0 ;
98+
99+ return 1 ;
100+ }
101+
102+
103+ static int
104+ valid_field_value (const char * val , unsigned val_len )
105+ {
106+ unsigned i ;
107+
108+ for (i = 0 ; i < val_len ; ++ i )
109+ if (!((unsigned char ) val [i ] == '\t' ||
110+ ((unsigned char ) val [i ] >= 0x20 && (unsigned char ) val [i ] <= 0x7E ) ||
111+ (unsigned char ) val [i ] >= 0x80 ))
112+ {
113+ return 0 ;
114+ }
115+
116+ return 1 ;
117+ }
118+
119+
67120static void *
68121h1h_create_header_set (void * ctx , lsquic_stream_t * stream , int is_push_promise )
69122{
@@ -147,6 +200,13 @@ add_pseudo_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
147200 name_len = xhdr -> name_len ;
148201 val_len = xhdr -> val_len ;
149202
203+ if (!valid_field_value (val , val_len ))
204+ {
205+ LSQ_INFO ("pseudo-header `%.*s' contains invalid characters" ,
206+ name_len , name );
207+ return 1 ;
208+ }
209+
150210 switch (name_len )
151211 {
152212 case 5 :
@@ -382,8 +442,6 @@ static int
382442add_real_header (struct header_writer_ctx * hwc , struct lsxpack_header * xhdr )
383443{
384444 int err ;
385- unsigned i ;
386- int n_upper ;
387445 const char * name , * val ;
388446 unsigned name_len , val_len ;
389447
@@ -399,6 +457,19 @@ add_real_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
399457 name_len = xhdr -> name_len ;
400458 val_len = xhdr -> val_len ;
401459
460+ if (!valid_field_name (name , name_len ))
461+ {
462+ LSQ_INFO ("invalid header name `%.*s'" , name_len , name );
463+ return 1 ;
464+ }
465+
466+ if (!valid_field_value (val , val_len ))
467+ {
468+ LSQ_INFO ("header `%.*s' contains invalid value characters" ,
469+ name_len , name );
470+ return 1 ;
471+ }
472+
402473 if (4 == name_len && 0 == memcmp (name , "host" , 4 ))
403474 {
404475 if (hwc -> pseh_mask & BIT (PSEH_AUTHORITY ))
@@ -410,16 +481,6 @@ add_real_header (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
410481 hwc -> hwc_flags |= HWC_SEEN_HOST ;
411482 }
412483
413- n_upper = 0 ;
414- for (i = 0 ; i < name_len ; ++ i )
415- n_upper += isupper (name [i ]);
416- if (n_upper > 0 )
417- {
418- LSQ_INFO ("Header name `%.*s' contains uppercase letters" ,
419- name_len , name );
420- return 1 ;
421- }
422-
423484 if (6 == name_len && memcmp (name , "cookie" , 6 ) == 0 )
424485 {
425486 return save_cookie (hwc , val , val_len );
@@ -453,6 +514,11 @@ add_header_to_uh (struct header_writer_ctx *hwc, struct lsxpack_header *xhdr)
453514 const char * name ;
454515
455516 name = lsxpack_header_get_name (xhdr );
517+ if (xhdr -> name_len == 0 )
518+ {
519+ LSQ_INFO ("empty header name" );
520+ return 1 ;
521+ }
456522 LSQ_DEBUG ("Got header '%.*s': '%.*s'" , (int ) xhdr -> name_len , name ,
457523 (int ) xhdr -> val_len , lsxpack_header_get_value (xhdr ));
458524 if (':' == name [0 ])
0 commit comments