2626#include <fluent-bit/flb_log_event_decoder.h>
2727#include <msgpack.h>
2828
29+ #include <ctype.h>
30+
2931#include <stdio.h>
32+ #include <string.h>
3033#include <sys/types.h>
3134#include <sys/stat.h>
3235#include <fcntl.h>
@@ -82,6 +85,96 @@ static char *check_delimiter(const char *str)
8285 return NULL ;
8386}
8487
88+ /*
89+ * Convert the user-controlled tag into a safe, relative path. Each component is
90+ * cleaned so only filesystem-friendly characters remain, ".." segments are
91+ * collapsed into a single underscore and leading separators are dropped to
92+ * guarantee the result stays within the configured base path.
93+ */
94+ static int sanitize_tag_name (const char * tag , char * buf , size_t size )
95+ {
96+ size_t i ;
97+ size_t out_len = 0 ;
98+ size_t component_len ;
99+ char sanitized_char ;
100+ const char * p ;
101+ const char * component_start ;
102+
103+ if (tag == NULL || buf == NULL || size < 2 ) {
104+ return -1 ;
105+ }
106+
107+ p = tag ;
108+
109+ while (* p != '\0' ) {
110+ component_len = 0 ;
111+ component_start = NULL ;
112+
113+ /* Skip consecutive separators so we never generate empty components */
114+ while (* p == '/' || * p == '\\' ) {
115+ p ++ ;
116+ }
117+
118+ if (* p == '\0' ) {
119+ break ;
120+ }
121+
122+ component_start = p ;
123+
124+ while (* p != '\0' && * p != '/' && * p != '\\' ) {
125+ component_len ++ ;
126+ p ++ ;
127+ }
128+
129+ if (component_len == 0 ) {
130+ continue ;
131+ }
132+
133+ if (out_len > 0 ) {
134+ if (out_len >= size - 1 ) {
135+ break ;
136+ }
137+
138+ buf [out_len ++ ] = FLB_PATH_SEPARATOR [0 ];
139+ }
140+
141+ if ((component_len == 1 && component_start [0 ] == '.' ) ||
142+ (component_len == 2 && component_start [0 ] == '.' && component_start [1 ] == '.' )) {
143+ if (out_len >= size - 1 ) {
144+ break ;
145+ }
146+
147+ buf [out_len ++ ] = '_' ;
148+ continue ;
149+ }
150+
151+ for (i = 0 ; i < component_len ; i ++ ) {
152+ sanitized_char = component_start [i ];
153+
154+ if (!isalnum ((unsigned char ) sanitized_char ) && sanitized_char != '-' &&
155+ sanitized_char != '_' && sanitized_char != '.' ) {
156+ sanitized_char = '_' ;
157+ }
158+
159+ if (out_len >= size - 1 ) {
160+ break ;
161+ }
162+
163+ buf [out_len ++ ] = sanitized_char ;
164+ }
165+ }
166+
167+ if (out_len == 0 ) {
168+ buf [0 ] = '_' ;
169+ buf [1 ] = '\0' ;
170+ return 0 ;
171+ }
172+
173+ buf [out_len ] = '\0' ;
174+
175+ return 0 ;
176+ }
177+
85178
86179static int cb_file_init (struct flb_output_instance * ins ,
87180 struct flb_config * config ,
@@ -502,7 +595,8 @@ static void cb_file_flush(struct flb_event_chunk *event_chunk,
502595 size_t last_off = 0 ;
503596 size_t alloc_size = 0 ;
504597 size_t total ;
505- char out_file [PATH_MAX ];
598+ char out_file [PATH_MAX * 2 ];
599+ char sanitized_tag [PATH_MAX ];
506600 char * buf ;
507601 long file_pos ;
508602 struct flb_file_conf * ctx = out_context ;
@@ -513,22 +607,33 @@ static void cb_file_flush(struct flb_event_chunk *event_chunk,
513607 (void ) config ;
514608
515609 /* Set the right output file */
610+ if (ctx -> out_file == NULL ) {
611+ ret = sanitize_tag_name (event_chunk -> tag ,
612+ sanitized_tag ,
613+ sizeof (sanitized_tag ));
614+
615+ if (ret != 0 ) {
616+ flb_plg_error (ctx -> ins , "failed to sanitize tag for output file" );
617+ FLB_OUTPUT_RETURN (FLB_ERROR );
618+ }
619+ }
620+
516621 if (ctx -> out_path ) {
517622 if (ctx -> out_file ) {
518- snprintf (out_file , PATH_MAX - 1 , "%s" FLB_PATH_SEPARATOR "%s" ,
623+ snprintf (out_file , sizeof ( out_file ) , "%s" FLB_PATH_SEPARATOR "%s" ,
519624 ctx -> out_path , ctx -> out_file );
520625 }
521626 else {
522- snprintf (out_file , PATH_MAX - 1 , "%s" FLB_PATH_SEPARATOR "%s" ,
523- ctx -> out_path , event_chunk -> tag );
627+ snprintf (out_file , sizeof ( out_file ) , "%s" FLB_PATH_SEPARATOR "%s" ,
628+ ctx -> out_path , sanitized_tag );
524629 }
525630 }
526631 else {
527632 if (ctx -> out_file ) {
528- snprintf (out_file , PATH_MAX - 1 , "%s" , ctx -> out_file );
633+ snprintf (out_file , PATH_MAX , "%s" , ctx -> out_file );
529634 }
530635 else {
531- snprintf (out_file , PATH_MAX - 1 , "%s" , event_chunk -> tag );
636+ snprintf (out_file , PATH_MAX , "%s" , sanitized_tag );
532637 }
533638 }
534639
0 commit comments