1
2
3
4
5
6#include <linux/kernel.h>
7#include <linux/string.h>
8#include <linux/ratelimit.h>
9#include <linux/mmu_context.h>
10#include <asm/desc_defs.h>
11#include <asm/desc.h>
12#include <asm/inat.h>
13#include <asm/insn.h>
14#include <asm/insn-eval.h>
15#include <asm/ldt.h>
16#include <asm/vm86.h>
17
18#undef pr_fmt
19#define pr_fmt(fmt) "insn: " fmt
20
21enum reg_type {
22 REG_TYPE_RM = 0,
23 REG_TYPE_INDEX,
24 REG_TYPE_BASE,
25};
26
27
28
29
30
31
32
33
34
35
36
37static bool is_string_insn(struct insn *insn)
38{
39 insn_get_opcode(insn);
40
41
42 if (insn->opcode.nbytes != 1)
43 return false;
44
45 switch (insn->opcode.bytes[0]) {
46 case 0x6c ... 0x6f:
47 case 0xa4 ... 0xa7:
48 case 0xaa ... 0xaf:
49 return true;
50 default:
51 return false;
52 }
53}
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69static int get_seg_reg_override_idx(struct insn *insn)
70{
71 int idx = INAT_SEG_REG_DEFAULT;
72 int num_overrides = 0, i;
73
74 insn_get_prefixes(insn);
75
76
77 for (i = 0; i < insn->prefixes.nbytes; i++) {
78 insn_attr_t attr;
79
80 attr = inat_get_opcode_attribute(insn->prefixes.bytes[i]);
81 switch (attr) {
82 case INAT_MAKE_PREFIX(INAT_PFX_CS):
83 idx = INAT_SEG_REG_CS;
84 num_overrides++;
85 break;
86 case INAT_MAKE_PREFIX(INAT_PFX_SS):
87 idx = INAT_SEG_REG_SS;
88 num_overrides++;
89 break;
90 case INAT_MAKE_PREFIX(INAT_PFX_DS):
91 idx = INAT_SEG_REG_DS;
92 num_overrides++;
93 break;
94 case INAT_MAKE_PREFIX(INAT_PFX_ES):
95 idx = INAT_SEG_REG_ES;
96 num_overrides++;
97 break;
98 case INAT_MAKE_PREFIX(INAT_PFX_FS):
99 idx = INAT_SEG_REG_FS;
100 num_overrides++;
101 break;
102 case INAT_MAKE_PREFIX(INAT_PFX_GS):
103 idx = INAT_SEG_REG_GS;
104 num_overrides++;
105 break;
106
107 }
108 }
109
110
111 if (num_overrides > 1)
112 return -EINVAL;
113
114 return idx;
115}
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131static bool check_seg_overrides(struct insn *insn, int regoff)
132{
133 if (regoff == offsetof(struct pt_regs, di) && is_string_insn(insn))
134 return false;
135
136 return true;
137}
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156static int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off)
157{
158 if (user_64bit_mode(regs))
159 return INAT_SEG_REG_IGNORE;
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 switch (off) {
175 case offsetof(struct pt_regs, ax):
176 case offsetof(struct pt_regs, cx):
177 case offsetof(struct pt_regs, dx):
178
179 if (insn->addr_bytes == 2)
180 return -EINVAL;
181
182 case -EDOM:
183 case offsetof(struct pt_regs, bx):
184 case offsetof(struct pt_regs, si):
185 return INAT_SEG_REG_DS;
186
187 case offsetof(struct pt_regs, di):
188 if (is_string_insn(insn))
189 return INAT_SEG_REG_ES;
190 return INAT_SEG_REG_DS;
191
192 case offsetof(struct pt_regs, bp):
193 case offsetof(struct pt_regs, sp):
194 return INAT_SEG_REG_SS;
195
196 case offsetof(struct pt_regs, ip):
197 return INAT_SEG_REG_CS;
198
199 default:
200 return -EINVAL;
201 }
202}
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256static int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff)
257{
258 int idx;
259
260
261
262
263
264
265
266 if (regoff == offsetof(struct pt_regs, ip)) {
267 if (user_64bit_mode(regs))
268 return INAT_SEG_REG_IGNORE;
269 else
270 return INAT_SEG_REG_CS;
271 }
272
273 if (!insn)
274 return -EINVAL;
275
276 if (!check_seg_overrides(insn, regoff))
277 return resolve_default_seg(insn, regs, regoff);
278
279 idx = get_seg_reg_override_idx(insn);
280 if (idx < 0)
281 return idx;
282
283 if (idx == INAT_SEG_REG_DEFAULT)
284 return resolve_default_seg(insn, regs, regoff);
285
286
287
288
289
290 if (user_64bit_mode(regs)) {
291 if (idx != INAT_SEG_REG_FS &&
292 idx != INAT_SEG_REG_GS)
293 idx = INAT_SEG_REG_IGNORE;
294 }
295
296 return idx;
297}
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318static short get_segment_selector(struct pt_regs *regs, int seg_reg_idx)
319{
320#ifdef CONFIG_X86_64
321 unsigned short sel;
322
323 switch (seg_reg_idx) {
324 case INAT_SEG_REG_IGNORE:
325 return 0;
326 case INAT_SEG_REG_CS:
327 return (unsigned short)(regs->cs & 0xffff);
328 case INAT_SEG_REG_SS:
329 return (unsigned short)(regs->ss & 0xffff);
330 case INAT_SEG_REG_DS:
331 savesegment(ds, sel);
332 return sel;
333 case INAT_SEG_REG_ES:
334 savesegment(es, sel);
335 return sel;
336 case INAT_SEG_REG_FS:
337 savesegment(fs, sel);
338 return sel;
339 case INAT_SEG_REG_GS:
340 savesegment(gs, sel);
341 return sel;
342 default:
343 return -EINVAL;
344 }
345#else
346 struct kernel_vm86_regs *vm86regs = (struct kernel_vm86_regs *)regs;
347
348 if (v8086_mode(regs)) {
349 switch (seg_reg_idx) {
350 case INAT_SEG_REG_CS:
351 return (unsigned short)(regs->cs & 0xffff);
352 case INAT_SEG_REG_SS:
353 return (unsigned short)(regs->ss & 0xffff);
354 case INAT_SEG_REG_DS:
355 return vm86regs->ds;
356 case INAT_SEG_REG_ES:
357 return vm86regs->es;
358 case INAT_SEG_REG_FS:
359 return vm86regs->fs;
360 case INAT_SEG_REG_GS:
361 return vm86regs->gs;
362 case INAT_SEG_REG_IGNORE:
363
364 default:
365 return -EINVAL;
366 }
367 }
368
369 switch (seg_reg_idx) {
370 case INAT_SEG_REG_CS:
371 return (unsigned short)(regs->cs & 0xffff);
372 case INAT_SEG_REG_SS:
373 return (unsigned short)(regs->ss & 0xffff);
374 case INAT_SEG_REG_DS:
375 return (unsigned short)(regs->ds & 0xffff);
376 case INAT_SEG_REG_ES:
377 return (unsigned short)(regs->es & 0xffff);
378 case INAT_SEG_REG_FS:
379 return (unsigned short)(regs->fs & 0xffff);
380 case INAT_SEG_REG_GS:
381
382
383
384
385 return get_user_gs(regs);
386 case INAT_SEG_REG_IGNORE:
387
388 default:
389 return -EINVAL;
390 }
391#endif
392}
393
394static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
395 enum reg_type type)
396{
397 int regno = 0;
398
399 static const int regoff[] = {
400 offsetof(struct pt_regs, ax),
401 offsetof(struct pt_regs, cx),
402 offsetof(struct pt_regs, dx),
403 offsetof(struct pt_regs, bx),
404 offsetof(struct pt_regs, sp),
405 offsetof(struct pt_regs, bp),
406 offsetof(struct pt_regs, si),
407 offsetof(struct pt_regs, di),
408#ifdef CONFIG_X86_64
409 offsetof(struct pt_regs, r8),
410 offsetof(struct pt_regs, r9),
411 offsetof(struct pt_regs, r10),
412 offsetof(struct pt_regs, r11),
413 offsetof(struct pt_regs, r12),
414 offsetof(struct pt_regs, r13),
415 offsetof(struct pt_regs, r14),
416 offsetof(struct pt_regs, r15),
417#endif
418 };
419 int nr_registers = ARRAY_SIZE(regoff);
420
421
422
423
424 if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
425 nr_registers -= 8;
426
427 switch (type) {
428 case REG_TYPE_RM:
429 regno = X86_MODRM_RM(insn->modrm.value);
430
431
432
433
434
435 if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5)
436 return -EDOM;
437
438 if (X86_REX_B(insn->rex_prefix.value))
439 regno += 8;
440 break;
441
442 case REG_TYPE_INDEX:
443 regno = X86_SIB_INDEX(insn->sib.value);
444 if (X86_REX_X(insn->rex_prefix.value))
445 regno += 8;
446
447
448
449
450
451
452
453 if (X86_MODRM_MOD(insn->modrm.value) != 3 && regno == 4)
454 return -EDOM;
455 break;
456
457 case REG_TYPE_BASE:
458 regno = X86_SIB_BASE(insn->sib.value);
459
460
461
462
463
464 if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5)
465 return -EDOM;
466
467 if (X86_REX_B(insn->rex_prefix.value))
468 regno += 8;
469 break;
470
471 default:
472 pr_err_ratelimited("invalid register type: %d\n", type);
473 return -EINVAL;
474 }
475
476 if (regno >= nr_registers) {
477 WARN_ONCE(1, "decoded an instruction with an invalid register");
478 return -EINVAL;
479 }
480 return regoff[regno];
481}
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500static int get_reg_offset_16(struct insn *insn, struct pt_regs *regs,
501 int *offs1, int *offs2)
502{
503
504
505
506
507
508 static const int regoff1[] = {
509 offsetof(struct pt_regs, bx),
510 offsetof(struct pt_regs, bx),
511 offsetof(struct pt_regs, bp),
512 offsetof(struct pt_regs, bp),
513 offsetof(struct pt_regs, si),
514 offsetof(struct pt_regs, di),
515 offsetof(struct pt_regs, bp),
516 offsetof(struct pt_regs, bx),
517 };
518
519 static const int regoff2[] = {
520 offsetof(struct pt_regs, si),
521 offsetof(struct pt_regs, di),
522 offsetof(struct pt_regs, si),
523 offsetof(struct pt_regs, di),
524 -EDOM,
525 -EDOM,
526 -EDOM,
527 -EDOM,
528 };
529
530 if (!offs1 || !offs2)
531 return -EINVAL;
532
533
534 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
535 *offs1 = insn_get_modrm_rm_off(insn, regs);
536 *offs2 = -EDOM;
537 return 0;
538 }
539
540 *offs1 = regoff1[X86_MODRM_RM(insn->modrm.value)];
541 *offs2 = regoff2[X86_MODRM_RM(insn->modrm.value)];
542
543
544
545
546
547
548
549
550 if ((X86_MODRM_MOD(insn->modrm.value) == 0) &&
551 (X86_MODRM_RM(insn->modrm.value) == 6))
552 *offs1 = -EDOM;
553
554 return 0;
555}
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570static struct desc_struct *get_desc(unsigned short sel)
571{
572 struct desc_ptr gdt_desc = {0, 0};
573 unsigned long desc_base;
574
575#ifdef CONFIG_MODIFY_LDT_SYSCALL
576 if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) {
577 struct desc_struct *desc = NULL;
578 struct ldt_struct *ldt;
579
580
581 sel >>= 3;
582
583 mutex_lock(¤t->active_mm->context.lock);
584 ldt = current->active_mm->context.ldt;
585 if (ldt && sel < ldt->nr_entries)
586 desc = &ldt->entries[sel];
587
588 mutex_unlock(¤t->active_mm->context.lock);
589
590 return desc;
591 }
592#endif
593 native_store_gdt(&gdt_desc);
594
595
596
597
598
599
600
601
602 desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK);
603
604 if (desc_base > gdt_desc.size)
605 return NULL;
606
607 return (struct desc_struct *)(gdt_desc.address + desc_base);
608}
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627unsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx)
628{
629 struct desc_struct *desc;
630 short sel;
631
632 sel = get_segment_selector(regs, seg_reg_idx);
633 if (sel < 0)
634 return -1L;
635
636 if (v8086_mode(regs))
637
638
639
640
641 return (unsigned long)(sel << 4);
642
643 if (user_64bit_mode(regs)) {
644
645
646
647
648 unsigned long base;
649
650 if (seg_reg_idx == INAT_SEG_REG_FS)
651 rdmsrl(MSR_FS_BASE, base);
652 else if (seg_reg_idx == INAT_SEG_REG_GS)
653
654
655
656
657 rdmsrl(MSR_KERNEL_GS_BASE, base);
658 else
659 base = 0;
660 return base;
661 }
662
663
664 if (!sel)
665 return -1L;
666
667 desc = get_desc(sel);
668 if (!desc)
669 return -1L;
670
671 return get_desc_base(desc);
672}
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691static unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx)
692{
693 struct desc_struct *desc;
694 unsigned long limit;
695 short sel;
696
697 sel = get_segment_selector(regs, seg_reg_idx);
698 if (sel < 0)
699 return 0;
700
701 if (user_64bit_mode(regs) || v8086_mode(regs))
702 return -1L;
703
704 if (!sel)
705 return 0;
706
707 desc = get_desc(sel);
708 if (!desc)
709 return 0;
710
711
712
713
714
715
716
717 limit = get_desc_limit(desc);
718 if (desc->g)
719 limit = (limit << 12) + 0xfff;
720
721 return limit;
722}
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740int insn_get_code_seg_params(struct pt_regs *regs)
741{
742 struct desc_struct *desc;
743 short sel;
744
745 if (v8086_mode(regs))
746
747 return INSN_CODE_SEG_PARAMS(2, 2);
748
749 sel = get_segment_selector(regs, INAT_SEG_REG_CS);
750 if (sel < 0)
751 return sel;
752
753 desc = get_desc(sel);
754 if (!desc)
755 return -EINVAL;
756
757
758
759
760
761
762 if (!(desc->type & BIT(3)))
763 return -EINVAL;
764
765 switch ((desc->l << 1) | desc->d) {
766 case 0:
767
768
769
770 return INSN_CODE_SEG_PARAMS(2, 2);
771 case 1:
772
773
774
775 return INSN_CODE_SEG_PARAMS(4, 4);
776 case 2:
777
778
779
780 return INSN_CODE_SEG_PARAMS(4, 8);
781 case 3:
782
783 default:
784 return -EINVAL;
785 }
786}
787
788
789
790
791
792
793
794
795
796
797
798
799
800int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs)
801{
802 return get_reg_offset(insn, regs, REG_TYPE_RM);
803}
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826static int get_seg_base_limit(struct insn *insn, struct pt_regs *regs,
827 int regoff, unsigned long *base,
828 unsigned long *limit)
829{
830 int seg_reg_idx;
831
832 if (!base)
833 return -EINVAL;
834
835 seg_reg_idx = resolve_seg_reg(insn, regs, regoff);
836 if (seg_reg_idx < 0)
837 return seg_reg_idx;
838
839 *base = insn_get_seg_base(regs, seg_reg_idx);
840 if (*base == -1L)
841 return -EINVAL;
842
843 if (!limit)
844 return 0;
845
846 *limit = get_seg_limit(regs, seg_reg_idx);
847 if (!(*limit))
848 return -EINVAL;
849
850 return 0;
851}
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876static int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs,
877 int *regoff, long *eff_addr)
878{
879 insn_get_modrm(insn);
880
881 if (!insn->modrm.nbytes)
882 return -EINVAL;
883
884 if (X86_MODRM_MOD(insn->modrm.value) != 3)
885 return -EINVAL;
886
887 *regoff = get_reg_offset(insn, regs, REG_TYPE_RM);
888 if (*regoff < 0)
889 return -EINVAL;
890
891
892 if (insn->addr_bytes == 2)
893 *eff_addr = regs_get_register(regs, *regoff) & 0xffff;
894 else if (insn->addr_bytes == 4)
895 *eff_addr = regs_get_register(regs, *regoff) & 0xffffffff;
896 else
897 *eff_addr = regs_get_register(regs, *regoff);
898
899 return 0;
900}
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924static int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs,
925 int *regoff, long *eff_addr)
926{
927 long tmp;
928
929 if (insn->addr_bytes != 8 && insn->addr_bytes != 4)
930 return -EINVAL;
931
932 insn_get_modrm(insn);
933
934 if (!insn->modrm.nbytes)
935 return -EINVAL;
936
937 if (X86_MODRM_MOD(insn->modrm.value) > 2)
938 return -EINVAL;
939
940 *regoff = get_reg_offset(insn, regs, REG_TYPE_RM);
941
942
943
944
945
946
947 if (*regoff == -EDOM) {
948 if (user_64bit_mode(regs))
949 tmp = regs->ip + insn->length;
950 else
951 tmp = 0;
952 } else if (*regoff < 0) {
953 return -EINVAL;
954 } else {
955 tmp = regs_get_register(regs, *regoff);
956 }
957
958 if (insn->addr_bytes == 4) {
959 int addr32 = (int)(tmp & 0xffffffff) + insn->displacement.value;
960
961 *eff_addr = addr32 & 0xffffffff;
962 } else {
963 *eff_addr = tmp + insn->displacement.value;
964 }
965
966 return 0;
967}
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991static int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs,
992 int *regoff, short *eff_addr)
993{
994 int addr_offset1, addr_offset2, ret;
995 short addr1 = 0, addr2 = 0, displacement;
996
997 if (insn->addr_bytes != 2)
998 return -EINVAL;
999
1000 insn_get_modrm(insn);
1001
1002 if (!insn->modrm.nbytes)
1003 return -EINVAL;
1004
1005 if (X86_MODRM_MOD(insn->modrm.value) > 2)
1006 return -EINVAL;
1007
1008 ret = get_reg_offset_16(insn, regs, &addr_offset1, &addr_offset2);
1009 if (ret < 0)
1010 return -EINVAL;
1011
1012
1013
1014
1015
1016
1017 if (addr_offset1 != -EDOM)
1018 addr1 = regs_get_register(regs, addr_offset1) & 0xffff;
1019
1020 if (addr_offset2 != -EDOM)
1021 addr2 = regs_get_register(regs, addr_offset2) & 0xffff;
1022
1023 displacement = insn->displacement.value & 0xffff;
1024 *eff_addr = addr1 + addr2 + displacement;
1025
1026
1027
1028
1029
1030
1031
1032 *regoff = addr_offset1;
1033
1034 return 0;
1035}
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059static int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs,
1060 int *base_offset, long *eff_addr)
1061{
1062 long base, indx;
1063 int indx_offset;
1064
1065 if (insn->addr_bytes != 8 && insn->addr_bytes != 4)
1066 return -EINVAL;
1067
1068 insn_get_modrm(insn);
1069
1070 if (!insn->modrm.nbytes)
1071 return -EINVAL;
1072
1073 if (X86_MODRM_MOD(insn->modrm.value) > 2)
1074 return -EINVAL;
1075
1076 insn_get_sib(insn);
1077
1078 if (!insn->sib.nbytes)
1079 return -EINVAL;
1080
1081 *base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
1082 indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
1083
1084
1085
1086
1087
1088
1089 if (*base_offset == -EDOM)
1090 base = 0;
1091 else if (*base_offset < 0)
1092 return -EINVAL;
1093 else
1094 base = regs_get_register(regs, *base_offset);
1095
1096 if (indx_offset == -EDOM)
1097 indx = 0;
1098 else if (indx_offset < 0)
1099 return -EINVAL;
1100 else
1101 indx = regs_get_register(regs, indx_offset);
1102
1103 if (insn->addr_bytes == 4) {
1104 int addr32, base32, idx32;
1105
1106 base32 = base & 0xffffffff;
1107 idx32 = indx & 0xffffffff;
1108
1109 addr32 = base32 + idx32 * (1 << X86_SIB_SCALE(insn->sib.value));
1110 addr32 += insn->displacement.value;
1111
1112 *eff_addr = addr32 & 0xffffffff;
1113 } else {
1114 *eff_addr = base + indx * (1 << X86_SIB_SCALE(insn->sib.value));
1115 *eff_addr += insn->displacement.value;
1116 }
1117
1118 return 0;
1119}
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138static void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs)
1139{
1140 unsigned long linear_addr = -1L, seg_base, seg_limit;
1141 int ret, regoff;
1142 short eff_addr;
1143 long tmp;
1144
1145 insn_get_modrm(insn);
1146 insn_get_displacement(insn);
1147
1148 if (insn->addr_bytes != 2)
1149 goto out;
1150
1151 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
1152 ret = get_eff_addr_reg(insn, regs, ®off, &tmp);
1153 if (ret)
1154 goto out;
1155
1156 eff_addr = tmp;
1157 } else {
1158 ret = get_eff_addr_modrm_16(insn, regs, ®off, &eff_addr);
1159 if (ret)
1160 goto out;
1161 }
1162
1163 ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
1164 if (ret)
1165 goto out;
1166
1167
1168
1169
1170
1171
1172
1173 if ((unsigned long)(eff_addr & 0xffff) > seg_limit)
1174 goto out;
1175
1176 linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base;
1177
1178
1179 if (v8086_mode(regs))
1180 linear_addr &= 0xfffff;
1181
1182out:
1183 return (void __user *)linear_addr;
1184}
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202static void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs)
1203{
1204 unsigned long linear_addr = -1L, seg_base, seg_limit;
1205 int eff_addr, regoff;
1206 long tmp;
1207 int ret;
1208
1209 if (insn->addr_bytes != 4)
1210 goto out;
1211
1212 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
1213 ret = get_eff_addr_reg(insn, regs, ®off, &tmp);
1214 if (ret)
1215 goto out;
1216
1217 eff_addr = tmp;
1218
1219 } else {
1220 if (insn->sib.nbytes) {
1221 ret = get_eff_addr_sib(insn, regs, ®off, &tmp);
1222 if (ret)
1223 goto out;
1224
1225 eff_addr = tmp;
1226 } else {
1227 ret = get_eff_addr_modrm(insn, regs, ®off, &tmp);
1228 if (ret)
1229 goto out;
1230
1231 eff_addr = tmp;
1232 }
1233 }
1234
1235 ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit);
1236 if (ret)
1237 goto out;
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250 if (!user_64bit_mode(regs) && ((unsigned int)eff_addr > seg_limit))
1251 goto out;
1252
1253
1254
1255
1256
1257 if (v8086_mode(regs) && (eff_addr & ~0xffff))
1258 goto out;
1259
1260
1261
1262
1263
1264
1265 linear_addr = (unsigned long)(eff_addr & 0xffffffff) + seg_base;
1266
1267
1268 if (v8086_mode(regs))
1269 linear_addr &= 0xfffff;
1270
1271out:
1272 return (void __user *)linear_addr;
1273}
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290#ifndef CONFIG_X86_64
1291static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
1292{
1293 return (void __user *)-1L;
1294}
1295#else
1296static void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs)
1297{
1298 unsigned long linear_addr = -1L, seg_base;
1299 int regoff, ret;
1300 long eff_addr;
1301
1302 if (insn->addr_bytes != 8)
1303 goto out;
1304
1305 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
1306 ret = get_eff_addr_reg(insn, regs, ®off, &eff_addr);
1307 if (ret)
1308 goto out;
1309
1310 } else {
1311 if (insn->sib.nbytes) {
1312 ret = get_eff_addr_sib(insn, regs, ®off, &eff_addr);
1313 if (ret)
1314 goto out;
1315 } else {
1316 ret = get_eff_addr_modrm(insn, regs, ®off, &eff_addr);
1317 if (ret)
1318 goto out;
1319 }
1320
1321 }
1322
1323 ret = get_seg_base_limit(insn, regs, regoff, &seg_base, NULL);
1324 if (ret)
1325 goto out;
1326
1327 linear_addr = (unsigned long)eff_addr + seg_base;
1328
1329out:
1330 return (void __user *)linear_addr;
1331}
1332#endif
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
1350{
1351 if (!insn || !regs)
1352 return (void __user *)-1L;
1353
1354 switch (insn->addr_bytes) {
1355 case 2:
1356 return get_addr_ref_16(insn, regs);
1357 case 4:
1358 return get_addr_ref_32(insn, regs);
1359 case 8:
1360 return get_addr_ref_64(insn, regs);
1361 default:
1362 return (void __user *)-1L;
1363 }
1364}
1365