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