Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

habanalabs: fix UAF in export_dmabuf()

As soon as we'd inserted a file reference into descriptor table, another
thread could close it. That's fine for the case when all we are doing is
returning that descriptor to userland (it's a race, but it's a userland
race and there's nothing the kernel can do about it). However, if we
follow fd_install() with any kind of access to objects that would be
destroyed on close (be it the struct file itself or anything destroyed
by its ->release()), we have a UAF.

dma_buf_fd() is a combination of reserving a descriptor and fd_install().
habanalabs export_dmabuf() calls it and then proceeds to access the
objects destroyed on close. In particular, it grabs an extra reference to
another struct file that will be dropped as part of ->release() for ours;
that "will be" is actually "might have already been".

Fix that by reserving descriptor before anything else and do fd_install()
only when everything had been set up. As a side benefit, we no longer
have the failure exit with file already created, but reference to
underlying file (as well as ->dmabuf_export_cnt, etc.) not grabbed yet;
unlike dma_buf_fd(), fd_install() can't fail.

Fixes: db1a8dd916aa ("habanalabs: add support for dma-buf exporter")
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 33927f3d d7b8f8e2

+7 -16
+7 -16
drivers/accel/habanalabs/common/memory.c
··· 1829 1829 struct hl_dmabuf_priv *hl_dmabuf = dmabuf->priv; 1830 1830 struct hl_ctx *ctx; 1831 1831 1832 - if (!hl_dmabuf) 1833 - return; 1834 - 1835 1832 ctx = hl_dmabuf->ctx; 1836 1833 1837 1834 if (hl_dmabuf->memhash_hnode) ··· 1856 1859 { 1857 1860 DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 1858 1861 struct hl_device *hdev = ctx->hdev; 1859 - int rc, fd; 1862 + CLASS(get_unused_fd, fd)(flags); 1863 + 1864 + if (fd < 0) { 1865 + dev_err(hdev->dev, "failed to get a file descriptor for a dma-buf, %d\n", fd); 1866 + return fd; 1867 + } 1860 1868 1861 1869 exp_info.ops = &habanalabs_dmabuf_ops; 1862 1870 exp_info.size = total_size; ··· 1872 1870 if (IS_ERR(hl_dmabuf->dmabuf)) { 1873 1871 dev_err(hdev->dev, "failed to export dma-buf\n"); 1874 1872 return PTR_ERR(hl_dmabuf->dmabuf); 1875 - } 1876 - 1877 - fd = dma_buf_fd(hl_dmabuf->dmabuf, flags); 1878 - if (fd < 0) { 1879 - dev_err(hdev->dev, "failed to get a file descriptor for a dma-buf, %d\n", fd); 1880 - rc = fd; 1881 - goto err_dma_buf_put; 1882 1873 } 1883 1874 1884 1875 hl_dmabuf->ctx = ctx; ··· 1885 1890 get_file(ctx->hpriv->file_priv->filp); 1886 1891 1887 1892 *dmabuf_fd = fd; 1893 + fd_install(take_fd(fd), hl_dmabuf->dmabuf->file); 1888 1894 1889 1895 return 0; 1890 - 1891 - err_dma_buf_put: 1892 - hl_dmabuf->dmabuf->priv = NULL; 1893 - dma_buf_put(hl_dmabuf->dmabuf); 1894 - return rc; 1895 1896 } 1896 1897 1897 1898 static int validate_export_params_common(struct hl_device *hdev, u64 addr, u64 size, u64 offset)