From: Dan Carpenter <dan.carpenter@oracle.com>
To: almaz.alexandrovich@paragon-software.com
Cc: ntfs3@lists.linux.dev
Subject: [bug report] fs/ntfs3: integer overflow in ni_fiemap()
Date: Wed, 25 Aug 2021 11:04:40 +0300 [thread overview]
Message-ID: <20210825080440.GA17407@kili> (raw)
Hello Konstantin Komarov,
The patch 4342306f0f0d: "fs/ntfs3: Add file operations and
implementation" from Aug 13, 2021, leads to the following
Smatch static checker warning:
fs/ntfs3/frecord.c:1894 ni_fiemap()
warn: potential integer overflow from user 'vbo + len'
fs/ntfs3/frecord.c
1843 int ni_fiemap(struct ntfs_inode *ni, struct fiemap_extent_info *fieinfo,
1844 __u64 vbo, __u64 len)
"vbo" and "len" are u64 values which are controlled by the user from
ioctl_fiemap().
I looked at how BTRFS does it and it uses the fiemap_prep() function.
To be honest, I don't know why fiemap_prep() isn't used in ioctl_fiemap()
because that seems safer than relying on filesystems to do it themselves.
1845 {
1846 int err = 0;
1847 struct ntfs_sb_info *sbi = ni->mi.sbi;
1848 u8 cluster_bits = sbi->cluster_bits;
1849 struct runs_tree *run;
1850 struct rw_semaphore *run_lock;
1851 struct ATTRIB *attr;
1852 CLST vcn = vbo >> cluster_bits;
1853 CLST lcn, clen;
1854 u64 valid = ni->i_valid;
1855 u64 lbo, bytes;
1856 u64 end, alloc_size;
1857 size_t idx = -1;
1858 u32 flags;
1859 bool ok;
1860
1861 if (S_ISDIR(ni->vfs_inode.i_mode)) {
1862 run = &ni->dir.alloc_run;
1863 attr = ni_find_attr(ni, NULL, NULL, ATTR_ALLOC, I30_NAME,
1864 ARRAY_SIZE(I30_NAME), NULL, NULL);
1865 run_lock = &ni->dir.run_lock;
1866 } else {
1867 run = &ni->file.run;
1868 attr = ni_find_attr(ni, NULL, NULL, ATTR_DATA, NULL, 0, NULL,
1869 NULL);
1870 if (!attr) {
1871 err = -EINVAL;
1872 goto out;
1873 }
1874 if (is_attr_compressed(attr)) {
1875 /*unfortunately cp -r incorrectly treats compressed clusters*/
1876 err = -EOPNOTSUPP;
1877 ntfs_inode_warn(
1878 &ni->vfs_inode,
1879 "fiemap is not supported for compressed file (cp -r)");
1880 goto out;
1881 }
1882 run_lock = &ni->file.run_lock;
1883 }
1884
1885 if (!attr || !attr->non_res) {
1886 err = fiemap_fill_next_extent(
1887 fieinfo, 0, 0,
1888 attr ? le32_to_cpu(attr->res.data_size) : 0,
1889 FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_LAST |
1890 FIEMAP_EXTENT_MERGED);
1891 goto out;
1892 }
1893
--> 1894 end = vbo + len;
^^^^^^^^^^^^^^^
This can overflow.
1895 alloc_size = le64_to_cpu(attr->nres.alloc_size);
1896 if (end > alloc_size)
1897 end = alloc_size;
1898
1899 down_read(run_lock);
1900
1901 while (vbo < end) {
1902 if (idx == -1) {
1903 ok = run_lookup_entry(run, vcn, &lcn, &clen, &idx);
1904 } else {
1905 CLST vcn_next = vcn;
1906
1907 ok = run_get_entry(run, ++idx, &vcn, &lcn, &clen) &&
1908 vcn == vcn_next;
1909 if (!ok)
1910 vcn = vcn_next;
1911 }
1912
1913 if (!ok) {
1914 up_read(run_lock);
1915 down_write(run_lock);
1916
1917 err = attr_load_runs_vcn(ni, attr->type,
1918 attr_name(attr),
1919 attr->name_len, run, vcn);
1920
1921 up_write(run_lock);
1922 down_read(run_lock);
1923
1924 if (err)
1925 break;
1926
1927 ok = run_lookup_entry(run, vcn, &lcn, &clen, &idx);
1928
1929 if (!ok) {
1930 err = -EINVAL;
1931 break;
1932 }
1933 }
1934
1935 if (!clen) {
1936 err = -EINVAL; // ?
1937 break;
1938 }
1939
1940 if (lcn == SPARSE_LCN) {
1941 vcn += clen;
1942 vbo = (u64)vcn << cluster_bits;
1943 continue;
1944 }
1945
1946 flags = FIEMAP_EXTENT_MERGED;
1947 if (S_ISDIR(ni->vfs_inode.i_mode)) {
1948 ;
1949 } else if (is_attr_compressed(attr)) {
1950 CLST clst_data;
1951
1952 err = attr_is_frame_compressed(
1953 ni, attr, vcn >> attr->nres.c_unit, &clst_data);
1954 if (err)
1955 break;
1956 if (clst_data < NTFS_LZNT_CLUSTERS)
1957 flags |= FIEMAP_EXTENT_ENCODED;
1958 } else if (is_attr_encrypted(attr)) {
1959 flags |= FIEMAP_EXTENT_DATA_ENCRYPTED;
1960 }
1961
1962 vbo = (u64)vcn << cluster_bits;
1963 bytes = (u64)clen << cluster_bits;
1964 lbo = (u64)lcn << cluster_bits;
1965
1966 vcn += clen;
1967
1968 if (vbo + bytes >= end) {
1969 bytes = end - vbo;
1970 flags |= FIEMAP_EXTENT_LAST;
1971 }
1972
1973 if (vbo + bytes <= valid) {
1974 ;
1975 } else if (vbo >= valid) {
1976 flags |= FIEMAP_EXTENT_UNWRITTEN;
1977 } else {
1978 /* vbo < valid && valid < vbo + bytes */
1979 u64 dlen = valid - vbo;
1980
1981 err = fiemap_fill_next_extent(fieinfo, vbo, lbo, dlen,
1982 flags);
1983 if (err < 0)
1984 break;
1985 if (err == 1) {
1986 err = 0;
1987 break;
1988 }
1989
1990 vbo = valid;
1991 bytes -= dlen;
1992 if (!bytes)
1993 continue;
1994
1995 lbo += dlen;
1996 flags |= FIEMAP_EXTENT_UNWRITTEN;
1997 }
1998
1999 err = fiemap_fill_next_extent(fieinfo, vbo, lbo, bytes, flags);
2000 if (err < 0)
2001 break;
2002 if (err == 1) {
2003 err = 0;
2004 break;
2005 }
2006
2007 vbo += bytes;
2008 }
2009
2010 up_read(run_lock);
2011
2012 out:
2013 return err;
2014 }
regards,
dan carpenter
next reply other threads:[~2021-08-25 8:05 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-25 8:04 Dan Carpenter [this message]
2021-08-25 8:33 ` [bug report] fs/ntfs3: integer overflow in ni_fiemap() Kari Argillander
2021-08-25 8:35 ` Dan Carpenter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210825080440.GA17407@kili \
--to=dan.carpenter@oracle.com \
--cc=almaz.alexandrovich@paragon-software.com \
--cc=ntfs3@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.