From: Paul Moore <pmoore@redhat.com>
To: Boqun Feng <boqun.feng@gmail.com>
Cc: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
Al Viro <viro@zeniv.linux.org.uk>
Subject: Re: [PATCH] vfs: avoid recopying filename in getname_flags
Date: Fri, 13 Mar 2015 09:45:59 -0400 [thread overview]
Message-ID: <4092983.fczPVZEiUl@sifl> (raw)
In-Reply-To: <CAL0jBu-9wF665YX22em6qiittScfXM_eQVteMGqk6kZs234geA@mail.gmail.com>
On Monday, March 09, 2015 04:24:32 PM Boqun Feng wrote:
> Ping.
> Any opinion?
You might want to look at some of the recent changes to Al's vfs.git#for-next
branch; at the very least it looks like your patch should be rebased against
those changes.
> On Wed, Feb 25, 2015 at 8:31 PM, Boqun Feng <boqun.feng@gmail.com> wrote:
> > In the current implementation of getname_flags, filename in the
> > user-space will be recopied if it takes more space that
> > EMBEDDED_NAME_MAX, however, at this moment, EMBEDDED_NAME_MAX bytes of
> > the filename are already copied into kernel space, the only reason why
> > the recopy is needed is that "kname" needs to be relocated.
> >
> > And the recopy can be avoided if we change the memory layout of the
> > "names_cache" allocation. By putting the struct "filename" at the tail
> > of the allocation instead of the head, relocation of kname is avoided.
> >
> > Once putting the struct at the tail, each byte in the user space will be
> > copied only one time, so the recopy is avoided and code is more clear.
> >
> > Of course, other functions aware of the layout of the names_cache
> > allocation, i.e., getname_kernel and putname also need to be modified to
> > adapt to the new layout.
> >
> > This patch is based on v4.0-rc1.
> >
> > Cc: Al Viro <viro@zeniv.linux.org.uk>
> > Cc: Paul Moore <pmoore@redhat.com>
> > Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
> > ---
> >
> > fs/namei.c | 50 +++++++++++++++++++++++++++++++-------------------
> > 1 file changed, 31 insertions(+), 19 deletions(-)
> >
> > diff --git a/fs/namei.c b/fs/namei.c
> > index c83145a..3be372b 100644
> > --- a/fs/namei.c
> > +++ b/fs/namei.c
> > @@ -133,21 +133,20 @@ getname_flags(const char __user *filename, int
> > flags, int *empty)>
> > if (result)
> >
> > return result;
> >
> > - result = __getname();
> > - if (unlikely(!result))
> > + kname = __getname();
> > + if (unlikely(!kname))
> >
> > return ERR_PTR(-ENOMEM);
> >
> > - result->refcnt = 1;
> >
> > /*
> >
> > * First, try to embed the struct filename inside the names_cache
> > * allocation
> > */
> >
> > - kname = (char *)result + sizeof(*result);
> > + result = (struct filename *)(kname + EMBEDDED_NAME_MAX);
> >
> > result->name = kname;
> > result->separate = false;
> >
> > + result->refcnt = 1;
> >
> > max = EMBEDDED_NAME_MAX;
> >
> > -recopy:
> > len = strncpy_from_user(kname, filename, max);
> > if (unlikely(len < 0)) {
> >
> > err = ERR_PTR(len);
> >
> > @@ -157,23 +156,34 @@ recopy:
> > /*
> >
> > * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
> > * separate struct filename so we can dedicate the entire
> >
> > - * names_cache allocation for the pathname, and re-do the copy
> > from
> > + * names_cache allocation for the pathname, and continue the copy
> > from>
> > * userland.
> > */
> >
> > - if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) {
> > - kname = (char *)result;
> > -
> > + if (len == EMBEDDED_NAME_MAX) {
> >
> > result = kzalloc(sizeof(*result), GFP_KERNEL);
> > if (!result) {
> >
> > err = ERR_PTR(-ENOMEM);
> >
> > - result = (struct filename *)kname;
> > + result = (struct filename *)(kname +
> > EMBEDDED_NAME_MAX);>
> > goto error;
> >
> > }
> > result->name = kname;
> > result->separate = true;
> > result->refcnt = 1;
> >
> > - max = PATH_MAX;
> > - goto recopy;
> > + max = PATH_MAX - EMBEDDED_NAME_MAX;
> > + /* we can't simply add the number of rest chars we copy to
> > len, + * since strncpy_from_user may return negative to
> > indicate + * something is wrong, so we do the addition
> > later, after + * strncpy_from_user succeeds, and we know
> > we already copy + * EMBEDDED_NAME_MAX chars.
> > + */
> > + len = strncpy_from_user(kname + EMBEDDED_NAME_MAX,
> > + filename + EMBEDDED_NAME_MAX, max);
> > +
> > + if (unlikely(len < 0)) {
> > + err = ERR_PTR(len);
> > + goto error;
> > + }
> > + len += EMBEDDED_NAME_MAX;
> >
> > }
> >
> > /* The empty path is special. */
> >
> > @@ -209,28 +219,30 @@ struct filename *
> >
> > getname_kernel(const char * filename)
> > {
> >
> > struct filename *result;
> >
> > + char *kname;
> >
> > int len = strlen(filename) + 1;
> >
> > - result = __getname();
> > - if (unlikely(!result))
> > + kname = __getname();
> > + if (unlikely(!kname))
> >
> > return ERR_PTR(-ENOMEM);
> >
> > if (len <= EMBEDDED_NAME_MAX) {
> >
> > - result->name = (char *)(result) + sizeof(*result);
> > + result = (struct filename *)(kname + EMBEDDED_NAME_MAX);
> > + result->name = kname;
> >
> > result->separate = false;
> >
> > } else if (len <= PATH_MAX) {
> >
> > struct filename *tmp;
> >
> > tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
> > if (unlikely(!tmp)) {
> >
> > - __putname(result);
> > + __putname(kname);
> >
> > return ERR_PTR(-ENOMEM);
> >
> > }
> >
> > - tmp->name = (char *)result;
> > + tmp->name = kname;
> >
> > tmp->separate = true;
> > result = tmp;
> >
> > } else {
> >
> > - __putname(result);
> > + __putname(kname);
> >
> > return ERR_PTR(-ENAMETOOLONG);
> >
> > }
> > memcpy((char *)result->name, filename, len);
> >
> > @@ -253,7 +265,7 @@ void putname(struct filename *name)
> >
> > __putname(name->name);
> > kfree(name);
> >
> > } else
> >
> > - __putname(name);
> > + __putname(name->name);
> >
> > }
> >
> > static int check_acl(struct inode *inode, int mask)
> >
> > --
> > 2.3.0
--
paul moore
security @ redhat
next prev parent reply other threads:[~2015-03-13 13:46 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-02-25 12:31 [PATCH] vfs: avoid recopying filename in getname_flags Boqun Feng
2015-03-09 8:24 ` Boqun Feng
2015-03-13 13:45 ` Paul Moore [this message]
2015-03-18 5:27 ` Boqun Feng
2015-03-21 4:22 ` Boqun Feng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4092983.fczPVZEiUl@sifl \
--to=pmoore@redhat.com \
--cc=boqun.feng@gmail.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.