diff options
| author | Andrey Ryabinin <aryabinin@virtuozzo.com> | 2018-02-06 18:40:42 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-06 21:32:46 -0500 |
| commit | 42440c1f9911b4b7b8ba3dc4e90c1197bc561211 (patch) | |
| tree | b89beb05c6a0a42c7e289a8050ba7797aae6a586 /lib | |
| parent | b8fe1120b4ba342b4f156d24e952d6e686b20298 (diff) | |
lib/ubsan: add type mismatch handler for new GCC/Clang
UBSAN=y fails to build with new GCC/clang:
arch/x86/kernel/head64.o: In function `sanitize_boot_params':
arch/x86/include/asm/bootparam_utils.h:37: undefined reference to `__ubsan_handle_type_mismatch_v1'
because Clang and GCC 8 slightly changed ABI for 'type mismatch' errors.
Compiler now uses new __ubsan_handle_type_mismatch_v1() function with
slightly modified 'struct type_mismatch_data'.
Let's add new 'struct type_mismatch_data_common' which is independent from
compiler's layout of 'struct type_mismatch_data'. And make
__ubsan_handle_type_mismatch[_v1]() functions transform compiler-dependent
type mismatch data to our internal representation. This way, we can
support both old and new compilers with minimal amount of change.
Link: http://lkml.kernel.org/r/20180119152853.16806-1-aryabinin@virtuozzo.com
Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
Reported-by: Sodagudi Prasad <psodagud@codeaurora.org>
Cc: <stable@vger.kernel.org> [4.5+]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/ubsan.c | 48 | ||||
| -rw-r--r-- | lib/ubsan.h | 14 |
2 files changed, 52 insertions, 10 deletions
diff --git a/lib/ubsan.c b/lib/ubsan.c index 1e2328fa002d..50d1d5c25deb 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c | |||
| @@ -265,14 +265,14 @@ void __ubsan_handle_divrem_overflow(struct overflow_data *data, | |||
| 265 | } | 265 | } |
| 266 | EXPORT_SYMBOL(__ubsan_handle_divrem_overflow); | 266 | EXPORT_SYMBOL(__ubsan_handle_divrem_overflow); |
| 267 | 267 | ||
| 268 | static void handle_null_ptr_deref(struct type_mismatch_data *data) | 268 | static void handle_null_ptr_deref(struct type_mismatch_data_common *data) |
| 269 | { | 269 | { |
| 270 | unsigned long flags; | 270 | unsigned long flags; |
| 271 | 271 | ||
| 272 | if (suppress_report(&data->location)) | 272 | if (suppress_report(data->location)) |
| 273 | return; | 273 | return; |
| 274 | 274 | ||
| 275 | ubsan_prologue(&data->location, &flags); | 275 | ubsan_prologue(data->location, &flags); |
| 276 | 276 | ||
| 277 | pr_err("%s null pointer of type %s\n", | 277 | pr_err("%s null pointer of type %s\n", |
| 278 | type_check_kinds[data->type_check_kind], | 278 | type_check_kinds[data->type_check_kind], |
| @@ -281,15 +281,15 @@ static void handle_null_ptr_deref(struct type_mismatch_data *data) | |||
| 281 | ubsan_epilogue(&flags); | 281 | ubsan_epilogue(&flags); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | static void handle_misaligned_access(struct type_mismatch_data *data, | 284 | static void handle_misaligned_access(struct type_mismatch_data_common *data, |
| 285 | unsigned long ptr) | 285 | unsigned long ptr) |
| 286 | { | 286 | { |
| 287 | unsigned long flags; | 287 | unsigned long flags; |
| 288 | 288 | ||
| 289 | if (suppress_report(&data->location)) | 289 | if (suppress_report(data->location)) |
| 290 | return; | 290 | return; |
| 291 | 291 | ||
| 292 | ubsan_prologue(&data->location, &flags); | 292 | ubsan_prologue(data->location, &flags); |
| 293 | 293 | ||
| 294 | pr_err("%s misaligned address %p for type %s\n", | 294 | pr_err("%s misaligned address %p for type %s\n", |
| 295 | type_check_kinds[data->type_check_kind], | 295 | type_check_kinds[data->type_check_kind], |
| @@ -299,15 +299,15 @@ static void handle_misaligned_access(struct type_mismatch_data *data, | |||
| 299 | ubsan_epilogue(&flags); | 299 | ubsan_epilogue(&flags); |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | static void handle_object_size_mismatch(struct type_mismatch_data *data, | 302 | static void handle_object_size_mismatch(struct type_mismatch_data_common *data, |
| 303 | unsigned long ptr) | 303 | unsigned long ptr) |
| 304 | { | 304 | { |
| 305 | unsigned long flags; | 305 | unsigned long flags; |
| 306 | 306 | ||
| 307 | if (suppress_report(&data->location)) | 307 | if (suppress_report(data->location)) |
| 308 | return; | 308 | return; |
| 309 | 309 | ||
| 310 | ubsan_prologue(&data->location, &flags); | 310 | ubsan_prologue(data->location, &flags); |
| 311 | pr_err("%s address %p with insufficient space\n", | 311 | pr_err("%s address %p with insufficient space\n", |
| 312 | type_check_kinds[data->type_check_kind], | 312 | type_check_kinds[data->type_check_kind], |
| 313 | (void *) ptr); | 313 | (void *) ptr); |
| @@ -315,7 +315,7 @@ static void handle_object_size_mismatch(struct type_mismatch_data *data, | |||
| 315 | ubsan_epilogue(&flags); | 315 | ubsan_epilogue(&flags); |
| 316 | } | 316 | } |
| 317 | 317 | ||
| 318 | void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, | 318 | static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data, |
| 319 | unsigned long ptr) | 319 | unsigned long ptr) |
| 320 | { | 320 | { |
| 321 | 321 | ||
| @@ -326,8 +326,36 @@ void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, | |||
| 326 | else | 326 | else |
| 327 | handle_object_size_mismatch(data, ptr); | 327 | handle_object_size_mismatch(data, ptr); |
| 328 | } | 328 | } |
| 329 | |||
| 330 | void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, | ||
| 331 | unsigned long ptr) | ||
| 332 | { | ||
| 333 | struct type_mismatch_data_common common_data = { | ||
| 334 | .location = &data->location, | ||
| 335 | .type = data->type, | ||
| 336 | .alignment = data->alignment, | ||
| 337 | .type_check_kind = data->type_check_kind | ||
| 338 | }; | ||
| 339 | |||
| 340 | ubsan_type_mismatch_common(&common_data, ptr); | ||
| 341 | } | ||
| 329 | EXPORT_SYMBOL(__ubsan_handle_type_mismatch); | 342 | EXPORT_SYMBOL(__ubsan_handle_type_mismatch); |
| 330 | 343 | ||
| 344 | void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, | ||
| 345 | unsigned long ptr) | ||
| 346 | { | ||
| 347 | |||
| 348 | struct type_mismatch_data_common common_data = { | ||
| 349 | .location = &data->location, | ||
| 350 | .type = data->type, | ||
| 351 | .alignment = 1UL << data->log_alignment, | ||
| 352 | .type_check_kind = data->type_check_kind | ||
| 353 | }; | ||
| 354 | |||
| 355 | ubsan_type_mismatch_common(&common_data, ptr); | ||
| 356 | } | ||
| 357 | EXPORT_SYMBOL(__ubsan_handle_type_mismatch_v1); | ||
| 358 | |||
| 331 | void __ubsan_handle_nonnull_return(struct nonnull_return_data *data) | 359 | void __ubsan_handle_nonnull_return(struct nonnull_return_data *data) |
| 332 | { | 360 | { |
| 333 | unsigned long flags; | 361 | unsigned long flags; |
diff --git a/lib/ubsan.h b/lib/ubsan.h index 88f23557edbe..7e30b26497e0 100644 --- a/lib/ubsan.h +++ b/lib/ubsan.h | |||
| @@ -37,6 +37,20 @@ struct type_mismatch_data { | |||
| 37 | unsigned char type_check_kind; | 37 | unsigned char type_check_kind; |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | struct type_mismatch_data_v1 { | ||
| 41 | struct source_location location; | ||
| 42 | struct type_descriptor *type; | ||
| 43 | unsigned char log_alignment; | ||
| 44 | unsigned char type_check_kind; | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct type_mismatch_data_common { | ||
| 48 | struct source_location *location; | ||
| 49 | struct type_descriptor *type; | ||
| 50 | unsigned long alignment; | ||
| 51 | unsigned char type_check_kind; | ||
| 52 | }; | ||
| 53 | |||
| 40 | struct nonnull_arg_data { | 54 | struct nonnull_arg_data { |
| 41 | struct source_location location; | 55 | struct source_location location; |
| 42 | struct source_location attr_location; | 56 | struct source_location attr_location; |
