-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dealing with long path names #900
Comments
You wrote a bpf_strlen()? Would like to see diffs. :) |
Here is a diff against kernel 4.9.2:
Here is a corresponding diff for bcc (my tree is synced to
|
On Wed, Jan 11, 2017 at 4:23 PM, Konstantin Bukin ***@***.***> wrote:
Here is a diff against kernel 4.9.2:
build-test1:linux-4.9.2$git diff
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index c201017..64516be 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -327,6 +327,7 @@ extern const struct bpf_func_proto bpf_get_current_comm_proto;
extern const struct bpf_func_proto bpf_skb_vlan_push_proto;
extern const struct bpf_func_proto bpf_skb_vlan_pop_proto;
extern const struct bpf_func_proto bpf_get_stackid_proto;
+extern const struct bpf_func_proto bpf_strnlen_proto;
/* Shared helpers among cBPF and eBPF. */
void bpf_user_rnd_init_once(void);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index f09c70b..38c6400 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -426,6 +426,16 @@ enum bpf_func_id {
*/
BPF_FUNC_set_hash_invalid,
+ /**
+ * bpf_strnlen(str, size)
+ * Get the size of a user string INCLUDING final NUL
+ * @str: The string to measure.
+ * @count: Maximum count (including NUL character)
+ *
+ * see comments for strnlen_user(const char __user *str, long count)
+ */
+ BPF_FUNC_strnlen,
+
__BPF_FUNC_MAX_ID,
};
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index aa6d981..ab04742 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1048,6 +1048,7 @@ const struct bpf_func_proto bpf_ktime_get_ns_proto __weak;
const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak;
const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak;
const struct bpf_func_proto bpf_get_current_comm_proto __weak;
+const struct bpf_func_proto bpf_strnlen __weak;
const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void)
{
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 3991840..ec64244 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -120,6 +120,17 @@ const struct bpf_func_proto bpf_get_current_pid_tgid_proto = {
.ret_type = RET_INTEGER,
};
+BPF_CALL_2(bpf_strnlen, const char __user *, buf, u32, size)
+{
+ return strnlen_user(buf, size);
+}
unfortunately it's not so straightforward, since
strnlen_user() can only be called on user pointer in user context.
access_ok() macro just recently got
WARN_ON_IN_IRQ() warning to prevent such misuse.
btw, verifier just recently got support for variable length
bpf_probe_read(buf, len, unsafe_ptr)
where 'buf' can be a pointer inside map's value
and 'len' can be capped variable.
I think we need to solve it more generically than
adding strlen/strcpy helpers.
…
+
+const struct bpf_func_proto bpf_strnlen_proto = {
+ .func = bpf_strnlen,
+ .gpl_only = false,
+ .ret_type = RET_INTEGER,
+};
+
|
Right (that is the reason for "see comments for strnlen_user"). These are the only strings I am interested in. Do you know if that could be jit-enforced? A new function could be renamed into something like bpf_strnlen_user() until a more general solution is available. |
On Wed, Jan 11, 2017 at 5:07 PM, Konstantin Bukin ***@***.***> wrote:
strnlen_user() can only be called on user pointer in user context.
Right (that is the reason for "see comments for strnlen_user"). These are
the only strings I am interested in. Do you know if that could be
jit-enforced? A new function could be renamed into something like
bpf_strnlen_user() until a more general solution is available.
we can do something like bpf_probe_write_user() but it would restrict
it too much. It's hard to justify adding a helper for single use case.
|
I am also very interested in a similar use case, I'll provide a couple more points on this. As @4ast knows, I worked on a strncpy helper that can operate on unsafe memory: gianlucaborello/linux@8239c92 Overall, I also like a strnlen approach (which you can then combine with bpf_probe_read), but done with code borrowed from trace_kprobe.c:
I haven't tried this, but it should work (I apologize if it doesn't and I just assumed) and it's safe from an atomic context (unlike strnlen_user()) and also works against any type of memory (which is a huge plus, in my use case I frequently deal with strings from user as well as dereferencing kernel strings). Also, if you want to work on data bigger than 512 bytes don't use the stack, the verifier error you're getting is legit, but as @4ast says you can now use a map element value (which is what I'm doing in my project). Please find more details here: https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=5722569bb9c3bd922c4f10b5b2912fe88c255312 |
@kbukin1 the previously mentioned strncpy helper landed in net-next today: https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/?id=a5e8c07059d0f0b31737408711d44794928ac218. That, combined with the recent changes of allowing variable memory accesses (https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/kernel/bpf/verifier.c?id=06c1c049721a995dee2829ad13b24aaf5d7c5cce, so that you can use the string length discovered at runtime as buffer size in other helpers) and the ability to use maps directly as buffer pointers with helpers (https://git.kernel.org/cgit/linux/kernel/git/davem/net-next.git/commit/kernel/bpf/verifier.c?id=5722569bb9c3bd922c4f10b5b2912fe88c255312, so that you can bypass the limited stack size) should cover your use case quite well I suppose. I am writing a large BPF program and am able to get a lot of stuff done with these new additions. |
I need to ensure my tracer captures full paths passed by users into some system calls. Paths can be pretty long, up-to PATH_MAX chars. In cases when path is longer than some (~255-400 chars) value I would like putting several data structures carrying different parts of the long paths into BPF_PERF_OUTPUT buffer. So I need to find a length of a null-terminated string in a bpf program. The problem is maximum string I can iterate (using “if … goto” trick) is ~500 chars. An attempt to have a longer unrolled loop results in errors like:
bpf: Invalid argument. Program too large (4739 insns), at most 4096 insns
If I try to read 4095 bytes with bpf_probe_read() into a buffer allocated on the stack of bpf function (so all 4095 bytes could be passed to the user afterwards) then I get an error:
…
73: (b7) r2 = 2048
74: (85) call 4
invalid stack type R1 off=-2352 access_size=2048
Do you have any suggestions on how to find length of a long string (up-to PATH_MAX chars) in bpf program or how to pass long paths into user space? String lives in user space. A pointer to the string is passed as an argument into a system call. BPF program which needs string length is attached to the corresponding system call.
I added bpf_strnlen function to the kernel and bcc toolkit (which calls strnlen_user(buf,size)) and that is working as expected, but it would be great to be able to do that on an unmodified kernel. Any chance bpf/bcc will be getting something like bpf_strnlen() anytime soon? bpf_strnlen seems to be straightforward, but if you are interested I could make a pull request.
The text was updated successfully, but these errors were encountered: