@@ -665,6 +665,23 @@ struct ustring_buffer {
665
665
static __percpu struct ustring_buffer * ustring_per_cpu ;
666
666
667
667
static __always_inline char * test_string (char * str )
668
+ {
669
+ struct ustring_buffer * ubuf ;
670
+ char * kstr ;
671
+
672
+ if (!ustring_per_cpu )
673
+ return NULL ;
674
+
675
+ ubuf = this_cpu_ptr (ustring_per_cpu );
676
+ kstr = ubuf -> buffer ;
677
+
678
+ /* For safety, do not trust the string pointer */
679
+ if (!strncpy_from_kernel_nofault (kstr , str , USTRING_BUF_SIZE ))
680
+ return NULL ;
681
+ return kstr ;
682
+ }
683
+
684
+ static __always_inline char * test_ustring (char * str )
668
685
{
669
686
struct ustring_buffer * ubuf ;
670
687
char __user * ustr ;
@@ -676,23 +693,11 @@ static __always_inline char *test_string(char *str)
676
693
ubuf = this_cpu_ptr (ustring_per_cpu );
677
694
kstr = ubuf -> buffer ;
678
695
679
- /*
680
- * We use TASK_SIZE to denote user or kernel space, but this will
681
- * not work for all architectures. If it picks the wrong one, it may
682
- * just fail the filter (but will not bug).
683
- *
684
- * TODO: Have a way to properly denote which one this is for.
685
- */
686
- if (likely ((unsigned long )str >= TASK_SIZE )) {
687
- /* For safety, do not trust the string pointer */
688
- if (!strncpy_from_kernel_nofault (kstr , str , USTRING_BUF_SIZE ))
689
- return NULL ;
690
- } else {
691
- /* user space address? */
692
- ustr = (char __user * )str ;
693
- if (!strncpy_from_user_nofault (kstr , ustr , USTRING_BUF_SIZE ))
694
- return NULL ;
695
- }
696
+ /* user space address? */
697
+ ustr = (char __user * )str ;
698
+ if (!strncpy_from_user_nofault (kstr , ustr , USTRING_BUF_SIZE ))
699
+ return NULL ;
700
+
696
701
return kstr ;
697
702
}
698
703
@@ -709,24 +714,42 @@ static int filter_pred_string(struct filter_pred *pred, void *event)
709
714
return match ;
710
715
}
711
716
717
+ static __always_inline int filter_pchar (struct filter_pred * pred , char * str )
718
+ {
719
+ int cmp , match ;
720
+ int len ;
721
+
722
+ len = strlen (str ) + 1 ; /* including tailing '\0' */
723
+ cmp = pred -> regex .match (str , & pred -> regex , len );
724
+
725
+ match = cmp ^ pred -> not ;
726
+
727
+ return match ;
728
+ }
712
729
/* Filter predicate for char * pointers */
713
730
static int filter_pred_pchar (struct filter_pred * pred , void * event )
714
731
{
715
732
char * * addr = (char * * )(event + pred -> offset );
716
733
char * str ;
717
- int cmp , match ;
718
- int len ;
719
734
720
735
str = test_string (* addr );
721
736
if (!str )
722
737
return 0 ;
723
738
724
- len = strlen ( str ) + 1 ; /* including tailing '\0' */
725
- cmp = pred -> regex . match ( str , & pred -> regex , len );
739
+ return filter_pchar ( pred , str );
740
+ }
726
741
727
- match = cmp ^ pred -> not ;
742
+ /* Filter predicate for char * pointers in user space*/
743
+ static int filter_pred_pchar_user (struct filter_pred * pred , void * event )
744
+ {
745
+ char * * addr = (char * * )(event + pred -> offset );
746
+ char * str ;
728
747
729
- return match ;
748
+ str = test_ustring (* addr );
749
+ if (!str )
750
+ return 0 ;
751
+
752
+ return filter_pchar (pred , str );
730
753
}
731
754
732
755
/*
@@ -1232,6 +1255,7 @@ static int parse_pred(const char *str, void *data,
1232
1255
struct filter_pred * pred = NULL ;
1233
1256
char num_buf [24 ]; /* Big enough to hold an address */
1234
1257
char * field_name ;
1258
+ bool ustring = false;
1235
1259
char q ;
1236
1260
u64 val ;
1237
1261
int len ;
@@ -1266,6 +1290,12 @@ static int parse_pred(const char *str, void *data,
1266
1290
return - EINVAL ;
1267
1291
}
1268
1292
1293
+ /* See if the field is a user space string */
1294
+ if ((len = str_has_prefix (str + i , ".ustring" ))) {
1295
+ ustring = true;
1296
+ i += len ;
1297
+ }
1298
+
1269
1299
while (isspace (str [i ]))
1270
1300
i ++ ;
1271
1301
@@ -1405,7 +1435,10 @@ static int parse_pred(const char *str, void *data,
1405
1435
goto err_mem ;
1406
1436
}
1407
1437
1408
- pred -> fn = filter_pred_pchar ;
1438
+ if (ustring )
1439
+ pred -> fn = filter_pred_pchar_user ;
1440
+ else
1441
+ pred -> fn = filter_pred_pchar ;
1409
1442
}
1410
1443
/* go past the last quote */
1411
1444
i ++ ;
0 commit comments