Skip to content

Commit 2858c34

Browse files
paniakin-awsSuraj Jitindar Singh
authored and
Suraj Jitindar Singh
committed
Revert "binfmt_misc: cleanup on filesystem umount"
This reverts commit a43edc7. This change is causing failure with docker multirarch run, customers are getting exec format error, reverting it as a mitigation Signed-off-by: Mahmoud Adam <[email protected]>
1 parent a130851 commit 2858c34

File tree

1 file changed

+48
-168
lines changed

1 file changed

+48
-168
lines changed

fs/binfmt_misc.c

Lines changed: 48 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,12 @@ typedef struct {
6060
char *name;
6161
struct dentry *dentry;
6262
struct file *interp_file;
63-
refcount_t users; /* sync removal with load_misc_binary() */
6463
} Node;
6564

6665
static DEFINE_RWLOCK(entries_lock);
6766
static struct file_system_type bm_fs_type;
67+
static struct vfsmount *bm_mnt;
68+
static int entry_count;
6869

6970
/*
7071
* Max length of the register string. Determined by:
@@ -81,23 +82,19 @@ static struct file_system_type bm_fs_type;
8182
*/
8283
#define MAX_REGISTER_LENGTH 1920
8384

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
9389
*/
94-
static Node *search_binfmt_handler(struct linux_binprm *bprm)
90+
static Node *check_file(struct linux_binprm *bprm)
9591
{
9692
char *p = strrchr(bprm->interp, '.');
97-
Node *e;
93+
struct list_head *l;
9894

9995
/* 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);
10198
char *s;
10299
int j;
103100

@@ -126,49 +123,9 @@ static Node *search_binfmt_handler(struct linux_binprm *bprm)
126123
if (j == e->size)
127124
return e;
128125
}
129-
130126
return NULL;
131127
}
132128

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-
172129
/*
173130
* the loader itself
174131
*/
@@ -182,7 +139,12 @@ static int load_misc_binary(struct linux_binprm *bprm)
182139
if (!enabled)
183140
return retval;
184141

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);
186148
if (!fmt)
187149
return retval;
188150

@@ -236,16 +198,7 @@ static int load_misc_binary(struct linux_binprm *bprm)
236198

237199
retval = 0;
238200
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);
249202
return retval;
250203
}
251204

@@ -600,90 +553,30 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
600553
return inode;
601554
}
602555

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-
*/
616556
static void bm_evict_inode(struct inode *inode)
617557
{
618558
Node *e = inode->i_private;
619559

620-
clear_inode(inode);
560+
if (e && e->flags & MISC_FMT_OPEN_FILE)
561+
filp_close(e->interp_file, NULL);
621562

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);
629565
}
630566

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)
643568
{
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;
668570

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-
{
683571
write_lock(&entries_lock);
684572
list_del_init(&e->list);
685573
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);
687580
}
688581

689582
/* /<entry> */
@@ -710,8 +603,8 @@ bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
710603
static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
711604
size_t count, loff_t *ppos)
712605
{
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;
715608
int res = parse_command(buffer, count);
716609

717610
switch (res) {
@@ -725,22 +618,13 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
725618
break;
726619
case 3:
727620
/* 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));
730623

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-
*/
740624
if (!list_empty(&e->list))
741-
remove_binfmt_handler(e);
625+
kill_node(e);
742626

743-
inode_unlock(inode);
627+
inode_unlock(d_inode(root));
744628
break;
745629
default:
746630
return res;
@@ -799,7 +683,13 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
799683
if (!inode)
800684
goto out2;
801685

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+
803693
e->dentry = dget(dentry);
804694
inode->i_private = e;
805695
inode->i_fop = &bm_entry_operations;
@@ -843,8 +733,7 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
843733
size_t count, loff_t *ppos)
844734
{
845735
int res = parse_command(buffer, count);
846-
Node *e, *next;
847-
struct inode *inode;
736+
struct dentry *root;
848737

849738
switch (res) {
850739
case 1:
@@ -857,22 +746,13 @@ static ssize_t bm_status_write(struct file *file, const char __user *buffer,
857746
break;
858747
case 3:
859748
/* 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));
862751

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));
874754

875-
inode_unlock(inode);
755+
inode_unlock(d_inode(root));
876756
break;
877757
default:
878758
return res;

0 commit comments

Comments
 (0)