| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * x86 instruction analysis |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 6 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 7 | | - * (at your option) any later version. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | | - * GNU General Public License for more details. |
|---|
| 13 | | - * |
|---|
| 14 | | - * You should have received a copy of the GNU General Public License |
|---|
| 15 | | - * along with this program; if not, write to the Free Software |
|---|
| 16 | | - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 17 | 4 | * |
|---|
| 18 | 5 | * Copyright (C) IBM Corporation, 2002, 2004, 2009 |
|---|
| 19 | 6 | */ |
|---|
| .. | .. |
|---|
| 23 | 10 | #else |
|---|
| 24 | 11 | #include <string.h> |
|---|
| 25 | 12 | #endif |
|---|
| 26 | | -#include <asm/inat.h> |
|---|
| 27 | | -#include <asm/insn.h> |
|---|
| 13 | +#include <asm/inat.h> /*__ignore_sync_check__ */ |
|---|
| 14 | +#include <asm/insn.h> /* __ignore_sync_check__ */ |
|---|
| 15 | + |
|---|
| 16 | +#include <linux/errno.h> |
|---|
| 17 | +#include <linux/kconfig.h> |
|---|
| 18 | + |
|---|
| 19 | +#include <asm/emulate_prefix.h> /* __ignore_sync_check__ */ |
|---|
| 28 | 20 | |
|---|
| 29 | 21 | /* Verify next sizeof(t) bytes can be on the same instruction */ |
|---|
| 30 | 22 | #define validate_next(t, insn, n) \ |
|---|
| .. | .. |
|---|
| 71 | 63 | insn->addr_bytes = 4; |
|---|
| 72 | 64 | } |
|---|
| 73 | 65 | |
|---|
| 66 | +static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX }; |
|---|
| 67 | +static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX }; |
|---|
| 68 | + |
|---|
| 69 | +static int __insn_get_emulate_prefix(struct insn *insn, |
|---|
| 70 | + const insn_byte_t *prefix, size_t len) |
|---|
| 71 | +{ |
|---|
| 72 | + size_t i; |
|---|
| 73 | + |
|---|
| 74 | + for (i = 0; i < len; i++) { |
|---|
| 75 | + if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i]) |
|---|
| 76 | + goto err_out; |
|---|
| 77 | + } |
|---|
| 78 | + |
|---|
| 79 | + insn->emulate_prefix_size = len; |
|---|
| 80 | + insn->next_byte += len; |
|---|
| 81 | + |
|---|
| 82 | + return 1; |
|---|
| 83 | + |
|---|
| 84 | +err_out: |
|---|
| 85 | + return 0; |
|---|
| 86 | +} |
|---|
| 87 | + |
|---|
| 88 | +static void insn_get_emulate_prefix(struct insn *insn) |
|---|
| 89 | +{ |
|---|
| 90 | + if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix))) |
|---|
| 91 | + return; |
|---|
| 92 | + |
|---|
| 93 | + __insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix)); |
|---|
| 94 | +} |
|---|
| 95 | + |
|---|
| 74 | 96 | /** |
|---|
| 75 | 97 | * insn_get_prefixes - scan x86 instruction prefix bytes |
|---|
| 76 | 98 | * @insn: &struct insn containing instruction |
|---|
| .. | .. |
|---|
| 78 | 100 | * Populates the @insn->prefixes bitmap, and updates @insn->next_byte |
|---|
| 79 | 101 | * to point to the (first) opcode. No effect if @insn->prefixes.got |
|---|
| 80 | 102 | * is already set. |
|---|
| 103 | + * |
|---|
| 104 | + * * Returns: |
|---|
| 105 | + * 0: on success |
|---|
| 106 | + * < 0: on error |
|---|
| 81 | 107 | */ |
|---|
| 82 | | -void insn_get_prefixes(struct insn *insn) |
|---|
| 108 | +int insn_get_prefixes(struct insn *insn) |
|---|
| 83 | 109 | { |
|---|
| 84 | 110 | struct insn_field *prefixes = &insn->prefixes; |
|---|
| 85 | 111 | insn_attr_t attr; |
|---|
| .. | .. |
|---|
| 87 | 113 | int i, nb; |
|---|
| 88 | 114 | |
|---|
| 89 | 115 | if (prefixes->got) |
|---|
| 90 | | - return; |
|---|
| 116 | + return 0; |
|---|
| 117 | + |
|---|
| 118 | + insn_get_emulate_prefix(insn); |
|---|
| 91 | 119 | |
|---|
| 92 | 120 | nb = 0; |
|---|
| 93 | 121 | lb = 0; |
|---|
| .. | .. |
|---|
| 196 | 224 | |
|---|
| 197 | 225 | prefixes->got = 1; |
|---|
| 198 | 226 | |
|---|
| 227 | + return 0; |
|---|
| 228 | + |
|---|
| 199 | 229 | err_out: |
|---|
| 200 | | - return; |
|---|
| 230 | + return -ENODATA; |
|---|
| 201 | 231 | } |
|---|
| 202 | 232 | |
|---|
| 203 | 233 | /** |
|---|
| .. | .. |
|---|
| 209 | 239 | * If necessary, first collects any preceding (prefix) bytes. |
|---|
| 210 | 240 | * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got |
|---|
| 211 | 241 | * is already 1. |
|---|
| 242 | + * |
|---|
| 243 | + * Returns: |
|---|
| 244 | + * 0: on success |
|---|
| 245 | + * < 0: on error |
|---|
| 212 | 246 | */ |
|---|
| 213 | | -void insn_get_opcode(struct insn *insn) |
|---|
| 247 | +int insn_get_opcode(struct insn *insn) |
|---|
| 214 | 248 | { |
|---|
| 215 | 249 | struct insn_field *opcode = &insn->opcode; |
|---|
| 250 | + int pfx_id, ret; |
|---|
| 216 | 251 | insn_byte_t op; |
|---|
| 217 | | - int pfx_id; |
|---|
| 252 | + |
|---|
| 218 | 253 | if (opcode->got) |
|---|
| 219 | | - return; |
|---|
| 220 | | - if (!insn->prefixes.got) |
|---|
| 221 | | - insn_get_prefixes(insn); |
|---|
| 254 | + return 0; |
|---|
| 255 | + |
|---|
| 256 | + if (!insn->prefixes.got) { |
|---|
| 257 | + ret = insn_get_prefixes(insn); |
|---|
| 258 | + if (ret) |
|---|
| 259 | + return ret; |
|---|
| 260 | + } |
|---|
| 222 | 261 | |
|---|
| 223 | 262 | /* Get first opcode */ |
|---|
| 224 | 263 | op = get_next(insn_byte_t, insn); |
|---|
| .. | .. |
|---|
| 233 | 272 | insn->attr = inat_get_avx_attribute(op, m, p); |
|---|
| 234 | 273 | if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || |
|---|
| 235 | 274 | (!inat_accept_vex(insn->attr) && |
|---|
| 236 | | - !inat_is_group(insn->attr))) |
|---|
| 237 | | - insn->attr = 0; /* This instruction is bad */ |
|---|
| 238 | | - goto end; /* VEX has only 1 byte for opcode */ |
|---|
| 275 | + !inat_is_group(insn->attr))) { |
|---|
| 276 | + /* This instruction is bad */ |
|---|
| 277 | + insn->attr = 0; |
|---|
| 278 | + return -EINVAL; |
|---|
| 279 | + } |
|---|
| 280 | + /* VEX has only 1 byte for opcode */ |
|---|
| 281 | + goto end; |
|---|
| 239 | 282 | } |
|---|
| 240 | 283 | |
|---|
| 241 | 284 | insn->attr = inat_get_opcode_attribute(op); |
|---|
| .. | .. |
|---|
| 246 | 289 | pfx_id = insn_last_prefix_id(insn); |
|---|
| 247 | 290 | insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); |
|---|
| 248 | 291 | } |
|---|
| 249 | | - if (inat_must_vex(insn->attr)) |
|---|
| 250 | | - insn->attr = 0; /* This instruction is bad */ |
|---|
| 292 | + |
|---|
| 293 | + if (inat_must_vex(insn->attr)) { |
|---|
| 294 | + /* This instruction is bad */ |
|---|
| 295 | + insn->attr = 0; |
|---|
| 296 | + return -EINVAL; |
|---|
| 297 | + } |
|---|
| 251 | 298 | end: |
|---|
| 252 | 299 | opcode->got = 1; |
|---|
| 300 | + return 0; |
|---|
| 253 | 301 | |
|---|
| 254 | 302 | err_out: |
|---|
| 255 | | - return; |
|---|
| 303 | + return -ENODATA; |
|---|
| 256 | 304 | } |
|---|
| 257 | 305 | |
|---|
| 258 | 306 | /** |
|---|
| .. | .. |
|---|
| 262 | 310 | * Populates @insn->modrm and updates @insn->next_byte to point past the |
|---|
| 263 | 311 | * ModRM byte, if any. If necessary, first collects the preceding bytes |
|---|
| 264 | 312 | * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. |
|---|
| 313 | + * |
|---|
| 314 | + * Returns: |
|---|
| 315 | + * 0: on success |
|---|
| 316 | + * < 0: on error |
|---|
| 265 | 317 | */ |
|---|
| 266 | | -void insn_get_modrm(struct insn *insn) |
|---|
| 318 | +int insn_get_modrm(struct insn *insn) |
|---|
| 267 | 319 | { |
|---|
| 268 | 320 | struct insn_field *modrm = &insn->modrm; |
|---|
| 269 | 321 | insn_byte_t pfx_id, mod; |
|---|
| 322 | + int ret; |
|---|
| 323 | + |
|---|
| 270 | 324 | if (modrm->got) |
|---|
| 271 | | - return; |
|---|
| 272 | | - if (!insn->opcode.got) |
|---|
| 273 | | - insn_get_opcode(insn); |
|---|
| 325 | + return 0; |
|---|
| 326 | + |
|---|
| 327 | + if (!insn->opcode.got) { |
|---|
| 328 | + ret = insn_get_opcode(insn); |
|---|
| 329 | + if (ret) |
|---|
| 330 | + return ret; |
|---|
| 331 | + } |
|---|
| 274 | 332 | |
|---|
| 275 | 333 | if (inat_has_modrm(insn->attr)) { |
|---|
| 276 | 334 | mod = get_next(insn_byte_t, insn); |
|---|
| .. | .. |
|---|
| 280 | 338 | pfx_id = insn_last_prefix_id(insn); |
|---|
| 281 | 339 | insn->attr = inat_get_group_attribute(mod, pfx_id, |
|---|
| 282 | 340 | insn->attr); |
|---|
| 283 | | - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) |
|---|
| 284 | | - insn->attr = 0; /* This is bad */ |
|---|
| 341 | + if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) { |
|---|
| 342 | + /* Bad insn */ |
|---|
| 343 | + insn->attr = 0; |
|---|
| 344 | + return -EINVAL; |
|---|
| 345 | + } |
|---|
| 285 | 346 | } |
|---|
| 286 | 347 | } |
|---|
| 287 | 348 | |
|---|
| 288 | 349 | if (insn->x86_64 && inat_is_force64(insn->attr)) |
|---|
| 289 | 350 | insn->opnd_bytes = 8; |
|---|
| 351 | + |
|---|
| 290 | 352 | modrm->got = 1; |
|---|
| 353 | + return 0; |
|---|
| 291 | 354 | |
|---|
| 292 | 355 | err_out: |
|---|
| 293 | | - return; |
|---|
| 356 | + return -ENODATA; |
|---|
| 294 | 357 | } |
|---|
| 295 | 358 | |
|---|
| 296 | 359 | |
|---|
| .. | .. |
|---|
| 304 | 367 | int insn_rip_relative(struct insn *insn) |
|---|
| 305 | 368 | { |
|---|
| 306 | 369 | struct insn_field *modrm = &insn->modrm; |
|---|
| 370 | + int ret; |
|---|
| 307 | 371 | |
|---|
| 308 | 372 | if (!insn->x86_64) |
|---|
| 309 | 373 | return 0; |
|---|
| 310 | | - if (!modrm->got) |
|---|
| 311 | | - insn_get_modrm(insn); |
|---|
| 374 | + |
|---|
| 375 | + if (!modrm->got) { |
|---|
| 376 | + ret = insn_get_modrm(insn); |
|---|
| 377 | + if (ret) |
|---|
| 378 | + return 0; |
|---|
| 379 | + } |
|---|
| 312 | 380 | /* |
|---|
| 313 | 381 | * For rip-relative instructions, the mod field (top 2 bits) |
|---|
| 314 | 382 | * is zero and the r/m field (bottom 3 bits) is 0x5. |
|---|
| .. | .. |
|---|
| 322 | 390 | * |
|---|
| 323 | 391 | * If necessary, first collects the instruction up to and including the |
|---|
| 324 | 392 | * ModRM byte. |
|---|
| 393 | + * |
|---|
| 394 | + * Returns: |
|---|
| 395 | + * 0: if decoding succeeded |
|---|
| 396 | + * < 0: otherwise. |
|---|
| 325 | 397 | */ |
|---|
| 326 | | -void insn_get_sib(struct insn *insn) |
|---|
| 398 | +int insn_get_sib(struct insn *insn) |
|---|
| 327 | 399 | { |
|---|
| 328 | 400 | insn_byte_t modrm; |
|---|
| 401 | + int ret; |
|---|
| 329 | 402 | |
|---|
| 330 | 403 | if (insn->sib.got) |
|---|
| 331 | | - return; |
|---|
| 332 | | - if (!insn->modrm.got) |
|---|
| 333 | | - insn_get_modrm(insn); |
|---|
| 404 | + return 0; |
|---|
| 405 | + |
|---|
| 406 | + if (!insn->modrm.got) { |
|---|
| 407 | + ret = insn_get_modrm(insn); |
|---|
| 408 | + if (ret) |
|---|
| 409 | + return ret; |
|---|
| 410 | + } |
|---|
| 411 | + |
|---|
| 334 | 412 | if (insn->modrm.nbytes) { |
|---|
| 335 | 413 | modrm = (insn_byte_t)insn->modrm.value; |
|---|
| 336 | 414 | if (insn->addr_bytes != 2 && |
|---|
| .. | .. |
|---|
| 341 | 419 | } |
|---|
| 342 | 420 | insn->sib.got = 1; |
|---|
| 343 | 421 | |
|---|
| 422 | + return 0; |
|---|
| 423 | + |
|---|
| 344 | 424 | err_out: |
|---|
| 345 | | - return; |
|---|
| 425 | + return -ENODATA; |
|---|
| 346 | 426 | } |
|---|
| 347 | 427 | |
|---|
| 348 | 428 | |
|---|
| .. | .. |
|---|
| 353 | 433 | * If necessary, first collects the instruction up to and including the |
|---|
| 354 | 434 | * SIB byte. |
|---|
| 355 | 435 | * Displacement value is sign-expanded. |
|---|
| 436 | + * |
|---|
| 437 | + * * Returns: |
|---|
| 438 | + * 0: if decoding succeeded |
|---|
| 439 | + * < 0: otherwise. |
|---|
| 356 | 440 | */ |
|---|
| 357 | | -void insn_get_displacement(struct insn *insn) |
|---|
| 441 | +int insn_get_displacement(struct insn *insn) |
|---|
| 358 | 442 | { |
|---|
| 359 | 443 | insn_byte_t mod, rm, base; |
|---|
| 444 | + int ret; |
|---|
| 360 | 445 | |
|---|
| 361 | 446 | if (insn->displacement.got) |
|---|
| 362 | | - return; |
|---|
| 363 | | - if (!insn->sib.got) |
|---|
| 364 | | - insn_get_sib(insn); |
|---|
| 447 | + return 0; |
|---|
| 448 | + |
|---|
| 449 | + if (!insn->sib.got) { |
|---|
| 450 | + ret = insn_get_sib(insn); |
|---|
| 451 | + if (ret) |
|---|
| 452 | + return ret; |
|---|
| 453 | + } |
|---|
| 454 | + |
|---|
| 365 | 455 | if (insn->modrm.nbytes) { |
|---|
| 366 | 456 | /* |
|---|
| 367 | 457 | * Interpreting the modrm byte: |
|---|
| .. | .. |
|---|
| 404 | 494 | } |
|---|
| 405 | 495 | out: |
|---|
| 406 | 496 | insn->displacement.got = 1; |
|---|
| 497 | + return 0; |
|---|
| 407 | 498 | |
|---|
| 408 | 499 | err_out: |
|---|
| 409 | | - return; |
|---|
| 500 | + return -ENODATA; |
|---|
| 410 | 501 | } |
|---|
| 411 | 502 | |
|---|
| 412 | 503 | /* Decode moffset16/32/64. Return 0 if failed */ |
|---|
| .. | .. |
|---|
| 517 | 608 | } |
|---|
| 518 | 609 | |
|---|
| 519 | 610 | /** |
|---|
| 520 | | - * insn_get_immediate() - Get the immediates of instruction |
|---|
| 611 | + * insn_get_immediate() - Get the immediate in an instruction |
|---|
| 521 | 612 | * @insn: &struct insn containing instruction |
|---|
| 522 | 613 | * |
|---|
| 523 | 614 | * If necessary, first collects the instruction up to and including the |
|---|
| 524 | 615 | * displacement bytes. |
|---|
| 525 | 616 | * Basically, most of immediates are sign-expanded. Unsigned-value can be |
|---|
| 526 | | - * get by bit masking with ((1 << (nbytes * 8)) - 1) |
|---|
| 617 | + * computed by bit masking with ((1 << (nbytes * 8)) - 1) |
|---|
| 618 | + * |
|---|
| 619 | + * Returns: |
|---|
| 620 | + * 0: on success |
|---|
| 621 | + * < 0: on error |
|---|
| 527 | 622 | */ |
|---|
| 528 | | -void insn_get_immediate(struct insn *insn) |
|---|
| 623 | +int insn_get_immediate(struct insn *insn) |
|---|
| 529 | 624 | { |
|---|
| 625 | + int ret; |
|---|
| 626 | + |
|---|
| 530 | 627 | if (insn->immediate.got) |
|---|
| 531 | | - return; |
|---|
| 532 | | - if (!insn->displacement.got) |
|---|
| 533 | | - insn_get_displacement(insn); |
|---|
| 628 | + return 0; |
|---|
| 629 | + |
|---|
| 630 | + if (!insn->displacement.got) { |
|---|
| 631 | + ret = insn_get_displacement(insn); |
|---|
| 632 | + if (ret) |
|---|
| 633 | + return ret; |
|---|
| 634 | + } |
|---|
| 534 | 635 | |
|---|
| 535 | 636 | if (inat_has_moffset(insn->attr)) { |
|---|
| 536 | 637 | if (!__get_moffset(insn)) |
|---|
| .. | .. |
|---|
| 583 | 684 | } |
|---|
| 584 | 685 | done: |
|---|
| 585 | 686 | insn->immediate.got = 1; |
|---|
| 687 | + return 0; |
|---|
| 586 | 688 | |
|---|
| 587 | 689 | err_out: |
|---|
| 588 | | - return; |
|---|
| 690 | + return -ENODATA; |
|---|
| 589 | 691 | } |
|---|
| 590 | 692 | |
|---|
| 591 | 693 | /** |
|---|
| .. | .. |
|---|
| 594 | 696 | * |
|---|
| 595 | 697 | * If necessary, first collects the instruction up to and including the |
|---|
| 596 | 698 | * immediates bytes. |
|---|
| 597 | | - */ |
|---|
| 598 | | -void insn_get_length(struct insn *insn) |
|---|
| 699 | + * |
|---|
| 700 | + * Returns: |
|---|
| 701 | + * - 0 on success |
|---|
| 702 | + * - < 0 on error |
|---|
| 703 | +*/ |
|---|
| 704 | +int insn_get_length(struct insn *insn) |
|---|
| 599 | 705 | { |
|---|
| 706 | + int ret; |
|---|
| 707 | + |
|---|
| 600 | 708 | if (insn->length) |
|---|
| 601 | | - return; |
|---|
| 602 | | - if (!insn->immediate.got) |
|---|
| 603 | | - insn_get_immediate(insn); |
|---|
| 709 | + return 0; |
|---|
| 710 | + |
|---|
| 711 | + if (!insn->immediate.got) { |
|---|
| 712 | + ret = insn_get_immediate(insn); |
|---|
| 713 | + if (ret) |
|---|
| 714 | + return ret; |
|---|
| 715 | + } |
|---|
| 716 | + |
|---|
| 604 | 717 | insn->length = (unsigned char)((unsigned long)insn->next_byte |
|---|
| 605 | 718 | - (unsigned long)insn->kaddr); |
|---|
| 719 | + |
|---|
| 720 | + return 0; |
|---|
| 721 | +} |
|---|
| 722 | + |
|---|
| 723 | +/** |
|---|
| 724 | + * insn_decode() - Decode an x86 instruction |
|---|
| 725 | + * @insn: &struct insn to be initialized |
|---|
| 726 | + * @kaddr: address (in kernel memory) of instruction (or copy thereof) |
|---|
| 727 | + * @buf_len: length of the insn buffer at @kaddr |
|---|
| 728 | + * @m: insn mode, see enum insn_mode |
|---|
| 729 | + * |
|---|
| 730 | + * Returns: |
|---|
| 731 | + * 0: if decoding succeeded |
|---|
| 732 | + * < 0: otherwise. |
|---|
| 733 | + */ |
|---|
| 734 | +int insn_decode(struct insn *insn, const void *kaddr, int buf_len, enum insn_mode m) |
|---|
| 735 | +{ |
|---|
| 736 | + int ret; |
|---|
| 737 | + |
|---|
| 738 | +/* #define INSN_MODE_KERN -1 __ignore_sync_check__ mode is only valid in the kernel */ |
|---|
| 739 | + |
|---|
| 740 | + if (m == INSN_MODE_KERN) |
|---|
| 741 | + insn_init(insn, kaddr, buf_len, IS_ENABLED(CONFIG_X86_64)); |
|---|
| 742 | + else |
|---|
| 743 | + insn_init(insn, kaddr, buf_len, m == INSN_MODE_64); |
|---|
| 744 | + |
|---|
| 745 | + ret = insn_get_length(insn); |
|---|
| 746 | + if (ret) |
|---|
| 747 | + return ret; |
|---|
| 748 | + |
|---|
| 749 | + if (insn_complete(insn)) |
|---|
| 750 | + return 0; |
|---|
| 751 | + |
|---|
| 752 | + return -EINVAL; |
|---|
| 606 | 753 | } |
|---|