CINXE.COM

LKML: Alexey Nepomnyashih: [PATCH 6.1] efivarfs: Move efivarfs list into superblock s_fs_info

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>LKML: Alexey Nepomnyashih: [PATCH 6.1] efivarfs: Move efivarfs list into superblock s_fs_info</title><link href="/css/message.css" rel="stylesheet" type="text/css" /><link href="/css/wrap.css" rel="alternate stylesheet" type="text/css" title="wrap" /><link href="/css/nowrap.css" rel="stylesheet" type="text/css" title="nowrap" /><link href="/favicon.ico" rel="shortcut icon" /><script src="/js/simple-calendar.js" type="text/javascript"></script><script src="/js/styleswitcher.js" type="text/javascript"></script><link rel="alternate" type="application/rss+xml" title="lkml.org : last 100 messages" href="/rss.php" /><link rel="alternate" type="application/rss+xml" title="lkml.org : last messages by Alexey Nepomnyashih" href="/groupie.php?aid=" /><!--Matomo--><script> var _paq = window._paq = window._paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDoNotTrack", true]); _paq.push(["disableCookies"]); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//m.lkml.org/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script><!--End Matomo Code--></head><body onload="es.jasper.simpleCalendar.init();" itemscope="itemscope" itemtype="http://schema.org/BlogPosting"><table border="0" cellpadding="0" cellspacing="0"><tr><td width="180" align="center"><a href="/"><img style="border:0;width:135px;height:32px" src="/images/toprowlk.gif" alt="lkml.org" /></a></td><td width="32">聽</td><td class="nb"><div><a class="nb" href="/lkml"> [lkml]</a> 聽 <a class="nb" href="/lkml/2025"> [2025]</a> 聽 <a class="nb" href="/lkml/2025/3"> [Mar]</a> 聽 <a class="nb" href="/lkml/2025/3/21"> [21]</a> 聽 <a class="nb" href="/lkml/last100"> [last100]</a> 聽 <a href="/rss.php"><img src="/images/rss-or.gif" border="0" alt="RSS Feed" /></a></div><div>Views: <a href="#" class="nowrap" onclick="setActiveStyleSheet('wrap');return false;">[wrap]</a><a href="#" class="wrap" onclick="setActiveStyleSheet('nowrap');return false;">[no wrap]</a> 聽 <a class="nb" href="/lkml/mheaders/2025/3/21/1238" onclick="this.href='/lkml/headers'+'/2025/3/21/1238';">[headers]</a>聽 <a href="/lkml/bounce/2025/3/21/1238">[forward]</a>聽 </div></td><td width="32">聽</td></tr><tr><td valign="top"><div class="es-jasper-simpleCalendar" baseurl="/lkml/"></div><div class="threadlist">Messages in this thread</div><ul class="threadlist"><li class="root"><a href="/lkml/2025/3/21/1238">First message in thread</a></li><li class="origin"><a href="/lkml/2025/3/21/1260">Alexey Nepomnyashih</a><ul><li><a href="/lkml/2025/3/21/1260">Ard Biesheuvel</a></li></ul></li></ul><div class="threadlist">Patch in this message</div><ul class="threadlist"><li><a href="/lkml/diff/2025/3/21/1238/1">Get diff 1</a></li></ul></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerl.gif" width="32" height="32" alt="/" /></td><td class="c" rowspan="2" valign="top" style="padding-top: 1em"><table><tr><td><table><tr><td class="lp">From</td><td class="rp" itemprop="author">Alexey Nepomnyashih &lt;&gt;</td></tr><tr><td class="lp">Subject</td><td class="rp" itemprop="name">[PATCH 6.1] efivarfs: Move efivarfs list into superblock s_fs_info</td></tr><tr><td class="lp">Date</td><td class="rp" itemprop="datePublished">Fri, 21 Mar 2025 18:40:20 +0000</td></tr></table></td><td></td></tr></table><pre itemprop="articleBody">From: Ard Biesheuvel &lt;ardb&#64;kernel.org&gt;<br /><br />commit cdb46a8aefbf7fd36772bb206aaaf7e45d7cf8f6 upstream.<br /><br />syzbot reports issues with concurrent fsopen()/fsconfig() invocations on<br />efivarfs, which are the result of the fact that the efivarfs list (which<br />caches the names and GUIDs of existing EFI variables) is a global<br />structure. In normal use, these issues are unlikely to trigger, even in<br />the presence of multiple mounts of efivarfs, but the execution pattern<br />used by the syzkaller reproducer may result in multiple instances of the<br />superblock that share the global efivarfs list, and this causes list<br />corruption when the list is reinitialized by one user while another is<br />traversing it.<br /><br />So let's move the list head into the superblock s_fs_info field, so that<br />it will never be shared between distinct instances of the superblock. In<br />the common case, there will still be a single instance of this list, but<br />in the artificial syzkaller case, no list corruption can occur any<br />longer.<br /><br />Reported-by: syzbot+1902c359bfcaf39c46f2&#64;syzkaller.appspotmail.com<br />Signed-off-by: Ard Biesheuvel &lt;ardb&#64;kernel.org&gt;<br />Reported-by: syzbot+246ea4feed277471958a&#64;syzkaller.appspotmail.com<br />Closes: <a href="https://syzkaller.appspot.com/bug?extid=246ea4feed277471958a">https://syzkaller.appspot.com/bug?extid=246ea4feed277471958a</a><br />Signed-off-by: Alexey Nepomnyashih &lt;sdl&#64;nppct.ru&gt;<br />---<br /> fs/efivarfs/inode.c | 3 ++-<br /> fs/efivarfs/internal.h | 9 ++++++---<br /> fs/efivarfs/super.c | 26 +++++++++++++++++---------<br /> fs/efivarfs/vars.c | 5 +++--<br /> 4 files changed, 28 insertions(+), 15 deletions(-)<br /><br />diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c<br />index b3dc7ff42400..a999351e6615 100644<br />--- a/fs/efivarfs/inode.c<br />+++ b/fs/efivarfs/inode.c<br />&#64;&#64; -73,6 +73,7 &#64;&#64; static bool efivarfs_valid_name(const char *str, int len)<br /> static int efivarfs_create(struct user_namespace *mnt_userns, struct inode *dir,<br /> struct dentry *dentry, umode_t mode, bool excl)<br /> {<br />+ struct efivarfs_fs_info *info = dir-&gt;i_sb-&gt;s_fs_info;<br /> struct inode *inode = NULL;<br /> struct efivar_entry *var;<br /> int namelen, i = 0, err = 0;<br />&#64;&#64; -110,7 +111,7 &#64;&#64; static int efivarfs_create(struct user_namespace *mnt_userns, struct inode *dir,<br /> inode-&gt;i_private = var;<br /> kmemleak_ignore(var);<br /> <br />- err = efivar_entry_add(var, &amp;efivarfs_list);<br />+ err = efivar_entry_add(var, &amp;info-&gt;efivarfs_list);<br /> if (err)<br /> goto out;<br /> <br />diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h<br />index dcb973d8736c..1745be16ff65 100644<br />--- a/fs/efivarfs/internal.h<br />+++ b/fs/efivarfs/internal.h<br />&#64;&#64; -9,6 +9,10 &#64;&#64;<br /> #include &lt;linux/list.h&gt;<br /> #include &lt;linux/efi.h&gt;<br /> <br />+struct efivarfs_fs_info {<br />+ struct list_head efivarfs_list;<br />+};<br />+<br /> struct efi_variable {<br /> efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)];<br /> efi_guid_t VendorGuid;<br />&#64;&#64; -24,7 +28,8 &#64;&#64; struct efivar_entry {<br /> struct kobject kobj;<br /> };<br /> <br />-int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),<br />+int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,<br />+ struct list_head *),<br /> void *data, bool duplicates, struct list_head *head);<br /> <br /> int efivar_entry_add(struct efivar_entry *entry, struct list_head *head);<br />&#64;&#64; -54,6 +59,4 &#64;&#64; extern struct inode *efivarfs_get_inode(struct super_block *sb,<br /> const struct inode *dir, int mode, dev_t dev,<br /> bool is_removable);<br /> <br />-extern struct list_head efivarfs_list;<br />-<br /> #endif /* EFIVAR_FS_INTERNAL_H */<br />diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c<br />index b8c4641ed152..a2c13af6c090 100644<br />--- a/fs/efivarfs/super.c<br />+++ b/fs/efivarfs/super.c<br />&#64;&#64; -17,8 +17,6 &#64;&#64;<br /> <br /> #include "internal.h"<br /> <br />-LIST_HEAD(efivarfs_list);<br />-<br /> static void efivarfs_evict_inode(struct inode *inode)<br /> {<br /> clear_inode(inode);<br />&#64;&#64; -102,7 +100,8 &#64;&#64; static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)<br /> }<br /> <br /> static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,<br />- unsigned long name_size, void *data)<br />+ unsigned long name_size, void *data,<br />+ struct list_head *list)<br /> {<br /> struct super_block *sb = (struct super_block *)data;<br /> struct efivar_entry *entry;<br />&#64;&#64; -154,7 +153,7 &#64;&#64; static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,<br /> }<br /> <br /> __efivar_entry_get(entry, NULL, &amp;size, NULL);<br />- __efivar_entry_add(entry, &amp;efivarfs_list);<br />+ __efivar_entry_add(entry, list);<br /> <br /> /* copied by the above to local storage in the dentry. */<br /> kfree(name);<br />&#64;&#64; -185,6 +184,7 &#64;&#64; static int efivarfs_destroy(struct efivar_entry *entry, void *data)<br /> <br /> static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)<br /> {<br />+ struct efivarfs_fs_info *sfi = sb-&gt;s_fs_info;<br /> struct inode *inode = NULL;<br /> struct dentry *root;<br /> int err;<br />&#64;&#64; -210,11 +210,10 &#64;&#64; static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)<br /> if (!root)<br /> return -ENOMEM;<br /> <br />- INIT_LIST_HEAD(&amp;efivarfs_list);<br />-<br />- err = efivar_init(efivarfs_callback, (void *)sb, true, &amp;efivarfs_list);<br />+ err = efivar_init(efivarfs_callback, (void *)sb, true,<br />+ &amp;sfi-&gt;efivarfs_list);<br /> if (err)<br />- efivar_entry_iter(efivarfs_destroy, &amp;efivarfs_list, NULL);<br />+ efivar_entry_iter(efivarfs_destroy, &amp;sfi-&gt;efivarfs_list, NULL);<br /> <br /> return err;<br /> }<br />&#64;&#64; -241,6 +240,15 &#64;&#64; static const struct fs_context_operations efivarfs_context_ops = {<br /> <br /> static int efivarfs_init_fs_context(struct fs_context *fc)<br /> {<br />+ struct efivarfs_fs_info *sfi;<br />+<br />+ sfi = kzalloc(sizeof(*sfi), GFP_KERNEL);<br />+ if (!sfi)<br />+ return -ENOMEM;<br />+<br />+ INIT_LIST_HEAD(&amp;sfi-&gt;efivarfs_list);<br />+<br />+ fc-&gt;s_fs_info = sfi;<br /> fc-&gt;ops = &amp;efivarfs_context_ops;<br /> return 0;<br /> }<br />&#64;&#64; -252,7 +260,7 &#64;&#64; static void efivarfs_kill_sb(struct super_block *sb)<br /> kill_litter_super(sb);<br /> <br /> /* Remove all entries and destroy */<br />- efivar_entry_iter(efivarfs_destroy, &amp;efivarfs_list, NULL);<br />+ efivar_entry_iter(efivarfs_destroy, &amp;sfi-&gt;efivarfs_list, NULL);<br /> kfree(sfi);<br /> }<br /> <br />diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c<br />index 13bc60698955..2ad377818d0f 100644<br />--- a/fs/efivarfs/vars.c<br />+++ b/fs/efivarfs/vars.c<br />&#64;&#64; -369,7 +369,8 &#64;&#64; static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,<br /> *<br /> * Returns 0 on success, or a kernel error code on failure.<br /> */<br />-int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),<br />+int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *,<br />+ struct list_head *),<br /> void *data, bool duplicates, struct list_head *head)<br /> {<br /> unsigned long variable_name_size = 512;<br />&#64;&#64; -421,7 +422,7 &#64;&#64; int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),<br /> status = EFI_NOT_FOUND;<br /> } else {<br /> err = func(variable_name, vendor_guid,<br />- variable_name_size, data);<br />+ variable_name_size, data, head);<br /> if (err)<br /> status = EFI_NOT_FOUND;<br /> }<br />-- <br />2.43.0<br /><br /></pre></td><td width="32" rowspan="2" class="c" valign="top"><img src="/images/icornerr.gif" width="32" height="32" alt="\" /></td></tr><tr><td align="right" valign="bottom"> 聽 </td></tr><tr><td align="right" valign="bottom">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerl.gif" width="32" height="32" alt="\" /></td><td class="c">聽</td><td class="c" valign="bottom" style="padding-bottom: 0px"><img src="/images/bcornerr.gif" width="32" height="32" alt="/" /></td></tr><tr><td align="right" valign="top" colspan="2"> 聽 </td><td class="lm">Last update: 2025-03-21 19:41 聽聽 [W:0.082 / U:1.540 seconds]<br />漏2003-2020 <a href="http://blog.jasper.es/"><span itemprop="editor">Jasper Spaans</span></a>|hosted at <a href="https://www.digitalocean.com/?refcode=9a8e99d24cf9">Digital Ocean</a> and my Meterkast|<a href="http://blog.jasper.es/categories.html#lkml-ref">Read the blog</a></td><td>聽</td></tr></table><script language="javascript" src="/js/styleswitcher.js" type="text/javascript"></script></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10