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

audit: fix filename matching in __audit_inode() and __audit_inode_child()

In all likelihood there were some subtle, and perhaps not so subtle,
bugs with filename matching in audit_inode() and audit_inode_child()
for some time, however, recent changes to the audit filename code have
definitely broken the filename matching code. The breakage could
result in duplicate filenames in the audit log and other odd audit
record entries. This patch fixes the filename matching code and
restores some sanity to the filename audit records.

CC: viro@zeniv.linux.org.uk
CC: linux-fsdevel@vger.kernel.org
Signed-off-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

authored by

Paul Moore and committed by
Al Viro
57c59f58 fd3522fd

+25 -9
+25 -9
kernel/auditsc.c
··· 1846 1846 /* The struct filename _must_ have a populated ->name */ 1847 1847 BUG_ON(!name->name); 1848 1848 #endif 1849 + 1849 1850 /* 1850 1851 * If we have a pointer to an audit_names entry already, then we can 1851 1852 * just use it directly if the type is correct. ··· 1864 1863 } 1865 1864 1866 1865 list_for_each_entry_reverse(n, &context->names_list, list) { 1867 - if (!n->name || strcmp(n->name->name, name->name)) 1866 + if (n->ino) { 1867 + /* valid inode number, use that for the comparison */ 1868 + if (n->ino != inode->i_ino || 1869 + n->dev != inode->i_sb->s_dev) 1870 + continue; 1871 + } else if (n->name) { 1872 + /* inode number has not been set, check the name */ 1873 + if (strcmp(n->name->name, name->name)) 1874 + continue; 1875 + } else 1876 + /* no inode and no name (?!) ... this is odd ... */ 1868 1877 continue; 1869 1878 1870 1879 /* match the correct record type */ ··· 1947 1936 1948 1937 /* look for a parent entry first */ 1949 1938 list_for_each_entry(n, &context->names_list, list) { 1950 - if (!n->name || n->type != AUDIT_TYPE_PARENT) 1939 + if (!n->name || 1940 + (n->type != AUDIT_TYPE_PARENT && 1941 + n->type != AUDIT_TYPE_UNKNOWN)) 1951 1942 continue; 1952 1943 1953 - if (n->ino == parent->i_ino && 1954 - !audit_compare_dname_path(dname, n->name->name, n->name_len)) { 1944 + if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev && 1945 + !audit_compare_dname_path(dname, 1946 + n->name->name, n->name_len)) { 1947 + if (n->type == AUDIT_TYPE_UNKNOWN) 1948 + n->type = AUDIT_TYPE_PARENT; 1955 1949 found_parent = n; 1956 1950 break; 1957 1951 } ··· 1965 1949 /* is there a matching child entry? */ 1966 1950 list_for_each_entry(n, &context->names_list, list) { 1967 1951 /* can only match entries that have a name */ 1968 - if (!n->name || n->type != type) 1969 - continue; 1970 - 1971 - /* if we found a parent, make sure this one is a child of it */ 1972 - if (found_parent && (n->name != found_parent->name)) 1952 + if (!n->name || 1953 + (n->type != type && n->type != AUDIT_TYPE_UNKNOWN)) 1973 1954 continue; 1974 1955 1975 1956 if (!strcmp(dname, n->name->name) || ··· 1974 1961 found_parent ? 1975 1962 found_parent->name_len : 1976 1963 AUDIT_NAME_FULL)) { 1964 + if (n->type == AUDIT_TYPE_UNKNOWN) 1965 + n->type = type; 1977 1966 found_child = n; 1978 1967 break; 1979 1968 } ··· 2004 1989 found_child->name_put = false; 2005 1990 } 2006 1991 } 1992 + 2007 1993 if (inode) 2008 1994 audit_copy_inode(found_child, dentry, inode); 2009 1995 else