@@ -60,11 +60,12 @@ typedef struct {
60
60
char * name ;
61
61
struct dentry * dentry ;
62
62
struct file * interp_file ;
63
- refcount_t users ; /* sync removal with load_misc_binary() */
64
63
} Node ;
65
64
66
65
static DEFINE_RWLOCK (entries_lock );
67
66
static struct file_system_type bm_fs_type ;
67
+ static struct vfsmount * bm_mnt ;
68
+ static int entry_count ;
68
69
69
70
/*
70
71
* Max length of the register string. Determined by:
@@ -81,23 +82,19 @@ static struct file_system_type bm_fs_type;
81
82
*/
82
83
#define MAX_REGISTER_LENGTH 1920
83
84
84
- /**
85
- * search_binfmt_handler - search for a binary handler for @bprm
86
- * @misc: handle to binfmt_misc instance
87
- * @bprm: binary for which we are looking for a handler
88
- *
89
- * Search for a binary type handler for @bprm in the list of registered binary
90
- * type handlers.
91
- *
92
- * Return: binary type list entry on success, NULL on failure
85
+ /*
86
+ * Check if we support the binfmt
87
+ * if we do, return the node, else NULL
88
+ * locking is done in load_misc_binary
93
89
*/
94
- static Node * search_binfmt_handler (struct linux_binprm * bprm )
90
+ static Node * check_file (struct linux_binprm * bprm )
95
91
{
96
92
char * p = strrchr (bprm -> interp , '.' );
97
- Node * e ;
93
+ struct list_head * l ;
98
94
99
95
/* Walk all the registered handlers. */
100
- list_for_each_entry (e , & entries , list ) {
96
+ list_for_each (l , & entries ) {
97
+ Node * e = list_entry (l , Node , list );
101
98
char * s ;
102
99
int j ;
103
100
@@ -126,49 +123,9 @@ static Node *search_binfmt_handler(struct linux_binprm *bprm)
126
123
if (j == e -> size )
127
124
return e ;
128
125
}
129
-
130
126
return NULL ;
131
127
}
132
128
133
- /**
134
- * get_binfmt_handler - try to find a binary type handler
135
- * @misc: handle to binfmt_misc instance
136
- * @bprm: binary for which we are looking for a handler
137
- *
138
- * Try to find a binfmt handler for the binary type. If one is found take a
139
- * reference to protect against removal via bm_{entry,status}_write().
140
- *
141
- * Return: binary type list entry on success, NULL on failure
142
- */
143
- static Node * get_binfmt_handler (struct linux_binprm * bprm )
144
- {
145
- Node * e ;
146
-
147
- read_lock (& entries_lock );
148
- e = search_binfmt_handler (bprm );
149
- if (e )
150
- refcount_inc (& e -> users );
151
- read_unlock (& entries_lock );
152
- return e ;
153
- }
154
-
155
- /**
156
- * put_binfmt_handler - put binary handler node
157
- * @e: node to put
158
- *
159
- * Free node syncing with load_misc_binary() and defer final free to
160
- * load_misc_binary() in case it is using the binary type handler we were
161
- * requested to remove.
162
- */
163
- static void put_binfmt_handler (Node * e )
164
- {
165
- if (refcount_dec_and_test (& e -> users )) {
166
- if (e -> flags & MISC_FMT_OPEN_FILE )
167
- filp_close (e -> interp_file , NULL );
168
- kfree (e );
169
- }
170
- }
171
-
172
129
/*
173
130
* the loader itself
174
131
*/
@@ -182,7 +139,12 @@ static int load_misc_binary(struct linux_binprm *bprm)
182
139
if (!enabled )
183
140
return retval ;
184
141
185
- fmt = get_binfmt_handler (bprm );
142
+ /* to keep locking time low, we copy the interpreter string */
143
+ read_lock (& entries_lock );
144
+ fmt = check_file (bprm );
145
+ if (fmt )
146
+ dget (fmt -> dentry );
147
+ read_unlock (& entries_lock );
186
148
if (!fmt )
187
149
return retval ;
188
150
@@ -236,16 +198,7 @@ static int load_misc_binary(struct linux_binprm *bprm)
236
198
237
199
retval = 0 ;
238
200
ret :
239
-
240
- /*
241
- * If we actually put the node here all concurrent calls to
242
- * load_misc_binary() will have finished. We also know
243
- * that for the refcount to be zero ->evict_inode() must have removed
244
- * the node to be deleted from the list. All that is left for us is to
245
- * close and free.
246
- */
247
- put_binfmt_handler (fmt );
248
-
201
+ dput (fmt -> dentry );
249
202
return retval ;
250
203
}
251
204
@@ -600,90 +553,30 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
600
553
return inode ;
601
554
}
602
555
603
- /**
604
- * bm_evict_inode - cleanup data associated with @inode
605
- * @inode: inode to which the data is attached
606
- *
607
- * Cleanup the binary type handler data associated with @inode if a binary type
608
- * entry is removed or the filesystem is unmounted and the super block is
609
- * shutdown.
610
- *
611
- * If the ->evict call was not caused by a super block shutdown but by a write
612
- * to remove the entry or all entries via bm_{entry,status}_write() the entry
613
- * will have already been removed from the list. We keep the list_empty() check
614
- * to make that explicit.
615
- */
616
556
static void bm_evict_inode (struct inode * inode )
617
557
{
618
558
Node * e = inode -> i_private ;
619
559
620
- clear_inode (inode );
560
+ if (e && e -> flags & MISC_FMT_OPEN_FILE )
561
+ filp_close (e -> interp_file , NULL );
621
562
622
- if (e ) {
623
- write_lock (& entries_lock );
624
- if (!list_empty (& e -> list ))
625
- list_del_init (& e -> list );
626
- write_unlock (& entries_lock );
627
- put_binfmt_handler (e );
628
- }
563
+ clear_inode (inode );
564
+ kfree (e );
629
565
}
630
566
631
- /**
632
- * unlink_binfmt_dentry - remove the dentry for the binary type handler
633
- * @dentry: dentry associated with the binary type handler
634
- *
635
- * Do the actual filesystem work to remove a dentry for a registered binary
636
- * type handler. Since binfmt_misc only allows simple files to be created
637
- * directly under the root dentry of the filesystem we ensure that we are
638
- * indeed passed a dentry directly beneath the root dentry, that the inode
639
- * associated with the root dentry is locked, and that it is a regular file we
640
- * are asked to remove.
641
- */
642
- static void unlink_binfmt_dentry (struct dentry * dentry )
567
+ static void kill_node (Node * e )
643
568
{
644
- struct dentry * parent = dentry -> d_parent ;
645
- struct inode * inode , * parent_inode ;
646
-
647
- /* All entries are immediate descendants of the root dentry. */
648
- if (WARN_ON_ONCE (dentry -> d_sb -> s_root != parent ))
649
- return ;
650
-
651
- /* We only expect to be called on regular files. */
652
- inode = d_inode (dentry );
653
- if (WARN_ON_ONCE (!S_ISREG (inode -> i_mode )))
654
- return ;
655
-
656
- /* The parent inode must be locked. */
657
- parent_inode = d_inode (parent );
658
- if (WARN_ON_ONCE (!inode_is_locked (parent_inode )))
659
- return ;
660
-
661
- if (simple_positive (dentry )) {
662
- dget (dentry );
663
- simple_unlink (parent_inode , dentry );
664
- d_delete (dentry );
665
- dput (dentry );
666
- }
667
- }
569
+ struct dentry * dentry ;
668
570
669
- /**
670
- * remove_binfmt_handler - remove a binary type handler
671
- * @misc: handle to binfmt_misc instance
672
- * @e: binary type handler to remove
673
- *
674
- * Remove a binary type handler from the list of binary type handlers and
675
- * remove its associated dentry. This is called from
676
- * binfmt_{entry,status}_write(). In the future, we might want to think about
677
- * adding a proper ->unlink() method to binfmt_misc instead of forcing caller's
678
- * to use writes to files in order to delete binary type handlers. But it has
679
- * worked for so long that it's not a pressing issue.
680
- */
681
- static void remove_binfmt_handler (Node * e )
682
- {
683
571
write_lock (& entries_lock );
684
572
list_del_init (& e -> list );
685
573
write_unlock (& entries_lock );
686
- unlink_binfmt_dentry (e -> dentry );
574
+
575
+ dentry = e -> dentry ;
576
+ drop_nlink (d_inode (dentry ));
577
+ d_drop (dentry );
578
+ dput (dentry );
579
+ simple_release_fs (& bm_mnt , & entry_count );
687
580
}
688
581
689
582
/* /<entry> */
@@ -710,8 +603,8 @@ bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
710
603
static ssize_t bm_entry_write (struct file * file , const char __user * buffer ,
711
604
size_t count , loff_t * ppos )
712
605
{
713
- struct inode * inode = file_inode ( file ) ;
714
- Node * e = inode -> i_private ;
606
+ struct dentry * root ;
607
+ Node * e = file_inode ( file ) -> i_private ;
715
608
int res = parse_command (buffer , count );
716
609
717
610
switch (res ) {
@@ -725,22 +618,13 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
725
618
break ;
726
619
case 3 :
727
620
/* Delete this handler. */
728
- inode = d_inode ( inode -> i_sb -> s_root ) ;
729
- inode_lock (inode );
621
+ root = file_inode ( file ) -> i_sb -> s_root ;
622
+ inode_lock (d_inode ( root ) );
730
623
731
- /*
732
- * In order to add new element or remove elements from the list
733
- * via bm_{entry,register,status}_write() inode_lock() on the
734
- * root inode must be held.
735
- * The lock is exclusive ensuring that the list can't be
736
- * modified. Only load_misc_binary() can access but does so
737
- * read-only. So we only need to take the write lock when we
738
- * actually remove the entry from the list.
739
- */
740
624
if (!list_empty (& e -> list ))
741
- remove_binfmt_handler (e );
625
+ kill_node (e );
742
626
743
- inode_unlock (inode );
627
+ inode_unlock (d_inode ( root ) );
744
628
break ;
745
629
default :
746
630
return res ;
@@ -799,7 +683,13 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
799
683
if (!inode )
800
684
goto out2 ;
801
685
802
- refcount_set (& e -> users , 1 );
686
+ err = simple_pin_fs (& bm_fs_type , & bm_mnt , & entry_count );
687
+ if (err ) {
688
+ iput (inode );
689
+ inode = NULL ;
690
+ goto out2 ;
691
+ }
692
+
803
693
e -> dentry = dget (dentry );
804
694
inode -> i_private = e ;
805
695
inode -> i_fop = & bm_entry_operations ;
@@ -843,8 +733,7 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
843
733
size_t count , loff_t * ppos )
844
734
{
845
735
int res = parse_command (buffer , count );
846
- Node * e , * next ;
847
- struct inode * inode ;
736
+ struct dentry * root ;
848
737
849
738
switch (res ) {
850
739
case 1 :
@@ -857,22 +746,13 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
857
746
break ;
858
747
case 3 :
859
748
/* Delete all handlers. */
860
- inode = d_inode ( file_inode (file )-> i_sb -> s_root ) ;
861
- inode_lock (inode );
749
+ root = file_inode (file )-> i_sb -> s_root ;
750
+ inode_lock (d_inode ( root ) );
862
751
863
- /*
864
- * In order to add new element or remove elements from the list
865
- * via bm_{entry,register,status}_write() inode_lock() on the
866
- * root inode must be held.
867
- * The lock is exclusive ensuring that the list can't be
868
- * modified. Only load_misc_binary() can access but does so
869
- * read-only. So we only need to take the write lock when we
870
- * actually remove the entry from the list.
871
- */
872
- list_for_each_entry_safe (e , next , & entries , list )
873
- remove_binfmt_handler (e );
752
+ while (!list_empty (& entries ))
753
+ kill_node (list_first_entry (& entries , Node , list ));
874
754
875
- inode_unlock (inode );
755
+ inode_unlock (d_inode ( root ) );
876
756
break ;
877
757
default :
878
758
return res ;
0 commit comments