afs: Add rootcell checks
authorDavid Howells <dhowells@redhat.com>
Tue, 7 Jan 2025 18:34:50 +0000 (18:34 +0000)
committerChristian Brauner <brauner@kernel.org>
Fri, 10 Jan 2025 13:54:07 +0000 (14:54 +0100)
Add some checks for the validity of the cell name.  It's may get put into a
symlink, so preclude it containing any slashes or "..".  Also disallow
starting/ending with a dot.  This makes /afs/@cell/ as a symlink less of a
security risk.

Also disallow multiple setting of /proc/net/afs/rootcell for any given
network namespace.  Once set, the value may not be changed.  This makes it
easier to only create /afs/@cell and /afs/.@cell if there's a rootcell.

Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://lore.kernel.org/r/20250107183454.608451-3-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/afs/cell.c
fs/afs/proc.c

index 1aba6d4d03a9b06bd47fbc3bfd58012d4283e747..cee42646736c8684bcf2a172783c5d3bb445a636 100644 (file)
@@ -367,6 +367,14 @@ int afs_cell_init(struct afs_net *net, const char *rootcell)
                len = cp - rootcell;
        }
 
+       if (len == 0 || !rootcell[0] || rootcell[0] == '.' || rootcell[len - 1] == '.')
+               return -EINVAL;
+       if (memchr(rootcell, '/', len))
+               return -EINVAL;
+       cp = strstr(rootcell, "..");
+       if (cp && cp < rootcell + len)
+               return -EINVAL;
+
        /* allocate a cell record for the root cell */
        new_root = afs_lookup_cell(net, rootcell, len, vllist, false);
        if (IS_ERR(new_root)) {
index 15eab053af6dc05931363c619cd32cf041093a3f..e7614f4f30c21eb4b1bca3299ad7175dc9bb8c2a 100644 (file)
@@ -240,7 +240,13 @@ static int afs_proc_rootcell_write(struct file *file, char *buf, size_t size)
        /* determine command to perform */
        _debug("rootcell=%s", buf);
 
-       ret = afs_cell_init(net, buf);
+       ret = -EEXIST;
+       inode_lock(file_inode(file));
+       if (!net->ws_cell)
+               ret = afs_cell_init(net, buf);
+       else
+               printk("busy\n");
+       inode_unlock(file_inode(file));
 
 out:
        _leave(" = %d", ret);