diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/audit.h | 17 | ||||
-rw-r--r-- | kernel/auditsc.c | 105 |
2 files changed, 13 insertions, 109 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 4f521964ccaa..0c38604a630c 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,11 +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 | |||
1850 | /* | 1767 | /* |
1851 | * 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 |
1852 | * just use it directly if the type is correct. | 1769 | * just use it directly if the type is correct. |
@@ -1893,9 +1810,10 @@ out_alloc: | |||
1893 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); | 1810 | n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); |
1894 | if (!n) | 1811 | if (!n) |
1895 | return; | 1812 | return; |
1896 | if (name) | 1813 | if (name) { |
1897 | /* no need to set ->name_put as the original will cleanup */ | ||
1898 | n->name = name; | 1814 | n->name = name; |
1815 | name->refcnt++; | ||
1816 | } | ||
1899 | 1817 | ||
1900 | out: | 1818 | out: |
1901 | if (parent) { | 1819 | if (parent) { |
@@ -2000,8 +1918,7 @@ void __audit_inode_child(const struct inode *parent, | |||
2000 | if (found_parent) { | 1918 | if (found_parent) { |
2001 | found_child->name = found_parent->name; | 1919 | found_child->name = found_parent->name; |
2002 | found_child->name_len = AUDIT_NAME_FULL; | 1920 | found_child->name_len = AUDIT_NAME_FULL; |
2003 | /* don't call __putname() */ | 1921 | found_child->name->refcnt++; |
2004 | found_child->name_put = false; | ||
2005 | } | 1922 | } |
2006 | } | 1923 | } |
2007 | 1924 | ||