On Mon, Jan 29, 2024 at 04:00:20PM +0000, Qing Zhao wrote: > An update on the kernel building with my version 4 patch. > > Kees reported two FE issues with the current version 4 patch: > > 1. The operator “typeof” cannot return correct type for a->array; > 2. The operator “&” cannot return correct address for a->array; > > I fixed both in my local repository. > > With these additional fix. Kernel with counted-by annotation can be built > successfully.
Thanks for the fixes! > > And then, Kees reported one behavioral issue with the current counted-by: > > When the counted-by value is below zero, my current patch > > A. Didn’t report any warning for it. > B. Accepted the negative value as a wrapped size. > > i.e. for: > > struct foo { > signed char size; > unsigned char array[] __counted_by(size); > } *a; > > ... > a->size = -3; > report(__builtin_dynamic_object_size(p->array, 1)); > > this reports 253, rather than 0. > > And the array-bounds sanitizer doesn’t catch negative index bounds neither. > > a->size = -3; > report(a->array[1]); // does not trap > > > So, my questions are: > > How should we handle the negative counted-by value? Treat it as always 0-bounded: count < 0 ? 0 : count > > My approach is: > > I think that this is a user error, the compiler need to Issue warning > during runtime about this user error. > > Since I have one remaining patch that has not been finished yet: > > 6 Emit warnings when the user breaks the requirments for the new counted_by > attribute > compilation time: -Wcounted-by > run time: -fsanitizer=counted-by > * The initialization to the size field should be done before the first > reference to the FAM field. I would hope that regular compile-time warnings would catch this. > * the array has at least # of elements specified by the size field all > the time during the program. > * the value of counted-by should not be negative. This seems reasonable for a very strict program, but it won't work for the kernel as-is: a negative "count" is sometimes used to carry failure details back to other users of the structure. This could be refactored in the kernel, but I'd prefer that even without -fsanitizer=counted-by the runtime behaviors will be "safe". It does not seem sensible to me that adding a buffer size validation primitive to GCC will result in conditions where a size calculation will wrap around. I prefer no surprises. :) > Let me know your comment and suggestions. Clang has implemented the safety logic I'd prefer: * __bdos will report 0 for any sizing where the "counted_by" count variable is negative. Effectively, the count variable is always processed as: count < 0 ? 0 : count struct foo { int count; short array[] __counted_by(count); } *p; __bdos(p->array, 1) ==> sizeof(*p->array) * (count < 0 ? 0 : count) The logic for this is that __bdos can be _certain_ that the size is 0 when the count variable is pathological. * -fsanitize=array-bounds similarly treats count as above, so that: printf("%d\n", p->array[index]); ==> trap when index > (count < 0 ? 0 : count) Same logic for the sanitizer: any access to the array when count is invalid means the access is invalid and must be trapped. This means that software can run safely even in pathological conditions. -Kees -- Kees Cook