aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namei.c29
-rw-r--r--include/linux/audit.h3
-rw-r--r--include/linux/fs.h9
-rw-r--r--kernel/audit.h17
-rw-r--r--kernel/auditsc.c105
5 files changed, 29 insertions, 134 deletions
diff --git a/fs/namei.c b/fs/namei.c
index a3fde77d4abf..96ca11dea4a2 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -118,15 +118,6 @@
118 * POSIX.1 2.4: an empty pathname is invalid (ENOENT). 118 * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
119 * PATH_MAX includes the nul terminator --RR. 119 * PATH_MAX includes the nul terminator --RR.
120 */ 120 */
121void final_putname(struct filename *name)
122{
123 if (name->separate) {
124 __putname(name->name);
125 kfree(name);
126 } else {
127 __putname(name);
128 }
129}
130 121
131#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) 122#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename))
132 123
@@ -145,6 +136,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
145 result = __getname(); 136 result = __getname();
146 if (unlikely(!result)) 137 if (unlikely(!result))
147 return ERR_PTR(-ENOMEM); 138 return ERR_PTR(-ENOMEM);
139 result->refcnt = 1;
148 140
149 /* 141 /*
150 * First, try to embed the struct filename inside the names_cache 142 * First, try to embed the struct filename inside the names_cache
@@ -179,6 +171,7 @@ recopy:
179 } 171 }
180 result->name = kname; 172 result->name = kname;
181 result->separate = true; 173 result->separate = true;
174 result->refcnt = 1;
182 max = PATH_MAX; 175 max = PATH_MAX;
183 goto recopy; 176 goto recopy;
184 } 177 }
@@ -202,7 +195,7 @@ recopy:
202 return result; 195 return result;
203 196
204error: 197error:
205 final_putname(result); 198 putname(result);
206 return err; 199 return err;
207} 200}
208 201
@@ -243,19 +236,25 @@ getname_kernel(const char * filename)
243 memcpy((char *)result->name, filename, len); 236 memcpy((char *)result->name, filename, len);
244 result->uptr = NULL; 237 result->uptr = NULL;
245 result->aname = NULL; 238 result->aname = NULL;
239 result->refcnt = 1;
246 audit_getname(result); 240 audit_getname(result);
247 241
248 return result; 242 return result;
249} 243}
250 244
251#ifdef CONFIG_AUDITSYSCALL
252void putname(struct filename *name) 245void putname(struct filename *name)
253{ 246{
254 if (unlikely(!audit_dummy_context())) 247 BUG_ON(name->refcnt <= 0);
255 return audit_putname(name); 248
256 final_putname(name); 249 if (--name->refcnt > 0)
250 return;
251
252 if (name->separate) {
253 __putname(name->name);
254 kfree(name);
255 } else
256 __putname(name);
257} 257}
258#endif
259 258
260static int check_acl(struct inode *inode, int mask) 259static int check_acl(struct inode *inode, int mask)
261{ 260{
diff --git a/include/linux/audit.h b/include/linux/audit.h
index af84234e1f6e..87c2d347d255 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -128,7 +128,6 @@ extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
128extern void __audit_syscall_exit(int ret_success, long ret_value); 128extern void __audit_syscall_exit(int ret_success, long ret_value);
129extern struct filename *__audit_reusename(const __user char *uptr); 129extern struct filename *__audit_reusename(const __user char *uptr);
130extern void __audit_getname(struct filename *name); 130extern void __audit_getname(struct filename *name);
131extern void audit_putname(struct filename *name);
132 131
133#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */ 132#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */
134#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */ 133#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
@@ -353,8 +352,6 @@ static inline struct filename *audit_reusename(const __user char *name)
353} 352}
354static inline void audit_getname(struct filename *name) 353static inline void audit_getname(struct filename *name)
355{ } 354{ }
356static inline void audit_putname(struct filename *name)
357{ }
358static inline void __audit_inode(struct filename *name, 355static inline void __audit_inode(struct filename *name,
359 const struct dentry *dentry, 356 const struct dentry *dentry,
360 unsigned int flags) 357 unsigned int flags)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f90c0282c114..b49842fe203f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2080,6 +2080,7 @@ struct filename {
2080 const char *name; /* pointer to actual string */ 2080 const char *name; /* pointer to actual string */
2081 const __user char *uptr; /* original userland pointer */ 2081 const __user char *uptr; /* original userland pointer */
2082 struct audit_names *aname; 2082 struct audit_names *aname;
2083 int refcnt;
2083 bool separate; /* should "name" be freed? */ 2084 bool separate; /* should "name" be freed? */
2084}; 2085};
2085 2086
@@ -2101,6 +2102,7 @@ extern int filp_close(struct file *, fl_owner_t id);
2101extern struct filename *getname_flags(const char __user *, int, int *); 2102extern struct filename *getname_flags(const char __user *, int, int *);
2102extern struct filename *getname(const char __user *); 2103extern struct filename *getname(const char __user *);
2103extern struct filename *getname_kernel(const char *); 2104extern struct filename *getname_kernel(const char *);
2105extern void putname(struct filename *name);
2104 2106
2105enum { 2107enum {
2106 FILE_CREATED = 1, 2108 FILE_CREATED = 1,
@@ -2121,15 +2123,8 @@ extern void __init vfs_caches_init(unsigned long);
2121 2123
2122extern struct kmem_cache *names_cachep; 2124extern struct kmem_cache *names_cachep;
2123 2125
2124extern void final_putname(struct filename *name);
2125
2126#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL) 2126#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
2127#define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) 2127#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
2128#ifndef CONFIG_AUDITSYSCALL
2129#define putname(name) final_putname(name)
2130#else
2131extern void putname(struct filename *name);
2132#endif
2133 2128
2134#ifdef CONFIG_BLOCK 2129#ifdef CONFIG_BLOCK
2135extern int register_blkdev(unsigned int, const char *); 2130extern int register_blkdev(unsigned int, const char *);
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
218extern u32 audit_ever_enabled; 205extern 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 */
1789void 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
1900out: 1818out:
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