Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Signed-off-by: Xiu Jianfeng <xiujianfeng@huawei.com>
---
include/linux/string.h | 20 ++++++++++++++++++++
lib/memcpy_kunit.c | 12 ++++++++++++
2 files changed, 32 insertions(+)
Replace the open-coded memset with memset_range helper to simplify
the code, there is no functional change in this patch.
Signed-off-by: Xiu Jianfeng <xiujianfeng@huawei.com>
---
kernel/bpf/verifier.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-12-08 04:28:38
On Wed, 8 Dec 2021 11:04:50 +0800 Xiu Jianfeng [off-list ref] wrote:
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Is this likely to have more than a single call site?
+ *+ * @obj: Address of target struct instance+ * @v: Byte value to repeatedly write+ * @member1: struct member to start writing at+ * @member2: struct member where writing should stop
Perhaps "struct member before which writing should stop"?
On Wed, Dec 08, 2021 at 11:04:49AM +0800, Xiu Jianfeng wrote:
Xiu Jianfeng (2):
string.h: Introduce memset_range() for wiping members
For doing a memset range, the preferred method is to use
a struct_group in the structure itself. This makes the range
self-documenting, and allows the compile to validate the exact size,
makes it addressable, etc. The other memset helpers are for "everything
to the end", which doesn't usually benefit from the struct_group style
of range declaration.
bpf: use memset_range helper in __mark_reg_known
I never saw this patch arrive on the list?
--
Kees Cook
On Wed, 8 Dec 2021 11:04:50 +0800 Xiu Jianfeng [off-list ref] wrote:
quoted
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Is this likely to have more than a single call site?
There maybe more call site for this function, but I just use bpf as an example.
I mean zeroing from member1 to member2(including position indicated by member1 and member2)
quoted
+ *+ * @obj: Address of target struct instance+ * @v: Byte value to repeatedly write+ * @member1: struct member to start writing at+ * @member2: struct member where writing should stop
Perhaps "struct member before which writing should stop"?
memset_range should include position indicated by member2 as well
On Wed, Dec 08, 2021 at 11:04:49AM +0800, Xiu Jianfeng wrote:
quoted
Xiu Jianfeng (2):
string.h: Introduce memset_range() for wiping members
For doing a memset range, the preferred method is to use
a struct_group in the structure itself. This makes the range
self-documenting, and allows the compile to validate the exact size,
makes it addressable, etc. The other memset helpers are for "everything
to the end", which doesn't usually benefit from the struct_group style
of range declaration.
Do you mean there is no need to introduce this helper, but to use struct_group in the struct directly?
quoted
bpf: use memset_range helper in __mark_reg_known
I never saw this patch arrive on the list?
I have send this patch as well, can you please check again?
On Wed, Dec 08, 2021 at 11:04:50AM +0800, Xiu Jianfeng wrote:
quoted hunk
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Signed-off-by: Xiu Jianfeng <xiujianfeng@huawei.com>
---
include/linux/string.h | 20 ++++++++++++++++++++
lib/memcpy_kunit.c | 12 ++++++++++++
2 files changed, 32 insertions(+)
"u8*" should be "void*" as kernel legitimises pointer arithmetic on void*
and there is no dereference.
__val is redundant, just toss "v" into memset(), it will do the right
thing. In fact, toss "__ptr" as well, it is simply unnecessary.
All previous memsets are the same...
From: Andrew Morton <akpm@linux-foundation.org> Date: 2021-12-08 23:44:46
On Wed, 8 Dec 2021 18:30:26 +0800 xiujianfeng [off-list ref] wrote:
在 2021/12/8 12:28, Andrew Morton 写道:
quoted
On Wed, 8 Dec 2021 11:04:50 +0800 Xiu Jianfeng [off-list ref] wrote:
quoted
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Is this likely to have more than a single call site?
There maybe more call site for this function, but I just use bpf as an
example.
I mean zeroing from member1 to member2(including position indicated by
member1 and member2)
quoted
quoted
+ *+ * @obj: Address of target struct instance+ * @v: Byte value to repeatedly write+ * @member1: struct member to start writing at+ * @member2: struct member where writing should stop
Perhaps "struct member before which writing should stop"?
memset_range should include position indicated by member2 as well
In that case we could say "struct member where writing should stop
(inclusive)", to make it very clear.
struct a {
int b;
int c;
int d;
};
How do I zero out `c' and `d'?
if you want to zero out 'c' and 'd', you can use it like
memset_range(a_ptr, c, d);
But I don't think that's what the code does!
it expands to
memset(__ptr + offsetof(typeof(*(a)), c), __val,
offsetofend(typeof(*(a)), d) -
offsetof(typeof(*(a)), c));
which expands to
memset(__ptr + 4, __val,
8 -
4);
and `d' will not be written to.
On Wed, Dec 08, 2021 at 03:44:37PM -0800, Andrew Morton wrote:
On Wed, 8 Dec 2021 18:30:26 +0800 xiujianfeng [off-list ref] wrote:
quoted
在 2021/12/8 12:28, Andrew Morton 写道:
quoted
On Wed, 8 Dec 2021 11:04:50 +0800 Xiu Jianfeng [off-list ref] wrote:
quoted
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Is this likely to have more than a single call site?
There maybe more call site for this function, but I just use bpf as an
example.
I mean zeroing from member1 to member2(including position indicated by
member1 and member2)
quoted
quoted
+ *+ * @obj: Address of target struct instance+ * @v: Byte value to repeatedly write+ * @member1: struct member to start writing at+ * @member2: struct member where writing should stop
Perhaps "struct member before which writing should stop"?
memset_range should include position indicated by member2 as well
In that case we could say "struct member where writing should stop
(inclusive)", to make it very clear.
struct a {
int b;
int c;
int d;
};
How do I zero out `c' and `d'?
if you want to zero out 'c' and 'd', you can use it like
memset_range(a_ptr, c, d);
But I don't think that's what the code does!
it expands to
memset(__ptr + offsetof(typeof(*(a)), c), __val,
offsetofend(typeof(*(a)), d) -
offsetof(typeof(*(a)), c));
which expands to
memset(__ptr + 4, __val,
8 -
4);
and `d' will not be written to.
Please don't add memset_range(): just use a struct_group() to capture
the range and use memset() against the new substruct. This will allow
for the range to be documented where it is defined in the struct (rather
than deep in some code), keep any changes centralized instead of spread
around in memset_range() calls, protect against accidental struct member
reordering breaking things, and lets the compiler be able to examine
the range explicitly and do all the correct bounds checking:
struct a {
int b;
struct_group(range,
int c;
int d;
);
int e;
};
memset(&instance->range, 0, sizeof(instance->range));
memset_from/after() were added because of the very common case of "wipe
from here to end", which stays tied to a single member, and addressed
cases where struct_group() couldn't help (e.g. trailing padding).
--
Kees Cook
On Wed, 8 Dec 2021 18:30:26 +0800 xiujianfeng [off-list ref] wrote:
quoted
在 2021/12/8 12:28, Andrew Morton 写道:
quoted
On Wed, 8 Dec 2021 11:04:50 +0800 Xiu Jianfeng [off-list ref] wrote:
quoted
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Is this likely to have more than a single call site?
There maybe more call site for this function, but I just use bpf as an
example.
I mean zeroing from member1 to member2(including position indicated by
member1 and member2)
quoted
quoted
+ *+ * @obj: Address of target struct instance+ * @v: Byte value to repeatedly write+ * @member1: struct member to start writing at+ * @member2: struct member where writing should stop
Perhaps "struct member before which writing should stop"?
memset_range should include position indicated by member2 as well
In that case we could say "struct member where writing should stop
(inclusive)", to make it very clear.
struct a {
int b;
int c;
int d;
};
How do I zero out `c' and `d'?
if you want to zero out 'c' and 'd', you can use it like
memset_range(a_ptr, c, d);
But I don't think that's what the code does!
it expands to
memset(__ptr + offsetof(typeof(*(a)), c), __val,
offsetofend(typeof(*(a)), d) -
offsetof(typeof(*(a)), c));
which expands to
memset(__ptr + 4, __val,
8 -
4);
and `d' will not be written to.
#define offsetofend(TYPE, MEMBER) \
(offsetof(TYPE, MEMBER)>+ sizeof_field(TYPE, MEMBER))
if I understand correctly, offsetofend(typeof(*(a), d) is 12, so it expands to
memset(__ptr + 4, __val,
12 -
4);
Anyway, I will drop this patch because of Kees's suggestion, thank you.
On Wed, Dec 08, 2021 at 03:44:37PM -0800, Andrew Morton wrote:
quoted
On Wed, 8 Dec 2021 18:30:26 +0800 xiujianfeng [off-list ref] wrote:
quoted
在 2021/12/8 12:28, Andrew Morton 写道:
quoted
On Wed, 8 Dec 2021 11:04:50 +0800 Xiu Jianfeng [off-list ref] wrote:
quoted
Motivated by memset_after() and memset_startat(), introduce a new helper,
memset_range() that takes the target struct instance, the byte to write,
and two member names where zeroing should start and end.
Is this likely to have more than a single call site?
There maybe more call site for this function, but I just use bpf as an
example.
I mean zeroing from member1 to member2(including position indicated by
member1 and member2)
quoted
quoted
+ *+ * @obj: Address of target struct instance+ * @v: Byte value to repeatedly write+ * @member1: struct member to start writing at+ * @member2: struct member where writing should stop
Perhaps "struct member before which writing should stop"?
memset_range should include position indicated by member2 as well
In that case we could say "struct member where writing should stop
(inclusive)", to make it very clear.
struct a {
int b;
int c;
int d;
};
How do I zero out `c' and `d'?
if you want to zero out 'c' and 'd', you can use it like
memset_range(a_ptr, c, d);
But I don't think that's what the code does!
it expands to
memset(__ptr + offsetof(typeof(*(a)), c), __val,
offsetofend(typeof(*(a)), d) -
offsetof(typeof(*(a)), c));
which expands to
memset(__ptr + 4, __val,
8 -
4);
and `d' will not be written to.
Please don't add memset_range(): just use a struct_group() to capture
the range and use memset() against the new substruct. This will allow
for the range to be documented where it is defined in the struct (rather
than deep in some code), keep any changes centralized instead of spread
around in memset_range() calls, protect against accidental struct member
reordering breaking things, and lets the compiler be able to examine
the range explicitly and do all the correct bounds checking:
struct a {
int b;
struct_group(range,
int c;
int d;
);
int e;
};
memset(&instance->range, 0, sizeof(instance->range));
memset_from/after() were added because of the very common case of "wipe
from here to end", which stays tied to a single member, and addressed
cases where struct_group() couldn't help (e.g. trailing padding).