From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>,
Andrew Morton <akpm@linux-foundation.org>,
Peter Zijlstra <peterz@infradead.org>,
Frederic Weisbecker <fweisbec@gmail.com>,
"H. Peter Anvin" <hpa@zytor.com>,
Steven Rostedt <srostedt@redhat.com>
Subject: [PATCH v2 2/5] uaccess: add copy_strtok_from_user
Date: Thu, 26 Feb 2009 00:32:42 -0500 [thread overview]
Message-ID: <20090226053832.039095057@goodmis.org> (raw)
In-Reply-To: 20090226053240.607719846@goodmis.org
[-- Attachment #1: 0002-uaccess-add-copy_strtok_from_user.patch --]
[-- Type: text/plain, Size: 7012 bytes --]
From: Steven Rostedt <srostedt@redhat.com>
The ftrace utility reads delimited tokens from user space.
Andrew Morton did not like how ftrace open coded this. He had
a good point since more than one location performed this feature.
This patch creates a copy_strtok_from_user function that can copy
a delimited token from user space. This puts the code in the
lib/uaccess.c file. This keeps the code in a single location
and may be optimized in the future.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
---
include/linux/uaccess.h | 5 ++
lib/uaccess.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 180 insertions(+), 1 deletions(-)
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 6b58367..08769ad 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -106,4 +106,9 @@ extern long probe_kernel_read(void *dst, void *src, size_t size);
*/
extern long probe_kernel_write(void *dst, void *src, size_t size);
+extern int copy_strtok_from_user(void *to, const void __user *from,
+ unsigned int copy, unsigned int read,
+ unsigned int *copied, int skip,
+ const char *delim);
+
#endif /* __LINUX_UACCESS_H__ */
diff --git a/lib/uaccess.c b/lib/uaccess.c
index ac40796..0c12360 100644
--- a/lib/uaccess.c
+++ b/lib/uaccess.c
@@ -1,8 +1,19 @@
/*
- * Access kernel memory without faulting.
+ * lib/uaccess.c
+ * Generic memory access without faulting.
+ *
+ * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *
+ * Added copy_strtok_from_user -
+ * Copyright (C) 2009 Red Hat, Inc., Steven Rostedt <srostedt@redhat.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ *
*/
#include <linux/uaccess.h>
#include <linux/module.h>
+#include <linux/ctype.h>
#include <linux/mm.h>
/**
@@ -53,3 +64,166 @@ long probe_kernel_write(void *dst, void *src, size_t size)
return ret ? -EFAULT : 0;
}
EXPORT_SYMBOL_GPL(probe_kernel_write);
+
+/**
+ * copy_strtok_from_user - copy a delimited token from user space
+ * @to: The location to copy to
+ * @from: The location to copy from
+ * @copy: The number of bytes to copy
+ * @read: The number of bytes to read
+ * @copied: The number of bytes actually copied to @to
+ * @skip: If other than zero, will skip leading white space
+ * @delim: NULL terminated string of character delimiters
+ *
+ * This reads from a user buffer, a delimited toke.
+ * If skip is set, then it will trim all leading delimiters.
+ * Then it will copy thet token (non delimiter characters) until
+ * @copy bytes have been copied, @read bytes have been read from
+ * the user buffer, or more delimiters have been encountered.
+ *
+ * Note, if skip is not set, and a dilmiter exists at the beginning
+ * it will return immediately.
+ *
+ * Example of use:
+ *
+ * in user space a write(fd, "foo bar zot", 12) is done. We want to
+ * read three words.
+ *
+ * len = 12; - length of user buffer
+ * ret = copy_strtok_from_user(buf, ubuf, 100, len, @copied, 1, " ");
+ * ret will equal 4 ("foo " read)
+ * buf will contain "foo"
+ * copied will equal 3 ("foo" copied)
+ * Note, @skip could be 1 or zero and the same would have happened
+ * since there was no leading space.
+ *
+ * len -= ret; - 4 bytes was read
+ * read = ret;
+ * ret = copy_strtok_from_user(buf, ubuf+read, 100, len, @copied, 1, " ");
+ * ret will equal 5 (" bar " read, notice the double space between
+ * foo and bar in the original write.)
+ * buf will contain "bar"
+ * copied will equal 3 ("bar" copied)
+ * Note, @skip is 1, if it was zero the results would be different.
+ * (see below)
+ *
+ * len -= ret; - 5 bytes read
+ * read += ret;
+ * ret = copy_strtok_from_user(buf, ubuf+read, 100, len, @copied, 1, " ");
+ * ret = -EAGAIN (no space after "zot")
+ * buf will contain "zot"
+ * copied will equal 3 ("zot" copied)
+ *
+ * If the second copy_strtok_from_user above had 0 for @skip, where we
+ * did not want to skip leading space (" bar zot")
+ * ret will equal 1 (" " read)
+ * buf will not be modified
+ * copied will equal 0 (nothing copied).
+ *
+ * Returns:
+ * The number of bytes read from user space (@from). This may or may not
+ * be the same as what was copied into @to.
+ *
+ * -EAGAIN, if we copied a token successfully, but never hit an
+ * ending delimiter. The number of bytes copied will be the same
+ * as @read. Note, if skip is set, and all we hit were delimiters
+ * then we will also returne -EAGAIN with @copied = 0.
+ *
+ * @copied will contain the number of bytes copied into @to
+ *
+ * -EFAULT, if we faulted during any part of the copy.
+ * @copied will be undefined.
+ *
+ * -EINVAL, if we fill up @from before hitting a single delimiter.
+ * @copy must be bigger than the expected token to read.
+ */
+int copy_strtok_from_user(void *to, const void __user *from,
+ unsigned int copy, unsigned int read,
+ unsigned int *copied, int skip,
+ const char *delim)
+{
+ unsigned int have_read = 0;
+ unsigned int have_copied = 0;
+ const char __user *user = from;
+ char *kern = to;
+ int ret, len;
+ char ch;
+
+ /* get the first character */
+ ret = get_user(ch, user++);
+ if (ret)
+ return ret;
+ have_read++;
+
+ len = strlen(delim);
+
+ /*
+ * If skip is set, and the first character is a delimiter
+ * then we will continue to read until we find a non delimiter.
+ */
+ if (skip) {
+ while (have_read < read && memchr(delim, ch, len)) {
+ ret = get_user(ch, user++);
+ if (ret)
+ return ret;
+ have_read++;
+ }
+
+ /*
+ * If ch is still a delimiter, then have_read == read.
+ * We successfully copied zero bytes. But this is
+ * still valid. Just let the caller try again.
+ */
+ if (memchr(delim, ch, len)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ } else if (memchr(delim, ch, len)) {
+ /*
+ * If skip was not set and the first character was
+ * a delimiter, then we return immediately.
+ */
+ ret = have_read;
+ goto out;
+ }
+
+
+ /* Now read the actual token */
+ while (have_read < read &&
+ have_copied < copy && !memchr(delim, ch, len)) {
+
+ kern[have_copied++] = ch;
+
+ ret = get_user(ch, user++);
+ if (ret)
+ return ret;
+
+ have_read++;
+ }
+
+ /*
+ * If we ended with a delimiter then we have successfully
+ * read in a full token.
+ *
+ * If ch is not a delimiter, and we have filled up @from,
+ * then this was an invalid token.
+ *
+ * If ch is not white space, and we still have room in @from
+ * then we let the caller know we have split a token.
+ * (have_read == read)
+ */
+ if (memchr(delim, ch, len))
+ ret = have_read;
+ else if (have_copied == copy)
+ ret = -EINVAL;
+ else {
+ WARN_ON(have_read != read);
+ ret = -EAGAIN;
+ }
+
+ out:
+ *copied = have_copied;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(copy_strtok_from_user);
--
1.5.6.5
--
next prev parent reply other threads:[~2009-02-26 5:39 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-02-26 5:32 [PATCH v2 0/5] [RFC] copy_strtok_from_user Steven Rostedt
2009-02-26 5:32 ` [PATCH v2 1/5] uaccess: move probe_kernel_* functions to lib/uaccess.c Steven Rostedt
2009-02-26 5:32 ` Steven Rostedt [this message]
2009-02-26 5:32 ` [PATCH v2 3/5] tracing: convert event_trace to use copy_strtok_from_user Steven Rostedt
2009-02-26 5:32 ` [PATCH v2 4/5] tracing: convert ftrace_regex_write " Steven Rostedt
2009-02-26 5:32 ` [PATCH v2 5/5] tracing: convert ftrace_graph_write " Steven Rostedt
2009-02-26 10:03 ` [PATCH v2 0/5] [RFC] copy_strtok_from_user Peter Zijlstra
2009-02-26 12:28 ` Ingo Molnar
2009-02-26 12:30 ` Ingo Molnar
2009-02-26 12:46 ` Steven Rostedt
2009-02-26 12:48 ` Steven Rostedt
2009-02-26 12:51 ` Steven Rostedt
2009-02-26 14:04 ` Steven Rostedt
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=20090226053832.039095057@goodmis.org \
--to=rostedt@goodmis.org \
--cc=akpm@linux-foundation.org \
--cc=fweisbec@gmail.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=peterz@infradead.org \
--cc=srostedt@redhat.com \
/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.