* [PATCH v7 01/49] audit: remove unnecessary NULL ptr checks from do_path_lookup
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 02/49] audit: pass in dentry to audit_copy_inode wherever possible Jeff Layton
` (47 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
As best I can tell, whenever retval == 0, nd->path.dentry and nd->inode
are also non-NULL. Eliminate those checks and the superfluous
audit_context check.
Signed-off-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index dd1ed1b..e3661762 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1976,12 +1976,8 @@ static int do_path_lookup(int dfd, const char *name,
if (unlikely(retval == -ESTALE))
retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
- if (likely(!retval)) {
- if (unlikely(!audit_dummy_context())) {
- if (nd->path.dentry && nd->inode)
- audit_inode(name, nd->path.dentry);
- }
- }
+ if (likely(!retval))
+ audit_inode(name, nd->path.dentry);
return retval;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 02/49] audit: pass in dentry to audit_copy_inode wherever possible
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
2012-10-02 0:16 ` [PATCH v7 01/49] audit: remove unnecessary NULL ptr checks from do_path_lookup Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 15:53 ` Christoph Hellwig
2012-10-02 0:16 ` [PATCH v7 03/49] audit: no need to walk list in audit_inode if name is NULL Jeff Layton
` (46 subsequent siblings)
48 siblings, 1 reply; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
In some cases, we were passing in NULL even when we have a dentry.
Reported-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
kernel/auditsc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4b96415..5c45b9b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2226,7 +2226,7 @@ void __audit_inode_child(const struct dentry *dentry,
if (!strcmp(dname, n->name) ||
!audit_compare_dname_path(dname, n->name, &dirlen)) {
if (inode)
- audit_copy_inode(n, NULL, inode);
+ audit_copy_inode(n, dentry, inode);
else
n->ino = (unsigned long)-1;
found_child = n->name;
@@ -2258,7 +2258,7 @@ add_names:
}
if (inode)
- audit_copy_inode(n, NULL, inode);
+ audit_copy_inode(n, dentry, inode);
}
}
EXPORT_SYMBOL_GPL(__audit_inode_child);
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH v7 02/49] audit: pass in dentry to audit_copy_inode wherever possible
2012-10-02 0:16 ` [PATCH v7 02/49] audit: pass in dentry to audit_copy_inode wherever possible Jeff Layton
@ 2012-10-02 15:53 ` Christoph Hellwig
2012-10-02 16:40 ` Jeff Layton
0 siblings, 1 reply; 56+ messages in thread
From: Christoph Hellwig @ 2012-10-02 15:53 UTC (permalink / raw)
To: Jeff Layton; +Cc: viro, eparis, linux-fsdevel, linux-kernel, linux-audit
On Mon, Oct 01, 2012 at 08:16:11PM -0400, Jeff Layton wrote:
> In some cases, we were passing in NULL even when we have a dentry.
>
> Reported-by: Eric Paris <eparis@redhat.com>
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
> kernel/auditsc.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4b96415..5c45b9b 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2226,7 +2226,7 @@ void __audit_inode_child(const struct dentry *dentry,
> if (!strcmp(dname, n->name) ||
> !audit_compare_dname_path(dname, n->name, &dirlen)) {
> if (inode)
> - audit_copy_inode(n, NULL, inode);
> + audit_copy_inode(n, dentry, inode);
Btw, the calling conventions here also seems fairly ugly.
Instead of the optional dentry parameter I'd have a audit_copy_inode
that takes just the name and the inode, and an optional direct call
to audit_copy_fcaps for those callers that have a dentry. That would
also allow removing the branch for the dentry == NULL case in
audit_copy_fcaps.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v7 02/49] audit: pass in dentry to audit_copy_inode wherever possible
2012-10-02 15:53 ` Christoph Hellwig
@ 2012-10-02 16:40 ` Jeff Layton
0 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 16:40 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: viro, eparis, linux-fsdevel, linux-kernel, linux-audit
On Tue, 2 Oct 2012 11:53:38 -0400
Christoph Hellwig <hch@infradead.org> wrote:
> On Mon, Oct 01, 2012 at 08:16:11PM -0400, Jeff Layton wrote:
> > In some cases, we were passing in NULL even when we have a dentry.
> >
> > Reported-by: Eric Paris <eparis@redhat.com>
> > Signed-off-by: Jeff Layton <jlayton@redhat.com>
> > ---
> > kernel/auditsc.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index 4b96415..5c45b9b 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2226,7 +2226,7 @@ void __audit_inode_child(const struct dentry *dentry,
> > if (!strcmp(dname, n->name) ||
> > !audit_compare_dname_path(dname, n->name, &dirlen)) {
> > if (inode)
> > - audit_copy_inode(n, NULL, inode);
> > + audit_copy_inode(n, dentry, inode);
>
> Btw, the calling conventions here also seems fairly ugly.
>
> Instead of the optional dentry parameter I'd have a audit_copy_inode
> that takes just the name and the inode, and an optional direct call
> to audit_copy_fcaps for those callers that have a dentry. That would
> also allow removing the branch for the dentry == NULL case in
> audit_copy_fcaps.
>
[...]
> On Mon, Oct 01, 2012 at 08:16:12PM -0400, Jeff Layton wrote:
> > If name is NULL then the condition in the loop will never be true. Also,
> > with this change, we can eliminate the check for n->name == NULL since
> > the equivalence check will never be true if it is.
>
> Given that name == NULL is a static condition it seems like these
> should be two different calls, E.g. audit_dentry and audit_path.
>
Thanks Christoph,
Both of the above are good suggestions, but I'd prefer not to have to
respin this whole set to implement them. I believe what I have here is
an improvement on what's there now. Do you have any objection to doing
the above in a separate set on top of this series?
--
Jeff Layton <jlayton@redhat.com>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v7 03/49] audit: no need to walk list in audit_inode if name is NULL
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
2012-10-02 0:16 ` [PATCH v7 01/49] audit: remove unnecessary NULL ptr checks from do_path_lookup Jeff Layton
2012-10-02 0:16 ` [PATCH v7 02/49] audit: pass in dentry to audit_copy_inode wherever possible Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 15:56 ` Christoph Hellwig
2012-10-02 0:16 ` [PATCH v7 04/49] audit: reverse arguments to audit_inode_child Jeff Layton
` (45 subsequent siblings)
48 siblings, 1 reply; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
If name is NULL then the condition in the loop will never be true. Also,
with this change, we can eliminate the check for n->name == NULL since
the equivalence check will never be true if it is.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
kernel/auditsc.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 5c45b9b..4099440 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2161,11 +2161,15 @@ void __audit_inode(const char *name, const struct dentry *dentry)
if (!context->in_syscall)
return;
+ if (!name)
+ goto out_alloc;
+
list_for_each_entry_reverse(n, &context->names_list, list) {
- if (n->name && (n->name == name))
+ if (n->name == name)
goto out;
}
+out_alloc:
/* unable to find the name from a previous getname() */
n = audit_alloc_name(context);
if (!n)
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH v7 03/49] audit: no need to walk list in audit_inode if name is NULL
2012-10-02 0:16 ` [PATCH v7 03/49] audit: no need to walk list in audit_inode if name is NULL Jeff Layton
@ 2012-10-02 15:56 ` Christoph Hellwig
0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2012-10-02 15:56 UTC (permalink / raw)
To: Jeff Layton; +Cc: viro, eparis, linux-fsdevel, linux-kernel, linux-audit
On Mon, Oct 01, 2012 at 08:16:12PM -0400, Jeff Layton wrote:
> If name is NULL then the condition in the loop will never be true. Also,
> with this change, we can eliminate the check for n->name == NULL since
> the equivalence check will never be true if it is.
Given that name == NULL is a static condition it seems like these
should be two different calls, E.g. audit_dentry and audit_path.
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v7 04/49] audit: reverse arguments to audit_inode_child
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (2 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 03/49] audit: no need to walk list in audit_inode if name is NULL Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 05/49] audit: add a new "type" field to audit_names struct Jeff Layton
` (44 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Most of the callers get called with an inode and dentry in the reverse
order. The compiler then has to reshuffle the arg registers and/or
stack in order to pass them on to audit_inode_child.
Reverse those arguments for a micro-optimization.
Reported-by: Eric Paris <eparis@redhat.com>
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/btrfs/ioctl.c | 2 +-
fs/namei.c | 2 +-
include/linux/audit.h | 14 +++++++-------
include/linux/fsnotify.h | 8 ++++----
kernel/auditsc.c | 8 ++++----
5 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 9df50fa..7e78d47 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -614,7 +614,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir);
- audit_inode_child(victim, dir);
+ audit_inode_child(dir, victim);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
diff --git a/fs/namei.c b/fs/namei.c
index e3661762..d431111 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2180,7 +2180,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir);
- audit_inode_child(victim, dir);
+ audit_inode_child(dir, victim);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 36abf2a..2d8b761 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -462,8 +462,8 @@ extern void __audit_syscall_exit(int ret_success, long ret_value);
extern void __audit_getname(const char *name);
extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct dentry *dentry);
-extern void __audit_inode_child(const struct dentry *dentry,
- const struct inode *parent);
+extern void __audit_inode_child(const struct inode *parent,
+ const struct dentry *dentry);
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
extern void __audit_ptrace(struct task_struct *t);
@@ -502,10 +502,10 @@ static inline void audit_inode(const char *name, const struct dentry *dentry) {
if (unlikely(!audit_dummy_context()))
__audit_inode(name, dentry);
}
-static inline void audit_inode_child(const struct dentry *dentry,
- const struct inode *parent) {
+static inline void audit_inode_child(const struct inode *parent,
+ const struct dentry *dentry) {
if (unlikely(!audit_dummy_context()))
- __audit_inode_child(dentry, parent);
+ __audit_inode_child(parent, dentry);
}
void audit_core_dumps(long signr);
@@ -631,9 +631,9 @@ extern int audit_signals;
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
#define __audit_inode(n,d) do { ; } while (0)
-#define __audit_inode_child(i,p) do { ; } while (0)
+#define __audit_inode_child(p,d) do { ; } while (0)
#define audit_inode(n,d) do { (void)(d); } while (0)
-#define audit_inode_child(i,p) do { ; } while (0)
+#define audit_inode_child(p,d) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0)
#define audit_seccomp(i,s,c) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) (0)
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index a6dfe69..9c28471 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -109,7 +109,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
if (source)
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
- audit_inode_child(moved, new_dir);
+ audit_inode_child(new_dir, moved);
}
/*
@@ -155,7 +155,7 @@ static inline void fsnotify_inoderemove(struct inode *inode)
*/
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
- audit_inode_child(dentry, inode);
+ audit_inode_child(inode, dentry);
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
}
@@ -168,7 +168,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
{
fsnotify_link_count(inode);
- audit_inode_child(new_dentry, dir);
+ audit_inode_child(dir, new_dentry);
fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
}
@@ -181,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
__u32 mask = (FS_CREATE | FS_ISDIR);
struct inode *d_inode = dentry->d_inode;
- audit_inode_child(dentry, inode);
+ audit_inode_child(inode, dentry);
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4099440..ff58089 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2180,9 +2180,9 @@ out:
}
/**
- * audit_inode_child - collect inode info for created/removed objects
- * @dentry: dentry being audited
+ * __audit_inode_child - collect inode info for created/removed objects
* @parent: inode of dentry parent
+ * @dentry: dentry being audited
*
* For syscalls that create or remove filesystem objects, audit_inode
* can only collect information for the filesystem object's parent.
@@ -2192,8 +2192,8 @@ out:
* must be hooked prior, in order to capture the target inode during
* unsuccessful attempts.
*/
-void __audit_inode_child(const struct dentry *dentry,
- const struct inode *parent)
+void __audit_inode_child(const struct inode *parent,
+ const struct dentry *dentry)
{
struct audit_context *context = current->audit_context;
const char *found_parent = NULL, *found_child = NULL;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 05/49] audit: add a new "type" field to audit_names struct
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (3 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 04/49] audit: reverse arguments to audit_inode_child Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 15:50 ` Christoph Hellwig
2012-10-02 0:16 ` [PATCH v7 06/49] audit: set the name_len in audit_inode for parent lookups Jeff Layton
` (43 subsequent siblings)
48 siblings, 1 reply; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
For now, we just have two possibilities:
UNKNOWN: for a new audit_names record that we don't know anything about yet
NORMAL: for everything else
In later patches, we'll add other types so we can distinguish and update
records created under different circumstances.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
include/linux/audit.h | 5 +++++
kernel/auditsc.c | 15 ++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 2d8b761..48c49eb 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -450,6 +450,11 @@ struct audit_field {
extern int __init audit_register_class(int class, unsigned *list);
extern int audit_classify_syscall(int abi, unsigned syscall);
extern int audit_classify_arch(int arch);
+
+/* audit_names->type values */
+#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
+#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
+
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
/* Public API */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ff58089..bd11d09 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -120,6 +120,7 @@ struct audit_names {
struct audit_cap_data fcap;
unsigned int fcap_ver;
int name_len; /* number of name's characters to log */
+ unsigned char type; /* record type */
bool name_put; /* call __putname() for this name */
/*
* This was an allocated audit_names and not from the array of
@@ -2009,7 +2010,8 @@ retry:
#endif
}
-static struct audit_names *audit_alloc_name(struct audit_context *context)
+static struct audit_names *audit_alloc_name(struct audit_context *context,
+ unsigned char type)
{
struct audit_names *aname;
@@ -2024,6 +2026,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
}
aname->ino = (unsigned long)-1;
+ aname->type = type;
list_add_tail(&aname->list, &context->names_list);
context->name_count++;
@@ -2054,7 +2057,7 @@ void __audit_getname(const char *name)
return;
}
- n = audit_alloc_name(context);
+ n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
if (!n)
return;
@@ -2171,12 +2174,13 @@ void __audit_inode(const char *name, const struct dentry *dentry)
out_alloc:
/* unable to find the name from a previous getname() */
- n = audit_alloc_name(context);
+ n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
if (!n)
return;
out:
handle_path(dentry);
audit_copy_inode(n, dentry, inode);
+ n->type = AUDIT_TYPE_NORMAL;
}
/**
@@ -2233,6 +2237,7 @@ void __audit_inode_child(const struct inode *parent,
audit_copy_inode(n, dentry, inode);
else
n->ino = (unsigned long)-1;
+ n->type = AUDIT_TYPE_NORMAL;
found_child = n->name;
goto add_names;
}
@@ -2240,14 +2245,14 @@ void __audit_inode_child(const struct inode *parent,
add_names:
if (!found_parent) {
- n = audit_alloc_name(context);
+ n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
if (!n)
return;
audit_copy_inode(n, NULL, parent);
}
if (!found_child) {
- n = audit_alloc_name(context);
+ n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
if (!n)
return;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* Re: [PATCH v7 05/49] audit: add a new "type" field to audit_names struct
2012-10-02 0:16 ` [PATCH v7 05/49] audit: add a new "type" field to audit_names struct Jeff Layton
@ 2012-10-02 15:50 ` Christoph Hellwig
2012-10-02 15:58 ` Jeff Layton
2012-10-02 16:55 ` Jeff Layton
0 siblings, 2 replies; 56+ messages in thread
From: Christoph Hellwig @ 2012-10-02 15:50 UTC (permalink / raw)
To: Jeff Layton; +Cc: viro, eparis, linux-fsdevel, linux-kernel, linux-audit
> +#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
> +#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
I don't care about tab vs space after the #define, but at least be
consistent.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v7 05/49] audit: add a new "type" field to audit_names struct
2012-10-02 15:50 ` Christoph Hellwig
@ 2012-10-02 15:58 ` Jeff Layton
2012-10-02 16:55 ` Jeff Layton
1 sibling, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 15:58 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: viro, eparis, linux-fsdevel, linux-kernel, linux-audit
On Tue, 2 Oct 2012 11:50:28 -0400
Christoph Hellwig <hch@infradead.org> wrote:
> > +#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
> > +#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
>
> I don't care about tab vs space after the #define, but at least be
> consistent.
>
My bad...will fix.
--
Jeff Layton <jlayton@redhat.com>
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v7 05/49] audit: add a new "type" field to audit_names struct
2012-10-02 15:50 ` Christoph Hellwig
2012-10-02 15:58 ` Jeff Layton
@ 2012-10-02 16:55 ` Jeff Layton
1 sibling, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 16:55 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linux-fsdevel, linux-audit, viro, linux-kernel
On Tue, 2 Oct 2012 11:50:28 -0400
Christoph Hellwig <hch@infradead.org> wrote:
> > +#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
> > +#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
>
> I don't care about tab vs space after the #define, but at least be
> consistent.
>
I went ahead and fixed this in my tree but since it's just a whitespace
change, I'm not going to bother reposting unless Al requests it or
there are larger changes that need to be made.
--
Jeff Layton <jlayton@redhat.com>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v7 06/49] audit: set the name_len in audit_inode for parent lookups
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (4 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 05/49] audit: add a new "type" field to audit_names struct Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 07/49] audit: remove dirlen argument to audit_compare_dname_path Jeff Layton
` (42 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Currently, this gets set mostly by happenstance when we call into
audit_inode_child. While that might be a little more efficient, it seems
wrong. If the syscall ends up failing before audit_inode_child ever gets
called, then you'll have an audit_names record that shows the full path
but has the parent inode info attached.
Fix this by passing in a parent flag when we call audit_inode that gets
set to the value of LOOKUP_PARENT. We can then fix up the pathname for
the audit entry correctly from the get-go.
While we're at it, clean up the no-op macro for audit_inode in the
!CONFIG_AUDITSYSCALL case.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 14 +++++++-------
fs/open.c | 4 ++--
fs/xattr.c | 8 ++++----
include/linux/audit.h | 13 ++++++++-----
ipc/mqueue.c | 8 ++++----
kernel/audit.h | 1 +
kernel/auditfilter.c | 30 ++++++++++++++++++++++++++++++
kernel/auditsc.c | 41 +++++++++++++++++++++++++++++------------
8 files changed, 85 insertions(+), 34 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index d431111..6c9d86d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1977,7 +1977,7 @@ static int do_path_lookup(int dfd, const char *name,
retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
if (likely(!retval))
- audit_inode(name, nd->path.dentry);
+ audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
return retval;
}
@@ -2652,7 +2652,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = complete_walk(nd);
if (error)
return error;
- audit_inode(pathname, nd->path.dentry);
+ audit_inode(pathname, nd->path.dentry, 0);
if (open_flag & O_CREAT) {
error = -EISDIR;
goto out;
@@ -2662,7 +2662,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = complete_walk(nd);
if (error)
return error;
- audit_inode(pathname, dir);
+ audit_inode(pathname, dir, 0);
goto finish_open;
}
@@ -2691,7 +2691,7 @@ static int do_last(struct nameidata *nd, struct path *path,
if (error)
return error;
- audit_inode(pathname, dir);
+ audit_inode(pathname, dir, 0);
error = -EISDIR;
/* trailing slashes? */
if (nd->last.name[nd->last.len])
@@ -2721,7 +2721,7 @@ retry_lookup:
!S_ISREG(file->f_path.dentry->d_inode->i_mode))
will_truncate = false;
- audit_inode(pathname, file->f_path.dentry);
+ audit_inode(pathname, file->f_path.dentry, 0);
goto opened;
}
@@ -2738,7 +2738,7 @@ retry_lookup:
* create/update audit record if it already exists.
*/
if (path->dentry->d_inode)
- audit_inode(pathname, path->dentry);
+ audit_inode(pathname, path->dentry, 0);
/*
* If atomic_open() acquired write access it is dropped now due to
@@ -2803,7 +2803,7 @@ finish_lookup:
error = -ENOTDIR;
if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
goto out;
- audit_inode(pathname, nd->path.dentry);
+ audit_inode(pathname, nd->path.dentry, 0);
finish_open:
if (!S_ISREG(nd->inode->i_mode))
will_truncate = false;
diff --git a/fs/open.c b/fs/open.c
index e1f2cdb..ec06921 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -481,7 +481,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)
file = fget(fd);
if (file) {
- audit_inode(NULL, file->f_path.dentry);
+ audit_inode(NULL, file->f_path.dentry, 0);
err = chmod_common(&file->f_path, mode);
fput(file);
}
@@ -594,7 +594,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
if (error)
goto out_fput;
dentry = file->f_path.dentry;
- audit_inode(NULL, dentry);
+ audit_inode(NULL, dentry, 0);
error = chown_common(&file->f_path, user, group);
mnt_drop_write_file(file);
out_fput:
diff --git a/fs/xattr.c b/fs/xattr.c
index 4d45b71..588455b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -408,7 +408,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
if (!f)
return error;
dentry = f->f_path.dentry;
- audit_inode(NULL, dentry);
+ audit_inode(NULL, dentry, 0);
error = mnt_want_write_file(f);
if (!error) {
error = setxattr(dentry, name, value, size, flags);
@@ -502,7 +502,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
f = fget_light(fd, &fput_needed);
if (!f)
return error;
- audit_inode(NULL, f->f_path.dentry);
+ audit_inode(NULL, f->f_path.dentry, 0);
error = getxattr(f->f_path.dentry, name, value, size);
fput_light(f, fput_needed);
return error;
@@ -583,7 +583,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
f = fget_light(fd, &fput_needed);
if (!f)
return error;
- audit_inode(NULL, f->f_path.dentry);
+ audit_inode(NULL, f->f_path.dentry, 0);
error = listxattr(f->f_path.dentry, list, size);
fput_light(f, fput_needed);
return error;
@@ -654,7 +654,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
if (!f)
return error;
dentry = f->f_path.dentry;
- audit_inode(NULL, dentry);
+ audit_inode(NULL, dentry, 0);
error = mnt_want_write_file(f);
if (!error) {
error = removexattr(dentry, name);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 48c49eb..155524b 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -454,6 +454,7 @@ extern int audit_classify_arch(int arch);
/* audit_names->type values */
#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
+#define AUDIT_TYPE_PARENT 2 /* a parent audit record */
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
@@ -466,7 +467,8 @@ extern void __audit_syscall_entry(int arch,
extern void __audit_syscall_exit(int ret_success, long ret_value);
extern void __audit_getname(const char *name);
extern void audit_putname(const char *name);
-extern void __audit_inode(const char *name, const struct dentry *dentry);
+extern void __audit_inode(const char *name, const struct dentry *dentry,
+ unsigned int parent);
extern void __audit_inode_child(const struct inode *parent,
const struct dentry *dentry);
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
@@ -503,9 +505,10 @@ static inline void audit_getname(const char *name)
if (unlikely(!audit_dummy_context()))
__audit_getname(name);
}
-static inline void audit_inode(const char *name, const struct dentry *dentry) {
+static inline void audit_inode(const char *name, const struct dentry *dentry,
+ unsigned int parent) {
if (unlikely(!audit_dummy_context()))
- __audit_inode(name, dentry);
+ __audit_inode(name, dentry, parent);
}
static inline void audit_inode_child(const struct inode *parent,
const struct dentry *dentry) {
@@ -635,9 +638,9 @@ extern int audit_signals;
#define audit_dummy_context() 1
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
-#define __audit_inode(n,d) do { ; } while (0)
+#define __audit_inode(n,d,p) do { ; } while (0)
#define __audit_inode_child(p,d) do { ; } while (0)
-#define audit_inode(n,d) do { (void)(d); } while (0)
+#define audit_inode(n,d,p) do { ; } while (0)
#define audit_inode_child(p,d) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0)
#define audit_seccomp(i,s,c) do { ; } while (0)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 9a08acc..69cb5fe 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -805,7 +805,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
if (oflag & O_CREAT) {
if (path.dentry->d_inode) { /* entry already exists */
- audit_inode(name, path.dentry);
+ audit_inode(name, path.dentry, 0);
if (oflag & O_EXCL) {
error = -EEXIST;
goto out;
@@ -825,7 +825,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
error = -ENOENT;
goto out;
}
- audit_inode(name, path.dentry);
+ audit_inode(name, path.dentry, 0);
filp = do_open(&path, oflag);
}
@@ -979,7 +979,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
goto out_fput;
}
info = MQUEUE_I(inode);
- audit_inode(NULL, filp->f_path.dentry);
+ audit_inode(NULL, filp->f_path.dentry, 0);
if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
ret = -EBADF;
@@ -1096,7 +1096,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
goto out_fput;
}
info = MQUEUE_I(inode);
- audit_inode(NULL, filp->f_path.dentry);
+ audit_inode(NULL, filp->f_path.dentry, 0);
if (unlikely(!(filp->f_mode & FMODE_READ))) {
ret = -EBADF;
diff --git a/kernel/audit.h b/kernel/audit.h
index 8167668..276ca88 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -76,6 +76,7 @@ static inline int audit_hash_ino(u32 ino)
extern int audit_match_class(int class, unsigned syscall);
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
+extern int parent_len(const char *path);
extern int audit_compare_dname_path(const char *dname, const char *path,
int *dirlen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index a6c3f1a..29b167b 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1198,6 +1198,36 @@ int audit_comparator(u32 left, u32 op, u32 right)
}
}
+/**
+ * parent_len - find the length of the parent portion of a pathname
+ * @path: pathname of which to determine length
+ */
+int parent_len(const char *path)
+{
+ int plen;
+ const char *p;
+
+ plen = strlen(path);
+
+ if (plen == 0)
+ return plen;
+
+ /* disregard trailing slashes */
+ p = path + plen - 1;
+ while ((*p == '/') && (p > path))
+ p--;
+
+ /* walk backward until we find the next slash or hit beginning */
+ while ((*p != '/') && (p > path))
+ p--;
+
+ /* did we find a slash? Then increment to include it in path */
+ if (*p == '/')
+ p++;
+
+ return p - path;
+}
+
/* Compare given dentry name with last component in given path,
* return of 0 indicates a match. */
int audit_compare_dname_path(const char *dname, const char *path,
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index bd11d09..011e923 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2149,13 +2149,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
}
/**
- * audit_inode - store the inode and device from a lookup
+ * __audit_inode - store the inode and device from a lookup
* @name: name being audited
* @dentry: dentry being audited
- *
- * Called from fs/namei.c:path_lookup().
+ * @parent: does this dentry represent the parent?
*/
-void __audit_inode(const char *name, const struct dentry *dentry)
+void __audit_inode(const char *name, const struct dentry *dentry,
+ unsigned int parent)
{
struct audit_context *context = current->audit_context;
const struct inode *inode = dentry->d_inode;
@@ -2168,19 +2168,38 @@ void __audit_inode(const char *name, const struct dentry *dentry)
goto out_alloc;
list_for_each_entry_reverse(n, &context->names_list, list) {
- if (n->name == name)
- goto out;
+ /* does the name pointer match? */
+ if (n->name != name)
+ continue;
+
+ /* match the correct record type */
+ if (parent) {
+ if (n->type == AUDIT_TYPE_PARENT ||
+ n->type == AUDIT_TYPE_UNKNOWN)
+ goto out;
+ } else {
+ if (n->type != AUDIT_TYPE_PARENT)
+ goto out;
+ }
}
out_alloc:
- /* unable to find the name from a previous getname() */
+ /* unable to find the name from a previous getname(). Allocate a new
+ * anonymous entry.
+ */
n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
if (!n)
return;
out:
+ if (parent) {
+ n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL;
+ n->type = AUDIT_TYPE_PARENT;
+ } else {
+ n->name_len = AUDIT_NAME_FULL;
+ n->type = AUDIT_TYPE_NORMAL;
+ }
handle_path(dentry);
audit_copy_inode(n, dentry, inode);
- n->type = AUDIT_TYPE_NORMAL;
}
/**
@@ -2204,7 +2223,6 @@ void __audit_inode_child(const struct inode *parent,
const struct inode *inode = dentry->d_inode;
const char *dname = dentry->d_name.name;
struct audit_names *n;
- int dirlen = 0;
if (!context->in_syscall)
return;
@@ -2218,8 +2236,7 @@ void __audit_inode_child(const struct inode *parent,
continue;
if (n->ino == parent->i_ino &&
- !audit_compare_dname_path(dname, n->name, &dirlen)) {
- n->name_len = dirlen; /* update parent data in place */
+ !audit_compare_dname_path(dname, n->name, NULL)) {
found_parent = n->name;
goto add_names;
}
@@ -2232,7 +2249,7 @@ void __audit_inode_child(const struct inode *parent,
/* strcmp() is the more likely scenario */
if (!strcmp(dname, n->name) ||
- !audit_compare_dname_path(dname, n->name, &dirlen)) {
+ !audit_compare_dname_path(dname, n->name, NULL)) {
if (inode)
audit_copy_inode(n, dentry, inode);
else
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 07/49] audit: remove dirlen argument to audit_compare_dname_path
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (5 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 06/49] audit: set the name_len in audit_inode for parent lookups Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 08/49] audit: make audit_compare_dname_path use parent_len helper Jeff Layton
` (41 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
All the callers set this to NULL now.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
kernel/audit.h | 3 +--
kernel/audit_watch.c | 2 +-
kernel/auditfilter.c | 6 +-----
kernel/auditsc.c | 4 ++--
4 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/kernel/audit.h b/kernel/audit.h
index 276ca88..ee31316 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -77,8 +77,7 @@ static inline int audit_hash_ino(u32 ino)
extern int audit_match_class(int class, unsigned syscall);
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
extern int parent_len(const char *path);
-extern int audit_compare_dname_path(const char *dname, const char *path,
- int *dirlen);
+extern int audit_compare_dname_path(const char *dname, const char *path);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
int done, int multi,
const void *payload, int size);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 3823281..b6a873a 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -265,7 +265,7 @@ static void audit_update_watch(struct audit_parent *parent,
/* Run all of the watches on this parent looking for the one that
* matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
- if (audit_compare_dname_path(dname, owatch->path, NULL))
+ if (audit_compare_dname_path(dname, owatch->path))
continue;
/* If the update involves invalidating rules, do the inode-based
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 29b167b..f9c48d0 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1230,8 +1230,7 @@ int parent_len(const char *path)
/* Compare given dentry name with last component in given path,
* return of 0 indicates a match. */
-int audit_compare_dname_path(const char *dname, const char *path,
- int *dirlen)
+int audit_compare_dname_path(const char *dname, const char *path)
{
int dlen, plen;
const char *p;
@@ -1260,9 +1259,6 @@ int audit_compare_dname_path(const char *dname, const char *path,
p++;
}
- /* return length of path's directory component */
- if (dirlen)
- *dirlen = p - path;
return strncmp(p, dname, dlen);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 011e923..b03ef6a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2236,7 +2236,7 @@ void __audit_inode_child(const struct inode *parent,
continue;
if (n->ino == parent->i_ino &&
- !audit_compare_dname_path(dname, n->name, NULL)) {
+ !audit_compare_dname_path(dname, n->name)) {
found_parent = n->name;
goto add_names;
}
@@ -2249,7 +2249,7 @@ void __audit_inode_child(const struct inode *parent,
/* strcmp() is the more likely scenario */
if (!strcmp(dname, n->name) ||
- !audit_compare_dname_path(dname, n->name, NULL)) {
+ !audit_compare_dname_path(dname, n->name)) {
if (inode)
audit_copy_inode(n, dentry, inode);
else
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 08/49] audit: make audit_compare_dname_path use parent_len helper
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (6 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 07/49] audit: remove dirlen argument to audit_compare_dname_path Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 09/49] audit: optimize audit_compare_dname_path Jeff Layton
` (40 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
From: Eric Paris <eparis@redhat.com>
Signed-off-by: Eric Paris <eparis@redhat.com>
---
kernel/auditfilter.c | 27 +++++++--------------------
1 file changed, 7 insertions(+), 20 deletions(-)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index f9c48d0..f47ba18 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1232,32 +1232,19 @@ int parent_len(const char *path)
* return of 0 indicates a match. */
int audit_compare_dname_path(const char *dname, const char *path)
{
- int dlen, plen;
+ int dlen, pathlen, parentlen;
const char *p;
- if (!dname || !path)
- return 1;
-
dlen = strlen(dname);
- plen = strlen(path);
- if (plen < dlen)
+ pathlen = strlen(path);
+ if (pathlen < dlen)
return 1;
- /* disregard trailing slashes */
- p = path + plen - 1;
- while ((*p == '/') && (p > path))
- p--;
-
- /* find last path component */
- p = p - dlen + 1;
- if (p < path)
+ parentlen = parent_len(path);
+ if (pathlen - parentlen != dlen)
return 1;
- else if (p > path) {
- if (*--p != '/')
- return 1;
- else
- p++;
- }
+
+ p = path + parentlen;
return strncmp(p, dname, dlen);
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 09/49] audit: optimize audit_compare_dname_path
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (7 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 08/49] audit: make audit_compare_dname_path use parent_len helper Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 10/49] audit: overhaul __audit_inode_child to accomodate retrying Jeff Layton
` (39 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
In the cases where we already know the length of the parent, pass it as
a parm so we don't need to recompute it. In the cases where we don't
know the length, pass in AUDIT_NAME_FULL (-1) to indicate that it should
be determined.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
kernel/audit.h | 5 ++++-
kernel/audit_watch.c | 3 ++-
kernel/auditfilter.c | 16 +++++++++++-----
kernel/auditsc.c | 8 +++-----
4 files changed, 20 insertions(+), 12 deletions(-)
diff --git a/kernel/audit.h b/kernel/audit.h
index ee31316..34af33c 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -74,10 +74,13 @@ static inline int audit_hash_ino(u32 ino)
return (ino & (AUDIT_INODE_BUCKETS-1));
}
+/* Indicates that audit should log the full pathname. */
+#define AUDIT_NAME_FULL -1
+
extern int audit_match_class(int class, unsigned syscall);
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
extern int parent_len(const char *path);
-extern int audit_compare_dname_path(const char *dname, const char *path);
+extern int audit_compare_dname_path(const char *dname, const char *path, int plen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
int done, int multi,
const void *payload, int size);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index b6a873a..f8e9353 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -265,7 +265,8 @@ static void audit_update_watch(struct audit_parent *parent,
/* Run all of the watches on this parent looking for the one that
* matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
- if (audit_compare_dname_path(dname, owatch->path))
+ if (audit_compare_dname_path(dname, owatch->path,
+ AUDIT_NAME_FULL))
continue;
/* If the update involves invalidating rules, do the inode-based
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index f47ba18..1e0899d 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1228,11 +1228,17 @@ int parent_len(const char *path)
return p - path;
}
-/* Compare given dentry name with last component in given path,
- * return of 0 indicates a match. */
-int audit_compare_dname_path(const char *dname, const char *path)
+/**
+ * audit_compare_dname_path - compare given dentry name with last component in
+ * given path. Return of 0 indicates a match.
+ * @dname: dentry name that we're comparing
+ * @path: full pathname that we're comparing
+ * @parentlen: length of the parent if known. Passing in AUDIT_NAME_FULL
+ * here indicates that we must compute this value.
+ */
+int audit_compare_dname_path(const char *dname, const char *path, int parentlen)
{
- int dlen, pathlen, parentlen;
+ int dlen, pathlen;
const char *p;
dlen = strlen(dname);
@@ -1240,7 +1246,7 @@ int audit_compare_dname_path(const char *dname, const char *path)
if (pathlen < dlen)
return 1;
- parentlen = parent_len(path);
+ parentlen = parentlen == AUDIT_NAME_FULL ? parent_len(path) : parentlen;
if (pathlen - parentlen != dlen)
return 1;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index b03ef6a..52d1f0f 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -81,9 +81,6 @@
* a name dynamically and also add those to the list anchored by names_list. */
#define AUDIT_NAMES 5
-/* Indicates that audit should log the full pathname. */
-#define AUDIT_NAME_FULL -1
-
/* no execve audit message should be longer than this (userspace limits) */
#define MAX_EXECVE_AUDIT_LEN 7500
@@ -2236,7 +2233,7 @@ void __audit_inode_child(const struct inode *parent,
continue;
if (n->ino == parent->i_ino &&
- !audit_compare_dname_path(dname, n->name)) {
+ !audit_compare_dname_path(dname, n->name, n->name_len)) {
found_parent = n->name;
goto add_names;
}
@@ -2249,7 +2246,8 @@ void __audit_inode_child(const struct inode *parent,
/* strcmp() is the more likely scenario */
if (!strcmp(dname, n->name) ||
- !audit_compare_dname_path(dname, n->name)) {
+ !audit_compare_dname_path(dname, n->name,
+ AUDIT_NAME_FULL)) {
if (inode)
audit_copy_inode(n, dentry, inode);
else
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 10/49] audit: overhaul __audit_inode_child to accomodate retrying
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (8 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 09/49] audit: optimize audit_compare_dname_path Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 11/49] vfs: allocate page instead of names_cache buffer in mount_block_root Jeff Layton
` (38 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
In order to accomodate retrying path-based syscalls, we need to add a
new "type" argument to audit_inode_child. This will tell us whether
we're looking for a child entry that represents a create or a delete.
If we find a parent, don't automatically assume that we need to create a
new entry. Instead, use the information we have to try to find an
existing entry first. Update it if one is found and create a new one if
not.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/btrfs/ioctl.c | 2 +-
fs/namei.c | 2 +-
include/linux/audit.h | 12 ++++++----
include/linux/fsnotify.h | 8 +++----
kernel/auditsc.c | 57 +++++++++++++++++++++++++-----------------------
5 files changed, 44 insertions(+), 37 deletions(-)
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 7e78d47..45f987b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -614,7 +614,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir);
- audit_inode_child(dir, victim);
+ audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
diff --git a/fs/namei.c b/fs/namei.c
index 6c9d86d..64f7350 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2180,7 +2180,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir);
- audit_inode_child(dir, victim);
+ audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 155524b..0f7284a 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -455,6 +455,8 @@ extern int audit_classify_arch(int arch);
#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
#define AUDIT_TYPE_PARENT 2 /* a parent audit record */
+#define AUDIT_TYPE_CHILD_DELETE 3 /* a child being deleted */
+#define AUDIT_TYPE_CHILD_CREATE 4 /* a child being created */
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
@@ -470,7 +472,8 @@ extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct dentry *dentry,
unsigned int parent);
extern void __audit_inode_child(const struct inode *parent,
- const struct dentry *dentry);
+ const struct dentry *dentry,
+ const unsigned char type);
extern void __audit_seccomp(unsigned long syscall, long signr, int code);
extern void __audit_ptrace(struct task_struct *t);
@@ -511,9 +514,10 @@ static inline void audit_inode(const char *name, const struct dentry *dentry,
__audit_inode(name, dentry, parent);
}
static inline void audit_inode_child(const struct inode *parent,
- const struct dentry *dentry) {
+ const struct dentry *dentry,
+ const unsigned char type) {
if (unlikely(!audit_dummy_context()))
- __audit_inode_child(parent, dentry);
+ __audit_inode_child(parent, dentry, type);
}
void audit_core_dumps(long signr);
@@ -641,7 +645,7 @@ extern int audit_signals;
#define __audit_inode(n,d,p) do { ; } while (0)
#define __audit_inode_child(p,d) do { ; } while (0)
#define audit_inode(n,d,p) do { ; } while (0)
-#define audit_inode_child(p,d) do { ; } while (0)
+#define audit_inode_child(p,d,t) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0)
#define audit_seccomp(i,s,c) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) (0)
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 9c28471..0fbfb46 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -109,7 +109,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
if (source)
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
- audit_inode_child(new_dir, moved);
+ audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE);
}
/*
@@ -155,7 +155,7 @@ static inline void fsnotify_inoderemove(struct inode *inode)
*/
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
- audit_inode_child(inode, dentry);
+ audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
}
@@ -168,7 +168,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
{
fsnotify_link_count(inode);
- audit_inode_child(dir, new_dentry);
+ audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE);
fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
}
@@ -181,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
__u32 mask = (FS_CREATE | FS_ISDIR);
struct inode *d_inode = dentry->d_inode;
- audit_inode_child(inode, dentry);
+ audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE);
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 52d1f0f..2f20b97 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2203,6 +2203,7 @@ out:
* __audit_inode_child - collect inode info for created/removed objects
* @parent: inode of dentry parent
* @dentry: dentry being audited
+ * @type: AUDIT_TYPE_* value that we're looking for
*
* For syscalls that create or remove filesystem objects, audit_inode
* can only collect information for the filesystem object's parent.
@@ -2213,13 +2214,13 @@ out:
* unsuccessful attempts.
*/
void __audit_inode_child(const struct inode *parent,
- const struct dentry *dentry)
+ const struct dentry *dentry,
+ const unsigned char type)
{
struct audit_context *context = current->audit_context;
- const char *found_parent = NULL, *found_child = NULL;
const struct inode *inode = dentry->d_inode;
const char *dname = dentry->d_name.name;
- struct audit_names *n;
+ struct audit_names *n, *found_parent = NULL, *found_child = NULL;
if (!context->in_syscall)
return;
@@ -2227,63 +2228,65 @@ void __audit_inode_child(const struct inode *parent,
if (inode)
handle_one(inode);
- /* parent is more likely, look for it first */
+ /* look for a parent entry first */
list_for_each_entry(n, &context->names_list, list) {
- if (!n->name)
+ if (!n->name || n->type != AUDIT_TYPE_PARENT)
continue;
if (n->ino == parent->i_ino &&
!audit_compare_dname_path(dname, n->name, n->name_len)) {
- found_parent = n->name;
- goto add_names;
+ found_parent = n;
+ break;
}
}
- /* no matching parent, look for matching child */
+ /* is there a matching child entry? */
list_for_each_entry(n, &context->names_list, list) {
- if (!n->name)
+ /* can only match entries that have a name */
+ if (!n->name || n->type != type)
+ continue;
+
+ /* if we found a parent, make sure this one is a child of it */
+ if (found_parent && (n->name != found_parent->name))
continue;
- /* strcmp() is the more likely scenario */
if (!strcmp(dname, n->name) ||
!audit_compare_dname_path(dname, n->name,
+ found_parent ?
+ found_parent->name_len :
AUDIT_NAME_FULL)) {
- if (inode)
- audit_copy_inode(n, dentry, inode);
- else
- n->ino = (unsigned long)-1;
- n->type = AUDIT_TYPE_NORMAL;
- found_child = n->name;
- goto add_names;
+ found_child = n;
+ break;
}
}
-add_names:
if (!found_parent) {
- n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
+ /* create a new, "anonymous" parent record */
+ n = audit_alloc_name(context, AUDIT_TYPE_PARENT);
if (!n)
return;
audit_copy_inode(n, NULL, parent);
}
if (!found_child) {
- n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
- if (!n)
+ found_child = audit_alloc_name(context, type);
+ if (!found_child)
return;
/* Re-use the name belonging to the slot for a matching parent
* directory. All names for this context are relinquished in
* audit_free_names() */
if (found_parent) {
- n->name = found_parent;
- n->name_len = AUDIT_NAME_FULL;
+ found_child->name = found_parent->name;
+ found_child->name_len = AUDIT_NAME_FULL;
/* don't call __putname() */
- n->name_put = false;
+ found_child->name_put = false;
}
-
- if (inode)
- audit_copy_inode(n, dentry, inode);
}
+ if (inode)
+ audit_copy_inode(found_child, dentry, inode);
+ else
+ found_child->ino = (unsigned long)-1;
}
EXPORT_SYMBOL_GPL(__audit_inode_child);
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 11/49] vfs: allocate page instead of names_cache buffer in mount_block_root
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (9 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 10/49] audit: overhaul __audit_inode_child to accomodate retrying Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 12/49] vfs: make dir_name arg to do_mount a const char * Jeff Layton
` (37 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
First, it's incorrect to call putname() after __getname_gfp() since the
bare __getname_gfp() call skips the auditing code, while putname()
doesn't.
mount_block_root allocates a PATH_MAX buffer via __getname_gfp, and then
calls get_fs_names to fill the buffer. That function can call
get_filesystem_list which assumes that that buffer is a full page in
size. On arches where PAGE_SIZE != 4k, then this could potentially
overrun.
In practice, it's hard to imagine the list of filesystem names even
approaching 4k, but it's best to be safe. Just allocate a page for this
purpose instead.
With this, we can also remove the __getname_gfp() definition since there
are no more callers.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
include/linux/fs.h | 3 +--
init/do_mounts.c | 7 ++++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index aa11047..69513a7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2221,8 +2221,7 @@ extern void __init vfs_caches_init(unsigned long);
extern struct kmem_cache *names_cachep;
-#define __getname_gfp(gfp) kmem_cache_alloc(names_cachep, (gfp))
-#define __getname() __getname_gfp(GFP_KERNEL)
+#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
#ifndef CONFIG_AUDITSYSCALL
#define putname(name) __putname(name)
diff --git a/init/do_mounts.c b/init/do_mounts.c
index d3f0aee..f8a6642 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -353,8 +353,9 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
void __init mount_block_root(char *name, int flags)
{
- char *fs_names = __getname_gfp(GFP_KERNEL
- | __GFP_NOTRACK_FALSE_POSITIVE);
+ struct page *page = alloc_page(GFP_KERNEL |
+ __GFP_NOTRACK_FALSE_POSITIVE);
+ char *fs_names = page_address(page);
char *p;
#ifdef CONFIG_BLOCK
char b[BDEVNAME_SIZE];
@@ -406,7 +407,7 @@ retry:
#endif
panic("VFS: Unable to mount root fs on %s", b);
out:
- putname(fs_names);
+ put_page(page);
}
#ifdef CONFIG_ROOT_NFS
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 12/49] vfs: make dir_name arg to do_mount a const char *
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (10 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 11/49] vfs: allocate page instead of names_cache buffer in mount_block_root Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 13/49] acct: constify the name arg to acct_on Jeff Layton
` (36 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Nothing changes it, so it should be safe to do.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namespace.c | 2 +-
include/linux/fs.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 4d31f73..8e52b1c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2185,7 +2185,7 @@ int copy_mount_string(const void __user *data, char **where)
* Therefore, if this magic number is present, it carries no information
* and must be discarded.
*/
-long do_mount(char *dev_name, char *dir_name, char *type_page,
+long do_mount(char *dev_name, const char *dir_name, char *type_page,
unsigned long flags, void *data_page)
{
struct path path;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 69513a7..b6ce6fc 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2072,7 +2072,7 @@ extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data);
extern void kern_unmount(struct vfsmount *mnt);
extern int may_umount_tree(struct vfsmount *);
extern int may_umount(struct vfsmount *);
-extern long do_mount(char *, char *, char *, unsigned long, void *);
+extern long do_mount(char *, const char *, char *, unsigned long, void *);
extern struct vfsmount *collect_mounts(struct path *);
extern void drop_collected_mounts(struct vfsmount *);
extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 13/49] acct: constify the name arg to acct_on
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (11 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 12/49] vfs: make dir_name arg to do_mount a const char * Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 14/49] vfs: define getname_info struct and have getname() return it Jeff Layton
` (35 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
kernel/acct.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/acct.c b/kernel/acct.c
index 02e6167..e97d159 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
}
}
-static int acct_on(char *name)
+static int acct_on(const char *name)
{
struct file *file;
struct vfsmount *mnt;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 14/49] vfs: define getname_info struct and have getname() return it
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (12 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 13/49] acct: constify the name arg to acct_on Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 15/49] audit: allow audit code to satisfy getname requests from its names_list Jeff Layton
` (34 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
getname() is intended to copy pathname strings from userspace into a
kernel buffer. The result is just a string in kernel space. It would
however be quite helpful to be able to attach some ancillary info to
the string.
For instance, we could attach some audit-related info to reduce the
amount of audit-related processing needed. When auditing is enabled,
we could also call getname() on the string more than once and not
need to recopy it from userspace.
This patchset converts the getname()/putname() interfaces to return
a struct instead of a string. For now, the struct just tracks the
string in kernel space and the original userland pointer for it.
Later, we'll add other information to the struct as it becomes
convenient.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
arch/alpha/kernel/osf_sys.c | 16 ++---
arch/avr32/kernel/process.c | 4 +-
arch/blackfin/kernel/process.c | 4 +-
arch/cris/arch-v10/kernel/process.c | 4 +-
arch/cris/arch-v32/kernel/process.c | 4 +-
arch/h8300/kernel/process.c | 4 +-
arch/hexagon/kernel/syscall.c | 4 +-
arch/ia64/kernel/process.c | 4 +-
arch/m32r/kernel/process.c | 4 +-
arch/microblaze/kernel/sys_microblaze.c | 4 +-
arch/mips/kernel/linux32.c | 4 +-
arch/mips/kernel/syscall.c | 4 +-
arch/openrisc/kernel/process.c | 4 +-
arch/parisc/hpux/fs.c | 4 +-
arch/parisc/kernel/process.c | 4 +-
arch/parisc/kernel/sys_parisc32.c | 4 +-
arch/score/kernel/sys_score.c | 4 +-
arch/sh/kernel/process_32.c | 4 +-
arch/sh/kernel/process_64.c | 4 +-
arch/tile/kernel/process.c | 8 +--
arch/unicore32/kernel/sys.c | 4 +-
arch/xtensa/kernel/process.c | 4 +-
fs/compat.c | 12 ++--
fs/exec.c | 13 ++--
fs/filesystems.c | 4 +-
fs/namei.c | 113 +++++++++++++++++++-------------
fs/namespace.c | 4 +-
fs/open.c | 4 +-
fs/quota/quota.c | 4 +-
include/linux/audit.h | 8 ++-
include/linux/fs.h | 14 +++-
ipc/mqueue.c | 13 ++--
kernel/acct.c | 4 +-
kernel/auditsc.c | 86 +++++++++++++-----------
mm/swapfile.c | 11 ++--
35 files changed, 218 insertions(+), 176 deletions(-)
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index bc1acdd..b3f41e8 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -452,7 +452,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
{
int retval;
struct cdfs_args tmp;
- char *devname;
+ struct getname_info *devname;
retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
@@ -461,7 +461,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
retval = PTR_ERR(devname);
if (IS_ERR(devname))
goto out;
- retval = do_mount(devname, dirname, "ext2", flags, NULL);
+ retval = do_mount(devname->name, dirname, "ext2", flags, NULL);
putname(devname);
out:
return retval;
@@ -472,7 +472,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
{
int retval;
struct cdfs_args tmp;
- char *devname;
+ struct getname_info *devname;
retval = -EFAULT;
if (copy_from_user(&tmp, args, sizeof(tmp)))
@@ -481,7 +481,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
retval = PTR_ERR(devname);
if (IS_ERR(devname))
goto out;
- retval = do_mount(devname, dirname, "iso9660", flags, NULL);
+ retval = do_mount(devname->name, dirname, "iso9660", flags, NULL);
putname(devname);
out:
return retval;
@@ -502,7 +502,7 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,
int, flag, void __user *, data)
{
int retval;
- char *name;
+ struct getname_info *name;
name = getname(path);
retval = PTR_ERR(name);
@@ -510,13 +510,13 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,
goto out;
switch (typenr) {
case 1:
- retval = osf_ufs_mount(name, data, flag);
+ retval = osf_ufs_mount(name->name, data, flag);
break;
case 6:
- retval = osf_cdfs_mount(name, data, flag);
+ retval = osf_cdfs_mount(name->name, data, flag);
break;
case 9:
- retval = osf_procfs_mount(name, data, flag);
+ retval = osf_procfs_mount(name->name, data, flag);
break;
default:
retval = -EINVAL;
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 92c5af9..c2034e8 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -388,14 +388,14 @@ asmlinkage int sys_execve(const char __user *ufilename,
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, uargv, uenvp, regs);
+ error = do_execve(filename->name, uargv, uenvp, regs);
putname(filename);
out:
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 62bcea7..bc5c162 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -213,14 +213,14 @@ asmlinkage int sys_execve(const char __user *name,
const char __user *const __user *envp)
{
int error;
- char *filename;
+ struct getname_info *filename;
struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
return error;
}
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c
index bee8df4..92b57e7 100644
--- a/arch/cris/arch-v10/kernel/process.c
+++ b/arch/cris/arch-v10/kernel/process.c
@@ -212,14 +212,14 @@ asmlinkage int sys_execve(const char *fname,
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(fname);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c
index 0570e8c..a80be6f 100644
--- a/arch/cris/arch-v32/kernel/process.c
+++ b/arch/cris/arch-v32/kernel/process.c
@@ -224,7 +224,7 @@ sys_execve(const char *fname,
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(fname);
error = PTR_ERR(filename);
@@ -232,7 +232,7 @@ sys_execve(const char *fname,
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index 0e9c315..67d357d 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -214,14 +214,14 @@ asmlinkage int sys_execve(const char *name,
int dummy, ...)
{
int error;
- char * filename;
+ struct getname_info *filename;
struct pt_regs *regs = (struct pt_regs *) ((unsigned char *)&dummy-4);
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
return error;
}
diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c
index 553cd60..f67b4d5 100644
--- a/arch/hexagon/kernel/syscall.c
+++ b/arch/hexagon/kernel/syscall.c
@@ -40,7 +40,7 @@ asmlinkage int sys_execve(char __user *ufilename,
const char __user *const __user *envp)
{
struct pt_regs *pregs = current_thread_info()->regs;
- char *filename;
+ struct getname_info *filename;
int retval;
filename = getname(ufilename);
@@ -48,7 +48,7 @@ asmlinkage int sys_execve(char __user *ufilename,
if (IS_ERR(filename))
return retval;
- retval = do_execve(filename, argv, envp, pregs);
+ retval = do_execve(filename->name, argv, envp, pregs);
putname(filename);
return retval;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index dd6fc14..d2cf668 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -611,14 +611,14 @@ sys_execve (const char __user *filename,
const char __user *const __user *envp,
struct pt_regs *regs)
{
- char *fname;
+ struct getname_info *fname;
int error;
fname = getname(filename);
error = PTR_ERR(fname);
if (IS_ERR(fname))
goto out;
- error = do_execve(fname, argv, envp, regs);
+ error = do_execve(fname->name, argv, envp, regs);
putname(fname);
out:
return error;
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 3a4a32b..e1ea185 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -293,14 +293,14 @@ asmlinkage int sys_execve(const char __user *ufilename,
unsigned long r6, struct pt_regs regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, uargv, uenvp, ®s);
+ error = do_execve(filename->name, uargv, uenvp, ®s);
putname(filename);
out:
return error;
diff --git a/arch/microblaze/kernel/sys_microblaze.c b/arch/microblaze/kernel/sys_microblaze.c
index e5b154f..f273d16 100644
--- a/arch/microblaze/kernel/sys_microblaze.c
+++ b/arch/microblaze/kernel/sys_microblaze.c
@@ -54,13 +54,13 @@ asmlinkage long microblaze_execve(const char __user *filenamei,
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(filenamei);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 922a554..62ff5a9 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -83,13 +83,13 @@ out:
asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
{
int error;
- char * filename;
+ struct getname_info *filename;
filename = getname(compat_ptr(regs.regs[4]));
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
+ error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]),
compat_ptr(regs.regs[6]), ®s);
putname(filename);
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index b08220c..679c417 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -133,13 +133,13 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
{
int error;
- char * filename;
+ struct getname_info *filename;
filename = getname((const char __user *) (long)regs.regs[4]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *) (long)regs.regs[5],
(const char __user *const __user *) (long)regs.regs[6],
®s);
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
index 55210f3..9edec79 100644
--- a/arch/openrisc/kernel/process.c
+++ b/arch/openrisc/kernel/process.c
@@ -271,7 +271,7 @@ asmlinkage long _sys_execve(const char __user *name,
struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(name);
error = PTR_ERR(filename);
@@ -279,7 +279,7 @@ asmlinkage long _sys_execve(const char __user *name,
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index c71eb6c..a40d81f 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -34,14 +34,14 @@
int hpux_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *) regs->gr[25],
(const char __user *const __user *) regs->gr[24],
regs);
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 2c05a92..f8d32be 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -339,13 +339,13 @@ unsigned long thread_saved_pc(struct task_struct *t)
asmlinkage int sys_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *) regs->gr[25],
(const char __user *const __user *) regs->gr[24],
regs);
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index dc9a624..7e17607 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -60,14 +60,14 @@
asmlinkage int sys32_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
filename = getname((const char __user *) regs->gr[26]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, compat_ptr(regs->gr[25]),
+ error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]),
compat_ptr(regs->gr[24]), regs);
putname(filename);
out:
diff --git a/arch/score/kernel/sys_score.c b/arch/score/kernel/sys_score.c
index e478bf9..9ee9ac9 100644
--- a/arch/score/kernel/sys_score.c
+++ b/arch/score/kernel/sys_score.c
@@ -92,14 +92,14 @@ asmlinkage long
score_execve(struct pt_regs *regs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname((char __user*)regs->regs[4]);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *)regs->regs[5],
(const char __user *const __user *)regs->regs[6],
regs);
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 59521e8..93d4879 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -298,14 +298,14 @@ asmlinkage int sys_execve(const char __user *ufilename,
{
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, uargv, uenvp, regs);
+ error = do_execve(filename->name, uargv, uenvp, regs);
putname(filename);
out:
return error;
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c
index 602545b..bad7c30 100644
--- a/arch/sh/kernel/process_64.c
+++ b/arch/sh/kernel/process_64.c
@@ -491,14 +491,14 @@ asmlinkage int sys_execve(const char *ufilename, char **uargv,
struct pt_regs *pregs)
{
int error;
- char *filename;
+ struct getname_info *filename;
filename = getname((char __user *)ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
+ error = do_execve(filename->name,
(const char __user *const __user *)uargv,
(const char __user *const __user *)uenvp,
pregs);
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 6be7991..04b0e62 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -594,13 +594,13 @@ SYSCALL_DEFINE4(execve, const char __user *, path,
struct pt_regs *, regs)
{
long error;
- char *filename;
+ struct getname_info *filename;
filename = getname(path);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
if (error == 0)
single_step_execve();
@@ -615,13 +615,13 @@ long compat_sys_execve(const char __user *path,
struct pt_regs *regs)
{
long error;
- char *filename;
+ struct getname_info *filename;
filename = getname(path);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = compat_do_execve(filename, argv, envp, regs);
+ error = compat_do_execve(filename->name, argv, envp, regs);
putname(filename);
if (error == 0)
single_step_execve();
diff --git a/arch/unicore32/kernel/sys.c b/arch/unicore32/kernel/sys.c
index 5fd9af7..7a0c372 100644
--- a/arch/unicore32/kernel/sys.c
+++ b/arch/unicore32/kernel/sys.c
@@ -51,13 +51,13 @@ asmlinkage long __sys_execve(const char __user *filename,
struct pt_regs *regs)
{
int error;
- char *fn;
+ struct getname_info *fn;
fn = getname(filename);
error = PTR_ERR(fn);
if (IS_ERR(fn))
goto out;
- error = do_execve(fn, argv, envp, regs);
+ error = do_execve(fn->name, argv, envp, regs);
putname(fn);
out:
return error;
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 2c8d6a3..03d723d 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -325,13 +325,13 @@ long xtensa_execve(const char __user *name,
struct pt_regs *regs)
{
long error;
- char * filename;
+ struct getname_info *filename;
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename, argv, envp, regs);
+ error = do_execve(filename->name, argv, envp, regs);
putname(filename);
out:
return error;
diff --git a/fs/compat.c b/fs/compat.c
index 1bdb350..224f726 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -776,16 +776,16 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
char *kernel_type;
unsigned long data_page;
char *kernel_dev;
- char *dir_page;
+ struct getname_info *dir;
int retval;
retval = copy_mount_string(type, &kernel_type);
if (retval < 0)
goto out;
- dir_page = getname(dir_name);
- retval = PTR_ERR(dir_page);
- if (IS_ERR(dir_page))
+ dir = getname(dir_name);
+ retval = PTR_ERR(dir);
+ if (IS_ERR(dir))
goto out1;
retval = copy_mount_string(dev_name, &kernel_dev);
@@ -807,7 +807,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
}
}
- retval = do_mount(kernel_dev, dir_page, kernel_type,
+ retval = do_mount(kernel_dev, dir->name, kernel_type,
flags, (void*)data_page);
out4:
@@ -815,7 +815,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,
out3:
kfree(kernel_dev);
out2:
- putname(dir_page);
+ putname(dir);
out1:
kfree(kernel_type);
out:
diff --git a/fs/exec.c b/fs/exec.c
index 50a1270..222e282 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -115,7 +115,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt)
SYSCALL_DEFINE1(uselib, const char __user *, library)
{
struct file *file;
- char *tmp = getname(library);
+ struct getname_info *tmp = getname(library);
int error = PTR_ERR(tmp);
static const struct open_flags uselib_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
@@ -126,7 +126,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
if (IS_ERR(tmp))
goto out;
- file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
+ file = do_filp_open(AT_FDCWD, tmp->name, &uselib_flags, LOOKUP_FOLLOW);
putname(tmp);
error = PTR_ERR(file);
if (IS_ERR(file))
@@ -2325,10 +2325,10 @@ SYSCALL_DEFINE3(execve,
const char __user *const __user *, argv,
const char __user *const __user *, envp)
{
- const char *path = getname(filename);
+ struct getname_info *path = getname(filename);
int error = PTR_ERR(path);
if (!IS_ERR(path)) {
- error = do_execve(path, argv, envp, current_pt_regs());
+ error = do_execve(path->name, argv, envp, current_pt_regs());
putname(path);
}
return error;
@@ -2338,10 +2338,11 @@ asmlinkage long compat_sys_execve(const char __user * filename,
const compat_uptr_t __user * argv,
const compat_uptr_t __user * envp)
{
- const char *path = getname(filename);
+ struct getname_info *path = getname(filename);
int error = PTR_ERR(path);
if (!IS_ERR(path)) {
- error = compat_do_execve(path, argv, envp, current_pt_regs());
+ error = compat_do_execve(path->name, argv, envp,
+ current_pt_regs());
putname(path);
}
return error;
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 96f2428..9f4d31a 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_filesystem);
static int fs_index(const char __user * __name)
{
struct file_system_type * tmp;
- char * name;
+ struct getname_info *name;
int err, index;
name = getname(__name);
@@ -135,7 +135,7 @@ static int fs_index(const char __user * __name)
err = -EINVAL;
read_lock(&file_systems_lock);
for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) {
- if (strcmp(tmp->name,name) == 0) {
+ if (strcmp(tmp->name, name->name) == 0) {
err = index;
break;
}
diff --git a/fs/namei.c b/fs/namei.c
index 64f7350..60db390 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -117,18 +117,37 @@
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
* PATH_MAX includes the nul terminator --RR.
*/
-static char *getname_flags(const char __user *filename, int flags, int *empty)
+void final_putname(struct getname_info *ginfo)
{
- char *result = __getname(), *err;
+ __putname(ginfo->name);
+ kfree(ginfo);
+}
+
+static struct getname_info *
+getname_flags(const char __user *filename, int flags, int *empty)
+{
+ struct getname_info *result, *err;
+ char *kname;
int len;
+ /* FIXME: create dedicated slabcache? */
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
- len = strncpy_from_user(result, filename, PATH_MAX);
- err = ERR_PTR(len);
- if (unlikely(len < 0))
+ kname = __getname();
+ if (unlikely(!kname)) {
+ err = ERR_PTR(-ENOMEM);
+ goto error_free_ginfo;
+ }
+
+ result->name = kname;
+ result->uptr = filename;
+ len = strncpy_from_user(kname, filename, PATH_MAX);
+ if (unlikely(len < 0)) {
+ err = ERR_PTR(len);
goto error;
+ }
/* The empty path is special. */
if (unlikely(!len)) {
@@ -146,25 +165,28 @@ static char *getname_flags(const char __user *filename, int flags, int *empty)
}
error:
- __putname(result);
+ __putname(kname);
+error_free_ginfo:
+ kfree(result);
return err;
}
-char *getname(const char __user * filename)
+struct getname_info *
+getname(const char __user * filename)
{
return getname_flags(filename, 0, NULL);
}
+EXPORT_SYMBOL(getname);
-#ifdef CONFIG_AUDITSYSCALL
-void putname(const char *name)
+void putname(struct getname_info *ginfo)
{
+#ifdef CONFIG_AUDITSYSCALL
if (unlikely(!audit_dummy_context()))
- audit_putname(name);
- else
- __putname(name);
+ return audit_putname(ginfo);
+#endif
+ final_putname(ginfo);
}
EXPORT_SYMBOL(putname);
-#endif
static int check_acl(struct inode *inode, int mask)
{
@@ -2098,13 +2120,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
struct path *path, int *empty)
{
struct nameidata nd;
- char *tmp = getname_flags(name, flags, empty);
+ struct getname_info *tmp = getname_flags(name, flags, empty);
int err = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
BUG_ON(flags & LOOKUP_PARENT);
- err = do_path_lookup(dfd, tmp, flags, &nd);
+ err = do_path_lookup(dfd, tmp->name, flags, &nd);
putname(tmp);
if (!err)
*path = nd.path;
@@ -2118,22 +2140,22 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
return user_path_at_empty(dfd, name, flags, path, NULL);
}
-static int user_path_parent(int dfd, const char __user *path,
- struct nameidata *nd, char **name)
+static struct getname_info *
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
{
- char *s = getname(path);
+ struct getname_info *s = getname(path);
int error;
if (IS_ERR(s))
- return PTR_ERR(s);
+ return s;
- error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd);
- if (error)
+ error = do_path_lookup(dfd, s->name, LOOKUP_PARENT, nd);
+ if (error) {
putname(s);
- else
- *name = s;
+ return ERR_PTR(error);
+ }
- return error;
+ return s;
}
/*
@@ -3044,11 +3066,11 @@ EXPORT_SYMBOL(done_path_create);
struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
{
- char *tmp = getname(pathname);
+ struct getname_info *tmp = getname(pathname);
struct dentry *res;
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- res = kern_path_create(dfd, tmp, path, is_dir);
+ res = kern_path_create(dfd, tmp->name, path, is_dir);
putname(tmp);
return res;
}
@@ -3253,13 +3275,13 @@ out:
static long do_rmdir(int dfd, const char __user *pathname)
{
int error = 0;
- char * name;
+ struct getname_info *name;
struct dentry *dentry;
struct nameidata nd;
- error = user_path_parent(dfd, pathname, &nd, &name);
- if (error)
- return error;
+ name = user_path_parent(dfd, pathname, &nd);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
switch(nd.last_type) {
case LAST_DOTDOT:
@@ -3348,14 +3370,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
static long do_unlinkat(int dfd, const char __user *pathname)
{
int error;
- char *name;
+ struct getname_info *name;
struct dentry *dentry;
struct nameidata nd;
struct inode *inode = NULL;
- error = user_path_parent(dfd, pathname, &nd, &name);
- if (error)
- return error;
+ name = user_path_parent(dfd, pathname, &nd);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
error = -EISDIR;
if (nd.last_type != LAST_NORM)
@@ -3439,7 +3461,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
int, newdfd, const char __user *, newname)
{
int error;
- char *from;
+ struct getname_info *from;
struct dentry *dentry;
struct path path;
@@ -3452,9 +3474,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
if (IS_ERR(dentry))
goto out_putname;
- error = security_path_symlink(&path, dentry, from);
+ error = security_path_symlink(&path, dentry, from->name);
if (!error)
- error = vfs_symlink(path.dentry->d_inode, dentry, from);
+ error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
done_path_create(&path, dentry);
out_putname:
putname(from);
@@ -3734,17 +3756,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
struct dentry *old_dentry, *new_dentry;
struct dentry *trap;
struct nameidata oldnd, newnd;
- char *from;
- char *to;
+ struct getname_info *from;
+ struct getname_info *to;
int error;
- error = user_path_parent(olddfd, oldname, &oldnd, &from);
- if (error)
+ from = user_path_parent(olddfd, oldname, &oldnd);
+ if (IS_ERR(from)) {
+ error = PTR_ERR(from);
goto exit;
+ }
- error = user_path_parent(newdfd, newname, &newnd, &to);
- if (error)
+ to = user_path_parent(newdfd, newname, &newnd);
+ if (IS_ERR(to)) {
+ error = PTR_ERR(to);
goto exit1;
+ }
error = -EXDEV;
if (oldnd.path.mnt != newnd.path.mnt)
@@ -3968,7 +3994,6 @@ EXPORT_SYMBOL(follow_down_one);
EXPORT_SYMBOL(follow_down);
EXPORT_SYMBOL(follow_up);
EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
-EXPORT_SYMBOL(getname);
EXPORT_SYMBOL(lock_rename);
EXPORT_SYMBOL(lookup_one_len);
EXPORT_SYMBOL(page_follow_link_light);
diff --git a/fs/namespace.c b/fs/namespace.c
index 8e52b1c..7dfe6ac 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2402,7 +2402,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
{
int ret;
char *kernel_type;
- char *kernel_dir;
+ struct getname_info *kernel_dir;
char *kernel_dev;
unsigned long data_page;
@@ -2424,7 +2424,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
if (ret < 0)
goto out_data;
- ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags,
+ ret = do_mount(kernel_dev, kernel_dir->name, kernel_type, flags,
(void *) data_page);
free_page(data_page);
diff --git a/fs/open.c b/fs/open.c
index ec06921..3796d0c 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -945,13 +945,13 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
- char *tmp = getname(filename);
+ struct getname_info *tmp = getname(filename);
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp, &op, lookup);
+ struct file *f = do_filp_open(dfd, tmp->name, &op, lookup);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 6f15578..1cf3f2a 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -315,11 +315,11 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)
#ifdef CONFIG_BLOCK
struct block_device *bdev;
struct super_block *sb;
- char *tmp = getname(special);
+ struct getname_info *tmp = getname(special);
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- bdev = lookup_bdev(tmp);
+ bdev = lookup_bdev(tmp->name);
putname(tmp);
if (IS_ERR(bdev))
return ERR_CAST(bdev);
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 0f7284a..d361921 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -459,6 +459,8 @@ extern int audit_classify_arch(int arch);
#define AUDIT_TYPE_CHILD_CREATE 4 /* a child being created */
#ifdef CONFIG_AUDITSYSCALL
+struct getname_info;
+
/* These are defined in auditsc.c */
/* Public API */
extern int audit_alloc(struct task_struct *task);
@@ -467,8 +469,8 @@ extern void __audit_syscall_entry(int arch,
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
-extern void __audit_getname(const char *name);
-extern void audit_putname(const char *name);
+extern void __audit_getname(struct getname_info *ginfo);
+extern void audit_putname(struct getname_info *ginfo);
extern void __audit_inode(const char *name, const struct dentry *dentry,
unsigned int parent);
extern void __audit_inode_child(const struct inode *parent,
@@ -503,7 +505,7 @@ static inline void audit_syscall_exit(void *pt_regs)
__audit_syscall_exit(success, return_code);
}
}
-static inline void audit_getname(const char *name)
+static inline void audit_getname(struct getname_info *name)
{
if (unlikely(!audit_dummy_context()))
__audit_getname(name);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b6ce6fc..1b0d0fb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2189,6 +2189,10 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
#endif /* CONFIG_FILE_LOCKING */
/* fs/open.c */
+struct getname_info {
+ const char *name; /* pointer to actual string */
+ const __user char *uptr; /* original userland pointer */
+};
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
struct file *filp);
@@ -2201,7 +2205,9 @@ extern struct file *file_open_root(struct dentry *, struct vfsmount *,
const char *, int);
extern struct file * dentry_open(const struct path *, int, const struct cred *);
extern int filp_close(struct file *, fl_owner_t id);
-extern char * getname(const char __user *);
+
+extern struct getname_info *getname(const char __user *);
+
enum {
FILE_CREATED = 1,
FILE_OPENED = 2
@@ -2221,12 +2227,14 @@ extern void __init vfs_caches_init(unsigned long);
extern struct kmem_cache *names_cachep;
+extern void final_putname(struct getname_info *ginfo);
+
#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL)
#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
#ifndef CONFIG_AUDITSYSCALL
-#define putname(name) __putname(name)
+#define putname(name) final_putname(name)
#else
-extern void putname(const char *name);
+extern void putname(struct getname_info *ginfo);
#endif
#ifdef CONFIG_BLOCK
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 69cb5fe..2071a27 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -773,7 +773,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
{
struct path path;
struct file *filp;
- char *name;
+ struct getname_info *name;
struct mq_attr attr;
int fd, error;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
@@ -796,7 +796,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
ro = mnt_want_write(mnt); /* we'll drop it in any case */
error = 0;
mutex_lock(&root->d_inode->i_mutex);
- path.dentry = lookup_one_len(name, root, strlen(name));
+ path.dentry = lookup_one_len(name->name, root, strlen(name->name));
if (IS_ERR(path.dentry)) {
error = PTR_ERR(path.dentry);
goto out_putfd;
@@ -805,7 +805,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
if (oflag & O_CREAT) {
if (path.dentry->d_inode) { /* entry already exists */
- audit_inode(name, path.dentry, 0);
+ audit_inode(name->name, path.dentry, 0);
if (oflag & O_EXCL) {
error = -EEXIST;
goto out;
@@ -825,7 +825,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
error = -ENOENT;
goto out;
}
- audit_inode(name, path.dentry, 0);
+ audit_inode(name->name, path.dentry, 0);
filp = do_open(&path, oflag);
}
@@ -850,7 +850,7 @@ out_putname:
SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
{
int err;
- char *name;
+ struct getname_info *name;
struct dentry *dentry;
struct inode *inode = NULL;
struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
@@ -864,7 +864,8 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
if (err)
goto out_name;
mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT);
- dentry = lookup_one_len(name, mnt->mnt_root, strlen(name));
+ dentry = lookup_one_len(name->name, mnt->mnt_root,
+ strlen(name->name));
if (IS_ERR(dentry)) {
err = PTR_ERR(dentry);
goto out_unlock;
diff --git a/kernel/acct.c b/kernel/acct.c
index e97d159..3943608 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -260,10 +260,10 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
return -EPERM;
if (name) {
- char *tmp = getname(name);
+ struct getname_info *tmp = getname(name);
if (IS_ERR(tmp))
return (PTR_ERR(tmp));
- error = acct_on(tmp);
+ error = acct_on(tmp->name);
putname(tmp);
} else {
struct bsd_acct_struct *acct;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 2f20b97..0ba346b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -103,28 +103,29 @@ struct audit_cap_data {
* we don't let putname() free it (instead we free all of the saved
* pointers at syscall exit time).
*
- * Further, in fs/namei.c:path_lookup() we store the inode and device. */
+ * Further, in fs/namei.c:path_lookup() we store the inode and device.
+ */
struct audit_names {
- struct list_head list; /* audit_context->names_list */
- const char *name;
- unsigned long ino;
- dev_t dev;
- umode_t mode;
- uid_t uid;
- gid_t gid;
- dev_t rdev;
- u32 osid;
- struct audit_cap_data fcap;
- unsigned int fcap_ver;
- int name_len; /* number of name's characters to log */
- unsigned char type; /* record type */
- bool name_put; /* call __putname() for this name */
+ struct list_head list; /* audit_context->names_list */
+ struct getname_info *ginfo;
+ unsigned long ino;
+ dev_t dev;
+ umode_t mode;
+ uid_t uid;
+ gid_t gid;
+ dev_t rdev;
+ u32 osid;
+ struct audit_cap_data fcap;
+ unsigned int fcap_ver;
+ int name_len; /* nr of characters to log */
+ unsigned char type; /* record type */
+ bool name_put; /* call final_putname() */
/*
* This was an allocated audit_names and not from the array of
* names allocated in the task audit context. Thus this name
* should be freed on syscall exit
*/
- bool should_free;
+ bool should_free;
};
struct audit_aux_data {
@@ -1004,7 +1005,7 @@ static inline void audit_free_names(struct audit_context *context)
context->ino_count);
list_for_each_entry(n, &context->names_list, list) {
printk(KERN_ERR "names[%d] = %p = %s\n", i,
- n->name, n->name ?: "(null)");
+ n->ginfo, n->ginfo->name ?: "(null)");
}
dump_stack();
return;
@@ -1017,8 +1018,8 @@ static inline void audit_free_names(struct audit_context *context)
list_for_each_entry_safe(n, next, &context->names_list, list) {
list_del(&n->list);
- if (n->name && n->name_put)
- __putname(n->name);
+ if (n->ginfo && n->name_put)
+ __putname(n->ginfo);
if (n->should_free)
kfree(n);
}
@@ -1529,12 +1530,12 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
audit_log_format(ab, "item=%d", record_num);
- if (n->name) {
+ if (n->ginfo) {
switch (n->name_len) {
case AUDIT_NAME_FULL:
/* log the full path */
audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, n->name);
+ audit_log_untrustedstring(ab, n->ginfo->name);
break;
case 0:
/* name was specified as a relative path and the
@@ -1544,7 +1545,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
default:
/* log the name's directory component */
audit_log_format(ab, " name=");
- audit_log_n_untrustedstring(ab, n->name,
+ audit_log_n_untrustedstring(ab, n->ginfo->name,
n->name_len);
}
} else
@@ -2040,7 +2041,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
* Add a name to the list of audit names for this context.
* Called from fs/namei.c:getname().
*/
-void __audit_getname(const char *name)
+void __audit_getname(struct getname_info *ginfo)
{
struct audit_context *context = current->audit_context;
struct audit_names *n;
@@ -2048,17 +2049,22 @@ void __audit_getname(const char *name)
if (!context->in_syscall) {
#if AUDIT_DEBUG == 2
printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n",
- __FILE__, __LINE__, context->serial, name);
+ __FILE__, __LINE__, context->serial, ginfo);
dump_stack();
#endif
return;
}
+#if AUDIT_DEBUG
+ /* The getname_info _must_ have a populated ->name */
+ BUG_ON(!ginfo->name);
+#endif
+
n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
if (!n)
return;
- n->name = name;
+ n->ginfo = ginfo;
n->name_len = AUDIT_NAME_FULL;
n->name_put = true;
@@ -2073,7 +2079,7 @@ void __audit_getname(const char *name)
* then we delay the putname until syscall exit.
* Called from include/linux/fs.h:putname().
*/
-void audit_putname(const char *name)
+void audit_putname(struct getname_info *ginfo)
{
struct audit_context *context = current->audit_context;
@@ -2081,17 +2087,17 @@ void audit_putname(const char *name)
if (!context->in_syscall) {
#if AUDIT_DEBUG == 2
printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n",
- __FILE__, __LINE__, context->serial, name);
+ __FILE__, __LINE__, context->serial, ginfo);
if (context->name_count) {
struct audit_names *n;
int i;
list_for_each_entry(n, &context->names_list, list)
printk(KERN_ERR "name[%d] = %p = %s\n", i,
- n->name, n->name ?: "(null)");
+ n->ginfo, n->ginfo->name ?: "(null)");
}
#endif
- __putname(name);
+ __putname(ginfo);
}
#if AUDIT_DEBUG
else {
@@ -2102,8 +2108,8 @@ void audit_putname(const char *name)
" put_count=%d\n",
__FILE__, __LINE__,
context->serial, context->major,
- context->in_syscall, name, context->name_count,
- context->put_count);
+ context->in_syscall, ginfo->name,
+ context->name_count, context->put_count);
dump_stack();
}
}
@@ -2166,7 +2172,7 @@ void __audit_inode(const char *name, const struct dentry *dentry,
list_for_each_entry_reverse(n, &context->names_list, list) {
/* does the name pointer match? */
- if (n->name != name)
+ if (!n->ginfo || n->ginfo->name != name)
continue;
/* match the correct record type */
@@ -2189,7 +2195,7 @@ out_alloc:
return;
out:
if (parent) {
- n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL;
+ n->name_len = n->ginfo ? parent_len(n->ginfo->name) : AUDIT_NAME_FULL;
n->type = AUDIT_TYPE_PARENT;
} else {
n->name_len = AUDIT_NAME_FULL;
@@ -2230,11 +2236,11 @@ void __audit_inode_child(const struct inode *parent,
/* look for a parent entry first */
list_for_each_entry(n, &context->names_list, list) {
- if (!n->name || n->type != AUDIT_TYPE_PARENT)
+ if (!n->ginfo || n->type != AUDIT_TYPE_PARENT)
continue;
if (n->ino == parent->i_ino &&
- !audit_compare_dname_path(dname, n->name, n->name_len)) {
+ !audit_compare_dname_path(dname, n->ginfo->name, n->name_len)) {
found_parent = n;
break;
}
@@ -2243,15 +2249,15 @@ void __audit_inode_child(const struct inode *parent,
/* is there a matching child entry? */
list_for_each_entry(n, &context->names_list, list) {
/* can only match entries that have a name */
- if (!n->name || n->type != type)
+ if (!n->ginfo || n->type != type)
continue;
/* if we found a parent, make sure this one is a child of it */
- if (found_parent && (n->name != found_parent->name))
+ if (found_parent && (n->ginfo != found_parent->ginfo))
continue;
- if (!strcmp(dname, n->name) ||
- !audit_compare_dname_path(dname, n->name,
+ if (!strcmp(dname, n->ginfo->name) ||
+ !audit_compare_dname_path(dname, n->ginfo->name,
found_parent ?
found_parent->name_len :
AUDIT_NAME_FULL)) {
@@ -2277,7 +2283,7 @@ void __audit_inode_child(const struct inode *parent,
* directory. All names for this context are relinquished in
* audit_free_names() */
if (found_parent) {
- found_child->name = found_parent->name;
+ found_child->ginfo = found_parent->ginfo;
found_child->name_len = AUDIT_NAME_FULL;
/* don't call __putname() */
found_child->name_put = false;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 14e254c..8dbf46d 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1483,7 +1483,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
struct file *swap_file, *victim;
struct address_space *mapping;
struct inode *inode;
- char *pathname;
+ struct getname_info *pathname;
int oom_score_adj;
int i, type, prev;
int err;
@@ -1498,8 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
if (IS_ERR(pathname))
goto out;
- victim = filp_open(pathname, O_RDWR|O_LARGEFILE, 0);
- putname(pathname);
+ victim = filp_open(pathname->name, O_RDWR|O_LARGEFILE, 0);
err = PTR_ERR(victim);
if (IS_ERR(victim))
goto out;
@@ -1936,7 +1935,7 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
{
struct swap_info_struct *p;
- char *name;
+ struct getname_info *name;
struct file *swap_file = NULL;
struct address_space *mapping;
int i;
@@ -1967,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
name = NULL;
goto bad_swap;
}
- swap_file = filp_open(name, O_RDWR|O_LARGEFILE, 0);
+ swap_file = filp_open(name->name, O_RDWR|O_LARGEFILE, 0);
if (IS_ERR(swap_file)) {
error = PTR_ERR(swap_file);
swap_file = NULL;
@@ -2053,7 +2052,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
printk(KERN_INFO "Adding %uk swap on %s. "
"Priority:%d extents:%d across:%lluk %s%s%s\n",
- p->pages<<(PAGE_SHIFT-10), name, p->prio,
+ p->pages<<(PAGE_SHIFT-10), name->name, p->prio,
nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
(p->flags & SWP_SOLIDSTATE) ? "SS" : "",
(p->flags & SWP_DISCARDABLE) ? "D" : "",
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 15/49] audit: allow audit code to satisfy getname requests from its names_list
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (13 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 14/49] vfs: define getname_info struct and have getname() return it Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 16/49] vfs: turn do_path_lookup into wrapper around getname_info variant Jeff Layton
` (33 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Currently, if we call getname() on a userland string more than once,
we'll get multiple copies of the string and multiple audit_names
records.
Add a function that will allow the audit_names code to satisfy getname
requests using info from the audit_names list, avoiding a new allocation
and audit_names records.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 4 ++++
include/linux/audit.h | 8 ++++++++
kernel/auditsc.c | 23 +++++++++++++++++++++++
3 files changed, 35 insertions(+)
diff --git a/fs/namei.c b/fs/namei.c
index 60db390..01a2dd18 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -130,6 +130,10 @@ getname_flags(const char __user *filename, int flags, int *empty)
char *kname;
int len;
+ result = audit_reusename(filename);
+ if (result)
+ return result;
+
/* FIXME: create dedicated slabcache? */
result = kzalloc(sizeof(*result), GFP_KERNEL);
if (unlikely(!result))
diff --git a/include/linux/audit.h b/include/linux/audit.h
index d361921..ea58de3 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -469,6 +469,7 @@ extern void __audit_syscall_entry(int arch,
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
extern void __audit_syscall_exit(int ret_success, long ret_value);
+extern struct getname_info *__audit_reusename(const __user char *uptr);
extern void __audit_getname(struct getname_info *ginfo);
extern void audit_putname(struct getname_info *ginfo);
extern void __audit_inode(const char *name, const struct dentry *dentry,
@@ -505,6 +506,12 @@ static inline void audit_syscall_exit(void *pt_regs)
__audit_syscall_exit(success, return_code);
}
}
+static inline struct getname_info *audit_reusename(const __user char *name)
+{
+ if (unlikely(!audit_dummy_context()))
+ return __audit_reusename(name);
+ return NULL;
+}
static inline void audit_getname(struct getname_info *name)
{
if (unlikely(!audit_dummy_context()))
@@ -642,6 +649,7 @@ extern int audit_signals;
#define audit_syscall_entry(ta,a,b,c,d,e) do { ; } while (0)
#define audit_syscall_exit(r) do { ; } while (0)
#define audit_dummy_context() 1
+#define audit_reusename(g) ({ NULL; })
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
#define __audit_inode(n,d,p) do { ; } while (0)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 0ba346b..89974ca 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2035,6 +2035,29 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
}
/**
+ * audit_reusename - fill out getname_info with info from existing entry
+ * @uptr: userland ptr to pathname
+ *
+ * Search the audit_names list for the current audit context. If there is an
+ * existing entry with a matching "uptr" then return the getname_info
+ * associated with that audit_name. If not, return NULL.
+ */
+struct getname_info *
+__audit_reusename(const __user char *uptr)
+{
+ struct audit_context *context = current->audit_context;
+ struct audit_names *n;
+
+ list_for_each_entry(n, &context->names_list, list) {
+ if (!n->ginfo)
+ continue;
+ if (n->ginfo->uptr == uptr)
+ return n->ginfo;
+ }
+ return NULL;
+}
+
+/**
* audit_getname - add a name to the list
* @name: name to add
*
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 16/49] vfs: turn do_path_lookup into wrapper around getname_info variant
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (14 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 15/49] audit: allow audit code to satisfy getname requests from its names_list Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 17/49] vfs: make path_openat take a getname_info pointer Jeff Layton
` (32 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
...and make the user_path callers use that variant instead.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 30 +++++++++++++++++++++++-------
1 file changed, 23 insertions(+), 7 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 01a2dd18..5e31fbb 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1993,20 +1993,30 @@ static int path_lookupat(int dfd, const char *name,
return err;
}
-static int do_path_lookup(int dfd, const char *name,
+static int ginfo_lookup(int dfd, struct getname_info *ginfo,
unsigned int flags, struct nameidata *nd)
{
- int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd);
+ int retval = path_lookupat(dfd, ginfo->name, flags | LOOKUP_RCU, nd);
if (unlikely(retval == -ECHILD))
- retval = path_lookupat(dfd, name, flags, nd);
+ retval = path_lookupat(dfd, ginfo->name, flags, nd);
if (unlikely(retval == -ESTALE))
- retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);
+ retval = path_lookupat(dfd, ginfo->name,
+ flags | LOOKUP_REVAL, nd);
if (likely(!retval))
- audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
+ audit_inode(ginfo->name, nd->path.dentry,
+ flags & LOOKUP_PARENT);
return retval;
}
+static int do_path_lookup(int dfd, const char *name,
+ unsigned int flags, struct nameidata *nd)
+{
+ struct getname_info ginfo = { .name = name };
+
+ return ginfo_lookup(dfd, &ginfo, flags, nd);
+}
+
/* does lookup, returns the object with parent locked */
struct dentry *kern_path_locked(const char *name, struct path *path)
{
@@ -2130,7 +2140,7 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
BUG_ON(flags & LOOKUP_PARENT);
- err = do_path_lookup(dfd, tmp->name, flags, &nd);
+ err = ginfo_lookup(dfd, tmp, flags, &nd);
putname(tmp);
if (!err)
*path = nd.path;
@@ -2144,6 +2154,12 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
return user_path_at_empty(dfd, name, flags, path, NULL);
}
+/*
+ * NB: most callers don't do anything directly with the reference to the
+ * to ginfo, but the nd->last pointer points into the name string
+ * allocated by getname. So we must hold the reference to it until all
+ * path-walking is complete.
+ */
static struct getname_info *
user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
{
@@ -2153,7 +2169,7 @@ user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
if (IS_ERR(s))
return s;
- error = do_path_lookup(dfd, s->name, LOOKUP_PARENT, nd);
+ error = ginfo_lookup(dfd, s, LOOKUP_PARENT, nd);
if (error) {
putname(s);
return ERR_PTR(error);
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 17/49] vfs: make path_openat take a getname_info pointer
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (15 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 16/49] vfs: turn do_path_lookup into wrapper around getname_info variant Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 18/49] audit: make audit_inode take getname_info Jeff Layton
` (31 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
...and fix up the callers. For do_file_open_root, just declare a
getname_info on the stack and fill out the .name field. For
do_filp_open, make it also take a getname_info pointer, and fix up its
callers to call it appropriately.
For filp_open, add a variant that takes a getname_info pointer and turn
filp_open into a wrapper around it.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/exec.c | 5 +++--
fs/internal.h | 4 ++--
fs/namei.c | 28 +++++++++++++++-------------
fs/open.c | 33 +++++++++++++++++++++++++++++----
include/linux/fs.h | 1 +
kernel/acct.c | 6 +++---
mm/swapfile.c | 4 ++--
7 files changed, 55 insertions(+), 26 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index 222e282..77ea602 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -126,7 +126,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
if (IS_ERR(tmp))
goto out;
- file = do_filp_open(AT_FDCWD, tmp->name, &uselib_flags, LOOKUP_FOLLOW);
+ file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
putname(tmp);
error = PTR_ERR(file);
if (IS_ERR(file))
@@ -761,13 +761,14 @@ struct file *open_exec(const char *name)
{
struct file *file;
int err;
+ struct getname_info tmp = { .name = name };
static const struct open_flags open_exec_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
.acc_mode = MAY_EXEC | MAY_OPEN,
.intent = LOOKUP_OPEN
};
- file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW);
+ file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW);
if (IS_ERR(file))
goto out;
diff --git a/fs/internal.h b/fs/internal.h
index 371bcc4..ddc0d2c 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -97,8 +97,8 @@ struct open_flags {
int acc_mode;
int intent;
};
-extern struct file *do_filp_open(int dfd, const char *pathname,
- const struct open_flags *op, int lookup_flags);
+extern struct file *do_filp_open(int dfd, struct getname_info *ginfo,
+ const struct open_flags *op, int flags);
extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
const char *, const struct open_flags *, int lookup_flags);
diff --git a/fs/namei.c b/fs/namei.c
index 5e31fbb..048373c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2667,7 +2667,7 @@ out_dput:
*/
static int do_last(struct nameidata *nd, struct path *path,
struct file *file, const struct open_flags *op,
- int *opened, const char *pathname)
+ int *opened, struct getname_info *ginfo)
{
struct dentry *dir = nd->path.dentry;
int open_flag = op->open_flag;
@@ -2679,6 +2679,7 @@ static int do_last(struct nameidata *nd, struct path *path,
struct path save_parent = { .dentry = NULL, .mnt = NULL };
bool retried = false;
int error;
+ const char *pathname = ginfo->name;
nd->flags &= ~LOOKUP_PARENT;
nd->flags |= op->intent;
@@ -2913,7 +2914,7 @@ stale_open:
goto retry_lookup;
}
-static struct file *path_openat(int dfd, const char *pathname,
+static struct file *path_openat(int dfd, struct getname_info *ginfo,
struct nameidata *nd, const struct open_flags *op, int flags)
{
struct file *base = NULL;
@@ -2928,16 +2929,16 @@ static struct file *path_openat(int dfd, const char *pathname,
file->f_flags = op->open_flag;
- error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base);
+ error = path_init(dfd, ginfo->name, flags | LOOKUP_PARENT, nd, &base);
if (unlikely(error))
goto out;
current->total_link_count = 0;
- error = link_path_walk(pathname, nd);
+ error = link_path_walk(ginfo->name, nd);
if (unlikely(error))
goto out;
- error = do_last(nd, &path, file, op, &opened, pathname);
+ error = do_last(nd, &path, file, op, &opened, ginfo);
while (unlikely(error > 0)) { /* trailing symlink */
struct path link = path;
void *cookie;
@@ -2955,7 +2956,7 @@ static struct file *path_openat(int dfd, const char *pathname,
error = follow_link(&link, nd, &cookie);
if (unlikely(error))
break;
- error = do_last(nd, &path, file, op, &opened, pathname);
+ error = do_last(nd, &path, file, op, &opened, ginfo);
put_link(nd, &link, cookie);
}
out:
@@ -2979,17 +2980,17 @@ out:
return file;
}
-struct file *do_filp_open(int dfd, const char *pathname,
+struct file *do_filp_open(int dfd, struct getname_info *ginfo,
const struct open_flags *op, int flags)
{
struct nameidata nd;
struct file *filp;
- filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU);
+ filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_RCU);
if (unlikely(filp == ERR_PTR(-ECHILD)))
- filp = path_openat(dfd, pathname, &nd, op, flags);
+ filp = path_openat(dfd, ginfo, &nd, op, flags);
if (unlikely(filp == ERR_PTR(-ESTALE)))
- filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL);
+ filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_REVAL);
return filp;
}
@@ -2998,6 +2999,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
{
struct nameidata nd;
struct file *file;
+ struct getname_info ginfo = { .name = name };
nd.root.mnt = mnt;
nd.root.dentry = dentry;
@@ -3007,11 +3009,11 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
return ERR_PTR(-ELOOP);
- file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU);
+ file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_RCU);
if (unlikely(file == ERR_PTR(-ECHILD)))
- file = path_openat(-1, name, &nd, op, flags);
+ file = path_openat(-1, &ginfo, &nd, op, flags);
if (unlikely(file == ERR_PTR(-ESTALE)))
- file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL);
+ file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_REVAL);
return file;
}
diff --git a/fs/open.c b/fs/open.c
index 3796d0c..d0f225e 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -909,6 +909,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
}
/**
+ * filp_open_ginfo - open file and return file pointer
+ *
+ * @ginfo: getname_info containing path to open
+ * @flags: open flags as per the open(2) second argument
+ * @mode: mode for the new file if O_CREAT is set, else ignored
+ *
+ * This is the helper to open a file from kernelspace if you really
+ * have to. But in generally you should not do this, so please move
+ * along, nothing to see here..
+ */
+struct file *filp_open_ginfo(struct getname_info *ginfo, int flags, umode_t mode)
+{
+ struct open_flags op;
+ int lookup = build_open_flags(flags, mode, &op);
+ return do_filp_open(AT_FDCWD, ginfo, &op, lookup);
+}
+
+/**
* filp_open - open file and return file pointer
*
* @filename: path to open
@@ -921,9 +939,16 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
*/
struct file *filp_open(const char *filename, int flags, umode_t mode)
{
- struct open_flags op;
- int lookup = build_open_flags(flags, mode, &op);
- return do_filp_open(AT_FDCWD, filename, &op, lookup);
+ struct file *filp;
+ struct getname_info *ginfo = kzalloc(sizeof(*ginfo), GFP_KERNEL);
+
+ if (!ginfo)
+ return ERR_PTR(-ENOMEM);
+
+ ginfo->name = filename;
+ filp = filp_open_ginfo(ginfo, flags, mode);
+ putname(ginfo);
+ return filp;
}
EXPORT_SYMBOL(filp_open);
@@ -951,7 +976,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
- struct file *f = do_filp_open(dfd, tmp->name, &op, lookup);
+ struct file *f = do_filp_open(dfd, tmp, &op, lookup);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1b0d0fb..a37b0c1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2200,6 +2200,7 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset,
loff_t len);
extern long do_sys_open(int dfd, const char __user *filename, int flags,
umode_t mode);
+extern struct file *filp_open_ginfo(struct getname_info *, int, umode_t);
extern struct file *filp_open(const char *, int, umode_t);
extern struct file *file_open_root(struct dentry *, struct vfsmount *,
const char *, int);
diff --git a/kernel/acct.c b/kernel/acct.c
index 3943608..a6b3e14 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -193,7 +193,7 @@ static void acct_file_reopen(struct bsd_acct_struct *acct, struct file *file,
}
}
-static int acct_on(const char *name)
+static int acct_on(struct getname_info *pathname)
{
struct file *file;
struct vfsmount *mnt;
@@ -201,7 +201,7 @@ static int acct_on(const char *name)
struct bsd_acct_struct *acct = NULL;
/* Difference from BSD - they don't do O_APPEND */
- file = filp_open(name, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
+ file = filp_open_ginfo(pathname, O_WRONLY|O_APPEND|O_LARGEFILE, 0);
if (IS_ERR(file))
return PTR_ERR(file);
@@ -263,7 +263,7 @@ SYSCALL_DEFINE1(acct, const char __user *, name)
struct getname_info *tmp = getname(name);
if (IS_ERR(tmp))
return (PTR_ERR(tmp));
- error = acct_on(tmp->name);
+ error = acct_on(tmp);
putname(tmp);
} else {
struct bsd_acct_struct *acct;
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 8dbf46d..0f8b1a4 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1498,7 +1498,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
if (IS_ERR(pathname))
goto out;
- victim = filp_open(pathname->name, O_RDWR|O_LARGEFILE, 0);
+ victim = filp_open_ginfo(pathname, O_RDWR|O_LARGEFILE, 0);
err = PTR_ERR(victim);
if (IS_ERR(victim))
goto out;
@@ -1966,7 +1966,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
name = NULL;
goto bad_swap;
}
- swap_file = filp_open(name->name, O_RDWR|O_LARGEFILE, 0);
+ swap_file = filp_open_ginfo(name, O_RDWR|O_LARGEFILE, 0);
if (IS_ERR(swap_file)) {
error = PTR_ERR(swap_file);
swap_file = NULL;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 18/49] audit: make audit_inode take getname_info
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (16 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 17/49] vfs: make path_openat take a getname_info pointer Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 19/49] vfs: embed getname_info inside of names_cache allocation if possible Jeff Layton
` (30 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Keep a pointer to the audit_names "slot" in getname_info.
Have all of the audit_inode callers pass a getname_info ponter to
audit_inode instead of a string pointer. If the aname field is already
populated, then we can skip walking the list altogether and just use it
directly.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 16 +++++++---------
include/linux/audit.h | 10 +++++-----
include/linux/fs.h | 6 ++++--
ipc/mqueue.c | 4 ++--
kernel/auditsc.c | 29 +++++++++++++++++++++++++----
5 files changed, 43 insertions(+), 22 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 048373c..5e2f5ae 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2004,8 +2004,7 @@ static int ginfo_lookup(int dfd, struct getname_info *ginfo,
flags | LOOKUP_REVAL, nd);
if (likely(!retval))
- audit_inode(ginfo->name, nd->path.dentry,
- flags & LOOKUP_PARENT);
+ audit_inode(ginfo, nd->path.dentry, flags & LOOKUP_PARENT);
return retval;
}
@@ -2679,7 +2678,6 @@ static int do_last(struct nameidata *nd, struct path *path,
struct path save_parent = { .dentry = NULL, .mnt = NULL };
bool retried = false;
int error;
- const char *pathname = ginfo->name;
nd->flags &= ~LOOKUP_PARENT;
nd->flags |= op->intent;
@@ -2695,7 +2693,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = complete_walk(nd);
if (error)
return error;
- audit_inode(pathname, nd->path.dentry, 0);
+ audit_inode(ginfo, nd->path.dentry, 0);
if (open_flag & O_CREAT) {
error = -EISDIR;
goto out;
@@ -2705,7 +2703,7 @@ static int do_last(struct nameidata *nd, struct path *path,
error = complete_walk(nd);
if (error)
return error;
- audit_inode(pathname, dir, 0);
+ audit_inode(ginfo, dir, 0);
goto finish_open;
}
@@ -2734,7 +2732,7 @@ static int do_last(struct nameidata *nd, struct path *path,
if (error)
return error;
- audit_inode(pathname, dir, 0);
+ audit_inode(ginfo, dir, 0);
error = -EISDIR;
/* trailing slashes? */
if (nd->last.name[nd->last.len])
@@ -2764,7 +2762,7 @@ retry_lookup:
!S_ISREG(file->f_path.dentry->d_inode->i_mode))
will_truncate = false;
- audit_inode(pathname, file->f_path.dentry, 0);
+ audit_inode(ginfo, file->f_path.dentry, 0);
goto opened;
}
@@ -2781,7 +2779,7 @@ retry_lookup:
* create/update audit record if it already exists.
*/
if (path->dentry->d_inode)
- audit_inode(pathname, path->dentry, 0);
+ audit_inode(ginfo, path->dentry, 0);
/*
* If atomic_open() acquired write access it is dropped now due to
@@ -2846,7 +2844,7 @@ finish_lookup:
error = -ENOTDIR;
if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
goto out;
- audit_inode(pathname, nd->path.dentry, 0);
+ audit_inode(ginfo, nd->path.dentry, 0);
finish_open:
if (!S_ISREG(nd->inode->i_mode))
will_truncate = false;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index ea58de3..481cf75 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -472,7 +472,7 @@ extern void __audit_syscall_exit(int ret_success, long ret_value);
extern struct getname_info *__audit_reusename(const __user char *uptr);
extern void __audit_getname(struct getname_info *ginfo);
extern void audit_putname(struct getname_info *ginfo);
-extern void __audit_inode(const char *name, const struct dentry *dentry,
+extern void __audit_inode(struct getname_info *ginfo, const struct dentry *dentry,
unsigned int parent);
extern void __audit_inode_child(const struct inode *parent,
const struct dentry *dentry,
@@ -517,10 +517,10 @@ static inline void audit_getname(struct getname_info *name)
if (unlikely(!audit_dummy_context()))
__audit_getname(name);
}
-static inline void audit_inode(const char *name, const struct dentry *dentry,
+static inline void audit_inode(struct getname_info *ginfo, const struct dentry *dentry,
unsigned int parent) {
if (unlikely(!audit_dummy_context()))
- __audit_inode(name, dentry, parent);
+ __audit_inode(ginfo, dentry, parent);
}
static inline void audit_inode_child(const struct inode *parent,
const struct dentry *dentry,
@@ -652,9 +652,9 @@ extern int audit_signals;
#define audit_reusename(g) ({ NULL; })
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
-#define __audit_inode(n,d,p) do { ; } while (0)
+#define __audit_inode(g,d,p) do { ; } while (0)
#define __audit_inode_child(p,d) do { ; } while (0)
-#define audit_inode(n,d,p) do { ; } while (0)
+#define audit_inode(g,d,p) do { ; } while (0)
#define audit_inode_child(p,d,t) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0)
#define audit_seccomp(i,s,c) do { ; } while (0)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a37b0c1..4ce38f2 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2189,9 +2189,11 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
#endif /* CONFIG_FILE_LOCKING */
/* fs/open.c */
+struct audit_names;
struct getname_info {
- const char *name; /* pointer to actual string */
- const __user char *uptr; /* original userland pointer */
+ const char *name; /* pointer to actual string */
+ const __user char *uptr; /* original userland pointer */
+ struct audit_names *aname;
};
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 2071a27..07d489e 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -805,7 +805,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
if (oflag & O_CREAT) {
if (path.dentry->d_inode) { /* entry already exists */
- audit_inode(name->name, path.dentry, 0);
+ audit_inode(name, path.dentry, 0);
if (oflag & O_EXCL) {
error = -EEXIST;
goto out;
@@ -825,7 +825,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
error = -ENOENT;
goto out;
}
- audit_inode(name->name, path.dentry, 0);
+ audit_inode(name, path.dentry, 0);
filp = do_open(&path, oflag);
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 89974ca..92ef854 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2090,6 +2090,7 @@ void __audit_getname(struct getname_info *ginfo)
n->ginfo = ginfo;
n->name_len = AUDIT_NAME_FULL;
n->name_put = true;
+ ginfo->aname = n;
if (!context->pwd.dentry)
get_fs_pwd(current->fs, &context->pwd);
@@ -2176,11 +2177,11 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
/**
* __audit_inode - store the inode and device from a lookup
- * @name: name being audited
+ * @ginfo: getname_info for name being audited
* @dentry: dentry being audited
* @parent: does this dentry represent the parent?
*/
-void __audit_inode(const char *name, const struct dentry *dentry,
+void __audit_inode(struct getname_info *ginfo, const struct dentry *dentry,
unsigned int parent)
{
struct audit_context *context = current->audit_context;
@@ -2190,12 +2191,32 @@ void __audit_inode(const char *name, const struct dentry *dentry,
if (!context->in_syscall)
return;
- if (!name)
+ if (!ginfo)
goto out_alloc;
+#if AUDIT_DEBUG
+ /* The getname_info _must_ have a populated ->name */
+ BUG_ON(!ginfo->name);
+#endif
+ /*
+ * If we have a pointer to an audit_names entry already, then we can
+ * just use it directly if the type is correct.
+ */
+ n = ginfo->aname;
+ if (n) {
+ if (parent) {
+ if (n->type == AUDIT_TYPE_PARENT ||
+ n->type == AUDIT_TYPE_UNKNOWN)
+ goto out;
+ } else {
+ if (n->type != AUDIT_TYPE_PARENT)
+ goto out;
+ }
+ }
+
list_for_each_entry_reverse(n, &context->names_list, list) {
/* does the name pointer match? */
- if (!n->ginfo || n->ginfo->name != name)
+ if (!n->ginfo || n->ginfo->name != ginfo->name)
continue;
/* match the correct record type */
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 19/49] vfs: embed getname_info inside of names_cache allocation if possible
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (17 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 18/49] audit: make audit_inode take getname_info Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 20/49] vfs: unexport getname and putname symbols Jeff Layton
` (29 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
In the common case where a name is much smaller than PATH_MAX, an extra
allocation for struct getname_info is unnecessary. Before allocating a
separate one, try to embed the getname_info inside the buffer first. If
it turns out that that's not long enough, then fall back to allocating a
separate getname_info struct and redoing the copy.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 69 ++++++++++++++++++++++++++++++++++++++----------------
include/linux/fs.h | 1 +
2 files changed, 50 insertions(+), 20 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 5e2f5ae..48cb4aa 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -119,40 +119,69 @@
*/
void final_putname(struct getname_info *ginfo)
{
- __putname(ginfo->name);
- kfree(ginfo);
+ if (ginfo->separate) {
+ __putname(ginfo->name);
+ kfree(ginfo);
+ } else {
+ __putname(ginfo);
+ }
}
+#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct getname_info))
+
static struct getname_info *
getname_flags(const char __user *filename, int flags, int *empty)
{
struct getname_info *result, *err;
- char *kname;
int len;
+ long max;
+ char *kname;
result = audit_reusename(filename);
if (result)
return result;
- /* FIXME: create dedicated slabcache? */
- result = kzalloc(sizeof(*result), GFP_KERNEL);
+ result = __getname();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
- kname = __getname();
- if (unlikely(!kname)) {
- err = ERR_PTR(-ENOMEM);
- goto error_free_ginfo;
- }
-
+ /*
+ * First, try to embed the getname_info inside the names_cache
+ * allocation
+ */
+ kname = (char *)result + sizeof(*result);
result->name = kname;
- result->uptr = filename;
- len = strncpy_from_user(kname, filename, PATH_MAX);
+ result->separate = false;
+ max = EMBEDDED_NAME_MAX;
+
+recopy:
+ len = strncpy_from_user(kname, filename, max);
if (unlikely(len < 0)) {
err = ERR_PTR(len);
goto error;
}
+ /*
+ * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
+ * separate getname_info struct so we can dedicate the entire
+ * names_cache allocation for the pathname, and re-do the copy from
+ * userland.
+ */
+ if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) {
+ kname = (char *)result;
+
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
+ if (!result) {
+ err = ERR_PTR(-ENOMEM);
+ result = (struct getname_info *)kname;
+ goto error;
+ }
+ result->name = kname;
+ result->separate = true;
+ max = PATH_MAX;
+ goto recopy;
+ }
+
/* The empty path is special. */
if (unlikely(!len)) {
if (empty)
@@ -163,15 +192,15 @@ getname_flags(const char __user *filename, int flags, int *empty)
}
err = ERR_PTR(-ENAMETOOLONG);
- if (likely(len < PATH_MAX)) {
- audit_getname(result);
- return result;
- }
+ if (unlikely(len >= PATH_MAX))
+ goto error;
+
+ result->uptr = filename;
+ audit_getname(result);
+ return result;
error:
- __putname(kname);
-error_free_ginfo:
- kfree(result);
+ final_putname(result);
return err;
}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4ce38f2..a3c2c17 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2194,6 +2194,7 @@ struct getname_info {
const char *name; /* pointer to actual string */
const __user char *uptr; /* original userland pointer */
struct audit_names *aname;
+ bool separate; /* should "name" be freed? */
};
extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 20/49] vfs: unexport getname and putname symbols
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (18 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 19/49] vfs: embed getname_info inside of names_cache allocation if possible Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 21/49] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
` (28 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
I see no callers in module code.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 48cb4aa..d3f8998 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -209,7 +209,6 @@ getname(const char __user * filename)
{
return getname_flags(filename, 0, NULL);
}
-EXPORT_SYMBOL(getname);
void putname(struct getname_info *ginfo)
{
@@ -219,7 +218,6 @@ void putname(struct getname_info *ginfo)
#endif
final_putname(ginfo);
}
-EXPORT_SYMBOL(putname);
static int check_acl(struct inode *inode, int mask)
{
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 21/49] vfs: add a retry_estale helper function to handle retries on ESTALE
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (19 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 20/49] vfs: unexport getname and putname symbols Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 22/49] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
` (27 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
This function is expected to be called from path-based syscalls to help
them decide whether to try the lookup and call again in the event that
they got an -ESTALE return back on an earier try.
Currently, we only retry the call once on an ESTALE error, but in the
event that we decide that that's not enough in the future, we should be
able to change the logic in this helper without too much effort.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
include/linux/fs.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a3c2c17..78e8639 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2221,6 +2221,27 @@ extern int finish_open(struct file *file, struct dentry *dentry,
int *opened);
extern int finish_no_open(struct file *file, struct dentry *dentry);
+/**
+ * retry_estale - determine whether the caller should retry an operation
+ *
+ * @error: the error we'll be returning
+ * @try: number of retries already performed
+ *
+ * Check to see if the error code was -ESTALE, and then determine whether
+ * to retry the call based on the number of retries so far. Currently, we only
+ * retry the call once.
+ *
+ * Returns true if the caller should try again.
+ */
+static inline bool
+retry_estale(const long error, const unsigned int try)
+{
+ if (likely(error != -ESTALE))
+ return false;
+
+ return !try;
+}
+
/* fs/ioctl.c */
extern int ioctl_preallocate(struct file *filp, void __user *argp);
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 22/49] vfs: make fstatat retry on ESTALE errors from getattr call
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (20 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 21/49] vfs: add a retry_estale helper function to handle retries on ESTALE Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 23/49] vfs: fix readlinkat to retry on ESTALE Jeff Layton
` (26 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/stat.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/fs/stat.c b/fs/stat.c
index 4078022..7f1602a 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -74,7 +74,8 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
{
struct path path;
int error = -EINVAL;
- int lookup_flags = 0;
+ unsigned int try = 0;
+ unsigned int lookup_flags = 0;
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH)) != 0)
@@ -85,12 +86,15 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
- error = user_path_at(dfd, filename, lookup_flags, &path);
- if (error)
- goto out;
+ do {
+ error = user_path_at(dfd, filename, lookup_flags, &path);
+ if (error)
+ break;
- error = vfs_getattr(path.mnt, path.dentry, stat);
- path_put(&path);
+ error = vfs_getattr(path.mnt, path.dentry, stat);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
out:
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 23/49] vfs: fix readlinkat to retry on ESTALE
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (21 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 22/49] vfs: make fstatat retry on ESTALE errors from getattr call Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 24/49] vfs: add new "reval" argument to kern_path_create and user_path_create Jeff Layton
` (25 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/stat.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/fs/stat.c b/fs/stat.c
index 7f1602a..ede71cb 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -300,14 +300,21 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
struct path path;
int error;
int empty = 0;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_EMPTY;
if (bufsiz <= 0)
return -EINVAL;
- error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty);
- if (!error) {
- struct inode *inode = path.dentry->d_inode;
+ do {
+ struct inode *inode;
+
+ error = user_path_at_empty(dfd, pathname, lookup_flags,
+ &path, &empty);
+ if (error)
+ break;
+ inode = path.dentry->d_inode;
error = empty ? -ENOENT : -EINVAL;
if (inode->i_op->readlink) {
error = security_inode_readlink(path.dentry);
@@ -318,7 +325,8 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
}
}
path_put(&path);
- }
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 24/49] vfs: add new "reval" argument to kern_path_create and user_path_create
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (22 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 23/49] vfs: fix readlinkat to retry on ESTALE Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 25/49] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
` (24 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
...for now, all of the callers pass in "false". Eventually, we'll set
that to "true" when we retry the lookup after getting back an ESTALE on
a call.
While we're at it, change the is_dir arg to a bool since that's how it's
used currently.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
arch/powerpc/platforms/cell/spufs/syscalls.c | 2 +-
drivers/base/devtmpfs.c | 7 ++++---
fs/namei.c | 23 +++++++++++++++--------
fs/ocfs2/refcounttree.c | 3 ++-
include/linux/namei.h | 4 ++--
net/unix/af_unix.c | 2 +-
6 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 5b7d8ff..cb4acc7 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -66,7 +66,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
struct dentry *dentry;
int ret;
- dentry = user_path_create(AT_FDCWD, pathname, &path, 1);
+ dentry = user_path_create(AT_FDCWD, pathname, &path, true, false);
ret = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
ret = spufs_create(&path, dentry, flags, mode, neighbor);
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index deb4a45..2124437 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -148,7 +148,7 @@ static int dev_mkdir(const char *name, umode_t mode)
struct path path;
int err;
- dentry = kern_path_create(AT_FDCWD, name, &path, 1);
+ dentry = kern_path_create(AT_FDCWD, name, &path, true, false);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
@@ -193,10 +193,11 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)
struct path path;
int err;
- dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
+ dentry = kern_path_create(AT_FDCWD, nodename, &path, false, false);
if (dentry == ERR_PTR(-ENOENT)) {
create_path(nodename);
- dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
+ dentry = kern_path_create(AT_FDCWD, nodename, &path,
+ false, false);
}
if (IS_ERR(dentry))
return PTR_ERR(dentry);
diff --git a/fs/namei.c b/fs/namei.c
index d3f8998..6c75fc1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3042,12 +3042,18 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
return file;
}
-struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir)
+struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, bool is_dir, bool reval)
{
struct dentry *dentry = ERR_PTR(-EEXIST);
struct nameidata nd;
int err2;
- int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd);
+ int error;
+ unsigned int lookup_flags = LOOKUP_PARENT;
+
+ if (reval)
+ lookup_flags |= LOOKUP_REVAL;
+
+ error = do_path_lookup(dfd, pathname, lookup_flags, &nd);
if (error)
return ERR_PTR(error);
@@ -3111,13 +3117,14 @@ void done_path_create(struct path *path, struct dentry *dentry)
}
EXPORT_SYMBOL(done_path_create);
-struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+ struct path *path, bool is_dir, bool reval)
{
struct getname_info *tmp = getname(pathname);
struct dentry *res;
if (IS_ERR(tmp))
return ERR_CAST(tmp);
- res = kern_path_create(dfd, tmp->name, path, is_dir);
+ res = kern_path_create(dfd, tmp->name, path, is_dir, reval);
putname(tmp);
return res;
}
@@ -3178,7 +3185,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
if (error)
return error;
- dentry = user_path_create(dfd, filename, &path, 0);
+ dentry = user_path_create(dfd, filename, &path, false, false);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
@@ -3240,7 +3247,7 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
struct path path;
int error;
- dentry = user_path_create(dfd, pathname, &path, 1);
+ dentry = user_path_create(dfd, pathname, &path, true, false);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
@@ -3516,7 +3523,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
if (IS_ERR(from))
return PTR_ERR(from);
- dentry = user_path_create(newdfd, newname, &path, 0);
+ dentry = user_path_create(newdfd, newname, &path, false, false);
error = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_putname;
@@ -3616,7 +3623,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
if (error)
return error;
- new_dentry = user_path_create(newdfd, newname, &new_path, 0);
+ new_dentry = user_path_create(newdfd, newname, &new_path, false, false);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry))
goto out;
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c
index 30a0550..645e225 100644
--- a/fs/ocfs2/refcounttree.c
+++ b/fs/ocfs2/refcounttree.c
@@ -4453,7 +4453,8 @@ int ocfs2_reflink_ioctl(struct inode *inode,
return error;
}
- new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0);
+ new_dentry = user_path_create(AT_FDCWD, newname, &new_path,
+ false, false);
error = PTR_ERR(new_dentry);
if (IS_ERR(new_dentry)) {
mlog_errno(error);
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 4bf19d8..2202740 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -65,8 +65,8 @@ extern int user_path_at_empty(int, const char __user *, unsigned, struct path *,
extern int kern_path(const char *, unsigned, struct path *);
-extern struct dentry *kern_path_create(int, const char *, struct path *, int);
-extern struct dentry *user_path_create(int, const char __user *, struct path *, int);
+extern struct dentry *kern_path_create(int, const char *, struct path *, bool, bool);
+extern struct dentry *user_path_create(int, const char __user *, struct path *, bool, bool);
extern void done_path_create(struct path *, struct dentry *);
extern struct dentry *kern_path_locked(const char *, struct path *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c5ee4ff..f15b0ff 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -832,7 +832,7 @@ static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
* Get the parent directory, calculate the hash for last
* component.
*/
- dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
+ dentry = kern_path_create(AT_FDCWD, sun_path, &path, false, false);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
return err;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 25/49] vfs: fix mknodat to retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (23 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 24/49] vfs: add new "reval" argument to kern_path_create and user_path_create Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 26/49] vfs: fix mkdir " Jeff Layton
` (23 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 43 +++++++++++++++++++++++++------------------
1 file changed, 25 insertions(+), 18 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 6c75fc1..ac62973 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3180,34 +3180,41 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
struct dentry *dentry;
struct path path;
int error;
+ unsigned int try = 0;
error = may_mknod(mode);
if (error)
return error;
- dentry = user_path_create(dfd, filename, &path, false, false);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ do {
+ dentry = user_path_create(dfd, filename, &path, false, try);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
- if (!IS_POSIXACL(path.dentry->d_inode))
- mode &= ~current_umask();
- error = security_path_mknod(&path, dentry, mode, dev);
- if (error)
- goto out;
- switch (mode & S_IFMT) {
- case 0: case S_IFREG:
- error = vfs_create(path.dentry->d_inode,dentry,mode,true);
+ if (!IS_POSIXACL(path.dentry->d_inode))
+ mode &= ~current_umask();
+ error = security_path_mknod(&path, dentry, mode, dev);
+ if (error)
+ goto out;
+ switch (mode & S_IFMT) {
+ case 0:
+ case S_IFREG:
+ error = vfs_create(path.dentry->d_inode, dentry,
+ mode, true);
break;
- case S_IFCHR: case S_IFBLK:
- error = vfs_mknod(path.dentry->d_inode,dentry,mode,
+ case S_IFCHR:
+ case S_IFBLK:
+ error = vfs_mknod(path.dentry->d_inode, dentry, mode,
new_decode_dev(dev));
break;
- case S_IFIFO: case S_IFSOCK:
- error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
- break;
- }
+ case S_IFIFO:
+ case S_IFSOCK:
+ error = vfs_mknod(path.dentry->d_inode, dentry,
+ mode, 0);
+ }
out:
- done_path_create(&path, dentry);
+ done_path_create(&path, dentry);
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 26/49] vfs: fix mkdir to retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (24 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 25/49] vfs: fix mknodat to retry on ESTALE errors Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 27/49] vfs: fix symlinkat " Jeff Layton
` (22 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ac62973..dd1d519 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3253,17 +3253,20 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
struct dentry *dentry;
struct path path;
int error;
+ unsigned int try = 0;
- dentry = user_path_create(dfd, pathname, &path, true, false);
- if (IS_ERR(dentry))
- return PTR_ERR(dentry);
+ do {
+ dentry = user_path_create(dfd, pathname, &path, true, false);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
- if (!IS_POSIXACL(path.dentry->d_inode))
- mode &= ~current_umask();
- error = security_path_mkdir(&path, dentry, mode);
- if (!error)
- error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
- done_path_create(&path, dentry);
+ if (!IS_POSIXACL(path.dentry->d_inode))
+ mode &= ~current_umask();
+ error = security_path_mkdir(&path, dentry, mode);
+ if (!error)
+ error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+ done_path_create(&path, dentry);
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 27/49] vfs: fix symlinkat to retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (25 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 26/49] vfs: fix mkdir " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 28/49] vfs: fix linkat " Jeff Layton
` (21 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index dd1d519..fb9d36f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3528,21 +3528,25 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
struct getname_info *from;
struct dentry *dentry;
struct path path;
+ unsigned int try = 0;
from = getname(oldname);
if (IS_ERR(from))
return PTR_ERR(from);
- dentry = user_path_create(newdfd, newname, &path, false, false);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto out_putname;
+ do {
+ dentry = user_path_create(newdfd, newname, &path, false, false);
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
+ break;
+ }
- error = security_path_symlink(&path, dentry, from->name);
- if (!error)
- error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
- done_path_create(&path, dentry);
-out_putname:
+ error = security_path_symlink(&path, dentry, from->name);
+ if (!error)
+ error = vfs_symlink(path.dentry->d_inode, dentry,
+ from->name);
+ done_path_create(&path, dentry);
+ } while (retry_estale(error, try++));
putname(from);
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 28/49] vfs: fix linkat to retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (26 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 27/49] vfs: fix symlinkat " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 29/49] vfs: add a reval argument to user_path_parent Jeff Layton
` (20 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 46 ++++++++++++++++++++++++++--------------------
1 file changed, 26 insertions(+), 20 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index fb9d36f..e0ee4b9 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3616,6 +3616,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
struct path old_path, new_path;
int how = 0;
int error;
+ unsigned int try = 0;
if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL;
@@ -3633,30 +3634,35 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
if (flags & AT_SYMLINK_FOLLOW)
how |= LOOKUP_FOLLOW;
- error = user_path_at(olddfd, oldname, how, &old_path);
- if (error)
- return error;
+ do {
+ error = user_path_at(olddfd, oldname, how, &old_path);
+ if (error)
+ break;
- new_dentry = user_path_create(newdfd, newname, &new_path, false, false);
- error = PTR_ERR(new_dentry);
- if (IS_ERR(new_dentry))
- goto out;
+ new_dentry = user_path_create(newdfd, newname, &new_path,
+ false, false);
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto out;
- error = -EXDEV;
- if (old_path.mnt != new_path.mnt)
- goto out_dput;
- error = may_linkat(&old_path);
- if (unlikely(error))
- goto out_dput;
- error = security_path_link(old_path.dentry, &new_path, new_dentry);
- if (error)
- goto out_dput;
- error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
+ error = -EXDEV;
+ if (old_path.mnt != new_path.mnt)
+ goto out_dput;
+ error = may_linkat(&old_path);
+ if (unlikely(error))
+ goto out_dput;
+ error = security_path_link(old_path.dentry, &new_path,
+ new_dentry);
+ if (error)
+ goto out_dput;
+ error = vfs_link(old_path.dentry, new_path.dentry->d_inode,
+ new_dentry);
out_dput:
- done_path_create(&new_path, new_dentry);
+ done_path_create(&new_path, new_dentry);
out:
- path_put(&old_path);
-
+ path_put(&old_path);
+ how |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 29/49] vfs: add a reval argument to user_path_parent
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (27 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 28/49] vfs: fix linkat " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 30/49] vfs: make rmdir retry on ESTALE errors Jeff Layton
` (19 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
...so we can tell it when to set LOOKUP_REVAL.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index e0ee4b9..b73315d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2187,15 +2187,20 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,
* path-walking is complete.
*/
static struct getname_info *
-user_path_parent(int dfd, const char __user *path, struct nameidata *nd)
+user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
+ unsigned int reval)
{
struct getname_info *s = getname(path);
int error;
+ unsigned int flags = LOOKUP_PARENT;
+
+ if (reval)
+ flags |= LOOKUP_REVAL;
if (IS_ERR(s))
return s;
- error = ginfo_lookup(dfd, s, LOOKUP_PARENT, nd);
+ error = ginfo_lookup(dfd, s, flags, nd);
if (error) {
putname(s);
return ERR_PTR(error);
@@ -3343,7 +3348,7 @@ static long do_rmdir(int dfd, const char __user *pathname)
struct dentry *dentry;
struct nameidata nd;
- name = user_path_parent(dfd, pathname, &nd);
+ name = user_path_parent(dfd, pathname, &nd, 0);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -3439,7 +3444,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
struct nameidata nd;
struct inode *inode = NULL;
- name = user_path_parent(dfd, pathname, &nd);
+ name = user_path_parent(dfd, pathname, &nd, 0);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -3834,13 +3839,13 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
struct getname_info *to;
int error;
- from = user_path_parent(olddfd, oldname, &oldnd);
+ from = user_path_parent(olddfd, oldname, &oldnd, 0);
if (IS_ERR(from)) {
error = PTR_ERR(from);
goto exit;
}
- to = user_path_parent(newdfd, newname, &newnd);
+ to = user_path_parent(newdfd, newname, &newnd, 0);
if (IS_ERR(to)) {
error = PTR_ERR(to);
goto exit1;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 30/49] vfs: make rmdir retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (28 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 29/49] vfs: add a reval argument to user_path_parent Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 31/49] vfs: make do_unlinkat " Jeff Layton
` (18 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 81 ++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 44 insertions(+), 37 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index b73315d..0d0b1c0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3347,49 +3347,56 @@ static long do_rmdir(int dfd, const char __user *pathname)
struct getname_info *name;
struct dentry *dentry;
struct nameidata nd;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_PARENT;
- name = user_path_parent(dfd, pathname, &nd, 0);
- if (IS_ERR(name))
- return PTR_ERR(name);
-
- switch(nd.last_type) {
- case LAST_DOTDOT:
- error = -ENOTEMPTY;
- goto exit1;
- case LAST_DOT:
- error = -EINVAL;
- goto exit1;
- case LAST_ROOT:
- error = -EBUSY;
- goto exit1;
- }
+ do {
+ name = user_path_parent(dfd, pathname, &nd, try);
+ if (IS_ERR(name))
+ return PTR_ERR(name);
+
+ switch (nd.last_type) {
+ case LAST_DOTDOT:
+ error = -ENOTEMPTY;
+ goto exit1;
+ case LAST_DOT:
+ error = -EINVAL;
+ goto exit1;
+ case LAST_ROOT:
+ error = -EBUSY;
+ goto exit1;
+ }
- nd.flags &= ~LOOKUP_PARENT;
- error = mnt_want_write(nd.path.mnt);
- if (error)
- goto exit1;
+ nd.flags &= ~LOOKUP_PARENT;
+ error = mnt_want_write(nd.path.mnt);
+ if (error)
+ goto exit1;
- mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
- dentry = lookup_hash(&nd);
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto exit2;
- if (!dentry->d_inode) {
- error = -ENOENT;
- goto exit3;
- }
- error = security_path_rmdir(&nd.path, dentry);
- if (error)
- goto exit3;
- error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+ mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex,
+ I_MUTEX_PARENT);
+ dentry = lookup_hash(&nd);
+ if (IS_ERR(dentry)) {
+ error = PTR_ERR(dentry);
+ goto exit2;
+ }
+ if (!dentry->d_inode) {
+ error = -ENOENT;
+ goto exit3;
+ }
+ error = security_path_rmdir(&nd.path, dentry);
+ if (error)
+ goto exit3;
+ error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
exit3:
- dput(dentry);
+ dput(dentry);
exit2:
- mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
- mnt_drop_write(nd.path.mnt);
+ mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+ mnt_drop_write(nd.path.mnt);
exit1:
- path_put(&nd.path);
- putname(name);
+ path_put(&nd.path);
+ lookup_flags |= LOOKUP_REVAL;
+ putname(name);
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 31/49] vfs: make do_unlinkat retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (29 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 30/49] vfs: make rmdir retry on ESTALE errors Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 32/49] vfs: fix renameat to " Jeff Layton
` (17 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/fs/namei.c b/fs/namei.c
index 0d0b1c0..f311ed1 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3450,8 +3450,11 @@ static long do_unlinkat(int dfd, const char __user *pathname)
struct dentry *dentry;
struct nameidata nd;
struct inode *inode = NULL;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_PARENT;
- name = user_path_parent(dfd, pathname, &nd, 0);
+retry:
+ name = user_path_parent(dfd, pathname, &nd, try);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -3489,6 +3492,10 @@ exit2:
exit1:
path_put(&nd.path);
putname(name);
+ if (retry_estale(error, try++)) {
+ lookup_flags |= LOOKUP_REVAL;
+ goto retry;
+ }
return error;
slashes:
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 32/49] vfs: fix renameat to retry on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (30 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 31/49] vfs: make do_unlinkat " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 33/49] vfs: have do_sys_truncate retry once on an ESTALE error Jeff Layton
` (16 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
...as always, rename is the messiest of the bunch. We have to track
whether to retry or not via a separate flag since the error handling
is already quite complex.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index f311ed1..dfdcd47 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3851,15 +3851,18 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
struct nameidata oldnd, newnd;
struct getname_info *from;
struct getname_info *to;
+ unsigned int try = 0;
+ bool should_retry = false;
int error;
- from = user_path_parent(olddfd, oldname, &oldnd, 0);
+retry:
+ from = user_path_parent(olddfd, oldname, &oldnd, try);
if (IS_ERR(from)) {
error = PTR_ERR(from);
goto exit;
}
- to = user_path_parent(newdfd, newname, &newnd, 0);
+ to = user_path_parent(newdfd, newname, &newnd, try);
if (IS_ERR(to)) {
error = PTR_ERR(to);
goto exit1;
@@ -3931,11 +3934,17 @@ exit3:
unlock_rename(new_dir, old_dir);
mnt_drop_write(oldnd.path.mnt);
exit2:
+ if (retry_estale(error, try++))
+ should_retry = true;
path_put(&newnd.path);
putname(to);
exit1:
path_put(&oldnd.path);
putname(from);
+ if (should_retry) {
+ should_retry = false;
+ goto retry;
+ }
exit:
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 33/49] vfs: have do_sys_truncate retry once on an ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (31 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 32/49] vfs: fix renameat to " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 34/49] vfs: have faccessat " Jeff Layton
` (15 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/open.c | 86 +++++++++++++++++++++++++++++++++------------------------------
1 file changed, 45 insertions(+), 41 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index d0f225e..5dcee00 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -66,62 +66,66 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
struct path path;
struct inode *inode;
int error;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
+ unsigned int try = 0;
- error = -EINVAL;
if (length < 0) /* sorry, but loff_t says... */
- goto out;
+ return -EINVAL;
- error = user_path(pathname, &path);
- if (error)
- goto out;
- inode = path.dentry->d_inode;
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ inode = path.dentry->d_inode;
- /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
- error = -EISDIR;
- if (S_ISDIR(inode->i_mode))
- goto dput_and_out;
+ /* For dirs, -EISDIR. For other non-regulars, -EINVAL */
+ error = -EISDIR;
+ if (S_ISDIR(inode->i_mode))
+ goto dput_and_out;
- error = -EINVAL;
- if (!S_ISREG(inode->i_mode))
- goto dput_and_out;
+ error = -EINVAL;
+ if (!S_ISREG(inode->i_mode))
+ goto dput_and_out;
- error = mnt_want_write(path.mnt);
- if (error)
- goto dput_and_out;
+ error = mnt_want_write(path.mnt);
+ if (error)
+ goto dput_and_out;
- error = inode_permission(inode, MAY_WRITE);
- if (error)
- goto mnt_drop_write_and_out;
+ error = inode_permission(inode, MAY_WRITE);
+ if (error)
+ goto mnt_drop_write_and_out;
- error = -EPERM;
- if (IS_APPEND(inode))
- goto mnt_drop_write_and_out;
+ error = -EPERM;
+ if (IS_APPEND(inode))
+ goto mnt_drop_write_and_out;
- error = get_write_access(inode);
- if (error)
- goto mnt_drop_write_and_out;
+ error = get_write_access(inode);
+ if (error)
+ goto mnt_drop_write_and_out;
- /*
- * Make sure that there are no leases. get_write_access() protects
- * against the truncate racing with a lease-granting setlease().
- */
- error = break_lease(inode, O_WRONLY);
- if (error)
- goto put_write_and_out;
+ /*
+ * Make sure that there are no leases. get_write_access()
+ * protects against the truncate racing with a lease-granting
+ * setlease().
+ */
+ error = break_lease(inode, O_WRONLY);
+ if (error)
+ goto put_write_and_out;
- error = locks_verify_truncate(inode, NULL, length);
- if (!error)
- error = security_path_truncate(&path);
- if (!error)
- error = do_truncate(path.dentry, length, 0, NULL);
+ error = locks_verify_truncate(inode, NULL, length);
+ if (!error)
+ error = security_path_truncate(&path);
+ if (!error)
+ error = do_truncate(path.dentry, length, 0, NULL);
put_write_and_out:
- put_write_access(inode);
+ put_write_access(inode);
mnt_drop_write_and_out:
- mnt_drop_write(path.mnt);
+ mnt_drop_write(path.mnt);
dput_and_out:
- path_put(&path);
-out:
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 34/49] vfs: have faccessat retry once on an ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (32 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 33/49] vfs: have do_sys_truncate retry once on an ESTALE error Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 35/49] vfs: have chdir retry lookup and call once on " Jeff Layton
` (14 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/open.c | 64 +++++++++++++++++++++++++++++++++------------------------------
1 file changed, 34 insertions(+), 30 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 5dcee00..a5a5c9a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -312,6 +312,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
struct path path;
struct inode *inode;
int res;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
+ unsigned int try = 0;
if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
return -EINVAL;
@@ -335,42 +337,44 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
old_cred = override_creds(override_cred);
- res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
- if (res)
- goto out;
+ do {
+ res = user_path_at(dfd, filename, lookup_flags, &path);
+ if (res)
+ break;
- inode = path.dentry->d_inode;
+ inode = path.dentry->d_inode;
+
+ if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+ /*
+ * MAY_EXEC on regular files is denied if the fs is
+ * mounted with the "noexec" flag.
+ */
+ res = -EACCES;
+ if (path.mnt->mnt_flags & MNT_NOEXEC)
+ goto out_path_release;
+ }
- if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+ res = inode_permission(inode, mode | MAY_ACCESS);
+ /* SuS v2 requires we report a read only fs too */
+ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
+ goto out_path_release;
/*
- * MAY_EXEC on regular files is denied if the fs is mounted
- * with the "noexec" flag.
+ * This is a rare case where using __mnt_is_readonly()
+ * is OK without a mnt_want/drop_write() pair. Since
+ * no actual write to the fs is performed here, we do
+ * not need to telegraph to that to anyone.
+ *
+ * By doing this, we accept that this access is
+ * inherently racy and know that the fs may change
+ * state before we even see this result.
*/
- res = -EACCES;
- if (path.mnt->mnt_flags & MNT_NOEXEC)
- goto out_path_release;
- }
-
- res = inode_permission(inode, mode | MAY_ACCESS);
- /* SuS v2 requires we report a read only fs too */
- if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
- goto out_path_release;
- /*
- * This is a rare case where using __mnt_is_readonly()
- * is OK without a mnt_want/drop_write() pair. Since
- * no actual write to the fs is performed here, we do
- * not need to telegraph to that to anyone.
- *
- * By doing this, we accept that this access is
- * inherently racy and know that the fs may change
- * state before we even see this result.
- */
- if (__mnt_is_readonly(path.mnt))
- res = -EROFS;
+ if (__mnt_is_readonly(path.mnt))
+ res = -EROFS;
out_path_release:
- path_put(&path);
-out:
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(res, try++));
revert_creds(old_cred);
put_cred(override_cred);
return res;
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 35/49] vfs: have chdir retry lookup and call once on ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (33 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 34/49] vfs: have faccessat " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 36/49] vfs: make chroot retry " Jeff Layton
` (13 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/open.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index a5a5c9a..81ba325 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -389,20 +389,21 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename)
{
struct path path;
int error;
+ int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+ unsigned int try = 0;
- error = user_path_dir(filename, &path);
- if (error)
- goto out;
-
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
- if (error)
- goto dput_and_out;
-
- set_fs_pwd(current->fs, &path);
+ do {
+ error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
+ if (error)
+ break;
-dput_and_out:
- path_put(&path);
-out:
+ error = inode_permission(path.dentry->d_inode,
+ MAY_EXEC | MAY_CHDIR);
+ if (!error)
+ set_fs_pwd(current->fs, &path);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 36/49] vfs: make chroot retry once on ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (34 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 35/49] vfs: have chdir retry lookup and call once on " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 37/49] vfs: make fchmodat retry once on ESTALE errors Jeff Layton
` (12 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/open.c | 37 +++++++++++++++++++++----------------
1 file changed, 21 insertions(+), 16 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 81ba325..a015cb8 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -437,27 +437,32 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
{
struct path path;
int error;
+ int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
+ unsigned int try = 0;
- error = user_path_dir(filename, &path);
- if (error)
- goto out;
+ do {
+ error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
+ if (error)
+ break;
- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
- if (error)
- goto dput_and_out;
+ error = inode_permission(path.dentry->d_inode,
+ MAY_EXEC | MAY_CHDIR);
+ if (error)
+ goto dput_and_out;
- error = -EPERM;
- if (!capable(CAP_SYS_CHROOT))
- goto dput_and_out;
- error = security_path_chroot(&path);
- if (error)
- goto dput_and_out;
+ error = -EPERM;
+ if (!capable(CAP_SYS_CHROOT))
+ goto dput_and_out;
+ error = security_path_chroot(&path);
+ if (error)
+ goto dput_and_out;
- set_fs_root(current->fs, &path);
- error = 0;
+ set_fs_root(current->fs, &path);
+ error = 0;
dput_and_out:
- path_put(&path);
-out:
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 37/49] vfs: make fchmodat retry once on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (35 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 36/49] vfs: make chroot retry " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 38/49] vfs: make fchownat " Jeff Layton
` (11 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/open.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index a015cb8..232cbfb 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -506,12 +506,17 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode
{
struct path path;
int error;
+ unsigned int try = 0;
+ int lookup_flags = LOOKUP_FOLLOW;
- error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path);
- if (!error) {
+ do {
+ error = user_path_at(dfd, filename, lookup_flags, &path);
+ if (error)
+ break;
error = chmod_common(&path, mode);
path_put(&path);
- }
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 38/49] vfs: make fchownat retry once on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (36 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 37/49] vfs: make fchmodat retry once on ESTALE errors Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 39/49] vfs: convert do_filp_open to use retry_estale helper Jeff Layton
` (10 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/open.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/fs/open.c b/fs/open.c
index 232cbfb..1bdfd9a 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -567,24 +567,29 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
struct path path;
int error = -EINVAL;
int lookup_flags;
+ unsigned int try = 0;
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
- goto out;
+ return error;
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
- error = user_path_at(dfd, filename, lookup_flags, &path);
- if (error)
- goto out;
- error = mnt_want_write(path.mnt);
- if (error)
- goto out_release;
- error = chown_common(&path, user, group);
- mnt_drop_write(path.mnt);
-out_release:
- path_put(&path);
-out:
+
+ do {
+ error = user_path_at(dfd, filename, lookup_flags, &path);
+ if (error)
+ break;
+
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = chown_common(&path, user, group);
+ mnt_drop_write(path.mnt);
+ }
+
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 39/49] vfs: convert do_filp_open to use retry_estale helper
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (37 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 38/49] vfs: make fchownat " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 40/49] vfs: convert do_file_open_root " Jeff Layton
` (9 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/namei.c b/fs/namei.c
index dfdcd47..8e39510 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3015,11 +3015,12 @@ struct file *do_filp_open(int dfd, struct getname_info *ginfo,
{
struct nameidata nd;
struct file *filp;
+ unsigned int try = 0;
filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_RCU);
if (unlikely(filp == ERR_PTR(-ECHILD)))
filp = path_openat(dfd, ginfo, &nd, op, flags);
- if (unlikely(filp == ERR_PTR(-ESTALE)))
+ while (retry_estale(PTR_ERR(filp), try++))
filp = path_openat(dfd, ginfo, &nd, op, flags | LOOKUP_REVAL);
return filp;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 40/49] vfs: convert do_file_open_root to use retry_estale helper
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (38 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 39/49] vfs: convert do_filp_open to use retry_estale helper Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 41/49] vfs: allow utimensat() calls to retry once on an ESTALE error Jeff Layton
` (8 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/namei.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/namei.c b/fs/namei.c
index 8e39510..9a7736f 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3031,6 +3031,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
struct nameidata nd;
struct file *file;
struct getname_info ginfo = { .name = name };
+ unsigned int try = 0;
nd.root.mnt = mnt;
nd.root.dentry = dentry;
@@ -3043,7 +3044,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_RCU);
if (unlikely(file == ERR_PTR(-ECHILD)))
file = path_openat(-1, &ginfo, &nd, op, flags);
- if (unlikely(file == ERR_PTR(-ESTALE)))
+ while (retry_estale(PTR_ERR(file), try++))
file = path_openat(-1, &ginfo, &nd, op, flags | LOOKUP_REVAL);
return file;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 41/49] vfs: allow utimensat() calls to retry once on an ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (39 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 40/49] vfs: convert do_file_open_root " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 42/49] vfs: allow setxattr to retry once on ESTALE errors Jeff Layton
` (7 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Clearly, we can't handle the NULL filename case, but we can deal with
the case where there's a real pathname.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/utimes.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/fs/utimes.c b/fs/utimes.c
index fa4dbe4..b6b2865 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -156,16 +156,21 @@ long do_utimes(int dfd, const char __user *filename, struct timespec *times,
} else {
struct path path;
int lookup_flags = 0;
+ unsigned int try = 0;
if (!(flags & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
- error = user_path_at(dfd, filename, lookup_flags, &path);
- if (error)
- goto out;
+ do {
+ error = user_path_at(dfd, filename,
+ lookup_flags, &path);
+ if (error)
+ break;
- error = utimes_common(&path, times);
- path_put(&path);
+ error = utimes_common(&path, times);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
}
out:
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 42/49] vfs: allow setxattr to retry once on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (40 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 41/49] vfs: allow utimensat() calls to retry once on an ESTALE error Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 43/49] vfs: allow lsetxattr() " Jeff Layton
` (6 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index 588455b..ba286ba 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -364,16 +364,21 @@ SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
{
struct path path;
int error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
- error = user_path(pathname, &path);
- if (error)
- return error;
- error = mnt_want_write(path.mnt);
- if (!error) {
- error = setxattr(path.dentry, name, value, size, flags);
- mnt_drop_write(path.mnt);
- }
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = setxattr(path.dentry, name, value, size, flags);
+ mnt_drop_write(path.mnt);
+ }
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 43/49] vfs: allow lsetxattr() to retry once on ESTALE errors
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (41 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 42/49] vfs: allow setxattr to retry once on ESTALE errors Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 44/49] vfs: make getxattr retry once on an ESTALE error Jeff Layton
` (5 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index ba286ba..d981635 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -388,16 +388,21 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
{
struct path path;
int error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = 0;
- error = user_lpath(pathname, &path);
- if (error)
- return error;
- error = mnt_want_write(path.mnt);
- if (!error) {
- error = setxattr(path.dentry, name, value, size, flags);
- mnt_drop_write(path.mnt);
- }
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = setxattr(path.dentry, name, value, size, flags);
+ mnt_drop_write(path.mnt);
+ }
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 44/49] vfs: make getxattr retry once on an ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (42 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 43/49] vfs: allow lsetxattr() " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 45/49] vfs: make lgetxattr retry once on ESTALE Jeff Layton
` (4 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index d981635..1775213 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -479,12 +479,17 @@ SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
{
struct path path;
ssize_t error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
- error = user_path(pathname, &path);
- if (error)
- return error;
- error = getxattr(path.dentry, name, value, size);
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = getxattr(path.dentry, name, value, size);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 45/49] vfs: make lgetxattr retry once on ESTALE
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (43 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 44/49] vfs: make getxattr retry once on an ESTALE error Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 46/49] vfs: make listxattr retry once on ESTALE error Jeff Layton
` (3 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index 1775213..fbb93d7 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -498,12 +498,17 @@ SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
{
struct path path;
ssize_t error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = 0;
- error = user_lpath(pathname, &path);
- if (error)
- return error;
- error = getxattr(path.dentry, name, value, size);
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = getxattr(path.dentry, name, value, size);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 46/49] vfs: make listxattr retry once on ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (44 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 45/49] vfs: make lgetxattr retry once on ESTALE Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 47/49] vfs: make llistxattr " Jeff Layton
` (2 subsequent siblings)
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index fbb93d7..6be45cd 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -571,12 +571,17 @@ SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
{
struct path path;
ssize_t error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
- error = user_path(pathname, &path);
- if (error)
- return error;
- error = listxattr(path.dentry, list, size);
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = listxattr(path.dentry, list, size);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 47/49] vfs: make llistxattr retry once on ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (45 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 46/49] vfs: make listxattr retry once on ESTALE error Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 48/49] vfs: make removexattr retry once on ESTALE Jeff Layton
2012-10-02 0:16 ` [PATCH v7 49/49] vfs: make lremovexattr retry once on ESTALE error Jeff Layton
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index 6be45cd..db6c528 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -590,12 +590,17 @@ SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
{
struct path path;
ssize_t error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = 0;
- error = user_lpath(pathname, &path);
- if (error)
- return error;
- error = listxattr(path.dentry, list, size);
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = listxattr(path.dentry, list, size);
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 48/49] vfs: make removexattr retry once on ESTALE
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (46 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 47/49] vfs: make llistxattr " Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
2012-10-02 0:16 ` [PATCH v7 49/49] vfs: make lremovexattr retry once on ESTALE error Jeff Layton
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index db6c528..d29d5a4 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -642,16 +642,21 @@ SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
{
struct path path;
int error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = LOOKUP_FOLLOW;
- error = user_path(pathname, &path);
- if (error)
- return error;
- error = mnt_want_write(path.mnt);
- if (!error) {
- error = removexattr(path.dentry, name);
- mnt_drop_write(path.mnt);
- }
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = removexattr(path.dentry, name);
+ mnt_drop_write(path.mnt);
+ }
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread
* [PATCH v7 49/49] vfs: make lremovexattr retry once on ESTALE error
2012-10-02 0:16 [PATCH v7 00/49] audit/getname/estale patch series Jeff Layton
` (47 preceding siblings ...)
2012-10-02 0:16 ` [PATCH v7 48/49] vfs: make removexattr retry once on ESTALE Jeff Layton
@ 2012-10-02 0:16 ` Jeff Layton
48 siblings, 0 replies; 56+ messages in thread
From: Jeff Layton @ 2012-10-02 0:16 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, linux-audit, linux-kernel
Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
fs/xattr.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c
index d29d5a4..1781875 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -665,16 +665,21 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
{
struct path path;
int error;
+ unsigned int try = 0;
+ unsigned int lookup_flags = 0;
- error = user_lpath(pathname, &path);
- if (error)
- return error;
- error = mnt_want_write(path.mnt);
- if (!error) {
- error = removexattr(path.dentry, name);
- mnt_drop_write(path.mnt);
- }
- path_put(&path);
+ do {
+ error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
+ if (error)
+ break;
+ error = mnt_want_write(path.mnt);
+ if (!error) {
+ error = removexattr(path.dentry, name);
+ mnt_drop_write(path.mnt);
+ }
+ path_put(&path);
+ lookup_flags |= LOOKUP_REVAL;
+ } while (retry_estale(error, try++));
return error;
}
--
1.7.11.4
^ permalink raw reply related [flat|nested] 56+ messages in thread