diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 18:27:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-17 18:27:47 -0500 |
commit | 05016b0f0a9d900e976db7f50a7761c0aefe5a1c (patch) | |
tree | 20b2f04fee785dc9ef81596cb2f7deec6d8016e0 /kernel | |
parent | c6b1de1b646fe232206d4065df4d14040cebd613 (diff) | |
parent | 55422d0bd292f5ad143cc32cb8bb8505257274c4 (diff) |
Merge branch 'getname2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull getname/putname updates from Al Viro:
"Rework of getname/getname_kernel/etc., mostly from Paul Moore. Gets
rid of quite a pile of kludges between namei and audit..."
* 'getname2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
audit: replace getname()/putname() hacks with reference counters
audit: fix filename matching in __audit_inode() and __audit_inode_child()
audit: enable filename recording via getname_kernel()
simpler calling conventions for filename_mountpoint()
fs: create proper filename objects using getname_kernel()
fs: rework getname_kernel to handle up to PATH_MAX sized filenames
cut down the number of do_path_lookup() callers
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.h | 17 | ||||
-rw-r--r-- | kernel/auditsc.c | 171 |
2 files changed, 37 insertions, 151 deletions
diff --git a/kernel/audit.h b/kernel/audit.h index 3cdffad5a1d9..1caa0d345d90 100644 --- a/kernel/audit.h +++ b/kernel/audit.h | |||
@@ -24,12 +24,6 @@ | |||
24 | #include <linux/skbuff.h> | 24 | #include <linux/skbuff.h> |
25 | #include <uapi/linux/mqueue.h> | 25 | #include <uapi/linux/mqueue.h> |
26 | 26 | ||
27 | /* 0 = no checking | ||
28 | 1 = put_count checking | ||
29 | 2 = verbose put_count checking | ||
30 | */ | ||
31 | #define AUDIT_DEBUG 0 | ||
32 | |||
33 | /* AUDIT_NAMES is the number of slots we reserve in the audit_context | 27 | /* AUDIT_NAMES is the number of slots we reserve in the audit_context |
34 | * for saving names from getname(). If we get more names we will allocate | 28 | * for saving names from getname(). If we get more names we will allocate |
35 | * a name dynamically and also add those to the list anchored by names_list. */ | 29 | * a name dynamically and also add those to the list anchored by names_list. */ |
@@ -74,9 +68,8 @@ struct audit_cap_data { | |||
74 | }; | 68 | }; |
75 | }; | 69 | }; |
76 | 70 | ||
77 | /* When fs/namei.c:getname() is called, we store the pointer in name and | 71 | /* When fs/namei.c:getname() is called, we store the pointer in name and bump |
78 | * we don't let putname() free it (instead we free all of the saved | 72 | * the refcnt in the associated filename struct. |
79 | * pointers at syscall exit time). | ||
80 | * | 73 | * |
81 | * Further, in fs/namei.c:path_lookup() we store the inode and device. | 74 | * Further, in fs/namei.c:path_lookup() we store the inode and device. |
82 | */ | 75 | */ |
@@ -86,7 +79,6 @@ struct audit_names { | |||
86 | struct filename *name; | 79 | struct filename *name; |
87 | int name_len; /* number of chars to log */ | 80 | int name_len; /* number of chars to log */ |
88 | bool hidden; /* don't log this record */ | 81 | bool hidden; /* don't log this record */ |
89 | bool name_put; /* call __putname()? */ | ||
90 | 82 | ||
91 | unsigned long ino; | 83 | unsigned long ino; |
92 | dev_t dev; | 84 | dev_t dev; |
@@ -208,11 +200,6 @@ struct audit_context { | |||
208 | }; | 200 | }; |
209 | int fds[2]; | 201 | int fds[2]; |
210 | struct audit_proctitle proctitle; | 202 | struct audit_proctitle proctitle; |
211 | |||
212 | #if AUDIT_DEBUG | ||
213 | int put_count; | ||
214 | int ino_count; | ||
215 | #endif | ||
216 | }; | 203 | }; |
217 | 204 | ||
218 | extern u32 audit_ever_enabled; | 205 | extern u32 audit_ever_enabled; |
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 55f82fce2526..dc4ae70a7413 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -866,33 +866,10 @@ static inline void audit_free_names(struct audit_context *context) | |||
866 | { | 866 | { |
867 | struct audit_names *n, *next; | 867 | struct audit_names *n, *next; |
868 | 868 | ||
869 | #if AUDIT_DEBUG == 2 | ||
870 | if (context->put_count + context->ino_count != context->name_count) { | ||
871 | int i = 0; | ||
872 | |||
873 | pr_err("%s:%d(:%d): major=%d in_syscall=%d" | ||
874 | " name_count=%d put_count=%d ino_count=%d" | ||
875 | " [NOT freeing]\n", __FILE__, __LINE__, | ||
876 | context->serial, context->major, context->in_syscall, | ||
877 | context->name_count, context->put_count, | ||
878 | context->ino_count); | ||
879 | list_for_each_entry(n, &context->names_list, list) { | ||
880 | pr_err("names[%d] = %p = %s\n", i++, n->name, | ||
881 | n->name->name ?: "(null)"); | ||
882 | } | ||
883 | dump_stack(); | ||
884 | return; | ||
885 | } | ||
886 | #endif | ||
887 | #if AUDIT_DEBUG | ||
888 | context->put_count = 0; | ||
889 | context->ino_count = 0; | ||
890 | #endif | ||
891 | |||
892 | list_for_each_entry_safe(n, next, &context->names_list, list) { | 869 | list_for_each_entry_safe(n, next, &context->names_list, list) { |
893 | list_del(&n->list); | 870 | list_del(&n->list); |
894 | if (n->name && n->name_put) | 871 | if (n->name) |
895 | final_putname(n->name); | 872 | putname(n->name); |
896 | if (n->should_free) | 873 | if (n->should_free) |
897 | kfree(n); | 874 | kfree(n); |
898 | } | 875 | } |
@@ -1711,9 +1688,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context, | |||
1711 | list_add_tail(&aname->list, &context->names_list); | 1688 | list_add_tail(&aname->list, &context->names_list); |
1712 | 1689 | ||
1713 | context->name_count++; | 1690 | context->name_count++; |
1714 | #if AUDIT_DEBUG | ||
1715 | context->ino_count++; | ||
1716 | #endif | ||
1717 | return aname; | 1691 | return aname; |
1718 | } | 1692 | } |
1719 | 1693 | ||
@@ -1734,8 +1708,10 @@ __audit_reusename(const __user char *uptr) | |||
1734 | list_for_each_entry(n, &context->names_list, list) { | 1708 | list_for_each_entry(n, &context->names_list, list) { |
1735 | if (!n->name) | 1709 | if (!n->name) |
1736 | continue; | 1710 | continue; |
1737 | if (n->name->uptr == uptr) | 1711 | if (n->name->uptr == uptr) { |
1712 | n->name->refcnt++; | ||
1738 | return n->name; | 1713 | return n->name; |
1714 | } | ||
1739 | } | 1715 | } |
1740 | return NULL; | 1716 | return NULL; |
1741 | } | 1717 | } |
@@ -1752,19 +1728,8 @@ void __audit_getname(struct filename *name) | |||
1752 | struct audit_context *context = current->audit_context; | 1728 | struct audit_context *context = current->audit_context; |
1753 | struct audit_names *n; | 1729 | struct audit_names *n; |
1754 | 1730 | ||
1755 | if (!context->in_syscall) { | 1731 | if (!context->in_syscall) |
1756 | #if AUDIT_DEBUG == 2 | ||
1757 | pr_err("%s:%d(:%d): ignoring getname(%p)\n", | ||
1758 | __FILE__, __LINE__, context->serial, name); | ||
1759 | dump_stack(); | ||
1760 | #endif | ||
1761 | return; | 1732 | return; |
1762 | } | ||
1763 | |||
1764 | #if AUDIT_DEBUG | ||
1765 | /* The filename _must_ have a populated ->name */ | ||
1766 | BUG_ON(!name->name); | ||
1767 | #endif | ||
1768 | 1733 | ||
1769 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); | 1734 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); |
1770 | if (!n) | 1735 | if (!n) |
@@ -1772,56 +1737,13 @@ void __audit_getname(struct filename *name) | |||
1772 | 1737 | ||
1773 | n->name = name; | 1738 | n->name = name; |
1774 | n->name_len = AUDIT_NAME_FULL; | 1739 | n->name_len = AUDIT_NAME_FULL; |
1775 | n->name_put = true; | ||
1776 | name->aname = n; | 1740 | name->aname = n; |
1741 | name->refcnt++; | ||
1777 | 1742 | ||
1778 | if (!context->pwd.dentry) | 1743 | if (!context->pwd.dentry) |
1779 | get_fs_pwd(current->fs, &context->pwd); | 1744 | get_fs_pwd(current->fs, &context->pwd); |
1780 | } | 1745 | } |
1781 | 1746 | ||
1782 | /* audit_putname - intercept a putname request | ||
1783 | * @name: name to intercept and delay for putname | ||
1784 | * | ||
1785 | * If we have stored the name from getname in the audit context, | ||
1786 | * then we delay the putname until syscall exit. | ||
1787 | * Called from include/linux/fs.h:putname(). | ||
1788 | */ | ||
1789 | void audit_putname(struct filename *name) | ||
1790 | { | ||
1791 | struct audit_context *context = current->audit_context; | ||
1792 | |||
1793 | BUG_ON(!context); | ||
1794 | if (!name->aname || !context->in_syscall) { | ||
1795 | #if AUDIT_DEBUG == 2 | ||
1796 | pr_err("%s:%d(:%d): final_putname(%p)\n", | ||
1797 | __FILE__, __LINE__, context->serial, name); | ||
1798 | if (context->name_count) { | ||
1799 | struct audit_names *n; | ||
1800 | int i = 0; | ||
1801 | |||
1802 | list_for_each_entry(n, &context->names_list, list) | ||
1803 | pr_err("name[%d] = %p = %s\n", i++, n->name, | ||
1804 | n->name->name ?: "(null)"); | ||
1805 | } | ||
1806 | #endif | ||
1807 | final_putname(name); | ||
1808 | } | ||
1809 | #if AUDIT_DEBUG | ||
1810 | else { | ||
1811 | ++context->put_count; | ||
1812 | if (context->put_count > context->name_count) { | ||
1813 | pr_err("%s:%d(:%d): major=%d in_syscall=%d putname(%p)" | ||
1814 | " name_count=%d put_count=%d\n", | ||
1815 | __FILE__, __LINE__, | ||
1816 | context->serial, context->major, | ||
1817 | context->in_syscall, name->name, | ||
1818 | context->name_count, context->put_count); | ||
1819 | dump_stack(); | ||
1820 | } | ||
1821 | } | ||
1822 | #endif | ||
1823 | } | ||
1824 | |||
1825 | /** | 1747 | /** |
1826 | * __audit_inode - store the inode and device from a lookup | 1748 | * __audit_inode - store the inode and device from a lookup |
1827 | * @name: name being audited | 1749 | * @name: name being audited |
@@ -1842,10 +1764,6 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, | |||
1842 | if (!name) | 1764 | if (!name) |
1843 | goto out_alloc; | 1765 | goto out_alloc; |
1844 | 1766 | ||
1845 | #if AUDIT_DEBUG | ||
1846 | /* The struct filename _must_ have a populated ->name */ | ||
1847 | BUG_ON(!name->name); | ||
1848 | #endif | ||
1849 | /* | 1767 | /* |
1850 | * If we have a pointer to an audit_names entry already, then we can | 1768 | * If we have a pointer to an audit_names entry already, then we can |
1851 | * just use it directly if the type is correct. | 1769 | * just use it directly if the type is correct. |
@@ -1863,7 +1781,17 @@ void __audit_inode(struct filename *name, const struct dentry *dentry, | |||
1863 | } | 1781 | } |
1864 | 1782 | ||
1865 | list_for_each_entry_reverse(n, &context->names_list, list) { | 1783 | list_for_each_entry_reverse(n, &context->names_list, list) { |
1866 | if (!n->name || strcmp(n->name->name, name->name)) | 1784 | if (n->ino) { |
1785 | /* valid inode number, use that for the comparison */ | ||
1786 | if (n->ino != inode->i_ino || | ||
1787 | n->dev != inode->i_sb->s_dev) | ||
1788 | continue; | ||
1789 | } else if (n->name) { | ||
1790 | /* inode number has not been set, check the name */ | ||
1791 | if (strcmp(n->name->name, name->name)) | ||
1792 | continue; | ||
1793 | } else | ||
1794 | /* no inode and no name (?!) ... this is odd ... */ | ||
1867 | continue; | 1795 | continue; |
1868 | 1796 | ||
1869 | /* match the correct record type */ | 1797 | /* match the correct record type */ |
@@ -1882,44 +1810,11 @@ out_alloc: | |||
1882 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); | 1810 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); |
1883 | if (!n) | 1811 | if (!n) |
1884 | return; | 1812 | return; |
1885 | /* unfortunately, while we may have a path name to record with the | ||
1886 | * inode, we can't always rely on the string lasting until the end of | ||
1887 | * the syscall so we need to create our own copy, it may fail due to | ||
1888 | * memory allocation issues, but we do our best */ | ||
1889 | if (name) { | 1813 | if (name) { |
1890 | /* we can't use getname_kernel() due to size limits */ | 1814 | n->name = name; |
1891 | size_t len = strlen(name->name) + 1; | 1815 | name->refcnt++; |
1892 | struct filename *new = __getname(); | ||
1893 | |||
1894 | if (unlikely(!new)) | ||
1895 | goto out; | ||
1896 | |||
1897 | if (len <= (PATH_MAX - sizeof(*new))) { | ||
1898 | new->name = (char *)(new) + sizeof(*new); | ||
1899 | new->separate = false; | ||
1900 | } else if (len <= PATH_MAX) { | ||
1901 | /* this looks odd, but is due to final_putname() */ | ||
1902 | struct filename *new2; | ||
1903 | |||
1904 | new2 = kmalloc(sizeof(*new2), GFP_KERNEL); | ||
1905 | if (unlikely(!new2)) { | ||
1906 | __putname(new); | ||
1907 | goto out; | ||
1908 | } | ||
1909 | new2->name = (char *)new; | ||
1910 | new2->separate = true; | ||
1911 | new = new2; | ||
1912 | } else { | ||
1913 | /* we should never get here, but let's be safe */ | ||
1914 | __putname(new); | ||
1915 | goto out; | ||
1916 | } | ||
1917 | strlcpy((char *)new->name, name->name, len); | ||
1918 | new->uptr = NULL; | ||
1919 | new->aname = n; | ||
1920 | n->name = new; | ||
1921 | n->name_put = true; | ||
1922 | } | 1816 | } |
1817 | |||
1923 | out: | 1818 | out: |
1924 | if (parent) { | 1819 | if (parent) { |
1925 | n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; | 1820 | n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; |
@@ -1970,11 +1865,16 @@ void __audit_inode_child(const struct inode *parent, | |||
1970 | 1865 | ||
1971 | /* look for a parent entry first */ | 1866 | /* look for a parent entry first */ |
1972 | list_for_each_entry(n, &context->names_list, list) { | 1867 | list_for_each_entry(n, &context->names_list, list) { |
1973 | if (!n->name || n->type != AUDIT_TYPE_PARENT) | 1868 | if (!n->name || |
1869 | (n->type != AUDIT_TYPE_PARENT && | ||
1870 | n->type != AUDIT_TYPE_UNKNOWN)) | ||
1974 | continue; | 1871 | continue; |
1975 | 1872 | ||
1976 | if (n->ino == parent->i_ino && | 1873 | if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev && |
1977 | !audit_compare_dname_path(dname, n->name->name, n->name_len)) { | 1874 | !audit_compare_dname_path(dname, |
1875 | n->name->name, n->name_len)) { | ||
1876 | if (n->type == AUDIT_TYPE_UNKNOWN) | ||
1877 | n->type = AUDIT_TYPE_PARENT; | ||
1978 | found_parent = n; | 1878 | found_parent = n; |
1979 | break; | 1879 | break; |
1980 | } | 1880 | } |
@@ -1983,11 +1883,8 @@ void __audit_inode_child(const struct inode *parent, | |||
1983 | /* is there a matching child entry? */ | 1883 | /* is there a matching child entry? */ |
1984 | list_for_each_entry(n, &context->names_list, list) { | 1884 | list_for_each_entry(n, &context->names_list, list) { |
1985 | /* can only match entries that have a name */ | 1885 | /* can only match entries that have a name */ |
1986 | if (!n->name || n->type != type) | 1886 | if (!n->name || |
1987 | continue; | 1887 | (n->type != type && n->type != AUDIT_TYPE_UNKNOWN)) |
1988 | |||
1989 | /* if we found a parent, make sure this one is a child of it */ | ||
1990 | if (found_parent && (n->name != found_parent->name)) | ||
1991 | continue; | 1888 | continue; |
1992 | 1889 | ||
1993 | if (!strcmp(dname, n->name->name) || | 1890 | if (!strcmp(dname, n->name->name) || |
@@ -1995,6 +1892,8 @@ void __audit_inode_child(const struct inode *parent, | |||
1995 | found_parent ? | 1892 | found_parent ? |
1996 | found_parent->name_len : | 1893 | found_parent->name_len : |
1997 | AUDIT_NAME_FULL)) { | 1894 | AUDIT_NAME_FULL)) { |
1895 | if (n->type == AUDIT_TYPE_UNKNOWN) | ||
1896 | n->type = type; | ||
1998 | found_child = n; | 1897 | found_child = n; |
1999 | break; | 1898 | break; |
2000 | } | 1899 | } |
@@ -2019,10 +1918,10 @@ void __audit_inode_child(const struct inode *parent, | |||
2019 | if (found_parent) { | 1918 | if (found_parent) { |
2020 | found_child->name = found_parent->name; | 1919 | found_child->name = found_parent->name; |
2021 | found_child->name_len = AUDIT_NAME_FULL; | 1920 | found_child->name_len = AUDIT_NAME_FULL; |
2022 | /* don't call __putname() */ | 1921 | found_child->name->refcnt++; |
2023 | found_child->name_put = false; | ||
2024 | } | 1922 | } |
2025 | } | 1923 | } |
1924 | |||
2026 | if (inode) | 1925 | if (inode) |
2027 | audit_copy_inode(found_child, dentry, inode); | 1926 | audit_copy_inode(found_child, dentry, inode); |
2028 | else | 1927 | else |