On Mon, Apr 3, 2023 at 6:28 PM Daniel Rosenberg <drosen@xxxxxxxxxx> wrote: > > For Fuse-BPF, I need to access strings and blocks of data in a bpf > context. In the initial patch set for Fuse-BPF [1] I was using > PTR_TO_PACKETs as a stand in for buffers of unknown size. That used > start and end pointers to give the verifier the ability to statically > check bounds. I'm currently attempting to switch this over to using > dynptrs for buffers of variable length, but have run into some issues. > > So far as I can tell, while a dynptr can have a variable size, any > time you interact with a dynptr, you need to already know how large it > is. For instance, bpf_dynptr_read reads the dynptr into a local > buffer. However, that buffer may not be larger than the dynptr you're > reading. That seems pretty counter intuitive to me. > bpf_dynptr_check_off_len ensures that the length passed in is not > longer than the dynptr. This means I can't, for example, have a buffer > that could support NAME_MAX characters, and read a dynptr into it. I > assume this is to ensure that the entirety of the buffer is > initialized. If that's the case, I could create a variant that zeroes > out the remaining buffer area. you are right, we should probably fix this logic to allow to fill up min(<dynptr size>, <fixed buf size>) bytes of provided fixed-sized buffers. Zero-filling at the end is an option, but I'm not sure we have to do it (e.g., bpf_probe_read_str() variants don't zero fill, I think). > > One workaround I've considered is attempting to read to the minimum > length of string I'm comparing against, treating read failures as a > nonmatching string. Then I could read any additional space for larger > comparisons afterwards. This would mean one call to dynptr_read for > every string length I'm checking against. > > The bpf_dynptr_slice(_rdrw) functions looks nearly like what I want, > but require a buffer that will be unused for local dynptrs. > bpf_dynptr_data rejects readonly dynptrs, so is not a suitable > replacement. It seems like I could really use either a > bpf_dynptr_data_rdonly helper, or a similar kfunc, though I suspect > the kfunc will require some additions to the special_kfunc_set. bpf_dynptr_slice(_rdwr) is basically the same as bpf_dynptr_data() and bpf_dynptr_read() as far as fixed length of read/accessible memory goes, so I don't think it gives you anything new, tbh. > > One alternative I'm looking into is providing kfuncs that perform the > requested operations. That allows checks to happen at runtime. > However, I'm having some difficulties working with strings as kfunc > arguments. There is an existing helper function bpf_strncmp, which > uses one constant argument which ends up interpreted as a > PTR_TO_MAP_VALUE. To make a kfunc, I assume I'd need to add another > special kfunc and then adjust the expected types. I think we need something like bpf_dynptr_strncmp(), which would take two dynptrs, one for each string you'd like to compare. But in general, when you say "I need to access strings and blocks of data " above, what exact operations do you need to do on them? strncmp is one of them, anything else? Note, Joanne is working on another dynptr-related patch set that adds bpf_dynptr_clone()+bpf_dynptr_trim()+bpf_dynptr_advance(), which allows to create temporary smaller views into other dynptrs, which will make dynptr a universal "memory view" mechanism. So designing APIs with assumption that dynptr is describing a smaller portion of a bigger variable-sized memory is on the table with that. > > Any of these solutions that use fixed sizes ignore cases where I may > need to compare two strings, neither of which is a constant string > known at compile time. > How should I go about using possibly read-only dynptrs whose lengths > are only known at runtime? > > [1] https://lore.kernel.org/bpf/20220926231822.994383-1-drosen@xxxxxxxxxx/ > > > -Daniel