14
14
#include <linux/audit.h>
15
15
#include <linux/sched/mm.h>
16
16
#include <linux/statfs.h>
17
+ #include <linux/stringhash.h>
17
18
18
19
#include "fanotify.h"
19
20
@@ -22,12 +23,24 @@ static bool fanotify_path_equal(struct path *p1, struct path *p2)
22
23
return p1 -> mnt == p2 -> mnt && p1 -> dentry == p2 -> dentry ;
23
24
}
24
25
26
+ static unsigned int fanotify_hash_path (const struct path * path )
27
+ {
28
+ return hash_ptr (path -> dentry , FANOTIFY_EVENT_HASH_BITS ) ^
29
+ hash_ptr (path -> mnt , FANOTIFY_EVENT_HASH_BITS );
30
+ }
31
+
25
32
static inline bool fanotify_fsid_equal (__kernel_fsid_t * fsid1 ,
26
33
__kernel_fsid_t * fsid2 )
27
34
{
28
35
return fsid1 -> val [0 ] == fsid2 -> val [0 ] && fsid1 -> val [1 ] == fsid2 -> val [1 ];
29
36
}
30
37
38
+ static unsigned int fanotify_hash_fsid (__kernel_fsid_t * fsid )
39
+ {
40
+ return hash_32 (fsid -> val [0 ], FANOTIFY_EVENT_HASH_BITS ) ^
41
+ hash_32 (fsid -> val [1 ], FANOTIFY_EVENT_HASH_BITS );
42
+ }
43
+
31
44
static bool fanotify_fh_equal (struct fanotify_fh * fh1 ,
32
45
struct fanotify_fh * fh2 )
33
46
{
@@ -38,6 +51,16 @@ static bool fanotify_fh_equal(struct fanotify_fh *fh1,
38
51
!memcmp (fanotify_fh_buf (fh1 ), fanotify_fh_buf (fh2 ), fh1 -> len );
39
52
}
40
53
54
+ static unsigned int fanotify_hash_fh (struct fanotify_fh * fh )
55
+ {
56
+ long salt = (long )fh -> type | (long )fh -> len << 8 ;
57
+
58
+ /*
59
+ * full_name_hash() works long by long, so it handles fh buf optimally.
60
+ */
61
+ return full_name_hash ((void * )salt , fanotify_fh_buf (fh ), fh -> len );
62
+ }
63
+
41
64
static bool fanotify_fid_event_equal (struct fanotify_fid_event * ffe1 ,
42
65
struct fanotify_fid_event * ffe2 )
43
66
{
@@ -325,7 +348,8 @@ static int fanotify_encode_fh_len(struct inode *inode)
325
348
* Return 0 on failure to encode.
326
349
*/
327
350
static int fanotify_encode_fh (struct fanotify_fh * fh , struct inode * inode ,
328
- unsigned int fh_len , gfp_t gfp )
351
+ unsigned int fh_len , unsigned int * hash ,
352
+ gfp_t gfp )
329
353
{
330
354
int dwords , type = 0 ;
331
355
char * ext_buf = NULL ;
@@ -368,6 +392,9 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
368
392
fh -> type = type ;
369
393
fh -> len = fh_len ;
370
394
395
+ /* Mix fh into event merge key */
396
+ * hash ^= fanotify_hash_fh (fh );
397
+
371
398
return FANOTIFY_FH_HDR_LEN + fh_len ;
372
399
373
400
out_err :
@@ -421,6 +448,7 @@ static struct inode *fanotify_dfid_inode(u32 event_mask, const void *data,
421
448
}
422
449
423
450
static struct fanotify_event * fanotify_alloc_path_event (const struct path * path ,
451
+ unsigned int * hash ,
424
452
gfp_t gfp )
425
453
{
426
454
struct fanotify_path_event * pevent ;
@@ -431,6 +459,7 @@ static struct fanotify_event *fanotify_alloc_path_event(const struct path *path,
431
459
432
460
pevent -> fae .type = FANOTIFY_EVENT_TYPE_PATH ;
433
461
pevent -> path = * path ;
462
+ * hash ^= fanotify_hash_path (path );
434
463
path_get (path );
435
464
436
465
return & pevent -> fae ;
@@ -456,6 +485,7 @@ static struct fanotify_event *fanotify_alloc_perm_event(const struct path *path,
456
485
457
486
static struct fanotify_event * fanotify_alloc_fid_event (struct inode * id ,
458
487
__kernel_fsid_t * fsid ,
488
+ unsigned int * hash ,
459
489
gfp_t gfp )
460
490
{
461
491
struct fanotify_fid_event * ffe ;
@@ -466,16 +496,18 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id,
466
496
467
497
ffe -> fae .type = FANOTIFY_EVENT_TYPE_FID ;
468
498
ffe -> fsid = * fsid ;
499
+ * hash ^= fanotify_hash_fsid (fsid );
469
500
fanotify_encode_fh (& ffe -> object_fh , id , fanotify_encode_fh_len (id ),
470
- gfp );
501
+ hash , gfp );
471
502
472
503
return & ffe -> fae ;
473
504
}
474
505
475
506
static struct fanotify_event * fanotify_alloc_name_event (struct inode * id ,
476
507
__kernel_fsid_t * fsid ,
477
- const struct qstr * file_name ,
508
+ const struct qstr * name ,
478
509
struct inode * child ,
510
+ unsigned int * hash ,
479
511
gfp_t gfp )
480
512
{
481
513
struct fanotify_name_event * fne ;
@@ -488,24 +520,30 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
488
520
size = sizeof (* fne ) + FANOTIFY_FH_HDR_LEN + dir_fh_len ;
489
521
if (child_fh_len )
490
522
size += FANOTIFY_FH_HDR_LEN + child_fh_len ;
491
- if (file_name )
492
- size += file_name -> len + 1 ;
523
+ if (name )
524
+ size += name -> len + 1 ;
493
525
fne = kmalloc (size , gfp );
494
526
if (!fne )
495
527
return NULL ;
496
528
497
529
fne -> fae .type = FANOTIFY_EVENT_TYPE_FID_NAME ;
498
530
fne -> fsid = * fsid ;
531
+ * hash ^= fanotify_hash_fsid (fsid );
499
532
info = & fne -> info ;
500
533
fanotify_info_init (info );
501
534
dfh = fanotify_info_dir_fh (info );
502
- info -> dir_fh_totlen = fanotify_encode_fh (dfh , id , dir_fh_len , 0 );
535
+ info -> dir_fh_totlen = fanotify_encode_fh (dfh , id , dir_fh_len , hash , 0 );
503
536
if (child_fh_len ) {
504
537
ffh = fanotify_info_file_fh (info );
505
- info -> file_fh_totlen = fanotify_encode_fh (ffh , child , child_fh_len , 0 );
538
+ info -> file_fh_totlen = fanotify_encode_fh (ffh , child ,
539
+ child_fh_len , hash , 0 );
540
+ }
541
+ if (name ) {
542
+ long salt = name -> len ;
543
+
544
+ fanotify_info_copy_name (info , name );
545
+ * hash ^= full_name_hash ((void * )salt , name -> name , name -> len );
506
546
}
507
- if (file_name )
508
- fanotify_info_copy_name (info , file_name );
509
547
510
548
pr_debug ("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n" ,
511
549
__func__ , id -> i_ino , size , dir_fh_len , child_fh_len ,
@@ -530,15 +568,16 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
530
568
struct inode * child = NULL ;
531
569
bool name_event = false;
532
570
unsigned int hash = 0 ;
571
+ bool ondir = mask & FAN_ONDIR ;
572
+ struct pid * pid ;
533
573
534
574
if ((fid_mode & FAN_REPORT_DIR_FID ) && dirid ) {
535
575
/*
536
576
* With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we
537
577
* report the child fid for events reported on a non-dir child
538
578
* in addition to reporting the parent fid and maybe child name.
539
579
*/
540
- if ((fid_mode & FAN_REPORT_FID ) &&
541
- id != dirid && !(mask & FAN_ONDIR ))
580
+ if ((fid_mode & FAN_REPORT_FID ) && id != dirid && !ondir )
542
581
child = id ;
543
582
544
583
id = dirid ;
@@ -559,8 +598,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
559
598
if (!(fid_mode & FAN_REPORT_NAME )) {
560
599
name_event = !!child ;
561
600
file_name = NULL ;
562
- } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS ) ||
563
- !(mask & FAN_ONDIR )) {
601
+ } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS ) || !ondir ) {
564
602
name_event = true;
565
603
}
566
604
}
@@ -583,28 +621,25 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
583
621
event = fanotify_alloc_perm_event (path , gfp );
584
622
} else if (name_event && (file_name || child )) {
585
623
event = fanotify_alloc_name_event (id , fsid , file_name , child ,
586
- gfp );
624
+ & hash , gfp );
587
625
} else if (fid_mode ) {
588
- event = fanotify_alloc_fid_event (id , fsid , gfp );
626
+ event = fanotify_alloc_fid_event (id , fsid , & hash , gfp );
589
627
} else {
590
- event = fanotify_alloc_path_event (path , gfp );
628
+ event = fanotify_alloc_path_event (path , & hash , gfp );
591
629
}
592
630
593
631
if (!event )
594
632
goto out ;
595
633
596
- /*
597
- * Use the victim inode instead of the watching inode as the id for
598
- * event queue, so event reported on parent is merged with event
599
- * reported on child when both directory and child watches exist.
600
- * Hash object id for queue merge.
601
- */
602
- hash = hash_ptr (id , FANOTIFY_EVENT_HASH_BITS );
603
- fanotify_init_event (event , hash , mask );
604
634
if (FAN_GROUP_FLAG (group , FAN_REPORT_TID ))
605
- event -> pid = get_pid (task_pid (current ));
635
+ pid = get_pid (task_pid (current ));
606
636
else
607
- event -> pid = get_pid (task_tgid (current ));
637
+ pid = get_pid (task_tgid (current ));
638
+
639
+ /* Mix event info, FAN_ONDIR flag and pid into event merge key */
640
+ hash ^= hash_long ((unsigned long )pid | ondir , FANOTIFY_EVENT_HASH_BITS );
641
+ fanotify_init_event (event , hash , mask );
642
+ event -> pid = pid ;
608
643
609
644
out :
610
645
set_active_memcg (old_memcg );
0 commit comments