Saturday, July 16, 2022
HomeOperating Systemdiscovering binary variations « codeblog

discovering binary variations « codeblog


As a part of the persevering with work to substitute 1-element arrays within the Linux kernel, it’s very useful to point out {that a} supply change has had no executable code distinction. For instance, if you happen to began with this:


struct foo {
    unsigned lengthy flags;
    u32 size;
    u32 information[1];
};

void foo_init(int rely)
{
    struct foo *occasion;
    size_t bytes = sizeof(*occasion) + sizeof(u32) * (rely - 1);
    ...
    occasion = kmalloc(bytes, GFP_KERNEL);
    ...
};

And also you modified solely the struct definition:


-    u32 information[1];
+    u32 information[];

The bytes calculation goes to be incorrect, since it’s nonetheless subtracting 1 component’s value of house from the specified rely. (And let’s ignore for the second the open-coded calculation which will find yourself with an arithmetic over/underflow right here; that may be solved individually through the use of the struct_size() helper or the size_mul(), size_add(), and so forth household of helpers.)

The missed adjustment to the scale calculation is comparatively simple to seek out on this instance, however typically it’s a lot much less apparent how construction sizes could be woven into the code. I’ve been checking for points through the use of the unbelievable diffoscope device. It will possibly produce a LOT of noise if you happen to attempt to examine builds with out maintaining in thoughts the problems solved by reproducible builds, with some extra notes. I put together my construct with the “recognized to disrupt code structure” choices disabled, however with debug data enabled:


$ KBF="KBUILD_BUILD_TIMESTAMP=1970-01-01 KBUILD_BUILD_USER=person KBUILD_BUILD_HOST=host KBUILD_BUILD_VERSION=1"
$ OUT=gcc
$ make $KBF O=$OUT allmodconfig
$ ./scripts/config --file $OUT/.config 
        -d GCOV_KERNEL -d KCOV -d GCC_PLUGINS -d IKHEADERS -d KASAN -d UBSAN 
        -d DEBUG_INFO_NONE -e DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT
$ make $KBF O=$OUT olddefconfig

Then I construct a inventory goal, saving the output in “earlier than”. On this case, I’m inspecting drivers/scsi/megaraid/:


$ make -jN $KBF O=$OUT drivers/scsi/megaraid/
$ mkdir -p $OUT/earlier than
$ cp $OUT/drivers/scsi/megaraid/*.o $OUT/earlier than/

Then I patch and construct a modified goal, saving the output in “after”:


$ vi the/supply/code.c
$ make -jN $KBF O=$OUT drivers/scsi/megaraid/
$ mkdir -p $OUT/after
$ cp $OUT/drivers/scsi/megaraid/*.o $OUT/after/

After which run diffoscope:


$ diffoscope $OUT/earlier than/ $OUT/after/

If diffoscope output reviews nothing, then we’re achieved. 🥳

Often, although, when supply traces transfer round different stuff will shift too (e.g. WARN macros depend on line numbers, so the bug desk might change contents a bit, and so forth), and diffoscope output will look noisy. To look at simply the executable code, the command that diffoscope used is reported within the output, and we will run it instantly, however with presumably shifted line numbers not reported. i.e. working objdump with out --line-numbers:


$ ARGS="--disassemble --demangle --reloc --no-show-raw-insn --section=.textual content"
$ for i in $(cd $OUT/earlier than && echo *.o); do
        echo $i
        diff -u 

If I see an surprising distinction, for instance:


-    c120:      movq   $0x0,0x800(%rbx)
+    c120:      movq   $0x0,0x7f8(%rbx)

Then I am going to seek for the sample with line numbers added to the objdump output:


$ vi 

I might seek for "0x0,0x7f8", discover the supply file and line quantity above it, open that supply file at that place, and look to see the place one thing was being miscalculated:


$ vi drivers/scsi/megaraid/megaraid_sas_fp.c +329

As soon as tracked down, I might begin over on the "patch and construct a modified goal" step above, repeating till there have been no variations. For instance, within the beginning instance, I might additionally have to make this modification:


-    size_t bytes = sizeof(*occasion) + sizeof(u32) * (rely - 1);
+    size_t bytes = sizeof(*occasion) + sizeof(u32) * rely;

Although, as hinted earlier, higher but can be:


-    size_t bytes = sizeof(*occasion) + sizeof(u32) * (rely - 1);
+    size_t bytes = struct_size(occasion, information, rely);

However typically including the helper utilization will add binary output variations since they're performing overflow checking which may saturate at SIZE_MAX. To assist with patch readability, these modifications might be achieved individually from fixing the array declaration.

© 2022, Kees Prepare dinner. This work is licensed beneath a Artistic Commons Attribution-ShareAlike 4.0 License.

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments